Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/gpencil/gpencil_brush.c
| Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_gpencil.h" | #include "BKE_gpencil.h" | ||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "BKE_object_deform.h" | |||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | #include "RNA_define.h" | ||||
| Show All 13 Lines | |||||
| /* ************************************************ */ | /* ************************************************ */ | ||||
| /* General Brush Editing Context */ | /* General Brush Editing Context */ | ||||
| /* Context for brush operators */ | /* Context for brush operators */ | ||||
| typedef struct tGP_BrushEditData { | typedef struct tGP_BrushEditData { | ||||
| /* Current editor/region/etc. */ | /* Current editor/region/etc. */ | ||||
| /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */ | /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */ | ||||
| Scene *scene; | Scene *scene; | ||||
| Object *object; | |||||
| ScrArea *sa; | ScrArea *sa; | ||||
| ARegion *ar; | ARegion *ar; | ||||
| /* Current GPencil datablock */ | /* Current GPencil datablock */ | ||||
| bGPdata *gpd; | bGPdata *gpd; | ||||
| /* Brush Settings */ | /* Brush Settings */ | ||||
| GP_BrushEdit_Settings *settings; | GP_BrushEdit_Settings *settings; | ||||
| Show All 34 Lines | typedef struct tGP_BrushEditData { | ||||
| GHash *stroke_customdata; | GHash *stroke_customdata; | ||||
| /* - general customdata */ | /* - general customdata */ | ||||
| void *customdata; | void *customdata; | ||||
| /* Timer for in-place accumulation of brush effect */ | /* Timer for in-place accumulation of brush effect */ | ||||
| wmTimer *timer; | wmTimer *timer; | ||||
| bool timerTick; /* is this event from a timer */ | bool timerTick; /* is this event from a timer */ | ||||
| int vrgroup; /* active vertex group */ | |||||
| } tGP_BrushEditData; | } tGP_BrushEditData; | ||||
| /* Callback for performing some brush operation on a single point */ | /* Callback for performing some brush operation on a single point */ | ||||
| typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | ||||
| const int radius, const int co[2]); | const int radius, const int co[2]); | ||||
| /* ************************************************ */ | /* ************************************************ */ | ||||
| /* Utility Functions */ | /* Utility Functions */ | ||||
| /* apply lock axis reset */ | |||||
| static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, float save_pt[3]) | |||||
| { | |||||
| if (gso->sa->spacetype != SPACE_VIEW3D) { | |||||
| return; | |||||
| } | |||||
| ToolSettings *ts = gso->scene->toolsettings; | |||||
| int axis = ts->gp_sculpt.lock_axis; | |||||
| /* lock axis control */ | |||||
| if (axis == 1) { | |||||
| pt->x = save_pt[0]; | |||||
| } | |||||
| if (axis == 2) { | |||||
| pt->y = save_pt[1]; | |||||
| } | |||||
| if (axis == 3) { | |||||
| pt->z = save_pt[2]; | |||||
| } | |||||
| } | |||||
| /* Context ---------------------------------------- */ | /* Context ---------------------------------------- */ | ||||
| /* Get the sculpting settings */ | /* Get the sculpting settings */ | ||||
| static GP_BrushEdit_Settings *gpsculpt_get_settings(Scene *scene) | static GP_BrushEdit_Settings *gpsculpt_get_settings(Scene *scene) | ||||
| { | { | ||||
| return &scene->toolsettings->gp_sculpt; | return &scene->toolsettings->gp_sculpt; | ||||
| } | } | ||||
| /* Get the active brush */ | /* Get the active brush */ | ||||
| static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene) | static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene, Object *ob) | ||||
| { | { | ||||
| GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt; | GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt; | ||||
| return &gset->brush[gset->brushtype]; | GP_EditBrush_Data *brush = NULL; | ||||
| if ((ob) && (ob->mode == OB_MODE_GPENCIL_WEIGHT)) { | |||||
| brush = &gset->brush[gset->weighttype]; | |||||
| } | |||||
| else { | |||||
| brush = &gset->brush[gset->brushtype]; | |||||
| } | |||||
| return brush; | |||||
| } | } | ||||
| /* Brush Operations ------------------------------- */ | /* Brush Operations ------------------------------- */ | ||||
| /* Invert behaviour of brush? */ | /* Invert behaviour of brush? */ | ||||
| static bool gp_brush_invert_check(tGP_BrushEditData *gso) | static bool gp_brush_invert_check(tGP_BrushEditData *gso) | ||||
| { | { | ||||
| /* The basic setting is the brush's setting (from the panel) */ | /* The basic setting is the brush's setting (from the panel) */ | ||||
| bool invert = ((gso->brush->flag & GP_EDITBRUSH_FLAG_INVERT) != 0); | bool invert = ((gso->brush->flag & GP_EDITBRUSH_FLAG_INVERT) != 0); | ||||
| /* During runtime, the user can hold down the Ctrl key to invert the basic behaviour */ | /* During runtime, the user can hold down the Ctrl key to invert the basic behaviour */ | ||||
| if (gso->flag & GP_EDITBRUSH_FLAG_INVERT) { | if (gso->flag & GP_EDITBRUSH_FLAG_INVERT) { | ||||
| invert ^= true; | invert ^= true; | ||||
| } | } | ||||
| /* set temporary status */ | |||||
| if (invert) { | |||||
| gso->brush->flag |= GP_EDITBRUSH_FLAG_TMP_INVERT; | |||||
| } | |||||
| else { | |||||
| gso->brush->flag &= ~GP_EDITBRUSH_FLAG_TMP_INVERT; | |||||
| } | |||||
| return invert; | return invert; | ||||
| } | } | ||||
| /* Compute strength of effect */ | /* Compute strength of effect */ | ||||
| static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2]) | static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2]) | ||||
| { | { | ||||
| GP_EditBrush_Data *brush = gso->brush; | GP_EditBrush_Data *brush = gso->brush; | ||||
| Show All 25 Lines | |||||
| /* This section defines the callbacks used by each brush to perform their magic. | /* This section defines the callbacks used by each brush to perform their magic. | ||||
| * These are called on each point within the brush's radius. | * These are called on each point within the brush's radius. | ||||
| */ | */ | ||||
| /* ----------------------------------------------- */ | /* ----------------------------------------------- */ | ||||
| /* Smooth Brush */ | /* Smooth Brush */ | ||||
| /* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */ | /* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */ | ||||
| static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | static bool gp_brush_smooth_apply( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| GP_EditBrush_Data *brush = gso->brush; | GP_EditBrush_Data *brush = gso->brush; | ||||
| float inf = gp_brush_influence_calc(gso, radius, co); | float inf = gp_brush_influence_calc(gso, radius, co); | ||||
| bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0; | bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0; | ||||
| /* need one flag enabled by default */ | /* need one flag enabled by default */ | ||||
| if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION | | if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION | | ||||
| GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | | GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | | ||||
| GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0) | GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0) | ||||
| { | { | ||||
| gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION; | gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION; | ||||
| } | } | ||||
| /* perform smoothing */ | /* perform smoothing */ | ||||
| if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) { | if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) { | ||||
| gp_smooth_stroke(gps, i, inf, affect_pressure); | gp_smooth_stroke(gps, pt_index, inf, affect_pressure); | ||||
| } | } | ||||
| if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) { | if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) { | ||||
| gp_smooth_stroke_strength(gps, i, inf); | gp_smooth_stroke_strength(gps, pt_index, inf); | ||||
| } | } | ||||
| if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) { | if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) { | ||||
| gp_smooth_stroke_thickness(gps, i, inf); | gp_smooth_stroke_thickness(gps, pt_index, inf); | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* ----------------------------------------------- */ | /* ----------------------------------------------- */ | ||||
| /* Line Thickness Brush */ | /* Line Thickness Brush */ | ||||
| /* Make lines thicker or thinner by the specified amounts */ | /* Make lines thicker or thinner by the specified amounts */ | ||||
| static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | static bool gp_brush_thickness_apply( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| bGPDspoint *pt = gps->points + i; | bGPDspoint *pt = gps->points + pt_index; | ||||
| float inf; | float inf; | ||||
| /* Compute strength of effect | /* Compute strength of effect | ||||
| * - We divide the strength by 10, so that users can set "sane" values. | * - We divide the strength by 10, so that users can set "sane" values. | ||||
| * Otherwise, good default values are in the range of 0.093 | * Otherwise, good default values are in the range of 0.093 | ||||
| */ | */ | ||||
| inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; | inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; | ||||
| Show All 20 Lines | |||||
| } | } | ||||
| /* ----------------------------------------------- */ | /* ----------------------------------------------- */ | ||||
| /* Color Strength Brush */ | /* Color Strength Brush */ | ||||
| /* Make color more or less transparent by the specified amounts */ | /* Make color more or less transparent by the specified amounts */ | ||||
| static bool gp_brush_strength_apply( | static bool gp_brush_strength_apply( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int i, | tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | ||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| bGPDspoint *pt = gps->points + i; | bGPDspoint *pt = gps->points + pt_index; | ||||
| float inf; | float inf; | ||||
| /* Compute strength of effect | /* Compute strength of effect | ||||
| * - We divide the strength by 10, so that users can set "sane" values. | * - We divide the strength by 10, so that users can set "sane" values. | ||||
| * Otherwise, good default values are in the range of 0.093 | * Otherwise, good default values are in the range of 0.093 | ||||
| */ | */ | ||||
| inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; | inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | else { | ||||
| data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights"); | data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights"); | ||||
| /* hook up to the cache */ | /* hook up to the cache */ | ||||
| BLI_ghash_insert(gso->stroke_customdata, gps, data); | BLI_ghash_insert(gso->stroke_customdata, gps, data); | ||||
| } | } | ||||
| } | } | ||||
| /* store references to stroke points in the initial stage */ | /* store references to stroke points in the initial stage */ | ||||
| static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | static bool gp_brush_grab_store_points( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); | tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); | ||||
| float inf = gp_brush_influence_calc(gso, radius, co); | float inf = gp_brush_influence_calc(gso, radius, co); | ||||
| BLI_assert(data != NULL); | BLI_assert(data != NULL); | ||||
| BLI_assert(data->size < data->capacity); | BLI_assert(data->size < data->capacity); | ||||
| /* insert this point into the set of affected points */ | /* insert this point into the set of affected points */ | ||||
| data->points[data->size] = i; | data->points[data->size] = pt_index; | ||||
| data->weights[data->size] = inf; | data->weights[data->size] = inf; | ||||
| data->size++; | data->size++; | ||||
| /* done */ | /* done */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Compute effect vector for grab brush */ | /* Compute effect vector for grab brush */ | ||||
| Show All 22 Lines | else { | ||||
| gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]); | gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]); | ||||
| gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]); | gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]); | ||||
| gso->dvec[2] = 0.0f; /* unused */ | gso->dvec[2] = 0.0f; /* unused */ | ||||
| } | } | ||||
| } | } | ||||
| /* Apply grab transform to all relevant points of the affected strokes */ | /* Apply grab transform to all relevant points of the affected strokes */ | ||||
| static void gp_brush_grab_apply_cached( | static void gp_brush_grab_apply_cached( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, float diff_mat[4][4]) | tGP_BrushEditData *gso, bGPDstroke *gps, float diff_mat[4][4]) | ||||
| { | { | ||||
| tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); | tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); | ||||
| int i; | int i; | ||||
| /* Apply dvec to all of the stored points */ | /* Apply dvec to all of the stored points */ | ||||
| for (i = 0; i < data->size; i++) { | for (i = 0; i < data->size; i++) { | ||||
| bGPDspoint *pt = &gps->points[data->points[i]]; | bGPDspoint *pt = &gps->points[data->points[i]]; | ||||
| float delta[3] = {0.0f}; | float delta[3] = {0.0f}; | ||||
| /* adjust the amount of displacement to apply */ | /* adjust the amount of displacement to apply */ | ||||
| mul_v3_v3fl(delta, gso->dvec, data->weights[i]); | mul_v3_v3fl(delta, gso->dvec, data->weights[i]); | ||||
| if (!parented) { | |||||
| /* apply */ | |||||
| add_v3_v3(&pt->x, delta); | |||||
| } | |||||
| else { | |||||
| float fpt[3]; | float fpt[3]; | ||||
| float save_pt[3]; | |||||
| copy_v3_v3(save_pt, &pt->x); | |||||
| /* apply transformation */ | /* apply transformation */ | ||||
| mul_v3_m4v3(fpt, diff_mat, &pt->x); | mul_v3_m4v3(fpt, diff_mat, &pt->x); | ||||
| /* apply */ | /* apply */ | ||||
| add_v3_v3(fpt, delta); | add_v3_v3(fpt, delta); | ||||
| copy_v3_v3(&pt->x, fpt); | copy_v3_v3(&pt->x, fpt); | ||||
| /* undo transformation to the init parent position */ | /* undo transformation to the init parent position */ | ||||
| float inverse_diff_mat[4][4]; | float inverse_diff_mat[4][4]; | ||||
| invert_m4_m4(inverse_diff_mat, diff_mat); | invert_m4_m4(inverse_diff_mat, diff_mat); | ||||
| mul_m4_v3(inverse_diff_mat, &pt->x); | mul_m4_v3(inverse_diff_mat, &pt->x); | ||||
| } | |||||
| /* compute lock axis */ | |||||
| gpsculpt_compute_lock_axis(gso, pt, save_pt); | |||||
| } | } | ||||
| } | } | ||||
| /* free customdata used for handling this stroke */ | /* free customdata used for handling this stroke */ | ||||
| static void gp_brush_grab_stroke_free(void *ptr) | static void gp_brush_grab_stroke_free(void *ptr) | ||||
| { | { | ||||
| tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr; | tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr; | ||||
| /* free arrays */ | /* free arrays */ | ||||
| MEM_freeN(data->points); | MEM_freeN(data->points); | ||||
| MEM_freeN(data->weights); | MEM_freeN(data->weights); | ||||
| /* ... and this item itself, since it was also allocated */ | /* ... and this item itself, since it was also allocated */ | ||||
| MEM_freeN(data); | MEM_freeN(data); | ||||
| } | } | ||||
| /* ----------------------------------------------- */ | /* ----------------------------------------------- */ | ||||
| /* Push Brush */ | /* Push Brush */ | ||||
| /* NOTE: Depends on gp_brush_grab_calc_dvec() */ | /* NOTE: Depends on gp_brush_grab_calc_dvec() */ | ||||
| static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | static bool gp_brush_push_apply( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| bGPDspoint *pt = gps->points + i; | bGPDspoint *pt = gps->points + pt_index; | ||||
| float save_pt[3]; | |||||
| copy_v3_v3(save_pt, &pt->x); | |||||
| float inf = gp_brush_influence_calc(gso, radius, co); | float inf = gp_brush_influence_calc(gso, radius, co); | ||||
| float delta[3] = {0.0f}; | float delta[3] = {0.0f}; | ||||
| /* adjust the amount of displacement to apply */ | /* adjust the amount of displacement to apply */ | ||||
| mul_v3_v3fl(delta, gso->dvec, inf); | mul_v3_v3fl(delta, gso->dvec, inf); | ||||
| /* apply */ | /* apply */ | ||||
| add_v3_v3(&pt->x, delta); | add_v3_v3(&pt->x, delta); | ||||
| /* compute lock axis */ | |||||
| gpsculpt_compute_lock_axis(gso, pt, save_pt); | |||||
| /* done */ | /* done */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* ----------------------------------------------- */ | /* ----------------------------------------------- */ | ||||
| /* Pinch Brush */ | /* Pinch Brush */ | ||||
| /* Compute reference midpoint for the brush - this is what we'll be moving towards */ | /* Compute reference midpoint for the brush - this is what we'll be moving towards */ | ||||
| Show All 27 Lines | else { | ||||
| // XXX: fix View2D offsets later | // XXX: fix View2D offsets later | ||||
| gso->dvec[0] = (float)gso->mval[0]; | gso->dvec[0] = (float)gso->mval[0]; | ||||
| gso->dvec[1] = (float)gso->mval[1]; | gso->dvec[1] = (float)gso->mval[1]; | ||||
| gso->dvec[2] = 0.0f; | gso->dvec[2] = 0.0f; | ||||
| } | } | ||||
| } | } | ||||
| /* Shrink distance between midpoint and this point... */ | /* Shrink distance between midpoint and this point... */ | ||||
| static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | static bool gp_brush_pinch_apply( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| bGPDspoint *pt = gps->points + i; | bGPDspoint *pt = gps->points + pt_index; | ||||
| float fac, inf; | float fac, inf; | ||||
| float vec[3]; | float vec[3]; | ||||
| float save_pt[3]; | |||||
| copy_v3_v3(save_pt, &pt->x); | |||||
| /* Scale down standard influence value to get it more manageable... | /* Scale down standard influence value to get it more manageable... | ||||
| * - No damping = Unmanageable at > 0.5 strength | * - No damping = Unmanageable at > 0.5 strength | ||||
| * - Div 10 = Not enough effect | * - Div 10 = Not enough effect | ||||
| * - Div 5 = Happy medium... (by trial and error) | * - Div 5 = Happy medium... (by trial and error) | ||||
| */ | */ | ||||
| inf = gp_brush_influence_calc(gso, radius, co) / 5.0f; | inf = gp_brush_influence_calc(gso, radius, co) / 5.0f; | ||||
| /* 1) Make this point relative to the cursor/midpoint (dvec) */ | /* 1) Make this point relative to the cursor/midpoint (dvec) */ | ||||
| Show All 11 Lines | static bool gp_brush_pinch_apply( | ||||
| else { | else { | ||||
| /* Shrink (default) */ | /* Shrink (default) */ | ||||
| fac = 1.0f - (inf * inf); /* squared to temper the effect... */ | fac = 1.0f - (inf * inf); /* squared to temper the effect... */ | ||||
| } | } | ||||
| mul_v3_fl(vec, fac); | mul_v3_fl(vec, fac); | ||||
| /* 3) Translate back to original space, with the shrinkage applied */ | /* 3) Translate back to original space, with the shrinkage applied */ | ||||
| add_v3_v3v3(&pt->x, gso->dvec, vec); | add_v3_v3v3(&pt->x, gso->dvec, vec); | ||||
| /* compute lock axis */ | |||||
| gpsculpt_compute_lock_axis(gso, pt, save_pt); | |||||
| /* done */ | /* done */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* ----------------------------------------------- */ | /* ----------------------------------------------- */ | ||||
| /* Twist Brush - Rotate Around midpoint */ | /* Twist Brush - Rotate Around midpoint */ | ||||
| /* Take the screenspace coordinates of the point, rotate this around the brush midpoint, | /* Take the screenspace coordinates of the point, rotate this around the brush midpoint, | ||||
| * convert the rotated point and convert it into "data" space | * convert the rotated point and convert it into "data" space | ||||
| */ | */ | ||||
| static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | static bool gp_brush_twist_apply( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| bGPDspoint *pt = gps->points + i; | bGPDspoint *pt = gps->points + pt_index; | ||||
| float angle, inf; | float angle, inf; | ||||
| float save_pt[3]; | |||||
| copy_v3_v3(save_pt, &pt->x); | |||||
| /* Angle to rotate by */ | /* Angle to rotate by */ | ||||
| inf = gp_brush_influence_calc(gso, radius, co); | inf = gp_brush_influence_calc(gso, radius, co); | ||||
| angle = DEG2RADF(1.0f) * inf; | angle = DEG2RADF(1.0f) * inf; | ||||
| if (gp_brush_invert_check(gso)) { | if (gp_brush_invert_check(gso)) { | ||||
| /* invert angle that we rotate by */ | /* invert angle that we rotate by */ | ||||
| angle *= -1; | angle *= -1; | ||||
| } | } | ||||
| Show All 11 Lines | if (gps->flag & GP_STROKE_3DSPACE) { | ||||
| normalize_v3(axis); | normalize_v3(axis); | ||||
| axis_angle_normalized_to_mat3(rmat, axis, angle); | axis_angle_normalized_to_mat3(rmat, axis, angle); | ||||
| /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */ | /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */ | ||||
| sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center (center is stored in dvec) */ | sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center (center is stored in dvec) */ | ||||
| mul_m3_v3(rmat, vec); | mul_m3_v3(rmat, vec); | ||||
| add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */ | add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */ | ||||
| /* compute lock axis */ | |||||
| gpsculpt_compute_lock_axis(gso, pt, save_pt); | |||||
| } | } | ||||
| else { | else { | ||||
| const float axis[3] = {0.0f, 0.0f, 1.0f}; | const float axis[3] = {0.0f, 0.0f, 1.0f}; | ||||
| float vec[3] = {0.0f}; | float vec[3] = {0.0f}; | ||||
| float rmat[3][3]; | float rmat[3][3]; | ||||
| /* Express position of point relative to cursor, ready to rotate */ | /* Express position of point relative to cursor, ready to rotate */ | ||||
| // XXX: There is still some offset here, but it's close to working as expected... | // XXX: There is still some offset here, but it's close to working as expected... | ||||
| Show All 23 Lines | static bool gp_brush_twist_apply( | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* ----------------------------------------------- */ | /* ----------------------------------------------- */ | ||||
| /* Randomize Brush */ | /* Randomize Brush */ | ||||
| /* Apply some random jitter to the point */ | /* Apply some random jitter to the point */ | ||||
| static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, | static bool gp_brush_randomize_apply( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | const int radius, const int co[2]) | ||||
| { | { | ||||
| bGPDspoint *pt = gps->points + i; | bGPDspoint *pt = gps->points + pt_index; | ||||
| float save_pt[3]; | |||||
| copy_v3_v3(save_pt, &pt->x); | |||||
| /* Amount of jitter to apply depends on the distance of the point to the cursor, | /* Amount of jitter to apply depends on the distance of the point to the cursor, | ||||
| * as well as the strength of the brush | * as well as the strength of the brush | ||||
| */ | */ | ||||
| const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f; | const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f; | ||||
| const float fac = BLI_frand() * inf; | const float fac = BLI_frand() * inf; | ||||
| /* need one flag enabled by default */ | /* need one flag enabled by default */ | ||||
| if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION | | if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION | | ||||
| GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | | GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | | ||||
| Show All 35 Lines | if (gps->flag & GP_STROKE_3DSPACE) { | ||||
| if (gso->sa->spacetype == SPACE_VIEW3D) { | if (gso->sa->spacetype == SPACE_VIEW3D) { | ||||
| bool flip; | bool flip; | ||||
| RegionView3D *rv3d = gso->ar->regiondata; | RegionView3D *rv3d = gso->ar->regiondata; | ||||
| float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip); | float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip); | ||||
| if (flip == false) { | if (flip == false) { | ||||
| float dvec[3]; | float dvec[3]; | ||||
| ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac); | ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac); | ||||
| add_v3_v3(&pt->x, dvec); | add_v3_v3(&pt->x, dvec); | ||||
| /* compute lock axis */ | |||||
| gpsculpt_compute_lock_axis(gso, pt, save_pt); | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* ERROR */ | /* ERROR */ | ||||
| BLI_assert(!"3D stroke being sculpted in non-3D view"); | BLI_assert(!"3D stroke being sculpted in non-3D view"); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 28 Lines | if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) { | ||||
| /* only limit lower value */ | /* only limit lower value */ | ||||
| CLAMP_MIN(pt->pressure, 0.0f); | CLAMP_MIN(pt->pressure, 0.0f); | ||||
| } | } | ||||
| /* done */ | /* done */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Weight Paint Brush */ | |||||
| /* Change weight paint for vertex groups */ | |||||
| static bool gp_brush_weight_apply( | |||||
| tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, | |||||
| const int radius, const int co[2]) | |||||
| { | |||||
| bGPDspoint *pt = gps->points + pt_index; | |||||
| float inf; | |||||
| /* Compute strength of effect | |||||
| * - We divide the strength by 10, so that users can set "sane" values. | |||||
| * Otherwise, good default values are in the range of 0.093 | |||||
| */ | |||||
| inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; | |||||
| /* need a vertex group */ | |||||
| if (gso->vrgroup == -1) { | |||||
| if (gso->object) { | |||||
| BKE_object_defgroup_add(gso->object); | |||||
| gso->vrgroup = 0; | |||||
| } | |||||
| } | |||||
| /* get current weight */ | |||||
| float curweight = 0.0f; | |||||
| for (int i = 0; i < pt->totweight; ++i) { | |||||
| bGPDweight *gpw = &pt->weights[i]; | |||||
| if (gpw->index == gso->vrgroup) { | |||||
| curweight = gpw->factor; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (gp_brush_invert_check(gso)) { | |||||
| /* reduce weight */ | |||||
| curweight -= inf; | |||||
| } | |||||
| else { | |||||
| /* increase weight */ | |||||
| curweight += inf; | |||||
| } | |||||
| CLAMP(curweight, 0.0f, 1.0f); | |||||
| BKE_gpencil_vgroup_add_point_weight(pt, gso->vrgroup, curweight); | |||||
| /* weight should stay within [0.0, 1.0] */ | |||||
| if (pt->pressure < 0.0f) | |||||
| pt->pressure = 0.0f; | |||||
| return true; | |||||
| } | |||||
| /* ************************************************ */ | /* ************************************************ */ | ||||
| /* Non Callback-Based Brushes */ | /* Non Callback-Based Brushes */ | ||||
| /* Clone Brush ------------------------------------- */ | /* Clone Brush ------------------------------------- */ | ||||
| /* How this brush currently works: | /* How this brush currently works: | ||||
| * - If this is start of the brush stroke, paste immediately under the cursor | * - If this is start of the brush stroke, paste immediately under the cursor | ||||
| * by placing the midpoint of the buffer strokes under the cursor now | * by placing the midpoint of the buffer strokes under the cursor now | ||||
| * | * | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) | ||||
| /* Create a buffer for storing the current strokes */ | /* Create a buffer for storing the current strokes */ | ||||
| if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) { | if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) { | ||||
| data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array"); | data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array"); | ||||
| } | } | ||||
| /* Init colormap for mapping between the pasted stroke's source colour(names) | /* Init colormap for mapping between the pasted stroke's source colour(names) | ||||
| * and the final colours that will be used here instead... | * and the final colours that will be used here instead... | ||||
| */ | */ | ||||
| data->new_colors = gp_copybuf_validate_colormap(gso->gpd); | data->new_colors = gp_copybuf_validate_colormap(C); | ||||
| } | } | ||||
| /* Free custom data used for "clone" brush */ | /* Free custom data used for "clone" brush */ | ||||
| static void gp_brush_clone_free(tGP_BrushEditData *gso) | static void gp_brush_clone_free(tGP_BrushEditData *gso) | ||||
| { | { | ||||
| tGPSB_CloneBrushData *data = gso->customdata; | tGPSB_CloneBrushData *data = gso->customdata; | ||||
| /* free strokes array */ | /* free strokes array */ | ||||
| Show All 38 Lines | if (ED_gpencil_stroke_can_use(C, gps)) { | ||||
| bGPDstroke *new_stroke; | bGPDstroke *new_stroke; | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| int i; | int i; | ||||
| /* Make a new stroke */ | /* Make a new stroke */ | ||||
| new_stroke = MEM_dupallocN(gps); | new_stroke = MEM_dupallocN(gps); | ||||
| new_stroke->points = MEM_dupallocN(gps->points); | new_stroke->points = MEM_dupallocN(gps->points); | ||||
| BKE_gpencil_stroke_weights_duplicate(gps, new_stroke); | |||||
| new_stroke->triangles = MEM_dupallocN(gps->triangles); | new_stroke->triangles = MEM_dupallocN(gps->triangles); | ||||
| new_stroke->next = new_stroke->prev = NULL; | new_stroke->next = new_stroke->prev = NULL; | ||||
| BLI_addtail(&gpf->strokes, new_stroke); | BLI_addtail(&gpf->strokes, new_stroke); | ||||
| /* Fix color references */ | /* Fix color references */ | ||||
| BLI_assert(new_stroke->colorname[0] != '\0'); | BLI_assert(new_stroke->colorname[0] != '\0'); | ||||
| new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname); | new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname); | ||||
| ▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | else { | ||||
| gp_brush_clone_add(C, gso); | gp_brush_clone_add(C, gso); | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* ************************************************ */ | /* ************************************************ */ | ||||
| /* Cursor drawing */ | |||||
| /* Helper callback for drawing the cursor itself */ | |||||
| static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) | |||||
| { | |||||
| GP_EditBrush_Data *brush = gpsculpt_get_brush(CTX_data_scene(C)); | |||||
| if (brush) { | |||||
| Gwn_VertFormat *format = immVertexFormat(); | |||||
| unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); | |||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | |||||
| glEnable(GL_LINE_SMOOTH); | |||||
| glEnable(GL_BLEND); | |||||
| /* Inner Ring: Light color for action of the brush */ | |||||
| /* TODO: toggle between add and remove? */ | |||||
| immUniformColor4ub(255, 255, 255, 200); | |||||
| imm_draw_circle_wire_2d(pos, x, y, brush->size, 40); | |||||
| /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ | |||||
| immUniformColor3ub(30, 30, 30); | |||||
| imm_draw_circle_wire_2d(pos, x, y, brush->size + 1, 40); | |||||
| immUnbindProgram(); | |||||
| glDisable(GL_BLEND); | |||||
| glDisable(GL_LINE_SMOOTH); | |||||
| } | |||||
| } | |||||
| /* Turn brush cursor in on/off */ | |||||
| static void gpencil_toggle_brush_cursor(bContext *C, bool enable) | |||||
| { | |||||
| GP_BrushEdit_Settings *gset = gpsculpt_get_settings(CTX_data_scene(C)); | |||||
| if (gset->paintcursor && !enable) { | |||||
| /* clear cursor */ | |||||
| WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor); | |||||
| gset->paintcursor = NULL; | |||||
| } | |||||
| else if (enable) { | |||||
| /* enable cursor */ | |||||
| gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C), | |||||
| NULL, | |||||
| gp_brush_drawcursor, NULL); | |||||
| } | |||||
| } | |||||
| /* ************************************************ */ | |||||
| /* Header Info for GPencil Sculpt */ | /* Header Info for GPencil Sculpt */ | ||||
| static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) | static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) | ||||
| { | { | ||||
| const char *brush_name = NULL; | const char *brush_name = NULL; | ||||
| char str[UI_MAX_DRAW_STR] = ""; | char str[UI_MAX_DRAW_STR] = ""; | ||||
| RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name); | RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name); | ||||
| Show All 10 Lines | |||||
| /* ************************************************ */ | /* ************************************************ */ | ||||
| /* Grease Pencil Sculpting Operator */ | /* Grease Pencil Sculpting Operator */ | ||||
| /* Init/Exit ----------------------------------------------- */ | /* Init/Exit ----------------------------------------------- */ | ||||
| static bool gpsculpt_brush_init(bContext *C, wmOperator *op) | static bool gpsculpt_brush_init(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| Object *ob = CTX_data_active_object(C); | |||||
| tGP_BrushEditData *gso; | tGP_BrushEditData *gso; | ||||
| /* setup operator data */ | /* setup operator data */ | ||||
| gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData"); | gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData"); | ||||
| op->customdata = gso; | op->customdata = gso; | ||||
| /* store state */ | /* store state */ | ||||
| gso->settings = gpsculpt_get_settings(scene); | gso->settings = gpsculpt_get_settings(scene); | ||||
| gso->brush = gpsculpt_get_brush(scene); | gso->brush = gpsculpt_get_brush(scene, ob); | ||||
| if ((ob) && (ob->mode == OB_MODE_GPENCIL_WEIGHT)) { | |||||
| gso->brush_type = gso->settings->weighttype; | |||||
| } | |||||
| else { | |||||
| gso->brush_type = gso->settings->brushtype; | gso->brush_type = gso->settings->brushtype; | ||||
| } | |||||
| gso->is_painting = false; | gso->is_painting = false; | ||||
| gso->first = true; | gso->first = true; | ||||
| gso->gpd = ED_gpencil_data_get_active(C); | gso->gpd = ED_gpencil_data_get_active(C); | ||||
| gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */ | gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */ | ||||
| gso->scene = scene; | gso->scene = scene; | ||||
| gso->object = ob; | |||||
| if (ob) { | |||||
| gso->vrgroup = ob->actdef - 1; | |||||
| if (!BLI_findlink(&ob->defbase, gso->vrgroup)) { | |||||
| gso->vrgroup = -1; | |||||
| } | |||||
| } | |||||
| else { | |||||
| gso->vrgroup = - 1; | |||||
| } | |||||
| gso->sa = CTX_wm_area(C); | gso->sa = CTX_wm_area(C); | ||||
| gso->ar = CTX_wm_region(C); | gso->ar = CTX_wm_region(C); | ||||
| /* initialise custom data for brushes */ | /* initialise custom data for brushes */ | ||||
| switch (gso->brush_type) { | switch (gso->brush_type) { | ||||
| case GP_EDITBRUSH_TYPE_CLONE: | case GP_EDITBRUSH_TYPE_CLONE: | ||||
| { | { | ||||
| bGPDstroke *gps; | bGPDstroke *gps; | ||||
| Show All 38 Lines | static bool gpsculpt_brush_init(bContext *C, wmOperator *op) | ||||
| /* setup space conversions */ | /* setup space conversions */ | ||||
| gp_point_conversion_init(C, &gso->gsc); | gp_point_conversion_init(C, &gso->gsc); | ||||
| /* update header */ | /* update header */ | ||||
| gpsculpt_brush_header_set(C, gso); | gpsculpt_brush_header_set(C, gso); | ||||
| /* setup cursor drawing */ | /* setup cursor drawing */ | ||||
| WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR); | //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR); | ||||
| gpencil_toggle_brush_cursor(C, true); | if (gso->sa->spacetype != SPACE_VIEW3D) { | ||||
| ED_gpencil_toggle_brush_cursor(C, true); | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| static void gpsculpt_brush_exit(bContext *C, wmOperator *op) | static void gpsculpt_brush_exit(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| tGP_BrushEditData *gso = op->customdata; | tGP_BrushEditData *gso = op->customdata; | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| Show All 23 Lines | static void gpsculpt_brush_exit(bContext *C, wmOperator *op) | ||||
| /* unregister timer (only used for realtime) */ | /* unregister timer (only used for realtime) */ | ||||
| if (gso->timer) { | if (gso->timer) { | ||||
| WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer); | WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer); | ||||
| } | } | ||||
| /* disable cursor and headerprints */ | /* disable cursor and headerprints */ | ||||
| ED_area_headerprint(CTX_wm_area(C), NULL); | ED_area_headerprint(CTX_wm_area(C), NULL); | ||||
| WM_cursor_modal_restore(win); | WM_cursor_modal_restore(win); | ||||
| gpencil_toggle_brush_cursor(C, false); | if (gso->sa->spacetype != SPACE_VIEW3D) { | ||||
| ED_gpencil_toggle_brush_cursor(C, false); | |||||
| } | |||||
| /* disable temp invert flag */ | |||||
| gso->brush->flag &= ~GP_EDITBRUSH_FLAG_TMP_INVERT; | |||||
| /* free operator data */ | /* free operator data */ | ||||
| MEM_freeN(gso); | MEM_freeN(gso); | ||||
| op->customdata = NULL; | op->customdata = NULL; | ||||
| } | } | ||||
| /* poll callback for stroke sculpting operator(s) */ | /* poll callback for stroke sculpting operator(s) */ | ||||
| static int gpsculpt_brush_poll(bContext *C) | static int gpsculpt_brush_poll(bContext *C) | ||||
| { | { | ||||
| Show All 34 Lines | static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) | ||||
| /* save off new current frame, so that next update works fine */ | /* save off new current frame, so that next update works fine */ | ||||
| gso->cfra = cfra; | gso->cfra = cfra; | ||||
| } | } | ||||
| /* Apply ----------------------------------------------- */ | /* Apply ----------------------------------------------- */ | ||||
| /* Apply brush operation to points in this stroke */ | /* Apply brush operation to points in this stroke */ | ||||
| static bool gpsculpt_brush_do_stroke( | static bool gpsculpt_brush_do_stroke( | ||||
| tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, | tGP_BrushEditData *gso, bGPDstroke *gps, | ||||
| float diff_mat[4][4], GP_BrushApplyCb apply) | float diff_mat[4][4], GP_BrushApplyCb apply) | ||||
| { | { | ||||
| GP_SpaceConversion *gsc = &gso->gsc; | GP_SpaceConversion *gsc = &gso->gsc; | ||||
| rcti *rect = &gso->brush_rect; | rcti *rect = &gso->brush_rect; | ||||
| const int radius = gso->brush->size; | const int radius = gso->brush->size; | ||||
| bGPDspoint *pt1, *pt2; | bGPDspoint *pt1, *pt2; | ||||
| int pc1[2] = {0}; | int pc1[2] = {0}; | ||||
| int pc2[2] = {0}; | int pc2[2] = {0}; | ||||
| int i; | int i; | ||||
| bool include_last = false; | bool include_last = false; | ||||
| bool changed = false; | bool changed = false; | ||||
| if (gps->totpoints == 1) { | if (gps->totpoints == 1) { | ||||
| if (!parented) { | |||||
| gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]); | |||||
| } | |||||
| else { | |||||
| bGPDspoint pt_temp; | bGPDspoint pt_temp; | ||||
| gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); | gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); | ||||
| gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); | gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); | ||||
| } | |||||
| /* do boundbox check first */ | /* do boundbox check first */ | ||||
| if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { | if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { | ||||
| /* only check if point is inside */ | /* only check if point is inside */ | ||||
| if (len_v2v2_int(gso->mval, pc1) <= radius) { | if (len_v2v2_int(gso->mval, pc1) <= radius) { | ||||
| /* apply operation to this point */ | /* apply operation to this point */ | ||||
| changed = apply(gso, gps, 0, radius, pc1); | changed = apply(gso, gps, 0, radius, pc1); | ||||
| } | } | ||||
| Show All 10 Lines | for (i = 0; (i + 1) < gps->totpoints; i++) { | ||||
| /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */ | /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */ | ||||
| if (gso->settings->flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { | if (gso->settings->flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { | ||||
| if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) { | if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) { | ||||
| include_last = false; | include_last = false; | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| if (!parented) { | |||||
| gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]); | |||||
| gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]); | |||||
| } | |||||
| else { | |||||
| bGPDspoint npt; | bGPDspoint npt; | ||||
| gp_point_to_parent_space(pt1, diff_mat, &npt); | gp_point_to_parent_space(pt1, diff_mat, &npt); | ||||
| gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); | gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); | ||||
| gp_point_to_parent_space(pt2, diff_mat, &npt); | gp_point_to_parent_space(pt2, diff_mat, &npt); | ||||
| gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); | gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); | ||||
| } | |||||
| /* Check that point segment of the boundbox of the selection stroke */ | /* Check that point segment of the boundbox of the selection stroke */ | ||||
| if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || | if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || | ||||
| ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) | ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) | ||||
| { | { | ||||
| /* Check if point segment of stroke had anything to do with | /* Check if point segment of stroke had anything to do with | ||||
| * brush region (either within stroke painted, or on its lines) | * brush region (either within stroke painted, or on its lines) | ||||
| * - this assumes that linewidth is irrelevant | * - this assumes that linewidth is irrelevant | ||||
| ▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | switch (gso->brush_type) { | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| /* Find visible strokes, and perform operations on those if hit */ | /* Find visible strokes, and perform operations on those if hit */ | ||||
| float diff_mat[4][4]; | float diff_mat[4][4]; | ||||
| bool parented = false; | Object *obact = CTX_data_active_object(C); | ||||
| bGPdata *gpd = gso->gpd; | |||||
| bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); | |||||
| CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) | CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) | ||||
| { | { | ||||
| bGPDframe *gpf = gpl->actframe; | bGPDframe *init_gpf = gpl->actframe; | ||||
| if (gpf == NULL) | if (is_multiedit) { | ||||
| continue; | init_gpf = gpl->frames.first; | ||||
| /* calculate difference matrix if parent object */ | |||||
| if (gpl->parent != NULL) { | |||||
| ED_gpencil_parent_location(gpl, diff_mat); | |||||
| parented = true; | |||||
| } | |||||
| else { | |||||
| parented = false; | |||||
| } | } | ||||
| for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { | |||||
| if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { | |||||
| /* calculate difference matrix */ | |||||
| ED_gpencil_parent_location(obact, gpd, gpl, diff_mat); | |||||
| for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { | for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { | ||||
| /* skip strokes that are invalid for current view */ | /* skip strokes that are invalid for current view */ | ||||
| if (ED_gpencil_stroke_can_use(C, gps) == false) | if (ED_gpencil_stroke_can_use(C, gps) == false) | ||||
| continue; | continue; | ||||
| /* check if the color is editable */ | /* 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; | continue; | ||||
| } | } | ||||
| switch (gso->brush_type) { | switch (gso->brush_type) { | ||||
| case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */ | case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */ | ||||
| { | { | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_smooth_apply); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply); | ||||
| break; | break; | ||||
| } | } | ||||
| case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */ | case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */ | ||||
| { | { | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_apply); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply); | ||||
| break; | break; | ||||
| } | } | ||||
| case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */ | case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */ | ||||
| { | { | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_strength_apply); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply); | ||||
| break; | break; | ||||
| } | } | ||||
| case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */ | case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */ | ||||
| { | { | ||||
| if (gso->first) { | if (gso->first) { | ||||
| /* First time this brush stroke is being applied: | /* First time this brush stroke is being applied: | ||||
| * 1) Prepare data buffers (init/clear) for this stroke | * 1) Prepare data buffers (init/clear) for this stroke | ||||
| * 2) Use the points now under the cursor | * 2) Use the points now under the cursor | ||||
| */ | */ | ||||
| gp_brush_grab_stroke_init(gso, gps); | gp_brush_grab_stroke_init(gso, gps); | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_grab_store_points); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Apply effect to the stored points */ | /* Apply effect to the stored points */ | ||||
| gp_brush_grab_apply_cached(gso, gps, parented, diff_mat); | gp_brush_grab_apply_cached(gso, gps, diff_mat); | ||||
| changed |= true; | changed |= true; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case GP_EDITBRUSH_TYPE_PUSH: /* Push points */ | case GP_EDITBRUSH_TYPE_PUSH: /* Push points */ | ||||
| { | { | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_push_apply); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply); | ||||
| break; | break; | ||||
| } | } | ||||
| case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */ | case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */ | ||||
| { | { | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_pinch_apply); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply); | ||||
| break; | break; | ||||
| } | } | ||||
| case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */ | case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */ | ||||
| { | { | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_twist_apply); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply); | ||||
| break; | break; | ||||
| } | } | ||||
| case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */ | case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */ | ||||
| { | { | ||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_randomize_apply); | changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply); | ||||
| break; | |||||
| } | |||||
| case GP_EDITBRUSH_TYPE_WEIGHT: /* Adjust vertex group weight */ | |||||
| { | |||||
| changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply); | |||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type); | printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type); | ||||
| break; | break; | ||||
| } | } | ||||
| /* Triangulation must be calculated if changed */ | /* Triangulation must be calculated if changed */ | ||||
| if (changed) { | if (changed) { | ||||
| gps->flag |= GP_STROKE_RECALC_CACHES; | gps->flag |= GP_STROKE_RECALC_CACHES; | ||||
| gps->tot_triangles = 0; | gps->tot_triangles = 0; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /* if not multiedit out of loop */ | |||||
| if (!is_multiedit) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /* Calculate settings for applying brush */ | /* Calculate settings for applying brush */ | ||||
| static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) | static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) | ||||
| ▲ Show 20 Lines • Show All 405 Lines • Show Last 20 Lines | |||||