Blender V2.61 - r43446
|
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 (((mtex->tex) && 00127 equals_v3v3(mtex->ofs, snap->ofs) && 00128 equals_v3v3(mtex->size, snap->size) && 00129 mtex->rot == snap->rot) && 00130 00131 /* make brush smaller shouldn't cause a resample */ 00132 ((mtex->brush_map_mode == MTEX_MAP_MODE_FIXED && 00133 (brush_size(vc->scene, brush) <= snap->brush_size)) || 00134 (brush_size(vc->scene, brush) == snap->brush_size)) && 00135 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(vc->scene, 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(vc->scene, 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(vc->scene, 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_TO_BORDER); 00326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); 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 const Scene *scene = CTX_data_scene(C); 00377 float window[2]; 00378 int hit; 00379 00380 stroke = paint_stroke_new(C, NULL, NULL, NULL, NULL, 0); 00381 00382 window[0] = x + stroke->vc.ar->winrct.xmin; 00383 window[1] = y + stroke->vc.ar->winrct.ymin; 00384 00385 if(stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && 00386 sculpt_stroke_get_location(C, stroke, location, window)) { 00387 *pixel_radius = project_brush_radius(stroke->vc.rv3d, 00388 brush_unprojected_radius(scene, stroke->brush), 00389 location, &stroke->mats); 00390 00391 if (*pixel_radius == 0) 00392 *pixel_radius = brush_size(scene, stroke->brush); 00393 00394 mul_m4_v3(stroke->vc.obact->obmat, location); 00395 00396 hit = 1; 00397 } 00398 else { 00399 Sculpt* sd = CTX_data_tool_settings(C)->sculpt; 00400 Brush* brush = paint_brush(&sd->paint); 00401 00402 *pixel_radius = brush_size(scene, brush); 00403 hit = 0; 00404 } 00405 00406 paint_stroke_free(stroke); 00407 00408 return hit; 00409 } 00410 00411 /* Draw an overlay that shows what effect the brush's texture will 00412 have on brush strength */ 00413 /* TODO: sculpt only for now */ 00414 static void paint_draw_alpha_overlay(Sculpt *sd, Brush *brush, 00415 ViewContext *vc, int x, int y) 00416 { 00417 rctf quad; 00418 00419 /* check for overlay mode */ 00420 if(!(brush->flag & BRUSH_TEXTURE_OVERLAY) || 00421 !(ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED))) 00422 return; 00423 00424 /* save lots of GL state 00425 TODO: check on whether all of these are needed? */ 00426 glPushAttrib(GL_COLOR_BUFFER_BIT| 00427 GL_CURRENT_BIT| 00428 GL_DEPTH_BUFFER_BIT| 00429 GL_ENABLE_BIT| 00430 GL_LINE_BIT| 00431 GL_POLYGON_BIT| 00432 GL_STENCIL_BUFFER_BIT| 00433 GL_TRANSFORM_BIT| 00434 GL_VIEWPORT_BIT| 00435 GL_TEXTURE_BIT); 00436 00437 if(load_tex(sd, brush, vc)) { 00438 glEnable(GL_BLEND); 00439 00440 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 00441 glDepthMask(GL_FALSE); 00442 glDepthFunc(GL_ALWAYS); 00443 00444 glMatrixMode(GL_TEXTURE); 00445 glPushMatrix(); 00446 glLoadIdentity(); 00447 00448 if(brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) { 00449 /* brush rotation */ 00450 glTranslatef(0.5, 0.5, 0); 00451 glRotatef((double)RAD2DEGF((brush->flag & BRUSH_RAKE) ? 00452 sd->last_angle : sd->special_rotation), 00453 0.0, 0.0, 1.0); 00454 glTranslatef(-0.5f, -0.5f, 0); 00455 00456 /* scale based on tablet pressure */ 00457 if(sd->draw_pressure && brush_use_size_pressure(vc->scene, brush)) { 00458 glTranslatef(0.5f, 0.5f, 0); 00459 glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1); 00460 glTranslatef(-0.5f, -0.5f, 0); 00461 } 00462 00463 if(sd->draw_anchored) { 00464 const float *aim = sd->anchored_initial_mouse; 00465 const rcti *win = &vc->ar->winrct; 00466 quad.xmin = aim[0]-sd->anchored_size - win->xmin; 00467 quad.ymin = aim[1]-sd->anchored_size - win->ymin; 00468 quad.xmax = aim[0]+sd->anchored_size - win->xmin; 00469 quad.ymax = aim[1]+sd->anchored_size - win->ymin; 00470 } 00471 else { 00472 const int radius= brush_size(vc->scene, brush); 00473 quad.xmin = x - radius; 00474 quad.ymin = y - radius; 00475 quad.xmax = x + radius; 00476 quad.ymax = y + radius; 00477 } 00478 } 00479 else { 00480 quad.xmin = 0; 00481 quad.ymin = 0; 00482 quad.xmax = vc->ar->winrct.xmax - vc->ar->winrct.xmin; 00483 quad.ymax = vc->ar->winrct.ymax - vc->ar->winrct.ymin; 00484 } 00485 00486 /* set quad color */ 00487 glColor4f(U.sculpt_paint_overlay_col[0], 00488 U.sculpt_paint_overlay_col[1], 00489 U.sculpt_paint_overlay_col[2], 00490 brush->texture_overlay_alpha / 100.0f); 00491 00492 /* draw textured quad */ 00493 glBegin(GL_QUADS); 00494 glTexCoord2f(0, 0); 00495 glVertex2f(quad.xmin, quad.ymin); 00496 glTexCoord2f(1, 0); 00497 glVertex2f(quad.xmax, quad.ymin); 00498 glTexCoord2f(1, 1); 00499 glVertex2f(quad.xmax, quad.ymax); 00500 glTexCoord2f(0, 1); 00501 glVertex2f(quad.xmin, quad.ymax); 00502 glEnd(); 00503 00504 glPopMatrix(); 00505 } 00506 00507 glPopAttrib(); 00508 } 00509 00510 /* Special actions taken when paint cursor goes over mesh */ 00511 /* TODO: sculpt only for now */ 00512 static void paint_cursor_on_hit(Sculpt *sd, Brush *brush, ViewContext *vc, 00513 const float location[3]) 00514 { 00515 float unprojected_radius, projected_radius; 00516 00517 /* update the brush's cached 3D radius */ 00518 if(!brush_use_locked_size(vc->scene, brush)) { 00519 /* get 2D brush radius */ 00520 if(sd->draw_anchored) 00521 projected_radius = sd->anchored_size; 00522 else { 00523 if(brush->flag & BRUSH_ANCHORED) 00524 projected_radius = 8; 00525 else 00526 projected_radius = brush_size(vc->scene, brush); 00527 } 00528 00529 /* convert brush radius from 2D to 3D */ 00530 unprojected_radius = paint_calc_object_space_radius(vc, location, 00531 projected_radius); 00532 00533 /* scale 3D brush radius by pressure */ 00534 if(sd->draw_pressure && brush_use_size_pressure(vc->scene, brush)) 00535 unprojected_radius *= sd->pressure_value; 00536 00537 /* set cached value in either Brush or UnifiedPaintSettings */ 00538 brush_set_unprojected_radius(vc->scene, brush, unprojected_radius); 00539 } 00540 } 00541 00542 static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) 00543 { 00544 Scene *scene = CTX_data_scene(C); 00545 Paint *paint = paint_get_active(scene); 00546 Brush *brush = paint_brush(paint); 00547 ViewContext vc; 00548 float final_radius; 00549 float translation[2]; 00550 float outline_alpha, *outline_col; 00551 00552 /* set various defaults */ 00553 translation[0] = x; 00554 translation[1] = y; 00555 outline_alpha = 0.5; 00556 outline_col = brush->add_col; 00557 final_radius = brush_size(scene, brush); 00558 00559 /* check that brush drawing is enabled */ 00560 if(!(paint->flags & PAINT_SHOW_BRUSH)) 00561 return; 00562 00563 /* can't use stroke vc here because this will be called during 00564 mouse over too, not just during a stroke */ 00565 view3d_set_viewcontext(C, &vc); 00566 00567 /* TODO: as sculpt and other paint modes are unified, this 00568 special mode of drawing will go away */ 00569 if(vc.obact->sculpt) { 00570 Sculpt *sd = CTX_data_tool_settings(C)->sculpt; 00571 float location[3]; 00572 int pixel_radius, hit; 00573 const float root_alpha = brush_alpha(scene, brush); 00574 float visual_strength = root_alpha*root_alpha; 00575 const float min_alpha = 0.20f; 00576 const float max_alpha = 0.80f; 00577 00578 /* this is probably here so that rake takes into 00579 account the brush movements before the stroke 00580 starts, but this doesn't really belong in draw code 00581 (TODO) */ 00582 { 00583 const float u = 0.5f; 00584 const float v = 1 - u; 00585 const float r = 20; 00586 00587 const float dx = sd->last_x - x; 00588 const float dy = sd->last_y - y; 00589 00590 if(dx*dx + dy*dy >= r*r) { 00591 sd->last_angle = atan2(dx, dy); 00592 00593 sd->last_x = u*sd->last_x + v*x; 00594 sd->last_y = u*sd->last_y + v*y; 00595 } 00596 } 00597 00598 /* test if brush is over the mesh */ 00599 hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location); 00600 00601 /* draw overlay */ 00602 paint_draw_alpha_overlay(sd, brush, &vc, x, y); 00603 00604 if(brush_use_locked_size(scene, brush)) 00605 brush_set_size(scene, brush, pixel_radius); 00606 00607 /* check if brush is subtracting, use different color then */ 00608 /* TODO: no way currently to know state of pen flip or 00609 invert key modifier without starting a stroke */ 00610 if((!(brush->flag & BRUSH_INVERTED) ^ 00611 !(brush->flag & BRUSH_DIR_IN)) && 00612 ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW, 00613 SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, 00614 SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE)) 00615 outline_col = brush->sub_col; 00616 00617 /* only do if brush is over the mesh */ 00618 if(hit) { 00619 /* scale the alpha by pen pressure */ 00620 if(sd->draw_pressure && brush_use_alpha_pressure(vc.scene, brush)) 00621 visual_strength *= sd->pressure_value; 00622 00623 paint_cursor_on_hit(sd, brush, &vc, location); 00624 } 00625 00626 /* don't show effect of strength past the soft limit */ 00627 if(visual_strength > 1) 00628 visual_strength = 1; 00629 00630 outline_alpha = ((paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ? 00631 min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f); 00632 00633 if(sd->draw_anchored) { 00634 final_radius = sd->anchored_size; 00635 translation[0] = sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin; 00636 translation[1] = sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin; 00637 } 00638 } 00639 00640 /* make lines pretty */ 00641 glEnable(GL_BLEND); 00642 glEnable(GL_LINE_SMOOTH); 00643 00644 /* set brush color */ 00645 glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha); 00646 00647 /* draw brush outline */ 00648 glTranslatef(translation[0], translation[1], 0); 00649 glutil_draw_lined_arc(0.0, M_PI*2.0, final_radius, 40); 00650 glTranslatef(-translation[0], -translation[1], 0); 00651 00652 /* restore GL state */ 00653 glDisable(GL_BLEND); 00654 glDisable(GL_LINE_SMOOTH); 00655 } 00656 00657 /* if this is a tablet event, return tablet pressure and set *pen_flip 00658 to 1 if the eraser tool is being used, 0 otherwise */ 00659 static float event_tablet_data(wmEvent *event, int *pen_flip) 00660 { 00661 int erasor = 0; 00662 float pressure = 1; 00663 00664 if(event->custom == EVT_DATA_TABLET) { 00665 wmTabletData *wmtab= event->customdata; 00666 00667 erasor = (wmtab->Active == EVT_TABLET_ERASER); 00668 pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1; 00669 } 00670 00671 if(pen_flip) 00672 (*pen_flip) = erasor; 00673 00674 return pressure; 00675 } 00676 00677 /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */ 00678 static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2]) 00679 { 00680 Scene *scene = CTX_data_scene(C); 00681 Paint *paint = paint_get_active(scene); 00682 Brush *brush = paint_brush(paint); 00683 PaintStroke *stroke = op->customdata; 00684 float mouse[3]; 00685 PointerRNA itemptr; 00686 float location[3]; 00687 float pressure; 00688 int pen_flip; 00689 00690 /* see if tablet affects event */ 00691 pressure = event_tablet_data(event, &pen_flip); 00692 00693 /* TODO: as sculpt and other paint modes are unified, this 00694 separation will go away */ 00695 if(stroke->vc.obact->sculpt) { 00696 float delta[2]; 00697 00698 brush_jitter_pos(scene, brush, mouse_in, mouse); 00699 00700 /* XXX: meh, this is round about because 00701 brush_jitter_pos isn't written in the best way to 00702 be reused here */ 00703 if(brush->flag & BRUSH_JITTER_PRESSURE) { 00704 sub_v2_v2v2(delta, mouse, mouse_in); 00705 mul_v2_fl(delta, pressure); 00706 add_v2_v2v2(mouse, mouse_in, delta); 00707 } 00708 } 00709 else { 00710 copy_v2_v2(mouse, mouse_in); 00711 } 00712 00713 /* TODO: can remove the if statement once all modes have this */ 00714 if(stroke->get_location) 00715 stroke->get_location(C, stroke, location, mouse); 00716 else 00717 zero_v3(location); 00718 00719 /* Add to stroke */ 00720 RNA_collection_add(op->ptr, "stroke", &itemptr); 00721 00722 RNA_float_set_array(&itemptr, "location", location); 00723 RNA_float_set_array(&itemptr, "mouse", mouse); 00724 RNA_boolean_set(&itemptr, "pen_flip", pen_flip); 00725 RNA_float_set(&itemptr, "pressure", pressure); 00726 00727 stroke->last_mouse_position[0] = mouse[0]; 00728 stroke->last_mouse_position[1] = mouse[1]; 00729 00730 stroke->update_step(C, stroke, &itemptr); 00731 } 00732 00733 /* Returns zero if no sculpt changes should be made, non-zero otherwise */ 00734 static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *event) 00735 { 00736 output[0] = event->x; 00737 output[1] = event->y; 00738 00739 if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) && 00740 !ELEM4(stroke->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK) && 00741 !(stroke->brush->flag & BRUSH_ANCHORED) && 00742 !(stroke->brush->flag & BRUSH_RESTORE_MESH)) 00743 { 00744 float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; 00745 float dx = stroke->last_mouse_position[0] - event->x, dy = stroke->last_mouse_position[1] - event->y; 00746 00747 /* If the mouse is moving within the radius of the last move, 00748 don't update the mouse position. This allows sharp turns. */ 00749 if(dx*dx + dy*dy < stroke->brush->smooth_stroke_radius * stroke->brush->smooth_stroke_radius) 00750 return 0; 00751 00752 output[0] = event->x * v + stroke->last_mouse_position[0] * u; 00753 output[1] = event->y * v + stroke->last_mouse_position[1] * u; 00754 } 00755 00756 return 1; 00757 } 00758 00759 /* For brushes with stroke spacing enabled, moves mouse in steps 00760 towards the final mouse location. */ 00761 static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2]) 00762 { 00763 PaintStroke *stroke = op->customdata; 00764 int cnt = 0; 00765 00766 if(paint_space_stroke_enabled(stroke->brush)) { 00767 float mouse[2]; 00768 float vec[2]; 00769 float length, scale; 00770 00771 copy_v2_v2(mouse, stroke->last_mouse_position); 00772 sub_v2_v2v2(vec, final_mouse, mouse); 00773 00774 length = len_v2(vec); 00775 00776 if(length > FLT_EPSILON) { 00777 const Scene *scene = CTX_data_scene(C); 00778 int steps; 00779 int i; 00780 float pressure= 1.0f; 00781 00782 /* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */ 00783 if(brush_use_size_pressure(scene, stroke->brush)) 00784 pressure = event_tablet_data(event, NULL); 00785 00786 if(pressure > FLT_EPSILON) { 00787 scale = (brush_size(scene, stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length; 00788 if(scale > FLT_EPSILON) { 00789 mul_v2_fl(vec, scale); 00790 00791 steps = (int)(1.0f / scale); 00792 00793 for(i = 0; i < steps; ++i, ++cnt) { 00794 add_v2_v2(mouse, vec); 00795 paint_brush_stroke_add_step(C, op, event, mouse); 00796 } 00797 } 00798 } 00799 } 00800 } 00801 00802 return cnt; 00803 } 00804 00805 /**** Public API ****/ 00806 00807 PaintStroke *paint_stroke_new(bContext *C, 00808 StrokeGetLocation get_location, 00809 StrokeTestStart test_start, 00810 StrokeUpdateStep update_step, 00811 StrokeDone done, int event_type) 00812 { 00813 PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke"); 00814 00815 stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C))); 00816 view3d_set_viewcontext(C, &stroke->vc); 00817 view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats); 00818 00819 stroke->get_location = get_location; 00820 stroke->test_start = test_start; 00821 stroke->update_step = update_step; 00822 stroke->done = done; 00823 stroke->event_type= event_type; /* for modal, return event */ 00824 00825 return stroke; 00826 } 00827 00828 void paint_stroke_free(PaintStroke *stroke) 00829 { 00830 MEM_freeN(stroke); 00831 } 00832 00833 /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ 00834 int paint_space_stroke_enabled(Brush *br) 00835 { 00836 return (br->flag & BRUSH_SPACE) && 00837 !(br->flag & BRUSH_ANCHORED) && 00838 !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK); 00839 } 00840 00841 int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) 00842 { 00843 PaintStroke *stroke = op->customdata; 00844 float mouse[2]; 00845 int first= 0; 00846 00847 // let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously! 00848 // this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it 00849 // since the 2D deltas are zero -- code in this file needs to be updated to use the 00850 // post-NDOF_MOTION MOUSEMOVE 00851 if (event->type == NDOF_MOTION) 00852 return OPERATOR_PASS_THROUGH; 00853 00854 if(!stroke->stroke_started) { 00855 stroke->last_mouse_position[0] = event->x; 00856 stroke->last_mouse_position[1] = event->y; 00857 stroke->stroke_started = stroke->test_start(C, op, event); 00858 00859 if(stroke->stroke_started) { 00860 stroke->smooth_stroke_cursor = 00861 WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke); 00862 00863 if(stroke->brush->flag & BRUSH_AIRBRUSH) 00864 stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate); 00865 } 00866 00867 first= 1; 00868 //ED_region_tag_redraw(ar); 00869 } 00870 00871 if(event->type == stroke->event_type && event->val == KM_RELEASE) { 00872 /* exit stroke, free data */ 00873 if(stroke->smooth_stroke_cursor) 00874 WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor); 00875 00876 if(stroke->timer) 00877 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer); 00878 00879 stroke->done(C, stroke); 00880 MEM_freeN(stroke); 00881 return OPERATOR_FINISHED; 00882 } 00883 else if( (first) || 00884 (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) || 00885 (event->type == TIMER && (event->customdata == stroke->timer)) ) 00886 { 00887 if(stroke->stroke_started) { 00888 if(paint_smooth_stroke(stroke, mouse, event)) { 00889 if(paint_space_stroke_enabled(stroke->brush)) { 00890 if(!paint_space_stroke(C, op, event, mouse)) { 00891 //ED_region_tag_redraw(ar); 00892 } 00893 } 00894 else { 00895 paint_brush_stroke_add_step(C, op, event, mouse); 00896 } 00897 } 00898 else { 00899 ;//ED_region_tag_redraw(ar); 00900 } 00901 } 00902 } 00903 00904 /* we want the stroke to have the first daub at the start location 00905 * instead of waiting till we have moved the space distance */ 00906 if(first && 00907 stroke->stroke_started && 00908 paint_space_stroke_enabled(stroke->brush) && 00909 !(stroke->brush->flag & BRUSH_ANCHORED) && 00910 !(stroke->brush->flag & BRUSH_SMOOTH_STROKE)) 00911 { 00912 paint_brush_stroke_add_step(C, op, event, mouse); 00913 } 00914 00915 return OPERATOR_RUNNING_MODAL; 00916 } 00917 00918 int paint_stroke_exec(bContext *C, wmOperator *op) 00919 { 00920 PaintStroke *stroke = op->customdata; 00921 00922 /* only when executed for the first time */ 00923 if(stroke->stroke_started == 0) { 00924 /* XXX stroke->last_mouse_position is unset, this may cause problems */ 00925 stroke->test_start(C, op, NULL); 00926 stroke->stroke_started= 1; 00927 } 00928 00929 RNA_BEGIN(op->ptr, itemptr, "stroke") { 00930 stroke->update_step(C, stroke, &itemptr); 00931 } 00932 RNA_END; 00933 00934 stroke->done(C, stroke); 00935 00936 MEM_freeN(stroke); 00937 op->customdata = NULL; 00938 00939 return OPERATOR_FINISHED; 00940 } 00941 00942 int paint_stroke_cancel(bContext *C, wmOperator *op) 00943 { 00944 PaintStroke *stroke = op->customdata; 00945 00946 if(stroke->done) 00947 stroke->done(C, stroke); 00948 00949 MEM_freeN(stroke); 00950 op->customdata = NULL; 00951 00952 return OPERATOR_CANCELLED; 00953 } 00954 00955 ViewContext *paint_stroke_view_context(PaintStroke *stroke) 00956 { 00957 return &stroke->vc; 00958 } 00959 00960 void *paint_stroke_mode_data(struct PaintStroke *stroke) 00961 { 00962 return stroke->mode_data; 00963 } 00964 00965 void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data) 00966 { 00967 stroke->mode_data = mode_data; 00968 } 00969 00970 int paint_poll(bContext *C) 00971 { 00972 Paint *p = paint_get_active(CTX_data_scene(C)); 00973 Object *ob = CTX_data_active_object(C); 00974 00975 return p && ob && paint_brush(p) && 00976 CTX_wm_area(C)->spacetype == SPACE_VIEW3D && 00977 CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW; 00978 } 00979 00980 void paint_cursor_start(bContext *C, int (*poll)(bContext *C)) 00981 { 00982 Paint *p = paint_get_active(CTX_data_scene(C)); 00983 00984 if(p && !p->paint_cursor) 00985 p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL); 00986 } 00987