Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Dobarro <pablodp606@gmail.com>2020-08-06 02:30:34 +0300
committerPablo Dobarro <pablodp606@gmail.com>2020-08-06 18:27:57 +0300
commit5f51438185915a2f45dd2c0ddf2a0773c6c39ffd (patch)
treef46bd2da11ba4d8973975c50b7c62497d2a3bbe0 /source/blender/editors/sculpt_paint/paint_cursor.c
parent56af04d31f6aeab518e7cdc41ea29be73d621948 (diff)
Cleanup: Paint Cursor Refactor
The paint_draw_cursor function was handling the cursor drawing for 2D and 3D views of all paint modes, calculating the brush radius, updating the SculptSession data and updating and drawing all sculpt cursor overlays for different tools. It was almost impossible to understand when and what was being drawn and in which state the GPU matrix was. Now everyting is organized into different functions, with clear separation between modes, sculpt tool overlays and different drawing setups. Update and drawing functions are also separated (this allows to skip one PBVH query on each cursor drawing). Reviewed By: sergey Differential Revision: https://developer.blender.org/D8206
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_cursor.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c1091
1 files changed, 639 insertions, 452 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 9398e4443f3..e3027ead1f1 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -539,54 +539,6 @@ static int project_brush_radius(ViewContext *vc, float radius, const float locat
return 0;
}
-static bool sculpt_get_brush_geometry(bContext *C,
- ViewContext *vc,
- int x,
- int y,
- int *pixel_radius,
- float location[3],
- UnifiedPaintSettings *ups)
-{
- Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- float mouse[2];
- bool hit = false;
-
- mouse[0] = x;
- mouse[1] = y;
-
- if (vc->obact->sculpt && vc->obact->sculpt->pbvh) {
- if (!ups->stroke_active) {
- hit = SCULPT_stroke_get_location(C, location, mouse);
- }
- else {
- hit = ups->last_hit;
- copy_v3_v3(location, ups->last_location);
- }
- }
-
- if (hit) {
- Brush *brush = BKE_paint_brush(paint);
-
- *pixel_radius = project_brush_radius(
- vc, BKE_brush_unprojected_radius_get(scene, brush), location);
-
- if (*pixel_radius == 0) {
- *pixel_radius = BKE_brush_size_get(scene, brush);
- }
-
- mul_m4_v3(vc->obact->obmat, location);
- }
- else {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- *pixel_radius = BKE_brush_size_get(scene, brush);
- }
-
- return hit;
-}
-
/* Draw an overlay that shows what effect the brush's texture will
* have on brush strength. */
static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
@@ -1041,10 +993,10 @@ static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc)
/* Special actions taken when paint cursor goes over mesh */
/* TODO: sculpt only for now. */
-static void paint_cursor_on_hit(UnifiedPaintSettings *ups,
- Brush *brush,
- ViewContext *vc,
- const float location[3])
+static void paint_cursor_update_unprojected_radius(UnifiedPaintSettings *ups,
+ Brush *brush,
+ ViewContext *vc,
+ const float location[3])
{
float unprojected_radius, projected_radius;
@@ -1076,18 +1028,6 @@ static void paint_cursor_on_hit(UnifiedPaintSettings *ups,
}
}
-static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
-{
- if (paint->flags & PAINT_SHOW_BRUSH) {
- if (ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) &&
- brush->imagepaint_tool == PAINT_TOOL_FILL) {
- return true;
- }
- return false;
- }
- return true;
-}
-
static void cursor_draw_point_screen_space(const uint gpuattr,
const ARegion *region,
const float true_location[3],
@@ -1187,8 +1127,27 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
}
}
-static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss)
+static void sculpt_geometry_preview_lines_draw(const uint gpuattr,
+ Brush *brush,
+ const bool is_multires,
+ SculptSession *ss)
{
+ if (!(brush->flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
+ return;
+ }
+
+ if (is_multires) {
+ return;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ return;
+ }
+
+ if (!ss->deform_modifiers_active) {
+ return;
+ }
+
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
/* Cursor normally draws on top, but for this part we need depth tests. */
@@ -1214,30 +1173,21 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession
static void SCULPT_layer_brush_height_preview_draw(const uint gpuattr,
const Brush *brush,
- const float obmat[4][4],
- const float location[3],
- const float normal[3],
const float rds,
const float line_width,
const float outline_col[3],
const float alpha)
{
- float cursor_trans[4][4], cursor_rot[4][4];
- float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float quat[4];
- float height_preview_trans[3];
- copy_m4_m4(cursor_trans, obmat);
- madd_v3_v3v3fl(height_preview_trans, location, normal, brush->height);
- translate_m4(
- cursor_trans, height_preview_trans[0], height_preview_trans[1], height_preview_trans[2]);
- rotation_between_vecs_to_quat(quat, z_axis, normal);
- quat_to_mat4(cursor_rot, quat);
+ float cursor_trans[4][4];
+ unit_m4(cursor_trans);
+ translate_m4(cursor_trans, 0.0f, 0.0f, brush->height);
+ GPU_matrix_push();
GPU_matrix_mul(cursor_trans);
- GPU_matrix_mul(cursor_rot);
GPU_line_width(line_width);
immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
+ GPU_matrix_pop();
}
static bool paint_use_2d_cursor(ePaintMode mode)
@@ -1248,428 +1198,665 @@ static bool paint_use_2d_cursor(ePaintMode mode)
return false;
}
-static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
+typedef enum PaintCursorDrawingType {
+ PAINT_CURSOR_CURVE,
+ PAINT_CURSOR_2D,
+ PAINT_CURSOR_3D,
+} PaintCursorDrawingType;
+
+typedef struct PaintCursorContext {
+ bContext *C;
+ ARegion *region;
+ wmWindow *win;
+ wmWindowManager *wm;
+ Depsgraph *depsgraph;
+ Scene *scene;
+ UnifiedPaintSettings *ups;
+ Brush *brush;
+ Paint *paint;
+ ePaintMode mode;
+ ViewContext vc;
+
+ /* Sculpt related data. */
+ Sculpt *sd;
+ SculptSession *ss;
+ int prev_active_vertex_index;
+ bool is_stroke_active;
+ bool is_cursor_over_mesh;
+ bool is_multires;
+ float radius;
+
+ /* 3D view cursor position and normal. */
+ float location[3];
+ float scene_space_location[3];
+ float normal[3];
+
+ /* Cursor main colors. */
+ float outline_col[3];
+ float outline_alpha;
+
+ /* GPU attribute for drawing. */
+ uint pos;
+
+ PaintCursorDrawingType cursor_type;
+
+ /* This variable is set after drawing the overlay, not on initialization. It can't be used for
+ * checking if alpha overlay is enabled before drawing it. */
+ bool alpha_overlay_drawn;
+
+ float zoomx;
+ int x, y;
+ float translation[2];
+
+ float final_radius;
+ int pixel_radius;
+
+} PaintCursorContext;
+
+static bool paint_cursor_context_init(bContext *C,
+ const int x,
+ const int y,
+ PaintCursorContext *pcontext)
{
ARegion *region = CTX_wm_region(C);
if (region && region->regiontype != RGN_TYPE_WINDOW) {
- return;
+ return false;
}
- const wmWindowManager *wm = CTX_wm_manager(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ pcontext->C = C;
+ pcontext->region = region;
+ pcontext->wm = CTX_wm_manager(C);
+ pcontext->win = CTX_wm_window(C);
+ pcontext->depsgraph = CTX_data_depsgraph_pointer(C);
+ pcontext->scene = CTX_data_scene(C);
+ pcontext->ups = &pcontext->scene->toolsettings->unified_paint_settings;
+ pcontext->paint = BKE_paint_get_active_from_context(C);
+ pcontext->brush = BKE_paint_brush(pcontext->paint);
+ pcontext->mode = BKE_paintmode_get_active_from_context(C);
+
+ ED_view3d_viewcontext_init(C, &pcontext->vc, pcontext->depsgraph);
+
+ if (pcontext->brush->flag & BRUSH_CURVE) {
+ pcontext->cursor_type = PAINT_CURSOR_CURVE;
+ }
+ else if (paint_use_2d_cursor(pcontext->mode)) {
+ pcontext->cursor_type = PAINT_CURSOR_2D;
+ }
+ else {
+ pcontext->cursor_type = PAINT_CURSOR_3D;
+ }
- /* 2d or 3d painting? */
- const bool use_2d_cursor = paint_use_2d_cursor(mode);
+ pcontext->x = x;
+ pcontext->y = y;
+ pcontext->translation[0] = (float)x;
+ pcontext->translation[1] = (float)y;
- /* check that brush drawing is enabled */
- if (ommit_cursor_drawing(paint, mode, brush)) {
- return;
+ float zoomx, zoomy;
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ pcontext->zoomx = max_ff(zoomx, zoomy);
+ pcontext->final_radius = (BKE_brush_size_get(pcontext->scene, pcontext->brush) * zoomx);
+
+ /* There is currently no way to check if the direction is invertex before starting the stroke, so
+ * this does not reflect the state of the brush in the UI. */
+ if (((pcontext->ups->draw_inverted == 0) ^ ((pcontext->brush->flag & BRUSH_DIR_IN) == 0)) &&
+ BKE_brush_sculpt_has_secondary_color(pcontext->brush)) {
+ copy_v3_v3(pcontext->outline_col, pcontext->brush->sub_col);
+ }
+ else {
+ copy_v3_v3(pcontext->outline_col, pcontext->brush->add_col);
}
+ pcontext->outline_alpha = pcontext->brush->add_col[3];
- /* Can't use stroke vc here because this will be called during
- * mouse over too, not just during a stroke. */
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ Object *active_object = pcontext->vc.obact;
+ pcontext->ss = active_object ? active_object->sculpt : NULL;
- if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
- return;
+ pcontext->is_stroke_active = pcontext->ups->stroke_active;
+
+ return true;
+}
+
+static void paint_cursor_update_pixel_radius(PaintCursorContext *pcontext)
+{
+ if (pcontext->is_cursor_over_mesh) {
+ Brush *brush = BKE_paint_brush(pcontext->paint);
+ pcontext->pixel_radius = project_brush_radius(
+ &pcontext->vc,
+ BKE_brush_unprojected_radius_get(pcontext->scene, brush),
+ pcontext->location);
+
+ if (pcontext->pixel_radius == 0) {
+ pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush);
+ }
+
+ copy_v3_v3(pcontext->scene_space_location, pcontext->location);
+ mul_m4_v3(pcontext->vc.obact->obmat, pcontext->scene_space_location);
}
+ else {
+ Sculpt *sd = CTX_data_tool_settings(pcontext->C)->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
- /* Skip everything and draw brush here. */
- if (brush->flag & BRUSH_CURVE) {
- paint_draw_curve_cursor(brush, &vc);
- return;
+ pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush);
}
+}
- float zoomx, zoomy;
- get_imapaint_zoom(C, &zoomx, &zoomy);
- zoomx = max_ff(zoomx, zoomy);
+static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcontext)
+{
+ BLI_assert(pcontext->ss != NULL);
+ BLI_assert(pcontext->mode == PAINT_MODE_SCULPT);
+
+ bContext *C = pcontext->C;
+ SculptSession *ss = pcontext->ss;
+ Brush *brush = pcontext->brush;
+ Scene *scene = pcontext->scene;
+ UnifiedPaintSettings *ups = pcontext->ups;
+ ViewContext *vc = &pcontext->vc;
+ SculptCursorGeometryInfo gi;
+
+ float mouse[2] = {pcontext->x - pcontext->region->winrct.xmin,
+ pcontext->y - pcontext->region->winrct.ymin};
+
+ /* This updates the active vertex, which is needed for most of the Sculpt/Vertex Colors tools to
+ * work correctly */
+ pcontext->prev_active_vertex_index = ss->active_vertex_index;
+ if (!ups->stroke_active) {
+ pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update(
+ C, &gi, mouse, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
+ copy_v3_v3(pcontext->location, gi.location);
+ copy_v3_v3(pcontext->normal, gi.normal);
+ }
+ else {
+ pcontext->is_cursor_over_mesh = ups->last_hit;
+ copy_v3_v3(pcontext->location, ups->last_location);
+ }
- /* Set various defaults. */
- const float *outline_col = brush->add_col;
- const float outline_alpha = brush->add_col[3];
- float translation[2] = {x, y};
- float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
+ paint_cursor_update_pixel_radius(pcontext);
- /* Don't calculate rake angles while a stroke is active because the rake variables are global
- * and we may get interference with the stroke itself.
- * For line strokes, such interference is visible. */
- if (!ups->stroke_active) {
- paint_calculate_rake_rotation(ups, brush, translation);
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ BKE_brush_size_set(scene, brush, pcontext->pixel_radius);
+ }
+
+ if (pcontext->is_cursor_over_mesh) {
+ paint_cursor_update_unprojected_radius(ups, brush, vc, pcontext->scene_space_location);
}
- /* Draw overlay. */
- bool alpha_overlay_active = paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
+ pcontext->is_multires = ss->pbvh != NULL && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
- if (ups->draw_anchored) {
- final_radius = ups->anchored_size;
- copy_v2_fl2(translation,
- ups->anchored_initial_mouse[0] + region->winrct.xmin,
- ups->anchored_initial_mouse[1] + region->winrct.ymin);
+ pcontext->sd = CTX_data_tool_settings(pcontext->C)->sculpt;
+}
+
+static void paint_update_mouse_cursor(PaintCursorContext *pcontext)
+{
+ WM_cursor_set(pcontext->win, WM_CURSOR_PAINT);
+}
+
+static void paint_draw_2D_view_brush_cursor(PaintCursorContext *pcontext)
+{
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha);
+
+ /* Draw brush outline. */
+ if (pcontext->ups->stroke_active && BKE_brush_use_size_pressure(pcontext->brush)) {
+ imm_draw_circle_wire_2d(pcontext->pos,
+ pcontext->translation[0],
+ pcontext->translation[1],
+ pcontext->final_radius * pcontext->ups->size_pressure_value,
+ 40);
+ /* Outer at half alpha. */
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.5f);
}
- /* Make lines pretty. */
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_2d(pcontext->pos,
+ pcontext->translation[0],
+ pcontext->translation[1],
+ pcontext->final_radius,
+ 40);
+
+ immUnbindProgram();
+}
+
+static void paint_draw_legacy_3D_view_brush_cursor(PaintCursorContext *pcontext)
+{
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha);
+ imm_draw_circle_wire_3d(pcontext->pos,
+ pcontext->translation[0],
+ pcontext->translation[1],
+ pcontext->final_radius,
+ 40);
+}
+
+static void paint_draw_3D_view_inactive_brush_cursor(PaintCursorContext *pcontext)
+{
+ GPU_line_width(1.0f);
+ /* Reduce alpha to increase the contrast when the cursor is over the mesh. */
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.8);
+ imm_draw_circle_wire_3d(pcontext->pos,
+ pcontext->translation[0],
+ pcontext->translation[1],
+ pcontext->final_radius,
+ 80);
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.35f);
+ imm_draw_circle_wire_3d(pcontext->pos,
+ pcontext->translation[0],
+ pcontext->translation[1],
+ pcontext->final_radius * clamp_f(pcontext->brush->alpha, 0.0f, 1.0f),
+ 80);
+}
+
+static void paint_cursor_update_object_space_radius(PaintCursorContext *pcontext)
+{
+ if (!BKE_brush_use_locked_size(pcontext->scene, pcontext->brush)) {
+ pcontext->radius = paint_calc_object_space_radius(
+ &pcontext->vc, pcontext->location, BKE_brush_size_get(pcontext->scene, pcontext->brush));
+ }
+ else {
+ pcontext->radius = BKE_brush_unprojected_radius_get(pcontext->scene, pcontext->brush);
+ }
+}
+
+static void paint_cursor_drawing_setup_cursor_space(PaintCursorContext *pcontext)
+{
+ float cursor_trans[4][4], cursor_rot[4][4];
+ float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+ copy_m4_m4(cursor_trans, pcontext->vc.obact->obmat);
+ translate_m4(cursor_trans, pcontext->location[0], pcontext->location[1], pcontext->location[2]);
+ rotation_between_vecs_to_quat(quat, z_axis, pcontext->normal);
+ quat_to_mat4(cursor_rot, quat);
+ GPU_matrix_mul(cursor_trans);
+ GPU_matrix_mul(cursor_rot);
+}
+
+static void paint_cursor_draw_main_inactive_cursor(PaintCursorContext *pcontext)
+{
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha);
GPU_line_width(2.0f);
+ imm_draw_circle_wire_3d(pcontext->pos, 0, 0, pcontext->radius, 80);
- /* TODO: also set blend mode? */
- GPU_blend(true);
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha * 0.5f);
+ imm_draw_circle_wire_3d(
+ pcontext->pos, 0, 0, pcontext->radius * clamp_f(pcontext->brush->alpha, 0.0f, 1.0f), 80);
+}
- GPU_line_smooth(true);
+static void paint_cursor_pose_brush_segments_draw(PaintCursorContext *pcontext)
+{
+ SculptSession *ss = pcontext->ss;
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ GPU_line_width(2.0f);
- if (use_2d_cursor) {
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBegin(GPU_PRIM_LINES, ss->pose_ik_chain_preview->tot_segments * 2);
+ for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
+ immVertex3fv(pcontext->pos, ss->pose_ik_chain_preview->segments[i].initial_orig);
+ immVertex3fv(pcontext->pos, ss->pose_ik_chain_preview->segments[i].initial_head);
+ }
- immUniformColor3fvAlpha(outline_col, outline_alpha);
+ immEnd();
+}
- /* Draw brush outline. */
- if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
- imm_draw_circle_wire_2d(
- pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
- /* Outer at half alpha. */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
- }
+static void paint_cursor_pose_brush_origins_draw(PaintCursorContext *pcontext)
+{
- GPU_line_width(1.0f);
- imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
+ SculptSession *ss = pcontext->ss;
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
+ cursor_draw_point_screen_space(pcontext->pos,
+ pcontext->region,
+ ss->pose_ik_chain_preview->segments[i].initial_orig,
+ pcontext->vc.obact->obmat,
+ 3);
}
- else {
- /* 3D Painting. */
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
-
- /* TODO: as sculpt and other paint modes are unified, this
- * special mode of drawing will go away. */
- Object *obact = vc.obact;
- SculptSession *ss = obact ? obact->sculpt : NULL;
- if ((mode == PAINT_MODE_SCULPT) && ss) {
- float location[3];
- int pixel_radius;
-
- /* Test if brush is over the mesh. */
- bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
-
- if (BKE_brush_use_locked_size(scene, brush)) {
- BKE_brush_size_set(scene, brush, pixel_radius);
- }
+}
- /* Check if brush is subtracting, use different color then */
- /* TODO: no way currently to know state of pen flip or
- * invert key modifier without starting a stroke. */
- if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
- BKE_brush_sculpt_has_secondary_color(brush)) {
- outline_col = brush->sub_col;
- }
+static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *pcontext)
+{
+ Brush *brush = pcontext->brush;
+
+ /* 2D fallof is better represented with the default 2D cursor, there is no need to draw anything
+ * else. */
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ paint_draw_legacy_3D_view_brush_cursor(pcontext);
+ return;
+ }
+
+ if (pcontext->alpha_overlay_drawn) {
+ paint_draw_legacy_3D_view_brush_cursor(pcontext);
+ return;
+ }
- /* Only do if brush is over the mesh. */
- if (hit) {
- paint_cursor_on_hit(ups, brush, &vc, location);
+ if (!pcontext->is_cursor_over_mesh) {
+ paint_draw_3D_view_inactive_brush_cursor(pcontext);
+ return;
+ }
+
+ paint_cursor_update_object_space_radius(pcontext);
+
+ const bool update_previews = pcontext->prev_active_vertex_index !=
+ SCULPT_active_vertex_get(pcontext->ss);
+
+ /* Setup drawing. */
+ wmViewport(&pcontext->region->winrct);
+
+ /* Drawing of Cursor overlays in 2D screen space. */
+
+ /* Cursor location symmetry points. */
+
+ const float *active_vertex_co = SCULPT_active_vertex_co_get(pcontext->ss);
+ if (len_v3v3(active_vertex_co, pcontext->location) < pcontext->radius) {
+ immUniformColor3fvAlpha(pcontext->outline_col, pcontext->outline_alpha);
+ cursor_draw_point_with_symmetry(pcontext->pos,
+ pcontext->region,
+ active_vertex_co,
+ pcontext->sd,
+ pcontext->vc.obact,
+ pcontext->radius);
+ }
+
+ /* Pose brush updates and rotation origins. */
+
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ /* Just after switching to the Pose Brush, the active vertex can be the same and the
+ * cursor won't be tagged to update, so always initialize the preview chain if it is
+ * null before drawing it. */
+ SculptSession *ss = pcontext->ss;
+ if (update_previews || !ss->pose_ik_chain_preview) {
+ BKE_sculpt_update_object_for_edit(
+ pcontext->depsgraph, pcontext->vc.obact, true, false, false);
+
+ /* Free the previous pose brush preview. */
+ if (ss->pose_ik_chain_preview) {
+ SCULPT_pose_ik_chain_free(ss->pose_ik_chain_preview);
}
+
+ /* Generate a new pose brush preview from the current cursor location. */
+ ss->pose_ik_chain_preview = SCULPT_pose_ik_chain_init(
+ pcontext->sd, pcontext->vc.obact, ss, brush, pcontext->location, pcontext->radius);
}
- immUniformColor3fvAlpha(outline_col, outline_alpha);
+ /* Draw the pose brush rotation origins. */
+ paint_cursor_pose_brush_origins_draw(pcontext);
+ }
- if (ups->stroke_active && BKE_brush_use_size_pressure(brush) && mode != PAINT_MODE_SCULPT) {
- imm_draw_circle_wire_3d(
- pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
- /* Outer at half alpha. */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
- }
+ /* Setup 3D perspective drawing. */
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(pcontext->wm,
+ pcontext->win,
+ pcontext->depsgraph,
+ pcontext->scene,
+ pcontext->region,
+ CTX_wm_view3d(pcontext->C),
+ NULL,
+ NULL,
+ NULL);
- /* Only sculpt mode cursor for now. */
- /* Disable for PBVH_GRIDS. */
- bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
+ GPU_matrix_push();
+ GPU_matrix_mul(pcontext->vc.obact->obmat);
- SculptCursorGeometryInfo gi;
- float mouse[2] = {x - region->winrct.xmin, y - region->winrct.ymin};
- int prev_active_vertex_index = -1;
- bool is_cursor_over_mesh = false;
+ /* Drawing Cursor overlays in 3D object space. */
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX)) {
+ SCULPT_geometry_preview_lines_update(pcontext->C, pcontext->ss, pcontext->radius);
+ sculpt_geometry_preview_lines_draw(
+ pcontext->pos, pcontext->brush, pcontext->is_multires, pcontext->ss);
+ }
- /* Update the active vertex. */
- if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) {
- prev_active_vertex_index = ss->active_vertex_index;
- is_cursor_over_mesh = SCULPT_cursor_geometry_info_update(
- C, &gi, mouse, (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ paint_cursor_pose_brush_segments_draw(pcontext);
+ }
+
+ GPU_matrix_pop();
+
+ /* Drawing Cursor overlays in Paint Cursor space (as additional info on top of the brush cursor)
+ */
+ GPU_matrix_push();
+ paint_cursor_drawing_setup_cursor_space(pcontext);
+ /* Main inactive cursor. */
+ paint_cursor_draw_main_inactive_cursor(pcontext);
+
+ /* Cloth brush simulation areas. */
+ if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
+ const float white[3] = {1.0f, 1.0f, 1.0f};
+ const float zero_v[3] = {0.0f};
+ /* This functions sets its own drawing space in order to draw the simulation limits when the
+ * cursor is active. When used here, this cursor overlay is already in cursor space, so its
+ * position and normal should be set to 0. */
+ SCULPT_cloth_simulation_limits_draw(
+ pcontext->pos, brush, zero_v, zero_v, pcontext->radius, 1.0f, white, 0.25f);
+ }
+
+ /* Layer brush height. */
+ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
+ SCULPT_layer_brush_height_preview_draw(pcontext->pos,
+ brush,
+ pcontext->radius,
+ 1.0f,
+ pcontext->outline_col,
+ pcontext->outline_alpha);
+ }
+
+ GPU_matrix_pop();
+
+ /* Reset drawing. */
+ GPU_matrix_pop_projection();
+ wmWindowViewport(pcontext->win);
+}
+
+static void paint_cursor_cursor_draw_3d_view_brush_cursor_active(PaintCursorContext *pcontext)
+{
+ BLI_assert(pcontext->ss != NULL);
+ BLI_assert(pcontext->mode == PAINT_MODE_SCULPT);
+
+ SculptSession *ss = pcontext->ss;
+ Brush *brush = pcontext->brush;
+
+ /* The cursor can be updated as active before creating the StrokeCache, so this needs to be
+ * checked. */
+ if (!ss->cache) {
+ return;
+ }
+
+ /* Most of the brushes initialize the necessary data for the custom cursor drawing after the
+ * first brush step, so make sure that it is not drawn before being initialized. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ /* Setup drawing. */
+ wmViewport(&pcontext->region->winrct);
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(pcontext->wm,
+ pcontext->win,
+ pcontext->depsgraph,
+ pcontext->scene,
+ pcontext->region,
+ CTX_wm_view3d(pcontext->C),
+ NULL,
+ NULL,
+ NULL);
+ GPU_matrix_push();
+ GPU_matrix_mul(pcontext->vc.obact->obmat);
+
+ /* Draw the special active cursors different tools may have. */
+
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ sculpt_geometry_preview_lines_draw(pcontext->pos, brush, pcontext->is_multires, ss);
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_MULTIPLANE_SCRAPE) {
+ SCULPT_multiplane_scrape_preview_draw(
+ pcontext->pos, brush, ss, pcontext->outline_col, pcontext->outline_alpha);
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
+ if (brush->cloth_force_falloff_type == BRUSH_CLOTH_FORCE_FALLOFF_PLANE) {
+ SCULPT_cloth_plane_falloff_preview_draw(
+ pcontext->pos, ss, pcontext->outline_col, pcontext->outline_alpha);
}
- /* Use special paint crosshair cursor in all paint modes. */
- wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, WM_CURSOR_PAINT);
-
- if ((mode == PAINT_MODE_SCULPT) && ss &&
- (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)) {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- if (!ups->stroke_active) {
- bool update_previews = false;
- if (is_cursor_over_mesh && !alpha_overlay_active) {
-
- if (prev_active_vertex_index != ss->active_vertex_index) {
- update_previews = true;
- }
-
- float rds;
- if (!BKE_brush_use_locked_size(scene, brush)) {
- rds = paint_calc_object_space_radius(
- &vc, gi.location, BKE_brush_size_get(scene, brush));
- }
- else {
- rds = BKE_brush_unprojected_radius_get(scene, brush);
- }
-
- wmViewport(&region->winrct);
-
- /* Draw 3D active vertex preview with symmetry. */
- if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
- cursor_draw_point_with_symmetry(pos, region, gi.active_vertex_co, sd, vc.obact, rds);
- }
-
- /* Draw pose brush origins. */
- if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
-
- /* Just after switching to the Pose Brush, the active vertex can be the same and the
- * cursor won't be tagged to update, so always initialize the preview chain if it is
- * null before drawing it. */
- if (update_previews || !ss->pose_ik_chain_preview) {
- BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false, false);
-
- /* Free the previous pose brush preview. */
- if (ss->pose_ik_chain_preview) {
- SCULPT_pose_ik_chain_free(ss->pose_ik_chain_preview);
- }
-
- /* Generate a new pose brush preview from the current cursor location. */
- ss->pose_ik_chain_preview = SCULPT_pose_ik_chain_init(
- sd, vc.obact, ss, brush, gi.location, rds);
- }
-
- /* Draw the pose brush rotation origins. */
- for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
- cursor_draw_point_screen_space(pos,
- region,
- ss->pose_ik_chain_preview->segments[i].initial_orig,
- vc.obact->obmat,
- 3);
- }
- }
-
- /* Draw 3D brush cursor. */
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(wm,
- CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- region,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
-
- float cursor_trans[4][4], cursor_rot[4][4];
- float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float quat[4];
-
- copy_m4_m4(cursor_trans, vc.obact->obmat);
- translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
- rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
- quat_to_mat4(cursor_rot, quat);
-
- GPU_matrix_push();
- GPU_matrix_mul(cursor_trans);
- GPU_matrix_mul(cursor_rot);
- immUniformColor3fvAlpha(outline_col, outline_alpha);
- GPU_line_width(2.0f);
- imm_draw_circle_wire_3d(pos, 0, 0, rds, 80);
-
- GPU_line_width(1.0f);
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
- imm_draw_circle_wire_3d(pos, 0, 0, rds * clamp_f(brush->alpha, 0.0f, 1.0f), 80);
- GPU_matrix_pop();
-
- /* Cloth brush simulation areas. */
- if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
- GPU_matrix_push();
- const float white[3] = {1.0f, 1.0f, 1.0f};
- SCULPT_cloth_simulation_limits_draw(
- pos, brush, vc.obact->obmat, gi.location, gi.normal, rds, 1.0f, white, 0.25f);
- GPU_matrix_pop();
- }
-
- /* Layer brush height. */
- if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- GPU_matrix_push();
- SCULPT_layer_brush_height_preview_draw(pos,
- brush,
- vc.obact->obmat,
- gi.location,
- gi.normal,
- rds,
- 1.0f,
- outline_col,
- outline_alpha);
- GPU_matrix_pop();
- }
-
- /* Update and draw dynamic mesh preview lines. */
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
- !is_multires) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
- SCULPT_geometry_preview_lines_update(C, ss, rds);
- sculpt_geometry_preview_lines_draw(pos, ss);
- }
- }
-
- /* Draw pose brush line preview. */
- if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
- immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
- GPU_line_width(2.0f);
-
- immBegin(GPU_PRIM_LINES, ss->pose_ik_chain_preview->tot_segments * 2);
- for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
- immVertex3fv(pos, ss->pose_ik_chain_preview->segments[i].initial_orig);
- immVertex3fv(pos, ss->pose_ik_chain_preview->segments[i].initial_head);
- }
-
- immEnd();
- }
-
- GPU_matrix_pop();
-
- GPU_matrix_pop_projection();
-
- wmWindowViewport(win);
- }
- else {
- /* Draw default cursor when the mouse is not over the mesh or there are no supported
- * overlays active. */
- GPU_line_width(1.0f);
- /* Reduce alpha to increase the contrast when the cursor is over the mesh. */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.8);
- imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 80);
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.35f);
- imm_draw_circle_wire_3d(pos,
- translation[0],
- translation[1],
- final_radius * clamp_f(brush->alpha, 0.0f, 1.0f),
- 80);
- }
- }
- else {
- if (vc.obact->sculpt->cache &&
- !SCULPT_stroke_is_first_brush_step_of_symmetry_pass(vc.obact->sculpt->cache)) {
- wmViewport(&region->winrct);
-
- /* Draw cached dynamic mesh preview lines. */
- if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
- !is_multires) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(wm,
- CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- region,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- sculpt_geometry_preview_lines_draw(pos, ss);
- GPU_matrix_pop();
- GPU_matrix_pop_projection();
- }
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_MULTIPLANE_SCRAPE &&
- brush->flag2 & BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW &&
- !SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(wm,
- CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- region,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- SCULPT_multiplane_scrape_preview_draw(pos, ss, outline_col, outline_alpha);
- GPU_matrix_pop();
- GPU_matrix_pop_projection();
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
- !SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(CTX_wm_manager(C),
- CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- region,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
-
- /* Plane falloff preview */
- if (brush->cloth_force_falloff_type == BRUSH_CLOTH_FORCE_FALLOFF_PLANE) {
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- SCULPT_cloth_plane_falloff_preview_draw(pos, ss, outline_col, outline_alpha);
- GPU_matrix_pop();
- }
-
- /* Display the simulation limits if sculpting outside them. */
- /* This does not makes much sense of plane fallof as the fallof is infinte. */
- else if (brush->cloth_force_falloff_type == BRUSH_CLOTH_FORCE_FALLOFF_RADIAL) {
- if (len_v3v3(ss->cache->true_location, ss->cache->true_initial_location) >
- ss->cache->radius * (1.0f + brush->cloth_sim_limit)) {
- const float red[3] = {1.0f, 0.2f, 0.2f};
- GPU_matrix_push();
- SCULPT_cloth_simulation_limits_draw(pos,
- brush,
- vc.obact->obmat,
- ss->cache->true_initial_location,
- ss->cache->true_initial_normal,
- ss->cache->radius,
- 2.0f,
- red,
- 0.8f);
- GPU_matrix_pop();
- }
- }
-
- GPU_matrix_pop_projection();
- }
-
- wmWindowViewport(win);
- }
+ else if (brush->cloth_force_falloff_type == BRUSH_CLOTH_FORCE_FALLOFF_RADIAL) {
+ /* Display the simulation limits if sculpting outside them. */
+ /* This does not makes much sense of plane fallof as the fallof is infinte. */
+
+ if (len_v3v3(ss->cache->true_location, ss->cache->true_initial_location) >
+ ss->cache->radius * (1.0f + brush->cloth_sim_limit)) {
+ const float red[3] = {1.0f, 0.2f, 0.2f};
+ SCULPT_cloth_simulation_limits_draw(pcontext->pos,
+ brush,
+ ss->cache->true_initial_location,
+ ss->cache->true_initial_normal,
+ ss->cache->radius,
+ 2.0f,
+ red,
+ 0.8f);
}
}
- else {
- /* Draw default cursor in unsupported modes. */
- GPU_line_width(1.0f);
- imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
+ }
+
+ GPU_matrix_pop();
+
+ /* This Cloth brush cursor overlay always works in cursor space. */
+ paint_cursor_drawing_setup_cursor_space(pcontext);
+
+ GPU_matrix_pop_projection();
+ wmWindowViewport(pcontext->win);
+}
+
+static void paint_cursor_draw_3D_view_brush_cursor(PaintCursorContext *pcontext)
+{
+
+ /* These paint tools are not using the SculptSession, so they need to use the default 2D brush
+ * cursor in the 3D view. */
+ if (pcontext->mode != PAINT_MODE_SCULPT || !pcontext->ss) {
+ paint_draw_legacy_3D_view_brush_cursor(pcontext);
+ return;
+ }
+
+ paint_cursor_sculpt_session_update_and_init(pcontext);
+
+ if (pcontext->is_stroke_active) {
+ paint_cursor_cursor_draw_3d_view_brush_cursor_active(pcontext);
+ }
+ else {
+ paint_cursor_draw_3d_view_brush_cursor_inactive(pcontext);
+ }
+}
+
+static bool paint_cursor_is_3d_view_navigating(PaintCursorContext *pcontext)
+{
+ ViewContext *vc = &pcontext->vc;
+ return vc->rv3d && (vc->rv3d->rflag & RV3D_NAVIGATING);
+}
+
+static bool paint_cursor_is_brush_cursor_enabled(PaintCursorContext *pcontext)
+{
+ if (pcontext->paint->flags & PAINT_SHOW_BRUSH) {
+ if (ELEM(pcontext->mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) &&
+ pcontext->brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ return false;
}
+ return true;
}
+ return false;
+}
- immUnbindProgram();
+static void paint_cursor_update_rake_rotation(PaintCursorContext *pcontext)
+{
+ /* Don't calculate rake angles while a stroke is active because the rake variables are global
+ * and we may get interference with the stroke itself.
+ * For line strokes, such interference is visible. */
+ if (!pcontext->ups->stroke_active) {
+ paint_calculate_rake_rotation(pcontext->ups, pcontext->brush, pcontext->translation);
+ }
+}
- /* Restore GL state. */
+static void paint_cursor_check_and_draw_alpha_overlays(PaintCursorContext *pcontext)
+{
+ pcontext->alpha_overlay_drawn = paint_draw_alpha_overlay(pcontext->ups,
+ pcontext->brush,
+ &pcontext->vc,
+ pcontext->x,
+ pcontext->y,
+ pcontext->zoomx,
+ pcontext->mode);
+}
+
+static void paint_cursor_update_anchored_location(PaintCursorContext *pcontext)
+{
+ UnifiedPaintSettings *ups = pcontext->ups;
+ if (ups->draw_anchored) {
+ pcontext->final_radius = ups->anchored_size;
+ copy_v2_fl2(pcontext->translation,
+ ups->anchored_initial_mouse[0] + pcontext->region->winrct.xmin,
+ ups->anchored_initial_mouse[1] + pcontext->region->winrct.ymin);
+ }
+}
+
+static void paint_cursor_setup_2D_drawing(PaintCursorContext *pcontext)
+{
+ GPU_line_width(2.0f);
+ GPU_blend(true);
+ GPU_line_smooth(true);
+ pcontext->pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+}
+
+static void paint_cursor_setup_3D_drawing(PaintCursorContext *pcontext)
+{
+ GPU_line_width(2.0f);
+ GPU_blend(true);
+ GPU_line_smooth(true);
+ pcontext->pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+}
+
+static void paint_cursor_restore_drawing_state(void)
+{
+ immUnbindProgram();
GPU_blend(false);
GPU_line_smooth(false);
}
+static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
+{
+ PaintCursorContext pcontext;
+ if (!paint_cursor_context_init(C, x, y, &pcontext)) {
+ return;
+ }
+
+ if (!paint_cursor_is_brush_cursor_enabled(&pcontext)) {
+ return;
+ }
+ if (paint_cursor_is_3d_view_navigating(&pcontext)) {
+ return;
+ }
+
+ switch (pcontext.cursor_type) {
+ case PAINT_CURSOR_CURVE:
+ paint_draw_curve_cursor(pcontext.brush, &pcontext.vc);
+ break;
+ case PAINT_CURSOR_2D:
+ paint_cursor_update_rake_rotation(&pcontext);
+ paint_cursor_check_and_draw_alpha_overlays(&pcontext);
+ paint_cursor_update_anchored_location(&pcontext);
+
+ paint_cursor_setup_2D_drawing(&pcontext);
+ paint_draw_2D_view_brush_cursor(&pcontext);
+ paint_cursor_restore_drawing_state();
+ break;
+ case PAINT_CURSOR_3D:
+ paint_update_mouse_cursor(&pcontext);
+
+ paint_cursor_update_rake_rotation(&pcontext);
+ paint_cursor_check_and_draw_alpha_overlays(&pcontext);
+ paint_cursor_update_anchored_location(&pcontext);
+
+ paint_cursor_setup_3D_drawing(&pcontext);
+ paint_cursor_draw_3D_view_brush_cursor(&pcontext);
+ paint_cursor_restore_drawing_state();
+ break;
+ }
+}
+
/* Public API */
void paint_cursor_start(Paint *p, bool (*poll)(bContext *C))