|
Blender
V2.59
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2009 by Nicholas Bishop 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Jason Wilkins, Tom Musgrove. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 * 00027 */ 00028 00034 #include "MEM_guardedalloc.h" 00035 00036 #include "BLI_math.h" 00037 #include "BLI_utildefines.h" 00038 00039 #include "DNA_object_types.h" 00040 #include "DNA_scene_types.h" 00041 #include "DNA_brush_types.h" 00042 00043 #include "RNA_access.h" 00044 00045 #include "BKE_context.h" 00046 #include "BKE_paint.h" 00047 #include "BKE_brush.h" 00048 00049 #include "WM_api.h" 00050 #include "WM_types.h" 00051 00052 #include "BIF_gl.h" 00053 #include "BIF_glutil.h" 00054 00055 #include "ED_screen.h" 00056 #include "ED_view3d.h" 00057 00058 #include "paint_intern.h" 00059 /* still needed for sculpt_stroke_get_location, should be 00060 removed eventually (TODO) */ 00061 #include "sculpt_intern.h" 00062 00063 #include <float.h> 00064 #include <math.h> 00065 00066 typedef struct PaintStroke { 00067 void *mode_data; 00068 void *smooth_stroke_cursor; 00069 wmTimer *timer; 00070 00071 /* Cached values */ 00072 ViewContext vc; 00073 bglMats mats; 00074 Brush *brush; 00075 00076 float last_mouse_position[2]; 00077 00078 /* Set whether any stroke step has yet occurred 00079 e.g. in sculpt mode, stroke doesn't start until cursor 00080 passes over the mesh */ 00081 int stroke_started; 00082 /* event that started stroke, for modal() return */ 00083 int event_type; 00084 00085 StrokeGetLocation get_location; 00086 StrokeTestStart test_start; 00087 StrokeUpdateStep update_step; 00088 StrokeDone done; 00089 } PaintStroke; 00090 00091 /*** Cursor ***/ 00092 static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata) 00093 { 00094 Brush *brush = paint_brush(paint_get_active(CTX_data_scene(C))); 00095 PaintStroke *stroke = customdata; 00096 00097 glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col); 00098 glEnable(GL_LINE_SMOOTH); 00099 glEnable(GL_BLEND); 00100 00101 if(stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) { 00102 ARegion *ar = CTX_wm_region(C); 00103 sdrawline(x, y, (int)stroke->last_mouse_position[0] - ar->winrct.xmin, 00104 (int)stroke->last_mouse_position[1] - ar->winrct.ymin); 00105 } 00106 00107 glDisable(GL_BLEND); 00108 glDisable(GL_LINE_SMOOTH); 00109 } 00110 00111 typedef struct Snapshot { 00112 float size[3]; 00113 float ofs[3]; 00114 float rot; 00115 int brush_size; 00116 int winx; 00117 int winy; 00118 int brush_map_mode; 00119 int curve_changed_timestamp; 00120 } Snapshot; 00121 00122 static int same_snap(Snapshot* snap, Brush* brush, ViewContext* vc) 00123 { 00124 MTex* mtex = &brush->mtex; 00125 00126 return 00127 (mtex->tex && 00128 mtex->ofs[0] == snap->ofs[0] && 00129 mtex->ofs[1] == snap->ofs[1] && 00130 mtex->ofs[2] == snap->ofs[2] && 00131 mtex->size[0] == snap->size[0] && 00132 mtex->size[1] == snap->size[1] && 00133 mtex->size[2] == snap->size[2] && 00134 mtex->rot == snap->rot) && 00135 ((mtex->brush_map_mode == MTEX_MAP_MODE_FIXED && brush_size(brush) <= snap->brush_size) || (brush_size(brush) == snap->brush_size)) && // make brush smaller shouldn't cause a resample 00136 mtex->brush_map_mode == snap->brush_map_mode && 00137 vc->ar->winx == snap->winx && 00138 vc->ar->winy == snap->winy; 00139 } 00140 00141 static void make_snap(Snapshot* snap, Brush* brush, ViewContext* vc) 00142 { 00143 if (brush->mtex.tex) { 00144 snap->brush_map_mode = brush->mtex.brush_map_mode; 00145 copy_v3_v3(snap->ofs, brush->mtex.ofs); 00146 copy_v3_v3(snap->size, brush->mtex.size); 00147 snap->rot = brush->mtex.rot; 00148 } 00149 else { 00150 snap->brush_map_mode = -1; 00151 snap->ofs[0]= snap->ofs[1]= snap->ofs[2]= -1; 00152 snap->size[0]= snap->size[1]= snap->size[2]= -1; 00153 snap->rot = -1; 00154 } 00155 00156 snap->brush_size = brush_size(brush); 00157 snap->winx = vc->ar->winx; 00158 snap->winy = vc->ar->winy; 00159 } 00160 00161 static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc) 00162 { 00163 static GLuint overlay_texture = 0; 00164 static int init = 0; 00165 static int tex_changed_timestamp = -1; 00166 static int curve_changed_timestamp = -1; 00167 static Snapshot snap; 00168 static int old_size = -1; 00169 00170 GLubyte* buffer = NULL; 00171 00172 int size; 00173 int j; 00174 int refresh; 00175 00176 #ifndef _OPENMP 00177 (void)sd; /* quied unused warning */ 00178 #endif 00179 00180 if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED && !br->mtex.tex) return 0; 00181 00182 refresh = 00183 !overlay_texture || 00184 (br->mtex.tex && 00185 (!br->mtex.tex->preview || 00186 br->mtex.tex->preview->changed_timestamp[0] != tex_changed_timestamp)) || 00187 !br->curve || 00188 br->curve->changed_timestamp != curve_changed_timestamp || 00189 !same_snap(&snap, br, vc); 00190 00191 if (refresh) { 00192 if (br->mtex.tex && br->mtex.tex->preview) 00193 tex_changed_timestamp = br->mtex.tex->preview->changed_timestamp[0]; 00194 00195 if (br->curve) 00196 curve_changed_timestamp = br->curve->changed_timestamp; 00197 00198 make_snap(&snap, br, vc); 00199 00200 if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) { 00201 int s = brush_size(br); 00202 int r = 1; 00203 00204 for (s >>= 1; s > 0; s >>= 1) 00205 r++; 00206 00207 size = (1<<r); 00208 00209 if (size < 256) 00210 size = 256; 00211 00212 if (size < old_size) 00213 size = old_size; 00214 } 00215 else 00216 size = 512; 00217 00218 if (old_size != size) { 00219 if (overlay_texture) { 00220 glDeleteTextures(1, &overlay_texture); 00221 overlay_texture = 0; 00222 } 00223 00224 init = 0; 00225 00226 old_size = size; 00227 } 00228 00229 buffer = MEM_mallocN(sizeof(GLubyte)*size*size, "load_tex"); 00230 00231 #pragma omp parallel for schedule(static) if (sd->flags & SCULPT_USE_OPENMP) 00232 for (j= 0; j < size; j++) { 00233 int i; 00234 float y; 00235 float len; 00236 00237 for (i= 0; i < size; i++) { 00238 00239 // largely duplicated from tex_strength 00240 00241 const float rotation = -br->mtex.rot; 00242 float radius = brush_size(br); 00243 int index = j*size + i; 00244 float x; 00245 float avg; 00246 00247 x = (float)i/size; 00248 y = (float)j/size; 00249 00250 x -= 0.5f; 00251 y -= 0.5f; 00252 00253 if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) { 00254 x *= vc->ar->winx / radius; 00255 y *= vc->ar->winy / radius; 00256 } 00257 else { 00258 x *= 2; 00259 y *= 2; 00260 } 00261 00262 len = sqrtf(x*x + y*y); 00263 00264 if ((br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) || len <= 1) { 00265 /* it is probably worth optimizing for those cases where 00266 the texture is not rotated by skipping the calls to 00267 atan2, sqrtf, sin, and cos. */ 00268 if (br->mtex.tex && (rotation > 0.001f || rotation < -0.001f)) { 00269 const float angle = atan2f(y, x) + rotation; 00270 00271 x = len * cosf(angle); 00272 y = len * sinf(angle); 00273 } 00274 00275 x *= br->mtex.size[0]; 00276 y *= br->mtex.size[1]; 00277 00278 x += br->mtex.ofs[0]; 00279 y += br->mtex.ofs[1]; 00280 00281 avg = br->mtex.tex ? paint_get_tex_pixel(br, x, y) : 1; 00282 00283 avg += br->texture_sample_bias; 00284 00285 if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) 00286 avg *= brush_curve_strength(br, len, 1); /* Falloff curve */ 00287 00288 buffer[index] = 255 - (GLubyte)(255*avg); 00289 } 00290 else { 00291 buffer[index] = 0; 00292 } 00293 } 00294 } 00295 00296 if (!overlay_texture) 00297 glGenTextures(1, &overlay_texture); 00298 } 00299 else { 00300 size= old_size; 00301 } 00302 00303 glBindTexture(GL_TEXTURE_2D, overlay_texture); 00304 00305 if (refresh) { 00306 if (!init) { 00307 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); 00308 init = 1; 00309 } 00310 else { 00311 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); 00312 } 00313 00314 if (buffer) 00315 MEM_freeN(buffer); 00316 } 00317 00318 glEnable(GL_TEXTURE_2D); 00319 00320 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 00321 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00323 00324 if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) { 00325 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00327 } 00328 00329 return 1; 00330 } 00331 00332 static int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats) 00333 { 00334 float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2]; 00335 00336 ED_view3d_global_to_vector(rv3d, location, view); 00337 00338 // create a vector that is not orthogonal to view 00339 00340 if (fabsf(view[0]) < 0.1f) { 00341 nonortho[0] = view[0] + 1.0f; 00342 nonortho[1] = view[1]; 00343 nonortho[2] = view[2]; 00344 } 00345 else if (fabsf(view[1]) < 0.1f) { 00346 nonortho[0] = view[0]; 00347 nonortho[1] = view[1] + 1.0f; 00348 nonortho[2] = view[2]; 00349 } 00350 else { 00351 nonortho[0] = view[0]; 00352 nonortho[1] = view[1]; 00353 nonortho[2] = view[2] + 1.0f; 00354 } 00355 00356 // get a vector in the plane of the view 00357 cross_v3_v3v3(ortho, nonortho, view); 00358 normalize_v3(ortho); 00359 00360 // make a point on the surface of the brush tagent to the view 00361 mul_v3_fl(ortho, radius); 00362 add_v3_v3v3(offset, location, ortho); 00363 00364 // project the center of the brush, and the tagent point to the view onto the screen 00365 projectf(mats, location, p1); 00366 projectf(mats, offset, p2); 00367 00368 // the distance between these points is the size of the projected brush in pixels 00369 return len_v2v2(p1, p2); 00370 } 00371 00372 static int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, 00373 float location[3]) 00374 { 00375 struct PaintStroke *stroke; 00376 float window[2]; 00377 int hit; 00378 00379 stroke = paint_stroke_new(C, NULL, NULL, NULL, NULL, 0); 00380 00381 window[0] = x + stroke->vc.ar->winrct.xmin; 00382 window[1] = y + stroke->vc.ar->winrct.ymin; 00383 00384 if(stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && 00385 sculpt_stroke_get_location(C, stroke, location, window)) { 00386 *pixel_radius = project_brush_radius(stroke->vc.rv3d, 00387 brush_unprojected_radius(stroke->brush), 00388 location, &stroke->mats); 00389 00390 if (*pixel_radius == 0) 00391 *pixel_radius = brush_size(stroke->brush); 00392 00393 mul_m4_v3(stroke->vc.obact->obmat, location); 00394 00395 hit = 1; 00396 } 00397 else { 00398 Sculpt* sd = CTX_data_tool_settings(C)->sculpt; 00399 Brush* brush = paint_brush(&sd->paint); 00400 00401 *pixel_radius = brush_size(brush); 00402 hit = 0; 00403 } 00404 00405 paint_stroke_free(stroke); 00406 00407 return hit; 00408 } 00409 00410 /* Draw an overlay that shows what effect the brush's texture will 00411 have on brush strength */ 00412 /* TODO: sculpt only for now */ 00413 static void paint_draw_alpha_overlay(Sculpt *sd, Brush *brush, 00414 ViewContext *vc, int x, int y) 00415 { 00416 rctf quad; 00417 00418 /* check for overlay mode */ 00419 if(!(brush->flag & BRUSH_TEXTURE_OVERLAY) || 00420 !(ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED))) 00421 return; 00422 00423 /* save lots of GL state 00424 TODO: check on whether all of these are needed? */ 00425 glPushAttrib(GL_COLOR_BUFFER_BIT| 00426 GL_CURRENT_BIT| 00427 GL_DEPTH_BUFFER_BIT| 00428 GL_ENABLE_BIT| 00429 GL_LINE_BIT| 00430 GL_POLYGON_BIT| 00431 GL_STENCIL_BUFFER_BIT| 00432 GL_TRANSFORM_BIT| 00433 GL_VIEWPORT_BIT| 00434 GL_TEXTURE_BIT); 00435 00436 if(load_tex(sd, brush, vc)) { 00437 glEnable(GL_BLEND); 00438 00439 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 00440 glDepthMask(GL_FALSE); 00441 glDepthFunc(GL_ALWAYS); 00442 00443 glMatrixMode(GL_TEXTURE); 00444 glPushMatrix(); 00445 glLoadIdentity(); 00446 00447 if(brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) { 00448 /* brush rotation */ 00449 glTranslatef(0.5, 0.5, 0); 00450 glRotatef((double)((brush->flag & BRUSH_RAKE) ? 00451 sd->last_angle : sd->special_rotation) * (180.0/M_PI), 00452 0.0, 0.0, 1.0); 00453 glTranslatef(-0.5f, -0.5f, 0); 00454 00455 /* scale based on tablet pressure */ 00456 if(sd->draw_pressure && brush_use_size_pressure(brush)) { 00457 glTranslatef(0.5f, 0.5f, 0); 00458 glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1); 00459 glTranslatef(-0.5f, -0.5f, 0); 00460 } 00461 00462 if(sd->draw_anchored) { 00463 const float *aim = sd->anchored_initial_mouse; 00464 const rcti *win = &vc->ar->winrct; 00465 quad.xmin = aim[0]-sd->anchored_size - win->xmin; 00466 quad.ymin = aim[1]-sd->anchored_size - win->ymin; 00467 quad.xmax = aim[0]+sd->anchored_size - win->xmin; 00468 quad.ymax = aim[1]+sd->anchored_size - win->ymin; 00469 } 00470 else { 00471 const int radius= brush_size(brush); 00472 quad.xmin = x - radius; 00473 quad.ymin = y - radius; 00474 quad.xmax = x + radius; 00475 quad.ymax = y + radius; 00476 } 00477 } 00478 else { 00479 quad.xmin = 0; 00480 quad.ymin = 0; 00481 quad.xmax = vc->ar->winrct.xmax - vc->ar->winrct.xmin; 00482 quad.ymax = vc->ar->winrct.ymax - vc->ar->winrct.ymin; 00483 } 00484 00485 /* set quad color */ 00486 glColor4f(U.sculpt_paint_overlay_col[0], 00487 U.sculpt_paint_overlay_col[1], 00488 U.sculpt_paint_overlay_col[2], 00489 brush->texture_overlay_alpha / 100.0f); 00490 00491 /* draw textured quad */ 00492 glBegin(GL_QUADS); 00493 glTexCoord2f(0, 0); 00494 glVertex2f(quad.xmin, quad.ymin); 00495 glTexCoord2f(1, 0); 00496 glVertex2f(quad.xmax, quad.ymin); 00497 glTexCoord2f(1, 1); 00498 glVertex2f(quad.xmax, quad.ymax); 00499 glTexCoord2f(0, 1); 00500 glVertex2f(quad.xmin, quad.ymax); 00501 glEnd(); 00502 00503 glPopMatrix(); 00504 } 00505 00506 glPopAttrib(); 00507 } 00508 00509 /* Special actions taken when paint cursor goes over mesh */ 00510 /* TODO: sculpt only for now */ 00511 static void paint_cursor_on_hit(Sculpt *sd, Brush *brush, ViewContext *vc, 00512 float location[3], float *visual_strength) 00513 { 00514 float unprojected_radius, projected_radius; 00515 00516 /* TODO: check whether this should really only be done when 00517 brush is over mesh? */ 00518 if(sd->draw_pressure && brush_use_alpha_pressure(brush)) 00519 (*visual_strength) *= sd->pressure_value; 00520 00521 if(sd->draw_anchored) 00522 projected_radius = sd->anchored_size; 00523 else { 00524 if(brush->flag & BRUSH_ANCHORED) 00525 projected_radius = 8; 00526 else 00527 projected_radius = brush_size(brush); 00528 } 00529 unprojected_radius = paint_calc_object_space_radius(vc, location, 00530 projected_radius); 00531 00532 if(sd->draw_pressure && brush_use_size_pressure(brush)) 00533 unprojected_radius *= sd->pressure_value; 00534 00535 if(!brush_use_locked_size(brush)) 00536 brush_set_unprojected_radius(brush, unprojected_radius); 00537 } 00538 00539 static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) 00540 { 00541 Paint *paint = paint_get_active(CTX_data_scene(C)); 00542 Brush *brush = paint_brush(paint); 00543 ViewContext vc; 00544 float final_radius; 00545 float translation[2]; 00546 float outline_alpha, *outline_col; 00547 00548 /* set various defaults */ 00549 translation[0] = x; 00550 translation[1] = y; 00551 outline_alpha = 0.5; 00552 outline_col = brush->add_col; 00553 final_radius = brush_size(brush); 00554 00555 /* check that brush drawing is enabled */ 00556 if(!(paint->flags & PAINT_SHOW_BRUSH)) 00557 return; 00558 00559 /* can't use stroke vc here because this will be called during 00560 mouse over too, not just during a stroke */ 00561 view3d_set_viewcontext(C, &vc); 00562 00563 /* TODO: as sculpt and other paint modes are unified, this 00564 special mode of drawing will go away */ 00565 if(vc.obact->sculpt) { 00566 Sculpt *sd = CTX_data_tool_settings(C)->sculpt; 00567 float location[3]; 00568 int pixel_radius, hit; 00569 const float root_alpha = brush_alpha(brush); 00570 float visual_strength = root_alpha*root_alpha; 00571 const float min_alpha = 0.20f; 00572 const float max_alpha = 0.80f; 00573 00574 /* this is probably here so that rake takes into 00575 account the brush movements before the stroke 00576 starts, but this doesn't really belong in draw code 00577 (TODO) */ 00578 { 00579 const float u = 0.5f; 00580 const float v = 1 - u; 00581 const float r = 20; 00582 00583 const float dx = sd->last_x - x; 00584 const float dy = sd->last_y - y; 00585 00586 if(dx*dx + dy*dy >= r*r) { 00587 sd->last_angle = atan2(dx, dy); 00588 00589 sd->last_x = u*sd->last_x + v*x; 00590 sd->last_y = u*sd->last_y + v*y; 00591 } 00592 } 00593 00594 /* test if brush is over the mesh */ 00595 hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location); 00596 00597 /* draw overlay */ 00598 paint_draw_alpha_overlay(sd, brush, &vc, x, y); 00599 00600 if(brush_use_locked_size(brush)) 00601 brush_set_size(brush, pixel_radius); 00602 00603 /* check if brush is subtracting, use different color then */ 00604 /* TODO: no way currently to know state of pen flip or 00605 invert key modifier without starting a stroke */ 00606 if((!(brush->flag & BRUSH_INVERTED) ^ 00607 !(brush->flag & BRUSH_DIR_IN)) && 00608 ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW, 00609 SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, 00610 SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE)) 00611 outline_col = brush->sub_col; 00612 00613 /* only do if brush is over the mesh */ 00614 if(hit) 00615 paint_cursor_on_hit(sd, brush, &vc, location, &visual_strength); 00616 00617 /* don't show effect of strength past the soft limit */ 00618 if(visual_strength > 1) 00619 visual_strength = 1; 00620 00621 outline_alpha = ((paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ? 00622 min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f); 00623 00624 if(sd->draw_anchored) { 00625 final_radius = sd->anchored_size; 00626 translation[0] = sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin; 00627 translation[1] = sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin; 00628 } 00629 } 00630 00631 /* make lines pretty */ 00632 glEnable(GL_BLEND); 00633 glEnable(GL_LINE_SMOOTH); 00634 00635 /* set brush color */ 00636 glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha); 00637 00638 /* draw brush outline */ 00639 glTranslatef(translation[0], translation[1], 0); 00640 glutil_draw_lined_arc(0.0, M_PI*2.0, final_radius, 40); 00641 glTranslatef(-translation[0], -translation[1], 0); 00642 00643 /* restore GL state */ 00644 glDisable(GL_BLEND); 00645 glDisable(GL_LINE_SMOOTH); 00646 } 00647 00648 /* if this is a tablet event, return tablet pressure and set *pen_flip 00649 to 1 if the eraser tool is being used, 0 otherwise */ 00650 static float event_tablet_data(wmEvent *event, int *pen_flip) 00651 { 00652 int erasor = 0; 00653 float pressure = 1; 00654 00655 if(event->custom == EVT_DATA_TABLET) { 00656 wmTabletData *wmtab= event->customdata; 00657 00658 erasor = (wmtab->Active == EVT_TABLET_ERASER); 00659 pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1; 00660 } 00661 00662 if(pen_flip) 00663 (*pen_flip) = erasor; 00664 00665 return pressure; 00666 } 00667 00668 /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */ 00669 static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2]) 00670 { 00671 Paint *paint = paint_get_active(CTX_data_scene(C)); 00672 Brush *brush = paint_brush(paint); 00673 PaintStroke *stroke = op->customdata; 00674 float mouse[3]; 00675 PointerRNA itemptr; 00676 float location[3]; 00677 float pressure; 00678 int pen_flip; 00679 00680 /* see if tablet affects event */ 00681 pressure = event_tablet_data(event, &pen_flip); 00682 00683 /* TODO: as sculpt and other paint modes are unified, this 00684 separation will go away */ 00685 if(stroke->vc.obact->sculpt) { 00686 float delta[3]; 00687 00688 brush_jitter_pos(brush, mouse_in, mouse); 00689 00690 /* XXX: meh, this is round about because 00691 brush_jitter_pos isn't written in the best way to 00692 be reused here */ 00693 if(brush->flag & BRUSH_JITTER_PRESSURE) { 00694 sub_v3_v3v3(delta, mouse, mouse_in); 00695 mul_v3_fl(delta, pressure); 00696 add_v3_v3v3(mouse, mouse_in, delta); 00697 } 00698 } 00699 else 00700 copy_v3_v3(mouse, mouse_in); 00701 00702 /* TODO: can remove the if statement once all modes have this */ 00703 if(stroke->get_location) 00704 stroke->get_location(C, stroke, location, mouse); 00705 else 00706 zero_v3(location); 00707 00708 /* Add to stroke */ 00709 RNA_collection_add(op->ptr, "stroke", &itemptr); 00710 00711 RNA_float_set_array(&itemptr, "location", location); 00712 RNA_float_set_array(&itemptr, "mouse", mouse); 00713 RNA_boolean_set(&itemptr, "pen_flip", pen_flip); 00714 RNA_float_set(&itemptr, "pressure", pressure); 00715 00716 stroke->last_mouse_position[0] = mouse[0]; 00717 stroke->last_mouse_position[1] = mouse[1]; 00718 00719 stroke->update_step(C, stroke, &itemptr); 00720 } 00721 00722 /* Returns zero if no sculpt changes should be made, non-zero otherwise */ 00723 static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *event) 00724 { 00725 output[0] = event->x; 00726 output[1] = event->y; 00727 00728 if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) && 00729 !ELEM4(stroke->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK) && 00730 !(stroke->brush->flag & BRUSH_ANCHORED) && 00731 !(stroke->brush->flag & BRUSH_RESTORE_MESH)) 00732 { 00733 float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; 00734 float dx = stroke->last_mouse_position[0] - event->x, dy = stroke->last_mouse_position[1] - event->y; 00735 00736 /* If the mouse is moving within the radius of the last move, 00737 don't update the mouse position. This allows sharp turns. */ 00738 if(dx*dx + dy*dy < stroke->brush->smooth_stroke_radius * stroke->brush->smooth_stroke_radius) 00739 return 0; 00740 00741 output[0] = event->x * v + stroke->last_mouse_position[0] * u; 00742 output[1] = event->y * v + stroke->last_mouse_position[1] * u; 00743 } 00744 00745 return 1; 00746 } 00747 00748 /* For brushes with stroke spacing enabled, moves mouse in steps 00749 towards the final mouse location. */ 00750 static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2]) 00751 { 00752 PaintStroke *stroke = op->customdata; 00753 int cnt = 0; 00754 00755 if(paint_space_stroke_enabled(stroke->brush)) { 00756 float mouse[2]; 00757 float vec[2]; 00758 float length, scale; 00759 00760 copy_v2_v2(mouse, stroke->last_mouse_position); 00761 sub_v2_v2v2(vec, final_mouse, mouse); 00762 00763 length = len_v2(vec); 00764 00765 if(length > FLT_EPSILON) { 00766 int steps; 00767 int i; 00768 float pressure= 1.0f; 00769 00770 /* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */ 00771 if(brush_use_size_pressure(stroke->brush)) 00772 pressure = event_tablet_data(event, NULL); 00773 00774 if(pressure > FLT_EPSILON) { 00775 scale = (brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length; 00776 if(scale > FLT_EPSILON) { 00777 mul_v2_fl(vec, scale); 00778 00779 steps = (int)(1.0f / scale); 00780 00781 for(i = 0; i < steps; ++i, ++cnt) { 00782 add_v2_v2(mouse, vec); 00783 paint_brush_stroke_add_step(C, op, event, mouse); 00784 } 00785 } 00786 } 00787 } 00788 } 00789 00790 return cnt; 00791 } 00792 00793 /**** Public API ****/ 00794 00795 PaintStroke *paint_stroke_new(bContext *C, 00796 StrokeGetLocation get_location, 00797 StrokeTestStart test_start, 00798 StrokeUpdateStep update_step, 00799 StrokeDone done, int event_type) 00800 { 00801 PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke"); 00802 00803 stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C))); 00804 view3d_set_viewcontext(C, &stroke->vc); 00805 view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats); 00806 00807 stroke->get_location = get_location; 00808 stroke->test_start = test_start; 00809 stroke->update_step = update_step; 00810 stroke->done = done; 00811 stroke->event_type= event_type; /* for modal, return event */ 00812 00813 return stroke; 00814 } 00815 00816 void paint_stroke_free(PaintStroke *stroke) 00817 { 00818 MEM_freeN(stroke); 00819 } 00820 00821 /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ 00822 int paint_space_stroke_enabled(Brush *br) 00823 { 00824 return (br->flag & BRUSH_SPACE) && 00825 !(br->flag & BRUSH_ANCHORED) && 00826 !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK); 00827 } 00828 00829 int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) 00830 { 00831 PaintStroke *stroke = op->customdata; 00832 float mouse[2]; 00833 int first= 0; 00834 00835 // let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously! 00836 // this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it 00837 // since the 2D deltas are zero -- code in this file needs to be updated to use the 00838 // post-NDOF_MOTION MOUSEMOVE 00839 if (event->type == NDOF_MOTION) 00840 return OPERATOR_PASS_THROUGH; 00841 00842 if(!stroke->stroke_started) { 00843 stroke->last_mouse_position[0] = event->x; 00844 stroke->last_mouse_position[1] = event->y; 00845 stroke->stroke_started = stroke->test_start(C, op, event); 00846 00847 if(stroke->stroke_started) { 00848 stroke->smooth_stroke_cursor = 00849 WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke); 00850 00851 if(stroke->brush->flag & BRUSH_AIRBRUSH) 00852 stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate); 00853 } 00854 00855 first= 1; 00856 //ED_region_tag_redraw(ar); 00857 } 00858 00859 if(event->type == stroke->event_type && event->val == KM_RELEASE) { 00860 /* exit stroke, free data */ 00861 if(stroke->smooth_stroke_cursor) 00862 WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor); 00863 00864 if(stroke->timer) 00865 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer); 00866 00867 stroke->done(C, stroke); 00868 MEM_freeN(stroke); 00869 return OPERATOR_FINISHED; 00870 } 00871 else if(first || ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (event->type == TIMER && (event->customdata == stroke->timer))) { 00872 if(stroke->stroke_started) { 00873 if(paint_smooth_stroke(stroke, mouse, event)) { 00874 if(paint_space_stroke_enabled(stroke->brush)) { 00875 if(!paint_space_stroke(C, op, event, mouse)) { 00876 //ED_region_tag_redraw(ar); 00877 } 00878 } 00879 else { 00880 paint_brush_stroke_add_step(C, op, event, mouse); 00881 } 00882 } 00883 else { 00884 ;//ED_region_tag_redraw(ar); 00885 } 00886 } 00887 } 00888 00889 /* we want the stroke to have the first daub at the start location instead of waiting till we have moved the space distance */ 00890 if(first && 00891 stroke->stroke_started && 00892 paint_space_stroke_enabled(stroke->brush) && 00893 !(stroke->brush->flag & BRUSH_ANCHORED) && 00894 !(stroke->brush->flag & BRUSH_SMOOTH_STROKE)) 00895 { 00896 paint_brush_stroke_add_step(C, op, event, mouse); 00897 } 00898 00899 return OPERATOR_RUNNING_MODAL; 00900 } 00901 00902 int paint_stroke_exec(bContext *C, wmOperator *op) 00903 { 00904 PaintStroke *stroke = op->customdata; 00905 00906 /* only when executed for the first time */ 00907 if(stroke->stroke_started == 0) { 00908 /* XXX stroke->last_mouse_position is unset, this may cause problems */ 00909 stroke->test_start(C, op, NULL); 00910 stroke->stroke_started= 1; 00911 } 00912 00913 RNA_BEGIN(op->ptr, itemptr, "stroke") { 00914 stroke->update_step(C, stroke, &itemptr); 00915 } 00916 RNA_END; 00917 00918 stroke->done(C, stroke); 00919 00920 MEM_freeN(stroke); 00921 op->customdata = NULL; 00922 00923 return OPERATOR_FINISHED; 00924 } 00925 00926 int paint_stroke_cancel(bContext *C, wmOperator *op) 00927 { 00928 PaintStroke *stroke = op->customdata; 00929 00930 if(stroke->done) 00931 stroke->done(C, stroke); 00932 00933 MEM_freeN(stroke); 00934 op->customdata = NULL; 00935 00936 return OPERATOR_CANCELLED; 00937 } 00938 00939 ViewContext *paint_stroke_view_context(PaintStroke *stroke) 00940 { 00941 return &stroke->vc; 00942 } 00943 00944 void *paint_stroke_mode_data(struct PaintStroke *stroke) 00945 { 00946 return stroke->mode_data; 00947 } 00948 00949 void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data) 00950 { 00951 stroke->mode_data = mode_data; 00952 } 00953 00954 int paint_poll(bContext *C) 00955 { 00956 Paint *p = paint_get_active(CTX_data_scene(C)); 00957 Object *ob = CTX_data_active_object(C); 00958 00959 return p && ob && paint_brush(p) && 00960 CTX_wm_area(C)->spacetype == SPACE_VIEW3D && 00961 CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW; 00962 } 00963 00964 void paint_cursor_start(bContext *C, int (*poll)(bContext *C)) 00965 { 00966 Paint *p = paint_get_active(CTX_data_scene(C)); 00967 00968 if(p && !p->paint_cursor) 00969 p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL); 00970 } 00971