diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_stroke.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_stroke.c | 681 |
1 files changed, 271 insertions, 410 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 6d58731d79c..3a67775cb98 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -28,6 +28,9 @@ #include "MEM_guardedalloc.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" @@ -41,9 +44,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "BLI_math.h" - - #include "BIF_gl.h" #include "BIF_glutil.h" @@ -51,8 +51,9 @@ #include "ED_view3d.h" #include "paint_intern.h" -#include "sculpt_intern.h" // XXX, for expedience in getting this working, refactor later (or this just shows that this needs unification) - +/* still needed for sculpt_stroke_get_location, should be + removed eventually (TODO) */ +#include "sculpt_intern.h" #include <float.h> #include <math.h> @@ -100,109 +101,6 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata glDisable(GL_LINE_SMOOTH); } -#if 0 - -// grid texture for testing - -#define GRID_WIDTH 8 -#define GRID_LENGTH 8 - -#define W (0xFFFFFFFF) -#define G (0x00888888) -#define E (0xE1E1E1E1) -#define C (0xC3C3C3C3) -#define O (0xB4B4B4B4) -#define Q (0xA9A9A9A9) - -static unsigned grid_texture0[256] = -{ - W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W, - W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W, -}; - -static unsigned grid_texture1[64] = -{ - C,C,C,C,C,C,C,C, - C,G,G,G,G,G,G,C, - C,G,G,G,G,G,G,C, - C,G,G,G,G,G,G,C, - C,G,G,G,G,G,G,C, - C,G,G,G,G,G,G,C, - C,G,G,G,G,G,G,C, - C,C,C,C,C,C,C,C, -}; - -static unsigned grid_texture2[16] = -{ - O,O,O,O, - O,G,G,O, - O,G,G,O, - O,O,O,O, -}; - -static unsigned grid_texture3[4] = -{ - Q,Q, - Q,Q, -}; - -static unsigned grid_texture4[1] = -{ - Q, -}; - -#undef W -#undef G -#undef E -#undef C -#undef O -#undef Q - -static void load_grid() -{ - static GLuint overlay_texture; - - if (!overlay_texture) { - //GLfloat largest_supported_anisotropy; - - glGenTextures(1, &overlay_texture); - glBindTexture(GL_TEXTURE_2D, overlay_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture0); - glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture1); - glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture2); - glTexImage2D(GL_TEXTURE_2D, 3, GL_RGB, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture3); - glTexImage2D(GL_TEXTURE_2D, 4, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture4); - glEnable(GL_TEXTURE_2D); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); - - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - - //glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy); - //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy); - } -} - -#endif - -extern float get_tex_pixel(Brush* br, float u, float v); - typedef struct Snapshot { float size[3]; float ofs[3]; @@ -253,7 +151,7 @@ static void make_snap(Snapshot* snap, Brush* brush, ViewContext* vc) snap->winy = vc->ar->winy; } -int load_tex(Sculpt *sd, Brush* br, ViewContext* vc) +static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc) { static GLuint overlay_texture = 0; static int init = 0; @@ -268,8 +166,12 @@ int load_tex(Sculpt *sd, Brush* br, ViewContext* vc) int j; int refresh; +#ifndef _OPENMP + (void)sd; /* quied unused warning */ +#endif + if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED && !br->mtex.tex) return 0; - + refresh = !overlay_texture || (br->mtex.tex && @@ -369,7 +271,7 @@ int load_tex(Sculpt *sd, Brush* br, ViewContext* vc) x += br->mtex.ofs[0]; y += br->mtex.ofs[1]; - avg = br->mtex.tex ? get_tex_pixel(br, x, y) : 1; + avg = br->mtex.tex ? paint_get_tex_pixel(br, x, y) : 1; avg += br->texture_sample_bias; @@ -420,18 +322,6 @@ int load_tex(Sculpt *sd, Brush* br, ViewContext* vc) return 1; } -/* Convert a point in model coordinates to 2D screen coordinates. */ -// XXX duplicated from sculpt.c, deal with this later. -static void projectf(bglMats *mats, const float v[3], float p[2]) -{ - double ux, uy, uz; - - gluProject(v[0],v[1],v[2], mats->modelview, mats->projection, - (GLint *)mats->viewport, &ux, &uy, &uz); - p[0]= ux; - p[1]= uy; -} - static int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats) { float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2]; @@ -472,7 +362,8 @@ static int project_brush_radius(RegionView3D* rv3d, float radius, float location return len_v2v2(p1, p2); } -int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, float location[3], float modelview[16], float projection[16], int viewport[4]) +static int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, + float location[3]) { struct PaintStroke *stroke; float window[2]; @@ -483,12 +374,11 @@ int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, floa window[0] = x + stroke->vc.ar->winrct.xmin; window[1] = y + stroke->vc.ar->winrct.ymin; - memcpy(modelview, stroke->vc.rv3d->viewmat, sizeof(float[16])); - memcpy(projection, stroke->vc.rv3d->winmat, sizeof(float[16])); - memcpy(viewport, stroke->mats.viewport, sizeof(int[4])); - - if (stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && sculpt_stroke_get_location(C, stroke, location, window)) { - *pixel_radius = project_brush_radius(stroke->vc.rv3d, brush_unprojected_radius(stroke->brush), location, &stroke->mats); + if(stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && + sculpt_stroke_get_location(C, stroke, location, window)) { + *pixel_radius = project_brush_radius(stroke->vc.rv3d, + brush_unprojected_radius(stroke->brush), + location, &stroke->mats); if (*pixel_radius == 0) *pixel_radius = brush_size(stroke->brush); @@ -510,58 +400,174 @@ int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, floa return hit; } -// XXX duplicated from sculpt.c -float unproject_brush_radius(Object *ob, ViewContext *vc, float center[3], float offset) +/* Draw an overlay that shows what effect the brush's texture will + have on brush strength */ +/* TODO: sculpt only for now */ +static void paint_draw_alpha_overlay(Sculpt *sd, Brush *brush, + ViewContext *vc, int x, int y) { - float delta[3], scale, loc[3]; + rctf quad; + + /* check for overlay mode */ + if(!(brush->flag & BRUSH_TEXTURE_OVERLAY) || + !(ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED))) + return; + + /* save lots of GL state + TODO: check on whether all of these are needed? */ + glPushAttrib(GL_COLOR_BUFFER_BIT| + GL_CURRENT_BIT| + GL_DEPTH_BUFFER_BIT| + GL_ENABLE_BIT| + GL_LINE_BIT| + GL_POLYGON_BIT| + GL_STENCIL_BUFFER_BIT| + GL_TRANSFORM_BIT| + GL_VIEWPORT_BIT| + GL_TEXTURE_BIT); + + if(load_tex(sd, brush, vc)) { + glEnable(GL_BLEND); - mul_v3_m4v3(loc, ob->obmat, center); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthMask(GL_FALSE); + glDepthFunc(GL_ALWAYS); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + + if(brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) { + /* brush rotation */ + glTranslatef(0.5f, 0.5f, 0); + glRotatef(((brush->flag & BRUSH_RAKE) ? + sd->last_angle : sd->special_rotation) * (180.0f/M_PI), + 0, 0, 1); + glTranslatef(-0.5f, -0.5f, 0); + + /* scale based on tablet pressure */ + if(sd->draw_pressure && brush_use_size_pressure(brush)) { + glTranslatef(0.5f, 0.5f, 0); + glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1); + glTranslatef(-0.5f, -0.5f, 0); + } - initgrabz(vc->rv3d, loc[0], loc[1], loc[2]); - window_to_3d_delta(vc->ar, delta, offset, 0); + if(sd->draw_anchored) { + const float *aim = sd->anchored_initial_mouse; + const rcti *win = &vc->ar->winrct; + quad.xmin = aim[0]-sd->anchored_size - win->xmin; + quad.ymin = aim[1]-sd->anchored_size - win->ymin; + quad.xmax = aim[0]+sd->anchored_size - win->xmin; + quad.ymax = aim[1]+sd->anchored_size - win->ymin; + } + else { + const int radius= brush_size(brush); + quad.xmin = x - radius; + quad.ymin = y - radius; + quad.xmax = x + radius; + quad.ymax = y + radius; + } + } + else { + quad.xmin = 0; + quad.ymin = 0; + quad.xmax = vc->ar->winrct.xmax - vc->ar->winrct.xmin; + quad.ymax = vc->ar->winrct.ymax - vc->ar->winrct.ymin; + } - scale= fabsf(mat4_to_scale(ob->obmat)); - scale= (scale == 0.0f)? 1.0f: scale; + /* set quad color */ + glColor4f(U.sculpt_paint_overlay_col[0], + U.sculpt_paint_overlay_col[1], + U.sculpt_paint_overlay_col[2], + brush->texture_overlay_alpha / 100.0f); + + /* draw textured quad */ + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(quad.xmin, quad.ymin); + glTexCoord2f(1, 0); + glVertex2f(quad.xmax, quad.ymin); + glTexCoord2f(1, 1); + glVertex2f(quad.xmax, quad.ymax); + glTexCoord2f(0, 1); + glVertex2f(quad.xmin, quad.ymax); + glEnd(); + + glPopMatrix(); + } - return len_v3(delta)/scale; + glPopAttrib(); } -// XXX paint cursor now does a lot of the same work that is needed during a sculpt stroke -// problem: all this stuff was not intended to be used at this point, so things feel a -// bit hacked. I've put lots of stuff in Brush that probably better goes in Paint -// Functions should be refactored so that they can be used between sculpt.c and -// paint_stroke.c clearly and optimally and the lines of communication between the -// two modules should be more clearly defined. -static void paint_draw_cursor(bContext *C, int x, int y, void *unused) +/* Special actions taken when paint cursor goes over mesh */ +/* TODO: sculpt only for now */ +static void paint_cursor_on_hit(Sculpt *sd, Brush *brush, ViewContext *vc, + float location[3], float *visual_strength) { - ViewContext vc; - - (void)unused; + float unprojected_radius, projected_radius; - view3d_set_viewcontext(C, &vc); - - if (vc.obact->sculpt) { - Paint *paint = paint_get_active(CTX_data_scene(C)); - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - Brush *brush = paint_brush(paint); + /* TODO: check whether this should really only be done when + brush is over mesh? */ + if(sd->draw_pressure && brush_use_alpha_pressure(brush)) + (*visual_strength) *= sd->pressure_value; - int pixel_radius, viewport[4]; - float location[3], modelview[16], projection[16]; + if(sd->draw_anchored) + projected_radius = sd->anchored_size; + else { + if(brush->flag & BRUSH_ANCHORED) + projected_radius = 8; + else + projected_radius = brush_size(brush); + } + unprojected_radius = paint_calc_object_space_radius(vc, location, + projected_radius); - int hit; + if(sd->draw_pressure && brush_use_size_pressure(brush)) + unprojected_radius *= sd->pressure_value; - int flip; - int sign; + if(!brush_use_locked_size(brush)) + brush_set_unprojected_radius(brush, unprojected_radius); +} - float* col; - float alpha; +static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) +{ + Paint *paint = paint_get_active(CTX_data_scene(C)); + Brush *brush = paint_brush(paint); + ViewContext vc; + float final_radius; + float translation[2]; + float outline_alpha, *outline_col; + + /* set various defaults */ + translation[0] = x; + translation[1] = y; + outline_alpha = 0.5; + outline_col = brush->add_col; + final_radius = brush_size(brush); + + /* check that brush drawing is enabled */ + if(!(paint->flags & PAINT_SHOW_BRUSH)) + return; + + /* can't use stroke vc here because this will be called during + mouse over too, not just during a stroke */ + view3d_set_viewcontext(C, &vc); + /* TODO: as sculpt and other paint modes are unified, this + special mode of drawing will go away */ + if(vc.obact->sculpt) { + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + float location[3]; + int pixel_radius, hit; const float root_alpha = brush_alpha(brush); float visual_strength = root_alpha*root_alpha; - const float min_alpha = 0.20f; const float max_alpha = 0.80f; + /* this is probably here so that rake takes into + account the brush movements before the stroke + starts, but this doesn't really belong in draw code + (TODO) */ { const float u = 0.5f; const float v = 1 - u; @@ -570,7 +576,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused) const float dx = sd->last_x - x; const float dy = sd->last_y - y; - if (dx*dx + dy*dy >= r*r) { + if(dx*dx + dy*dy >= r*r) { sd->last_angle = atan2(dx, dy); sd->last_x = u*sd->last_x + v*x; @@ -578,252 +584,106 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused) } } - if(!brush_use_locked_size(brush) && !(paint->flags & PAINT_SHOW_BRUSH)) - return; + /* test if brush is over the mesh */ + hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location); - hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location, modelview, projection, viewport); + /* draw overlay */ + paint_draw_alpha_overlay(sd, brush, &vc, x, y); - if (brush_use_locked_size(brush)) + if(brush_use_locked_size(brush)) brush_set_size(brush, pixel_radius); - // XXX: no way currently to know state of pen flip or invert key modifier without starting a stroke - flip = 1; - - sign = flip * ((brush->flag & BRUSH_DIR_IN)? -1 : 1); - - if (sign < 0 && ELEM4(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH)) - col = brush->sub_col; - else - col = brush->add_col; - - alpha = (paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ? min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f; - - if (ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED) && brush->flag & BRUSH_TEXTURE_OVERLAY) { - glPushAttrib( - GL_COLOR_BUFFER_BIT| - GL_CURRENT_BIT| - GL_DEPTH_BUFFER_BIT| - GL_ENABLE_BIT| - GL_LINE_BIT| - GL_POLYGON_BIT| - GL_STENCIL_BUFFER_BIT| - GL_TRANSFORM_BIT| - GL_VIEWPORT_BIT| - GL_TEXTURE_BIT); - - if (load_tex(sd, brush, &vc)) { - glEnable(GL_BLEND); - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDepthMask(GL_FALSE); - glDepthFunc(GL_ALWAYS); - - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); - - if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) { - glTranslatef(0.5f, 0.5f, 0); - - if (brush->flag & BRUSH_RAKE) { - glRotatef(sd->last_angle*(float)(180.0/M_PI), 0, 0, 1); - } - else { - glRotatef(sd->special_rotation*(float)(180.0/M_PI), 0, 0, 1); - } - - glTranslatef(-0.5f, -0.5f, 0); - - if (sd->draw_pressure && brush_use_size_pressure(brush)) { - glTranslatef(0.5f, 0.5f, 0); - glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1); - glTranslatef(-0.5f, -0.5f, 0); - } - } - - glColor4f( - U.sculpt_paint_overlay_col[0], - U.sculpt_paint_overlay_col[1], - U.sculpt_paint_overlay_col[2], - brush->texture_overlay_alpha / 100.0f); - - glBegin(GL_QUADS); - if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) { - if (sd->draw_anchored) { - glTexCoord2f(0, 0); - glVertex2f(sd->anchored_initial_mouse[0]-sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]-sd->anchored_size - vc.ar->winrct.ymin); - - glTexCoord2f(1, 0); - glVertex2f(sd->anchored_initial_mouse[0]+sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]-sd->anchored_size - vc.ar->winrct.ymin); - - glTexCoord2f(1, 1); - glVertex2f(sd->anchored_initial_mouse[0]+sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]+sd->anchored_size - vc.ar->winrct.ymin); - - glTexCoord2f(0, 1); - glVertex2f(sd->anchored_initial_mouse[0]-sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]+sd->anchored_size - vc.ar->winrct.ymin); - } - else { - const int radius= brush_size(brush); - - glTexCoord2f(0, 0); - glVertex2f((float)x-radius, (float)y-radius); - - glTexCoord2f(1, 0); - glVertex2f((float)x+radius, (float)y-radius); - - glTexCoord2f(1, 1); - glVertex2f((float)x+radius, (float)y+radius); - - glTexCoord2f(0, 1); - glVertex2f((float)x-radius, (float)y+radius); - } - } - else { - glTexCoord2f(0, 0); - glVertex2f(0, 0); - - glTexCoord2f(1, 0); - glVertex2f(viewport[2], 0); - - glTexCoord2f(1, 1); - glVertex2f(viewport[2], viewport[3]); - - glTexCoord2f(0, 1); - glVertex2f(0, viewport[3]); - } - glEnd(); - - glPopMatrix(); - } - - glPopAttrib(); + /* check if brush is subtracting, use different color then */ + /* TODO: no way currently to know state of pen flip or + invert key modifier without starting a stroke */ + if((!(brush->flag & BRUSH_INVERTED) ^ + !(brush->flag & BRUSH_DIR_IN)) && + ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW, + SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, + SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE)) + outline_col = brush->sub_col; + + /* only do if brush is over the mesh */ + if(hit) + paint_cursor_on_hit(sd, brush, &vc, location, &visual_strength); + + /* don't show effect of strength past the soft limit */ + if(visual_strength > 1) + visual_strength = 1; + + outline_alpha = ((paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ? + min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f); + + if(sd->draw_anchored) { + final_radius = sd->anchored_size; + translation[0] = sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin; + translation[1] = sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin; } + } - if (hit) { - float unprojected_radius; - - // XXX duplicated from brush_strength & paint_stroke_add_step, refactor later - //wmEvent* event = CTX_wm_window(C)->eventstate; - - if (sd->draw_pressure && brush_use_alpha_pressure(brush)) - visual_strength *= sd->pressure_value; - - // don't show effect of strength past the soft limit - if (visual_strength > 1) visual_strength = 1; - - if (sd->draw_anchored) { - unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, sd->anchored_size); - } - else { - if (brush->flag & BRUSH_ANCHORED) - unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, 8); - else - unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, brush_size(brush)); - } - - if (sd->draw_pressure && brush_use_size_pressure(brush)) - unprojected_radius *= sd->pressure_value; - - if (!brush_use_locked_size(brush)) - brush_set_unprojected_radius(brush, unprojected_radius); - - if(!(paint->flags & PAINT_SHOW_BRUSH)) - return; - - } + /* make lines pretty */ + glEnable(GL_BLEND); + glEnable(GL_LINE_SMOOTH); - glPushAttrib( - GL_COLOR_BUFFER_BIT| - GL_CURRENT_BIT| - GL_DEPTH_BUFFER_BIT| - GL_ENABLE_BIT| - GL_LINE_BIT| - GL_POLYGON_BIT| - GL_STENCIL_BUFFER_BIT| - GL_TRANSFORM_BIT| - GL_VIEWPORT_BIT| - GL_TEXTURE_BIT); + /* set brush color */ + glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha); - glColor4f(col[0], col[1], col[2], alpha); + /* draw brush outline */ + glTranslatef(translation[0], translation[1], 0); + glutil_draw_lined_arc(0.0, M_PI*2.0, final_radius, 40); + glTranslatef(-translation[0], -translation[1], 0); - glEnable(GL_BLEND); + /* restore GL state */ + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); +} - glEnable(GL_LINE_SMOOTH); +/* if this is a tablet event, return tablet pressure and set *pen_flip + to 1 if the eraser tool is being used, 0 otherwise */ +static float event_tablet_data(wmEvent *event, int *pen_flip) +{ + int erasor = 0; + float pressure = 1; - if (sd->draw_anchored) { - glTranslatef(sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin, 0.0f); - glutil_draw_lined_arc(0.0, M_PI*2.0, sd->anchored_size, 40); - glTranslatef(-sd->anchored_initial_mouse[0] + vc.ar->winrct.xmin, -sd->anchored_initial_mouse[1] + vc.ar->winrct.xmin, 0.0f); - } - else { - glTranslatef((float)x, (float)y, 0.0f); - glutil_draw_lined_arc(0.0, M_PI*2.0, brush_size(brush), 40); - glTranslatef(-(float)x, -(float)y, 0.0f); - } + if(event->custom == EVT_DATA_TABLET) { + wmTabletData *wmtab= event->customdata; - glPopAttrib(); + erasor = (wmtab->Active == EVT_TABLET_ERASER); + pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1; } - else { - Paint *paint = paint_get_active(CTX_data_scene(C)); - Brush *brush = paint_brush(paint); - - if(!(paint->flags & PAINT_SHOW_BRUSH)) - return; - - glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], 0.5f); - 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(brush), 40); // XXX: for now use the brushes size instead of potentially using the unified size because the feature has been enabled for sculpt - glTranslatef((float)-x, (float)-y, 0.0f); + if(pen_flip) + (*pen_flip) = erasor; - glDisable(GL_BLEND); - glDisable(GL_LINE_SMOOTH); - } + return pressure; } /* 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_in[2]) { - Paint *paint = paint_get_active(CTX_data_scene(C)); // XXX - Brush *brush = paint_brush(paint); // XXX - + Paint *paint = paint_get_active(CTX_data_scene(C)); + Brush *brush = paint_brush(paint); + PaintStroke *stroke = op->customdata; float mouse[3]; - PointerRNA itemptr; - float location[3]; - float pressure; - int pen_flip; - - ViewContext vc; // XXX - - PaintStroke *stroke = op->customdata; + int pen_flip; - view3d_set_viewcontext(C, &vc); // XXX + /* see if tablet affects event */ + pressure = event_tablet_data(event, &pen_flip); - /* Tablet */ - if(event->custom == EVT_DATA_TABLET) { - wmTabletData *wmtab= event->customdata; - - pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1; - pen_flip = (wmtab->Active == EVT_TABLET_ERASER); - } - else { - pressure = 1; - pen_flip = 0; - } - - // XXX: temporary check for sculpt mode until things are more unified - if (vc.obact->sculpt) { + /* TODO: as sculpt and other paint modes are unified, this + separation will go away */ + if(stroke->vc.obact->sculpt) { float delta[3]; brush_jitter_pos(brush, mouse_in, mouse); - // XXX: meh, this is round about because brush_jitter_pos isn't written in the best way to be reused here - if (brush->flag & BRUSH_JITTER_PRESSURE) { + /* XXX: meh, this is round about because + brush_jitter_pos isn't written in the best way to + be reused here */ + if(brush->flag & BRUSH_JITTER_PRESSURE) { sub_v3_v3v3(delta, mouse, mouse_in); mul_v3_fl(delta, pressure); add_v3_v3v3(mouse, mouse_in, delta); @@ -832,7 +692,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev else copy_v3_v3(mouse, mouse_in); - /* XXX: can remove the if statement once all modes have this */ + /* TODO: can remove the if statement once all modes have this */ if(stroke->get_location) stroke->get_location(C, stroke, location, mouse); else @@ -841,10 +701,10 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev /* Add to stroke */ RNA_collection_add(op->ptr, "stroke", &itemptr); - RNA_float_set_array(&itemptr, "location", location); - RNA_float_set_array(&itemptr, "mouse", mouse); - RNA_boolean_set (&itemptr, "pen_flip", pen_flip); - RNA_float_set (&itemptr, "pressure", pressure); + RNA_float_set_array(&itemptr, "location", location); + RNA_float_set_array(&itemptr, "mouse", mouse); + RNA_boolean_set(&itemptr, "pen_flip", pen_flip); + RNA_float_set(&itemptr, "pressure", pressure); stroke->last_mouse_position[0] = mouse[0]; stroke->last_mouse_position[1] = mouse[1]; @@ -878,14 +738,6 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *ev 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) && - !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK); -} - /* 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]) @@ -906,23 +758,24 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const if(length > FLT_EPSILON) { int steps; int i; - float pressure = 1; - - // XXX duplicate code - if(event->custom == EVT_DATA_TABLET) { - wmTabletData *wmtab= event->customdata; - if(wmtab->Active != EVT_TABLET_NONE) - pressure = brush_use_size_pressure(stroke->brush) ? wmtab->Pressure : 1; - } - - scale = (brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length; - mul_v2_fl(vec, scale); - - steps = (int)(1.0f / scale); - - for(i = 0; i < steps; ++i, ++cnt) { - add_v2_v2(mouse, vec); - paint_brush_stroke_add_step(C, op, event, mouse); + float pressure= 1.0f; + + /* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */ + if(brush_use_size_pressure(stroke->brush)) + pressure = event_tablet_data(event, NULL); + + if(pressure > FLT_EPSILON) { + scale = (brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length; + if(scale > FLT_EPSILON) { + mul_v2_fl(vec, scale); + + steps = (int)(1.0f / scale); + + for(i = 0; i < steps; ++i, ++cnt) { + add_v2_v2(mouse, vec); + paint_brush_stroke_add_step(C, op, event, mouse); + } + } } } } @@ -957,6 +810,14 @@ void paint_stroke_free(PaintStroke *stroke) MEM_freeN(stroke); } +/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ +int paint_space_stroke_enabled(Brush *br) +{ + return (br->flag & BRUSH_SPACE) && + !(br->flag & BRUSH_ANCHORED) && + !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK); +} + int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) { PaintStroke *stroke = op->customdata; |