From ff8d16399c8a72b4430a206c0f907aaf1c6c0f89 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 21 Aug 2016 13:20:49 +0200 Subject: Cleanup: let's try to avoid too much indirect header imports, makes things harder when some cope changes... --- source/blender/alembic/intern/abc_exporter.cc | 1 + source/blender/alembic/intern/abc_points.cc | 1 + 2 files changed, 2 insertions(+) (limited to 'source') diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index f71d78bd60e..2e9f429f887 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -44,6 +44,7 @@ extern "C" { #include "DNA_curve_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" /* for FILE_MAX */ diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index 758d4827b8a..322bb906bf5 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -30,6 +30,7 @@ extern "C" { #include "DNA_mesh_types.h" +#include "DNA_object_types.h" #include "BKE_lattice.h" #include "BKE_mesh.h" -- cgit v1.2.3 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') 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 95d3ca8bc68c85643b9ce6b7340e2e1f48224fc2 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 19 Aug 2016 15:12:52 +0200 Subject: Fix inconsistency: expected scale not be subject to scale influence We should treat all three "target" ("expected") parameters in a similar way: The "influence" control should only work on the measurement part of stabilisation, i.e. it should only control the automatic part of stabilisation, while the target parameters are deliberately set by the user and thus should even be in effect when the automatic stabilsation is turned down. It used to be so for location and rotation, but for the scale part, I re-used the existing code for autoscale, which also had the scale influence work on the autoscale factor. This was sensible in the old version, since scale_influence was the only way to control the result. But now, the user has always total control trough the "target_*" parameters and thus we should prefer to treat all similar. --- source/blender/blenkernel/intern/tracking_stabilize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 4d72d851ae9..0f047242f93 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -1023,7 +1023,7 @@ static void stabilization_calculate_data(StabContext *ctx, float target_pos[2]; float scaleinf = get_animated_scaleinf(ctx, framenr); - *r_scale = (get_animated_target_scale(ctx,framenr) - 1.0f) * scaleinf + 1.0f; + *r_scale = get_animated_target_scale(ctx,framenr); if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) { *r_scale *= expf(scale_step * scaleinf); /* Averaged in log scale */ -- cgit v1.2.3 From 3dbe1744402c2790d7854f09cf977bb275436479 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 22 Aug 2016 17:22:06 +0200 Subject: 2D stabilization: flip orientation of the scale parameter values > 1 will zoom in and values < 1 zoom out Rationale: the changed orientation is more natural from a user POV and doing it this way is also more consistent with the calculation of the other target_* parameters. Compatibility: This will break *.blend files saved with the previous version of this patch from the last days (test period). It will *not* break any old/migrated files: Previously, the DNA field "scale" was only used to cache autoscale. Only with the Stabilisator rework, "scale" becomes a first class persistent DNA field. There is migration code to init this field to 1.0 --- source/blender/blenkernel/intern/tracking_stabilize.c | 19 ++++++++++++------- source/blender/blenloader/intern/versioning_270.c | 19 ++++++++++--------- source/blender/makesrna/intern/rna_tracking.c | 8 ++++---- 3 files changed, 26 insertions(+), 20 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 0f047242f93..93addc47fe1 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -1020,13 +1020,13 @@ static void stabilization_calculate_data(StabContext *ctx, float *r_scale, float *r_angle) { - float target_pos[2]; + float target_pos[2], target_scale; float scaleinf = get_animated_scaleinf(ctx, framenr); - *r_scale = get_animated_target_scale(ctx,framenr); - if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) { - *r_scale *= expf(scale_step * scaleinf); /* Averaged in log scale */ + *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */ + } else { + *r_scale = 1.0f; } mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr)); @@ -1039,6 +1039,11 @@ static void stabilization_calculate_data(StabContext *ctx, get_animated_target_pos(ctx, framenr, target_pos); sub_v2_v2(r_translation, target_pos); *r_angle -= get_animated_target_rot(ctx,framenr); + target_scale = get_animated_target_scale(ctx,framenr); + if (target_scale != 0.0f) { + *r_scale /= target_scale; + /* target_scale is an expected/intended reference zoom value*/ + } /* Convert from relative to absolute coordinates, square pixels. */ r_translation[0] *= (float)size * aspect; @@ -1194,9 +1199,9 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, J = G - E; K = G * F - E * H; - S = (dx * I + dy * J + K) / (-w * I - h * J); + S = (-w * I - h * J) / (dx * I + dy * J + K); - scale = min_ff(scale, S); + scale = max_ff(scale, S); } } } @@ -1205,7 +1210,7 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, stab->scale = scale; if (stab->maxscale > 0.0f) { - stab->scale = max_ff(stab->scale, 1.0f / stab->maxscale); + stab->scale = min_ff(stab->scale, stab->maxscale); } } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index f6ac42c1941..1ef32d6f006 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -91,9 +91,6 @@ static void migrate_single_rot_stabilization_track_settings(MovieTrackingStabili } } stab->rot_track = NULL; /* this field is now ignored */ - - /* by default show the track lists expanded, to improve "discoverability" */ - stab->flag |= TRACKING_SHOW_STAB_TRACKS; } static void do_version_constraints_radians_degrees_270_1(ListBase *lb) @@ -1369,13 +1366,17 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) for (clip = main->movieclip.first; clip != NULL; clip = clip->id.next) { if (clip->tracking.stabilization.rot_track) { migrate_single_rot_stabilization_track_settings(&clip->tracking.stabilization); - if (!clip->tracking.stabilization.scale) { - /* ensure init. - * Was previously used for autoscale only, - * now used always (as "target scale") */ - clip->tracking.stabilization.scale = 1.0f; - } } + if (clip->tracking.stabilization.scale == 0.0f) { + /* ensure init. + * Was previously used for autoscale only, + * now used always (as "target scale") */ + clip->tracking.stabilization.scale = 1.0f; + } + /* by default show the track lists expanded, to improve "discoverability" */ + clip->tracking.stabilization.flag |= TRACKING_SHOW_STAB_TRACKS; + /* deprecated, not used anymore */ + clip->tracking.stabilization.ok = false; } } } diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index cbfebe5efc4..2d068bbab26 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1768,7 +1768,7 @@ static void rna_def_trackingStabilization(BlenderRNA *brna) prop = RNA_def_property(srna, "target_rotation", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "target_rot"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); - RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10.0f, 3); RNA_def_property_ui_text(prop, "Expected Rotation", "Rotation present on original shot, will be compensated (e.g. for deliberate tilting)"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); @@ -1776,9 +1776,9 @@ static void rna_def_trackingStabilization(BlenderRNA *brna) /* target scale */ prop = RNA_def_property(srna, "target_zoom", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "scale"); - RNA_def_property_range(prop, FLT_EPSILON, 100.0f); - RNA_def_property_ui_range(prop, 0.1f, 10.0f, 1, 3); /* increment in steps of 0.01. Show 3 digit after point */ - RNA_def_property_ui_text(prop, "Expected Zoom", + RNA_def_property_range(prop, FLT_EPSILON, FLT_MAX); + RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.001f, 3); /* increment in steps of 0.001. Show 3 digit after point */ + RNA_def_property_ui_text(prop, "Expected Scale", "Explicitly scale resulting frame to compensate zoom of original shot"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate"); -- cgit v1.2.3 From fd65a649303cee33266c6fffffab5f86df47545e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 19 Aug 2016 14:33:49 +0200 Subject: 2D stabilization: change presentation of target_scale in UI Alongside with this change, we fix disabling of Autoscale, because this feature works even when rotation/scale is disabled. --- source/blender/makesrna/intern/rna_tracking.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 2d068bbab26..6e41a7ad09a 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1774,7 +1774,7 @@ static void rna_def_trackingStabilization(BlenderRNA *brna) RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); /* target scale */ - prop = RNA_def_property(srna, "target_zoom", PROP_FLOAT, PROP_FACTOR); + prop = RNA_def_property(srna, "target_scale", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "scale"); RNA_def_property_range(prop, FLT_EPSILON, FLT_MAX); RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.001f, 3); /* increment in steps of 0.001. Show 3 digit after point */ -- cgit v1.2.3 From 498ba756abeec746322b883d98ba6a192f37e7ea Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 22 Aug 2016 17:29:19 +0200 Subject: 2D stabilization: by default init anchor_frame to frame 1 It is common in blender to use 1-based counting for frame sequences (while 0-based is allowed). Thus initializing to use frame 1 as reference for stabilization is likely to produce smooth start values in most cases --- source/blender/blenkernel/intern/tracking.c | 2 +- source/blender/blenloader/intern/versioning_270.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index d5d3384bb48..a86606f1099 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -330,7 +330,7 @@ void BKE_tracking_settings_init(MovieTracking *tracking) tracking->settings.object_distance = 1; tracking->stabilization.scaleinf = 1.0f; - tracking->stabilization.anchor_frame = MINFRAME; + tracking->stabilization.anchor_frame = 1; zero_v2(tracking->stabilization.target_pos); tracking->stabilization.target_rot = 0.0f; tracking->stabilization.scale = 1.0f; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 1ef32d6f006..49ef8baa184 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1373,6 +1373,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) * now used always (as "target scale") */ clip->tracking.stabilization.scale = 1.0f; } + /* blender prefers 1-based frame counting; + * thus using frame 1 as reference typically works best */ + clip->tracking.stabilization.anchor_frame = 1; /* by default show the track lists expanded, to improve "discoverability" */ clip->tracking.stabilization.flag |= TRACKING_SHOW_STAB_TRACKS; /* deprecated, not used anymore */ -- cgit v1.2.3 From baaa2d6d396ef8003cf2241ae0a6304d6aebb496 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 22 Aug 2016 07:02:22 +0200 Subject: Change Request: use weight centre of location tracks as pivot Previously, this extension used the translation compensated image centre as reference point for rotation measurement and compensation. During user tests, it turned out that this setup tends to give poor results with very simple track configurations. This can be improved by useiing the weighted average of the location tracks for each frame as pivot point. But there is a technical problem: the existing public API functions do not allow to pass the pivot point for each frame alongside with the stabilisation data. Thus this change implements a trick to package a compensation shift into the translation offset, so the rotation can be performed around a fixed point (center of frame). The compensation shift will then shift the image as if it had been rotated around the desired pivot point. --- .../blender/blenkernel/intern/tracking_stabilize.c | 330 +++++++++++++++------ 1 file changed, 240 insertions(+), 90 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 93addc47fe1..758e1c4a06b 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -452,6 +452,29 @@ static MovieTrackingMarker *get_tracking_data_point( } } + +/* Define the reference point for rotation/scale measurement and compensation. + * The stabilizator works by assuming the image was distorted by a affine linear + * transform, i.e. it was rotated and stretched around this reference point + * (pivot point) and then shifted laterally. Any scale and orientation changes + * will be picked up relative to this point. And later the image will be + * stabilized by rotating around this point. The result can only be as + * accurate as this pivot point actually matches the real rotation center + * of the actual movements. Thus any scheme to define a pivot point is + * always guesswork. + * + * As a simple default, we use the weighted average of the location markers + * of the current frame as pivot point. TODO It is planned to add further + * options, like e.g. anchoring the pivot point at the canvas. Moreover, + * it is planned to allow for a user controllable offset. + */ +static void setup_pivot(const float ref_pos[2], float r_pivot[2]) +{ + zero_v2(r_pivot); /* TODO: add an animated offset position here. */ + add_v2_v2(r_pivot, ref_pos); +} + + /* Calculate the contribution of a single track at the time position (frame) of * the given marker. Each track has a local reference frame, which is as close * as possible to the global anchor_frame. Thus the translation contribution is @@ -508,22 +531,21 @@ static void translation_contribution(TrackStabilizationBase *track_ref, * in the same framework, we average the scales as logarithms. * * aspect is a total aspect ratio of the undistorted image (includes fame and - * pixel aspect). + * pixel aspect). The function returns a quality factor, which can be used + * to damp the contributions of points in close proximity to the pivot point, + * since such contributions might be dominated by rounding errors and thus + * poison the calculated average. When the quality factor goes towards zero, + * the weight of this contribution should be reduced accordingly. */ -static void rotation_contribution(TrackStabilizationBase *track_ref, - MovieTrackingMarker *marker, - float aspect, - float target_pos[2], - float averaged_translation_contribution[2], - float *result_angle, - float *result_scale) +static float rotation_contribution(TrackStabilizationBase *track_ref, + MovieTrackingMarker *marker, + const float aspect, + const float pivot[2], + float *result_angle, + float *result_scale) { - float len; + float len, quality; float pos[2]; - float pivot[2]; - copy_v2_fl(pivot, 0.5f); /* Use center of frame as hard wired pivot. */ - add_v2_v2(pivot, averaged_translation_contribution); - sub_v2_v2(pivot, target_pos); sub_v2_v2v2(pos, marker->pos, pivot); pos[0] *= aspect; @@ -531,9 +553,47 @@ static void rotation_contribution(TrackStabilizationBase *track_ref, *result_angle = atan2f(pos[1],pos[0]); - len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS; + len = len_v2(pos); + + /* prevent points very close to the pivot point from poisoning the result */ + quality = 1 - expf(-len*len / SCALE_ERROR_LIMIT_BIAS*SCALE_ERROR_LIMIT_BIAS); + len += SCALE_ERROR_LIMIT_BIAS; + *result_scale = len * track_ref->stabilization_scale_base; BLI_assert(0.0 < *result_scale); + + return quality; +} + + +/* Workaround to allow for rotation around an arbitrary pivot point. + * Currently, the public API functions do not support this flexibility. + * Rather, rotation will always be applied around a fixed origin. + * As a workaround, we shift the image after rotation to match the + * desired rotation centre. And since this offset needs to be applied + * after the rotation and scaling, we can collapse it with the + * translation compensation, which is also a lateral shift (offset). + * The offset to apply is intended_pivot - rotated_pivot + */ +static void compensate_rotation_center(const int size, float aspect, + const float angle, + const float scale, + const float pivot[2], + float result_translation[2]) +{ + const float origin[2] = {0.5f*aspect*size, 0.5f*size}; + float intended_pivot[2], rotated_pivot[2]; + float rotation_mat[2][2]; + + copy_v2_v2(intended_pivot, pivot); + copy_v2_v2(rotated_pivot, pivot); + rotate_m2(rotation_mat, +angle); + sub_v2_v2(rotated_pivot, origin); + mul_m2v2(rotation_mat, rotated_pivot); + mul_v2_fl(rotated_pivot, scale); + add_v2_v2(rotated_pivot, origin); + add_v2_v2(result_translation, intended_pivot); + sub_v2_v2(result_translation, rotated_pivot); } @@ -553,6 +613,7 @@ static bool average_track_contributions(StabContext *ctx, int framenr, float aspect, float r_translation[2], + float r_pivot[2], float *r_angle, float *r_scale_step) { @@ -561,12 +622,15 @@ static bool average_track_contributions(StabContext *ctx, MovieTrackingTrack *track; MovieTracking *tracking = ctx->tracking; MovieTrackingStabilization *stab = &tracking->stabilization; + float ref_pos[2]; BLI_assert(stab->flag & TRACKING_2D_STABILIZATION); zero_v2(r_translation); *r_scale_step = 0.0f; /* logarithm */ *r_angle = 0.0f; + zero_v2(ref_pos); + ok = false; weight_sum = 0.0f; for (track = tracking->tracks.first; track; track = track->next) { @@ -586,8 +650,10 @@ static bool average_track_contributions(StabContext *ctx, float offset[2]; weight_sum += weight; translation_contribution(stabilization_base, marker, offset); - mul_v2_fl(offset, weight); - add_v2_v2(r_translation, offset); + r_translation[0] += weight * offset[0]; + r_translation[1] += weight * offset[1]; + ref_pos[0] += weight * marker->pos[0]; + ref_pos[1] += weight * marker->pos[1]; ok |= (weight_sum > EPSILON_WEIGHT); } } @@ -596,8 +662,11 @@ static bool average_track_contributions(StabContext *ctx, return false; } + ref_pos[0] /= weight_sum; + ref_pos[1] /= weight_sum; r_translation[0] /= weight_sum; r_translation[1] /= weight_sum; + setup_pivot(ref_pos, r_pivot); if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) { return ok; @@ -619,17 +688,15 @@ static bool average_track_contributions(StabContext *ctx, TrackStabilizationBase *stabilization_base = access_stabilization_baseline_data(ctx, track); BLI_assert(stabilization_base != NULL); - float rotation, scale; - float target_pos[2]; + float rotation, scale, quality; + quality = rotation_contribution(stabilization_base, + marker, + aspect, + r_pivot, + &rotation, + &scale); + weight *= quality; weight_sum += weight; - get_animated_target_pos(ctx, framenr, target_pos); - rotation_contribution(stabilization_base, - marker, - aspect, - target_pos, - r_translation, - &rotation, - &scale); *r_angle += rotation * weight; if (stab->flag & TRACKING_STABILIZE_SCALE) { *r_scale_step += logf(scale) * weight; @@ -656,6 +723,75 @@ static bool average_track_contributions(StabContext *ctx, } +/* Calculate weight center of location tracks for given frame. + * This function performs similar calculations as average_track_contributions(), + * but does not require the tracks to be initialized for stabilisation. Moreover, + * when there is no usable tracking data for the given frame number, data from + * a neighbouring frame is used. Thus this function can be used to calculate + * a starting point on initialization. + */ +static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2]) +{ + bool ok = false; + float weight_sum; + MovieTrackingTrack *track; + MovieTracking *tracking = ctx->tracking; + + zero_v2(r_ref_pos); + weight_sum = 0.0f; + for (track = tracking->tracks.first; track; track = track->next) { + if (track->flag & TRACK_USE_2D_STAB) { + float weight = 0.0f; + MovieTrackingMarker *marker = + get_tracking_data_point(ctx, track, framenr, &weight); + if (marker) { + weight_sum += weight; + r_ref_pos[0] += weight * marker->pos[0]; + r_ref_pos[1] += weight * marker->pos[1]; + ok |= (weight_sum > EPSILON_WEIGHT); + } + } + } + if (ok) { + r_ref_pos[0] /= weight_sum; + r_ref_pos[1] /= weight_sum; + } else { + /* No usable tracking data on any track on this frame. + * Use data from neighbouring frames to extrapolate... + */ + int next_lower = MINAFRAME; + int next_higher = MAXFRAME; + use_values_from_fcurves(ctx, true); + for (track = tracking->tracks.first; track; track = track->next) { + /* Note: we deliberately do not care if this track + * is already initialized for stabilisation */ + if (track->flag & TRACK_USE_2D_STAB) { + int startpoint = search_closest_marker_index(track, framenr); + retrieve_next_higher_usable_frame(ctx, + track, + startpoint, + framenr, + &next_higher); + retrieve_next_lower_usable_frame(ctx, + track, + startpoint, + framenr, + &next_lower); + } + } + if (next_lower >= MINFRAME) { + /* use next usable frame to the left. + * Also default to this frame when we're in a gap */ + average_marker_positions(ctx, next_lower, r_ref_pos); + + } else if (next_higher < MAXFRAME) { + average_marker_positions(ctx, next_higher, r_ref_pos); + } + use_values_from_fcurves(ctx, false); + } +} + + /* Linear interpolation of data retrieved at two measurement points. * This function is used to fill gaps in the middle of the covered area, * at frames without any usable tracks for stabilization. @@ -670,8 +806,9 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx, int framenr, int frame_a, int frame_b, - float aspect, - float translation[2], + const float aspect, + float r_translation[2], + float r_pivot[2], float *r_angle, float *r_scale_step) { @@ -679,6 +816,7 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx, float trans_a[2], trans_b[2]; float angle_a, angle_b; float scale_a, scale_b; + float pivot_a[2], pivot_b[2]; bool success = false; BLI_assert(frame_a <= frame_b); @@ -688,16 +826,17 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx, t = ((float)framenr - frame_a) / (frame_b - frame_a); s = 1.0f - t; - success = average_track_contributions(ctx, frame_a, aspect, trans_a, &angle_a, &scale_a); + success = average_track_contributions(ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a); if (!success) { return false; } - success = average_track_contributions(ctx, frame_b, aspect, trans_b, &angle_b, &scale_b); + success = average_track_contributions(ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b); if (!success) { return false; } - interp_v2_v2v2(translation, trans_a, trans_b, t); + interp_v2_v2v2(r_translation, trans_a, trans_b, t); + interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t); *r_scale_step = s * scale_a + t * scale_b; *r_angle = s * angle_a + t * angle_b; return true; @@ -802,13 +941,12 @@ static void initialize_track_for_stabilization(StabContext *ctx, MovieTrackingTrack *track, int reference_frame, float aspect, - const float target_pos[2], const float average_translation[2], - float average_angle, - float average_scale_step) + const float pivot[2], + const float average_angle, + const float average_scale_step) { float pos[2], angle, len; - float pivot[2]; TrackStabilizationBase *local_data = access_stabilization_baseline_data(ctx, track); MovieTrackingMarker *marker = @@ -825,9 +963,6 @@ static void initialize_track_for_stabilization(StabContext *ctx, marker->pos); /* Per track baseline value for rotation. */ - copy_v2_fl(pivot, 0.5f); /* Use center of frame as hard wired pivot. */ - add_v2_v2(pivot, average_translation); - sub_v2_v2(pivot, target_pos); sub_v2_v2v2(pos, marker->pos, pivot); pos[0] *= aspect; @@ -855,10 +990,9 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) */ int reference_frame = tracking->stabilization.anchor_frame; float average_angle=0, average_scale_step=0; - float average_translation[2]; - float target_pos_at_ref_frame[2]; - zero_v2(target_pos_at_ref_frame); + float average_translation[2], average_pos[2], pivot[2]; zero_v2(average_translation); + zero_v2(pivot); /* Initialize private working data. */ for (track = tracking->tracks.first; track != NULL; track = track->next) { @@ -891,6 +1025,10 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) goto cleanup; } + /* starting point for pivot, before having initialized any track */ + average_marker_positions(ctx, reference_frame, average_pos); + setup_pivot(average_pos, pivot); + for (i = 0; i < track_cnt; ++i) { track = order[i].data; if (reference_frame != order[i].reference_frame) { @@ -899,18 +1037,16 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) reference_frame, aspect, average_translation, + pivot, &average_angle, &average_scale_step); - get_animated_target_pos(ctx, - reference_frame, - target_pos_at_ref_frame); } initialize_track_for_stabilization(ctx, track, reference_frame, aspect, - target_pos_at_ref_frame, average_translation, + pivot, average_angle, average_scale_step); } @@ -936,6 +1072,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, int framenr, float aspect, float r_translation[2], + float r_pivot[2], float *r_angle, float *r_scale_step) { @@ -953,6 +1090,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, framenr, aspect, r_translation, + r_pivot, r_angle, r_scale_step); if (!success) { @@ -971,6 +1109,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, next_higher, aspect, r_translation, + r_pivot, r_angle, r_scale_step); } @@ -982,6 +1121,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, next_higher, aspect, r_translation, + r_pivot, r_angle, r_scale_step); } @@ -991,6 +1131,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx, next_lower, aspect, r_translation, + r_pivot, r_angle, r_scale_step); } @@ -1017,6 +1158,7 @@ static void stabilization_calculate_data(StabContext *ctx, bool do_compensate, float scale_step, float r_translation[2], + float r_pivot[0], float *r_scale, float *r_angle) { @@ -1048,6 +1190,8 @@ static void stabilization_calculate_data(StabContext *ctx, /* Convert from relative to absolute coordinates, square pixels. */ r_translation[0] *= (float)size * aspect; r_translation[1] *= (float)size; + r_pivot[0] *= (float)size * aspect; + r_pivot[1] *= (float)size; /* Output measured data, or inverse of the measured values for * compensation? @@ -1062,24 +1206,24 @@ static void stabilization_calculate_data(StabContext *ctx, } -/* Determine the inner part of the frame, which is always safe to use. - * When enlarging the image by the inverse of this factor, any black areas - * appearing due to frame translation and rotation will be removed. +/* Calculate scale factor necessary to eliminate black image areas + * caused by the compensating movements of the stabilizator. + * This function visits every frame where stabilisation data is + * available and determines the factor for this frame. The overall + * largest factor found is returned as result. * - * NOTE: When calling this function, basic initialization of tracks must be - * done already + * NOTE: all tracks need to be initialized before calling this function. */ -static void stabilization_determine_safe_image_area(StabContext *ctx, - int size, - float image_aspect) +static float calculate_autoscale_factor(StabContext *ctx, + int size, float aspect) { MovieTrackingStabilization *stab = ctx->stab; float pixel_aspect = ctx->tracking->camera.pixel_aspect; + int height = size, width = aspect*size; int sfra = INT_MAX, efra = INT_MIN, cfra; float scale = 1.0f, scale_step = 0.0f; MovieTrackingTrack *track; - stab->scale = 1.0f; /* Calculate maximal frame range of tracks where stabilization is active. */ for (track = ctx->tracking->tracks.first; track; track = track->next) { @@ -1094,38 +1238,40 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, } } - /* For every frame we calculate scale factor needed to eliminate black border area - * and choose largest scale factor as final one. - */ + use_values_from_fcurves(ctx, true); for (cfra = sfra; cfra <= efra; cfra++) { - float translation[2], angle, tmp_scale; + float translation[2], pivot[2], angle, tmp_scale; int i; float mat[4][4]; float points[4][2] = {{0.0f, 0.0f}, - {0.0f, size}, - {image_aspect * size, size}, - {image_aspect * size, 0.0f}}; + {0.0f, height}, + {width, height}, + {width, 0.0f}}; float si, co; bool do_compensate = true; stabilization_determine_offset_for_frame(ctx, cfra, - image_aspect, + aspect, translation, + pivot, &angle, &scale_step); stabilization_calculate_data(ctx, cfra, size, - image_aspect, + aspect, do_compensate, scale_step, translation, + pivot, &tmp_scale, &angle); + compensate_rotation_center(size, aspect, + angle, tmp_scale, pivot, + translation); - BKE_tracking_stabilization_data_to_mat4(size * image_aspect, - size, + BKE_tracking_stabilization_data_to_mat4(width, height, pixel_aspect, translation, 1.0f, @@ -1175,12 +1321,12 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, float w, h, E, F, G, H, I, J, K, S; if (j % 2) { - w = (float)size / 2.0f; - h = image_aspect*size / 2.0f; + w = (float)height / 2.0f; + h = (float)width / 2.0f; } else { - w = image_aspect*size / 2.0f; - h = (float)size / 2.0f; + w = (float)width / 2.0f; + h = (float)height / 2.0f; } E = -w * co + h * si; @@ -1206,12 +1352,12 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, } } } - - stab->scale = scale; - if (stab->maxscale > 0.0f) { - stab->scale = min_ff(stab->scale, stab->maxscale); + scale = min_ff(scale, stab->maxscale); } + use_values_from_fcurves(ctx, false); + + return scale; } @@ -1223,19 +1369,14 @@ static void stabilization_determine_safe_image_area(StabContext *ctx, * turns out to be tricky, hard to maintain and generally not worth the * effort. Thus we'll re-initialize on every frame. */ -static StabContext *init_stabilizer(MovieClip *clip, int width, int height) +static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect) { - MovieTracking *tracking = &clip->tracking; - MovieTrackingStabilization *stab = &tracking->stabilization; - float pixel_aspect = tracking->camera.pixel_aspect; - float aspect = (float)width * pixel_aspect / height; - int size = height; - StabContext *ctx = initialize_stabilization_working_context(clip); BLI_assert(ctx != NULL); initialize_all_tracks(ctx, aspect); - if (stab->flag & TRACKING_AUTOSCALE) { - stabilization_determine_safe_image_area(ctx, size, aspect); + if (ctx->stab->flag & TRACKING_AUTOSCALE) { + ctx->stab->scale = 1.0; + ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect); } /* By default, just use values for the global current frame. */ use_values_from_fcurves(ctx, false); @@ -1280,9 +1421,10 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, float pixel_aspect = tracking->camera.pixel_aspect; float aspect = (float)width * pixel_aspect / height; int size = height; + float pivot[2]; if (enabled) { - ctx = init_stabilizer(clip, width, height); + ctx = init_stabilizer(clip, size, aspect); } if (enabled && @@ -1290,6 +1432,7 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, framenr, aspect, translation, + pivot, angle, &scale_step)) { @@ -1300,8 +1443,12 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, do_compensate, scale_step, translation, + pivot, scale, angle); + compensate_rotation_center(size, aspect, + *angle, *scale, pivot, + translation); } else { zero_v2(translation); @@ -1439,18 +1586,21 @@ void BKE_tracking_stabilization_data_to_mat4(int buffer_width, aspect_mat[4][4], inv_aspect_mat[4][4]; float scale_vector[3] = {scale, scale, 1.0f}; - float pivot[2]; /* XXX this should be a parameter, it is part of the stabilization data */ + float pivot[2]; /* TODO this should be a parameter, it is part of the stabilization data */ - /* Use the motion compensated image center as rotation center. - * This is not 100% correct, but reflects the way the rotation data was - * measured. Actually we'd need a way to find a good pivot, and use that - * both for averaging and for compensation. + /* Since we cannot receive the real pivot point coordinates (API limitation), + * we perform the rotation/scale around the center of frame. + * Then we correct by an additional shift, which was calculated in + * compensate_rotation_center() and "sneaked in" as additional offset + * in the translation parameter. This works, since translation needs to be + * applied after rotation/scale anyway. Thus effectively the image gets + * rotated around the desired pivot point */ /* TODO(sergey) pivot shouldn't be calculated here, rather received * as a parameter. */ - pivot[0] = pixel_aspect * buffer_width / 2.0f - translation[0]; - pivot[1] = (float)buffer_height / 2.0f - translation[1]; + pivot[0] = 0.5f * pixel_aspect * buffer_width; + pivot[1] = 0.5f * buffer_height; unit_m4(translation_mat); unit_m4(rotation_mat); -- cgit v1.2.3 From 9c3b9f6a836ace08baf04cf4e716a73f9797f88d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 23 Aug 2016 11:48:29 +0200 Subject: 2D stabilization: Fix broken auto-scale all the recent work Auto-scale is expected to work just fine now. Only thing changed now is the pivot point for the scale: it is now the same as rotation pivot, so scaling happens around weighted median of the translation tracks. This seems to be what is actually required for the VFX workflow. --- .../blender/blenkernel/intern/tracking_stabilize.c | 266 +++++++++++---------- 1 file changed, 138 insertions(+), 128 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 758e1c4a06b..cc552d86e8a 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -768,15 +768,15 @@ static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_ if (track->flag & TRACK_USE_2D_STAB) { int startpoint = search_closest_marker_index(track, framenr); retrieve_next_higher_usable_frame(ctx, - track, - startpoint, - framenr, - &next_higher); + track, + startpoint, + framenr, + &next_higher); retrieve_next_lower_usable_frame(ctx, - track, - startpoint, - framenr, - &next_lower); + track, + startpoint, + framenr, + &next_lower); } } if (next_lower >= MINFRAME) { @@ -1205,6 +1205,41 @@ static void stabilization_calculate_data(StabContext *ctx, } } +static void stabilization_data_to_mat4(float pixel_aspect, + const float pivot[2], + const float translation[2], + float scale, + float angle, + float r_mat[4][4]) +{ + float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4], + pivot_mat[4][4], inv_pivot_mat[4][4], + aspect_mat[4][4], inv_aspect_mat[4][4]; + float scale_vector[3] = {scale, scale, 1.0f}; + + unit_m4(translation_mat); + unit_m4(rotation_mat); + unit_m4(scale_mat); + unit_m4(aspect_mat); + unit_m4(pivot_mat); + unit_m4(inv_pivot_mat); + + /* aspect ratio correction matrix */ + aspect_mat[0][0] /= pixel_aspect; + invert_m4_m4(inv_aspect_mat, aspect_mat); + + add_v2_v2(pivot_mat[3], pivot); + sub_v2_v2(inv_pivot_mat[3], pivot); + + size_to_mat4(scale_mat, scale_vector); /* scale matrix */ + add_v2_v2(translation_mat[3], translation); /* translation matrix */ + rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */ + + /* Compose transformation matrix. */ + mul_m4_series(r_mat, aspect_mat, translation_mat, + pivot_mat, scale_mat, rotation_mat, inv_pivot_mat, + inv_aspect_mat); +} /* Calculate scale factor necessary to eliminate black image areas * caused by the compensating movements of the stabilizator. @@ -1215,7 +1250,8 @@ static void stabilization_calculate_data(StabContext *ctx, * NOTE: all tracks need to be initialized before calling this function. */ static float calculate_autoscale_factor(StabContext *ctx, - int size, float aspect) + int size, + float aspect) { MovieTrackingStabilization *stab = ctx->stab; float pixel_aspect = ctx->tracking->camera.pixel_aspect; @@ -1241,15 +1277,13 @@ static float calculate_autoscale_factor(StabContext *ctx, use_values_from_fcurves(ctx, true); for (cfra = sfra; cfra <= efra; cfra++) { float translation[2], pivot[2], angle, tmp_scale; - int i; float mat[4][4]; - float points[4][2] = {{0.0f, 0.0f}, - {0.0f, height}, - {width, height}, - {width, 0.0f}}; - float si, co; - bool do_compensate = true; - + const float points[4][2] = {{0.0f, 0.0f}, + {0.0f, height}, + {width, height}, + {width, 0.0f}}; + const bool do_compensate = true; + /* Calculate stabilization parameters for the current frame. */ stabilization_determine_offset_for_frame(ctx, cfra, aspect, @@ -1267,86 +1301,79 @@ static float calculate_autoscale_factor(StabContext *ctx, pivot, &tmp_scale, &angle); - compensate_rotation_center(size, aspect, - angle, tmp_scale, pivot, - translation); - - BKE_tracking_stabilization_data_to_mat4(width, height, - pixel_aspect, - translation, - 1.0f, - angle, - mat); - - si = sinf(angle); - co = cosf(angle); - + /* Compose transformation matrix. */ + /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have + * to construct transformation matrix using proper pivot point. + * Compensation for that will happen later on. + */ + stabilization_data_to_mat4(pixel_aspect, + pivot, + translation, + tmp_scale, + angle, + mat); /* Investigate the transformed border lines for this frame; * find out, where it cuts the original frame. */ - for (i = 0; i < 4; i++) { - int j; - float a[3] = {0.0f, 0.0f, 0.0f}, - b[3] = {0.0f, 0.0f, 0.0f}; - - copy_v2_v2(a, points[i]); - copy_v2_v2(b, points[(i + 1) % 4]); - a[2] = b[2] = 0.0f; - - mul_m4_v3(mat, a); - mul_m4_v3(mat, b); - - for (j = 0; j < 4; j++) { - float point[3] = {points[j][0], points[j][1], 0.0f}; - float v1[3], v2[3]; - - sub_v3_v3v3(v1, b, a); - sub_v3_v3v3(v2, point, a); - - if (cross_v2v2(v1, v2) >= 0.0f) { - const float rot_dx[4][2] = {{1.0f, 0.0f}, - {0.0f, -1.0f}, - {-1.0f, 0.0f}, - {0.0f, 1.0f}}; - const float rot_dy[4][2] = {{0.0f, 1.0f}, - {1.0f, 0.0f}, - {0.0f, -1.0f}, - {-1.0f, 0.0f}}; - - float dx = translation[0] * rot_dx[j][0] + - translation[1] * rot_dx[j][1], - dy = translation[0] * rot_dy[j][0] + - translation[1] * rot_dy[j][1]; - - float w, h, E, F, G, H, I, J, K, S; - - if (j % 2) { - w = (float)height / 2.0f; - h = (float)width / 2.0f; - } - else { - w = (float)width / 2.0f; - h = (float)height / 2.0f; - } - - E = -w * co + h * si; - F = -h * co - w * si; - - if ((i % 2) == (j % 2)) { - G = -w * co - h * si; - H = h * co - w * si; - } - else { - G = w * co + h * si; - H = -h * co + w * si; - } - - I = F - H; - J = G - E; - K = G * F - E * H; - - S = (-w * I - h * J) / (dx * I + dy * J + K); - + for (int edge_index = 0; edge_index < 4; edge_index++) { + /* Calculate coordinates of stabilized frame edge points. + * Use matrix multiplication here so we operate in homogeneous + * coordinates. + */ + float stable_edge_p1[3], stable_edge_p2[3]; + copy_v2_v2(stable_edge_p1, points[edge_index]); + copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]); + stable_edge_p1[2] = stable_edge_p2[2] = 0.0f; + mul_m4_v3(mat, stable_edge_p1); + mul_m4_v3(mat, stable_edge_p2); + /* Now we iterate over all original frame corners (we call them + * 'point' here) to see if there's black area between stabilized + * frame edge and original point. + */ + for (int point_index = 0; point_index < 4; point_index++) { + const float point[3] = {points[point_index][0], + points[point_index][1], + 0.0f}; + /* Calculate vector which goes from first edge point to + * second one. + */ + float stable_edge_vec[3]; + sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1); + /* Calculate vector which connects current frame point to + * first edge point. + */ + float point_to_edge_start_vec[3]; + sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1); + /* Use this two vectors to check whether frame point is inside + * of the stabilized frame or not. + * If the point is inside, there is no black area happening + * and no scaling required for it. + */ + if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) { + /* We are scaling around motion-compensated pivot point. */ + float scale_pivot[2]; + add_v2_v2v2(scale_pivot, pivot, translation); + /* Calculate line which goes via `point` and parallel to + * the stabilized frame edge. This line is coming via + * `point` and `point2` at the end. + */ + float point2[2]; + add_v2_v2v2(point2, point, stable_edge_vec); + /* Calculate actual distance between pivot point and + * the stabilized frame edge. Then calculate distance + * between pivot point and line which goes via actual + * corner and is parallel to the edge. + * + * Dividing one by another will give us required scale + * factor to get rid of black areas. + */ + float real_dist = dist_to_line_v2(scale_pivot, + stable_edge_p1, + stable_edge_p2); + float required_dist = dist_to_line_v2(scale_pivot, + point, + point2); + const float S = required_dist / real_dist; scale = max_ff(scale, S); } } @@ -1446,8 +1473,11 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip, pivot, scale, angle); - compensate_rotation_center(size, aspect, - *angle, *scale, pivot, + compensate_rotation_center(size, + aspect, + *angle, + *scale, + pivot, translation); } else { @@ -1578,16 +1608,11 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip, void BKE_tracking_stabilization_data_to_mat4(int buffer_width, int buffer_height, float pixel_aspect, - float translation[2], float scale, float angle, - float mat[4][4]) + float translation[2], + float scale, + float angle, + float r_mat[4][4]) { - float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4], - pivot_mat[4][4], inv_pivot_mat[4][4], - aspect_mat[4][4], inv_aspect_mat[4][4]; - float scale_vector[3] = {scale, scale, 1.0f}; - - float pivot[2]; /* TODO this should be a parameter, it is part of the stabilization data */ - /* Since we cannot receive the real pivot point coordinates (API limitation), * we perform the rotation/scale around the center of frame. * Then we correct by an additional shift, which was calculated in @@ -1599,29 +1624,14 @@ void BKE_tracking_stabilization_data_to_mat4(int buffer_width, /* TODO(sergey) pivot shouldn't be calculated here, rather received * as a parameter. */ + float pivot[2]; pivot[0] = 0.5f * pixel_aspect * buffer_width; pivot[1] = 0.5f * buffer_height; - - unit_m4(translation_mat); - unit_m4(rotation_mat); - unit_m4(scale_mat); - unit_m4(aspect_mat); - unit_m4(pivot_mat); - unit_m4(inv_pivot_mat); - - /* aspect ratio correction matrix */ - aspect_mat[0][0] /= pixel_aspect; - invert_m4_m4(inv_aspect_mat, aspect_mat); - - add_v2_v2(pivot_mat[3], pivot); - sub_v2_v2(inv_pivot_mat[3], pivot); - - size_to_mat4(scale_mat, scale_vector); /* scale matrix */ - add_v2_v2(translation_mat[3], translation); /* translation matrix */ - rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */ - - /* compose transformation matrix */ - mul_m4_series(mat, aspect_mat, translation_mat, - pivot_mat, scale_mat, rotation_mat, inv_pivot_mat, - inv_aspect_mat); + /* Compose transformation matrix. */ + stabilization_data_to_mat4(pixel_aspect, + pivot, + translation, + scale, + angle, + r_mat); } -- cgit v1.2.3 From e2f323c3ec2352c11d16a4fb2920184491300166 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 23 Aug 2016 12:01:55 +0200 Subject: attempt to fix compilation error on windows --- source/blender/blenkernel/intern/tracking_stabilize.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index cc552d86e8a..df42f253fdf 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -1158,7 +1158,7 @@ static void stabilization_calculate_data(StabContext *ctx, bool do_compensate, float scale_step, float r_translation[2], - float r_pivot[0], + float r_pivot[2], float *r_scale, float *r_angle) { @@ -1184,7 +1184,7 @@ static void stabilization_calculate_data(StabContext *ctx, target_scale = get_animated_target_scale(ctx,framenr); if (target_scale != 0.0f) { *r_scale /= target_scale; - /* target_scale is an expected/intended reference zoom value*/ + /* target_scale is an expected/intended reference zoom value */ } /* Convert from relative to absolute coordinates, square pixels. */ -- cgit v1.2.3 From a853367fbf2981458bfbae2f2df8ce7dc7499746 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 23 Aug 2016 15:54:36 +0200 Subject: Fix T49140: Noise and jitter present at some areas when using ambient oclusion in Blender internal renderer --- .../blender/render/intern/raytrace/rayobject.cpp | 66 +++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index 2104315dc00..3415e5268de 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -138,6 +138,68 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN /* Ray Triangle/Quad Intersection */ +static bool isect_ray_tri_watertight_no_sign_check_v3( + const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc, + const float v0[3], const float v1[3], const float v2[3], + float *r_lambda, float r_uv[2]) +{ + const int kx = isect_precalc->kx; + const int ky = isect_precalc->ky; + const int kz = isect_precalc->kz; + const float sx = isect_precalc->sx; + const float sy = isect_precalc->sy; + const float sz = isect_precalc->sz; + + /* Calculate vertices relative to ray origin. */ + const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]}; + const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]}; + const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]}; + + const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz]; + const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz]; + const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz]; + + /* Perform shear and scale of vertices. */ + const float ax = a_kx - sx * a_kz; + const float ay = a_ky - sy * a_kz; + const float bx = b_kx - sx * b_kz; + const float by = b_ky - sy * b_kz; + const float cx = c_kx - sx * c_kz; + const float cy = c_ky - sy * c_kz; + + /* Calculate scaled barycentric coordinates. */ + const float u = cx * by - cy * bx; + const float v = ax * cy - ay * cx; + const float w = bx * ay - by * ax; + float det; + + if ((u < 0.0f || v < 0.0f || w < 0.0f) && + (u > 0.0f || v > 0.0f || w > 0.0f)) + { + return false; + } + + /* Calculate determinant. */ + det = u + v + w; + if (UNLIKELY(det == 0.0f)) { + return false; + } + else { + /* Calculate scaled z-coordinates of vertices and use them to calculate + * the hit distance. + */ + const float t = (u * a_kz + v * b_kz + w * c_kz) * sz; + /* Normalize u, v and t. */ + const float inv_det = 1.0f / det; + if (r_uv) { + r_uv[0] = u * inv_det; + r_uv[1] = v * inv_det; + } + *r_lambda = t * inv_det; + return true; + } +} + MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda) { float uv[2], l; @@ -181,13 +243,13 @@ MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace isect_ray_tri_watertight_v3_precalc(&isect_precalc, r); - if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { + if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { return 1; } /* intersect second triangle in quad */ if (RE_rayface_isQuad(face)) { - if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { + if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { return 2; } } -- cgit v1.2.3 From eb5cd578b8cb9839b4b1fb8b6e9f56bbaad7bfae Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 23 Aug 2016 15:56:10 +0200 Subject: Cleanup: Output argument name and const qualifier --- source/blender/render/intern/raytrace/rayobject.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'source') diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index 3415e5268de..c16ef5500df 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -200,16 +200,19 @@ static bool isect_ray_tri_watertight_no_sign_check_v3( } } -MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda) +MALWAYS_INLINE int isec_tri_quad(const float start[3], + const struct IsectRayPrecalc *isect_precalc, + const RayFace *face, + float r_uv[2], float *r_lambda) { float uv[2], l; if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { /* check if intersection is within ray length */ - if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { + if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) { r_uv[0] = -uv[0]; r_uv[1] = -uv[1]; - *lambda = l; + *r_lambda = l; return 1; } } @@ -218,10 +221,10 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i if (RE_rayface_isQuad(face)) { if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { /* check if intersection is within ray length */ - if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { + if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) { r_uv[0] = -uv[0]; r_uv[1] = -uv[1]; - *lambda = l; + *r_lambda = l; return 2; } } @@ -232,13 +235,14 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i /* Simpler yes/no Ray Triangle/Quad Intersection */ -MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face) +MALWAYS_INLINE int isec_tri_quad_neighbour(const float start[3], + const float dir[3], + const RayFace *face) { float r[3]; struct IsectRayPrecalc isect_precalc; float uv[2], l; - negate_v3_v3(r, dir); /* note, different than above function */ isect_ray_tri_watertight_v3_precalc(&isect_precalc, r); -- 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') 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 22b913a27881b9bb8c4cb1738c803c8089ca0393 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 24 Aug 2016 10:19:44 +0200 Subject: Fix T49121: VSE and border render incompatible For now just check for such incompatible configuration, real fix requires quite some work to be done. --- source/blender/render/intern/source/pipeline.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'source') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index ec629aa2863..9f1ae4a96e0 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3059,6 +3059,13 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList * } #endif + if (RE_seq_render_active(scene, &scene->r)) { + if (scene->r.mode & R_BORDER) { + BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer"); + return false; + } + } + /* layer flag tests */ if (!render_scene_has_layers_to_render(scene)) { BKE_report(reports, RPT_ERROR, "All render layers are disabled"); -- cgit v1.2.3 From 262adf7d912c8086c2a040120915d5ee72eabeb6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 24 Aug 2016 11:00:21 +0200 Subject: Fix T49130: "Inner Edge" / "Buffer Edge" options in the Double Edge Mask are wired to the wrong settings Patch by Ted Schundler (tschundler), thanks! Differential Revision: https://developer.blender.org/D2141 --- source/blender/makesrna/intern/rna_nodetree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 2f9e6741677..a37fe049e72 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5391,13 +5391,13 @@ static void def_cmp_double_edge_mask(StructRNA *srna) }; prop = RNA_def_property(srna, "inner_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "custom2"); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, InnerEdgeMode_items); RNA_def_property_ui_text(prop, "Inner Edge Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "edge_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_sdna(prop, NULL, "custom2"); RNA_def_property_enum_items(prop, BufEdgeMode_items); RNA_def_property_ui_text(prop, "Buffer Edge Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); -- cgit v1.2.3 From 389b4feec16e8fba071fd890eef107ce207a76ff Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 24 Aug 2016 11:20:13 +0200 Subject: Fix T49128: Ghost of Previous Mask appears in Double Edge Mask Patch by Ted Schundler (tschundler), thanks! Differential Revision: https://developer.blender.org/D2163 --- .../blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp index 76afedf4b2a..ca3c5f7b069 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp @@ -20,6 +20,8 @@ * Monique Dewanchand */ +#include + #include "COM_DoubleEdgeMaskOperation.h" #include "BLI_math.h" #include "DNA_node_types.h" @@ -1151,12 +1153,13 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float if (true) { // if both input sockets have some data coming in... - t = (this->getWidth() * this->getHeight()) - 1; // determine size of the frame + rw = this->getWidth(); // width of a row of pixels + t = (rw * this->getHeight()) - 1; // determine size of the frame + memset(res, 0, sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later) lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops) limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops) lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops) - rw = this->getWidth(); // width of a row of pixels /* -- 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') 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 3c533be77ea8f6c88b188eb870bb46ba972d1372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 25 Aug 2016 05:19:41 +0200 Subject: Fix T49112: Alembic unicode path issues on Windows. Now we pass streams to Alembic instead of passing the filename string. That way we can open the stream ourselves with the proper unicode encoding. Note that this only applies to Ogawa archive, as HDF5 does not support streams. Differential Revision: https://developer.blender.org/D2160 --- source/blender/alembic/CMakeLists.txt | 1 + source/blender/alembic/intern/abc_exporter.cc | 85 ++++++++++++++---- source/blender/alembic/intern/abc_exporter.h | 2 + source/blender/alembic/intern/alembic_capi.cc | 125 ++++++++++++++++++-------- 4 files changed, 160 insertions(+), 53 deletions(-) (limited to 'source') diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt index 42bd6a9c340..0b6b2433bd0 100644 --- a/source/blender/alembic/CMakeLists.txt +++ b/source/blender/alembic/CMakeLists.txt @@ -33,6 +33,7 @@ set(INC ../makesrna ../windowmanager ../../../intern/guardedalloc + ../../../intern/utfconv ) set(INC_SYS diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index 2e9f429f887..764b1533309 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -30,6 +30,10 @@ #include +#ifdef WIN32 +# include "utfconv.h" +#endif + #include "abc_camera.h" #include "abc_curves.h" #include "abc_hair.h" @@ -67,6 +71,54 @@ extern "C" { using Alembic::Abc::TimeSamplingPtr; using Alembic::Abc::OBox3dProperty; + +/* ************************************************************************** */ + +/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to + * have a version supporting streams. */ +static Alembic::Abc::OArchive create_archive(std::ostream *ostream, + const std::string &filename, + const std::string &scene_name, + const Alembic::Abc::Argument &arg0, + const Alembic::Abc::Argument &arg1, + bool ogawa) +{ + Alembic::Abc::MetaData md = GetMetaData(arg0, arg1); + md.set(Alembic::Abc::kApplicationNameKey, "Blender"); + md.set(Alembic::Abc::kUserDescriptionKey, scene_name); + + time_t raw_time; + time(&raw_time); + char buffer[128]; + +#if defined _WIN32 || defined _WIN64 + ctime_s(buffer, 128, &raw_time); +#else + ctime_r(&raw_time, buffer); +#endif + + const std::size_t buffer_len = strlen(buffer); + if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { + buffer[buffer_len - 1] = '\0'; + } + + md.set(Alembic::Abc::kDateWrittenKey, buffer); + + Alembic::Abc::ErrorHandler::Policy policy = GetErrorHandlerPolicyFromArgs(arg0, arg1); + +#ifdef WITH_ALEMBIC_HDF5 + if (!ogawa) { + return Alembic::Abc::OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, md, policy); + } +#else + static_cast(filename); + static_cast(ogawa); +#endif + + Alembic::AbcCoreOgawa::WriteArchive archive_writer; + return Alembic::Abc::OArchive(archive_writer(ostream, md), Alembic::Abc::kWrapExisting, policy); +} + /* ************************************************************************** */ ExportSettings::ExportSettings() @@ -247,26 +299,25 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) Alembic::Abc::Argument arg(md); -#ifdef WITH_ALEMBIC_HDF5 - if (!m_settings.export_ogawa) { - m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(), - m_filename, - "Blender", - scene_name, - Alembic::Abc::ErrorHandler::kThrowPolicy, - arg); - } - else + /* Use stream to support unicode character paths on Windows. */ + if (m_settings.export_ogawa) { +#ifdef WIN32 + UTF16_ENCODE(m_filename); + std::wstring wstr(m_filename_16); + m_out_file.open(wstr.c_str(), std::ios::out | std::ios::binary); + UTF16_UN_ENCODE(m_filename); +#else + m_out_file.open(m_filename, std::ios::out | std::ios::binary); #endif - { - m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(), - m_filename, - "Blender", - scene_name, - Alembic::Abc::ErrorHandler::kThrowPolicy, - arg); } + m_archive = create_archive(&m_out_file, + m_filename, + scene_name, + Alembic::Abc::ErrorHandler::kThrowPolicy, + arg, + m_settings.export_ogawa); + /* Create time samplings for transforms and shapes. */ TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform); diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index 070eb9ea81a..6c242f973c4 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -24,6 +24,7 @@ #define __ABC_EXPORTER_H__ #include +#include #include #include #include @@ -75,6 +76,7 @@ class AbcExporter { const char *m_filename; + std::ofstream m_out_file; Alembic::Abc::OArchive m_archive; unsigned int m_trans_sampling_index, m_shape_sampling_index; diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index f42c708b4c2..d057cc341f6 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -29,6 +29,12 @@ #include #include +#include + +#ifdef WIN32 +# include "utfconv.h" +#endif + #include "abc_camera.h" #include "abc_curves.h" #include "abc_hair.h" @@ -109,49 +115,97 @@ using Alembic::AbcGeom::V3fArraySamplePtr; using Alembic::AbcMaterial::IMaterial; -struct AbcArchiveHandle { - int unused; -}; - -ABC_INLINE IArchive *archive_from_handle(AbcArchiveHandle *handle) -{ - return reinterpret_cast(handle); -} - -ABC_INLINE AbcArchiveHandle *handle_from_archive(IArchive *archive) +static IArchive open_archive(const std::string &filename, + const std::vector &input_streams, + bool &is_hdf5) { - return reinterpret_cast(archive); -} - -static IArchive *open_archive(const std::string &filename) -{ - Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr; - IArchive *archive; - try { - archive = new IArchive(Alembic::AbcCoreOgawa::ReadArchive(), - filename.c_str(), ErrorHandler::kThrowPolicy, - cache_ptr); + is_hdf5 = false; + Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams); + + return IArchive(archive_reader(filename), + kWrapExisting, + ErrorHandler::kThrowPolicy); } catch (const Exception &e) { std::cerr << e.what() << '\n'; #ifdef WITH_ALEMBIC_HDF5 try { - archive = new IArchive(Alembic::AbcCoreHDF5::ReadArchive(), - filename.c_str(), ErrorHandler::kThrowPolicy, - cache_ptr); + is_hdf5 = true; + Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr; + + return IArchive(Alembic::AbcCoreHDF5::ReadArchive(), + filename.c_str(), ErrorHandler::kThrowPolicy, + cache_ptr); } catch (const Exception &) { std::cerr << e.what() << '\n'; - return NULL; + return IArchive(); } #else - return NULL; + return IArchive(); #endif } - return archive; + return IArchive(); +} + +/* Wrapper around an archive to be able to use streams so that unicode paths + * work on Windows (T49112), and to make sure the input stream remains valid as + * long as the archive is open. */ +class ArchiveWrapper { + IArchive m_archive; + std::ifstream m_infile; + std::vector m_streams; + +public: + explicit ArchiveWrapper(const char *filename) + { +#ifdef WIN32 + UTF16_ENCODE(filename); + std::wstring wstr(filename_16); + m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary); + UTF16_UN_ENCODE(filename); +#else + m_infile.open(filename, std::ios::in | std::ios::binary); +#endif + + m_streams.push_back(&m_infile); + + bool is_hdf5; + m_archive = open_archive(filename, m_streams, is_hdf5); + + /* We can't open an HDF5 file from a stream, so close it. */ + if (is_hdf5) { + m_infile.close(); + m_streams.clear(); + } + } + + bool valid() const + { + return m_archive.valid(); + } + + IObject getTop() + { + return m_archive.getTop(); + } +}; + +struct AbcArchiveHandle { + int unused; +}; + +ABC_INLINE ArchiveWrapper *archive_from_handle(AbcArchiveHandle *handle) +{ + return reinterpret_cast(handle); +} + +ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveWrapper *archive) +{ + return reinterpret_cast(archive); } //#define USE_NURBS @@ -247,9 +301,10 @@ static void gather_objects_paths(const IObject &object, ListBase *object_paths) AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths) { - IArchive *archive = open_archive(filename); + ArchiveWrapper *archive = new ArchiveWrapper(filename); - if (!archive) { + if (!archive->valid()) { + delete archive; return NULL; } @@ -582,12 +637,10 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa data->do_update = do_update; data->progress = progress; - IArchive *archive = open_archive(data->filename); + ArchiveWrapper *archive = new ArchiveWrapper(data->filename); - if (!archive || !archive->valid()) { - if (archive) { - delete archive; - } + if (!archive->valid()) { + delete archive; data->error_code = ABC_ARCHIVE_FAIL; return; } @@ -812,7 +865,7 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale) { - IArchive *archive = archive_from_handle(handle); + ArchiveWrapper *archive = archive_from_handle(handle); if (!archive || !archive->valid()) { return; @@ -1088,7 +1141,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, const char **err_str, int read_flag) { - IArchive *archive = archive_from_handle(handle); + ArchiveWrapper *archive = archive_from_handle(handle); if (!archive || !archive->valid()) { *err_str = "Invalid archive!"; -- 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') 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 eb2cfc3a25513a7234e407978c7db984d7646351 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 25 Aug 2016 15:12:21 +0200 Subject: Depsgrpah: Use deque for the flush queue The idea of the change is to avoid queue growing too long and handle all the operations as quick as possible. Gives about 3% speedup on one of the barber shots here. --- source/blender/depsgraph/intern/eval/deg_eval_flush.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index f9e1504b3ce..98d8c60f012 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -33,7 +33,7 @@ #include "intern/eval/deg_eval_flush.h" // TODO(sergey): Use some sort of wrapper. -#include +#include extern "C" { #include "DNA_object_types.h" @@ -71,7 +71,7 @@ void lib_id_recalc_data_tag(Main *bmain, ID *id) } /* namespace */ -typedef std::queue FlushQueue; +typedef std::deque FlushQueue; static void flush_init_func(void *data_v, int i) { @@ -122,14 +122,14 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) */ GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags) { - queue.push(node); + queue.push_back(node); node->scheduled = true; } GSET_FOREACH_END(); while (!queue.empty()) { OperationDepsNode *node = queue.front(); - queue.pop(); + queue.pop_front(); for (;;) { node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; @@ -154,7 +154,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) foreach (DepsRelation *rel, node->outlinks) { OperationDepsNode *to_node = (OperationDepsNode *)rel->to; if (to_node->scheduled == false) { - queue.push(to_node); + queue.push_front(to_node); to_node->scheduled = true; } } -- cgit v1.2.3 From 84be763be299572eb98a7fbf3b87c27408c57984 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 25 Aug 2016 15:51:19 +0200 Subject: Depsgraph: Merge some traversal back on After previous commit there is no longer measurable difference in speed and doing all stuff in one go is preferrable here anyway. --- .../depsgraph/intern/eval/deg_eval_flush.cc | 82 ++++++++++------------ 1 file changed, 36 insertions(+), 46 deletions(-) (limited to 'source') diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 98d8c60f012..a7418ac2c11 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -136,6 +136,42 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) ComponentDepsNode *comp_node = node->owner; IDDepsNode *id_node = comp_node->owner; + + ID *id = id_node->id; + if(id_node->done == 0) { + deg_editors_id_update(bmain, id); + lib_id_recalc_tag(bmain, id); + /* TODO(sergey): For until we've got proper data nodes in the graph. */ + lib_id_recalc_data_tag(bmain, id); + } + + if(comp_node->done == 0) { + Object *object = NULL; + if (GS(id->name) == ID_OB) { + object = (Object *)id; + } + foreach (OperationDepsNode *op, comp_node->operations) { + op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + } + if (object != NULL) { + /* This code is used to preserve those areas which does + * direct object update, + * + * Plus it ensures visibility changes and relations and + * layers visibility update has proper flags to work with. + */ + if (comp_node->type == DEPSNODE_TYPE_ANIMATION) { + object->recalc |= OB_RECALC_TIME; + } + else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) { + object->recalc |= OB_RECALC_OB; + } + else { + object->recalc |= OB_RECALC_DATA; + } + } + } + id_node->done = 1; comp_node->done = 1; @@ -162,52 +198,6 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) } } } - - GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash) - { - if (id_node->done == 1) { - ID *id = id_node->id; - Object *object = NULL; - - if (GS(id->name) == ID_OB) { - object = (Object *)id; - } - - deg_editors_id_update(bmain, id_node->id); - - lib_id_recalc_tag(bmain, id_node->id); - /* TODO(sergey): For until we've got proper data nodes in the graph. */ - lib_id_recalc_data_tag(bmain, id_node->id); - - GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp_node, id_node->components) - { - if (comp_node->done) { - foreach (OperationDepsNode *op, comp_node->operations) { - op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - } - if (object != NULL) { - /* This code is used to preserve those areas which does - * direct object update, - * - * Plus it ensures visibility changes and relations and - * layers visibility update has proper flags to work with. - */ - if (comp_node->type == DEPSNODE_TYPE_ANIMATION) { - object->recalc |= OB_RECALC_TIME; - } - else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) { - object->recalc |= OB_RECALC_OB; - } - else { - object->recalc |= OB_RECALC_DATA; - } - } - } - } - GHASH_FOREACH_END(); - } - } - GHASH_FOREACH_END(); } static void graph_clear_func(void *data_v, int i) -- cgit v1.2.3 From 9444cd56db1a4e43d03fa8c735cd893b2e74b913 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 25 Aug 2016 16:08:41 +0200 Subject: Depsgraph: Prioritize evaluation of the new scheduled nodes The idea here is again to finish objects evaluation as soon as possible. Seems to be giving another 3% speedup in the barber scenes. --- source/blender/depsgraph/intern/eval/deg_eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index c3fd202d832..f8cca5393e2 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -304,7 +304,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers, deg_task_run_func, node, false, - TASK_PRIORITY_LOW, + TASK_PRIORITY_HIGH, thread_id); } } -- cgit v1.2.3 From 2d1f522a74a8637c9cc64509ed26be6d014e5871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 25 Aug 2016 16:22:26 +0200 Subject: Fixed little error in comment "amount" is for uncountable things, "number" is for countable things. --- source/blender/blenloader/intern/writefile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index b6a54715763..dbc67d30b35 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -49,7 +49,7 @@ * int, len data after BHead * void, old pointer * int - * int, in case of array: amount of structs + * int, in case of array: number of structs * data * ... * ... -- cgit v1.2.3 From 56360a3ddf5cb2f10b2613dfa0e5d7bb77d4891d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 26 Aug 2016 15:59:38 +1200 Subject: GPencil RNA: Set pressure and strength to 1.0 by default for new stroke points added via stroke.points.add() This commit adds optional "pressure" and "strength" arguments to the stroke.points.add() method. These are given default values of 1.0, so that old scripts can be ported over to the new API with less effort while reducing confusion about why auto generated strokes won't appear. --- source/blender/makesrna/intern/rna_gpencil.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 3ecaec75c77..167e1e93976 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -439,12 +439,23 @@ static void rna_GPencil_stroke_point_select_set(PointerRNA *ptr, const int value } } -static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count) +static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pressure, float strength) { if (count > 0) { + /* create space at the end of the array for extra points */ stroke->points = MEM_recallocN_id(stroke->points, sizeof(bGPDspoint) * (stroke->totpoints + count), "gp_stroke_points"); + + /* init the pressure and strength values so that old scripts won't need to + * be modified to give these initial values... + */ + for (int i = 0; i < count; i++) { + bGPDspoint *pt = stroke->points + (stroke->totpoints + i); + pt->pressure = pressure; + pt->strength = strength; + } + stroke->totpoints += count; } } @@ -890,7 +901,7 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr StructRNA *srna; FunctionRNA *func; - /* PropertyRNA *parm; */ + PropertyRNA *parm; RNA_def_property_srna(cprop, "GPencilStrokePoints"); srna = RNA_def_struct(brna, "GPencilStrokePoints", NULL); @@ -900,6 +911,8 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr func = RNA_def_function(srna, "add", "rna_GPencil_stroke_point_add"); RNA_def_function_ui_description(func, "Add a new grease pencil stroke point"); RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the stroke", 0, INT_MAX); + RNA_def_float(func, "pressure", 1.0f, 0.0f, 1.0f, "Pressure", "Pressure for newly created points", 0.0f, 1.0f); + RNA_def_float(func, "strength", 1.0f, 0.0f, 1.0f, "Strength", "Color intensity (alpha factor) for newly created points", 0.0f, 1.0f); func = RNA_def_function(srna, "pop", "rna_GPencil_stroke_point_pop"); RNA_def_function_ui_description(func, "Remove a grease pencil stroke point"); -- 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') 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') 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') 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 a80977cd213d1a158f4292b9809c85a5b2a7a699 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 26 Aug 2016 12:54:49 +0200 Subject: Fix T49139: Memory leak in UV image editor related to Undo (and possibly Waveform and Vectorscope). Assigning NULL to scopes' data pointer in 'non-UI readfile' context was terribly wrong for sure, if we'd really want to reset them here we should freed them first. But we can rather just ignore them here, those are purely runtime data managed by image editor, no need to touch them here. --- source/blender/blenloader/intern/readfile.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index ded60af4af2..7d65dbc2e17 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6697,10 +6697,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc * since it gets initialized later */ sima->iuser.scene = NULL; - sima->scopes.waveform_1 = NULL; - sima->scopes.waveform_2 = NULL; - sima->scopes.waveform_3 = NULL; - sima->scopes.vecscope = NULL; +#if 0 + /* Those are allocated and freed by space code, no need to handle them here. */ + MEM_SAFE_FREE(sima->scopes.waveform_1); + MEM_SAFE_FREE(sima->scopes.waveform_2); + MEM_SAFE_FREE(sima->scopes.waveform_3); + MEM_SAFE_FREE(sima->scopes.vecscope); +#endif sima->scopes.ok = 0; /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data -- cgit v1.2.3 From 86e0485b2e5e02bbe5465e051afebea9e7838605 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 26 Aug 2016 13:57:46 +0200 Subject: Cleanup: Use more meaningful names and move calculation into am if statement --- source/blender/blenkernel/intern/armature_update.c | 6 +++--- source/blender/blenkernel/intern/scene.c | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index aebd564ca58..3bc81a69c86 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -617,9 +617,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), /* pass */ } else { - /* TODO(sergey): Use time source node for time. */ - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ if ((pchan->flag & POSE_DONE) == 0) { + /* TODO(sergey): Use time source node for time. */ + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); } } @@ -641,8 +641,8 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), /* IK are being solved separately/ */ } else { - float ctime = BKE_scene_frame_get(scene); /* not accurate... */ if ((pchan->flag & POSE_DONE) == 0) { + float ctime = BKE_scene_frame_get(scene); /* not accurate... */ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index e610c56b28f..847884e08b7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1561,8 +1561,8 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state) tot_thread = BLI_system_thread_count(); for (i = 0; i < tot_thread; i++) { - int total_objects = 0; - double total_time = 0.0; + int thread_total_objects = 0; + double thread_total_time = 0.0; StatisicsEntry *entry; if (state->has_updated_objects) { @@ -1571,11 +1571,14 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state) entry; entry = entry->next) { - total_objects++; - total_time += entry->duration; + thread_total_objects++; + thread_total_time += entry->duration; } - printf("Thread %d: total %d objects in %f sec.\n", i, total_objects, total_time); + printf("Thread %d: total %d objects in %f sec.\n", + i, + thread_total_objects, + thread_total_time); for (entry = state->statistics[i].first; entry; -- cgit v1.2.3 From 5f1b580edc8938b7a4aca08c928c33f915ef5e64 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 26 Aug 2016 14:00:15 +0200 Subject: Depsgraph: Report overall number of updates objects --- source/blender/blenkernel/intern/scene.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 847884e08b7..acf6a313989 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1559,6 +1559,7 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state) #else finish_time = PIL_check_seconds_timer(); tot_thread = BLI_system_thread_count(); + int total_objects = 0; for (i = 0; i < tot_thread; i++) { int thread_total_objects = 0; @@ -1586,12 +1587,16 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state) { printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration); } + + total_objects += thread_total_objects; } BLI_freelistN(&state->statistics[i]); } if (state->has_updated_objects) { - printf("Scene update in %f sec\n", finish_time - state->base_time); + printf("Scene updated %d objects in %f sec\n", + total_objects, + finish_time - state->base_time); } #endif } -- cgit v1.2.3 From 72b24d9c6c24152b28570f1a8d106726948c6b3d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 26 Aug 2016 14:01:03 +0200 Subject: Cleanup: Remove unused variable --- source/blender/makesrna/intern/rna_gpencil.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 167e1e93976..7eaf8b65902 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -899,9 +899,7 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna) static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; - FunctionRNA *func; - PropertyRNA *parm; RNA_def_property_srna(cprop, "GPencilStrokePoints"); srna = RNA_def_struct(brna, "GPencilStrokePoints", NULL); -- cgit v1.2.3 From 1ada3231ecf4a16c14ceedf46ff10d0478929e23 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 26 Aug 2016 14:04:03 +0200 Subject: Depsgraph: Report number of objects to which update as flished This is an easiest way in the new depsgraph to get an idea how much objects were handled on update. --- source/blender/depsgraph/intern/eval/deg_eval_flush.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source') diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index a7418ac2c11..7c6c25bef0d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -127,6 +127,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) } GSET_FOREACH_END(); + int num_flushed_objects = 0; while (!queue.empty()) { OperationDepsNode *node = queue.front(); queue.pop_front(); @@ -149,6 +150,9 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) Object *object = NULL; if (GS(id->name) == ID_OB) { object = (Object *)id; + if(id_node->done == 0) { + ++num_flushed_objects; + } } foreach (OperationDepsNode *op, comp_node->operations) { op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; @@ -198,6 +202,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) } } } + DEG_DEBUG_PRINTF("Update flushed to %d objects\n", num_flushed_objects); } static void graph_clear_func(void *data_v, int i) -- cgit v1.2.3 From f2f107572cc3c2061b535e46f6a0d3571c555957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 26 Aug 2016 14:21:06 +0200 Subject: Fix T49168: crash when evaluating a cache constraint with a NULL cache file. --- source/blender/blenkernel/intern/constraint.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 70fdd4aa72e..116c75721af 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4353,11 +4353,15 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa bTransformCacheConstraint *data = con->data; Scene *scene = cob->scene; - const float frame = BKE_scene_frame_get(scene); - const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS); - CacheFile *cache_file = data->cache_file; + if (!cache_file) { + return; + } + + const float frame = BKE_scene_frame_get(scene); + const float time = BKE_cachefile_time_offset(cache_file, frame, FPS); + BKE_cachefile_ensure_handle(G.main, cache_file); ABC_get_transform(cache_file->handle, cob->ob, data->object_path, @@ -4391,6 +4395,13 @@ static void transformcache_free(bConstraint *con) } } +static void transformcache_new_data(void *cdata) +{ + bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata; + + data->cache_file = NULL; +} + static bConstraintTypeInfo CTI_TRANSFORM_CACHE = { CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */ sizeof(bTransformCacheConstraint), /* size */ @@ -4399,7 +4410,7 @@ static bConstraintTypeInfo CTI_TRANSFORM_CACHE = { transformcache_free, /* free data */ transformcache_id_looper, /* id looper */ transformcache_copy, /* copy data */ - NULL, /* new data */ + transformcache_new_data, /* new data */ NULL, /* get constraint targets */ NULL, /* flush constraint targets */ NULL, /* get target matrix */ -- cgit v1.2.3 From 8870c454a1aa9cd8a0547d533fc0d7fc2a048ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 26 Aug 2016 14:21:59 +0200 Subject: Fix cache constraint not reference counting cache files. --- source/blender/blenkernel/intern/constraint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 116c75721af..c4afa58b7d3 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4344,7 +4344,7 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = { static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) { bTransformCacheConstraint *data = con->data; - func(con, (ID **)&data->cache_file, false, userdata); + func(con, (ID **)&data->cache_file, true, userdata); } static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) -- cgit v1.2.3 From 62b1cdd66e39db58e422e15b20a80d5e05f3dd4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 26 Aug 2016 14:25:03 +0200 Subject: Fix over creation of cache files handles (leading to memory leaks). Multiple threads could create multiple handles for the same cache file, so protect handle creation with a mutex, to make sure only one is created. --- source/blender/blenkernel/BKE_cachefile.h | 2 ++ source/blender/blenkernel/intern/cachefile.c | 20 ++++++++++++++++++++ source/blender/blenloader/intern/readfile.c | 2 ++ source/blender/makesdna/DNA_cachefile_types.h | 1 + source/creator/creator.c | 2 ++ 5 files changed, 27 insertions(+) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index 51b161f1a06..7a9744ef9d6 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -38,6 +38,8 @@ struct CacheFile; struct Main; struct Scene; +void BKE_cachefiles_init(void); + void *BKE_cachefile_add(struct Main *bmain, const char *name); void BKE_cachefile_init(struct CacheFile *cache_file); diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 16f263791db..502f1d53ab2 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -35,6 +35,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BKE_animsys.h" @@ -48,6 +49,13 @@ # include "ABC_alembic.h" #endif +static SpinLock spin; + +void BKE_cachefiles_init(void) +{ + BLI_spin_init(&spin); +} + void *BKE_cachefile_add(Main *bmain, const char *name) { CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name); @@ -65,6 +73,7 @@ void BKE_cachefile_init(CacheFile *cache_file) cache_file->frame = 0.0f; cache_file->is_sequence = false; cache_file->scale = 1.0f; + cache_file->handle_mutex = BLI_mutex_alloc(); } /** Free (or release) any data used by this cachefile (does not free the cachefile itself). */ @@ -76,6 +85,7 @@ void BKE_cachefile_free(CacheFile *cache_file) ABC_free_handle(cache_file->handle); #endif + BLI_mutex_free(cache_file->handle_mutex); BLI_freelistN(&cache_file->object_paths); } @@ -114,9 +124,19 @@ void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file) void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file) { + BLI_spin_lock(&spin); + if (cache_file->handle_mutex == NULL) { + cache_file->handle_mutex = BLI_mutex_alloc(); + } + BLI_spin_unlock(&spin); + + BLI_mutex_lock(cache_file->handle_mutex); + if (cache_file->handle == NULL) { BKE_cachefile_reload(bmain, cache_file); } + + BLI_mutex_unlock(cache_file->handle_mutex); } void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 7d65dbc2e17..f5bfe1f4de6 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2707,6 +2707,7 @@ static void lib_link_cachefiles(FileData *fd, Main *bmain) BLI_listbase_clear(&cache_file->object_paths); cache_file->handle = NULL; + cache_file->handle_mutex = NULL; if (cache_file->adt) { lib_link_animdata(fd, &cache_file->id, cache_file->adt); @@ -2717,6 +2718,7 @@ static void lib_link_cachefiles(FileData *fd, Main *bmain) static void direct_link_cachefile(FileData *fd, CacheFile *cache_file) { cache_file->handle = NULL; + cache_file->handle_mutex = NULL; /* relink animdata */ cache_file->adt = newdataadr(fd, cache_file->adt); diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index 1cda0233aa8..dd47d63fc19 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -58,6 +58,7 @@ typedef struct CacheFile { struct AnimData *adt; struct AbcArchiveHandle *handle; + void *handle_mutex; /* Paths of the objects inside of the Alembic archive referenced by this * CacheFile. */ diff --git a/source/creator/creator.c b/source/creator/creator.c index bfb1dd94dd4..a59a45f885c 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -54,6 +54,7 @@ #include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_brush.h" +#include "BKE_cachefile.h" #include "BKE_context.h" #include "BKE_depsgraph.h" /* for DAG_init */ #include "BKE_font.h" @@ -357,6 +358,7 @@ int main( BKE_blender_globals_init(); /* blender.c */ IMB_init(); + BKE_cachefiles_init(); BKE_images_init(); BKE_modifier_init(); DAG_init(); -- cgit v1.2.3 From e9c5359f43b8fdc825a6dd55ea41bd1b52216bda Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 26 Aug 2016 16:14:56 +0200 Subject: Usual i18n/UI messages fixes... --- source/blender/makesrna/intern/rna_curve.c | 2 +- source/blender/makesrna/intern/rna_linestyle.c | 10 ++++++---- source/blender/makesrna/intern/rna_tracking.c | 2 +- source/blender/makesrna/intern/rna_wm.c | 6 +++--- 4 files changed, 11 insertions(+), 9 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index fb4ff6f4856..f4fb30e0793 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -1273,7 +1273,7 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_srna(cprop, "SplineBezierPoints"); srna = RNA_def_struct(brna, "SplineBezierPoints", NULL); RNA_def_struct_sdna(srna, "Nurb"); - RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline bezirt points"); + RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline Bezier points"); func = RNA_def_function(srna, "add", "rna_Curve_spline_bezpoints_add"); RNA_def_function_ui_description(func, "Add a number of points to this spline"); diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index d8cc61bf906..9b28009d161 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -1499,14 +1499,15 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA RNA_def_property_srna(cprop, "LineStyleThicknessModifiers"); srna = RNA_def_struct(brna, "LineStyleThicknessModifiers", NULL); RNA_def_struct_sdna(srna, "FreestyleLineStyle"); - RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thicknesss"); + RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thickness"); func = RNA_def_function(srna, "new", "rna_LineStyle_thickness_modifier_add"); RNA_def_function_ui_description(func, "Add a thickness modifier to line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "name", "ThicknessModifier", 0, "", "New name for the thickness modifier (not unique)"); RNA_def_property_flag(parm, PROP_REQUIRED); - parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, "", "Thickness modifier type to add"); + parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, + "", "Thickness modifier type to add"); RNA_def_property_flag(parm, PROP_REQUIRED); parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier"); RNA_def_function_return(func, parm); @@ -1528,14 +1529,15 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA * RNA_def_property_srna(cprop, "LineStyleGeometryModifiers"); srna = RNA_def_struct(brna, "LineStyleGeometryModifiers", NULL); RNA_def_struct_sdna(srna, "FreestyleLineStyle"); - RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometrys"); + RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometries"); func = RNA_def_function(srna, "new", "rna_LineStyle_geometry_modifier_add"); RNA_def_function_ui_description(func, "Add a geometry modifier to line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "name", "GeometryModifier", 0, "", "New name for the geometry modifier (not unique)"); RNA_def_property_flag(parm, PROP_REQUIRED); - parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, "", "Geometry modifier type to add"); + parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, + "", "Geometry modifier type to add"); RNA_def_property_flag(parm, PROP_REQUIRED); parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 6e41a7ad09a..2340345c1c6 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -2094,7 +2094,7 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_srna(cprop, "MovieTrackingObjects"); srna = RNA_def_struct(brna, "MovieTrackingObjects", NULL); RNA_def_struct_sdna(srna, "MovieTracking"); - RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie trackingobjects"); + RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie tracking objects"); func = RNA_def_function(srna, "new", "rna_trackingObject_new"); RNA_def_function_ui_description(func, "Add tracking object to this movie clip"); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index f97f194033c..90081a93188 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1935,15 +1935,15 @@ static void rna_def_wm_keyconfigs(BlenderRNA *brna, PropertyRNA *cprop) prop = RNA_def_property(srna, "addon", PROP_POINTER, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "addonconf"); RNA_def_property_struct_type(prop, "KeyConfig"); - RNA_def_property_ui_text(prop, "Addon Key Configuration", - "Key configuration that can be extended by addons, and is added to the active " + RNA_def_property_ui_text(prop, "Add-on Key Configuration", + "Key configuration that can be extended by add-ons, and is added to the active " "configuration when handling events"); prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "userconf"); RNA_def_property_struct_type(prop, "KeyConfig"); RNA_def_property_ui_text(prop, "User Key Configuration", - "Final key configuration that combines keymaps from the active and addon configurations, " + "Final key configuration that combines keymaps from the active and add-on configurations, " "and can be edited by the user"); RNA_api_keyconfigs(srna); -- cgit v1.2.3 From fef0cd81916f84b0efd9e059ac596c19e2627424 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 26 Aug 2016 20:29:40 +0200 Subject: Fix T49151: ParticleSettings' usercount not decremented when removing a psys from an object. --- source/blender/blenkernel/intern/particle.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source') diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 4fb302c71ea..aecaf8537bb 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3172,6 +3172,9 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob) /* clear particle system */ BLI_remlink(&ob->particlesystem, psys); + if (psys->part) { + id_us_min(&psys->part->id); + } psys_free(ob, psys); if (ob->particlesystem.first) -- 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') 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') 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 4ebfb700ba846fea5a50df99e409e25b86f711e2 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Sat, 27 Aug 2016 23:22:48 +0200 Subject: Fix missing viewport update changing BI lamp shadow method --- source/blender/makesrna/intern/rna_lamp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c index e4e3699f301..51709d3137c 100644 --- a/source/blender/makesrna/intern/rna_lamp.c +++ b/source/blender/makesrna/intern/rna_lamp.c @@ -546,7 +546,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, (spot) ? prop_spot_shadow_items : prop_shadow_items); - RNA_def_property_update(prop, 0, "rna_Lamp_update"); + RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); prop = RNA_def_property(srna, "shadow_buffer_size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "bufsize"); -- 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 +++++++++++++-------- source/blender/gpu/CMakeLists.txt | 2 + source/blender/gpu/intern/gpu_shader.c | 5 +- .../blender/gpu/shaders/gpu_shader_fire_frag.glsl | 17 ++ .../blender/gpu/shaders/gpu_shader_smoke_frag.glsl | 12 -- 5 files changed, 142 insertions(+), 87 deletions(-) create mode 100644 source/blender/gpu/shaders/gpu_shader_fire_frag.glsl (limited to 'source') 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) { diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index cfa083116f2..8885209ce01 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -78,6 +78,7 @@ set(SRC shaders/gpu_shader_vsm_store_frag.glsl shaders/gpu_shader_vsm_store_vert.glsl shaders/gpu_shader_fx_depth_resolve.glsl + shaders/gpu_shader_fire_frag.glsl shaders/gpu_shader_smoke_frag.glsl shaders/gpu_shader_smoke_vert.glsl @@ -99,6 +100,7 @@ set(SRC ) data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_smoke_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_material.glsl SRC) diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index df1213b01e2..5cfb323bc4b 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -45,6 +45,7 @@ #define MAX_EXT_DEFINE_LENGTH 1024 /* Non-generated shaders */ +extern char datatoc_gpu_shader_fire_frag_glsl[]; extern char datatoc_gpu_shader_smoke_vert_glsl[]; extern char datatoc_gpu_shader_smoke_frag_glsl[]; extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; @@ -618,8 +619,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) case GPU_SHADER_SMOKE_FIRE: if (!GG.shaders.smoke_fire) GG.shaders.smoke_fire = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, "#define USE_FIRE;\n", 0, 0, 0); + datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); retval = GG.shaders.smoke_fire; break; } diff --git a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl new file mode 100644 index 00000000000..3819203bcd9 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl @@ -0,0 +1,17 @@ + +varying vec3 coords; + +uniform sampler3D flame_texture; +uniform sampler1D spectrum_texture; + +void main() +{ + float flame = texture3D(flame_texture, coords).r; + vec4 emission = texture1D(spectrum_texture, flame); + + vec4 color; + color.rgb = emission.a * emission.rgb; + color.a = emission.a; + + gl_FragColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl index 4d1feb5c83e..fd790009e02 100644 --- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl @@ -8,11 +8,6 @@ uniform float density_scale; uniform sampler3D soot_texture; uniform sampler3D shadow_texture; -#ifdef USE_FIRE -uniform sampler3D flame_texture; -uniform sampler1D spectrum_texture; -#endif - void main() { /* compute color and density from volume texture */ @@ -37,12 +32,5 @@ void main() /* premultiply alpha */ vec4 color = vec4(soot_alpha * soot_color, soot_alpha); -#ifdef USE_FIRE - /* fire */ - float flame = texture3D(flame_texture, coords).r; - vec4 emission = texture1D(spectrum_texture, flame); - color.rgb += (1 - color.a) * emission.a * emission.rgb; -#endif - gl_FragColor = color; } -- 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') 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') 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') 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') 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') 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 195c7797e68ec99d8a4a6c396a74264d7d836189 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 29 Aug 2016 17:00:18 +1200 Subject: Fix: Some settings (e.g. "volumetric strokes") from old files were not getting correctly ported to GPv2 --- source/blender/blenloader/intern/versioning_270.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 49ef8baa184..0a36e7846fe 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1306,12 +1306,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* set color attributes */ copy_v4_v4(palcolor->color, gpl->color); copy_v4_v4(palcolor->fill, gpl->fill); - palcolor->flag = gpl->flag; + + if (gpl->flag & GP_LAYER_HIDE) palcolor->flag |= PC_COLOR_HIDE; + if (gpl->flag & GP_LAYER_LOCKED) palcolor->flag |= PC_COLOR_LOCKED; + if (gpl->flag & GP_LAYER_ONIONSKIN) palcolor->flag |= PC_COLOR_ONIONSKIN; + if (gpl->flag & GP_LAYER_VOLUMETRIC) palcolor->flag |= PC_COLOR_VOLUMETRIC; + if (gpl->flag & GP_LAYER_HQ_FILL) palcolor->flag |= PC_COLOR_HQ_FILL; + /* set layer opacity to 1 */ gpl->opacity = 1.0f; + /* set tint color */ ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f); - + + /* flush relevant layer-settings to strokes */ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* set stroke to palette and force recalculation */ @@ -1319,14 +1327,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) gps->palcolor = NULL; gps->flag |= GP_STROKE_RECALC_COLOR; gps->thickness = gpl->thickness; + /* set alpha strength to 1 */ for (int i = 0; i < gps->totpoints; i++) { gps->points[i].strength = 1.0f; } - } } } + /* set thickness to 0 (now it is a factor to override stroke thickness) */ gpl->thickness = 0.0f; } -- 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') 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') 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 a9f8e384f1b3335e8a87468fdb07678cd8b580fc Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 29 Aug 2016 13:03:50 +0200 Subject: Movie clip: Add missing animation data RNA declaration Was missing since the beginning of the days. --- source/blender/makesrna/intern/rna_movieclip.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index 19d78361019..15411f85ba3 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -347,6 +347,8 @@ static void rna_def_movieclip(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings"); RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings"); + + rna_def_animdata_common(srna); } void RNA_def_movieclip(BlenderRNA *brna) -- cgit v1.2.3 From 09dc8a7954a9ded72f5b3b30fcf7953be29301da Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 29 Aug 2016 13:09:03 +0200 Subject: Fix T49181: Movie clip animation lost when invoking action which reloads the clip Was a bug since the very beginning of movie clip animation support which was done on Feb 2012. --- source/blender/blenkernel/intern/movieclip.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 482015d3b26..6794a8e8f93 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1247,8 +1247,6 @@ static void free_buffers(MovieClip *clip) IMB_free_anim(clip->anim); clip->anim = NULL; } - - BKE_animdata_free((ID *) clip, false); } void BKE_movieclip_clear_cache(MovieClip *clip) @@ -1487,6 +1485,7 @@ void BKE_movieclip_free(MovieClip *clip) free_buffers(clip); BKE_tracking_free(&clip->tracking); + BKE_animdata_free((ID *) clip, false); } MovieClip *BKE_movieclip_copy(Main *bmain, MovieClip *clip) -- 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') 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') 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 5c04b4fdfb0c914889ddcf2202712e39e08d8946 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Mon, 29 Aug 2016 13:33:01 -0600 Subject: Fix T49196 --- source/gameengine/GamePlayer/ghost/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source') diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt index 6c09af33f9e..577e25d6198 100644 --- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt +++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt @@ -81,6 +81,10 @@ if(WIN32) blender_include_dirs(../../../../intern/utfconv) endif() +if(WITH_INPUT_NDOF) + add_definitions(-DWITH_INPUT_NDOF) +endif(WITH_INPUT_NDOF) + if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) endif() -- 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') 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') 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 062cf99fd1b5670df5818575ebf09a864e945a5d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 30 Aug 2016 10:29:53 +0200 Subject: Cleanup: Indentation --- source/blender/blenkernel/intern/library_remap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 1830ca0bd90..9b89a2fb807 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -875,8 +875,8 @@ void BKE_libblock_delete(Main *bmain, void *idv) BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); /* First tag all datablocks directly from target lib. - * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects). - * Avoids to have to loop twice. */ + * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects). + * Avoids to have to loop twice. */ for (i = 0; i < base_count; i++) { ListBase *lb = lbarray[i]; ID *id; -- cgit v1.2.3 From 47b87e1f3b5d52799024f5529b946837f390448e Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 29 Aug 2016 21:08:33 +0200 Subject: Usual i18n/UI messages fixes... --- source/blender/makesrna/intern/rna_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 98df12719d3..70c8f149554 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2291,7 +2291,7 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop) "rna_GPencilBrushes_index_get", "rna_GPencilBrushes_index_set", "rna_GPencilBrushes_index_range"); - RNA_def_property_ui_text(prop, "Active brush Index", "Index of active brush"); + RNA_def_property_ui_text(prop, "Active Brush Index", "Index of active brush"); } static void rna_def_transform_orientation(BlenderRNA *brna) -- 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') 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 43dcfcb27a30b98e13d1d7f516db618f4a306859 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 30 Aug 2016 12:12:12 +0200 Subject: Fix T49201: Mesh with OpenSubdiv subsurf and a texture disappears in Material viewport mode --- source/blender/gpu/intern/gpu_codegen.c | 2 +- source/blender/gpu/shaders/gpu_shader_geometry.glsl | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index c40bc8eaf27..211394e7932 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -877,7 +877,7 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) if (input->attribtype == CD_MTFACE) { BLI_dynstr_appendf( ds, - "\tINTERP_FACE_VARYING_2(var%d, " + "\tINTERP_FACE_VARYING_ATT_2(var%d, " "int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n", input->attribid, input->attribid); diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl index 6f063883e37..fe630dbeddb 100644 --- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl +++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl @@ -31,6 +31,18 @@ uniform int osd_fvar_count; tessCoord.t); \ } +#ifdef USE_NEW_SHADING +# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \ + { \ + vec2 tmp; \ + INTERP_FACE_VARYING_2(tmp, fvarOffset, tessCoord); \ + result = vec3(tmp, 0); \ + } +#else +# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \ + INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) +#endif + uniform samplerBuffer FVarDataBuffer; uniform isamplerBuffer FVarDataOffsetBuffer; -- cgit v1.2.3 From 959b06b3c85fc8a6df2b9983e016ee59e9491b64 Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Tue, 30 Aug 2016 17:15:26 +0300 Subject: Fix type mismatch causing the buffer overflow in D810 --- source/blender/gpu/shaders/gpu_shader_material.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 845a78720ba..119bfb61fec 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2185,11 +2185,11 @@ void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol) outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0)); } -void env_apply(vec4 col, vec4 hor, vec4 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol) +void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol) { vec3 vv = normalize(vm[2].xyz); float skyfac = 0.5 * (1.0 + dot(vn, -vv)); - outcol = col + f * mix(hor, zen, skyfac); + outcol = col + f * vec4(mix(hor, zen, skyfac), 0); } void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol) -- cgit v1.2.3 From a0cdebde115a7e9f5b217133432957f86539d29d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 30 Aug 2016 20:36:22 +0200 Subject: Fix bad usercount handling of materials in BKE_mesh_new_from_object(). Curves and meshes (when no modifier application required) would increase their material usercount twice. Not sure how/why it worked in previous code, but with new, stricter ID handling we need more careful check of ID 'ownership' handling. Reported by Sergey over IRC, thanks. --- source/blender/blenkernel/intern/mesh.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 733e9030056..c8e43ef388d 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2197,8 +2197,9 @@ Mesh *BKE_mesh_new_from_object( { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; - int render = settings == eModifierMode_Render, i; - int cage = !apply_modifiers; + bool render = settings == eModifierMode_Render, i; + bool cage = !apply_modifiers; + bool do_mat_id_us = true; /* perform the mesh extraction based on type */ switch (ob->type) { @@ -2268,6 +2269,12 @@ Mesh *BKE_mesh_new_from_object( BKE_mesh_texspace_copy_from_object(tmpmesh, ob); BKE_libblock_free_us(bmain, tmpobj); + + /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist() + * already transfers the ownership of materials from the temp copy of the Curve ID to the new + * Mesh ID, so we do not want to increase materials' usercount later. */ + do_mat_id_us = false; + break; } @@ -2315,8 +2322,11 @@ Mesh *BKE_mesh_new_from_object( if (cage) { /* copies the data */ tmpmesh = BKE_mesh_copy(bmain, ob->data); - /* if not getting the original caged mesh, get final derived mesh */ + + /* XXX BKE_mesh_copy() already handles materials usercount. */ + do_mat_id_us = false; } + /* if not getting the original caged mesh, get final derived mesh */ else { /* Make a dummy mesh, saves copying */ DerivedMesh *dm; @@ -2360,7 +2370,7 @@ Mesh *BKE_mesh_new_from_object( tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpcu->mat[i]; - if (tmpmesh->mat[i]) { + if (do_mat_id_us && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } @@ -2379,7 +2389,7 @@ Mesh *BKE_mesh_new_from_object( /* are we an object material or data based? */ tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpmb->mat[i]; - if (tmpmesh->mat[i]) { + if (do_mat_id_us && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } @@ -2399,7 +2409,7 @@ Mesh *BKE_mesh_new_from_object( /* are we an object material or data based? */ tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i]; - if (tmpmesh->mat[i]) { + if (do_mat_id_us && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } -- cgit v1.2.3 From c5a66b78727b9414f15dc4ece1dc5e572979015d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 30 Aug 2016 21:08:11 +0200 Subject: Fix stupid mistake in previous commit 'cleanup' part. Thanks to sergey for spotting it. --- source/blender/blenkernel/intern/mesh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index c8e43ef388d..ba3aef81514 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2197,8 +2197,9 @@ Mesh *BKE_mesh_new_from_object( { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; - bool render = settings == eModifierMode_Render, i; - bool cage = !apply_modifiers; + int i; + const bool render = (settings == eModifierMode_Render); + const bool cage = !apply_modifiers; bool do_mat_id_us = true; /* perform the mesh extraction based on type */ -- cgit v1.2.3 From 23e3b9f35bef214d3bdf3477d14343f29e4cf672 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Tue, 30 Aug 2016 22:05:27 +0200 Subject: Correct render pass identifier usage in toolitps --- source/blender/makesrna/intern/rna_material.c | 2 +- source/blender/makesrna/intern/rna_object.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index e4f9f856db7..2a8cc073e22 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1889,7 +1889,7 @@ void RNA_def_material(BlenderRNA *brna) prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "index"); - RNA_def_property_ui_text(prop, "Pass Index", "Index number for the IndexMA render pass"); + RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Material Index\" render pass"); RNA_def_property_update(prop, NC_OBJECT, "rna_Material_update"); /* flags */ diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 9683495c54c..2cbf23973c2 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2559,7 +2559,7 @@ static void rna_def_object(BlenderRNA *brna) /* render */ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "index"); - RNA_def_property_ui_text(prop, "Pass Index", "Index number for the IndexOB render pass"); + RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Object Index\" render pass"); RNA_def_property_update(prop, NC_OBJECT, "rna_Object_internal_update"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); -- cgit v1.2.3 From 8fb9f2dbe9cb69476bf1f98c8503e5acd446c5b0 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Wed, 31 Aug 2016 06:26:05 -0600 Subject: [Windows] Add support for code signing the final binaries. The option is controlled with the WITH_WINDOWS_CODESIGN option and needs: - Signtool must be found on the system, the standard windows sdk folders will be searched for it. - The path to the pfx file (WINDOWS_CODESIGN_PFX) - The password for the pfx , this can either be set by the WINDOWS_CODESIGN_PFX_PASSWORD variable but given that ends up in CMakeCache.txt (which might be undesirable) there is a backup option of setting the PFXPASSWORD environment variable on the system. Reviewers: sergey, juicyfruit Reviewed By: juicyfruit Tags: #bf_blender, #platform:_windows Differential Revision: https://developer.blender.org/D2182 --- source/blenderplayer/CMakeLists.txt | 2 +- source/creator/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 2748de0e7dd..58bebc66a3e 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -58,7 +58,7 @@ if(WIN32 AND NOT UNIX) blenderplayer ${EXETYPE} bad_level_call_stubs/stubs.c ${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc) - + WINDOWS_SIGN_TARGET(blenderplayer) install(TARGETS blenderplayer COMPONENT Blenderplayer DESTINATION ".") diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 7acea43d1f5..fc02dfda9d1 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -263,6 +263,7 @@ if(WITH_PYTHON_MODULE) else() add_executable(blender ${EXETYPE} ${SRC}) + WINDOWS_SIGN_TARGET(blender) endif() if(WITH_BUILDINFO) -- 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/blenkernel/intern/lamp.c | 2 -- source/blender/blenkernel/intern/world.c | 2 -- source/blender/editors/render/render_preview.c | 5 +---- 3 files changed, 1 insertion(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index e9d039ad480..d098366aef4 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -154,8 +154,6 @@ Lamp *localize_lamp(Lamp *la) if (lan->mtex[a]) { lan->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_lamp"); memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex)); - /* free lamp decrements */ - id_us_plus((ID *)lan->mtex[a]->tex); } } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index de1e3187a70..caa9a1e357f 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -158,8 +158,6 @@ World *localize_world(World *wrld) if (wrld->mtex[a]) { wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_world"); memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex)); - /* free world decrements */ - id_us_plus((ID *)wrldn->mtex[a]->tex); } } 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 475b43ad4a7f04c07226d97d46c6d2b18fa13f51 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 31 Aug 2016 02:17:11 +0200 Subject: Fix T49175: GLSL material crash with environment maps. --- .../nodes/shader/nodes/node_shader_material.c | 41 +++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'source') diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c index 8b21b1ff33b..6850cdbf6ea 100644 --- a/source/blender/nodes/shader/nodes/node_shader_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_material.c @@ -223,12 +223,27 @@ static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node) /* XXX this is also done as a local static function in gpu_codegen.c, * but we need this to hack around the crappy material node. */ -static GPUNodeLink *gpu_get_input_link(GPUNodeStack *in) +static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in) { - if (in->link) + if (in->link) { return in->link; - else - return GPU_uniform(in->vec); + } + else { + GPUNodeLink *result = NULL; + + /* note GPU_uniform() is only intended to be used as a parameter to + * GPU_link(), returning it directly results in leaks or double frees */ + if (in->type == GPU_FLOAT) + GPU_link(mat, "set_value", GPU_uniform(in->vec), &result); + else if (in->type == GPU_VEC3) + GPU_link(mat, "set_rgb", GPU_uniform(in->vec), &result); + else if (in->type == GPU_VEC4) + GPU_link(mat, "set_rgba", GPU_uniform(in->vec), &result); + else + BLI_assert(0); + + return result; + } } static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) @@ -251,18 +266,18 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU /* write values */ if (hasinput[MAT_IN_COLOR]) - shi.rgb = gpu_get_input_link(&in[MAT_IN_COLOR]); + shi.rgb = gpu_get_input_link(mat, &in[MAT_IN_COLOR]); if (hasinput[MAT_IN_SPEC]) - shi.specrgb = gpu_get_input_link(&in[MAT_IN_SPEC]); + shi.specrgb = gpu_get_input_link(mat, &in[MAT_IN_SPEC]); if (hasinput[MAT_IN_REFL]) - shi.refl = gpu_get_input_link(&in[MAT_IN_REFL]); + shi.refl = gpu_get_input_link(mat, &in[MAT_IN_REFL]); /* retrieve normal */ if (hasinput[MAT_IN_NORMAL]) { GPUNodeLink *tmp; - shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]); + shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]); if (GPU_material_use_world_space_shading(mat)) { GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn); @@ -276,15 +291,15 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU if (node->type == SH_NODE_MATERIAL_EXT) { if (hasinput[MAT_IN_MIR]) - shi.mir = gpu_get_input_link(&in[MAT_IN_MIR]); + shi.mir = gpu_get_input_link(mat, &in[MAT_IN_MIR]); if (hasinput[MAT_IN_AMB]) - shi.amb = gpu_get_input_link(&in[MAT_IN_AMB]); + shi.amb = gpu_get_input_link(mat, &in[MAT_IN_AMB]); if (hasinput[MAT_IN_EMIT]) - shi.emit = gpu_get_input_link(&in[MAT_IN_EMIT]); + shi.emit = gpu_get_input_link(mat, &in[MAT_IN_EMIT]); if (hasinput[MAT_IN_SPECTRA]) - shi.spectra = gpu_get_input_link(&in[MAT_IN_SPECTRA]); + shi.spectra = gpu_get_input_link(mat, &in[MAT_IN_SPECTRA]); if (hasinput[MAT_IN_ALPHA]) - shi.alpha = gpu_get_input_link(&in[MAT_IN_ALPHA]); + shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]); } GPU_shaderesult_set(&shi, &shr); /* clears shr */ -- cgit v1.2.3 From 9e39488fa60e35580581bde1123d55f2e012904f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 1 Sep 2016 15:27:08 +0200 Subject: OpenSubdiv: Fix missing object ORCO when Subsurf uses OpenSubdiv but disabled fore viewport --- source/blender/blenkernel/intern/DerivedMesh.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 79e500f8ceb..0d1ca1c33ad 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -2565,11 +2565,15 @@ static void editbmesh_calc_modifiers( * we'll be using GPU backend of OpenSubdiv. This is so * playback performance is kept as high as possible. */ -static bool calc_modifiers_skip_orco(const Object *ob) +static bool calc_modifiers_skip_orco(Scene *scene, + const Object *ob, + bool use_render_params) { - const ModifierData *last_md = ob->modifiers.last; + ModifierData *last_md = ob->modifiers.last; + const int required_mode = use_render_params ? eModifierMode_Render : eModifierMode_Realtime; if (last_md != NULL && - last_md->type == eModifierType_Subsurf) + last_md->type == eModifierType_Subsurf && + modifier_isEnabled(scene, last_md, required_mode)) { SubsurfModifierData *smd = (SubsurfModifierData *)last_md; /* TODO(sergey): Deduplicate this with checks from subsurf_ccg.c. */ @@ -2589,7 +2593,7 @@ static void mesh_build_data( BKE_object_sculpt_modifiers_changed(ob); #ifdef WITH_OPENSUBDIV - if (calc_modifiers_skip_orco(ob)) { + if (calc_modifiers_skip_orco(scene, ob, false)) { dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL); } #endif @@ -2624,7 +2628,7 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C BKE_editmesh_free_derivedmesh(em); #ifdef WITH_OPENSUBDIV - if (calc_modifiers_skip_orco(obedit)) { + if (calc_modifiers_skip_orco(scene, obedit, false)) { dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL); } #endif -- cgit v1.2.3 From 718f8ae1417c58ce9f5b3a24cc48cec56010221b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 1 Sep 2016 15:29:58 +0200 Subject: pydoc: added missing 'compress' parameter to b.t.BlendDataLibraries.write --- source/blender/python/intern/bpy_library_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index f582cebb260..bf91253141a 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -50,7 +50,7 @@ PyDoc_STRVAR(bpy_lib_write_doc, -".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False)\n" +".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False, compress=False)\n" "\n" " Write data-blocks into a blend file.\n" "\n" -- cgit v1.2.3 From 40d072ca7fff77d918330e7327f16d8eceb878a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 31 Aug 2016 18:51:32 +0200 Subject: D2184 Stamp: Make drawing stamp labels optional. When using metadata stamping, it's often handy to have "Camera" in front of the camera name, "Marker" in front of the marker text, etc., but sometimes those get in the way. This patch allows an artist to turn those labels on/off. Reviewed by: sergey, mont29, venomgfx --- source/blender/blenkernel/intern/image.c | 2 +- source/blender/makesdna/DNA_scene_types.h | 4 +++- source/blender/makesrna/intern/rna_scene.c | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 626d389ac2d..8a9cb73c8c9 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1866,7 +1866,7 @@ void BKE_image_stamp_buf( display = IMB_colormanagement_display_get_named(display_device); if (stamp_data_template == NULL) { - stampdata(scene, camera, &stamp_data, 1); + stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0); } else { stampdata_from_template(&stamp_data, scene, stamp_data_template); diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index a4934cc1f24..9f18a702aef 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1738,9 +1738,11 @@ typedef struct Scene { #define R_STAMP_CAMERALENS 0x0800 #define R_STAMP_STRIPMETA 0x1000 #define R_STAMP_MEMORY 0x2000 +#define R_STAMP_HIDE_LABELS 0x4000 #define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \ R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \ - R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY) + R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \ + R_STAMP_HIDE_LABELS) /* alphamode */ #define R_ADDSKY 0 diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 70c8f149554..f2a1e0a50ab 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -6289,6 +6289,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stamp Output", "Render the stamp info text in the rendered image"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "use_stamp_labels", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "stamp", R_STAMP_HIDE_LABELS); + RNA_def_property_ui_text(prop, "Stamp Labels", "Draw stamp labels (\"Camera\" in front of camera name, etc.)"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "use_stamp_strip_meta", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_STRIPMETA); RNA_def_property_ui_text(prop, "Strip Metadata", "Use metadata from the strips in the sequencer"); -- 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 ++++++++++++++++- source/blender/windowmanager/intern/wm_operators.c | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'source') 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); } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index fcdab746d57..8918b6bb1b8 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1375,6 +1375,10 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) wmOpPopUp *data = arg1; uiBlock *block = arg2; + /* Explicitly set UI_RETURN_OK flag, otherwise the menu might be cancelled + * in case WM_operator_call_ex exits/reloads the current file (T49199). */ + UI_popup_menu_retval_set(block, UI_RETURN_OK, true); + WM_operator_call_ex(C, data->op, true); /* let execute handle freeing it */ -- cgit v1.2.3 From 96dd1943afc4f08e4befb44602a3c621a446c678 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 1 Sep 2016 16:55:01 +0200 Subject: Fix crash calling wm.open_mainfile from menu with --debug-memory enabled Didn't do any bisecting, but guess it's caused rBb54e95a5c8dcb7 (2.74 is fine, 2.75 isn't). I think this fix makes some other hacks redundant but need to check details (will do when we're back to bcon1 to avoid regressions). --- source/blender/windowmanager/intern/wm_operators.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 8918b6bb1b8..0c137221856 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1369,9 +1369,6 @@ typedef struct wmOpPopUp { /* Only invoked by OK button in popups created with wm_block_dialog_create() */ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) { - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win = CTX_wm_window(C); - wmOpPopUp *data = arg1; uiBlock *block = arg2; @@ -1388,8 +1385,18 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) /* in this case, wm_operator_ui_popup_cancel wont run */ MEM_freeN(data); + /* get context data *after* WM_operator_call_ex which might have closed the current file and changed context */ + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + /* check window before 'block->handle' incase the - * popup execution closed the window and freed the block. see T44688. */ + * popup execution closed the window and freed the block. see T44688. + */ + /* Post 2.78 TODO: Check if this fix and others related to T44688 are still + * needed or can be improved now that requesting context data has been corrected + * (see above). We're close to release so not a good time for experiments. + * -- Julian + */ if (BLI_findindex(&wm->windows, win) != -1) { UI_popup_block_close(C, win, block); } -- cgit v1.2.3 From 2d589e8549cb7d14436668f2a324fe2c75f159a3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Aug 2016 16:57:26 +1000 Subject: Math Lib: avoid char > int conversion w/ line plot --- source/blender/blenlib/intern/math_geom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 40454a93ec8..dd30f267f78 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2892,8 +2892,8 @@ void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int int x2 = p2[0]; int y2 = p2[1]; - signed char ix; - signed char iy; + int ix; + int iy; /* if x1 == x2 or y1 == y2, then it does not matter what we set here */ int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1; -- cgit v1.2.3 From 159ac3f638df5b1a569aaab8800de9671f0667c9 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 1 Sep 2016 21:16:54 +0200 Subject: Fix T49224: Crash due to dangling value in 'Object.proxy_from' pointer. Why/how this may happen remains a mystery, so for now simply clearing this runtime-only pointer on Object reading... --- source/blender/blenloader/intern/readfile.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source') diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f5bfe1f4de6..57d499fbe91 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5303,6 +5303,9 @@ static void direct_link_object(FileData *fd, Object *ob) */ ob->recalc = 0; + /* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */ + ob->proxy_from = NULL; + /* loading saved files with editmode enabled works, but for undo we like * to stay in object mode during undo presses so keep editmode disabled. * -- 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') 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 98d28a8a6c503a217a1fe9377e6219f8d512fe11 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 2 Sep 2016 11:37:25 +0200 Subject: Blender 2.78 commit! Includes: - Version bump to 2.78 - Doxy file update - New splash screen - Wrapped some do_versions with version check - Updated template to use proper font After poking around a lot it seems Droid Sans was used during 2.7x series. (or at least difference between using this font and comparing to previous splash screens gives none visible difference). --- source/blender/blenkernel/BKE_blender_version.h | 6 +++--- source/blender/blenloader/intern/versioning_270.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 483fefbd89c..189340db618 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,8 +27,8 @@ /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 277 -#define BLENDER_SUBVERSION 3 +#define BLENDER_VERSION 278 +#define BLENDER_SUBVERSION 0 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 @@ -37,7 +37,7 @@ /* can be left blank, otherwise a,b,c... etc with no quotes */ #define BLENDER_VERSION_CHAR /* alpha/beta/rc/release, docs use this */ -#define BLENDER_VERSION_CYCLE alpha +#define BLENDER_VERSION_CYCLE rc extern char versionstr[]; /* from blender.c */ diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 0a36e7846fe..dfaa59c4e3f 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1348,7 +1348,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) /* ------- end of grease pencil initialization --------------- */ } - { + if (!MAIN_VERSION_ATLEAST(main, 278, 0)) { if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight_stab")) { MovieClip *clip; for (clip = main->movieclip.first; clip; clip = clip->id.next) { -- cgit v1.2.3 From ad400006d32c4e5ee7ba842a11b164e0d112364c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 2 Sep 2016 11:43:36 +0200 Subject: Point submodules to latest master branches We did not update them for really long time and the currently used hashes are quite old and probably wouldn't work without manually updating all submodules. Not as if it's something totally crucial (we ask to update submodules all the times and that's what `make update` does) but updating hashes will save some cloning/checkout time. --- source/tools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/tools b/source/tools index 373945d0978..896c5f78952 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 373945d0978b6601c55c9d5879e0f488b18515cd +Subproject commit 896c5f78952adb2d091d28c65086d46992dabdac -- 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/blenkernel/intern/object.c | 2 +- source/blender/editors/object/object_add.c | 2 +- source/blender/editors/object/object_edit.c | 2 +- source/blender/editors/object/object_relations.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d736a455163..cdd7560e3c4 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1138,7 +1138,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) /* increase user numbers */ id_us_plus((ID *)obn->data); id_us_plus((ID *)obn->gpd); - id_lib_extern((ID *)obn->dup_group); + id_us_plus((ID *)obn->dup_group); for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); 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') 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 From 95cb71451141c01fb1819a2689c1429b58a2a8d4 Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Sat, 3 Sep 2016 18:00:40 +0200 Subject: fix: not initialised variable can crash blender (related to modifiers with cage editing enabled) --- source/blender/blenkernel/intern/DerivedMesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 0d1ca1c33ad..714417ae29e 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -2282,7 +2282,7 @@ static void editbmesh_calc_modifiers( { ModifierData *md, *previewmd = NULL; float (*deformedVerts)[3] = NULL; - CustomDataMask mask, previewmask = 0, append_mask = 0; + CustomDataMask mask = 0, previewmask = 0, append_mask = 0; DerivedMesh *dm = NULL, *orcodm = NULL; int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); CDMaskLink *datamasks, *curr; -- cgit v1.2.3