Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/gpencil/gpencil_paint.c
| Show All 40 Lines | |||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_rand.h" | #include "BLI_rand.h" | ||||
| #include "BLI_math_geom.h" | #include "BLI_math_geom.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "PIL_time.h" | #include "PIL_time.h" | ||||
| #include "DNA_object_types.h" | |||||
| #include "DNA_scene_types.h" | |||||
| #include "DNA_gpencil_types.h" | |||||
| #include "DNA_brush_types.h" | |||||
| #include "DNA_windowmanager_types.h" | |||||
| #include "DNA_workspace_types.h" | |||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_paint.h" | #include "BKE_paint.h" | ||||
| #include "BKE_gpencil.h" | #include "BKE_gpencil.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_layer.h" | |||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "BKE_tracking.h" | #include "BKE_tracking.h" | ||||
| #include "BKE_colortools.h" | #include "BKE_colortools.h" | ||||
| #include "BKE_workspace.h" | |||||
| #include "DNA_object_types.h" | |||||
| #include "DNA_scene_types.h" | |||||
| #include "DNA_gpencil_types.h" | |||||
| #include "DNA_brush_types.h" | |||||
| #include "DNA_windowmanager_types.h" | |||||
| #include "UI_view2d.h" | #include "UI_view2d.h" | ||||
| #include "ED_gpencil.h" | #include "ED_gpencil.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_object.h" | |||||
| #include "ED_view3d.h" | #include "ED_view3d.h" | ||||
| #include "ED_clip.h" | #include "ED_clip.h" | ||||
| #include "BIF_glutil.h" | #include "BIF_glutil.h" | ||||
| #include "GPU_immediate.h" | #include "GPU_immediate.h" | ||||
| #include "GPU_immediate_util.h" | #include "GPU_immediate_util.h" | ||||
| Show All 35 Lines | |||||
| } eGPencil_PaintFlags; | } eGPencil_PaintFlags; | ||||
| /* Temporary 'Stroke' Operation data | /* Temporary 'Stroke' Operation data | ||||
| * "p" = op->customdata | * "p" = op->customdata | ||||
| */ | */ | ||||
| typedef struct tGPsdata { | typedef struct tGPsdata { | ||||
| EvaluationContext eval_ctx; | EvaluationContext eval_ctx; | ||||
| Main *bmain; /* main database pointer */ | |||||
| Scene *scene; /* current scene from context */ | Scene *scene; /* current scene from context */ | ||||
| struct Depsgraph *graph; | struct Depsgraph *graph; | ||||
| wmWindow *win; /* window where painting originated */ | wmWindow *win; /* window where painting originated */ | ||||
| ScrArea *sa; /* area where painting originated */ | ScrArea *sa; /* area where painting originated */ | ||||
| ARegion *ar; /* region where painting originated */ | ARegion *ar; /* region where painting originated */ | ||||
| View2D *v2d; /* needed for GP_STROKE_2DSPACE */ | View2D *v2d; /* needed for GP_STROKE_2DSPACE */ | ||||
| rctf *subrect; /* for using the camera rect within the 3d view */ | rctf *subrect; /* for using the camera rect within the 3d view */ | ||||
| rctf subrect_data; | rctf subrect_data; | ||||
| GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */ | GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */ | ||||
| PointerRNA ownerPtr; /* pointer to owner of gp-datablock */ | PointerRNA ownerPtr; /* pointer to owner of gp-datablock */ | ||||
| bGPdata *gpd; /* gp-datablock layer comes from */ | bGPdata *gpd; /* gp-datablock layer comes from */ | ||||
| bGPDlayer *gpl; /* layer we're working on */ | bGPDlayer *gpl; /* layer we're working on */ | ||||
| bGPDframe *gpf; /* frame we're working on */ | bGPDframe *gpf; /* frame we're working on */ | ||||
| char *align_flag; /* projection-mode flags (toolsettings - eGPencil_Placement_Flags) */ | char *align_flag; /* projection-mode flags (toolsettings - eGPencil_Placement_Flags) */ | ||||
| Show All 21 Lines | typedef struct tGPsdata { | ||||
| float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space | float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space | ||||
| * to region space */ | * to region space */ | ||||
| float mat[4][4]; | float mat[4][4]; | ||||
| float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */ | float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */ | ||||
| void *erasercursor; /* radial cursor data for drawing eraser */ | void *erasercursor; /* radial cursor data for drawing eraser */ | ||||
| bGPDpalettecolor *palettecolor; /* current palette color */ | /* Palette settings are only used for 3D view */ | ||||
| Palette *palette; /* current palette */ | |||||
| PaletteColor *palettecolor; /* current palette color */ | |||||
| bGPDbrush *brush; /* current drawing brush */ | bGPDbrush *brush; /* current drawing brush */ | ||||
| short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */ | short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */ | ||||
| int lock_axis; /* lock drawing to one axis */ | int lock_axis; /* lock drawing to one axis */ | ||||
| short keymodifier; /* key used for invoking the operator */ | short keymodifier; /* key used for invoking the operator */ | ||||
| ReportList *reports; | |||||
| } tGPsdata; | } tGPsdata; | ||||
| /* ------ */ | /* ------ */ | ||||
| /* Macros for accessing sensitivity thresholds... */ | /* Macros for accessing sensitivity thresholds... */ | ||||
| /* minimum number of pixels mouse should move before new point created */ | /* minimum number of pixels mouse should move before new point created */ | ||||
| #define MIN_MANHATTEN_PX (U.gp_manhattendist) | #define MIN_MANHATTEN_PX (U.gp_manhattendist) | ||||
| /* minimum length of new segment before new point can be added */ | /* minimum length of new segment before new point can be added */ | ||||
| #define MIN_EUCLIDEAN_PX (U.gp_euclideandist) | #define MIN_EUCLIDEAN_PX (U.gp_euclideandist) | ||||
| static bool gp_stroke_added_check(tGPsdata *p) | static bool gp_stroke_added_check(tGPsdata *p) | ||||
| { | { | ||||
| return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED); | return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED); | ||||
| } | } | ||||
| static void gp_stroke_added_enable(tGPsdata *p) | static void gp_stroke_added_enable(tGPsdata *p) | ||||
| { | { | ||||
| BLI_assert(p->gpf->strokes.last != NULL); | BLI_assert(p->gpf->strokes.last != NULL); | ||||
| p->flags |= GP_PAINTFLAG_STROKEADDED; | p->flags |= GP_PAINTFLAG_STROKEADDED; | ||||
| /* drawing batch cache is dirty now */ | |||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| p->gpd->flag |= GP_DATA_CACHE_IS_DIRTY; | |||||
| } | } | ||||
| /* ------ */ | /* ------ */ | ||||
| /* Forward defines for some functions... */ | /* Forward defines for some functions... */ | ||||
| static void gp_session_validatebuffer(tGPsdata *p); | static void gp_session_validatebuffer(tGPsdata *p); | ||||
| /* ******************************************* */ | /* ******************************************* */ | ||||
| /* Context Wrangling... */ | /* Context Wrangling... */ | ||||
| /* check if context is suitable for drawing */ | /* check if context is suitable for drawing */ | ||||
| static int gpencil_draw_poll(bContext *C) | static int gpencil_draw_poll(bContext *C) | ||||
| { | { | ||||
| if (ED_operator_regionactive(C)) { | if (ED_operator_regionactive(C)) { | ||||
| ScrArea *sa = CTX_wm_area(C); | |||||
| if (!ELEM(sa->spacetype, SPACE_VIEW3D)) { | |||||
| /* check if current context can support GPencil data */ | /* check if current context can support GPencil data */ | ||||
| if (ED_gpencil_data_get_pointers(C, NULL) != NULL) { | if (ED_gpencil_data_get_pointers(C, NULL) != NULL) { | ||||
| /* check if Grease Pencil isn't already running */ | /* check if Grease Pencil isn't already running */ | ||||
| if (ED_gpencil_session_active() == 0) | if (ED_gpencil_session_active() == 0) | ||||
| return 1; | return 1; | ||||
| else | else | ||||
| CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active"); | CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active"); | ||||
| } | } | ||||
| else { | else { | ||||
| CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into"); | CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into"); | ||||
| } | } | ||||
| return 0; | |||||
| } | } | ||||
| /* 3D Viewport */ | |||||
| else { | else { | ||||
| CTX_wm_operator_poll_msg_set(C, "Active region not set"); | if (ED_gpencil_session_active() == 0) { | ||||
| return 1; | |||||
| } | } | ||||
| else { | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | |||||
| } | |||||
| else { | |||||
| CTX_wm_operator_poll_msg_set(C, "Active region not set"); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| /* check if projecting strokes into 3d-geometry in the 3D-View */ | /* check if projecting strokes into 3d-geometry in the 3D-View */ | ||||
| static bool gpencil_project_check(tGPsdata *p) | static bool gpencil_project_check(tGPsdata *p) | ||||
| { | { | ||||
| bGPdata *gpd = p->gpd; | bGPdata *gpd = p->gpd; | ||||
| return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE))); | return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE))); | ||||
| } | } | ||||
| /* ******************************************* */ | /* ******************************************* */ | ||||
| /* Calculations/Conversions */ | /* Calculations/Conversions */ | ||||
| /* Utilities --------------------------------- */ | /* Utilities --------------------------------- */ | ||||
| /* get the reference point for stroke-point conversions */ | /* get the reference point for stroke-point conversions */ | ||||
| static void gp_get_3d_reference(tGPsdata *p, float vec[3]) | static void gp_get_3d_reference(tGPsdata *p, float vec[3]) | ||||
| { | { | ||||
| View3D *v3d = p->sa->spacedata.first; | View3D *v3d = p->sa->spacedata.first; | ||||
| const float *fp = ED_view3d_cursor3d_get(p->scene, v3d); | ToolSettings *ts = p->scene->toolsettings; | ||||
| Object *ob = NULL; | |||||
| /* the reference point used depends on the owner... */ | |||||
| #if 0 /* XXX: disabled for now, since we can't draw relative to the owner yet */ | |||||
| if (p->ownerPtr.type == &RNA_Object) { | if (p->ownerPtr.type == &RNA_Object) { | ||||
| Object *ob = (Object *)p->ownerPtr.data; | ob = (Object *)p->ownerPtr.data; | ||||
| /* active Object | |||||
| * - use relative distance of 3D-cursor from object center | |||||
| */ | |||||
| sub_v3_v3v3(vec, fp, ob->loc); | |||||
| } | |||||
| else | |||||
| #endif | |||||
| { | |||||
| /* use 3D-cursor */ | |||||
| copy_v3_v3(vec, fp); | |||||
| } | } | ||||
| ED_gp_get_drawing_reference(ts, v3d, p->scene, ob, p->gpl, *p->align_flag, vec); | |||||
| } | } | ||||
| /* Stroke Editing ---------------------------- */ | /* Stroke Editing ---------------------------- */ | ||||
| /* check if the current mouse position is suitable for adding a new point */ | /* check if the current mouse position is suitable for adding a new point */ | ||||
| static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) | static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) | ||||
| { | { | ||||
| int dx = abs(mval[0] - pmval[0]); | int dx = abs(mval[0] - pmval[0]); | ||||
| Show All 16 Lines | static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) | ||||
| else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX) | else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX) | ||||
| return true; | return true; | ||||
| /* mouse 'didn't move' */ | /* mouse 'didn't move' */ | ||||
| else | else | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */ | |||||
| static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis) | |||||
| { | |||||
| float plane_normal[3]; | |||||
| float vn[3]; | |||||
| float ray[3]; | |||||
| float rpoint[3]; | |||||
| /* normal vector for a plane locked to axis */ | |||||
| zero_v3(plane_normal); | |||||
| plane_normal[axis] = 1.0f; | |||||
| /* Reproject the points in the plane */ | |||||
| for (int i = 0; i < gps->totpoints; i++) { | |||||
| bGPDspoint *pt = &gps->points[i]; | |||||
| /* get a vector from the point with the current view direction of the viewport */ | |||||
| ED_view3d_global_to_vector(rv3d, &pt->x, vn); | |||||
| /* calculate line extrem point to create a ray that cross the plane */ | |||||
| mul_v3_fl(vn, -50.0f); | |||||
| add_v3_v3v3(ray, &pt->x, vn); | |||||
| /* if the line never intersect, the point is not changed */ | |||||
| if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) { | |||||
| copy_v3_v3(&pt->x, rpoint); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* reproject stroke to plane locked to axis in 3d cursor location */ | /* reproject stroke to plane locked to axis in 3d cursor location */ | ||||
| static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) | static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) | ||||
| { | { | ||||
| bGPdata *gpd = p->gpd; | bGPdata *gpd = p->gpd; | ||||
| Object *obact = (Object *)p->ownerPtr.data; | |||||
| float origin[3]; | float origin[3]; | ||||
| float cursor[3]; | float cursor[3]; | ||||
| RegionView3D *rv3d = p->ar->regiondata; | RegionView3D *rv3d = p->ar->regiondata; | ||||
| /* verify the stroke mode is CURSOR 3d space mode */ | /* verify the stroke mode is CURSOR 3d space mode */ | ||||
| if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) { | if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { | if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) { | if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */ | /* get drawing origin and copy */ | ||||
| gp_get_3d_reference(p, cursor); | gp_get_3d_reference(p, cursor); | ||||
| zero_v3(origin); | copy_v3_v3(origin, cursor); | ||||
| origin[p->lock_axis - 1] = cursor[p->lock_axis - 1]; | ED_gp_project_stroke_to_plane(obact, rv3d, gps, origin, p->lock_axis - 1, p->scene->toolsettings->gpencil_src); | ||||
| gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1); | |||||
| } | } | ||||
| /* convert screen-coordinates to buffer-coordinates */ | /* convert screen-coordinates to buffer-coordinates */ | ||||
| /* XXX this method needs a total overhaul! */ | /* XXX this method needs a total overhaul! */ | ||||
| static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth) | static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth) | ||||
| { | { | ||||
| bGPdata *gpd = p->gpd; | bGPdata *gpd = p->gpd; | ||||
| ▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | |||||
| /* add current stroke-point to buffer (returns whether point was successfully added) */ | /* add current stroke-point to buffer (returns whether point was successfully added) */ | ||||
| static short gp_stroke_addpoint( | static short gp_stroke_addpoint( | ||||
| tGPsdata *p, const int mval[2], float pressure, double curtime) | tGPsdata *p, const int mval[2], float pressure, double curtime) | ||||
| { | { | ||||
| bGPdata *gpd = p->gpd; | bGPdata *gpd = p->gpd; | ||||
| bGPDbrush *brush = p->brush; | bGPDbrush *brush = p->brush; | ||||
| tGPspoint *pt; | tGPspoint *pt; | ||||
| ToolSettings *ts = p->scene->toolsettings; | ToolSettings *ts = p->scene->toolsettings; | ||||
| Object *obact = (Object *)p->ownerPtr.data; | |||||
| /* check painting mode */ | /* check painting mode */ | ||||
| if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { | if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { | ||||
| /* straight lines only - i.e. only store start and end point in buffer */ | /* straight lines only - i.e. only store start and end point in buffer */ | ||||
| if (gpd->sbuffer_size == 0) { | if (gpd->sbuffer_size == 0) { | ||||
| /* first point in buffer (start point) */ | /* first point in buffer (start point) */ | ||||
| pt = (tGPspoint *)(gpd->sbuffer); | pt = (tGPspoint *)(gpd->sbuffer); | ||||
| ▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | if (gp_stroke_added_check(p)) { | ||||
| /* first time point is adding to temporary buffer -- need to allocate new point in stroke */ | /* first time point is adding to temporary buffer -- need to allocate new point in stroke */ | ||||
| if (gpd->sbuffer_size == 0) { | if (gpd->sbuffer_size == 0) { | ||||
| gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); | gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); | ||||
| gps->totpoints++; | gps->totpoints++; | ||||
| } | } | ||||
| pts = &gps->points[gps->totpoints - 1]; | pts = &gps->points[gps->totpoints - 1]; | ||||
| pts->totweight = 0; | |||||
| pts->weights = NULL; | |||||
| /* special case for poly lines: normally, | /* special case for poly lines: normally, | ||||
| * depth is needed only when creating new stroke from buffer, | * depth is needed only when creating new stroke from buffer, | ||||
| * but poly lines are converting to stroke instantly, | * but poly lines are converting to stroke instantly, | ||||
| * so initialize depth buffer before converting coordinates | * so initialize depth buffer before converting coordinates | ||||
| */ | */ | ||||
| if (gpencil_project_check(p)) { | if (gpencil_project_check(p)) { | ||||
| View3D *v3d = p->sa->spacedata.first; | View3D *v3d = p->sa->spacedata.first; | ||||
| view3d_region_operator_needs_opengl(p->win, p->ar); | view3d_region_operator_needs_opengl(p->win, p->ar); | ||||
| ED_view3d_autodist_init( | ED_view3d_autodist_init( | ||||
| &p->eval_ctx, p->graph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); | &p->eval_ctx, p->graph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); | ||||
| } | } | ||||
| /* convert screen-coordinates to appropriate coordinates (and store them) */ | /* convert screen-coordinates to appropriate coordinates (and store them) */ | ||||
| gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); | gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); | ||||
| /* if axis locked, reproject to plane locked (only in 3d space) */ | /* if axis locked, reproject to plane locked (only in 3d space) */ | ||||
| if (p->lock_axis > GP_LOCKAXIS_NONE) { | if (p->lock_axis > GP_LOCKAXIS_NONE) { | ||||
| gp_reproject_toplane(p, gps); | gp_reproject_toplane(p, gps); | ||||
| } | } | ||||
| /* if parented change position relative to parent object */ | /* if parented change position relative to parent object */ | ||||
| if (gpl->parent != NULL) { | gp_apply_parent_point(obact, gpd, gpl, pts); | ||||
| gp_apply_parent_point(gpl, pts); | |||||
| } | |||||
| /* copy pressure and time */ | /* copy pressure and time */ | ||||
| pts->pressure = pt->pressure; | pts->pressure = pt->pressure; | ||||
| pts->strength = pt->strength; | pts->strength = pt->strength; | ||||
| pts->time = pt->time; | pts->time = pt->time; | ||||
| pts->totweight = 0; | |||||
| pts->weights = NULL; | |||||
| /* force fill recalc */ | /* force fill recalc */ | ||||
| gps->flag |= GP_STROKE_RECALC_CACHES; | gps->flag |= GP_STROKE_RECALC_CACHES; | ||||
| /* drawing batch cache is dirty now */ | |||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| p->gpd->flag |= GP_DATA_CACHE_IS_DIRTY; | |||||
| } | } | ||||
| /* increment counters */ | /* increment counters */ | ||||
| if (gpd->sbuffer_size == 0) | if (gpd->sbuffer_size == 0) | ||||
| gpd->sbuffer_size++; | gpd->sbuffer_size++; | ||||
| return GP_STROKEADD_NORMAL; | return GP_STROKEADD_NORMAL; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| bGPdata *gpd = p->gpd; | bGPdata *gpd = p->gpd; | ||||
| bGPDlayer *gpl = p->gpl; | bGPDlayer *gpl = p->gpl; | ||||
| bGPDstroke *gps; | bGPDstroke *gps; | ||||
| bGPDspoint *pt; | bGPDspoint *pt; | ||||
| tGPspoint *ptc; | tGPspoint *ptc; | ||||
| bGPDbrush *brush = p->brush; | bGPDbrush *brush = p->brush; | ||||
| ToolSettings *ts = p->scene->toolsettings; | ToolSettings *ts = p->scene->toolsettings; | ||||
| Object *obact = (Object *)p->ownerPtr.data; | |||||
| int i, totelem; | int i, totelem; | ||||
| /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ | /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ | ||||
| int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; | int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; | ||||
| /* get total number of points to allocate space for | /* get total number of points to allocate space for | ||||
| * - drawing straight-lines only requires the endpoints | * - drawing straight-lines only requires the endpoints | ||||
| */ | */ | ||||
| Show All 38 Lines | static void gp_stroke_newfrombuffer(tGPsdata *p) | ||||
| for (i = 0; i < sublevel; i++) { | for (i = 0; i < sublevel; i++) { | ||||
| new_totpoints += new_totpoints - 1; | new_totpoints += new_totpoints - 1; | ||||
| } | } | ||||
| gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points"); | gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points"); | ||||
| /* initialize triangle memory to dummy data */ | /* initialize triangle memory to dummy data */ | ||||
| gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation"); | gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation"); | ||||
| gps->flag |= GP_STROKE_RECALC_CACHES; | gps->flag |= GP_STROKE_RECALC_CACHES; | ||||
| gps->tot_triangles = 0; | gps->tot_triangles = 0; | ||||
| /* drawing batch cache is dirty now */ | |||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| p->gpd->flag |= GP_DATA_CACHE_IS_DIRTY; | |||||
| /* set pointer to first non-initialized point */ | /* set pointer to first non-initialized point */ | ||||
| pt = gps->points + (gps->totpoints - totelem); | pt = gps->points + (gps->totpoints - totelem); | ||||
| /* copy points from the buffer to the stroke */ | /* copy points from the buffer to the stroke */ | ||||
| if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { | if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { | ||||
| /* straight lines only -> only endpoints */ | /* straight lines only -> only endpoints */ | ||||
| { | { | ||||
| /* first point */ | /* first point */ | ||||
| ptc = gpd->sbuffer; | ptc = gpd->sbuffer; | ||||
| /* convert screen-coordinates to appropriate coordinates (and store them) */ | /* convert screen-coordinates to appropriate coordinates (and store them) */ | ||||
| gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); | gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); | ||||
| /* if axis locked, reproject to plane locked (only in 3d space) */ | /* if axis locked, reproject to plane locked (only in 3d space) */ | ||||
| if (p->lock_axis > GP_LOCKAXIS_NONE) { | if (p->lock_axis > GP_LOCKAXIS_NONE) { | ||||
| gp_reproject_toplane(p, gps); | gp_reproject_toplane(p, gps); | ||||
| } | } | ||||
| /* if parented change position relative to parent object */ | /* if parented change position relative to parent object */ | ||||
| if (gpl->parent != NULL) { | gp_apply_parent_point(obact, gpd, gpl, pt); | ||||
| gp_apply_parent_point(gpl, pt); | |||||
| } | |||||
| /* copy pressure and time */ | /* copy pressure and time */ | ||||
| pt->pressure = ptc->pressure; | pt->pressure = ptc->pressure; | ||||
| pt->strength = ptc->strength; | pt->strength = ptc->strength; | ||||
| CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | ||||
| pt->time = ptc->time; | pt->time = ptc->time; | ||||
| pt->totweight = 0; | |||||
| pt->weights = NULL; | |||||
| pt++; | pt++; | ||||
| } | } | ||||
| if (totelem == 2) { | if (totelem == 2) { | ||||
| /* last point if applicable */ | /* last point if applicable */ | ||||
| ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1); | ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1); | ||||
| /* convert screen-coordinates to appropriate coordinates (and store them) */ | /* convert screen-coordinates to appropriate coordinates (and store them) */ | ||||
| gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); | gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); | ||||
| /* if axis locked, reproject to plane locked (only in 3d space) */ | /* if axis locked, reproject to plane locked (only in 3d space) */ | ||||
| if (p->lock_axis > GP_LOCKAXIS_NONE) { | if (p->lock_axis > GP_LOCKAXIS_NONE) { | ||||
| gp_reproject_toplane(p, gps); | gp_reproject_toplane(p, gps); | ||||
| } | } | ||||
| /* if parented change position relative to parent object */ | /* if parented change position relative to parent object */ | ||||
| if (gpl->parent != NULL) { | gp_apply_parent_point(obact, gpd, gpl, pt); | ||||
| gp_apply_parent_point(gpl, pt); | |||||
| } | |||||
| /* copy pressure and time */ | /* copy pressure and time */ | ||||
| pt->pressure = ptc->pressure; | pt->pressure = ptc->pressure; | ||||
| pt->strength = ptc->strength; | pt->strength = ptc->strength; | ||||
| CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | ||||
| pt->time = ptc->time; | pt->time = ptc->time; | ||||
| pt->totweight = 0; | |||||
| pt->weights = NULL; | |||||
| } | } | ||||
| } | } | ||||
| else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { | else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { | ||||
| /* first point */ | /* first point */ | ||||
| ptc = gpd->sbuffer; | ptc = gpd->sbuffer; | ||||
| /* convert screen-coordinates to appropriate coordinates (and store them) */ | /* convert screen-coordinates to appropriate coordinates (and store them) */ | ||||
| gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); | gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); | ||||
| /* if axis locked, reproject to plane locked (only in 3d space) */ | /* if axis locked, reproject to plane locked (only in 3d space) */ | ||||
| if (p->lock_axis > GP_LOCKAXIS_NONE) { | if (p->lock_axis > GP_LOCKAXIS_NONE) { | ||||
| gp_reproject_toplane(p, gps); | gp_reproject_toplane(p, gps); | ||||
| } | } | ||||
| /* if parented change position relative to parent object */ | /* if parented change position relative to parent object */ | ||||
| if (gpl->parent != NULL) { | gp_apply_parent_point(obact, gpd, gpl, pt); | ||||
| gp_apply_parent_point(gpl, pt); | |||||
| } | |||||
| /* copy pressure and time */ | /* copy pressure and time */ | ||||
| pt->pressure = ptc->pressure; | pt->pressure = ptc->pressure; | ||||
| pt->strength = ptc->strength; | pt->strength = ptc->strength; | ||||
| CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | ||||
| pt->time = ptc->time; | pt->time = ptc->time; | ||||
| pt->totweight = 0; | |||||
| pt->weights = NULL; | |||||
| } | } | ||||
| else { | else { | ||||
| float *depth_arr = NULL; | float *depth_arr = NULL; | ||||
| /* get an array of depths, far depths are blended */ | /* get an array of depths, far depths are blended */ | ||||
| if (gpencil_project_check(p)) { | if (gpencil_project_check(p)) { | ||||
| int mval[2], mval_prev[2] = { 0 }; | int mval[2], mval_prev[2] = { 0 }; | ||||
| int interp_depth = 0; | int interp_depth = 0; | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) { | ||||
| /* convert screen-coordinates to appropriate coordinates (and store them) */ | /* convert screen-coordinates to appropriate coordinates (and store them) */ | ||||
| gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); | gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); | ||||
| /* copy pressure and time */ | /* copy pressure and time */ | ||||
| pt->pressure = ptc->pressure; | pt->pressure = ptc->pressure; | ||||
| pt->strength = ptc->strength; | pt->strength = ptc->strength; | ||||
| CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | ||||
| pt->time = ptc->time; | pt->time = ptc->time; | ||||
| pt->totweight = 0; | |||||
| pt->weights = NULL; | |||||
| } | } | ||||
| /* subdivide the stroke */ | /* subdivide the stroke */ | ||||
| if (sublevel > 0) { | if (sublevel > 0) { | ||||
| int totpoints = gps->totpoints; | int totpoints = gps->totpoints; | ||||
| for (i = 0; i < sublevel; i++) { | for (i = 0; i < sublevel; i++) { | ||||
| /* we're adding one new point between each pair of verts on each step */ | /* we're adding one new point between each pair of verts on each step */ | ||||
| totpoints += totpoints - 1; | totpoints += totpoints - 1; | ||||
| Show All 20 Lines | if (brush->draw_smoothfac > 0.0f) { | ||||
| reduce += 0.25f; // reduce the factor | reduce += 0.25f; // reduce the factor | ||||
| } | } | ||||
| } | } | ||||
| /* if axis locked, reproject to plane locked (only in 3d space) */ | /* if axis locked, reproject to plane locked (only in 3d space) */ | ||||
| if (p->lock_axis > GP_LOCKAXIS_NONE) { | if (p->lock_axis > GP_LOCKAXIS_NONE) { | ||||
| gp_reproject_toplane(p, gps); | gp_reproject_toplane(p, gps); | ||||
| } | } | ||||
| /* if parented change position relative to parent object */ | /* change position relative to parent object */ | ||||
| if (gpl->parent != NULL) { | gp_apply_parent(obact, gpd, gpl, gps); | ||||
| gp_apply_parent(gpl, gps); | |||||
| } | |||||
| if (depth_arr) | if (depth_arr) | ||||
| MEM_freeN(depth_arr); | MEM_freeN(depth_arr); | ||||
| } | } | ||||
| /* Save palette color */ | /* Save palette color */ | ||||
| bGPDpalette *palette = BKE_gpencil_palette_getactive(p->gpd); | gps->palette = p->palette; | ||||
| bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); | gps->palcolor = p->palettecolor; | ||||
| gps->palcolor = palcolor; | if (p->palettecolor) | ||||
| BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); | BLI_strncpy(gps->colorname, p->palettecolor->info, sizeof(gps->colorname)); | ||||
| /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head | /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head | ||||
| * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist | * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist | ||||
| * when drawing the background | * when drawing the background | ||||
| */ | */ | ||||
| if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode != GP_PAINTMODE_DRAW_POLY)) { | if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode != GP_PAINTMODE_DRAW_POLY)) { | ||||
| BLI_addhead(&p->gpf->strokes, gps); | BLI_addhead(&p->gpf->strokes, gps); | ||||
| } | } | ||||
| Show All 14 Lines | static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) | ||||
| else { | else { | ||||
| return -dot_v3v3(rv3d->viewinv[2], co); | return -dot_v3v3(rv3d->viewinv[2], co); | ||||
| } | } | ||||
| } | } | ||||
| /* only erase stroke points that are visible */ | /* only erase stroke points that are visible */ | ||||
| static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y) | static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y) | ||||
| { | { | ||||
| Object *obact = (Object *)p->ownerPtr.data; | |||||
| if ((p->sa->spacetype == SPACE_VIEW3D) && | if ((p->sa->spacetype == SPACE_VIEW3D) && | ||||
| (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) | (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) | ||||
| { | { | ||||
| RegionView3D *rv3d = p->ar->regiondata; | RegionView3D *rv3d = p->ar->regiondata; | ||||
| bGPDlayer *gpl = p->gpl; | bGPDlayer *gpl = p->gpl; | ||||
| const int mval[2] = {x, y}; | const int mval[2] = {x, y}; | ||||
| float mval_3d[3]; | float mval_3d[3]; | ||||
| float fpt[3]; | float fpt[3]; | ||||
| float diff_mat[4][4]; | float diff_mat[4][4]; | ||||
| /* calculate difference matrix if parent object */ | /* calculate difference matrix if parent object */ | ||||
| ED_gpencil_parent_location(gpl, diff_mat); | ED_gpencil_parent_location(obact, p->gpd, gpl, diff_mat); | ||||
| if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) { | if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) { | ||||
| const float depth_mval = view3d_point_depth(rv3d, mval_3d); | const float depth_mval = view3d_point_depth(rv3d, mval_3d); | ||||
| mul_v3_m4v3(fpt, diff_mat, &pt->x); | mul_v3_m4v3(fpt, diff_mat, &pt->x); | ||||
| const float depth_pt = view3d_point_depth(rv3d, fpt); | const float depth_pt = view3d_point_depth(rv3d, fpt); | ||||
| if (depth_pt > depth_mval) { | if (depth_pt > depth_mval) { | ||||
| Show All 23 Lines | |||||
| /* eraser tool - evaluation per stroke */ | /* eraser tool - evaluation per stroke */ | ||||
| /* TODO: this could really do with some optimization (KD-Tree/BVH?) */ | /* TODO: this could really do with some optimization (KD-Tree/BVH?) */ | ||||
| static void gp_stroke_eraser_dostroke(tGPsdata *p, | static void gp_stroke_eraser_dostroke(tGPsdata *p, | ||||
| bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, | bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, | ||||
| const int mval[2], const int mvalo[2], | const int mval[2], const int mvalo[2], | ||||
| const int radius, const rcti *rect) | const int radius, const rcti *rect) | ||||
| { | { | ||||
| Object *obact = (Object *)p->ownerPtr.data; | |||||
| 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; | ||||
| float diff_mat[4][4]; | float diff_mat[4][4]; | ||||
| /* calculate difference matrix if parent object */ | /* calculate difference matrix */ | ||||
| if (gpl->parent != NULL) { | ED_gpencil_parent_location(obact, p->gpd, gpl, diff_mat); | ||||
| ED_gpencil_parent_location(gpl, diff_mat); | |||||
| } | |||||
| if (gps->totpoints == 0) { | if (gps->totpoints == 0) { | ||||
| /* just free stroke */ | /* just free stroke */ | ||||
| if (gps->points) | if (gps->points) { | ||||
| BKE_gpencil_free_stroke_weights(gps); | |||||
| MEM_freeN(gps->points); | MEM_freeN(gps->points); | ||||
| } | |||||
| if (gps->triangles) | if (gps->triangles) | ||||
| MEM_freeN(gps->triangles); | MEM_freeN(gps->triangles); | ||||
| BLI_freelinkN(&gpf->strokes, gps); | BLI_freelinkN(&gpf->strokes, gps); | ||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| } | } | ||||
| else if (gps->totpoints == 1) { | else if (gps->totpoints == 1) { | ||||
| /* only process if it hasn't been masked out... */ | /* only process if it hasn't been masked out... */ | ||||
| if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { | if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { | ||||
| if (gpl->parent == NULL) { | |||||
| gp_point_to_xy(&p->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(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]); | gp_point_to_xy(&p->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(mval, pc1) <= radius) { | if (len_v2v2_int(mval, pc1) <= radius) { | ||||
| /* free stroke */ | /* free stroke */ | ||||
| // XXX: pressure sensitive eraser should apply here too? | // XXX: pressure sensitive eraser should apply here too? | ||||
| if (gps->points) { | |||||
| BKE_gpencil_free_stroke_weights(gps); | |||||
| MEM_freeN(gps->points); | MEM_freeN(gps->points); | ||||
| } | |||||
| if (gps->triangles) | if (gps->triangles) | ||||
| MEM_freeN(gps->triangles); | MEM_freeN(gps->triangles); | ||||
| BLI_freelinkN(&gpf->strokes, gps); | BLI_freelinkN(&gpf->strokes, gps); | ||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* Pressure threshold at which stroke should be culled: Calculated as pressure value | /* Pressure threshold at which stroke should be culled: Calculated as pressure value | ||||
| * below which we would have invisible strokes | * below which we would have invisible strokes | ||||
| */ | */ | ||||
| Show All 26 Lines | for (i = 0; (i + 1) < gps->totpoints; i++) { | ||||
| /* get points to work with */ | /* get points to work with */ | ||||
| pt1 = gps->points + i; | pt1 = gps->points + i; | ||||
| pt2 = gps->points + i + 1; | pt2 = gps->points + i + 1; | ||||
| /* only process if it hasn't been masked out... */ | /* only process if it hasn't been masked out... */ | ||||
| if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) | if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) | ||||
| continue; | continue; | ||||
| if (gpl->parent == NULL) { | |||||
| gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); | |||||
| gp_point_to_xy(&p->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(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); | gp_point_to_xy(&p->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(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); | gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); | ||||
| } | |||||
| /* Check that point segment of the boundbox of the eraser stroke */ | /* Check that point segment of the boundbox of the eraser 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 | ||||
| * eraser region (either within stroke painted, or on its lines) | * eraser region (either within stroke painted, or on its lines) | ||||
| * - this assumes that linewidth is irrelevant | * - this assumes that linewidth is irrelevant | ||||
| Show All 23 Lines | for (i = 0; (i + 1) < gps->totpoints; i++) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Second Pass: Remove any points that are tagged */ | /* Second Pass: Remove any points that are tagged */ | ||||
| if (do_cull) { | if (do_cull) { | ||||
| gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG); | gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG); | ||||
| } | } | ||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| } | } | ||||
| } | } | ||||
| /* erase strokes which fall under the eraser strokes */ | /* erase strokes which fall under the eraser strokes */ | ||||
| static void gp_stroke_doeraser(tGPsdata *p) | static void gp_stroke_doeraser(tGPsdata *p) | ||||
| { | { | ||||
| bGPDlayer *gpl; | bGPDlayer *gpl; | ||||
| bGPDstroke *gps, *gpn; | bGPDstroke *gps, *gpn; | ||||
| ▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | static void gp_session_validatebuffer(tGPsdata *p) | ||||
| /* reset flags */ | /* reset flags */ | ||||
| gpd->sbuffer_sflag = 0; | gpd->sbuffer_sflag = 0; | ||||
| /* reset inittime */ | /* reset inittime */ | ||||
| p->inittime = 0.0; | p->inittime = 0.0; | ||||
| } | } | ||||
| /* create a new palette color */ | |||||
| static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette) | |||||
| { | |||||
| bGPDpalettecolor *palcolor; | |||||
| palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true); | |||||
| return palcolor; | |||||
| } | |||||
| /* initialize a drawing brush */ | /* initialize a drawing brush */ | ||||
| static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p) | static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p) | ||||
| { | { | ||||
| bGPDbrush *brush; | bGPDbrush *brush; | ||||
| /* if not exist, create a new one */ | /* if not exist, create a new one */ | ||||
| if (BLI_listbase_is_empty(&ts->gp_brushes)) { | if (BLI_listbase_is_empty(&ts->gp_brushes)) { | ||||
| /* create new brushes */ | /* create new brushes */ | ||||
| Show All 12 Lines | static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p) | ||||
| /* asign to temp tGPsdata */ | /* asign to temp tGPsdata */ | ||||
| p->brush = brush; | p->brush = brush; | ||||
| } | } | ||||
| /* initialize a paint palette brush and a default color if not exist */ | /* initialize a paint palette brush and a default color if not exist */ | ||||
| static void gp_init_palette(tGPsdata *p) | static void gp_init_palette(tGPsdata *p) | ||||
| { | { | ||||
| bGPdata *gpd; | bGPdata *gpd = p->gpd; | ||||
| bGPDpalette *palette; | |||||
| bGPDpalettecolor *palcolor; | |||||
| gpd = p->gpd; | bGPDpaletteref *palslot; | ||||
| Palette *palette = NULL; | |||||
| PaletteColor *palcolor = NULL; | |||||
| /* get palette and color info | |||||
| * NOTE: _validate() ensures that everything we need will exist... | |||||
| */ | |||||
| palslot = BKE_gpencil_paletteslot_validate(p->bmain, gpd); | |||||
| palette = palslot->palette; | |||||
| palcolor = BKE_palette_color_get_active(palette); | |||||
| /* assign color to temp tGPsdata */ | |||||
| if (palcolor) { | |||||
| p->palette = palette; | |||||
| p->palettecolor = palcolor; | |||||
| /* if not exist, create a new palette */ | /* set palette colors */ | ||||
| if (BLI_listbase_is_empty(&gpd->palettes)) { | copy_v4_v4(gpd->scolor, palcolor->rgb); | ||||
| /* create new palette */ | copy_v4_v4(gpd->sfill, palcolor->fill); | ||||
| palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true); | gpd->sflag = palcolor->flag; | ||||
| /* now create a default color */ | gpd->bstroke_style = palcolor->stroke_style; | ||||
| palcolor = gp_create_new_color(palette); | gpd->bfill_style = palcolor->fill_style; | ||||
| } | |||||
| else { | |||||
| /* Use the current palette and color */ | |||||
| palette = BKE_gpencil_palette_getactive(gpd); | |||||
| /* the palette needs one color */ | |||||
| if (BLI_listbase_is_empty(&palette->colors)) { | |||||
| palcolor = gp_create_new_color(palette); | |||||
| } | |||||
| else { | |||||
| palcolor = BKE_gpencil_palettecolor_getactive(palette); | |||||
| } | |||||
| /* in some situations can be null, so use first */ | |||||
| if (palcolor == NULL) { | |||||
| BKE_gpencil_palettecolor_setactive(palette, palette->colors.first); | |||||
| palcolor = palette->colors.first; | |||||
| } | } | ||||
| } | } | ||||
| /* asign to temp tGPsdata */ | |||||
| p->palettecolor = palcolor; | |||||
| } | |||||
| /* (re)init new painting data */ | /* (re)init new painting data */ | ||||
| static bool gp_session_initdata(bContext *C, tGPsdata *p) | static bool gp_session_initdata(bContext *C, tGPsdata *p) | ||||
| { | { | ||||
| bGPdata **gpd_ptr = NULL; | bGPdata **gpd_ptr = NULL; | ||||
| ScrArea *curarea = CTX_wm_area(C); | ScrArea *curarea = CTX_wm_area(C); | ||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| Object *obact = CTX_data_active_object(C); | |||||
| View3D *v3d = curarea->spacedata.first; | |||||
| /* make sure the active view (at the starting time) is a 3d-view */ | /* make sure the active view (at the starting time) is a 3d-view */ | ||||
| if (curarea == NULL) { | if (curarea == NULL) { | ||||
| p->status = GP_STATUS_ERROR; | p->status = GP_STATUS_ERROR; | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("Error: No active view for painting\n"); | printf("Error: No active view for painting\n"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* pass on current scene and window */ | /* pass on current scene and window */ | ||||
| CTX_data_eval_ctx(C, &p->eval_ctx); | CTX_data_eval_ctx(C, &p->eval_ctx); | ||||
| p->bmain = CTX_data_main(C); | |||||
| p->scene = CTX_data_scene(C); | p->scene = CTX_data_scene(C); | ||||
| p->graph = CTX_data_depsgraph(C); | p->graph = CTX_data_depsgraph(C); | ||||
| p->win = CTX_wm_window(C); | p->win = CTX_wm_window(C); | ||||
| unit_m4(p->imat); | unit_m4(p->imat); | ||||
| unit_m4(p->mat); | unit_m4(p->mat); | ||||
| switch (curarea->spacetype) { | switch (curarea->spacetype) { | ||||
| /* supported views first */ | /* supported views first */ | ||||
| case SPACE_VIEW3D: | case SPACE_VIEW3D: | ||||
| { | { | ||||
| /* View3D *v3d = curarea->spacedata.first; */ | /* View3D *v3d = curarea->spacedata.first; */ | ||||
| /* RegionView3D *rv3d = ar->regiondata; */ | /* RegionView3D *rv3d = ar->regiondata; */ | ||||
| /* set current area | /* set current area | ||||
| * - must verify that region data is 3D-view (and not something else) | * - must verify that region data is 3D-view (and not something else) | ||||
| */ | */ | ||||
| /* CAUTION: If this is the "toolbar", then this will change on the first stroke */ | /* CAUTION: If this is the "toolbar", then this will change on the first stroke */ | ||||
| p->sa = curarea; | p->sa = curarea; | ||||
| p->ar = ar; | p->ar = ar; | ||||
| p->align_flag = &ts->gpencil_v3d_align; | p->align_flag = &ts->gpencil_v3d_align; | ||||
| if (ar->regiondata == NULL) { | if (ar->regiondata == NULL) { | ||||
| p->status = GP_STATUS_ERROR; | p->status = GP_STATUS_ERROR; | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n"); | printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* if active object doesn't exist or it's not a Grease Pencil object, | |||||
| * use the scene's gp_object (), or create one if it doesn't exist | |||||
| */ | |||||
| float *cur = ED_view3d_cursor3d_get(p->scene, v3d); | |||||
| if ((!obact) || (obact->type != OB_GPENCIL)) { | |||||
| if (p->scene->gp_object) { | |||||
| /* use existing default */ | |||||
| /* XXX: This will still lose whatever mode we were in before, | |||||
| * making GP less convenient for annotations than it used to be | |||||
| */ | |||||
| obact = p->scene->gp_object; | |||||
| /* temporarily activate the object */ | |||||
| SceneLayer *sl = CTX_data_scene_layer(C); | |||||
| Base *base = BKE_scene_layer_base_find(sl, obact); | |||||
| if (base) { | |||||
| if (CTX_data_edit_object(C)) | |||||
| ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */ | |||||
| sl->basact = base; | |||||
| ED_base_object_activate(C, base); | |||||
| } | |||||
| else { | |||||
| printf("ERROR: Couldn't find base for active gp_object (sl = %p, obact = %s)\n", sl, obact->id.name); | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* create new default */ | |||||
| obact = ED_add_gpencil_object(C, p->scene, cur); | |||||
| p->scene->gp_object = obact; | |||||
| } | |||||
| } | |||||
| /* set grease pencil mode to object */ | |||||
| ts->gpencil_src = GP_TOOL_SOURCE_OBJECT; | |||||
| break; | break; | ||||
| } | } | ||||
| case SPACE_NODE: | case SPACE_NODE: | ||||
| { | { | ||||
| /* SpaceNode *snode = curarea->spacedata.first; */ | /* SpaceNode *snode = curarea->spacedata.first; */ | ||||
| /* set current area */ | /* set current area */ | ||||
| p->sa = curarea; | p->sa = curarea; | ||||
| ▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | if (ED_gpencil_session_active() == 0) { | ||||
| /* initialize undo stack, | /* initialize undo stack, | ||||
| * also, existing undo stack would make buffer drawn | * also, existing undo stack would make buffer drawn | ||||
| */ | */ | ||||
| gpencil_undo_init(p->gpd); | gpencil_undo_init(p->gpd); | ||||
| } | } | ||||
| /* clear out buffer (stored in gp-data), in case something contaminated it */ | /* clear out buffer (stored in gp-data), in case something contaminated it */ | ||||
| gp_session_validatebuffer(p); | gp_session_validatebuffer(p); | ||||
| /* set brush and create a new one if null */ | /* set brush and create a new one if null */ | ||||
| gp_init_drawing_brush(ts, p); | gp_init_drawing_brush(ts, p); | ||||
| /* set palette info and create a new one if null */ | |||||
| /* setup active palette */ | |||||
| if (curarea->spacetype == SPACE_VIEW3D) { | |||||
| /* NOTE: This is only done for 3D view, as Palettes aren't used for | |||||
| * annotations in 2D editors | |||||
| */ | |||||
| gp_init_palette(p); | gp_init_palette(p); | ||||
| /* set palette colors */ | } | ||||
| bGPDpalettecolor *palcolor = p->palettecolor; | |||||
| bGPdata *pdata = p->gpd; | |||||
| copy_v4_v4(pdata->scolor, palcolor->color); | |||||
| copy_v4_v4(pdata->sfill, palcolor->fill); | |||||
| pdata->sflag = palcolor->flag; | |||||
| /* lock axis */ | /* lock axis */ | ||||
| p->lock_axis = ts->gp_sculpt.lock_axis; | p->lock_axis = ts->gp_sculpt.lock_axis; | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| /* init new painting session */ | /* init new painting session */ | ||||
| static tGPsdata *gp_session_initpaint(bContext *C) | static tGPsdata *gp_session_initpaint(bContext *C) | ||||
| ▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | else { | ||||
| short add_frame_mode; | short add_frame_mode; | ||||
| if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) | if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) | ||||
| add_frame_mode = GP_GETFRAME_ADD_COPY; | add_frame_mode = GP_GETFRAME_ADD_COPY; | ||||
| else | else | ||||
| add_frame_mode = GP_GETFRAME_ADD_NEW; | add_frame_mode = GP_GETFRAME_ADD_NEW; | ||||
| p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode); | p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode); | ||||
| /* set as dirty draw manager cache */ | |||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| if (p->gpf == NULL) { | if (p->gpf == NULL) { | ||||
| p->status = GP_STATUS_ERROR; | p->status = GP_STATUS_ERROR; | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("Error: No frame created (gpencil_paint_init)\n"); | printf("Error: No frame created (gpencil_paint_init)\n"); | ||||
| return; | return; | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | static bool gpencil_is_tablet_eraser_active(const wmEvent *event) | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* ------------------------------- */ | /* ------------------------------- */ | ||||
| static void gpencil_draw_exit(bContext *C, wmOperator *op) | static void gpencil_draw_exit(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| tGPsdata *p = op->customdata; | tGPsdata *p = op->customdata; | ||||
| bGPdata *gpd = CTX_data_gpencil_data(C); | |||||
| /* clear undo stack */ | /* clear undo stack */ | ||||
| gpencil_undo_finish(); | gpencil_undo_finish(); | ||||
| /* restore cursor to indicate end of drawing */ | /* restore cursor to indicate end of drawing */ | ||||
| if (p->sa->spacetype != SPACE_VIEW3D) { | |||||
| WM_cursor_modal_restore(CTX_wm_window(C)); | WM_cursor_modal_restore(CTX_wm_window(C)); | ||||
| } | |||||
| else { | |||||
| /* or restore paint if 3D view */ | |||||
| if ((p) && (p->paintmode == GP_PAINTMODE_ERASER)) { | |||||
| WM_cursor_modal_set(p->win, CURSOR_STD); | |||||
| } | |||||
| /* drawing batch cache is dirty now */ | |||||
| if (gpd) { | |||||
| BKE_gpencil_batch_cache_dirty(gpd); | |||||
| gpd->flag |= GP_DATA_CACHE_IS_DIRTY; | |||||
| } | |||||
| } | |||||
| /* don't assume that operator data exists at all */ | /* don't assume that operator data exists at all */ | ||||
| if (p) { | if (p) { | ||||
| /* check size of buffer before cleanup, to determine if anything happened here */ | /* check size of buffer before cleanup, to determine if anything happened here */ | ||||
| if (p->paintmode == GP_PAINTMODE_ERASER) { | if (p->paintmode == GP_PAINTMODE_ERASER) { | ||||
| /* turn off radial brush cursor */ | /* turn off radial brush cursor */ | ||||
| gpencil_draw_toggle_eraser_cursor(C, p, false); | gpencil_draw_toggle_eraser_cursor(C, p, false); | ||||
| } | } | ||||
| /* always store the new eraser size to be used again next time | /* always store the new eraser size to be used again next time | ||||
| * NOTE: Do this even when not in eraser mode, as eraser may | * NOTE: Do this even when not in eraser mode, as eraser may | ||||
| * have been toggled at some point. | * have been toggled at some point. | ||||
| */ | */ | ||||
| U.gp_eraser = p->radius; | U.gp_eraser = p->radius; | ||||
| /* cleanup */ | /* cleanup */ | ||||
| gp_paint_cleanup(p); | gp_paint_cleanup(p); | ||||
| gp_session_cleanup(p); | gp_session_cleanup(p); | ||||
| /* finally, free the temp data */ | /* finally, free the temp data */ | ||||
| MEM_freeN(p); | MEM_freeN(p); | ||||
| } | } | ||||
| op->customdata = NULL; | op->customdata = NULL; | ||||
| } | } | ||||
| static void gpencil_draw_cancel(bContext *C, wmOperator *op) | static void gpencil_draw_cancel(bContext *C, wmOperator *op) | ||||
| Show All 27 Lines | static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| if (event != NULL) { | if (event != NULL) { | ||||
| p->keymodifier = event->keymodifier; | p->keymodifier = event->keymodifier; | ||||
| } | } | ||||
| else { | else { | ||||
| p->keymodifier = -1; | p->keymodifier = -1; | ||||
| } | } | ||||
| p->reports = op->reports; | |||||
| /* everything is now setup ok */ | /* everything is now setup ok */ | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| /* ------------------------------- */ | /* ------------------------------- */ | ||||
| /* ensure that the correct cursor icon is set */ | /* ensure that the correct cursor icon is set */ | ||||
| static void gpencil_draw_cursor_set(tGPsdata *p) | static void gpencil_draw_cursor_set(tGPsdata *p) | ||||
| { | { | ||||
| if (p->paintmode == GP_PAINTMODE_ERASER) | if (p->paintmode == GP_PAINTMODE_ERASER) | ||||
| WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */ | WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */ | ||||
| else | else | ||||
| WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR); | WM_cursor_modal_set(p->win, CURSOR_STD); | ||||
| } | } | ||||
| /* update UI indicators of status, including cursor and header prints */ | /* update UI indicators of status, including cursor and header prints */ | ||||
| static void gpencil_draw_status_indicators(tGPsdata *p) | static void gpencil_draw_status_indicators(tGPsdata *p) | ||||
| { | { | ||||
| /* header prints */ | /* header prints */ | ||||
| switch (p->status) { | switch (p->status) { | ||||
| case GP_STATUS_PAINTING: | case GP_STATUS_PAINTING: | ||||
| Show All 9 Lines | case GP_STATUS_IDLING: | ||||
| ED_area_headerprint(p->sa, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | " | ED_area_headerprint(p->sa, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | " | ||||
| "ESC/Enter to end (or click outside this area)")); | "ESC/Enter to end (or click outside this area)")); | ||||
| break; | break; | ||||
| case GP_PAINTMODE_DRAW_STRAIGHT: | case GP_PAINTMODE_DRAW_STRAIGHT: | ||||
| ED_area_headerprint(p->sa, IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | " | ED_area_headerprint(p->sa, IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | " | ||||
| "ESC/Enter to end (or click outside this area)")); | "ESC/Enter to end (or click outside this area)")); | ||||
| break; | break; | ||||
| case GP_PAINTMODE_DRAW: | case GP_PAINTMODE_DRAW: | ||||
| ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | " | ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw")); | ||||
| "E/ESC/Enter to end (or click outside this area)")); | |||||
| break; | break; | ||||
| case GP_PAINTMODE_DRAW_POLY: | case GP_PAINTMODE_DRAW_POLY: | ||||
| ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | " | ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | " | ||||
| "ESC/Enter to end (or click outside this area)")); | "Release Shift/ESC/Enter to end (or click outside this area)")); | ||||
| break; | break; | ||||
| default: /* unhandled future cases */ | default: /* unhandled future cases */ | ||||
| ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)")); | ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)")); | ||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) | ||||
| /* convert from window-space to area-space mouse coordinates | /* convert from window-space to area-space mouse coordinates | ||||
| * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding... | * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding... | ||||
| */ | */ | ||||
| p->mval[0] = event->mval[0] + 1; | p->mval[0] = event->mval[0] + 1; | ||||
| p->mval[1] = event->mval[1] + 1; | p->mval[1] = event->mval[1] + 1; | ||||
| /* verify key status for straight lines */ | /* verify key status for straight lines */ | ||||
| if ((event->ctrl > 0) || (event->alt > 0)) { | if (event->ctrl > 0) { | ||||
| if (p->straight[0] == 0) { | if (p->straight[0] == 0) { | ||||
| int dx = abs(p->mval[0] - p->mvalo[0]); | int dx = abs(p->mval[0] - p->mvalo[0]); | ||||
| int dy = abs(p->mval[1] - p->mvalo[1]); | int dy = abs(p->mval[1] - p->mvalo[1]); | ||||
| if ((dx > 0) || (dy > 0)) { | if ((dx > 0) || (dy > 0)) { | ||||
| /* check mouse direction to replace the other coordinate with previous values */ | /* check mouse direction to replace the other coordinate with previous values */ | ||||
| if (dx >= dy) { | if (dx >= dy) { | ||||
| /* horizontal */ | /* horizontal */ | ||||
| p->straight[0] = 1; | p->straight[0] = 1; | ||||
| ▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | |||||
| /* start of interactive drawing part of operator */ | /* start of interactive drawing part of operator */ | ||||
| static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| tGPsdata *p = NULL; | tGPsdata *p = NULL; | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("GPencil - Starting Drawing\n"); | printf("GPencil - Starting Drawing\n"); | ||||
| /* support for tablets eraser pen */ | |||||
| if (gpencil_is_tablet_eraser_active(event)) { | |||||
| RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER); | |||||
| } | |||||
| /* try to initialize context data needed while drawing */ | /* try to initialize context data needed while drawing */ | ||||
| if (!gpencil_draw_init(C, op, event)) { | if (!gpencil_draw_init(C, op, event)) { | ||||
| if (op->customdata) | if (op->customdata) | ||||
| MEM_freeN(op->customdata); | MEM_freeN(op->customdata); | ||||
| if (G.debug & G_DEBUG) | if (G.debug & G_DEBUG) | ||||
| printf("\tGP - no valid data\n"); | printf("\tGP - no valid data\n"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| Show All 9 Lines | static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| if (p->paintmode == GP_PAINTMODE_ERASER) { | if (p->paintmode == GP_PAINTMODE_ERASER) { | ||||
| gpencil_draw_toggle_eraser_cursor(C, p, true); | gpencil_draw_toggle_eraser_cursor(C, p, true); | ||||
| } | } | ||||
| /* set cursor | /* set cursor | ||||
| * NOTE: This may change later (i.e. intentionally via brush toggle, | * NOTE: This may change later (i.e. intentionally via brush toggle, | ||||
| * or unintentionally if the user scrolls outside the area)... | * or unintentionally if the user scrolls outside the area)... | ||||
| */ | */ | ||||
| gpencil_draw_cursor_set(p); | gpencil_draw_cursor_set(p); | ||||
| ED_gpencil_toggle_brush_cursor(C, true); | |||||
| /* only start drawing immediately if we're allowed to do so... */ | /* only start drawing immediately if we're allowed to do so... */ | ||||
| if (RNA_boolean_get(op->ptr, "wait_for_input") == false) { | if (RNA_boolean_get(op->ptr, "wait_for_input") == false) { | ||||
| /* hotkey invoked - start drawing */ | /* hotkey invoked - start drawing */ | ||||
| /* printf("\tGP - set first spot\n"); */ | /* printf("\tGP - set first spot\n"); */ | ||||
| p->status = GP_STATUS_PAINTING; | p->status = GP_STATUS_PAINTING; | ||||
| /* handle the initial drawing - i.e. for just doing a simple dot */ | /* handle the initial drawing - i.e. for just doing a simple dot */ | ||||
| gpencil_draw_apply_event(op, event); | gpencil_draw_apply_event(op, event); | ||||
| op->flag |= OP_IS_MODAL_CURSOR_REGION; | op->flag |= OP_IS_MODAL_CURSOR_REGION; | ||||
| } | } | ||||
| else { | else { | ||||
| /* toolbar invoked - don't start drawing yet... */ | /* toolbar invoked - don't start drawing yet... */ | ||||
| /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */ | /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */ | ||||
| op->flag |= OP_IS_MODAL_CURSOR_REGION; | op->flag |= OP_IS_MODAL_CURSOR_REGION; | ||||
| } | } | ||||
| /* enable paint mode */ | |||||
| if (p->sa->spacetype == SPACE_VIEW3D) { | |||||
| Object *ob = CTX_data_active_object(C); | |||||
| WorkSpace *workspace = CTX_wm_workspace(C); | |||||
| if (ob && (ob->type == OB_GPENCIL) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) { | |||||
| /* Just set paintmode flag... */ | |||||
| p->gpd->flag |= GP_DATA_STROKE_PAINTMODE; | |||||
| /* disable other GP modes */ | |||||
| p->gpd->flag &= ~GP_DATA_STROKE_EDITMODE; | |||||
| p->gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE; | |||||
| p->gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE; | |||||
| ob->mode = OB_MODE_GPENCIL_PAINT; | |||||
| /* set workspace mode */ | |||||
| BKE_workspace_object_mode_set(workspace, ob->mode); | |||||
| /* redraw mode on screen */ | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); | |||||
| } | |||||
| } | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | ||||
| /* add a modal handler for this operator, so that we can then draw continuous strokes */ | /* add a modal handler for this operator, so that we can then draw continuous strokes */ | ||||
| WM_event_add_modal_handler(C, op); | WM_event_add_modal_handler(C, op); | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ | /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ | ||||
| static bool gpencil_area_exists(bContext *C, ScrArea *sa_test) | static bool gpencil_area_exists(bContext *C, ScrArea *sa_test) | ||||
| { | { | ||||
| bScreen *sc = CTX_wm_screen(C); | bScreen *sc = CTX_wm_screen(C); | ||||
| return (BLI_findindex(&sc->areabase, sa_test) != -1); | return (BLI_findindex(&sc->areabase, sa_test) != -1); | ||||
| ▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) { | ||||
| /* allow numpad keys so that camera/view manipulations can still take place | /* allow numpad keys so that camera/view manipulations can still take place | ||||
| * - PAD0 in particular is really important for Grease Pencil drawing, | * - PAD0 in particular is really important for Grease Pencil drawing, | ||||
| * as animators may be working "to camera", so having this working | * as animators may be working "to camera", so having this working | ||||
| * is essential for ensuring that they can quickly return to that view | * is essential for ensuring that they can quickly return to that view | ||||
| */ | */ | ||||
| } | } | ||||
| else if ((ELEM(event->type, p->keymodifier)) && (event->val == KM_RELEASE)) { | else if ((ELEM(event->type, p->keymodifier)) && (event->val == KM_RELEASE)) { | ||||
| /* enable continuous if release D key in mid drawing */ | /* enable continuous if release D key in mid drawing */ | ||||
| if (p->sa->spacetype != SPACE_VIEW3D) { | |||||
| p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON; | p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON; | ||||
| } | } | ||||
| } | |||||
| else if ((event->type == BKEY) && (event->val == KM_RELEASE)) { | else if ((event->type == BKEY) && (event->val == KM_RELEASE)) { | ||||
| /* Add Blank Frame | /* Add Blank Frame | ||||
| * - Since this operator is non-modal, we can just call it here, and keep going... | * - Since this operator is non-modal, we can just call it here, and keep going... | ||||
| * - This operator is especially useful when animating | * - This operator is especially useful when animating | ||||
| */ | */ | ||||
| WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL); | WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL); | ||||
| estate = OPERATOR_RUNNING_MODAL; | estate = OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| else { | else { | ||||
| estate = OPERATOR_RUNNING_MODAL; | estate = OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| } | } | ||||
| //printf("\tGP - handle modal event...\n"); | //printf("\tGP - handle modal event...\n"); | ||||
| /* exit painting mode (and/or end current stroke) | /* exit painting mode (and/or end current stroke) | ||||
| * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] | * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] | ||||
| */ | */ | ||||
| if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) { | /* if polyline and release shift must cancel */ | ||||
| if ((ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) || | |||||
| ((p->paintmode == GP_PAINTMODE_DRAW_POLY) && (event->shift == 0))) | |||||
| { | |||||
| /* exit() ends the current stroke before cleaning up */ | /* exit() ends the current stroke before cleaning up */ | ||||
| /* printf("\t\tGP - end of paint op + end of stroke\n"); */ | /* printf("\t\tGP - end of paint op + end of stroke\n"); */ | ||||
| /* if drawing polygon and enable on back, must move stroke */ | /* if drawing polygon and enable on back, must move stroke */ | ||||
| if (ts) { | if (ts) { | ||||
| if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { | if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { | ||||
| if (p->flags & GP_PAINTFLAG_STROKEADDED) { | if (p->flags & GP_PAINTFLAG_STROKEADDED) { | ||||
| gpencil_move_last_stroke_to_back(C); | gpencil_move_last_stroke_to_back(C); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | if (p->status == GP_STATUS_PAINTING) { | ||||
| /* if drawing polygon and enable on back, must move stroke */ | /* if drawing polygon and enable on back, must move stroke */ | ||||
| if (ts) { | if (ts) { | ||||
| if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { | if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { | ||||
| if (p->flags & GP_PAINTFLAG_STROKEADDED) { | if (p->flags & GP_PAINTFLAG_STROKEADDED) { | ||||
| gpencil_move_last_stroke_to_back(C); | gpencil_move_last_stroke_to_back(C); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* drawing batch cache is dirty now */ | |||||
| BKE_gpencil_batch_cache_dirty(p->gpd); | |||||
| p->gpd->flag |= GP_DATA_CACHE_IS_DIRTY; | |||||
| p->status = GP_STATUS_DONE; | p->status = GP_STATUS_DONE; | ||||
| estate = OPERATOR_FINISHED; | estate = OPERATOR_FINISHED; | ||||
| } | } | ||||
| } | } | ||||
| else if (event->val == KM_PRESS) { | else if (event->val == KM_PRESS) { | ||||
| bool in_bounds = false; | bool in_bounds = false; | ||||
| /* Check if we're outside the bounds of the active region | /* Check if we're outside the bounds of the active region | ||||
| ▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ | /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ | ||||
| if (0 == gpencil_area_exists(C, p->sa)) | if (0 == gpencil_area_exists(C, p->sa)) | ||||
| estate = OPERATOR_CANCELLED; | estate = OPERATOR_CANCELLED; | ||||
| else { | else { | ||||
| /* update status indicators - cursor, header, etc. */ | /* update status indicators - cursor, header, etc. */ | ||||
| gpencil_draw_status_indicators(p); | gpencil_draw_status_indicators(p); | ||||
| gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */ | gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */ | ||||
| } | } | ||||
| /* process last operations before exiting */ | /* process last operations before exiting */ | ||||
| switch (estate) { | switch (estate) { | ||||
| case OPERATOR_FINISHED: | case OPERATOR_FINISHED: | ||||
| /* one last flush before we're done */ | /* one last flush before we're done */ | ||||
| gpencil_draw_exit(C, op); | gpencil_draw_exit(C, op); | ||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | ||||
| break; | break; | ||||
| ▲ Show 20 Lines • Show All 53 Lines • Show Last 20 Lines | |||||