diff options
author | Joseph Eagar <joeedh@gmail.com> | 2009-08-26 14:27:04 +0400 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2009-08-26 14:27:04 +0400 |
commit | de7f08cc41c7087ecde096c89ee58f43ccb1cf91 (patch) | |
tree | 401ab2a2a7429c2caa63c3135341958155a86935 /source/blender/editors/sculpt_paint | |
parent | a34ffefa0025d144826cd1bf7a136af743847f1b (diff) | |
parent | d893b0f9ff5fc21277b9c24568e224961537c23c (diff) |
merge with 2.5 at r22793
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image.c | 62 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_intern.h | 24 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_ops.c | 102 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_stroke.c | 330 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_utils.c | 53 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex.c | 858 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 751 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_stroke.c | 274 |
8 files changed, 1277 insertions, 1177 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 1b33f340d5e..128455a8487 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -71,6 +71,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_node.h" +#include "BKE_paint.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" #include "BKE_report.h" @@ -3706,7 +3707,7 @@ static void *do_projectpaint_thread(void *ph_v) ProjPaintImage *last_projIma= NULL; ImagePaintPartialRedraw *last_partial_redraw_cell; - float rgba[4], alpha, dist_nosqrt; + float rgba[4], alpha, dist_nosqrt, dist; float brush_size_sqared; float falloff; @@ -3720,6 +3721,7 @@ static void *do_projectpaint_thread(void *ph_v) float co[2]; float mask = 1.0f; /* airbrush wont use mask */ unsigned short mask_short; + float size_half = ((float)ps->brush->size) * 0.5f; LinkNode *smearPixels = NULL; LinkNode *smearPixels_f = NULL; @@ -3754,8 +3756,8 @@ static void *do_projectpaint_thread(void *ph_v) dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos); /*if (dist < s->brush->size) {*/ /* correct but uses a sqrtf */ - if (dist_nosqrt < brush_size_sqared) { - falloff = brush_sample_falloff_noalpha(ps->brush, sqrtf(dist_nosqrt)); + if (dist_nosqrt < brush_size_sqared && (dist=sqrtf(dist_nosqrt)) < size_half) { + falloff = brush_curve_strength(ps->brush, dist, size_half); if (falloff > 0.0f) { if (ps->is_texbrush) { brush_sample_tex(ps->brush, projPixel->projCoSS, rgba); @@ -4023,7 +4025,7 @@ static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s if(texpaint || (sima && sima->lock)) { int w = imapaintpartial.x2 - imapaintpartial.x1; int h = imapaintpartial.y2 - imapaintpartial.y1; - GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); + GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h, !texpaint); } } @@ -4375,15 +4377,17 @@ static Brush *image_paint_brush(bContext *C) Scene *scene= CTX_data_scene(C); ToolSettings *settings= scene->toolsettings; - return settings->imapaint.brush; + return paint_brush(&settings->imapaint.paint); } static int image_paint_poll(bContext *C) { + Object *obact = CTX_data_active_object(C); + if(!image_paint_brush(C)) return 0; - if((G.f & G_TEXTUREPAINT) && CTX_wm_region_view3d(C)) { + if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) { return 1; } else { @@ -4484,11 +4488,12 @@ static void paint_redraw(bContext *C, ImagePaintState *s, int final) } } -static int paint_init(bContext *C, wmOperator *op) +static int texture_paint_init(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); ToolSettings *settings= scene->toolsettings; PaintOperation *pop; + Brush *brush; pop= MEM_callocN(sizeof(PaintOperation), "PaintOperation"); pop->first= 1; @@ -4516,10 +4521,11 @@ static int paint_init(bContext *C, wmOperator *op) pop->ps.ar= CTX_wm_region(C); /* intialize brush */ - if(!settings->imapaint.brush) + brush= paint_brush(&settings->imapaint.paint); + if(!brush) return 0; - pop->s.brush = settings->imapaint.brush; + pop->s.brush = brush; pop->s.tool = settings->imapaint.tool; if(pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE)) pop->s.tool = PAINT_TOOL_DRAW; @@ -4607,11 +4613,13 @@ static int paint_init(bContext *C, wmOperator *op) static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) { PaintOperation *pop= op->customdata; - float time; + float time, mousef[2]; float pressure; int mouse[2], redraw; - RNA_int_get_array(itemptr, "mouse", mouse); + RNA_float_get_array(itemptr, "mouse", mousef); + mouse[0] = mousef[0]; + mouse[1] = mousef[1]; time= RNA_float_get(itemptr, "time"); pressure= RNA_float_get(itemptr, "pressure"); @@ -4670,7 +4678,7 @@ static void paint_exit(bContext *C, wmOperator *op) static int paint_exec(bContext *C, wmOperator *op) { - if(!paint_init(C, op)) { + if(!texture_paint_init(C, op)) { MEM_freeN(op->customdata); return OPERATOR_CANCELLED; } @@ -4691,7 +4699,7 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) PaintOperation *pop= op->customdata; wmTabletData *wmtab; PointerRNA itemptr; - float pressure; + float pressure, mousef[2]; double time; int tablet, mouse[2]; @@ -4712,7 +4720,7 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) tablet= (wmtab->Active != EVT_TABLET_NONE); pressure= wmtab->Pressure; if(wmtab->Active == EVT_TABLET_ERASER) - pop->s.blend= BRUSH_BLEND_ERASE_ALPHA; + pop->s.blend= IMB_BLEND_ERASE_ALPHA; } else pressure= 1.0f; @@ -4732,7 +4740,9 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) /* fill in stroke */ RNA_collection_add(op->ptr, "stroke", &itemptr); - RNA_int_set_array(&itemptr, "mouse", mouse); + mousef[0] = mouse[0]; + mousef[1] = mouse[1]; + RNA_float_set_array(&itemptr, "mouse", mousef); RNA_float_set(&itemptr, "time", (float)(time - pop->starttime)); RNA_float_set(&itemptr, "pressure", pressure); @@ -4744,7 +4754,7 @@ static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event) { PaintOperation *pop; - if(!paint_init(C, op)) { + if(!texture_paint_init(C, op)) { MEM_freeN(op->customdata); return OPERATOR_CANCELLED; } @@ -4872,7 +4882,7 @@ static int paint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *eve ToolSettings *ts = CTX_data_scene(C)->toolsettings; get_imapaint_zoom(C, &zoom, &zoom); toggle_paint_cursor(C, !ts->imapaint.paintcursor); - brush_radial_control_invoke(op, ts->imapaint.brush, 0.5 * zoom); + brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5 * zoom); return WM_radial_control_invoke(C, op, event); } @@ -4891,7 +4901,7 @@ static int paint_radial_control_exec(bContext *C, wmOperator *op) int ret; char str[256]; get_imapaint_zoom(C, &zoom, &zoom); - ret = brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->imapaint.brush, 2.0 / zoom); + ret = brush_radial_control_exec(op, paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint), 2.0 / zoom); WM_radial_control_string(op, str, 256); return ret; @@ -5144,13 +5154,13 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) me= get_mesh(ob); - if(!(G.f & G_TEXTUREPAINT) && !me) { + if(!(ob->mode & OB_MODE_TEXTURE_PAINT) && !me) { BKE_report(op->reports, RPT_ERROR, "Can only enter texture paint mode for mesh objects."); return OPERATOR_CANCELLED; } - if(G.f & G_TEXTUREPAINT) { - G.f &= ~G_TEXTUREPAINT; + if(ob->mode & OB_MODE_TEXTURE_PAINT) { + ob->mode &= ~OB_MODE_TEXTURE_PAINT; if(U.glreslimit != 0) GPU_free_images(); @@ -5159,13 +5169,13 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 0); } else { - G.f |= G_TEXTUREPAINT; + ob->mode |= OB_MODE_TEXTURE_PAINT; if(me->mtface==NULL) me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface); - brush_check_exists(&scene->toolsettings->imapaint.brush); + paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT); if(U.glreslimit != 0) GPU_free_images(); @@ -5200,13 +5210,13 @@ static int texture_paint_radial_control_invoke(bContext *C, wmOperator *op, wmEv { ToolSettings *ts = CTX_data_scene(C)->toolsettings; toggle_paint_cursor(C, !ts->imapaint.paintcursor); - brush_radial_control_invoke(op, ts->imapaint.brush, 0.5); + brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5); return WM_radial_control_invoke(C, op, event); } static int texture_paint_radial_control_exec(bContext *C, wmOperator *op) { - int ret = brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->imapaint.brush, 2); + int ret = brush_radial_control_exec(op, paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint), 2); char str[256]; WM_radial_control_string(op, str, 256); @@ -5216,7 +5226,7 @@ static int texture_paint_radial_control_exec(bContext *C, wmOperator *op) static int texture_paint_poll(bContext *C) { if(texture_paint_toggle_poll(C)) - if(G.f & G_TEXTUREPAINT) + if(CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT) return 1; return 0; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index b630975c934..ba1b57a1bef 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -29,14 +29,37 @@ #ifndef ED_PAINT_INTERN_H #define ED_PAINT_INTERN_H +struct bContext; struct Scene; struct Object; struct Mesh; +struct PaintStroke; +struct PointerRNA; struct ViewContext; +struct wmEvent; +struct wmOperator; struct wmOperatorType; struct ARegion; +/* paint_stroke.c */ +typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event); +typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr); +typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke); + +struct PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start, + StrokeUpdateStep update_step, StrokeDone done); +int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event); +int paint_stroke_exec(struct bContext *C, struct wmOperator *op); +struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke); +void *paint_stroke_mode_data(struct PaintStroke *stroke); +void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data); +int paint_poll(bContext *C); +void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C)); + /* paint_vertex.c */ +int vertex_paint_mode_poll(bContext *C); +void clear_vpaint(Scene *scene, int selected); + void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_weight_paint_radial_control(struct wmOperatorType *ot); void PAINT_OT_weight_paint(struct wmOperatorType *ot); @@ -59,6 +82,7 @@ int imapaint_pick_face(struct ViewContext *vc, struct Mesh *me, int *mval, unsig void imapaint_pick_uv(struct Scene *scene, struct Object *ob, struct Mesh *mesh, unsigned int faceindex, int *xy, float *uv); void paint_sample_color(struct Scene *scene, struct ARegion *ar, int x, int y); +void BRUSH_OT_curve_preset(struct wmOperatorType *ot); #endif /* ED_PAINT_INTERN_H */ diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index e9263ddabf0..c38b36007e9 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -1,15 +1,116 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "DNA_brush_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_paint.h" #include "ED_sculpt.h" +#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + #include "paint_intern.h" +#include <string.h> + +/* Brush operators */ +static int brush_add_exec(bContext *C, wmOperator *op) +{ + /*int type = RNA_enum_get(op->ptr, "type");*/ + Brush *br = NULL; + + br = add_brush("Brush"); + + if(br) + paint_brush_set(paint_get_active(CTX_data_scene(C)), br); + + return OPERATOR_FINISHED; +} + +static EnumPropertyItem brush_type_items[] = { + {OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt", ""}, + {OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""}, + {OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""}, + {OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""}, + {0, NULL, 0, NULL, NULL}}; + +void BRUSH_OT_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Brush"; + ot->idname= "BRUSH_OT_add"; + + /* api callbacks */ + ot->exec= brush_add_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "type", brush_type_items, OB_MODE_VERTEX_PAINT, "Type", "Which paint mode to create the brush for."); +} + +static int vertex_color_set_exec(bContext *C, wmOperator *op) +{ + int selected = RNA_boolean_get(op->ptr, "selected"); + Scene *scene = CTX_data_scene(C); + + clear_vpaint(scene, selected); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_vertex_color_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Set Vertex Colors"; + ot->idname= "PAINT_OT_vertex_color_set"; + + /* api callbacks */ + ot->exec= vertex_color_set_exec; + ot->poll= vertex_paint_mode_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "selected", 0, "Type", "Only color selected faces."); +} + /**************************** registration **********************************/ void ED_operatortypes_paint(void) { + /* brush */ + WM_operatortype_append(BRUSH_OT_add); + WM_operatortype_append(BRUSH_OT_curve_preset); + /* image */ WM_operatortype_append(PAINT_OT_texture_paint_toggle); WM_operatortype_append(PAINT_OT_texture_paint_radial_control); @@ -28,5 +129,6 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_vertex_paint_radial_control); WM_operatortype_append(PAINT_OT_vertex_paint_toggle); WM_operatortype_append(PAINT_OT_vertex_paint); + WM_operatortype_append(PAINT_OT_vertex_color_set); } diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c new file mode 100644 index 00000000000..bd9ea50e0f8 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -0,0 +1,330 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "RNA_access.h" + +#include "BKE_context.h" +#include "BKE_paint.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "BLI_arithb.h" + +#include "PIL_time.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "paint_intern.h" + +#include <float.h> +#include <math.h> + +typedef struct PaintStroke { + void *mode_data; + void *smooth_stroke_cursor; + wmTimer *timer; + + /* Cached values */ + ViewContext vc; + bglMats mats; + Brush *brush; + + float last_mouse_position[2]; + + /* Set whether any stroke step has yet occured + e.g. in sculpt mode, stroke doesn't start until cursor + passes over the mesh */ + int stroke_started; + + StrokeTestStart test_start; + StrokeUpdateStep update_step; + StrokeDone done; +} PaintStroke; + +/*** Cursor ***/ +static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata) +{ + Brush *brush = paint_brush(paint_get_active(CTX_data_scene(C))); + PaintStroke *stroke = customdata; + + glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + if(stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) { + ARegion *ar = CTX_wm_region(C); + sdrawline(x, y, (int)stroke->last_mouse_position[0] - ar->winrct.xmin, + (int)stroke->last_mouse_position[1] - ar->winrct.ymin); + } + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); +} + +static void paint_draw_cursor(bContext *C, int x, int y, void *customdata) +{ + Brush *brush = paint_brush(paint_get_active(CTX_data_scene(C))); + + glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + glTranslatef((float)x, (float)y, 0.0f); + glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40); + glTranslatef((float)-x, (float)-y, 0.0f); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); +} + +/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */ +static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2]) +{ + PointerRNA itemptr; + float cur_depth, pressure = 1; + float center[3]; + PaintStroke *stroke = op->customdata; + + cur_depth = read_cached_depth(&stroke->vc, mouse[0], mouse[1]); + view3d_unproject(&stroke->mats, center, mouse[0], mouse[1], cur_depth); + + /* Tablet */ + if(event->custom == EVT_DATA_TABLET) { + wmTabletData *wmtab= event->customdata; + if(wmtab->Active != EVT_TABLET_NONE) + pressure= wmtab->Pressure; + } + + /* Add to stroke */ + RNA_collection_add(op->ptr, "stroke", &itemptr); + RNA_float_set_array(&itemptr, "location", center); + RNA_float_set_array(&itemptr, "mouse", mouse); + RNA_boolean_set(&itemptr, "flip", event->shift); + RNA_float_set(&itemptr, "pressure", pressure); + + stroke->last_mouse_position[0] = mouse[0]; + stroke->last_mouse_position[1] = mouse[1]; + + stroke->update_step(C, stroke, &itemptr); +} + +/* Returns zero if no sculpt changes should be made, non-zero otherwise */ +static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *event) +{ + output[0] = event->x; + output[1] = event->y; + + if(stroke->brush->flag & BRUSH_SMOOTH_STROKE && stroke->brush->sculpt_tool != SCULPT_TOOL_GRAB) { + float u = stroke->brush->smooth_stroke_factor, v = 1.0 - u; + float dx = stroke->last_mouse_position[0] - event->x, dy = stroke->last_mouse_position[1] - event->y; + + /* If the mouse is moving within the radius of the last move, + don't update the mouse position. This allows sharp turns. */ + if(dx*dx + dy*dy < stroke->brush->smooth_stroke_radius * stroke->brush->smooth_stroke_radius) + return 0; + + output[0] = event->x * v + stroke->last_mouse_position[0] * u; + output[1] = event->y * v + stroke->last_mouse_position[1] * u; + } + + return 1; +} + +/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ +static int paint_space_stroke_enabled(Brush *br) +{ + return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB); +} + +/* For brushes with stroke spacing enabled, moves mouse in steps + towards the final mouse location. */ +static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2]) +{ + PaintStroke *stroke = op->customdata; + int cnt = 0; + + if(paint_space_stroke_enabled(stroke->brush)) { + float mouse[2] = {stroke->last_mouse_position[0], stroke->last_mouse_position[1]}; + float vec[2] = {final_mouse[0] - mouse[0], final_mouse[1] - mouse[1]}; + float length, scale; + int steps = 0, i; + + /* Normalize the vector between the last stroke dot and the goal */ + length = sqrt(vec[0]*vec[0] + vec[1]*vec[1]); + + if(length > FLT_EPSILON) { + scale = stroke->brush->spacing / length; + vec[0] *= scale; + vec[1] *= scale; + + steps = (int)(length / stroke->brush->spacing); + for(i = 0; i < steps; ++i, ++cnt) { + mouse[0] += vec[0]; + mouse[1] += vec[1]; + paint_brush_stroke_add_step(C, op, event, mouse); + } + } + } + + return cnt; +} + +/**** Public API ****/ + +PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start, + StrokeUpdateStep update_step, StrokeDone done) +{ + PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke"); + + stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C))); + view3d_set_viewcontext(C, &stroke->vc); + view3d_get_transformation(&stroke->vc, stroke->vc.obact, &stroke->mats); + + stroke->test_start = test_start; + stroke->update_step = update_step; + stroke->done = done; + + return stroke; +} + +int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + PaintStroke *stroke = op->customdata; + float mouse[2]; + + if(event->type == TIMER && (event->customdata != stroke->timer)) + return OPERATOR_RUNNING_MODAL; + + if(!stroke->stroke_started) { + stroke->last_mouse_position[0] = event->x; + stroke->last_mouse_position[1] = event->y; + stroke->stroke_started = stroke->test_start(C, op, event); + + if(stroke->stroke_started) { + stroke->smooth_stroke_cursor = + WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke); + + if(stroke->brush->flag & BRUSH_AIRBRUSH) + stroke->timer = WM_event_add_window_timer(CTX_wm_window(C), TIMER, stroke->brush->rate); + } + + ED_region_tag_redraw(ar); + } + + if(stroke->stroke_started) { + if(paint_smooth_stroke(stroke, mouse, event)) { + if(paint_space_stroke_enabled(stroke->brush)) { + if(!paint_space_stroke(C, op, event, mouse)) + ED_region_tag_redraw(ar); + } + else + paint_brush_stroke_add_step(C, op, event, mouse); + } + else + ED_region_tag_redraw(ar); + } + + /* TODO: fix hardcoded event here */ + if(event->type == LEFTMOUSE && event->val == 0) { + /* Exit stroke, free data */ + + if(stroke->smooth_stroke_cursor) + WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor); + + if(stroke->timer) + WM_event_remove_window_timer(CTX_wm_window(C), stroke->timer); + + stroke->done(C, stroke); + MEM_freeN(stroke); + return OPERATOR_FINISHED; + } + else + return OPERATOR_RUNNING_MODAL; +} + +int paint_stroke_exec(bContext *C, wmOperator *op) +{ + PaintStroke *stroke = op->customdata; + + RNA_BEGIN(op->ptr, itemptr, "stroke") { + stroke->update_step(C, stroke, &itemptr); + } + RNA_END; + + MEM_freeN(stroke); + op->customdata = NULL; + + return OPERATOR_FINISHED; +} + +ViewContext *paint_stroke_view_context(PaintStroke *stroke) +{ + return &stroke->vc; +} + +void *paint_stroke_mode_data(struct PaintStroke *stroke) +{ + return stroke->mode_data; +} + +void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data) +{ + stroke->mode_data = mode_data; +} + +int paint_poll(bContext *C) +{ + Paint *p = paint_get_active(CTX_data_scene(C)); + Object *ob = CTX_data_active_object(C); + + return p && ob && paint_brush(p) && + CTX_wm_area(C)->spacetype == SPACE_VIEW3D && + CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW; +} + +void paint_cursor_start(bContext *C, int (*poll)(bContext *C)) +{ + Paint *p = paint_get_active(CTX_data_scene(C)); + + if(p && !p->paint_cursor) + p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL); +} + diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 46d41c043bd..68c5232e249 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -5,21 +5,31 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" + #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "RNA_access.h" +#include "RNA_define.h" + #include "BLI_arithb.h" #include "BKE_brush.h" +#include "BKE_context.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_paint.h" + #include "BKE_utildefines.h" #include "BIF_gl.h" #include "ED_view3d.h" +#include "WM_api.h" +#include "WM_types.h" + #include "paint_intern.h" /* 3D Paint */ @@ -160,7 +170,7 @@ int imapaint_pick_face(ViewContext *vc, Mesh *me, int *mval, unsigned int *index /* used for both 3d view and image window */ void paint_sample_color(Scene *scene, ARegion *ar, int x, int y) /* frontbuf */ { - Brush **br = current_brush_source(scene); + Brush *br = paint_brush(paint_get_active(scene)); unsigned int col; char *cp; @@ -173,10 +183,43 @@ void paint_sample_color(Scene *scene, ARegion *ar, int x, int y) /* frontbuf */ cp = (char *)&col; - if(br && *br) { - (*br)->rgb[0]= cp[0]/255.0f; - (*br)->rgb[1]= cp[1]/255.0f; - (*br)->rgb[2]= cp[2]/255.0f; + if(br) { + br->rgb[0]= cp[0]/255.0f; + br->rgb[1]= cp[1]/255.0f; + br->rgb[2]= cp[2]/255.0f; } } +static int brush_curve_preset_exec(bContext *C, wmOperator *op) +{ + Brush *br = paint_brush(paint_get_active(CTX_data_scene(C))); + brush_curve_preset(br, RNA_enum_get(op->ptr, "shape")); + + return OPERATOR_FINISHED; +} + +static int brush_curve_preset_poll(bContext *C) +{ + Brush *br = paint_brush(paint_get_active(CTX_data_scene(C))); + + return br && br->curve; +} + +void BRUSH_OT_curve_preset(wmOperatorType *ot) +{ + static EnumPropertyItem prop_shape_items[] = { + {BRUSH_PRESET_SHARP, "SHARP", 0, "Sharp", ""}, + {BRUSH_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""}, + {BRUSH_PRESET_MAX, "MAX", 0, "Max", ""}, + {0, NULL, 0, NULL, NULL}}; + + ot->name= "Preset"; + ot->idname= "BRUSH_OT_curve_preset"; + + ot->exec= brush_curve_preset_exec; + ot->poll= brush_curve_preset_poll; + + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "shape", prop_shape_items, BRUSH_PRESET_SHARP, "Mode", ""); +} diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 812c41f430e..ee3d9e5baa1 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -62,6 +62,7 @@ #include "DNA_userdef_types.h" #include "RNA_access.h" +#include "RNA_define.h" #include "BKE_armature.h" #include "BKE_brush.h" @@ -76,6 +77,7 @@ #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_utildefines.h" #include "WM_api.h" @@ -90,6 +92,8 @@ #include "ED_util.h" #include "ED_view3d.h" +#include "paint_intern.h" + /* vp->mode */ #define VP_MIX 0 #define VP_ADD 1 @@ -106,9 +110,19 @@ static void error() {} /* polling - retrieve whether cursor should be set or operator should be done */ + +/* Returns true if vertex paint mode is active */ +int vertex_paint_mode_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + + return ob && ob->mode == OB_MODE_VERTEX_PAINT; +} + static int vp_poll(bContext *C) { - if(G.f & G_VERTEXPAINT) { + if(vertex_paint_mode_poll(C) && + paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) { ScrArea *sa= CTX_wm_area(C); if(sa->spacetype==SPACE_VIEW3D) { ARegion *ar= CTX_wm_region(C); @@ -121,7 +135,10 @@ static int vp_poll(bContext *C) static int wp_poll(bContext *C) { - if(G.f & G_WEIGHTPAINT) { + Object *ob = CTX_data_active_object(C); + + if(ob && ob->mode & OB_MODE_WEIGHT_PAINT && + paint_brush(&CTX_data_tool_settings(C)->wpaint->paint)) { ScrArea *sa= CTX_wm_area(C); if(sa->spacetype==SPACE_VIEW3D) { ARegion *ar= CTX_wm_region(C); @@ -132,56 +149,6 @@ static int wp_poll(bContext *C) return 0; } - -/* Cursors */ -static void vp_drawcursor(bContext *C, int x, int y, void *customdata) -{ - ToolSettings *ts= CTX_data_tool_settings(C); - - glTranslatef((float)x, (float)y, 0.0f); - - glColor4ub(255, 255, 255, 128); - glEnable( GL_LINE_SMOOTH ); - glEnable(GL_BLEND); - glutil_draw_lined_arc(0.0, M_PI*2.0, ts->vpaint->brush->size, 40); - glDisable(GL_BLEND); - glDisable( GL_LINE_SMOOTH ); - - glTranslatef((float)-x, (float)-y, 0.0f); -} - -static void wp_drawcursor(bContext *C, int x, int y, void *customdata) -{ - ToolSettings *ts= CTX_data_tool_settings(C); - - glTranslatef((float)x, (float)y, 0.0f); - - glColor4ub(200, 200, 255, 128); - glEnable( GL_LINE_SMOOTH ); - glEnable(GL_BLEND); - glutil_draw_lined_arc(0.0, M_PI*2.0, ts->wpaint->brush->size, 40); - glDisable(GL_BLEND); - glDisable( GL_LINE_SMOOTH ); - - glTranslatef((float)-x, (float)-y, 0.0f); -} - -static void toggle_paint_cursor(bContext *C, int wpaint) -{ - ToolSettings *ts = CTX_data_scene(C)->toolsettings; - VPaint *vp = wpaint ? ts->wpaint : ts->vpaint; - - if(vp->paintcursor) { - WM_paint_cursor_end(CTX_wm_manager(C), vp->paintcursor); - vp->paintcursor = NULL; - } - else { - vp->paintcursor = wpaint ? - WM_paint_cursor_activate(CTX_wm_manager(C), wp_poll, wp_drawcursor, NULL) : - WM_paint_cursor_activate(CTX_wm_manager(C), vp_poll, vp_drawcursor, NULL); - } -} - static VPaint *new_vpaint(int wpaint) { VPaint *vp= MEM_callocN(sizeof(VPaint), "VPaint"); @@ -232,7 +199,8 @@ unsigned int rgba_to_mcol(float r, float g, float b, float a) static unsigned int vpaint_get_current_col(VPaint *vp) { - return rgba_to_mcol(vp->brush->rgb[0], vp->brush->rgb[1], vp->brush->rgb[2], 1.0f); + Brush *brush = paint_brush(&vp->paint); + return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f); } void do_shared_vertexcol(Mesh *me) @@ -362,34 +330,7 @@ static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount) } -void clear_vpaint(Scene *scene) -{ - Mesh *me; - Object *ob; - unsigned int *to, paintcol; - int a; - - if((G.f & G_VERTEXPAINT)==0) return; - - ob= OBACT; - me= get_mesh(ob); - if(!ob || ob->id.lib) return; - - if(me==0 || me->mcol==0 || me->totface==0) return; - - paintcol= vpaint_get_current_col(scene->toolsettings->vpaint); - - to= (unsigned int *)me->mcol; - a= 4*me->totface; - while(a--) { - *to= paintcol; - to++; - } - DAG_object_flush_update(scene, ob, OB_RECALC_DATA); - -} - -void clear_vpaint_selectedfaces(Scene *scene) +void clear_vpaint(Scene *scene, int selected) { Mesh *me; MFace *mf; @@ -409,7 +350,7 @@ void clear_vpaint_selectedfaces(Scene *scene) mf = me->mface; mcol = (unsigned int*)me->mcol; for (i = 0; i < me->totface; i++, mf++, mcol+=4) { - if (mf->flag & ME_FACE_SEL) { + if (!selected || mf->flag & ME_FACE_SEL) { mcol[0] = paintcol; mcol[1] = paintcol; mcol[2] = paintcol; @@ -540,10 +481,10 @@ void vpaint_dogamma(Scene *scene) int a, temp; unsigned char *cp, gamtab[256]; - if((G.f & G_VERTEXPAINT)==0) return; - ob= OBACT; me= get_mesh(ob); + + if(!(ob->mode & OB_MODE_VERTEX_PAINT)) return; if(me==0 || me->mcol==0 || me->totface==0) return; igam= 1.0/vp->gamma; @@ -721,6 +662,7 @@ static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac) static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha) { + Brush *brush = paint_brush(&vp->paint); if(vp->mode==VP_MIX || vp->mode==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha); else if(vp->mode==VP_ADD) *col= mcol_add( *col, paintcol, alpha); @@ -734,7 +676,7 @@ static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, u unsigned int testcol=0, a; char *cp, *ct, *co; - alpha= (int)(255.0*vp->brush->alpha); + alpha= (int)(255.0*brush->alpha); if(vp->mode==VP_MIX || vp->mode==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha); else if(vp->mode==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha); @@ -798,8 +740,9 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x return tot; } -static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, short *mval) +static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, float *mval) { + Brush *brush = paint_brush(&vp->paint); float fac, dx, dy; int alpha; short vertco[2]; @@ -810,14 +753,14 @@ static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], floa dy= mval[1]-vertco[1]; fac= sqrt(dx*dx + dy*dy); - if(fac > vp->brush->size) return 0; + if(fac > brush->size) return 0; if(vp->flag & VP_HARD) alpha= 255; else - alpha= 255.0*vp->brush->alpha*(1.0-fac/vp->brush->size); + alpha= 255.0*brush->alpha*(1.0-fac/brush->size); } else { - alpha= 255.0*vp->brush->alpha; + alpha= 255.0*brush->alpha; } if(vp->flag & VP_NORMALS) { @@ -839,6 +782,7 @@ static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], floa static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval) { + Brush *brush = paint_brush(&wp->paint); if(dw==NULL || uw==NULL) return; @@ -864,7 +808,7 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float if((wp->flag & VP_SPRAY)==0) { float testw=0.0f; - alpha= wp->brush->alpha; + alpha= brush->alpha; if(wp->mode==VP_MIX || wp->mode==VP_BLUR) testw = paintval*alpha + uw->weight*(1.0-alpha); else if(wp->mode==VP_ADD) @@ -1092,12 +1036,12 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */ if(me && me->totface>=MAXINDEX) { error("Maximum number of faces: %d", MAXINDEX-1); - G.f &= ~G_WEIGHTPAINT; + ob->mode &= ~OB_MODE_WEIGHT_PAINT; return OPERATOR_CANCELLED; } - if(G.f & G_WEIGHTPAINT) G.f &= ~G_WEIGHTPAINT; - else G.f |= G_WEIGHTPAINT; + if(ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT; + else ob->mode |= OB_MODE_WEIGHT_PAINT; /* Weightpaint works by overriding colors in mesh, @@ -1107,21 +1051,20 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */ */ DAG_object_flush_update(scene, ob, OB_RECALC_DATA); - if(G.f & G_WEIGHTPAINT) { + if(ob->mode & OB_MODE_WEIGHT_PAINT) { Object *par; if(wp==NULL) wp= scene->toolsettings->wpaint= new_vpaint(1); - brush_check_exists(&wp->brush); - - toggle_paint_cursor(C, 1); + paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); + paint_cursor_start(C, wp_poll); mesh_octree_table(ob, NULL, NULL, 's'); /* verify if active weight group is also active bone */ par= modifiers_isDeformedByArmature(ob); - if(par && (par->flag & OB_POSEMODE)) { + if(par && (par->mode & OB_MODE_POSE)) { bPoseChannel *pchan; for(pchan= par->pose->chanbase.first; pchan; pchan= pchan->next) if(pchan->bone->flag & BONE_ACTIVE) @@ -1131,9 +1074,6 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */ } } else { - if(wp) - toggle_paint_cursor(C, 1); - mesh_octree_table(ob, NULL, NULL, 'e'); } @@ -1174,8 +1114,12 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) static int vpaint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) { - toggle_paint_cursor(C, 0); - brush_radial_control_invoke(op, CTX_data_scene(C)->toolsettings->vpaint->brush, 1); + Paint *p = paint_get_active(CTX_data_scene(C)); + Brush *brush = paint_brush(p); + + WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor); + p->paint_cursor = NULL; + brush_radial_control_invoke(op, brush, 1); return WM_radial_control_invoke(C, op, event); } @@ -1183,19 +1127,24 @@ static int vpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve { int ret = WM_radial_control_modal(C, op, event); if(ret != OPERATOR_RUNNING_MODAL) - toggle_paint_cursor(C, 0); + paint_cursor_start(C, vp_poll); return ret; } static int vpaint_radial_control_exec(bContext *C, wmOperator *op) { - return brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->vpaint->brush, 1); + Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->vpaint->paint); + return brush_radial_control_exec(op, brush, 1); } static int wpaint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) { - toggle_paint_cursor(C, 1); - brush_radial_control_invoke(op, CTX_data_scene(C)->toolsettings->wpaint->brush, 1); + Paint *p = paint_get_active(CTX_data_scene(C)); + Brush *brush = paint_brush(p); + + WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor); + p->paint_cursor = NULL; + brush_radial_control_invoke(op, brush, 1); return WM_radial_control_invoke(C, op, event); } @@ -1203,13 +1152,14 @@ static int wpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve { int ret = WM_radial_control_modal(C, op, event); if(ret != OPERATOR_RUNNING_MODAL) - toggle_paint_cursor(C, 1); + paint_cursor_start(C, wp_poll); return ret; } static int wpaint_radial_control_exec(bContext *C, wmOperator *op) { - return brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->wpaint->brush, 1); + Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->wpaint->paint); + return brush_radial_control_exec(op, brush, 1); } void PAINT_OT_weight_paint_radial_control(wmOperatorType *ot) @@ -1254,206 +1204,10 @@ struct WPaintData { float wpimat[3][3]; }; -static void wpaint_exit(bContext *C, wmOperator *op) -{ - ToolSettings *ts= CTX_data_tool_settings(C); - Object *ob= CTX_data_active_object(C); - struct WPaintData *wpd= op->customdata; - - if(wpd->vertexcosnos) - MEM_freeN(wpd->vertexcosnos); - MEM_freeN(wpd->indexar); - - /* frees prev buffer */ - copy_wpaint_prev(ts->wpaint, NULL, 0); - - /* and particles too */ - if(ob->particlesystem.first) { - ParticleSystem *psys; - int i; - - for(psys= ob->particlesystem.first; psys; psys= psys->next) { - for(i=0; i<PSYS_TOT_VG; i++) { - if(psys->vgroup[i]==ob->actdef) { - psys->recalc |= PSYS_RECALC_RESET; - break; - } - } - } - } - - DAG_object_flush_update(CTX_data_scene(C), ob, OB_RECALC_DATA); - - MEM_freeN(wpd); - op->customdata= NULL; -} - - -static int wpaint_modal(bContext *C, wmOperator *op, wmEvent *event) -{ - ToolSettings *ts= CTX_data_tool_settings(C); - VPaint *wp= ts->wpaint; - - switch(event->type) { - case LEFTMOUSE: - if(event->val==0) { /* release */ - wpaint_exit(C, op); - return OPERATOR_FINISHED; - } - /* pass on, first press gets painted too */ - - case MOUSEMOVE: - { - struct WPaintData *wpd= op->customdata; - ViewContext *vc= &wpd->vc; - Object *ob= vc->obact; - Mesh *me= ob->data; - float mat[4][4]; - float paintweight= ts->vgroup_weight; - int *indexar= wpd->indexar; - int totindex, index, alpha, totw; - short mval[2]; - - view3d_operator_needs_opengl(C); - - /* load projection matrix */ - wmMultMatrix(ob->obmat); - wmGetSingleMatrix(mat); - wmLoadMatrix(wpd->vc.rv3d->viewmat); - - MTC_Mat4SwapMat4(wpd->vc.rv3d->persmat, mat); - - mval[0]= event->x - vc->ar->winrct.xmin; - mval[1]= event->y - vc->ar->winrct.ymin; - - /* which faces are involved */ - if(wp->flag & VP_AREA) { - totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], wp->brush->size); - } - else { - indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); - if(indexar[0]) totindex= 1; - else totindex= 0; - } - - if(wp->flag & VP_COLINDEX) { - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - - if(mface->mat_nr!=ob->actcol-1) { - indexar[index]= 0; - } - } - } - } - - if((G.f & G_FACESELECT) && me->mface) { - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - - if((mface->flag & ME_FACE_SEL)==0) { - indexar[index]= 0; - } - } - } - } - - /* make sure each vertex gets treated only once */ - /* and calculate filter weight */ - totw= 0; - if(wp->mode==VP_BLUR) - paintweight= 0.0f; - else - paintweight= ts->vgroup_weight; - - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= me->mface + (indexar[index]-1); - - (me->dvert+mface->v1)->flag= 1; - (me->dvert+mface->v2)->flag= 1; - (me->dvert+mface->v3)->flag= 1; - if(mface->v4) (me->dvert+mface->v4)->flag= 1; - - if(wp->mode==VP_BLUR) { - MDeformWeight *dw, *(*dw_func)(MDeformVert *, int) = verify_defweight; - - if(wp->flag & VP_ONLYVGROUP) - dw_func= get_defweight; - - dw= dw_func(me->dvert+mface->v1, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} - dw= dw_func(me->dvert+mface->v2, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} - dw= dw_func(me->dvert+mface->v3, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} - if(mface->v4) { - dw= dw_func(me->dvert+mface->v4, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} - } - } - } - } - - if(wp->mode==VP_BLUR) - paintweight/= (float)totw; - - for(index=0; index<totindex; index++) { - - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= me->mface + (indexar[index]-1); - - if((me->dvert+mface->v1)->flag) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v1, alpha, paintweight, wpd->vgroup_mirror); - } - (me->dvert+mface->v1)->flag= 0; - } - - if((me->dvert+mface->v2)->flag) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v2, alpha, paintweight, wpd->vgroup_mirror); - } - (me->dvert+mface->v2)->flag= 0; - } - - if((me->dvert+mface->v3)->flag) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v3, alpha, paintweight, wpd->vgroup_mirror); - } - (me->dvert+mface->v3)->flag= 0; - } - - if((me->dvert+mface->v4)->flag) { - if(mface->v4) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v4, alpha, paintweight, wpd->vgroup_mirror); - } - (me->dvert+mface->v4)->flag= 0; - } - } - } - } - - MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); - - DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA); - ED_region_tag_redraw(vc->ar); - } - } - - return OPERATOR_RUNNING_MODAL; -} - -static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *event) { Scene *scene= CTX_data_scene(C); + struct PaintStroke *stroke = op->customdata; ToolSettings *ts= CTX_data_tool_settings(C); VPaint *wp= ts->wpaint; Object *ob= CTX_data_active_object(C); @@ -1462,7 +1216,6 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) float mat[4][4], imat[4][4]; if(scene->obedit) return OPERATOR_CANCELLED; - // XXX if(multires_level1_test()) return; me= get_mesh(ob); if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; @@ -1471,8 +1224,9 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) if (!me->dvert) create_dverts(&me->id); - /* make customdata storage */ - op->customdata= wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData"); + /* make mode data storage */ + wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData"); + paint_stroke_set_mode_data(stroke, wpd); view3d_set_viewcontext(C, &wpd->vc); wpd->vgroup_mirror= -1; @@ -1544,11 +1298,203 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) } } - /* do paint once for click only paint */ - wpaint_modal(C, op, event); + return 1; +} + +static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) +{ + ToolSettings *ts= CTX_data_tool_settings(C); + VPaint *wp= ts->wpaint; + Brush *brush = paint_brush(&wp->paint); + struct WPaintData *wpd= paint_stroke_mode_data(stroke); + ViewContext *vc= &wpd->vc; + Object *ob= vc->obact; + Mesh *me= ob->data; + float mat[4][4]; + float paintweight= ts->vgroup_weight; + int *indexar= wpd->indexar; + int totindex, index, alpha, totw; + float mval[2]; + + view3d_operator_needs_opengl(C); + + /* load projection matrix */ + wmMultMatrix(ob->obmat); + wmGetSingleMatrix(mat); + wmLoadMatrix(wpd->vc.rv3d->viewmat); + + RNA_float_get_array(itemptr, "mouse", mval); + mval[0]-= vc->ar->winrct.xmin; + mval[1]-= vc->ar->winrct.ymin; + + MTC_Mat4SwapMat4(wpd->vc.rv3d->persmat, mat); + + /* which faces are involved */ + if(wp->flag & VP_AREA) { + totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush->size); + } + else { + indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); + if(indexar[0]) totindex= 1; + else totindex= 0; + } + + if(wp->flag & VP_COLINDEX) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + + if(mface->mat_nr!=ob->actcol-1) { + indexar[index]= 0; + } + } + } + } + + if((G.f & G_FACESELECT) && me->mface) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + + if((mface->flag & ME_FACE_SEL)==0) { + indexar[index]= 0; + } + } + } + } + + /* make sure each vertex gets treated only once */ + /* and calculate filter weight */ + totw= 0; + if(wp->mode==VP_BLUR) + paintweight= 0.0f; + else + paintweight= ts->vgroup_weight; + + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= me->mface + (indexar[index]-1); + + (me->dvert+mface->v1)->flag= 1; + (me->dvert+mface->v2)->flag= 1; + (me->dvert+mface->v3)->flag= 1; + if(mface->v4) (me->dvert+mface->v4)->flag= 1; + + if(wp->mode==VP_BLUR) { + MDeformWeight *dw, *(*dw_func)(MDeformVert *, int) = verify_defweight; + + if(wp->flag & VP_ONLYVGROUP) + dw_func= get_defweight; + + dw= dw_func(me->dvert+mface->v1, ob->actdef-1); + if(dw) {paintweight+= dw->weight; totw++;} + dw= dw_func(me->dvert+mface->v2, ob->actdef-1); + if(dw) {paintweight+= dw->weight; totw++;} + dw= dw_func(me->dvert+mface->v3, ob->actdef-1); + if(dw) {paintweight+= dw->weight; totw++;} + if(mface->v4) { + dw= dw_func(me->dvert+mface->v4, ob->actdef-1); + if(dw) {paintweight+= dw->weight; totw++;} + } + } + } + } + + if(wp->mode==VP_BLUR) + paintweight/= (float)totw; + + for(index=0; index<totindex; index++) { + + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= me->mface + (indexar[index]-1); + + if((me->dvert+mface->v1)->flag) { + alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval); + if(alpha) { + do_weight_paint_vertex(wp, ob, mface->v1, alpha, paintweight, wpd->vgroup_mirror); + } + (me->dvert+mface->v1)->flag= 0; + } + + if((me->dvert+mface->v2)->flag) { + alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval); + if(alpha) { + do_weight_paint_vertex(wp, ob, mface->v2, alpha, paintweight, wpd->vgroup_mirror); + } + (me->dvert+mface->v2)->flag= 0; + } + + if((me->dvert+mface->v3)->flag) { + alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval); + if(alpha) { + do_weight_paint_vertex(wp, ob, mface->v3, alpha, paintweight, wpd->vgroup_mirror); + } + (me->dvert+mface->v3)->flag= 0; + } + + if((me->dvert+mface->v4)->flag) { + if(mface->v4) { + alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval); + if(alpha) { + do_weight_paint_vertex(wp, ob, mface->v4, alpha, paintweight, wpd->vgroup_mirror); + } + (me->dvert+mface->v4)->flag= 0; + } + } + } + } + + MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); + + DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA); + ED_region_tag_redraw(vc->ar); +} + +static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke) +{ + ToolSettings *ts= CTX_data_tool_settings(C); + Object *ob= CTX_data_active_object(C); + struct WPaintData *wpd= paint_stroke_mode_data(stroke); + + if(wpd->vertexcosnos) + MEM_freeN(wpd->vertexcosnos); + MEM_freeN(wpd->indexar); + + /* frees prev buffer */ + copy_wpaint_prev(ts->wpaint, NULL, 0); + + /* and particles too */ + if(ob->particlesystem.first) { + ParticleSystem *psys; + int i; + + for(psys= ob->particlesystem.first; psys; psys= psys->next) { + for(i=0; i<PSYS_TOT_VG; i++) { + if(psys->vgroup[i]==ob->actdef) { + psys->recalc |= PSYS_RECALC_RESET; + break; + } + } + } + } + + DAG_object_flush_update(CTX_data_scene(C), ob, OB_RECALC_DATA); + + MEM_freeN(wpd); +} + + +static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + + op->customdata = paint_stroke_new(C, wpaint_stroke_test_start, + wpaint_stroke_update_step, + wpaint_stroke_done); /* add modal handler */ WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + + op->type->modal(C, op, event); return OPERATOR_RUNNING_MODAL; } @@ -1562,13 +1508,14 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) /* api callbacks */ ot->invoke= wpaint_invoke; - ot->modal= wpaint_modal; + ot->modal= paint_stroke_modal; /* ot->exec= vpaint_exec; <-- needs stroke property */ ot->poll= wp_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; - + + RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); } /* ************ set / clear vertex paint mode ********** */ @@ -1584,40 +1531,35 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ me= get_mesh(ob); if(me==NULL || object_data_is_libdata(ob)) { - G.f &= ~G_VERTEXPAINT; + ob->mode &= ~OB_MODE_VERTEX_PAINT; return OPERATOR_PASS_THROUGH; } if(me && me->totface>=MAXINDEX) { error("Maximum number of faces: %d", MAXINDEX-1); - G.f &= ~G_VERTEXPAINT; + ob->mode &= ~OB_MODE_VERTEX_PAINT; return OPERATOR_FINISHED; } if(me && me->mcol==NULL) make_vertexcol(scene, 0); /* toggle: end vpaint */ - if(G.f & G_VERTEXPAINT) { + if(ob->mode & OB_MODE_VERTEX_PAINT) { - G.f &= ~G_VERTEXPAINT; - - if(vp) { - toggle_paint_cursor(C, 0); - vp->paintcursor= NULL; - } + ob->mode &= ~OB_MODE_VERTEX_PAINT; } else { - - G.f |= G_VERTEXPAINT; + ob->mode |= OB_MODE_VERTEX_PAINT; /* Turn off weight painting */ - if (G.f & G_WEIGHTPAINT) + if (ob->mode & OB_MODE_WEIGHT_PAINT) set_wpaint(C, op); if(vp==NULL) vp= scene->toolsettings->vpaint= new_vpaint(0); - toggle_paint_cursor(C, 0); - brush_check_exists(&scene->toolsettings->vpaint->brush); + paint_cursor_start(C, vp_poll); + + paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT); } if (me) @@ -1676,177 +1618,175 @@ struct VPaintData { float vpimat[3][3]; }; -static void vpaint_exit(bContext *C, wmOperator *op) +static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event) { ToolSettings *ts= CTX_data_tool_settings(C); - struct VPaintData *vpd= op->customdata; + struct PaintStroke *stroke = op->customdata; + VPaint *vp= ts->vpaint; + struct VPaintData *vpd; + Object *ob= CTX_data_active_object(C); + Mesh *me; + float mat[4][4], imat[4][4]; + + /* context checks could be a poll() */ + me= get_mesh(ob); + if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; - if(vpd->vertexcosnos) - MEM_freeN(vpd->vertexcosnos); - MEM_freeN(vpd->indexar); + if(me->mcol==NULL) make_vertexcol(CTX_data_scene(C), 0); + if(me->mcol==NULL) return OPERATOR_CANCELLED; - /* frees prev buffer */ - copy_vpaint_prev(ts->vpaint, NULL, 0); + /* make mode data storage */ + vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData"); + paint_stroke_set_mode_data(stroke, vpd); + view3d_set_viewcontext(C, &vpd->vc); - MEM_freeN(vpd); - op->customdata= NULL; + vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob); + vpd->indexar= get_indexarray(); + vpd->paintcol= vpaint_get_current_col(vp); + + /* for filtering */ + copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface); + + /* some old cruft to sort out later */ + Mat4MulMat4(mat, ob->obmat, vpd->vc.rv3d->viewmat); + Mat4Invert(imat, mat); + Mat3CpyMat4(vpd->vpimat, imat); + + return 1; } -static int vpaint_modal(bContext *C, wmOperator *op, wmEvent *event) +static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { ToolSettings *ts= CTX_data_tool_settings(C); + struct VPaintData *vpd = paint_stroke_mode_data(stroke); VPaint *vp= ts->vpaint; - - switch(event->type) { - case LEFTMOUSE: - if(event->val==0) { /* release */ - vpaint_exit(C, op); - return OPERATOR_FINISHED; - } - /* pass on, first press gets painted too */ - - case MOUSEMOVE: - { - struct VPaintData *vpd= op->customdata; - ViewContext *vc= &vpd->vc; - Object *ob= vc->obact; - Mesh *me= ob->data; - float mat[4][4]; - int *indexar= vpd->indexar; - int totindex, index; - short mval[2]; + Brush *brush = paint_brush(&vp->paint); + ViewContext *vc= &vpd->vc; + Object *ob= vc->obact; + Mesh *me= ob->data; + float mat[4][4]; + int *indexar= vpd->indexar; + int totindex, index; + float mval[2]; + + RNA_float_get_array(itemptr, "mouse", mval); - view3d_operator_needs_opengl(C); + view3d_operator_needs_opengl(C); - /* load projection matrix */ - wmMultMatrix(ob->obmat); - wmGetSingleMatrix(mat); - wmLoadMatrix(vc->rv3d->viewmat); + /* load projection matrix */ + wmMultMatrix(ob->obmat); + wmGetSingleMatrix(mat); + wmLoadMatrix(vc->rv3d->viewmat); + + mval[0]-= vc->ar->winrct.xmin; + mval[1]-= vc->ar->winrct.ymin; + - mval[0]= event->x - vc->ar->winrct.xmin; - mval[1]= event->y - vc->ar->winrct.ymin; - - /* which faces are involved */ - if(vp->flag & VP_AREA) { - totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], vp->brush->size); - } - else { - indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); - if(indexar[0]) totindex= 1; - else totindex= 0; - } + /* which faces are involved */ + if(vp->flag & VP_AREA) { + totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush->size); + } + else { + indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); + if(indexar[0]) totindex= 1; + else totindex= 0; + } - MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); + MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); - if(vp->flag & VP_COLINDEX) { - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + if(vp->flag & VP_COLINDEX) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - if(mface->mat_nr!=ob->actcol-1) { - indexar[index]= 0; - } - } + if(mface->mat_nr!=ob->actcol-1) { + indexar[index]= 0; } - } - if((G.f & G_FACESELECT) && me->mface) { - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + } + } + } + if((G.f & G_FACESELECT) && me->mface) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - if((mface->flag & ME_FACE_SEL)==0) - indexar[index]= 0; - } - } - } + if((mface->flag & ME_FACE_SEL)==0) + indexar[index]= 0; + } + } + } - for(index=0; index<totindex; index++) { + for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - unsigned int *mcol= ( (unsigned int *)me->mcol) + 4*(indexar[index]-1); - unsigned int *mcolorig= ( (unsigned int *)vp->vpaint_prev) + 4*(indexar[index]-1); - int alpha; + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + unsigned int *mcol= ( (unsigned int *)me->mcol) + 4*(indexar[index]-1); + unsigned int *mcolorig= ( (unsigned int *)vp->vpaint_prev) + 4*(indexar[index]-1); + int alpha; - if(vp->mode==VP_BLUR) { - unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128); - if(mface->v4) { - unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128); - vpd->paintcol= mcol_blend( fcol1, fcol2, 128); - } - else { - vpd->paintcol= mcol_blend( mcol[2], fcol1, 170); - } + if(vp->mode==VP_BLUR) { + unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128); + if(mface->v4) { + unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128); + vpd->paintcol= mcol_blend( fcol1, fcol2, 128); + } + else { + vpd->paintcol= mcol_blend( mcol[2], fcol1, 170); + } - } + } - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v1, mval); - if(alpha) vpaint_blend(vp, mcol, mcolorig, vpd->paintcol, alpha); + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v1, mval); + if(alpha) vpaint_blend(vp, mcol, mcolorig, vpd->paintcol, alpha); - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v2, mval); - if(alpha) vpaint_blend(vp, mcol+1, mcolorig+1, vpd->paintcol, alpha); + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v2, mval); + if(alpha) vpaint_blend(vp, mcol+1, mcolorig+1, vpd->paintcol, alpha); - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v3, mval); - if(alpha) vpaint_blend(vp, mcol+2, mcolorig+2, vpd->paintcol, alpha); + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v3, mval); + if(alpha) vpaint_blend(vp, mcol+2, mcolorig+2, vpd->paintcol, alpha); - if(mface->v4) { - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v4, mval); - if(alpha) vpaint_blend(vp, mcol+3, mcolorig+3, vpd->paintcol, alpha); - } - } + if(mface->v4) { + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v4, mval); + if(alpha) vpaint_blend(vp, mcol+3, mcolorig+3, vpd->paintcol, alpha); } + } + } - MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); + MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); - do_shared_vertexcol(me); + do_shared_vertexcol(me); - ED_region_tag_redraw(vc->ar); + ED_region_tag_redraw(vc->ar); - DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA); - } - break; - } - - return OPERATOR_RUNNING_MODAL; + DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA); } -static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) { ToolSettings *ts= CTX_data_tool_settings(C); - VPaint *vp= ts->vpaint; - struct VPaintData *vpd; - Object *ob= CTX_data_active_object(C); - Mesh *me; - float mat[4][4], imat[4][4]; + struct VPaintData *vpd= paint_stroke_mode_data(stroke); - /* context checks could be a poll() */ - me= get_mesh(ob); - if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; - - if(me->mcol==NULL) make_vertexcol(CTX_data_scene(C), 0); - if(me->mcol==NULL) return OPERATOR_CANCELLED; - - /* make customdata storage */ - op->customdata= vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData"); - view3d_set_viewcontext(C, &vpd->vc); - - vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob); - vpd->indexar= get_indexarray(); - vpd->paintcol= vpaint_get_current_col(vp); + if(vpd->vertexcosnos) + MEM_freeN(vpd->vertexcosnos); + MEM_freeN(vpd->indexar); - /* for filtering */ - copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface); + /* frees prev buffer */ + copy_vpaint_prev(ts->vpaint, NULL, 0); - /* some old cruft to sort out later */ - Mat4MulMat4(mat, ob->obmat, vpd->vc.rv3d->viewmat); - Mat4Invert(imat, mat); - Mat3CpyMat4(vpd->vpimat, imat); + MEM_freeN(vpd); +} + +static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ - /* do paint once for click only paint */ - vpaint_modal(C, op, event); + op->customdata = paint_stroke_new(C, vpaint_stroke_test_start, + vpaint_stroke_update_step, + vpaint_stroke_done); /* add modal handler */ WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + + op->type->modal(C, op, event); return OPERATOR_RUNNING_MODAL; } @@ -1859,11 +1799,13 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) /* api callbacks */ ot->invoke= vpaint_invoke; - ot->modal= vpaint_modal; + ot->modal= paint_stroke_modal; /* ot->exec= vpaint_exec; <-- needs stroke property */ ot->poll= vp_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; + + RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 8cca135d99d..ba48bebce78 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -64,6 +64,7 @@ #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_multires.h" +#include "BKE_paint.h" #include "BKE_sculpt.h" #include "BKE_texture.h" #include "BKE_utildefines.h" @@ -79,6 +80,7 @@ #include "ED_space_api.h" #include "ED_util.h" #include "ED_view3d.h" +#include "paint_intern.h" #include "sculpt_intern.h" #include "RNA_access.h" @@ -124,29 +126,27 @@ typedef enum StrokeFlags { */ typedef struct StrokeCache { /* Invariants */ - float radius; + float initial_radius; float scale[3]; int flag; float clip_tolerance[3]; - int initial_mouse[2]; + float initial_mouse[2]; float depth; /* Variants */ + float radius; float true_location[3]; float location[3]; float flip; float pressure; - int mouse[2]; + float mouse[2]; /* The rest is temporary storage that isn't saved as a property */ int first_time; /* Beginning of stroke may do some things special */ - ViewContext vc; bglMats *mats; - float *layer_disps; /* Displacements for each vertex */ - float (*mesh_store)[3]; /* Copy of the mesh vertices' locations */ short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */ float (*face_norms)[3]; /* Copy of the mesh faces' normals */ float rotation; /* Texture rotation (radians) for anchored and rake modes */ @@ -178,19 +178,6 @@ typedef struct ProjVert { * Simple functions to get data from the GL */ -/* Uses window coordinates (x,y) and depth component z to find a point in - modelspace */ -static void unproject(bglMats *mats, float out[3], const short x, const short y, const float z) -{ - double ux, uy, uz; - - gluUnProject(x,y,z, mats->modelview, mats->projection, - (GLint *)mats->viewport, &ux, &uy, &uz ); - out[0] = ux; - out[1] = uy; - out[2] = uz; -} - /* Convert a point in model coordinates to 2D screen coordinates. */ static void projectf(bglMats *mats, const float v[3], float p[2]) { @@ -215,36 +202,23 @@ static void project(bglMats *mats, const float v[3], short p[2]) * */ -/* Return modified brush size. Uses current tablet pressure (if available) to - shrink the brush. Skipped for grab brush because only the first mouse down - size is used, which is small if the user has just touched the pen to the - tablet */ -static char brush_size(Sculpt *sd) -{ - float size= sd->brush->size; - - if((sd->brush->sculpt_tool != SCULPT_TOOL_GRAB) && (sd->brush->flag & BRUSH_SIZE_PRESSURE)) - size *= sd->session->cache->pressure; - - return size; -} - /* Return modified brush strength. Includes the direction of the brush, positive values pull vertices, negative values push. Uses tablet pressure and a special multiplier found experimentally to scale the strength factor. */ static float brush_strength(Sculpt *sd, StrokeCache *cache) { + Brush *brush = paint_brush(&sd->paint); /* Primary strength input; square it to make lower values more sensitive */ - float alpha = sd->brush->alpha * sd->brush->alpha; + float alpha = brush->alpha * brush->alpha; - float dir= sd->brush->flag & BRUSH_DIR_IN ? -1 : 1; + float dir= brush->flag & BRUSH_DIR_IN ? -1 : 1; float pressure= 1; float flip= cache->flip ? -1:1; - if(sd->brush->flag & BRUSH_ALPHA_PRESSURE) + if(brush->flag & BRUSH_ALPHA_PRESSURE) pressure *= cache->pressure; - switch(sd->brush->sculpt_tool){ + switch(brush->sculpt_tool){ case SCULPT_TOOL_DRAW: case SCULPT_TOOL_INFLATE: case SCULPT_TOOL_CLAY: @@ -263,7 +237,7 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache) } /* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */ -static void sculpt_clip(Sculpt *sd, float *co, const float val[3]) +static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float val[3]) { int i; @@ -271,7 +245,7 @@ static void sculpt_clip(Sculpt *sd, float *co, const float val[3]) if(sd->flags & (SCULPT_LOCK_X << i)) continue; - if((sd->session->cache->flag & (CLIP_X << i)) && (fabs(co[i]) <= sd->session->cache->clip_tolerance[i])) + if((ss->cache->flag & (CLIP_X << i)) && (fabs(co[i]) <= ss->cache->clip_tolerance[i])) co[i]= 0.0f; else co[i]= val[i]; @@ -293,23 +267,24 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons /* Currently only for the draw brush; finds average normal for all active vertices */ -static void calc_area_normal(Sculpt *sd, float out[3], const ListBase* active_verts) +static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const ListBase* active_verts) { - StrokeCache *cache = sd->session->cache; + Brush *brush = paint_brush(&sd->paint); + StrokeCache *cache = ss->cache; ActiveData *node = active_verts->first; - const int view = 0; /* XXX: should probably be a flag, not number: sd->brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */ + const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */ float out_flip[3]; float *out_dir = cache->view_normal_symmetry; out[0]=out[1]=out[2] = out_flip[0]=out_flip[1]=out_flip[2] = 0; - if(sd->brush->flag & BRUSH_ANCHORED) { + if(brush->flag & BRUSH_ANCHORED) { for(; node; node = node->next) add_norm_if(out_dir, out, out_flip, cache->orig_norms[node->Index]); } else { for(; node; node = node->next) - add_norm_if(out_dir, out, out_flip, sd->session->mvert[node->Index].no); + add_norm_if(out_dir, out, out_flip, ss->mvert[node->Index].no); } if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) { @@ -332,7 +307,7 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_ float area_normal[3]; ActiveData *node= active_verts->first; - calc_area_normal(sd, area_normal, active_verts); + calc_area_normal(sd, ss, area_normal, active_verts); while(node){ float *co= ss->mvert[node->Index].co; @@ -341,7 +316,7 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_ co[1]+area_normal[1]*ss->cache->radius*node->Fade*ss->cache->scale[1], co[2]+area_normal[2]*ss->cache->radius*node->Fade*ss->cache->scale[2]}; - sculpt_clip(sd, co, val); + sculpt_clip(sd, ss, co, val); node= node->next; } @@ -391,37 +366,37 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert) VecCopyf(avg, ss->mvert[vert].co); } -static void do_smooth_brush(Sculpt *s, const ListBase* active_verts) +static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts) { ActiveData *node= active_verts->first; int i; for(i = 0; i < 2; ++i) { while(node){ - float *co= s->session->mvert[node->Index].co; + float *co= ss->mvert[node->Index].co; float avg[3], val[3]; - neighbor_average(s->session, avg, node->Index); + neighbor_average(ss, avg, node->Index); val[0] = co[0]+(avg[0]-co[0])*node->Fade; val[1] = co[1]+(avg[1]-co[1])*node->Fade; val[2] = co[2]+(avg[2]-co[2])*node->Fade; - sculpt_clip(s, co, val); + sculpt_clip(s, ss, co, val); node= node->next; } } } -static void do_pinch_brush(Sculpt *s, const ListBase* active_verts) +static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts) { ActiveData *node= active_verts->first; while(node) { - float *co= s->session->mvert[node->Index].co; - const float val[3]= {co[0]+(s->session->cache->location[0]-co[0])*node->Fade, - co[1]+(s->session->cache->location[1]-co[1])*node->Fade, - co[2]+(s->session->cache->location[2]-co[2])*node->Fade}; - sculpt_clip(s, co, val); + float *co= ss->mvert[node->Index].co; + const float val[3]= {co[0]+(ss->cache->location[0]-co[0])*node->Fade, + co[1]+(ss->cache->location[1]-co[1])*node->Fade, + co[2]+(ss->cache->location[2]-co[2])*node->Fade}; + sculpt_clip(s, ss, co, val); node= node->next; } } @@ -440,7 +415,7 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss) VecCopyf(add, grab_delta); VecMulf(add, node->Fade); VecAddf(add, add, co); - sculpt_clip(sd, co, add); + sculpt_clip(sd, ss, co, add); node= node->next; } @@ -456,10 +431,10 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active if(ss->cache->flip) lim = -lim; - calc_area_normal(sd, area_normal, active_verts); + calc_area_normal(sd, ss, area_normal, active_verts); while(node){ - float *disp= &ss->cache->layer_disps[node->Index]; + float *disp= &ss->layer_disps[node->Index]; float *co= ss->mvert[node->Index].co; float val[3]; @@ -469,20 +444,19 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim)) *disp = lim; - val[0] = ss->cache->mesh_store[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0]; - val[1] = ss->cache->mesh_store[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1]; - val[2] = ss->cache->mesh_store[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2]; + val[0] = ss->mesh_co_orig[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0]; + val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1]; + val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2]; - sculpt_clip(sd, co, val); + sculpt_clip(sd, ss, co, val); node= node->next; } } -static void do_inflate_brush(Sculpt *s, const ListBase *active_verts) +static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts) { ActiveData *node= active_verts->first; - SculptSession *ss = s->session; float add[3]; while(node) { @@ -498,7 +472,7 @@ static void do_inflate_brush(Sculpt *s, const ListBase *active_verts) add[2]*= ss->cache->scale[2]; VecAddf(add, add, co); - sculpt_clip(s, co, add); + sculpt_clip(s, ss, co, add); node= node->next; } @@ -527,46 +501,86 @@ static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3] VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE); } +/* Projects a point onto a plane along the plane's normal */ +static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3]) +{ + float p1[3], sub1[3], sub2[3]; + + /* Find the intersection between squash-plane and vertex (along the area normal) */ + VecSubf(p1, co, plane_normal); + VecSubf(sub1, plane_center, p1); + VecSubf(sub2, co, p1); + VecSubf(intr, co, p1); + VecMulf(intr, Inpf(plane_normal, sub1) / Inpf(plane_normal, sub2)); + VecAddf(intr, intr, p1); +} + +static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3], int flip) +{ + float delta[3]; + float d; + + VecSubf(delta, co, plane_center); + d = Inpf(plane_normal, delta); + + if(flip) + d = -d; + + return d <= 0.0f; +} + static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts, int clay) { ActiveData *node= active_verts->first; /* area_normal and cntr define the plane towards which vertices are squashed */ float area_normal[3]; - float cntr[3]; + float cntr[3], cntr2[3], bstr = 0; + int flip = 0; - calc_area_normal(sd, area_normal, active_verts); + calc_area_normal(sd, ss, area_normal, active_verts); calc_flatten_center(ss, node, cntr); + if(clay) { + bstr= brush_strength(sd, ss->cache); + /* Limit clay application to here */ + cntr2[0]=cntr[0]+area_normal[0]*bstr*ss->cache->scale[0]; + cntr2[1]=cntr[1]+area_normal[1]*bstr*ss->cache->scale[1]; + cntr2[2]=cntr[2]+area_normal[2]*bstr*ss->cache->scale[2]; + flip = bstr < 0; + } + while(node){ float *co= ss->mvert[node->Index].co; - float p1[3], sub1[3], sub2[3], intr[3], val[3]; - - /* Find the intersection between squash-plane and vertex (along the area normal) */ - VecSubf(p1, co, area_normal); - VecSubf(sub1, cntr, p1); - VecSubf(sub2, co, p1); - VecSubf(intr, co, p1); - VecMulf(intr, Inpf(area_normal, sub1) / Inpf(area_normal, sub2)); - VecAddf(intr, intr, p1); - - VecSubf(val, intr, co); - VecMulf(val, fabs(node->Fade)); - VecAddf(val, val, co); + float intr[3], val[3]; - if(clay) { - /* Clay brush displaces after flattening */ - float tmp[3]; - VecCopyf(tmp, area_normal); - VecMulf(tmp, ss->cache->radius * node->Fade * 0.1); - VecAddf(val, val, tmp); - } + if(!clay || plane_point_side(co, area_normal, cntr2, flip)) { + /* Find the intersection between squash-plane and vertex (along the area normal) */ + point_plane_project(intr, co, area_normal, cntr); + + VecSubf(val, intr, co); - sculpt_clip(sd, co, val); + if(clay) { + if(bstr > FLT_EPSILON) + VecMulf(val, node->Fade / bstr); + else + VecMulf(val, node->Fade); + /* Clay displacement */ + val[0]+=area_normal[0] * ss->cache->scale[0]*node->Fade; + val[1]+=area_normal[1] * ss->cache->scale[1]*node->Fade; + val[2]+=area_normal[2] * ss->cache->scale[2]*node->Fade; + } + else + VecMulf(val, fabs(node->Fade)); + + VecAddf(val, val, co); + + sculpt_clip(sd, ss, co, val); + } node= node->next; } } - + /* Uses symm to selectively flip any axis of a coordinate. */ static void flip_coord(float out[3], float in[3], const char symm) { @@ -622,35 +636,29 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float } /* Return a multiplier for brush strength on a particular vertex. */ -static float tex_strength(Sculpt *sd, float *point, const float len) +static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len) { - SculptSession *ss= sd->session; - Brush *br = sd->brush; + Brush *br = paint_brush(&sd->paint); + MTex *tex = NULL; float avg= 1; - if(br->texact==-1 || !br->mtex[br->texact]) + if(br->texact >= 0) + tex = br->mtex[br->texact]; + + if(!tex) { avg= 1; - else if(br->tex_mode==BRUSH_TEX_3D) { - /* Get strength by feeding the vertex location directly - into a texture */ + } + else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) { float jnk; - const float factor= 0.01; - MTex mtex; - memset(&mtex,0,sizeof(MTex)); - mtex.tex= br->mtex[br->texact]->tex; - mtex.projx= 1; - mtex.projy= 2; - mtex.projz= 3; - VecCopyf(mtex.size, br->mtex[br->texact]->size); - VecMulf(mtex.size, factor); - if(!sd->texsep) - mtex.size[1]= mtex.size[2]= mtex.size[0]; - - externtex(&mtex,point,&avg,&jnk,&jnk,&jnk,&jnk); + + /* Get strength by feeding the vertex + location directly into a texture */ + externtex(tex, point, &avg, + &jnk, &jnk, &jnk, &jnk); } else if(ss->texcache) { const float bsize= ss->cache->pixel_radius * 2; - const float rot= sd->brush->rot + ss->cache->rotation; + const float rot= tex->rot + ss->cache->rotation; int px, py; float flip[3], point_2d[2]; @@ -663,9 +671,9 @@ static float tex_strength(Sculpt *sd, float *point, const float len) /* For Tile and Drag modes, get the 2D screen coordinates of the and scale them up or down to the texture size. */ - if(br->tex_mode==BRUSH_TEX_TILE) { - const int sx= (const int)br->mtex[br->texact]->size[0]; - const int sy= (const int)sd->texsep ? br->mtex[br->texact]->size[1] : sx; + if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) { + const int sx= (const int)tex->size[0]; + const int sy= (const int)tex->size[1]; float fx= point_2d[0]; float fy= point_2d[1]; @@ -685,7 +693,8 @@ static float tex_strength(Sculpt *sd, float *point, const float len) if(sy != 1) py %= sy-1; avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy); - } else { + } + else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) { float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize; float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize; @@ -699,7 +708,7 @@ static float tex_strength(Sculpt *sd, float *point, const float len) } } - avg*= brush_curve_strength(sd->brush, len, ss->cache->radius); /* Falloff curve */ + avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */ return avg; } @@ -737,9 +746,9 @@ static void sculpt_add_damaged_rect(SculptSession *ss) } } -static void do_brush_action(Sculpt *sd, StrokeCache *cache) +static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache) { - SculptSession *ss = sd->session; + Brush *brush = paint_brush(&sd->paint); float av_dist; ListBase active_verts={0,0}; ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry]; @@ -748,7 +757,7 @@ static void do_brush_action(Sculpt *sd, StrokeCache *cache) Mesh *me= NULL; /*XXX: get_mesh(OBACT); */ const float bstrength= brush_strength(sd, cache); KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */ - Brush *b = sd->brush; + Brush *b = brush; int i; sculpt_add_damaged_rect(ss); @@ -768,7 +777,7 @@ static void do_brush_action(Sculpt *sd, StrokeCache *cache) adata->Index = i; /* Fade is used to store the final strength at which the brush should modify a particular vertex. */ - adata->Fade= tex_strength(sd, vert, av_dist) * bstrength; + adata->Fade= tex_strength(sd, ss, vert, av_dist) * bstrength; adata->dist = av_dist; if(b->sculpt_tool == SCULPT_TOOL_GRAB && cache->first_time) @@ -788,13 +797,13 @@ static void do_brush_action(Sculpt *sd, StrokeCache *cache) do_draw_brush(sd, ss, &active_verts); break; case SCULPT_TOOL_SMOOTH: - do_smooth_brush(sd, &active_verts); + do_smooth_brush(sd, ss, &active_verts); break; case SCULPT_TOOL_PINCH: - do_pinch_brush(sd, &active_verts); + do_pinch_brush(sd, ss, &active_verts); break; case SCULPT_TOOL_INFLATE: - do_inflate_brush(sd, &active_verts); + do_inflate_brush(sd, ss, &active_verts); break; case SCULPT_TOOL_GRAB: do_grab_brush(sd, ss); @@ -843,20 +852,21 @@ static void calc_brushdata_symm(StrokeCache *cache, const char symm) cache->symmetry= symm; } -static void do_symmetrical_brush_actions(Sculpt *sd, StrokeCache *cache) +static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss) { + StrokeCache *cache = ss->cache; const char symm = sd->flags & 7; int i; VecCopyf(cache->location, cache->true_location); VecCopyf(cache->grab_delta_symmetry, cache->grab_delta); cache->symmetry = 0; - do_brush_action(sd, cache); + do_brush_action(sd, ss, cache); for(i = 1; i <= symm; ++i) { if(symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) { calc_brushdata_symm(cache, i); - do_brush_action(sd, cache); + do_brush_action(sd, ss, cache); } } @@ -929,9 +939,9 @@ static void projverts_clear_inside(SculptSession *ss) } #endif -static void sculpt_update_tex(Sculpt *sd) +static void sculpt_update_tex(Sculpt *sd, SculptSession *ss) { - SculptSession *ss= sd->session; + Brush *brush = paint_brush(&sd->paint); if(ss->texcache) { MEM_freeN(ss->texcache); @@ -939,9 +949,9 @@ static void sculpt_update_tex(Sculpt *sd) } /* Need to allocate a bigger buffer for bigger brush size */ - ss->texcache_side = sd->brush->size * 2; + ss->texcache_side = brush->size * 2; if(!ss->texcache || ss->texcache_side > ss->texcache_actual) { - ss->texcache = brush_gen_texture_cache(sd->brush, sd->brush->size); + ss->texcache = brush_gen_texture_cache(brush, brush->size); ss->texcache_actual = ss->texcache_side; } } @@ -992,8 +1002,8 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob) static void sculpt_update_mesh_elements(bContext *C) { - SculptSession *ss = CTX_data_tool_settings(C)->sculpt->session; Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; int oldtotvert = ss->totvert; if((ss->multires = sculpt_multires_active(ob))) { @@ -1026,54 +1036,20 @@ static void sculpt_update_mesh_elements(bContext *C) static int sculpt_mode_poll(bContext *C) { - return G.f & G_SCULPTMODE; + Object *ob = CTX_data_active_object(C); + return ob && ob->mode & OB_MODE_SCULPT; } static int sculpt_poll(bContext *C) { - return G.f & G_SCULPTMODE && CTX_wm_area(C)->spacetype == SPACE_VIEW3D && - CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW; -} - -/*** Sculpt Cursor ***/ -static void draw_paint_cursor(bContext *C, int x, int y, void *customdata) -{ - Sculpt *sd= CTX_data_tool_settings(C)->sculpt; - - glColor4ub(255, 100, 100, 128); - glEnable( GL_LINE_SMOOTH ); - glEnable(GL_BLEND); - - glTranslatef((float)x, (float)y, 0.0f); - glutil_draw_lined_arc(0.0, M_PI*2.0, sd->brush->size, 40); - glTranslatef((float)-x, (float)-y, 0.0f); - - if(sd->session && sd->session->cache && sd->brush && (sd->brush->flag & BRUSH_SMOOTH_STROKE)) { - ARegion *ar = CTX_wm_region(C); - sdrawline(x, y, sd->session->cache->mouse[0] - ar->winrct.xmin, sd->session->cache->mouse[1] - ar->winrct.ymin); - } - - glDisable(GL_BLEND); - glDisable( GL_LINE_SMOOTH ); -} - -static void toggle_paint_cursor(bContext *C) -{ - Sculpt *s = CTX_data_scene(C)->toolsettings->sculpt; - - if(s->session->cursor) { - WM_paint_cursor_end(CTX_wm_manager(C), s->session->cursor); - s->session->cursor = NULL; - } - else { - s->session->cursor = - WM_paint_cursor_activate(CTX_wm_manager(C), sculpt_poll, draw_paint_cursor, NULL); - } + return sculpt_mode_poll(C) && paint_poll(C); } static void sculpt_undo_push(bContext *C, Sculpt *sd) { - switch(sd->brush->sculpt_tool) { + Brush *brush = paint_brush(&sd->paint); + + switch(brush->sculpt_tool) { case SCULPT_TOOL_DRAW: ED_undo_push(C, "Draw Brush"); break; case SCULPT_TOOL_SMOOTH: @@ -1093,36 +1069,15 @@ static void sculpt_undo_push(bContext *C, Sculpt *sd) } } -static int sculpt_brush_curve_preset_exec(bContext *C, wmOperator *op) -{ - brush_curve_preset(CTX_data_scene(C)->toolsettings->sculpt->brush, RNA_enum_get(op->ptr, "mode")); - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_brush_curve_preset(wmOperatorType *ot) -{ - static EnumPropertyItem prop_mode_items[] = { - {BRUSH_PRESET_SHARP, "SHARP", 0, "Sharp Curve", ""}, - {BRUSH_PRESET_SMOOTH, "SMOOTH", 0, "Smooth Curve", ""}, - {BRUSH_PRESET_MAX, "MAX", 0, "Max Curve", ""}, - {0, NULL, 0, NULL, NULL}}; - - ot->name= "Preset"; - ot->idname= "SCULPT_OT_brush_curve_preset"; - - ot->exec= sculpt_brush_curve_preset_exec; - ot->poll= sculpt_mode_poll; - - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "mode", prop_mode_items, BRUSH_PRESET_SHARP, "Mode", ""); -} - /**** Radial control ****/ static int sculpt_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) { - toggle_paint_cursor(C); - brush_radial_control_invoke(op, CTX_data_scene(C)->toolsettings->sculpt->brush, 1); + Paint *p = paint_get_active(CTX_data_scene(C)); + Brush *brush = paint_brush(p); + + WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor); + p->paint_cursor = NULL; + brush_radial_control_invoke(op, brush, 1); return WM_radial_control_invoke(C, op, event); } @@ -1130,13 +1085,15 @@ static int sculpt_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve { int ret = WM_radial_control_modal(C, op, event); if(ret != OPERATOR_RUNNING_MODAL) - toggle_paint_cursor(C); + paint_cursor_start(C, sculpt_poll); return ret; } static int sculpt_radial_control_exec(bContext *C, wmOperator *op) { - return brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->sculpt->brush, 1); + Brush *brush = paint_brush(&CTX_data_tool_settings(C)->sculpt->paint); + + return brush_radial_control_exec(op, brush, 1); } static void SCULPT_OT_radial_control(wmOperatorType *ot) @@ -1162,7 +1119,7 @@ static float unproject_brush_radius(SculptSession *ss, float offset) float brush_edge[3]; /* In anchored mode, brush size changes with mouse loc, otherwise it's fixed using the brush radius */ - unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset, + view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset, ss->cache->initial_mouse[1], ss->cache->depth); return VecLenf(ss->cache->true_location, brush_edge); @@ -1170,31 +1127,32 @@ static float unproject_brush_radius(SculptSession *ss, float offset) static void sculpt_cache_free(StrokeCache *cache) { - if(cache->layer_disps) - MEM_freeN(cache->layer_disps); - if(cache->mesh_store) - MEM_freeN(cache->mesh_store); + int i; if(cache->orig_norms) MEM_freeN(cache->orig_norms); if(cache->face_norms) MEM_freeN(cache->face_norms); if(cache->mats) MEM_freeN(cache->mats); + for(i = 0; i < 8; ++i) + BLI_freelistN(&cache->grab_active_verts[i]); MEM_freeN(cache); } /* Initialize the stroke cache invariants from operator properties */ -static void sculpt_update_cache_invariants(Sculpt *sd, bContext *C, wmOperator *op) +static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bContext *C, wmOperator *op) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); + Brush *brush = paint_brush(&sd->paint); + ViewContext *vc = paint_stroke_view_context(op->customdata); int i; - sd->session->cache = cache; + ss->cache = cache; RNA_float_get_array(op->ptr, "scale", cache->scale); cache->flag = RNA_int_get(op->ptr, "flag"); RNA_float_get_array(op->ptr, "clip_tolerance", cache->clip_tolerance); - RNA_int_get_array(op->ptr, "initial_mouse", cache->initial_mouse); + RNA_float_get_array(op->ptr, "initial_mouse", cache->initial_mouse); cache->depth = RNA_float_get(op->ptr, "depth"); cache->mouse[0] = cache->initial_mouse[0]; @@ -1202,70 +1160,88 @@ static void sculpt_update_cache_invariants(Sculpt *sd, bContext *C, wmOperator * /* Truly temporary data that isn't stored in properties */ - view3d_set_viewcontext(C, &cache->vc); - cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats"); - view3d_get_transformation(&cache->vc, cache->vc.obact, cache->mats); + view3d_get_transformation(vc, vc->obact, cache->mats); sculpt_update_mesh_elements(C); - if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER) - cache->layer_disps = MEM_callocN(sizeof(float) * sd->session->totvert, "layer brush displacements"); + /* Initialize layer brush displacements */ + if(brush->sculpt_tool == SCULPT_TOOL_LAYER && + (!ss->layer_disps || !(brush->flag & BRUSH_PERSISTENT))) { + if(ss->layer_disps) + MEM_freeN(ss->layer_disps); + ss->layer_disps = MEM_callocN(sizeof(float) * ss->totvert, "layer brush displacements"); + } /* Make copies of the mesh vertex locations and normals for some tools */ - if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER || (sd->brush->flag & BRUSH_ANCHORED)) { - cache->mesh_store= MEM_mallocN(sizeof(float) * 3 * sd->session->totvert, "sculpt mesh vertices copy"); - for(i = 0; i < sd->session->totvert; ++i) - VecCopyf(cache->mesh_store[i], sd->session->mvert[i].co); - - if(sd->brush->flag & BRUSH_ANCHORED) { - cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * sd->session->totvert, "Sculpt orig norm"); - for(i = 0; i < sd->session->totvert; ++i) { - cache->orig_norms[i][0] = sd->session->mvert[i].no[0]; - cache->orig_norms[i][1] = sd->session->mvert[i].no[1]; - cache->orig_norms[i][2] = sd->session->mvert[i].no[2]; + if(brush->sculpt_tool == SCULPT_TOOL_LAYER || (brush->flag & BRUSH_ANCHORED)) { + if(brush->sculpt_tool != SCULPT_TOOL_LAYER || + !ss->mesh_co_orig || !(brush->flag & BRUSH_PERSISTENT)) { + if(!ss->mesh_co_orig) + ss->mesh_co_orig= MEM_mallocN(sizeof(float) * 3 * ss->totvert, + "sculpt mesh vertices copy"); + for(i = 0; i < ss->totvert; ++i) + VecCopyf(ss->mesh_co_orig[i], ss->mvert[i].co); + } + + if(brush->flag & BRUSH_ANCHORED) { + cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * ss->totvert, "Sculpt orig norm"); + for(i = 0; i < ss->totvert; ++i) { + cache->orig_norms[i][0] = ss->mvert[i].no[0]; + cache->orig_norms[i][1] = ss->mvert[i].no[1]; + cache->orig_norms[i][2] = ss->mvert[i].no[2]; } - if(sd->session->face_normals) { - float *fn = sd->session->face_normals; - cache->face_norms= MEM_mallocN(sizeof(float) * 3 * sd->session->totface, "Sculpt face norms"); - for(i = 0; i < sd->session->totface; ++i, fn += 3) + if(ss->face_normals) { + float *fn = ss->face_normals; + cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms"); + for(i = 0; i < ss->totface; ++i, fn += 3) VecCopyf(cache->face_norms[i], fn); } } } - unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth); - cache->radius = unproject_brush_radius(sd->session, brush_size(sd)); + view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth); + cache->initial_radius = unproject_brush_radius(ss, brush->size); cache->rotation = 0; cache->first_time = 1; } /* Initialize the stroke cache variants from operator properties */ -static void sculpt_update_cache_variants(Sculpt *sd, PointerRNA *ptr) +static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerRNA *ptr) { - StrokeCache *cache = sd->session->cache; + StrokeCache *cache = ss->cache; + Brush *brush = paint_brush(&sd->paint); float grab_location[3]; + int dx, dy; - if(!(sd->brush->flag & BRUSH_ANCHORED)) + if(!(brush->flag & BRUSH_ANCHORED)) RNA_float_get_array(ptr, "location", cache->true_location); cache->flip = RNA_boolean_get(ptr, "flip"); - RNA_int_get_array(ptr, "mouse", cache->mouse); + RNA_float_get_array(ptr, "mouse", cache->mouse); + cache->pressure = RNA_float_get(ptr, "pressure"); /* Truly temporary data that isn't stored in properties */ cache->previous_pixel_radius = cache->pixel_radius; - cache->pixel_radius = brush_size(sd); + cache->pixel_radius = brush->size; + + if(brush->flag & BRUSH_SIZE_PRESSURE) { + cache->pixel_radius *= cache->pressure; + cache->radius = cache->initial_radius * cache->pressure; + } + else + cache->radius = cache->initial_radius; - if(sd->brush->flag & BRUSH_ANCHORED) { + if(brush->flag & BRUSH_ANCHORED) { dx = cache->mouse[0] - cache->initial_mouse[0]; dy = cache->mouse[1] - cache->initial_mouse[1]; cache->pixel_radius = sqrt(dx*dx + dy*dy); - cache->radius = unproject_brush_radius(sd->session, cache->pixel_radius); + cache->radius = unproject_brush_radius(ss, cache->pixel_radius); cache->rotation = atan2(dy, dx); } - else if(sd->brush->flag & BRUSH_RAKE) { + else if(brush->flag & BRUSH_RAKE) { int update; dx = cache->last_rake[0] - cache->mouse[0]; @@ -1284,8 +1260,8 @@ static void sculpt_update_cache_variants(Sculpt *sd, PointerRNA *ptr) } /* Find the grab delta */ - if(sd->brush->sculpt_tool == SCULPT_TOOL_GRAB) { - unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth); + if(brush->sculpt_tool == SCULPT_TOOL_GRAB) { + view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth); if(!cache->first_time) VecSubf(cache->grab_delta, grab_location, cache->old_grab_location); VecCopyf(cache->old_grab_location, grab_location); @@ -1298,9 +1274,9 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Object *ob= CTX_data_active_object(C); ModifierData *md; - ViewContext vc; float scale[3], clip_tolerance[3] = {0,0,0}; - int mouse[2], flag = 0; + float mouse[2]; + int flag = 0; /* Set scaling adjustment */ scale[0] = 1.0f / ob->size[0]; @@ -1327,42 +1303,39 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE /* Initial mouse location */ mouse[0] = event->x; mouse[1] = event->y; - RNA_int_set_array(op->ptr, "initial_mouse", mouse); + RNA_float_set_array(op->ptr, "initial_mouse", mouse); /* Initial screen depth under the mouse */ - view3d_set_viewcontext(C, &vc); - RNA_float_set(op->ptr, "depth", read_cached_depth(&vc, event->x, event->y)); + RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y)); - sculpt_update_cache_invariants(sd, C, op); + sculpt_update_cache_invariants(sd, ss, C, op); } -static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) +static void sculpt_brush_stroke_init(bContext *C) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = CTX_data_active_object(C)->sculpt; view3d_operator_needs_opengl(C); /* TODO: Shouldn't really have to do this at the start of every stroke, but sculpt would need some sort of notification when changes are made to the texture. */ - sculpt_update_tex(sd); + sculpt_update_tex(sd, ss); - /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); - - return OPERATOR_RUNNING_MODAL; + sculpt_update_mesh_elements(C); } -static void sculpt_restore_mesh(Sculpt *sd) +static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) { - SculptSession *ss = sd->session; StrokeCache *cache = ss->cache; + Brush *brush = paint_brush(&sd->paint); int i; /* Restore the mesh before continuing with anchored stroke */ - if((sd->brush->flag & BRUSH_ANCHORED) && cache->mesh_store) { + if((brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) { for(i = 0; i < ss->totvert; ++i) { - VecCopyf(ss->mvert[i].co, cache->mesh_store[i]); + VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]); ss->mvert[i].no[0] = cache->orig_norms[i][0]; ss->mvert[i].no[1] = cache->orig_norms[i][1]; ss->mvert[i].no[2] = cache->orig_norms[i][2]; @@ -1374,8 +1347,8 @@ static void sculpt_restore_mesh(Sculpt *sd) VecCopyf(fn, cache->face_norms[i]); } - if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER) - memset(cache->layer_disps, 0, sizeof(float) * ss->totvert); + if(brush->sculpt_tool == SCULPT_TOOL_LAYER) + memset(ss->layer_disps, 0, sizeof(float) * ss->totvert); } } @@ -1387,187 +1360,107 @@ static void sculpt_post_stroke_free(SculptSession *ss) static void sculpt_flush_update(bContext *C) { - Sculpt *s = CTX_data_tool_settings(C)->sculpt; + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; ARegion *ar = CTX_wm_region(C); - MultiresModifierData *mmd = s->session->multires; + MultiresModifierData *mmd = ss->multires; - calc_damaged_verts(s->session); + calc_damaged_verts(ss); if(mmd) { - if(mmd->undo_verts && mmd->undo_verts != s->session->mvert) + if(mmd->undo_verts && mmd->undo_verts != ss->mvert) MEM_freeN(mmd->undo_verts); - mmd->undo_verts = s->session->mvert; - mmd->undo_verts_tot = s->session->totvert; - multires_mark_as_modified(CTX_data_active_object(C)); + mmd->undo_verts = ss->mvert; + mmd->undo_verts_tot = ss->totvert; + multires_mark_as_modified(ob); } ED_region_tag_redraw(ar); } -/* Returns zero if no sculpt changes should be made, non-zero otherwise */ -static int sculpt_smooth_stroke(Sculpt *s, int output[2], wmEvent *event) +static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event) { - output[0] = event->x; - output[1] = event->y; - - if(s->brush->flag & BRUSH_SMOOTH_STROKE && s->brush->sculpt_tool != SCULPT_TOOL_GRAB) { - StrokeCache *cache = s->session->cache; - float u = .9, v = 1.0 - u; - int dx = cache->mouse[0] - event->x, dy = cache->mouse[1] - event->y; - int radius = 50; - - /* If the mouse is moving within the radius of the last move, - don't update the mouse position. This allows sharp turns. */ - if(dx*dx + dy*dy < radius*radius) - return 0; - - output[0] = event->x * v + cache->mouse[0] * u; - output[1] = event->y * v + cache->mouse[1] * u; - } + ViewContext vc; + float cur_depth; - return 1; -} + view3d_set_viewcontext(C, &vc); + cur_depth = read_cached_depth(&vc, event->x, event->y); + + /* Don't start the stroke until a valid depth is found */ + if(cur_depth < 1.0 - FLT_EPSILON) { + SculptSession *ss = CTX_data_active_object(C)->sculpt; -/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ -int sculpt_space_stroke_enabled(Sculpt *s) -{ - Brush *br = s->brush; - return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB); + sculpt_brush_stroke_init_properties(C, op, event, ss); + sculptmode_update_all_projverts(ss); + + return 1; + } + else + return 0; } -/* Put the location of the next sculpt stroke dot into the stroke RNA and apply it to the mesh */ -static void sculpt_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, int mouse[2]) +static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - StrokeCache *cache = sd->session->cache; - PointerRNA itemptr; - float cur_depth; - float center[3]; - - cur_depth = read_cached_depth(&cache->vc, mouse[0], mouse[1]); - unproject(sd->session->cache->mats, center, mouse[0], mouse[1], cur_depth); - - /* Add to stroke */ - RNA_collection_add(op->ptr, "stroke", &itemptr); - RNA_float_set_array(&itemptr, "location", center); - RNA_int_set_array(&itemptr, "mouse", mouse); - RNA_boolean_set(&itemptr, "flip", event->shift); - sculpt_update_cache_variants(sd, &itemptr); - - sculpt_restore_mesh(sd); - do_symmetrical_brush_actions(sd, cache); -} + SculptSession *ss = CTX_data_active_object(C)->sculpt; -/* For brushes with stroke spacing enabled, moves mouse in steps - towards the final mouse location. */ -static int sculpt_space_stroke(bContext *C, wmOperator *op, wmEvent *event, Sculpt *s, const int final_mouse[2]) -{ - StrokeCache *cache = s->session->cache; - int cnt = 0; - - if(sculpt_space_stroke_enabled(s)) { - float vec[2] = {final_mouse[0] - cache->mouse[0], final_mouse[1] - cache->mouse[1]}; - int mouse[2] = {cache->mouse[0], cache->mouse[1]}; - float length, scale; - int steps = 0, i; - - /* Normalize the vector between the last stroke dot and the goal */ - length = sqrt(vec[0]*vec[0] + vec[1]*vec[1]); - - if(length > FLT_EPSILON) { - scale = s->brush->spacing / length; - vec[0] *= scale; - vec[1] *= scale; - - steps = (int)(length / s->brush->spacing); - for(i = 0; i < steps; ++i, ++cnt) { - mouse[0] += vec[0]; - mouse[1] += vec[1]; - sculpt_brush_stroke_add_step(C, op, event, mouse); - } - } - } + sculpt_update_cache_variants(sd, ss, itemptr); + sculpt_restore_mesh(sd, ss); + do_symmetrical_brush_actions(sd, ss); - return cnt; + /* Cleanup */ + sculpt_flush_update(C); + sculpt_post_stroke_free(ss); } -static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) +static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke) { - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - ARegion *ar = CTX_wm_region(C); - float cur_depth; - - sculpt_update_mesh_elements(C); + SculptSession *ss = CTX_data_active_object(C)->sculpt; - if(!sd->session->cache) { - ViewContext vc; - view3d_set_viewcontext(C, &vc); - cur_depth = read_cached_depth(&vc, event->x, event->y); - - /* Don't start the stroke until a valid depth is found */ - if(cur_depth < 1.0 - FLT_EPSILON) { - sculpt_brush_stroke_init_properties(C, op, event, sd->session); - sculptmode_update_all_projverts(sd->session); - } + /* Finished */ + if(ss->cache) { + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - ED_region_tag_redraw(ar); + request_depth_update(paint_stroke_view_context(stroke)->rv3d); + sculpt_cache_free(ss->cache); + ss->cache = NULL; + sculpt_undo_push(C, sd); } +} - if(sd->session->cache) { - int mouse[2]; - - if(sculpt_smooth_stroke(sd, mouse, event)) { - if(sculpt_space_stroke_enabled(sd)) { - if(!sculpt_space_stroke(C, op, event, sd, mouse)) - ED_region_tag_redraw(ar); - } - else - sculpt_brush_stroke_add_step(C, op, event, mouse); - - sculpt_flush_update(C); - sculpt_post_stroke_free(sd->session); - } - else - ED_region_tag_redraw(ar); - } +static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sculpt_brush_stroke_init(C); - /* Finished */ - if(event->type == LEFTMOUSE && event->val == 0) { - if(sd->session->cache) { - request_depth_update(sd->session->cache->vc.rv3d); - sculpt_cache_free(sd->session->cache); - sd->session->cache = NULL; - sculpt_undo_push(C, sd); - } + op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, + sculpt_stroke_update_step, + sculpt_stroke_done); - return OPERATOR_FINISHED; - } + /* add modal handler */ + WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + op->type->modal(C, op, event); + return OPERATOR_RUNNING_MODAL; } static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = CTX_data_active_object(C)->sculpt; - view3d_operator_needs_opengl(C); - sculpt_update_cache_invariants(sd, C, op); - sculptmode_update_all_projverts(sd->session); - sculpt_update_tex(sd); + op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done); - RNA_BEGIN(op->ptr, itemptr, "stroke") { - sculpt_update_cache_variants(sd, &itemptr); + sculpt_brush_stroke_init(C); - sculpt_restore_mesh(sd); - do_symmetrical_brush_actions(sd, sd->session->cache); + sculpt_update_cache_invariants(sd, ss, C, op); + sculptmode_update_all_projverts(ss); - sculpt_post_stroke_free(sd->session); - } - RNA_END; + paint_stroke_exec(C, op); sculpt_flush_update(C); - sculpt_cache_free(sd->session->cache); + sculpt_cache_free(ss->cache); sculpt_undo_push(C, sd); @@ -1584,7 +1477,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) /* api callbacks */ ot->invoke= sculpt_brush_stroke_invoke; - ot->modal= sculpt_brush_stroke_modal; + ot->modal= paint_stroke_modal; ot->exec= sculpt_brush_stroke_exec; ot->poll= sculpt_poll; @@ -1604,46 +1497,76 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "clip_tolerance", 3, NULL, 0.0f, FLT_MAX, "clip_tolerance", "", 0.0f, 1000.0f); /* The initial 2D location of the mouse */ - RNA_def_int_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX); + RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX); /* The initial screen depth of the mouse */ RNA_def_float(ot->srna, "depth", 0.0f, 0.0f, FLT_MAX, "depth", "", 0.0f, FLT_MAX); } +/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/ + +static int sculpt_set_persistent_base(bContext *C, wmOperator *op) +{ + SculptSession *ss = CTX_data_active_object(C)->sculpt; + + if(ss) { + if(ss->layer_disps) + MEM_freeN(ss->layer_disps); + ss->layer_disps = NULL; + + if(ss->mesh_co_orig) + MEM_freeN(ss->mesh_co_orig); + ss->mesh_co_orig = NULL; + } + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Set Persistent Base"; + ot->idname= "SCULPT_OT_set_persistent_base"; + + /* api callbacks */ + ot->exec= sculpt_set_persistent_base; + ot->poll= sculpt_mode_poll; + + ot->flag= OPTYPE_REGISTER; +} + /**** Toggle operator for turning sculpt mode on or off ****/ static int sculpt_toggle_mode(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); + Object *ob = CTX_data_active_object(C); - if(G.f & G_SCULPTMODE) { - multires_force_update(CTX_data_active_object(C)); + if(ob->mode & OB_MODE_SCULPT) { + multires_force_update(ob); /* Leave sculptmode */ - G.f &= ~G_SCULPTMODE; - - toggle_paint_cursor(C); + ob->mode &= ~OB_MODE_SCULPT; - sculptsession_free(ts->sculpt); + free_sculptsession(&ob->sculpt); } else { /* Enter sculptmode */ - G.f |= G_SCULPTMODE; + ob->mode |= OB_MODE_SCULPT; /* Create persistent sculpt mode data */ if(!ts->sculpt) ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data"); /* Create sculpt mode session data */ - if(ts->sculpt->session) - MEM_freeN(ts->sculpt->session); - ts->sculpt->session = MEM_callocN(sizeof(SculptSession), "sculpt session"); + if(ob->sculpt) + free_sculptsession(&ob->sculpt); + ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - toggle_paint_cursor(C); - - /* If there's no brush, create one */ - brush_check_exists(&ts->sculpt->brush); + paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); + + paint_cursor_start(C, sculpt_poll); WM_event_add_notifier(C, NC_SCENE|ND_MODE, CTX_data_scene(C)); } @@ -1669,5 +1592,5 @@ void ED_operatortypes_sculpt() WM_operatortype_append(SCULPT_OT_radial_control); WM_operatortype_append(SCULPT_OT_brush_stroke); WM_operatortype_append(SCULPT_OT_sculptmode_toggle); - WM_operatortype_append(SCULPT_OT_brush_curve_preset); + WM_operatortype_append(SCULPT_OT_set_persistent_base); } diff --git a/source/blender/editors/sculpt_paint/sculpt_stroke.c b/source/blender/editors/sculpt_paint/sculpt_stroke.c deleted file mode 100644 index 554ff580358..00000000000 --- a/source/blender/editors/sculpt_paint/sculpt_stroke.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2007 by Nicholas Bishop - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * - * Storage and manipulation of sculptmode brush strokes. - * - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_listBase.h" -#include "DNA_scene_types.h" - -#include "BKE_sculpt.h" -#include "BLI_blenlib.h" -#include "BIF_gl.h" - -#include "sculpt_intern.h" - -#include <math.h> - -/* Temporary storage of input stroke control points */ -typedef struct StrokePoint { - struct StrokePoint *next, *prev; - short x, y; -} StrokePoint; -typedef struct SculptStroke { - short (*loc)[2]; - int max; - int index; - float length; - ListBase final; - StrokePoint *final_mem; - float offset; -} SculptStroke; - -SculptStroke *sculpt_stroke_new(const int max) -{ - SculptStroke *stroke = MEM_callocN(sizeof(SculptStroke), "SculptStroke"); - stroke->loc = MEM_callocN(sizeof(short) * 4 * max, "SculptStroke.loc"); - stroke->max = max; - stroke->index = -1; - return stroke; -} - -void sculpt_stroke_free(SculptStroke *stroke) -{ - if(stroke) { - if(stroke->loc) MEM_freeN(stroke->loc); - if(stroke->final_mem) MEM_freeN(stroke->final_mem); - - MEM_freeN(stroke); - } -} - -void sculpt_stroke_add_point(SculptStroke *stroke, const short x, const short y) -{ - const int next = stroke->index + 1; - - if(stroke->index == -1) { - stroke->loc[0][0] = x; - stroke->loc[0][1] = y; - stroke->index = 0; - } - else if(next < stroke->max) { - const int dx = x - stroke->loc[stroke->index][0]; - const int dy = y - stroke->loc[stroke->index][1]; - stroke->loc[next][0] = x; - stroke->loc[next][1] = y; - stroke->length += sqrt(dx*dx + dy*dy); - stroke->index = next; - } -} - -static void sculpt_stroke_smooth(SculptStroke *stroke) -{ - /* Apply smoothing (exclude the first and last points)*/ - StrokePoint *p = stroke->final.first; - if(p && p->next && p->next->next) { - for(p = p->next->next; p && p->next && p->next->next; p = p->next) { - p->x = p->prev->prev->x*0.1 + p->prev->x*0.2 + p->x*0.4 + p->next->x*0.2 + p->next->next->x*0.1; - p->y = p->prev->prev->y*0.1 + p->prev->y*0.2 + p->y*0.4 + p->next->y*0.2 + p->next->next->y*0.1; - } - } -} - -static void sculpt_stroke_create_final(SculptStroke *stroke) -{ - if(stroke) { - StrokePoint *p, *pnext; - int i; - - /* Copy loc into final */ - if(stroke->final_mem) - MEM_freeN(stroke->final_mem); - stroke->final_mem = MEM_callocN(sizeof(StrokePoint) * (stroke->index + 1) * 2, "SculptStroke.final"); - stroke->final.first = stroke->final.last = NULL; - for(i = 0; i <= stroke->index; ++i) { - p = &stroke->final_mem[i]; - p->x = stroke->loc[i][0]; - p->y = stroke->loc[i][1]; - BLI_addtail(&stroke->final, p); - } - - /* Remove shortest edges */ - if(stroke->final.first) { - for(p = ((StrokePoint*)stroke->final.first)->next; p && p->next; p = pnext) { - const int dx = p->x - p->prev->x; - const int dy = p->y - p->prev->y; - const float len = sqrt(dx*dx + dy*dy); - pnext = p->next; - if(len < 10) { - BLI_remlink(&stroke->final, p); - } - } - } - - sculpt_stroke_smooth(stroke); - - /* Subdivide edges */ - for(p = stroke->final.first; p && p->next; p = pnext) { - StrokePoint *np = &stroke->final_mem[i++]; - - pnext = p->next; - np->x = (p->x + p->next->x) / 2; - np->y = (p->y + p->next->y) / 2; - BLI_insertlink(&stroke->final, p, np); - } - - sculpt_stroke_smooth(stroke); - } -} - -static float sculpt_stroke_seglen(StrokePoint *p1, StrokePoint *p2) -{ - int dx = p2->x - p1->x; - int dy = p2->y - p1->y; - return sqrt(dx*dx + dy*dy); -} - -static float sculpt_stroke_final_length(SculptStroke *stroke) -{ - StrokePoint *p; - float len = 0; - for(p = stroke->final.first; p && p->next; ++p) - len += sculpt_stroke_seglen(p, p->next); - return len; -} - -/* If partial is nonzero, cuts off apply after that length has been processed */ -static StrokePoint *sculpt_stroke_apply_generic(Sculpt *sd, SculptStroke *stroke, const int partial) -{ - const int sdspace = 0; //XXX: sd->spacing; - const short spacing = sdspace > 0 ? sdspace : 2; - const int dots = sculpt_stroke_final_length(stroke) / spacing; - int i; - StrokePoint *p = stroke->final.first; - float startloc = stroke->offset; - - for(i = 0; i < dots && p && p->next; ++i) { - const float dotloc = spacing * i; - short co[2]; - float len = sculpt_stroke_seglen(p, p->next); - float u, v; - - /* Find edge containing dot */ - while(dotloc > startloc + len && p && p->next && p->next->next) { - p = p->next; - startloc += len; - len = sculpt_stroke_seglen(p, p->next); - } - - if(!p || !p->next || dotloc > startloc + len) - break; - - if(partial && startloc > partial) { - /* Calculate offset for next stroke segment */ - stroke->offset = startloc + len - dotloc; - break; - } - - u = (dotloc - startloc) / len; - v = 1 - u; - - co[0] = p->x*v + p->next->x*u; - co[1] = p->y*v + p->next->y*u; - - //do_symmetrical_brush_actions(sd, a, co, NULL); - } - - return p ? p->next : NULL; -} - -void sculpt_stroke_apply(Sculpt *sd, SculptStroke *stroke) -{ - /* TODO: make these values user-modifiable? */ - const int partial_len = 100; - const int min_len = 200; - - if(stroke) { - sculpt_stroke_create_final(stroke); - - if(sculpt_stroke_final_length(stroke) > min_len) { - StrokePoint *p = sculpt_stroke_apply_generic(sd, stroke, partial_len); - - /* Replace remaining values in stroke->loc with remaining stroke->final values */ - stroke->index = -1; - stroke->length = 0; - for(; p; p = p->next) { - ++stroke->index; - stroke->loc[stroke->index][0] = p->x; - stroke->loc[stroke->index][1] = p->y; - if(p->next) { - stroke->length += sculpt_stroke_seglen(p, p->next); - } - } - } - } -} - -void sculpt_stroke_apply_all(Sculpt *sd, SculptStroke *stroke) -{ - sculpt_stroke_create_final(stroke); - - if(stroke) { - sculpt_stroke_apply_generic(sd, stroke, 0); - } -} - -/* XXX: drawing goes elsewhere */ -void sculpt_stroke_draw(SculptStroke *stroke) -{ - if(stroke) { - StrokePoint *p; - - /* Draws the original stroke */ - /*glColor3f(1, 0, 0); - glBegin(GL_LINE_STRIP); - for(i = 0; i <= stroke->index; ++i) - glVertex2s(stroke->loc[i][0], stroke->loc[i][1]); - glEnd();*/ - - /* Draws the smoothed stroke */ - glColor3f(0, 1, 0); - glBegin(GL_LINE_STRIP); - for(p = stroke->final.first; p; p = p->next) - glVertex2s(p->x, p->y); - glEnd(); - } -} |