diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image.c | 13 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_intern.h | 23 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_ops.c | 27 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_stroke.c | 330 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex.c | 867 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 282 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_stroke.c | 274 |
8 files changed, 984 insertions, 833 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 870b66cdbbd..465aa281e25 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -3707,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, dist; + float rgba[4], alpha, dist_nosqrt; float brush_size_sqared; float falloff; @@ -3721,7 +3721,6 @@ 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; @@ -3756,8 +3755,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 && (dist=sqrtf(dist_nosqrt)) < size_half) { - falloff = brush_curve_strength(ps->brush, dist, size_half); + if (dist_nosqrt < brush_size_sqared) { + falloff = brush_sample_falloff_noalpha(ps->brush, sqrtf(dist_nosqrt)); if (falloff > 0.0f) { if (ps->is_texbrush) { brush_sample_tex(ps->brush, projPixel->projCoSS, rgba); @@ -4720,7 +4719,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= IMB_BLEND_ERASE_ALPHA; + pop->s.blend= BRUSH_BLEND_ERASE_ALPHA; } else pressure= 1.0f; @@ -5175,7 +5174,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface); - paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT); + paint_init(&scene->toolsettings->imapaint.paint, "Brush"); if(U.glreslimit != 0) GPU_free_images(); @@ -5184,7 +5183,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 1); } - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index ba1b57a1bef..40423e17fe4 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -29,37 +29,14 @@ #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); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index c38b36007e9..63a6591d057 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -77,30 +77,10 @@ void BRUSH_OT_add(wmOperatorType *ot) 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) +/* Paint operators */ +static int paint_poll(bContext *C) { - 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."); + return !!paint_get_active(CTX_data_scene(C)); } /**************************** registration **********************************/ @@ -129,6 +109,5 @@ 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 deleted file mode 100644 index bd9ea50e0f8..00000000000 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * ***** 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_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 25ff57ca87f..1a548708ec8 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -43,7 +43,7 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" - +#include "MTC_matrixops.h" #include "DNA_action_types.h" #include "DNA_armature_types.h" @@ -62,7 +62,6 @@ #include "DNA_userdef_types.h" #include "RNA_access.h" -#include "RNA_define.h" #include "BKE_armature.h" #include "BKE_brush.h" @@ -92,8 +91,6 @@ #include "ED_util.h" #include "ED_view3d.h" -#include "paint_intern.h" - /* vp->mode */ #define VP_MIX 0 #define VP_ADD 1 @@ -110,18 +107,11 @@ 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) +static int vp_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(vertex_paint_mode_poll(C) && + if(ob && ob->mode & OB_MODE_VERTEX_PAINT && paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) { ScrArea *sa= CTX_wm_area(C); if(sa->spacetype==SPACE_VIEW3D) { @@ -149,6 +139,56 @@ static int wp_poll(bContext *C) return 0; } + +/* Cursors */ +static void vp_drawcursor(bContext *C, int x, int y, void *customdata) +{ + Brush *brush = paint_brush(&CTX_data_tool_settings(C)->vpaint->paint); + + 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, 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) +{ + Brush *brush = paint_brush(&CTX_data_tool_settings(C)->wpaint->paint); + + 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, 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"); @@ -295,7 +335,7 @@ void make_vertexcol(Scene *scene, int shade) /* single ob */ else memset(me->mcol, 255, 4*sizeof(MCol)*me->totface); - DAG_id_flush_update(&me->id, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } @@ -330,7 +370,34 @@ static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount) } -void clear_vpaint(Scene *scene, int selected) +void clear_vpaint(Scene *scene) +{ + Mesh *me; + Object *ob; + unsigned int *to, paintcol; + int a; + + ob= OBACT; + me= get_mesh(ob); + if(!ob || ob->id.lib) return; + + if(!(ob->mode & OB_MODE_VERTEX_PAINT)) 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) { Mesh *me; MFace *mf; @@ -350,7 +417,7 @@ void clear_vpaint(Scene *scene, int selected) mf = me->mface; mcol = (unsigned int*)me->mcol; for (i = 0; i < me->totface; i++, mf++, mcol+=4) { - if (!selected || mf->flag & ME_FACE_SEL) { + if (mf->flag & ME_FACE_SEL) { mcol[0] = paintcol; mcol[1] = paintcol; mcol[2] = paintcol; @@ -358,7 +425,7 @@ void clear_vpaint(Scene *scene, int selected) } } - DAG_id_flush_update(&me->id, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } @@ -408,8 +475,8 @@ void clear_wpaint_selectedfaces(Scene *scene) if (!strcmp(curdef->name, name)) break; if(curdef==NULL) { - int olddef= ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ - curdef= ED_vgroup_add_name (ob, name); + int olddef= ob->actdef; /* tsk, add_defgroup sets the active defgroup */ + curdef= add_defgroup_name (ob, name); ob->actdef= olddef; } @@ -431,9 +498,9 @@ void clear_wpaint_selectedfaces(Scene *scene) faceverts[3]= mface->v4; for (i=0; i<3 || faceverts[i]; i++) { if(!((me->dvert+faceverts[i])->flag)) { - dw= ED_vgroup_weight_verify(me->dvert+faceverts[i], vgroup); + dw= verify_defweight(me->dvert+faceverts[i], vgroup); if(dw) { - uw= ED_vgroup_weight_verify(wp->wpaint_prev+faceverts[i], vgroup); + uw= verify_defweight(wp->wpaint_prev+faceverts[i], vgroup); uw->weight= dw->weight; /* set the undo weight */ dw->weight= paintweight; @@ -442,11 +509,11 @@ void clear_wpaint_selectedfaces(Scene *scene) if(j>=0) { /* copy, not paint again */ if(vgroup_mirror != -1) { - dw= ED_vgroup_weight_verify(me->dvert+j, vgroup_mirror); - uw= ED_vgroup_weight_verify(wp->wpaint_prev+j, vgroup_mirror); + dw= verify_defweight(me->dvert+j, vgroup_mirror); + uw= verify_defweight(wp->wpaint_prev+j, vgroup_mirror); } else { - dw= ED_vgroup_weight_verify(me->dvert+j, vgroup); - uw= ED_vgroup_weight_verify(wp->wpaint_prev+j, vgroup); + dw= verify_defweight(me->dvert+j, vgroup); + uw= verify_defweight(wp->wpaint_prev+j, vgroup); } uw->weight= dw->weight; /* set the undo weight */ dw->weight= paintweight; @@ -468,7 +535,7 @@ void clear_wpaint_selectedfaces(Scene *scene) MEM_freeN(indexar); copy_wpaint_prev(wp, NULL, 0); - DAG_id_flush_update(&me->id, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } @@ -740,7 +807,7 @@ 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, float *mval) +static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, short *mval) { Brush *brush = paint_brush(&vp->paint); float fac, dx, dy; @@ -923,7 +990,7 @@ void sample_wpaint(Scene *scene, ARegion *ar, View3D *v3d, int mode) val= 0; // XXX pupmenu(str); if(val>=0) { ob->actdef= val+1; - DAG_id_flush_update(&me->id, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } MEM_freeN(str); } @@ -963,20 +1030,20 @@ void sample_wpaint(Scene *scene, ARegion *ar, View3D *v3d, int mode) fac= MIN4(w1, w2, w3, w4); if(w1==fac) { - dw= ED_vgroup_weight_get(me->dvert+mface->v1, ob->actdef-1); + dw= get_defweight(me->dvert+mface->v1, ob->actdef-1); if(dw) ts->vgroup_weight= dw->weight; else ts->vgroup_weight= 0.0f; } else if(w2==fac) { - dw= ED_vgroup_weight_get(me->dvert+mface->v2, ob->actdef-1); + dw= get_defweight(me->dvert+mface->v2, ob->actdef-1); if(dw) ts->vgroup_weight= dw->weight; else ts->vgroup_weight= 0.0f; } else if(w3==fac) { - dw= ED_vgroup_weight_get(me->dvert+mface->v3, ob->actdef-1); + dw= get_defweight(me->dvert+mface->v3, ob->actdef-1); if(dw) ts->vgroup_weight= dw->weight; else ts->vgroup_weight= 0.0f; } else if(w4==fac) { if(mface->v4) { - dw= ED_vgroup_weight_get(me->dvert+mface->v4, ob->actdef-1); + dw= get_defweight(me->dvert+mface->v4, ob->actdef-1); if(dw) ts->vgroup_weight= dw->weight; else ts->vgroup_weight= 0.0f; } } @@ -995,12 +1062,12 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index, int alpha, int vgroup= ob->actdef-1; if(wp->flag & VP_ONLYVGROUP) { - dw= ED_vgroup_weight_get(me->dvert+index, vgroup); - uw= ED_vgroup_weight_get(wp->wpaint_prev+index, vgroup); + dw= get_defweight(me->dvert+index, vgroup); + uw= get_defweight(wp->wpaint_prev+index, vgroup); } else { - dw= ED_vgroup_weight_verify(me->dvert+index, vgroup); - uw= ED_vgroup_weight_verify(wp->wpaint_prev+index, vgroup); + dw= verify_defweight(me->dvert+index, vgroup); + uw= verify_defweight(wp->wpaint_prev+index, vgroup); } if(dw==NULL || uw==NULL) return; @@ -1012,9 +1079,9 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index, int alpha, if(j>=0) { /* copy, not paint again */ if(vgroup_mirror != -1) - uw= ED_vgroup_weight_verify(me->dvert+j, vgroup_mirror); + uw= verify_defweight(me->dvert+j, vgroup_mirror); else - uw= ED_vgroup_weight_verify(me->dvert+j, vgroup); + uw= verify_defweight(me->dvert+j, vgroup); uw->weight= dw->weight; } @@ -1049,7 +1116,7 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */ * exit (exit needs doing regardless because we * should redeform). */ - DAG_id_flush_update(&me->id, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); if(ob->mode & OB_MODE_WEIGHT_PAINT) { Object *par; @@ -1057,8 +1124,9 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */ if(wp==NULL) wp= scene->toolsettings->wpaint= new_vpaint(1); - paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); - paint_cursor_start(C, wp_poll); + paint_init(&wp->paint, "Brush"); + + toggle_paint_cursor(C, 1); mesh_octree_table(ob, NULL, NULL, 's'); @@ -1070,10 +1138,13 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */ if(pchan->bone->flag & BONE_ACTIVE) break; if(pchan) - ED_vgroup_select_by_name(ob, pchan->name); + vertexgroup_select_by_name(ob, pchan->name); } } else { + if(wp) + toggle_paint_cursor(C, 1); + mesh_octree_table(ob, NULL, NULL, 'e'); } @@ -1114,11 +1185,9 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot) static int vpaint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) { - 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 *brush = paint_brush(&CTX_data_scene(C)->toolsettings->vpaint->paint); + + toggle_paint_cursor(C, 0); brush_radial_control_invoke(op, brush, 1); return WM_radial_control_invoke(C, op, event); } @@ -1127,7 +1196,7 @@ 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) - paint_cursor_start(C, vp_poll); + toggle_paint_cursor(C, 0); return ret; } @@ -1139,11 +1208,8 @@ static int vpaint_radial_control_exec(bContext *C, wmOperator *op) static int wpaint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) { - 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 *brush = paint_brush(&CTX_data_scene(C)->toolsettings->wpaint->paint); + toggle_paint_cursor(C, 1); brush_radial_control_invoke(op, brush, 1); return WM_radial_control_invoke(C, op, event); } @@ -1152,7 +1218,7 @@ 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) - paint_cursor_start(C, wp_poll); + toggle_paint_cursor(C, 1); return ret; } @@ -1204,10 +1270,207 @@ struct WPaintData { float wpimat[3][3]; }; -static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *event) +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; + Brush *brush = paint_brush(&wp->paint); + + 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], 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) { 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); @@ -1216,17 +1479,17 @@ static int wpaint_stroke_test_start(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; /* if nothing was added yet, we make dverts and a vertex deform group */ if (!me->dvert) - ED_vgroup_data_create(&me->id); + create_dverts(&me->id); - /* make mode data storage */ - wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData"); - paint_stroke_set_mode_data(stroke, wpd); + /* make customdata storage */ + op->customdata= wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData"); view3d_set_viewcontext(C, &wpd->vc); wpd->vgroup_mirror= -1; @@ -1256,14 +1519,14 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *event) if(pchan) { bDeformGroup *dg= get_named_vertexgroup(ob, pchan->name); if(dg==NULL) - dg= ED_vgroup_add_name(ob, pchan->name); /* sets actdef */ + dg= add_defgroup_name(ob, pchan->name); /* sets actdef */ else ob->actdef= get_defgroup_num(ob, dg); } } } if(ob->defbase.first==NULL) { - ED_vgroup_add(ob); + add_defgroup(ob); } // if(ob->lay & v3d->lay); else error("Active object is not in this layer"); @@ -1288,8 +1551,8 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *event) if (!strcmp(curdef->name, name)) break; if(curdef==NULL) { - int olddef= ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ - curdef= ED_vgroup_add_name (ob, name); + int olddef= ob->actdef; /* tsk, add_defgroup sets the active defgroup */ + curdef= add_defgroup_name (ob, name); ob->actdef= olddef; } @@ -1298,203 +1561,11 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *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; - - 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) = ED_vgroup_weight_verify; - - if(wp->flag & VP_ONLYVGROUP) - dw_func= ED_vgroup_weight_get; - - 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; - } - } - } - } - - Mat4SwapMat4(vc->rv3d->persmat, mat); - - DAG_id_flush_update(ob->data, 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_id_flush_update(ob->data, 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); + /* do paint once for click only paint */ + wpaint_modal(C, op, event); /* 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; } @@ -1508,14 +1579,13 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) /* api callbacks */ ot->invoke= wpaint_invoke; - ot->modal= paint_stroke_modal; + ot->modal= wpaint_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 ********** */ @@ -1547,6 +1617,11 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ if(ob->mode & OB_MODE_VERTEX_PAINT) { ob->mode &= ~OB_MODE_VERTEX_PAINT; + + if(vp) { + toggle_paint_cursor(C, 0); + vp->paintcursor= NULL; + } } else { ob->mode |= OB_MODE_VERTEX_PAINT; @@ -1557,14 +1632,14 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ if(vp==NULL) vp= scene->toolsettings->vpaint= new_vpaint(0); - paint_cursor_start(C, vp_poll); + toggle_paint_cursor(C, 0); - paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT); + paint_init(&vp->paint, "Brush"); } if (me) /* update modifier stack for mapping requirements */ - DAG_id_flush_update(&me->id, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); @@ -1610,24 +1685,158 @@ For future: */ -typedef struct VPaintData { +struct VPaintData { ViewContext vc; unsigned int paintcol; int *indexar; float *vertexcosnos; float vpimat[3][3]; -} VPaintData; +}; + +static void vpaint_exit(bContext *C, wmOperator *op) +{ + ToolSettings *ts= CTX_data_tool_settings(C); + struct VPaintData *vpd= op->customdata; + + if(vpd->vertexcosnos) + MEM_freeN(vpd->vertexcosnos); + MEM_freeN(vpd->indexar); + + /* frees prev buffer */ + copy_vpaint_prev(ts->vpaint, NULL, 0); + + MEM_freeN(vpd); + op->customdata= NULL; +} + +static int vpaint_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + ToolSettings *ts= CTX_data_tool_settings(C); + VPaint *vp= ts->vpaint; + Brush *brush = paint_brush(&vp->paint); + + 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]; + + view3d_operator_needs_opengl(C); + + /* load projection matrix */ + wmMultMatrix(ob->obmat); + wmGetSingleMatrix(mat); + wmLoadMatrix(vc->rv3d->viewmat); + + 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], 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); + + 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((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; + } + } + } + + 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(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->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); + + 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); + + do_shared_vertexcol(me); + + ED_region_tag_redraw(vc->ar); + + DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA); + } + break; + } + + return OPERATOR_RUNNING_MODAL; +} -static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event) +static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) { ToolSettings *ts= CTX_data_tool_settings(C); - 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; @@ -1635,9 +1844,8 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent if(me->mcol==NULL) make_vertexcol(CTX_data_scene(C), 0); if(me->mcol==NULL) return OPERATOR_CANCELLED; - /* make mode data storage */ - vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData"); - paint_stroke_set_mode_data(stroke, vpd); + /* 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); @@ -1651,119 +1859,12 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent Mat4MulMat4(mat, ob->obmat, vpd->vc.rv3d->viewmat); Mat4Invert(imat, mat); Mat3CpyMat4(vpd->vpimat, imat); - - return 1; -} - -static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, float mval[2]) -{ - ViewContext *vc = &vpd->vc; - Mesh *me = get_mesh(ob); - MFace *mface= ((MFace*)me->mface) + index; - unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index; - unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index; - int alpha, i; - - if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) || - (G.f & G_FACESELECT && !(mface->flag & ME_FACE_SEL))) - return; - - 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); - } - - } - - for(i = 0; i < (mface->v4 ? 4 : 3); ++i) { - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], mval); - if(alpha) - vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, alpha); - } -} - -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; - 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); - - /* load projection matrix */ - wmMultMatrix(ob->obmat); - wmGetSingleMatrix(mat); - wmLoadMatrix(vc->rv3d->viewmat); - - mval[0]-= vc->ar->winrct.xmin; - mval[1]-= 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], brush->size); - } - else { - indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); - if(indexar[0]) totindex= 1; - else totindex= 0; - } - - Mat4SwapMat4(vc->rv3d->persmat, mat); - - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) - vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval); - } - - Mat4SwapMat4(vc->rv3d->persmat, mat); - - ED_region_tag_redraw(vc->ar); - - DAG_id_flush_update(ob->data, OB_RECALC_DATA); -} - -static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) -{ - ToolSettings *ts= CTX_data_tool_settings(C); - struct VPaintData *vpd= paint_stroke_mode_data(stroke); - if(vpd->vertexcosnos) - MEM_freeN(vpd->vertexcosnos); - MEM_freeN(vpd->indexar); - - /* frees prev buffer */ - copy_vpaint_prev(ts->vpaint, NULL, 0); - - MEM_freeN(vpd); -} - -static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - - op->customdata = paint_stroke_new(C, vpaint_stroke_test_start, - vpaint_stroke_update_step, - vpaint_stroke_done); + /* do paint once for click only paint */ + vpaint_modal(C, op, event); /* 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; } @@ -1776,13 +1877,11 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) /* api callbacks */ ot->invoke= vpaint_invoke; - ot->modal= paint_stroke_modal; + ot->modal= vpaint_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 b08e8ab5c2b..f7f72d611dc 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -65,6 +65,7 @@ #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_paint.h" +#include "BKE_sculpt.h" #include "BKE_texture.h" #include "BKE_utildefines.h" #include "BKE_colortools.h" @@ -79,7 +80,6 @@ #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" @@ -144,6 +144,7 @@ typedef struct StrokeCache { int first_time; /* Beginning of stroke may do some things special */ + ViewContext vc; bglMats *mats; short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */ @@ -177,6 +178,19 @@ 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]) { @@ -533,7 +547,7 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase ActiveData *node= active_verts->first; /* area_normal and cntr define the plane towards which vertices are squashed */ float area_normal[3]; - float cntr[3], cntr2[3], bstr = 0; + float cntr[3], cntr2[3], bstr; int flip = 0; calc_area_normal(sd, ss, area_normal, active_verts); @@ -1041,7 +1055,47 @@ static int sculpt_mode_poll(bContext *C) static int sculpt_poll(bContext *C) { - return sculpt_mode_poll(C) && paint_poll(C); + return sculpt_mode_poll(C) && paint_brush(&CTX_data_tool_settings(C)->sculpt->paint) && + 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; + SculptSession *ss= CTX_data_active_object(C)->sculpt; + Brush *brush = paint_brush(&sd->paint); + + 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, brush->size, 40); + glTranslatef((float)-x, (float)-y, 0.0f); + + if(ss && ss->cache && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) { + ARegion *ar = CTX_wm_region(C); + sdrawline(x, y, (int)ss->cache->mouse[0] - ar->winrct.xmin, (int)ss->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->cursor) { + WM_paint_cursor_end(CTX_wm_manager(C), s->cursor); + s->cursor = NULL; + } + else { + s->cursor = + WM_paint_cursor_activate(CTX_wm_manager(C), sculpt_poll, draw_paint_cursor, NULL); + } } static void sculpt_undo_push(bContext *C, Sculpt *sd) @@ -1071,11 +1125,8 @@ static void sculpt_undo_push(bContext *C, Sculpt *sd) /**** Radial control ****/ static int sculpt_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) { - 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 *brush = paint_brush(&CTX_data_tool_settings(C)->sculpt->paint); + toggle_paint_cursor(C); brush_radial_control_invoke(op, brush, 1); return WM_radial_control_invoke(C, op, event); } @@ -1084,7 +1135,7 @@ 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) - paint_cursor_start(C, sculpt_poll); + toggle_paint_cursor(C); return ret; } @@ -1118,7 +1169,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 */ - view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset, + 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); @@ -1143,7 +1194,6 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); Brush *brush = paint_brush(&sd->paint); - ViewContext *vc = paint_stroke_view_context(op->customdata); int i; ss->cache = cache; @@ -1159,8 +1209,10 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte /* 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(vc, vc->obact, cache->mats); + view3d_get_transformation(&cache->vc, cache->vc.obact, cache->mats); sculpt_update_mesh_elements(C); @@ -1200,7 +1252,7 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte } } - view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth); + 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; @@ -1260,7 +1312,7 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR /* Find the grab delta */ if(brush->sculpt_tool == SCULPT_TOOL_GRAB) { - view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth); + 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); @@ -1273,6 +1325,7 @@ 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}; float mouse[2]; int flag = 0; @@ -1305,12 +1358,13 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE RNA_float_set_array(op->ptr, "initial_mouse", mouse); /* Initial screen depth under the mouse */ - RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y)); + view3d_set_viewcontext(C, &vc); + RNA_float_set(op->ptr, "depth", read_cached_depth(&vc, event->x, event->y)); sculpt_update_cache_invariants(sd, ss, C, op); } -static void sculpt_brush_stroke_init(bContext *C) +static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; @@ -1322,7 +1376,10 @@ static void sculpt_brush_stroke_init(bContext *C) changes are made to the texture. */ sculpt_update_tex(sd, ss); - sculpt_update_mesh_elements(C); + /* add modal handler */ + WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + + return OPERATOR_RUNNING_MODAL; } static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) @@ -1378,69 +1435,157 @@ static void sculpt_flush_update(bContext *C) ED_region_tag_redraw(ar); } -static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event) +/* Returns zero if no sculpt changes should be made, non-zero otherwise */ +static int sculpt_smooth_stroke(Sculpt *s, SculptSession *ss, float output[2], wmEvent *event) { - ViewContext vc; - float cur_depth; + Brush *brush = paint_brush(&s->paint); - 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; + output[0] = event->x; + output[1] = event->y; - sculpt_brush_stroke_init_properties(C, op, event, ss); - sculptmode_update_all_projverts(ss); + if(brush->flag & BRUSH_SMOOTH_STROKE && brush->sculpt_tool != SCULPT_TOOL_GRAB) { + StrokeCache *cache = ss->cache; + float u = brush->smooth_stroke_factor, v = 1.0 - u; + float dx = cache->mouse[0] - event->x, dy = cache->mouse[1] - event->y; - return 1; + /* 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 < brush->smooth_stroke_radius * brush->smooth_stroke_radius) + return 0; + + output[0] = event->x * v + cache->mouse[0] * u; + output[1] = event->y * v + cache->mouse[1] * u; } - else - return 0; + + return 1; } -static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) +/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ +int sculpt_space_stroke_enabled(Sculpt *s) +{ + Brush *br = paint_brush(&s->paint); + return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB); +} + +/* 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, float mouse[2]) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; - - sculpt_update_cache_variants(sd, ss, itemptr); + StrokeCache *cache = ss->cache; + PointerRNA itemptr; + float cur_depth, pressure = 1; + float center[3]; + + cur_depth = read_cached_depth(&cache->vc, mouse[0], mouse[1]); + unproject(ss->cache->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); + sculpt_update_cache_variants(sd, ss, &itemptr); + sculpt_restore_mesh(sd, ss); do_symmetrical_brush_actions(sd, ss); +} - /* Cleanup */ - sculpt_flush_update(C); - sculpt_post_stroke_free(ss); +/* 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, SculptSession *ss, const float final_mouse[2]) +{ + StrokeCache *cache = ss->cache; + Brush *brush = paint_brush(&s->paint); + int cnt = 0; + + if(sculpt_space_stroke_enabled(s)) { + float vec[2] = {final_mouse[0] - cache->mouse[0], final_mouse[1] - cache->mouse[1]}; + float 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 = brush->spacing / length; + vec[0] *= scale; + vec[1] *= scale; + + steps = (int)(length / 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); + } + } + } + + return cnt; } -static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke) +static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) { + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; + ARegion *ar = CTX_wm_region(C); + float cur_depth; - /* Finished */ - if(ss->cache) { - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + sculpt_update_mesh_elements(C); + + if(!ss->cache) { + ViewContext vc; + view3d_set_viewcontext(C, &vc); + cur_depth = read_cached_depth(&vc, event->x, event->y); - request_depth_update(paint_stroke_view_context(stroke)->rv3d); - sculpt_cache_free(ss->cache); - ss->cache = NULL; - sculpt_undo_push(C, sd); + /* 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, ss); + sculptmode_update_all_projverts(ss); + } + + ED_region_tag_redraw(ar); } -} -static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - sculpt_brush_stroke_init(C); + if(ss->cache) { + float mouse[2]; - op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, - sculpt_stroke_update_step, - sculpt_stroke_done); + if(sculpt_smooth_stroke(sd, ss, mouse, event)) { + if(sculpt_space_stroke_enabled(sd)) { + if(!sculpt_space_stroke(C, op, event, sd, ss, mouse)) + ED_region_tag_redraw(ar); + } + else + sculpt_brush_stroke_add_step(C, op, event, mouse); - /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + sculpt_flush_update(C); + sculpt_post_stroke_free(ss); + } + else + ED_region_tag_redraw(ar); + } + + /* Finished */ + if(event->type == LEFTMOUSE && event->val == 0) { + if(ss->cache) { + request_depth_update(ss->cache->vc.rv3d); + sculpt_cache_free(ss->cache); + ss->cache = NULL; + sculpt_undo_push(C, sd); + } + + return OPERATOR_FINISHED; + } - op->type->modal(C, op, event); - return OPERATOR_RUNNING_MODAL; } @@ -1449,14 +1594,20 @@ 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; - op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done); - - sculpt_brush_stroke_init(C); - + view3d_operator_needs_opengl(C); sculpt_update_cache_invariants(sd, ss, C, op); sculptmode_update_all_projverts(ss); + sculpt_update_tex(sd, ss); - paint_stroke_exec(C, op); + RNA_BEGIN(op->ptr, itemptr, "stroke") { + sculpt_update_cache_variants(sd, ss, &itemptr); + + sculpt_restore_mesh(sd, ss); + do_symmetrical_brush_actions(sd, ss); + + sculpt_post_stroke_free(ss); + } + RNA_END; sculpt_flush_update(C); sculpt_cache_free(ss->cache); @@ -1476,7 +1627,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) /* api callbacks */ ot->invoke= sculpt_brush_stroke_invoke; - ot->modal= paint_stroke_modal; + ot->modal= sculpt_brush_stroke_modal; ot->exec= sculpt_brush_stroke_exec; ot->poll= sculpt_poll; @@ -1563,9 +1714,10 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op) free_sculptsession(&ob->sculpt); ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); - - paint_cursor_start(C, sculpt_poll); + if(!ts->sculpt->cursor) + toggle_paint_cursor(C); + + paint_init(&ts->sculpt->paint, "Brush"); WM_event_add_notifier(C, NC_SCENE|ND_MODE, CTX_data_scene(C)); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 25f97b862e6..febca301939 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -32,6 +32,7 @@ #include "DNA_listBase.h" #include "DNA_vec_types.h" +#include "BKE_sculpt.h" struct Brush; struct Mesh; diff --git a/source/blender/editors/sculpt_paint/sculpt_stroke.c b/source/blender/editors/sculpt_paint/sculpt_stroke.c new file mode 100644 index 00000000000..554ff580358 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_stroke.c @@ -0,0 +1,274 @@ +/* + * $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(); + } +} |