|
Blender
V2.59
|
00001 /* 00002 * $Id: editarmature_sketch.c 36933 2011-05-26 21:04:01Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * ***** END GPL LICENSE BLOCK ***** 00021 */ 00022 00028 #include <string.h> 00029 #include <math.h> 00030 #include <float.h> 00031 00032 #include "MEM_guardedalloc.h" 00033 00034 #include "DNA_object_types.h" 00035 #include "DNA_scene_types.h" 00036 #include "DNA_armature_types.h" 00037 00038 #include "RNA_define.h" 00039 #include "RNA_access.h" 00040 00041 #include "BLI_blenlib.h" 00042 #include "BLI_math.h" 00043 #include "BLI_utildefines.h" 00044 #include "BLI_graph.h" 00045 #include "BLI_ghash.h" 00046 00047 #include "BKE_context.h" 00048 #include "BKE_sketch.h" 00049 00050 #include "ED_view3d.h" 00051 #include "ED_screen.h" 00052 00053 #include "BIF_gl.h" 00054 //#include "BIF_screen.h" 00055 //#include "BIF_space.h" 00056 //#include "BIF_mywindow.h" 00057 #include "ED_armature.h" 00058 #include "armature_intern.h" 00059 //#include "BIF_sketch.h" 00060 #include "BIF_retarget.h" 00061 #include "BIF_generate.h" 00062 //#include "BIF_interface.h" 00063 00064 #include "ED_transform.h" 00065 00066 #include "WM_api.h" 00067 #include "WM_types.h" 00068 00069 //#include "blendef.h" 00070 //#include "mydevice.h" 00071 #include "reeb.h" 00072 00073 00074 00075 typedef int (*GestureDetectFct)(bContext*, SK_Gesture*, SK_Sketch *); 00076 typedef void (*GestureApplyFct)(bContext*, SK_Gesture*, SK_Sketch *); 00077 00078 typedef struct SK_GestureAction { 00079 char name[64]; 00080 GestureDetectFct detect; 00081 GestureApplyFct apply; 00082 } SK_GestureAction; 00083 00084 #if 0 /* UNUSED 2.5 */ 00085 static SK_Point boneSnap; 00086 #endif 00087 00088 static int LAST_SNAP_POINT_VALID = 0; 00089 static float LAST_SNAP_POINT[3]; 00090 00091 00092 typedef struct SK_StrokeIterator { 00093 HeadFct head; 00094 TailFct tail; 00095 PeekFct peek; 00096 NextFct next; 00097 NextNFct nextN; 00098 PreviousFct previous; 00099 StoppedFct stopped; 00100 00101 float *p, *no; 00102 float size; 00103 00104 int length; 00105 int index; 00106 /*********************************/ 00107 SK_Stroke *stroke; 00108 int start; 00109 int end; 00110 int stride; 00111 } SK_StrokeIterator; 00112 00113 /******************** PROTOTYPES ******************************/ 00114 00115 void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end); 00116 00117 int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00118 void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00119 int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00120 void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00121 int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00122 void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00123 int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00124 void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00125 int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00126 void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00127 int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00128 void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00129 int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00130 void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); 00131 00132 SK_Sketch* contextSketch(const bContext *c, int create); 00133 SK_Sketch* viewcontextSketch(ViewContext *vc, int create); 00134 00135 void sk_resetOverdraw(SK_Sketch *sketch); 00136 int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk); 00137 00138 /******************** GESTURE ACTIONS ******************************/ 00139 00140 static SK_GestureAction GESTURE_ACTIONS[] = 00141 { 00142 {"Cut", sk_detectCutGesture, sk_applyCutGesture}, 00143 {"Trim", sk_detectTrimGesture, sk_applyTrimGesture}, 00144 {"Command", sk_detectCommandGesture, sk_applyCommandGesture}, 00145 {"Delete", sk_detectDeleteGesture, sk_applyDeleteGesture}, 00146 {"Merge", sk_detectMergeGesture, sk_applyMergeGesture}, 00147 {"Reverse", sk_detectReverseGesture, sk_applyReverseGesture}, 00148 {"Convert", sk_detectConvertGesture, sk_applyConvertGesture}, 00149 {"", NULL, NULL} 00150 }; 00151 00152 /******************** TEMPLATES UTILS *************************/ 00153 00154 static char *TEMPLATES_MENU = NULL; 00155 static int TEMPLATES_CURRENT = 0; 00156 static GHash *TEMPLATES_HASH = NULL; 00157 static RigGraph *TEMPLATE_RIGG = NULL; 00158 00159 void BIF_makeListTemplates(const bContext *C) 00160 { 00161 Object *obedit = CTX_data_edit_object(C); 00162 Scene *scene = CTX_data_scene(C); 00163 ToolSettings *ts = CTX_data_tool_settings(C); 00164 Base *base; 00165 int index = 0; 00166 00167 if (TEMPLATES_HASH != NULL) 00168 { 00169 BLI_ghash_free(TEMPLATES_HASH, NULL, NULL); 00170 } 00171 00172 TEMPLATES_HASH = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "makeListTemplates gh"); 00173 TEMPLATES_CURRENT = 0; 00174 00175 for ( base = FIRSTBASE; base; base = base->next ) 00176 { 00177 Object *ob = base->object; 00178 00179 if (ob != obedit && ob->type == OB_ARMATURE) 00180 { 00181 index++; 00182 BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob); 00183 00184 if (ob == ts->skgen_template) 00185 { 00186 TEMPLATES_CURRENT = index; 00187 } 00188 } 00189 } 00190 } 00191 00192 char *BIF_listTemplates(const bContext *UNUSED(C)) 00193 { 00194 GHashIterator ghi; 00195 char menu_header[] = "Template%t|None%x0|"; 00196 char *p; 00197 00198 if (TEMPLATES_MENU != NULL) 00199 { 00200 MEM_freeN(TEMPLATES_MENU); 00201 } 00202 00203 TEMPLATES_MENU = MEM_callocN(sizeof(char) * (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30), "skeleton template menu"); 00204 00205 p = TEMPLATES_MENU; 00206 00207 p += sprintf(TEMPLATES_MENU, "%s", menu_header); 00208 00209 BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); 00210 00211 while (!BLI_ghashIterator_isDone(&ghi)) 00212 { 00213 Object *ob = BLI_ghashIterator_getValue(&ghi); 00214 int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi)); 00215 00216 p += sprintf(p, "|%s%%x%i", ob->id.name+2, key); 00217 00218 BLI_ghashIterator_step(&ghi); 00219 } 00220 00221 return TEMPLATES_MENU; 00222 } 00223 00224 int BIF_currentTemplate(const bContext *C) 00225 { 00226 ToolSettings *ts = CTX_data_tool_settings(C); 00227 00228 if (TEMPLATES_CURRENT == 0 && ts->skgen_template != NULL) 00229 { 00230 GHashIterator ghi; 00231 BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); 00232 00233 while (!BLI_ghashIterator_isDone(&ghi)) 00234 { 00235 Object *ob = BLI_ghashIterator_getValue(&ghi); 00236 int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi)); 00237 00238 if (ob == ts->skgen_template) 00239 { 00240 TEMPLATES_CURRENT = key; 00241 break; 00242 } 00243 00244 BLI_ghashIterator_step(&ghi); 00245 } 00246 } 00247 00248 return TEMPLATES_CURRENT; 00249 } 00250 00251 static RigGraph* sk_makeTemplateGraph(const bContext *C, Object *ob) 00252 { 00253 Object *obedit = CTX_data_edit_object(C); 00254 if (ob == obedit) 00255 { 00256 return NULL; 00257 } 00258 00259 if (ob != NULL) 00260 { 00261 if (TEMPLATE_RIGG && TEMPLATE_RIGG->ob != ob) 00262 { 00263 RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG); 00264 TEMPLATE_RIGG = NULL; 00265 } 00266 00267 if (TEMPLATE_RIGG == NULL) 00268 { 00269 bArmature *arm; 00270 00271 arm = ob->data; 00272 00273 TEMPLATE_RIGG = RIG_graphFromArmature(C, ob, arm); 00274 } 00275 } 00276 00277 return TEMPLATE_RIGG; 00278 } 00279 00280 int BIF_nbJointsTemplate(const bContext *C) 00281 { 00282 ToolSettings *ts = CTX_data_tool_settings(C); 00283 RigGraph *rg = sk_makeTemplateGraph(C, ts->skgen_template); 00284 00285 if (rg) 00286 { 00287 return RIG_nbJoints(rg); 00288 } 00289 else 00290 { 00291 return -1; 00292 } 00293 } 00294 00295 const char * BIF_nameBoneTemplate(const bContext *C) 00296 { 00297 ToolSettings *ts = CTX_data_tool_settings(C); 00298 SK_Sketch *stk = contextSketch(C, 1); 00299 RigGraph *rg; 00300 int index = 0; 00301 00302 if (stk && stk->active_stroke != NULL) 00303 { 00304 index = stk->active_stroke->nb_points; 00305 } 00306 00307 rg = sk_makeTemplateGraph(C, ts->skgen_template); 00308 00309 if (rg == NULL) 00310 { 00311 return ""; 00312 } 00313 00314 return RIG_nameBone(rg, 0, index); 00315 } 00316 00317 void BIF_freeTemplates(bContext *UNUSED(C)) 00318 { 00319 if (TEMPLATES_MENU != NULL) 00320 { 00321 MEM_freeN(TEMPLATES_MENU); 00322 TEMPLATES_MENU = NULL; 00323 } 00324 00325 if (TEMPLATES_HASH != NULL) 00326 { 00327 BLI_ghash_free(TEMPLATES_HASH, NULL, NULL); 00328 TEMPLATES_HASH = NULL; 00329 } 00330 00331 if (TEMPLATE_RIGG != NULL) 00332 { 00333 RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG); 00334 TEMPLATE_RIGG = NULL; 00335 } 00336 } 00337 00338 void BIF_setTemplate(bContext *C, int index) 00339 { 00340 ToolSettings *ts = CTX_data_tool_settings(C); 00341 if (index > 0) 00342 { 00343 ts->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index)); 00344 } 00345 else 00346 { 00347 ts->skgen_template = NULL; 00348 00349 if (TEMPLATE_RIGG != NULL) 00350 { 00351 RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG); 00352 } 00353 TEMPLATE_RIGG = NULL; 00354 } 00355 } 00356 00357 /*********************** CONVERSION ***************************/ 00358 00359 static void sk_autoname(bContext *C, ReebArc *arc) 00360 { 00361 ToolSettings *ts = CTX_data_tool_settings(C); 00362 if (ts->skgen_retarget_options & SK_RETARGET_AUTONAME) 00363 { 00364 if (arc == NULL) 00365 { 00366 char *num = ts->skgen_num_string; 00367 int i = atoi(num); 00368 i++; 00369 BLI_snprintf(num, 8, "%i", i); 00370 } 00371 else 00372 { 00373 char *side = ts->skgen_side_string; 00374 int valid = 0; 00375 int caps = 0; 00376 00377 if (side[0] == '\0') 00378 { 00379 valid = 1; 00380 } 00381 else if (strcmp(side, "R")==0 || strcmp(side, "L")==0) 00382 { 00383 valid = 1; 00384 caps = 1; 00385 } 00386 else if (strcmp(side, "r")==0 || strcmp(side, "l")==0) 00387 { 00388 valid = 1; 00389 caps = 0; 00390 } 00391 00392 if (valid) 00393 { 00394 if (arc->head->p[0] < 0) 00395 { 00396 BLI_snprintf(side, 8, caps?"R":"r"); 00397 } 00398 else 00399 { 00400 BLI_snprintf(side, 8, caps?"L":"l"); 00401 } 00402 } 00403 } 00404 } 00405 } 00406 00407 static ReebNode *sk_pointToNode(SK_Point *pt, float imat[][4], float tmat[][3]) 00408 { 00409 ReebNode *node; 00410 00411 node = MEM_callocN(sizeof(ReebNode), "reeb node"); 00412 VECCOPY(node->p, pt->p); 00413 mul_m4_v3(imat, node->p); 00414 00415 VECCOPY(node->no, pt->no); 00416 mul_m3_v3(tmat, node->no); 00417 00418 return node; 00419 } 00420 00421 static ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[][4], float tmat[][3]) 00422 { 00423 ReebArc *arc; 00424 int i; 00425 00426 arc = MEM_callocN(sizeof(ReebArc), "reeb arc"); 00427 arc->head = sk_pointToNode(stk->points, imat, tmat); 00428 arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat); 00429 00430 arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */ 00431 arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets"); 00432 00433 for (i = 0; i < arc->bcount; i++) 00434 { 00435 VECCOPY(arc->buckets[i].p, stk->points[i + 1].p); 00436 mul_m4_v3(imat, arc->buckets[i].p); 00437 00438 VECCOPY(arc->buckets[i].no, stk->points[i + 1].no); 00439 mul_m3_v3(tmat, arc->buckets[i].no); 00440 } 00441 00442 return arc; 00443 } 00444 00445 static void sk_retargetStroke(bContext *C, SK_Stroke *stk) 00446 { 00447 ToolSettings *ts = CTX_data_tool_settings(C); 00448 Object *obedit = CTX_data_edit_object(C); 00449 float imat[4][4]; 00450 float tmat[3][3]; 00451 ReebArc *arc; 00452 RigGraph *rg; 00453 00454 invert_m4_m4(imat, obedit->obmat); 00455 00456 copy_m3_m4(tmat, obedit->obmat); 00457 transpose_m3(tmat); 00458 00459 arc = sk_strokeToArc(stk, imat, tmat); 00460 00461 sk_autoname(C, arc); 00462 00463 rg = sk_makeTemplateGraph(C, ts->skgen_template); 00464 00465 BIF_retargetArc(C, arc, rg); 00466 00467 sk_autoname(C, NULL); 00468 00469 MEM_freeN(arc->head); 00470 MEM_freeN(arc->tail); 00471 REEB_freeArc((BArc*)arc); 00472 } 00473 00474 /**************************************************************/ 00475 00476 static void sk_cancelStroke(SK_Sketch *sketch) 00477 { 00478 if (sketch->active_stroke != NULL) 00479 { 00480 sk_resetOverdraw(sketch); 00481 sk_removeStroke(sketch, sketch->active_stroke); 00482 } 00483 } 00484 00485 00486 static float sk_clampPointSize(SK_Point *pt, float size) 00487 { 00488 return MAX2(size * pt->size, size / 2); 00489 } 00490 00491 static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size) 00492 { 00493 glTranslatef(pt->p[0], pt->p[1], pt->p[2]); 00494 gluSphere(quad, sk_clampPointSize(pt, size), 8, 8); 00495 } 00496 00497 static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float size) 00498 { 00499 float vec1[3], vec2[3] = {0, 0, 1}, axis[3]; 00500 float angle, length; 00501 00502 sub_v3_v3v3(vec1, pt1->p, pt0->p); 00503 length = normalize_v3(vec1); 00504 cross_v3_v3v3(axis, vec2, vec1); 00505 00506 if (is_zero_v3(axis)) 00507 { 00508 axis[1] = 1; 00509 } 00510 00511 angle = angle_normalized_v3v3(vec2, vec1); 00512 00513 glRotatef(angle * 180 / M_PI + 180, axis[0], axis[1], axis[2]); 00514 00515 gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8); 00516 } 00517 00518 static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float height) 00519 { 00520 float vec2[3] = {0, 0, 1}, axis[3]; 00521 float angle; 00522 00523 glPushMatrix(); 00524 00525 cross_v3_v3v3(axis, vec2, pt->no); 00526 00527 if (is_zero_v3(axis)) 00528 { 00529 axis[1] = 1; 00530 } 00531 00532 angle = angle_normalized_v3v3(vec2, pt->no); 00533 00534 glRotatef(angle * 180 / M_PI, axis[0], axis[1], axis[2]); 00535 00536 glColor3f(0, 1, 1); 00537 gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2); 00538 00539 glPopMatrix(); 00540 } 00541 00542 static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end) 00543 { 00544 float rgb[3]; 00545 int i; 00546 GLUquadric *quad = gluNewQuadric(); 00547 gluQuadricNormals(quad, GLU_SMOOTH); 00548 00549 if (id != -1) 00550 { 00551 glLoadName(id); 00552 00553 for (i = 0; i < stk->nb_points; i++) 00554 { 00555 glPushMatrix(); 00556 00557 sk_drawPoint(quad, stk->points + i, 0.1); 00558 00559 if (i > 0) 00560 { 00561 sk_drawEdge(quad, stk->points + i - 1, stk->points + i, 0.1); 00562 } 00563 00564 glPopMatrix(); 00565 } 00566 00567 } 00568 else 00569 { 00570 float d_rgb[3] = {1, 1, 1}; 00571 00572 copy_v3_v3(rgb, color); 00573 sub_v3_v3(d_rgb, rgb); 00574 mul_v3_fl(d_rgb, 1.0f / (float)stk->nb_points); 00575 00576 for (i = 0; i < stk->nb_points; i++) 00577 { 00578 SK_Point *pt = stk->points + i; 00579 00580 glPushMatrix(); 00581 00582 if (pt->type == PT_EXACT) 00583 { 00584 glColor3f(0, 0, 0); 00585 sk_drawPoint(quad, pt, 0.15); 00586 sk_drawNormal(quad, pt, 0.05, 0.9); 00587 } 00588 00589 if (i >= start && i <= end) 00590 { 00591 glColor3f(0.3, 0.3, 0.3); 00592 } 00593 else 00594 { 00595 glColor3fv(rgb); 00596 } 00597 00598 if (pt->type != PT_EXACT) 00599 { 00600 00601 sk_drawPoint(quad, pt, 0.1); 00602 } 00603 00604 if (i > 0) 00605 { 00606 sk_drawEdge(quad, pt - 1, pt, 0.1); 00607 } 00608 00609 glPopMatrix(); 00610 00611 add_v3_v3(rgb, d_rgb); 00612 } 00613 } 00614 00615 gluDeleteQuadric(quad); 00616 } 00617 00618 static void drawSubdividedStrokeBy(ToolSettings *toolsettings, BArcIterator *iter, NextSubdivisionFunc next_subdividion) 00619 { 00620 SK_Stroke *stk = ((SK_StrokeIterator*)iter)->stroke; 00621 float head[3], tail[3]; 00622 int bone_start = 0; 00623 int end = iter->length; 00624 int index; 00625 GLUquadric *quad = gluNewQuadric(); 00626 gluQuadricNormals(quad, GLU_SMOOTH); 00627 00628 iter->head(iter); 00629 VECCOPY(head, iter->p); 00630 00631 index = next_subdividion(toolsettings, iter, bone_start, end, head, tail); 00632 while (index != -1) 00633 { 00634 SK_Point *pt = stk->points + index; 00635 00636 glPushMatrix(); 00637 00638 glColor3f(0, 1, 0); 00639 sk_drawPoint(quad, pt, 0.15); 00640 00641 sk_drawNormal(quad, pt, 0.05, 0.9); 00642 00643 glPopMatrix(); 00644 00645 VECCOPY(head, tail); 00646 bone_start = index; // start next bone from current index 00647 00648 index = next_subdividion(toolsettings, iter, bone_start, end, head, tail); 00649 } 00650 00651 gluDeleteQuadric(quad); 00652 } 00653 00654 static void sk_drawStrokeSubdivision(ToolSettings *toolsettings, SK_Stroke *stk) 00655 { 00656 int head_index = -1; 00657 int i; 00658 00659 if (toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET) 00660 { 00661 return; 00662 } 00663 00664 00665 for (i = 0; i < stk->nb_points; i++) 00666 { 00667 SK_Point *pt = stk->points + i; 00668 00669 if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */ 00670 { 00671 if (head_index == -1) 00672 { 00673 head_index = i; 00674 } 00675 else 00676 { 00677 if (i - head_index > 1) 00678 { 00679 SK_StrokeIterator sk_iter; 00680 BArcIterator *iter = (BArcIterator*)&sk_iter; 00681 00682 initStrokeIterator(iter, stk, head_index, i); 00683 00684 if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) 00685 { 00686 drawSubdividedStrokeBy(toolsettings, iter, nextAdaptativeSubdivision); 00687 } 00688 else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) 00689 { 00690 drawSubdividedStrokeBy(toolsettings, iter, nextLengthSubdivision); 00691 } 00692 else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED) 00693 { 00694 drawSubdividedStrokeBy(toolsettings, iter, nextFixedSubdivision); 00695 } 00696 00697 } 00698 00699 head_index = i; 00700 } 00701 } 00702 } 00703 } 00704 00705 static SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, int mval[2], int *dist, int *index, int all_pts) 00706 { 00707 ARegion *ar = CTX_wm_region(C); 00708 SK_Point *pt = NULL; 00709 int i; 00710 00711 for (i = 0; i < stk->nb_points; i++) 00712 { 00713 if (all_pts || stk->points[i].type == PT_EXACT) 00714 { 00715 short pval[2]; 00716 int pdist; 00717 00718 project_short_noclip(ar, stk->points[i].p, pval); 00719 00720 pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); 00721 00722 if (pdist < *dist) 00723 { 00724 *dist = pdist; 00725 pt = stk->points + i; 00726 00727 if (index != NULL) 00728 { 00729 *index = i; 00730 } 00731 } 00732 } 00733 } 00734 00735 return pt; 00736 } 00737 00738 #if 0 /* UNUSED 2.5 */ 00739 static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, int mval[2], int *dist) 00740 { 00741 ARegion *ar = CTX_wm_region(C); 00742 SK_Point *pt = NULL; 00743 EditBone *bone; 00744 00745 for (bone = ebones->first; bone; bone = bone->next) 00746 { 00747 float vec[3]; 00748 short pval[2]; 00749 int pdist; 00750 00751 if ((bone->flag & BONE_CONNECTED) == 0) 00752 { 00753 VECCOPY(vec, bone->head); 00754 mul_m4_v3(ob->obmat, vec); 00755 project_short_noclip(ar, vec, pval); 00756 00757 pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); 00758 00759 if (pdist < *dist) 00760 { 00761 *dist = pdist; 00762 pt = &boneSnap; 00763 VECCOPY(pt->p, vec); 00764 pt->type = PT_EXACT; 00765 } 00766 } 00767 00768 00769 VECCOPY(vec, bone->tail); 00770 mul_m4_v3(ob->obmat, vec); 00771 project_short_noclip(ar, vec, pval); 00772 00773 pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); 00774 00775 if (pdist < *dist) 00776 { 00777 *dist = pdist; 00778 pt = &boneSnap; 00779 VECCOPY(pt->p, vec); 00780 pt->type = PT_EXACT; 00781 } 00782 } 00783 00784 return pt; 00785 } 00786 #endif 00787 00788 void sk_resetOverdraw(SK_Sketch *sketch) 00789 { 00790 sketch->over.target = NULL; 00791 sketch->over.start = -1; 00792 sketch->over.end = -1; 00793 sketch->over.count = 0; 00794 } 00795 00796 int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk) 00797 { 00798 return sketch->over.target && 00799 sketch->over.count >= SK_OVERDRAW_LIMIT && 00800 (sketch->over.target == stk || stk == NULL) && 00801 (sketch->over.start != -1 || sketch->over.end != -1); 00802 } 00803 00804 static void sk_updateOverdraw(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) 00805 { 00806 if (sketch->over.target == NULL) 00807 { 00808 SK_Stroke *target; 00809 int closest_index = -1; 00810 int dist = SNAP_MIN_DISTANCE * 2; 00811 00812 for (target = sketch->strokes.first; target; target = target->next) 00813 { 00814 if (target != stk) 00815 { 00816 int index; 00817 00818 SK_Point *spt = sk_snapPointStroke(C, target, dd->mval, &dist, &index, 1); 00819 00820 if (spt != NULL) 00821 { 00822 sketch->over.target = target; 00823 closest_index = index; 00824 } 00825 } 00826 } 00827 00828 if (sketch->over.target != NULL) 00829 { 00830 if (closest_index > -1) 00831 { 00832 if (sk_lastStrokePoint(stk)->type == PT_EXACT) 00833 { 00834 sketch->over.count = SK_OVERDRAW_LIMIT; 00835 } 00836 else 00837 { 00838 sketch->over.count++; 00839 } 00840 } 00841 00842 if (stk->nb_points == 1) 00843 { 00844 sketch->over.start = closest_index; 00845 } 00846 else 00847 { 00848 sketch->over.end = closest_index; 00849 } 00850 } 00851 } 00852 else if (sketch->over.target != NULL) 00853 { 00854 SK_Point *closest_pt = NULL; 00855 int dist = SNAP_MIN_DISTANCE * 2; 00856 int index; 00857 00858 closest_pt = sk_snapPointStroke(C, sketch->over.target, dd->mval, &dist, &index, 1); 00859 00860 if (closest_pt != NULL) 00861 { 00862 if (sk_lastStrokePoint(stk)->type == PT_EXACT) 00863 { 00864 sketch->over.count = SK_OVERDRAW_LIMIT; 00865 } 00866 else 00867 { 00868 sketch->over.count++; 00869 } 00870 00871 sketch->over.end = index; 00872 } 00873 else 00874 { 00875 sketch->over.end = -1; 00876 } 00877 } 00878 } 00879 00880 /* return 1 on reverse needed */ 00881 static int sk_adjustIndexes(SK_Sketch *sketch, int *start, int *end) 00882 { 00883 int retval = 0; 00884 00885 *start = sketch->over.start; 00886 *end = sketch->over.end; 00887 00888 if (*start == -1) 00889 { 00890 *start = 0; 00891 } 00892 00893 if (*end == -1) 00894 { 00895 *end = sketch->over.target->nb_points - 1; 00896 } 00897 00898 if (*end < *start) 00899 { 00900 int tmp = *start; 00901 *start = *end; 00902 *end = tmp; 00903 retval = 1; 00904 } 00905 00906 return retval; 00907 } 00908 00909 static void sk_endOverdraw(SK_Sketch *sketch) 00910 { 00911 SK_Stroke *stk = sketch->active_stroke; 00912 00913 if (sk_hasOverdraw(sketch, NULL)) 00914 { 00915 int start; 00916 int end; 00917 00918 if (sk_adjustIndexes(sketch, &start, &end)) 00919 { 00920 sk_reverseStroke(stk); 00921 } 00922 00923 if (stk->nb_points > 1) 00924 { 00925 stk->points->type = sketch->over.target->points[start].type; 00926 sk_lastStrokePoint(stk)->type = sketch->over.target->points[end].type; 00927 } 00928 00929 sk_insertStrokePoints(sketch->over.target, stk->points, stk->nb_points, start, end); 00930 00931 sk_removeStroke(sketch, stk); 00932 00933 sk_resetOverdraw(sketch); 00934 } 00935 } 00936 00937 00938 static void sk_startStroke(SK_Sketch *sketch) 00939 { 00940 SK_Stroke *stk = sk_createStroke(); 00941 00942 BLI_addtail(&sketch->strokes, stk); 00943 sketch->active_stroke = stk; 00944 00945 sk_resetOverdraw(sketch); 00946 } 00947 00948 static void sk_endStroke(bContext *C, SK_Sketch *sketch) 00949 { 00950 ToolSettings *ts = CTX_data_tool_settings(C); 00951 sk_shrinkStrokeBuffer(sketch->active_stroke); 00952 00953 if (ts->bone_sketching & BONE_SKETCHING_ADJUST) 00954 { 00955 sk_endOverdraw(sketch); 00956 } 00957 00958 sketch->active_stroke = NULL; 00959 } 00960 00961 static void sk_updateDrawData(SK_DrawData *dd) 00962 { 00963 dd->type = PT_CONTINUOUS; 00964 00965 dd->previous_mval[0] = dd->mval[0]; 00966 dd->previous_mval[1] = dd->mval[1]; 00967 } 00968 00969 static float sk_distanceDepth(bContext *C, float p1[3], float p2[3]) 00970 { 00971 ARegion *ar = CTX_wm_region(C); 00972 RegionView3D *rv3d = ar->regiondata; 00973 float vec[3]; 00974 float distance; 00975 00976 sub_v3_v3v3(vec, p1, p2); 00977 00978 project_v3_v3v3(vec, vec, rv3d->viewinv[2]); 00979 00980 distance = len_v3(vec); 00981 00982 if (dot_v3v3(rv3d->viewinv[2], vec) > 0) 00983 { 00984 distance *= -1; 00985 } 00986 00987 return distance; 00988 } 00989 00990 static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float length, float distance) 00991 { 00992 ARegion *ar = CTX_wm_region(C); 00993 ScrArea *sa = CTX_wm_area(C); 00994 View3D *v3d = sa->spacedata.first; 00995 00996 float progress = 0; 00997 int i; 00998 00999 progress = len_v3v3(stk->points[start].p, stk->points[start - 1].p); 01000 01001 for (i = start; i <= end; i++) 01002 { 01003 float ray_start[3], ray_normal[3]; 01004 float delta = len_v3v3(stk->points[i].p, stk->points[i + 1].p); 01005 float pval[2]; 01006 01007 project_float(ar, stk->points[i].p, pval); 01008 ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal); 01009 01010 mul_v3_fl(ray_normal, distance * progress / length); 01011 add_v3_v3(stk->points[i].p, ray_normal); 01012 01013 progress += delta ; 01014 } 01015 } 01016 01017 static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_DrawData *dd) 01018 { 01019 ARegion *ar = CTX_wm_region(C); 01020 /* copied from grease pencil, need fixing */ 01021 SK_Point *last = sk_lastStrokePoint(stk); 01022 short cval[2]; 01023 float fp[3] = {0, 0, 0}; 01024 float dvec[3]; 01025 float mval_f[2]; 01026 01027 if (last != NULL) 01028 { 01029 VECCOPY(fp, last->p); 01030 } 01031 01032 initgrabz(ar->regiondata, fp[0], fp[1], fp[2]); 01033 01034 /* method taken from editview.c - mouse_cursor() */ 01035 project_short_noclip(ar, fp, cval); 01036 VECSUB2D(mval_f, cval, dd->mval); 01037 ED_view3d_win_to_delta(ar, mval_f, dvec); 01038 sub_v3_v3v3(vec, fp, dvec); 01039 } 01040 01041 static int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *UNUSED(sketch), SK_Stroke *stk, SK_DrawData *dd) 01042 { 01043 pt->type = dd->type; 01044 pt->mode = PT_PROJECT; 01045 sk_projectDrawPoint(C, pt->p, stk, dd); 01046 01047 return 1; 01048 } 01049 01050 static int sk_addStrokeDrawPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) 01051 { 01052 ARegion *ar = CTX_wm_region(C); 01053 RegionView3D *rv3d = ar->regiondata; 01054 SK_Point pt; 01055 01056 sk_initPoint(&pt, dd, rv3d->viewinv[2]); 01057 01058 sk_getStrokeDrawPoint(C, &pt, sketch, stk, dd); 01059 01060 sk_appendStrokePoint(stk, &pt); 01061 01062 return 1; 01063 } 01064 01065 static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) 01066 { 01067 ToolSettings *ts = CTX_data_tool_settings(C); 01068 int point_added = 0; 01069 01070 if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) 01071 { 01072 DepthPeel *p1, *p2; 01073 float *last_p = NULL; 01074 float dist = FLT_MAX; 01075 float p[3] = {0}; 01076 float size = 0; 01077 float mvalf[2]; 01078 01079 BLI_freelistN(&sketch->depth_peels); 01080 sketch->depth_peels.first = sketch->depth_peels.last = NULL; 01081 01082 mvalf[0]= dd->mval[0]; 01083 mvalf[1]= dd->mval[1]; 01084 peelObjectsContext(C, &sketch->depth_peels, mvalf); 01085 01086 if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) 01087 { 01088 last_p = stk->points[stk->nb_points - 1].p; 01089 } 01090 else if (LAST_SNAP_POINT_VALID) 01091 { 01092 last_p = LAST_SNAP_POINT; 01093 } 01094 01095 01096 for (p1 = sketch->depth_peels.first; p1; p1 = p1->next) 01097 { 01098 if (p1->flag == 0) 01099 { 01100 float vec[3]; 01101 float new_dist; 01102 float new_size = 0; 01103 01104 p2 = NULL; 01105 p1->flag = 1; 01106 01107 /* if peeling objects, take the first and last from each object */ 01108 if (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) 01109 { 01110 DepthPeel *peel; 01111 for (peel = p1->next; peel; peel = peel->next) 01112 { 01113 if (peel->ob == p1->ob) 01114 { 01115 peel->flag = 1; 01116 p2 = peel; 01117 } 01118 } 01119 } 01120 /* otherwise, pair first with second and so on */ 01121 else 01122 { 01123 for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) 01124 { 01125 /* nothing to do here */ 01126 } 01127 } 01128 01129 if (p2) 01130 { 01131 p2->flag = 1; 01132 01133 add_v3_v3v3(vec, p1->p, p2->p); 01134 mul_v3_fl(vec, 0.5f); 01135 new_size = len_v3v3(p1->p, p2->p); 01136 } 01137 else 01138 { 01139 VECCOPY(vec, p1->p); 01140 } 01141 01142 if (last_p == NULL) 01143 { 01144 VECCOPY(p, vec); 01145 size = new_size; 01146 dist = 0; 01147 break; 01148 } 01149 01150 new_dist = len_v3v3(last_p, vec); 01151 01152 if (new_dist < dist) 01153 { 01154 VECCOPY(p, vec); 01155 dist = new_dist; 01156 size = new_size; 01157 } 01158 } 01159 } 01160 01161 if (dist != FLT_MAX) 01162 { 01163 pt->type = dd->type; 01164 pt->mode = PT_SNAP; 01165 pt->size = size / 2; 01166 VECCOPY(pt->p, p); 01167 01168 point_added = 1; 01169 } 01170 01171 //BLI_freelistN(&depth_peels); 01172 } 01173 else 01174 { 01175 SK_Stroke *snap_stk; 01176 float vec[3]; 01177 float no[3]; 01178 float mval[2]; 01179 int found = 0; 01180 int dist = SNAP_MIN_DISTANCE; // Use a user defined value here 01181 01182 /* snap to strokes */ 01183 // if (ts->snap_mode == SCE_SNAP_MODE_VERTEX) /* snap all the time to strokes */ 01184 for (snap_stk = sketch->strokes.first; snap_stk; snap_stk = snap_stk->next) 01185 { 01186 SK_Point *spt = NULL; 01187 if (snap_stk == stk) 01188 { 01189 spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 0); 01190 } 01191 else 01192 { 01193 spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 1); 01194 } 01195 01196 if (spt != NULL) 01197 { 01198 VECCOPY(pt->p, spt->p); 01199 point_added = 1; 01200 } 01201 } 01202 01203 mval[0] = dd->mval[0]; 01204 mval[1] = dd->mval[1]; 01205 01206 /* try to snap to closer object */ 01207 found = snapObjectsContext(C, mval, &dist, vec, no, SNAP_NOT_SELECTED); 01208 if (found == 1) 01209 { 01210 pt->type = dd->type; 01211 pt->mode = PT_SNAP; 01212 VECCOPY(pt->p, vec); 01213 01214 point_added = 1; 01215 } 01216 } 01217 01218 return point_added; 01219 } 01220 01221 static int sk_addStrokeSnapPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) 01222 { 01223 int point_added; 01224 ARegion *ar = CTX_wm_region(C); 01225 RegionView3D *rv3d = ar->regiondata; 01226 SK_Point pt; 01227 01228 sk_initPoint(&pt, dd, rv3d->viewinv[2]); 01229 01230 point_added = sk_getStrokeSnapPoint(C, &pt, sketch, stk, dd); 01231 01232 if (point_added) 01233 { 01234 float final_p[3]; 01235 float length, distance; 01236 int total; 01237 int i; 01238 01239 VECCOPY(final_p, pt.p); 01240 01241 sk_projectDrawPoint(C, pt.p, stk, dd); 01242 sk_appendStrokePoint(stk, &pt); 01243 01244 /* update all previous point to give smooth Z progresion */ 01245 total = 0; 01246 length = 0; 01247 for (i = stk->nb_points - 2; i > 0; i--) 01248 { 01249 length += len_v3v3(stk->points[i].p, stk->points[i + 1].p); 01250 total++; 01251 if (stk->points[i].mode == PT_SNAP || stk->points[i].type == PT_EXACT) 01252 { 01253 break; 01254 } 01255 } 01256 01257 if (total > 1) 01258 { 01259 distance = sk_distanceDepth(C, final_p, stk->points[i].p); 01260 01261 sk_interpolateDepth(C, stk, i + 1, stk->nb_points - 2, length, distance); 01262 } 01263 01264 VECCOPY(stk->points[stk->nb_points - 1].p, final_p); 01265 01266 point_added = 1; 01267 } 01268 01269 return point_added; 01270 } 01271 01272 static void sk_addStrokePoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap) 01273 { 01274 ToolSettings *ts = CTX_data_tool_settings(C); 01275 int point_added = 0; 01276 01277 if (snap) 01278 { 01279 point_added = sk_addStrokeSnapPoint(C, sketch, stk, dd); 01280 } 01281 01282 if (point_added == 0) 01283 { 01284 point_added = sk_addStrokeDrawPoint(C, sketch, stk, dd); 01285 } 01286 01287 if (stk == sketch->active_stroke && ts->bone_sketching & BONE_SKETCHING_ADJUST) 01288 { 01289 sk_updateOverdraw(C, sketch, stk, dd); 01290 } 01291 } 01292 01293 static void sk_getStrokePoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap) 01294 { 01295 int point_added = 0; 01296 01297 if (snap) 01298 { 01299 point_added = sk_getStrokeSnapPoint(C, pt, sketch, stk, dd); 01300 LAST_SNAP_POINT_VALID = 1; 01301 VECCOPY(LAST_SNAP_POINT, pt->p); 01302 } 01303 else 01304 { 01305 LAST_SNAP_POINT_VALID = 0; 01306 } 01307 01308 if (point_added == 0) 01309 { 01310 point_added = sk_getStrokeDrawPoint(C, pt, sketch, stk, dd); 01311 } 01312 } 01313 01314 /********************************************/ 01315 01316 static void* headPoint(void *arg); 01317 static void* tailPoint(void *arg); 01318 static void* nextPoint(void *arg); 01319 static void* nextNPoint(void *arg, int n); 01320 static void* peekPoint(void *arg, int n); 01321 static void* previousPoint(void *arg); 01322 static int iteratorStopped(void *arg); 01323 01324 static void initIteratorFct(SK_StrokeIterator *iter) 01325 { 01326 iter->head = headPoint; 01327 iter->tail = tailPoint; 01328 iter->peek = peekPoint; 01329 iter->next = nextPoint; 01330 iter->nextN = nextNPoint; 01331 iter->previous = previousPoint; 01332 iter->stopped = iteratorStopped; 01333 } 01334 01335 static SK_Point* setIteratorValues(SK_StrokeIterator *iter, int index) 01336 { 01337 SK_Point *pt = NULL; 01338 01339 if (index >= 0 && index < iter->length) 01340 { 01341 pt = &(iter->stroke->points[iter->start + (iter->stride * index)]); 01342 iter->p = pt->p; 01343 iter->no = pt->no; 01344 iter->size = pt->size; 01345 } 01346 else 01347 { 01348 iter->p = NULL; 01349 iter->no = NULL; 01350 iter->size = 0; 01351 } 01352 01353 return pt; 01354 } 01355 01356 void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end) 01357 { 01358 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01359 01360 initIteratorFct(iter); 01361 iter->stroke = stk; 01362 01363 if (start < end) 01364 { 01365 iter->start = start + 1; 01366 iter->end = end - 1; 01367 iter->stride = 1; 01368 } 01369 else 01370 { 01371 iter->start = start - 1; 01372 iter->end = end + 1; 01373 iter->stride = -1; 01374 } 01375 01376 iter->length = iter->stride * (iter->end - iter->start + 1); 01377 01378 iter->index = -1; 01379 } 01380 01381 01382 static void* headPoint(void *arg) 01383 { 01384 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01385 SK_Point *result = NULL; 01386 01387 result = &(iter->stroke->points[iter->start - iter->stride]); 01388 iter->p = result->p; 01389 iter->no = result->no; 01390 iter->size = result->size; 01391 01392 return result; 01393 } 01394 01395 static void* tailPoint(void *arg) 01396 { 01397 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01398 SK_Point *result = NULL; 01399 01400 result = &(iter->stroke->points[iter->end + iter->stride]); 01401 iter->p = result->p; 01402 iter->no = result->no; 01403 iter->size = result->size; 01404 01405 return result; 01406 } 01407 01408 static void* nextPoint(void *arg) 01409 { 01410 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01411 SK_Point *result = NULL; 01412 01413 iter->index++; 01414 if (iter->index < iter->length) 01415 { 01416 result = setIteratorValues(iter, iter->index); 01417 } 01418 01419 return result; 01420 } 01421 01422 static void* nextNPoint(void *arg, int n) 01423 { 01424 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01425 SK_Point *result = NULL; 01426 01427 iter->index += n; 01428 01429 /* check if passed end */ 01430 if (iter->index < iter->length) 01431 { 01432 result = setIteratorValues(iter, iter->index); 01433 } 01434 01435 return result; 01436 } 01437 01438 static void* peekPoint(void *arg, int n) 01439 { 01440 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01441 SK_Point *result = NULL; 01442 int index = iter->index + n; 01443 01444 /* check if passed end */ 01445 if (index < iter->length) 01446 { 01447 result = setIteratorValues(iter, index); 01448 } 01449 01450 return result; 01451 } 01452 01453 static void* previousPoint(void *arg) 01454 { 01455 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01456 SK_Point *result = NULL; 01457 01458 if (iter->index > 0) 01459 { 01460 iter->index--; 01461 result = setIteratorValues(iter, iter->index); 01462 } 01463 01464 return result; 01465 } 01466 01467 static int iteratorStopped(void *arg) 01468 { 01469 SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; 01470 01471 if (iter->index >= iter->length) 01472 { 01473 return 1; 01474 } 01475 else 01476 { 01477 return 0; 01478 } 01479 } 01480 01481 static void sk_convertStroke(bContext *C, SK_Stroke *stk) 01482 { 01483 Object *obedit = CTX_data_edit_object(C); 01484 ToolSettings *ts = CTX_data_tool_settings(C); 01485 bArmature *arm = obedit->data; 01486 SK_Point *head; 01487 EditBone *parent = NULL; 01488 float invmat[4][4]; /* move in caller function */ 01489 float tmat[3][3]; 01490 int head_index = 0; 01491 int i; 01492 01493 head = NULL; 01494 01495 invert_m4_m4(invmat, obedit->obmat); 01496 01497 copy_m3_m4(tmat, obedit->obmat); 01498 transpose_m3(tmat); 01499 01500 for (i = 0; i < stk->nb_points; i++) 01501 { 01502 SK_Point *pt = stk->points + i; 01503 01504 if (pt->type == PT_EXACT) 01505 { 01506 if (head == NULL) 01507 { 01508 head_index = i; 01509 head = pt; 01510 } 01511 else 01512 { 01513 EditBone *bone = NULL; 01514 EditBone *new_parent; 01515 01516 if (i - head_index > 1) 01517 { 01518 SK_StrokeIterator sk_iter; 01519 BArcIterator *iter = (BArcIterator*)&sk_iter; 01520 01521 initStrokeIterator(iter, stk, head_index, i); 01522 01523 if (ts->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) 01524 { 01525 bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision); 01526 } 01527 else if (ts->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) 01528 { 01529 bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision); 01530 } 01531 else if (ts->bone_sketching_convert == SK_CONVERT_CUT_FIXED) 01532 { 01533 bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextFixedSubdivision); 01534 } 01535 } 01536 01537 if (bone == NULL) 01538 { 01539 bone = ED_armature_edit_bone_add(arm, "Bone"); 01540 01541 VECCOPY(bone->head, head->p); 01542 VECCOPY(bone->tail, pt->p); 01543 01544 mul_m4_v3(invmat, bone->head); 01545 mul_m4_v3(invmat, bone->tail); 01546 setBoneRollFromNormal(bone, head->no, invmat, tmat); 01547 } 01548 01549 new_parent = bone; 01550 bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; 01551 01552 /* move to end of chain */ 01553 while (bone->parent != NULL) 01554 { 01555 bone = bone->parent; 01556 bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; 01557 } 01558 01559 if (parent != NULL) 01560 { 01561 bone->parent = parent; 01562 bone->flag |= BONE_CONNECTED; 01563 } 01564 01565 parent = new_parent; 01566 head_index = i; 01567 head = pt; 01568 } 01569 } 01570 } 01571 } 01572 01573 static void sk_convert(bContext *C, SK_Sketch *sketch) 01574 { 01575 ToolSettings *ts = CTX_data_tool_settings(C); 01576 SK_Stroke *stk; 01577 01578 for (stk = sketch->strokes.first; stk; stk = stk->next) 01579 { 01580 if (stk->selected == 1) 01581 { 01582 if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) 01583 { 01584 sk_retargetStroke(C, stk); 01585 } 01586 else 01587 { 01588 sk_convertStroke(C, stk); 01589 } 01590 // XXX 01591 // allqueue(REDRAWBUTSEDIT, 0); 01592 } 01593 } 01594 } 01595 /******************* GESTURE *************************/ 01596 01597 01598 /* returns the number of self intersections */ 01599 static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gesture) 01600 { 01601 ARegion *ar = CTX_wm_region(C); 01602 int added = 0; 01603 int s_i; 01604 01605 for (s_i = 0; s_i < gesture->nb_points - 1; s_i++) 01606 { 01607 float s_p1[3] = {0, 0, 0}; 01608 float s_p2[3] = {0, 0, 0}; 01609 int g_i; 01610 01611 project_float(ar, gesture->points[s_i].p, s_p1); 01612 project_float(ar, gesture->points[s_i + 1].p, s_p2); 01613 01614 /* start checking from second next, because two consecutive cannot intersect */ 01615 for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++) 01616 { 01617 float g_p1[3] = {0, 0, 0}; 01618 float g_p2[3] = {0, 0, 0}; 01619 float vi[3]; 01620 float lambda; 01621 01622 project_float(ar, gesture->points[g_i].p, g_p1); 01623 project_float(ar, gesture->points[g_i + 1].p, g_p2); 01624 01625 if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) 01626 { 01627 SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); 01628 01629 isect->gesture_index = g_i; 01630 isect->before = s_i; 01631 isect->after = s_i + 1; 01632 isect->stroke = gesture; 01633 01634 sub_v3_v3v3(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p); 01635 mul_v3_fl(isect->p, lambda); 01636 add_v3_v3(isect->p, gesture->points[s_i].p); 01637 01638 BLI_addtail(list, isect); 01639 01640 added++; 01641 } 01642 } 01643 } 01644 01645 return added; 01646 } 01647 01648 static int cmpIntersections(void *i1, void *i2) 01649 { 01650 SK_Intersection *isect1 = i1, *isect2 = i2; 01651 01652 if (isect1->stroke == isect2->stroke) 01653 { 01654 if (isect1->before < isect2->before) 01655 { 01656 return -1; 01657 } 01658 else if (isect1->before > isect2->before) 01659 { 01660 return 1; 01661 } 01662 else 01663 { 01664 if (isect1->lambda < isect2->lambda) 01665 { 01666 return -1; 01667 } 01668 else if (isect1->lambda > isect2->lambda) 01669 { 01670 return 1; 01671 } 01672 } 01673 } 01674 01675 return 0; 01676 } 01677 01678 01679 /* returns the maximum number of intersections per stroke */ 01680 static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture) 01681 { 01682 ARegion *ar = CTX_wm_region(C); 01683 ScrArea *sa = CTX_wm_area(C); 01684 View3D *v3d = sa->spacedata.first; 01685 SK_Stroke *stk; 01686 int added = 0; 01687 01688 for (stk = sketch->strokes.first; stk; stk = stk->next) 01689 { 01690 int s_added = 0; 01691 int s_i; 01692 01693 for (s_i = 0; s_i < stk->nb_points - 1; s_i++) 01694 { 01695 float s_p1[3] = {0, 0, 0}; 01696 float s_p2[3] = {0, 0, 0}; 01697 int g_i; 01698 01699 project_float(ar, stk->points[s_i].p, s_p1); 01700 project_float(ar, stk->points[s_i + 1].p, s_p2); 01701 01702 for (g_i = 0; g_i < gesture->nb_points - 1; g_i++) 01703 { 01704 float g_p1[3] = {0, 0, 0}; 01705 float g_p2[3] = {0, 0, 0}; 01706 float vi[3]; 01707 float lambda; 01708 01709 project_float(ar, gesture->points[g_i].p, g_p1); 01710 project_float(ar, gesture->points[g_i + 1].p, g_p2); 01711 01712 if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) 01713 { 01714 SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); 01715 float ray_start[3], ray_end[3]; 01716 float mval[2]; 01717 01718 isect->gesture_index = g_i; 01719 isect->before = s_i; 01720 isect->after = s_i + 1; 01721 isect->stroke = stk; 01722 isect->lambda = lambda; 01723 01724 mval[0] = vi[0]; 01725 mval[1] = vi[1]; 01726 ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end); 01727 01728 isect_line_line_v3( stk->points[s_i].p, 01729 stk->points[s_i + 1].p, 01730 ray_start, 01731 ray_end, 01732 isect->p, 01733 vi); 01734 01735 BLI_addtail(list, isect); 01736 01737 s_added++; 01738 } 01739 } 01740 } 01741 01742 added = MAX2(s_added, added); 01743 } 01744 01745 BLI_sortlist(list, cmpIntersections); 01746 01747 return added; 01748 } 01749 01750 static int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture) 01751 { 01752 SK_StrokeIterator sk_iter; 01753 BArcIterator *iter = (BArcIterator*)&sk_iter; 01754 01755 float CORRELATION_THRESHOLD = 0.99f; 01756 float *vec; 01757 int i, j; 01758 01759 sk_appendStrokePoint(segments, &gesture->points[0]); 01760 vec = segments->points[segments->nb_points - 1].p; 01761 01762 initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1); 01763 01764 for (i = 1, j = 0; i < gesture->nb_points; i++) 01765 { 01766 float n[3]; 01767 01768 /* Calculate normal */ 01769 sub_v3_v3v3(n, gesture->points[i].p, vec); 01770 01771 if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD) 01772 { 01773 j = i - 1; 01774 sk_appendStrokePoint(segments, &gesture->points[j]); 01775 vec = segments->points[segments->nb_points - 1].p; 01776 segments->points[segments->nb_points - 1].type = PT_EXACT; 01777 } 01778 } 01779 01780 sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]); 01781 01782 return segments->nb_points - 1; 01783 } 01784 01785 int sk_detectCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01786 { 01787 if (gest->nb_segments == 1 && gest->nb_intersections == 1) 01788 { 01789 return 1; 01790 } 01791 01792 return 0; 01793 } 01794 01795 void sk_applyCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01796 { 01797 SK_Intersection *isect; 01798 01799 for (isect = gest->intersections.first; isect; isect = isect->next) 01800 { 01801 SK_Point pt; 01802 01803 pt.type = PT_EXACT; 01804 pt.mode = PT_PROJECT; /* take mode from neighbouring points */ 01805 VECCOPY(pt.p, isect->p); 01806 VECCOPY(pt.no, isect->stroke->points[isect->before].no); 01807 01808 sk_insertStrokePoint(isect->stroke, &pt, isect->after); 01809 } 01810 } 01811 01812 int sk_detectTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01813 { 01814 if (gest->nb_segments == 2 && gest->nb_intersections == 1 && gest->nb_self_intersections == 0) 01815 { 01816 float s1[3], s2[3]; 01817 float angle; 01818 01819 sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p); 01820 sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p); 01821 01822 angle = RAD2DEG(angle_v2v2(s1, s2)); 01823 01824 if (angle > 60 && angle < 120) 01825 { 01826 return 1; 01827 } 01828 } 01829 01830 return 0; 01831 } 01832 01833 void sk_applyTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01834 { 01835 SK_Intersection *isect; 01836 float trim_dir[3]; 01837 01838 sub_v3_v3v3(trim_dir, gest->segments->points[2].p, gest->segments->points[1].p); 01839 01840 for (isect = gest->intersections.first; isect; isect = isect->next) 01841 { 01842 SK_Point pt; 01843 float stroke_dir[3]; 01844 01845 pt.type = PT_EXACT; 01846 pt.mode = PT_PROJECT; /* take mode from neighbouring points */ 01847 VECCOPY(pt.p, isect->p); 01848 VECCOPY(pt.no, isect->stroke->points[isect->before].no); 01849 01850 sub_v3_v3v3(stroke_dir, isect->stroke->points[isect->after].p, isect->stroke->points[isect->before].p); 01851 01852 /* same direction, trim end */ 01853 if (dot_v3v3(stroke_dir, trim_dir) > 0) 01854 { 01855 sk_replaceStrokePoint(isect->stroke, &pt, isect->after); 01856 sk_trimStroke(isect->stroke, 0, isect->after); 01857 } 01858 /* else, trim start */ 01859 else 01860 { 01861 sk_replaceStrokePoint(isect->stroke, &pt, isect->before); 01862 sk_trimStroke(isect->stroke, isect->before, isect->stroke->nb_points - 1); 01863 } 01864 01865 } 01866 } 01867 01868 int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01869 { 01870 if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1) 01871 { 01872 SK_Intersection *isect, *self_isect; 01873 01874 /* get the the last intersection of the first pair */ 01875 for( isect = gest->intersections.first; isect; isect = isect->next ) 01876 { 01877 if (isect->stroke == isect->next->stroke) 01878 { 01879 isect = isect->next; 01880 break; 01881 } 01882 } 01883 01884 self_isect = gest->self_intersections.first; 01885 01886 if (isect && isect->gesture_index < self_isect->gesture_index) 01887 { 01888 return 1; 01889 } 01890 } 01891 01892 return 0; 01893 } 01894 01895 void sk_applyCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01896 { 01897 SK_Intersection *isect; 01898 int command = 1; 01899 01900 // XXX 01901 // command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3"); 01902 if(command < 1) return; 01903 01904 for (isect = gest->intersections.first; isect; isect = isect->next) 01905 { 01906 SK_Intersection *i2; 01907 01908 i2 = isect->next; 01909 01910 if (i2 && i2->stroke == isect->stroke) 01911 { 01912 switch (command) 01913 { 01914 case 1: 01915 sk_flattenStroke(isect->stroke, isect->before, i2->after); 01916 break; 01917 case 2: 01918 sk_straightenStroke(isect->stroke, isect->before, i2->after, isect->p, i2->p); 01919 break; 01920 case 3: 01921 sk_polygonizeStroke(isect->stroke, isect->before, i2->after); 01922 break; 01923 } 01924 01925 isect = i2; 01926 } 01927 } 01928 } 01929 01930 int sk_detectDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01931 { 01932 if (gest->nb_segments == 2 && gest->nb_intersections == 2) 01933 { 01934 float s1[3], s2[3]; 01935 float angle; 01936 01937 sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p); 01938 sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p); 01939 01940 angle = RAD2DEG(angle_v2v2(s1, s2)); 01941 01942 if (angle > 120) 01943 { 01944 return 1; 01945 } 01946 } 01947 01948 return 0; 01949 } 01950 01951 void sk_applyDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *sketch) 01952 { 01953 SK_Intersection *isect; 01954 01955 for (isect = gest->intersections.first; isect; isect = isect->next) 01956 { 01957 /* only delete strokes that are crossed twice */ 01958 if (isect->next && isect->next->stroke == isect->stroke) 01959 { 01960 isect = isect->next; 01961 01962 sk_removeStroke(sketch, isect->stroke); 01963 } 01964 } 01965 } 01966 01967 int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 01968 { 01969 ARegion *ar = CTX_wm_region(C); 01970 if (gest->nb_segments > 2 && gest->nb_intersections == 2) 01971 { 01972 short start_val[2], end_val[2]; 01973 short dist; 01974 01975 project_short_noclip(ar, gest->stk->points[0].p, start_val); 01976 project_short_noclip(ar, sk_lastStrokePoint(gest->stk)->p, end_val); 01977 01978 dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1])); 01979 01980 /* if gesture is a circle */ 01981 if ( dist <= 20 ) 01982 { 01983 SK_Intersection *isect; 01984 01985 /* check if it circled around an exact point */ 01986 for (isect = gest->intersections.first; isect; isect = isect->next) 01987 { 01988 /* only delete strokes that are crossed twice */ 01989 if (isect->next && isect->next->stroke == isect->stroke) 01990 { 01991 int start_index, end_index; 01992 int i; 01993 01994 start_index = MIN2(isect->after, isect->next->after); 01995 end_index = MAX2(isect->before, isect->next->before); 01996 01997 for (i = start_index; i <= end_index; i++) 01998 { 01999 if (isect->stroke->points[i].type == PT_EXACT) 02000 { 02001 return 1; /* at least one exact point found, stop detect here */ 02002 } 02003 } 02004 02005 /* skip next */ 02006 isect = isect->next; 02007 } 02008 } 02009 } 02010 } 02011 02012 return 0; 02013 } 02014 02015 void sk_applyMergeGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 02016 { 02017 SK_Intersection *isect; 02018 02019 /* check if it circled around an exact point */ 02020 for (isect = gest->intersections.first; isect; isect = isect->next) 02021 { 02022 /* only merge strokes that are crossed twice */ 02023 if (isect->next && isect->next->stroke == isect->stroke) 02024 { 02025 int start_index, end_index; 02026 int i; 02027 02028 start_index = MIN2(isect->after, isect->next->after); 02029 end_index = MAX2(isect->before, isect->next->before); 02030 02031 for (i = start_index; i <= end_index; i++) 02032 { 02033 /* if exact, switch to continuous */ 02034 if (isect->stroke->points[i].type == PT_EXACT) 02035 { 02036 isect->stroke->points[i].type = PT_CONTINUOUS; 02037 } 02038 } 02039 02040 /* skip next */ 02041 isect = isect->next; 02042 } 02043 } 02044 } 02045 02046 int sk_detectReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 02047 { 02048 if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 0) 02049 { 02050 SK_Intersection *isect; 02051 02052 /* check if it circled around an exact point */ 02053 for (isect = gest->intersections.first; isect; isect = isect->next) 02054 { 02055 /* only delete strokes that are crossed twice */ 02056 if (isect->next && isect->next->stroke == isect->stroke) 02057 { 02058 float start_v[3], end_v[3]; 02059 float angle; 02060 02061 if (isect->gesture_index < isect->next->gesture_index) 02062 { 02063 sub_v3_v3v3(start_v, isect->p, gest->stk->points[0].p); 02064 sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->next->p); 02065 } 02066 else 02067 { 02068 sub_v3_v3v3(start_v, isect->next->p, gest->stk->points[0].p); 02069 sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p); 02070 } 02071 02072 angle = RAD2DEG(angle_v2v2(start_v, end_v)); 02073 02074 if (angle > 120) 02075 { 02076 return 1; 02077 } 02078 02079 /* skip next */ 02080 isect = isect->next; 02081 } 02082 } 02083 } 02084 02085 return 0; 02086 } 02087 02088 void sk_applyReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 02089 { 02090 SK_Intersection *isect; 02091 02092 for (isect = gest->intersections.first; isect; isect = isect->next) 02093 { 02094 /* only reverse strokes that are crossed twice */ 02095 if (isect->next && isect->next->stroke == isect->stroke) 02096 { 02097 sk_reverseStroke(isect->stroke); 02098 02099 /* skip next */ 02100 isect = isect->next; 02101 } 02102 } 02103 } 02104 02105 int sk_detectConvertGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch)) 02106 { 02107 if (gest->nb_segments == 3 && gest->nb_self_intersections == 1) 02108 { 02109 return 1; 02110 } 02111 return 0; 02112 } 02113 02114 void sk_applyConvertGesture(bContext *C, SK_Gesture *UNUSED(gest), SK_Sketch *sketch) 02115 { 02116 sk_convert(C, sketch); 02117 } 02118 02119 static void sk_initGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) 02120 { 02121 gest->intersections.first = gest->intersections.last = NULL; 02122 gest->self_intersections.first = gest->self_intersections.last = NULL; 02123 02124 gest->segments = sk_createStroke(); 02125 gest->stk = sketch->gesture; 02126 02127 gest->nb_self_intersections = sk_getSelfIntersections(C, &gest->self_intersections, gest->stk); 02128 gest->nb_intersections = sk_getIntersections(C, &gest->intersections, sketch, gest->stk); 02129 gest->nb_segments = sk_getSegments(gest->segments, gest->stk); 02130 } 02131 02132 static void sk_freeGesture(SK_Gesture *gest) 02133 { 02134 sk_freeStroke(gest->segments); 02135 BLI_freelistN(&gest->intersections); 02136 BLI_freelistN(&gest->self_intersections); 02137 } 02138 02139 static void sk_applyGesture(bContext *C, SK_Sketch *sketch) 02140 { 02141 SK_Gesture gest; 02142 SK_GestureAction *act; 02143 02144 sk_initGesture(C, &gest, sketch); 02145 02146 /* detect and apply */ 02147 for (act = GESTURE_ACTIONS; act->apply != NULL; act++) 02148 { 02149 if (act->detect(C, &gest, sketch)) 02150 { 02151 act->apply(C, &gest, sketch); 02152 break; 02153 } 02154 } 02155 02156 sk_freeGesture(&gest); 02157 } 02158 02159 /********************************************/ 02160 02161 02162 static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], int extend) 02163 { 02164 ViewContext vc; 02165 rcti rect; 02166 unsigned int buffer[MAXPICKBUF]; 02167 short hits; 02168 02169 view3d_set_viewcontext(C, &vc); 02170 02171 rect.xmin= mval[0]-5; 02172 rect.xmax= mval[0]+5; 02173 rect.ymin= mval[1]-5; 02174 rect.ymax= mval[1]+5; 02175 02176 hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); 02177 02178 if (hits>0) 02179 { 02180 int besthitresult = -1; 02181 02182 if(hits == 1) { 02183 besthitresult = buffer[3]; 02184 } 02185 else { 02186 besthitresult = buffer[3]; 02187 /* loop and get best hit */ 02188 } 02189 02190 if (besthitresult > 0) 02191 { 02192 SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1); 02193 02194 if (extend == 0) 02195 { 02196 sk_selectAllSketch(sketch, -1); 02197 02198 selected_stk->selected = 1; 02199 } 02200 else 02201 { 02202 selected_stk->selected ^= 1; 02203 } 02204 02205 02206 } 02207 return 1; 02208 } 02209 02210 return 0; 02211 } 02212 02213 #if 0 /* UNUSED 2.5 */ 02214 static void sk_queueRedrawSketch(SK_Sketch *sketch) 02215 { 02216 if (sketch->active_stroke != NULL) 02217 { 02218 SK_Point *last = sk_lastStrokePoint(sketch->active_stroke); 02219 02220 if (last != NULL) 02221 { 02222 // XXX 02223 // allqueue(REDRAWVIEW3D, 0); 02224 } 02225 } 02226 } 02227 #endif 02228 02229 static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, int with_names) 02230 { 02231 ToolSettings *ts= scene->toolsettings; 02232 SK_Stroke *stk; 02233 02234 glClear(GL_DEPTH_BUFFER_BIT); 02235 glEnable(GL_DEPTH_TEST); 02236 02237 if (with_names) 02238 { 02239 int id; 02240 for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next) 02241 { 02242 sk_drawStroke(stk, id, NULL, -1, -1); 02243 } 02244 02245 glLoadName(-1); 02246 } 02247 else 02248 { 02249 float selected_rgb[3] = {1, 0, 0}; 02250 float unselected_rgb[3] = {1, 0.5, 0}; 02251 02252 for (stk = sketch->strokes.first; stk; stk = stk->next) 02253 { 02254 int start = -1; 02255 int end = -1; 02256 02257 if (sk_hasOverdraw(sketch, stk)) 02258 { 02259 sk_adjustIndexes(sketch, &start, &end); 02260 } 02261 02262 sk_drawStroke(stk, -1, (stk->selected==1?selected_rgb:unselected_rgb), start, end); 02263 02264 if (stk->selected == 1) 02265 { 02266 sk_drawStrokeSubdivision(ts, stk); 02267 } 02268 } 02269 02270 if (sketch->active_stroke != NULL) 02271 { 02272 SK_Point *last = sk_lastStrokePoint(sketch->active_stroke); 02273 02274 if (ts->bone_sketching & BONE_SKETCHING_QUICK) 02275 { 02276 sk_drawStrokeSubdivision(ts, sketch->active_stroke); 02277 } 02278 02279 if (last != NULL) 02280 { 02281 GLUquadric *quad = gluNewQuadric(); 02282 gluQuadricNormals(quad, GLU_SMOOTH); 02283 02284 glPushMatrix(); 02285 02286 glEnable(GL_BLEND); 02287 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 02288 02289 switch (sketch->next_point.mode) 02290 { 02291 case PT_SNAP: 02292 glColor3f(0, 1, 0); 02293 break; 02294 case PT_PROJECT: 02295 glColor3f(0, 0, 0); 02296 break; 02297 } 02298 02299 sk_drawPoint(quad, &sketch->next_point, 0.1); 02300 02301 glColor4f(selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3); 02302 02303 sk_drawEdge(quad, last, &sketch->next_point, 0.1); 02304 02305 glDisable(GL_BLEND); 02306 02307 glPopMatrix(); 02308 02309 gluDeleteQuadric(quad); 02310 } 02311 } 02312 } 02313 02314 #if 0 02315 if (sketch->depth_peels.first != NULL) 02316 { 02317 float colors[8][3] = { 02318 {1, 0, 0}, 02319 {0, 1, 0}, 02320 {0, 0, 1}, 02321 {1, 1, 0}, 02322 {1, 0, 1}, 02323 {0, 1, 1}, 02324 {1, 1, 1}, 02325 {0, 0, 0} 02326 }; 02327 DepthPeel *p; 02328 GLUquadric *quad = gluNewQuadric(); 02329 gluQuadricNormals(quad, GLU_SMOOTH); 02330 02331 for (p = sketch->depth_peels.first; p; p = p->next) 02332 { 02333 int index = GET_INT_FROM_POINTER(p->ob); 02334 index = (index >> 5) & 7; 02335 02336 glColor3fv(colors[index]); 02337 glPushMatrix(); 02338 glTranslatef(p->p[0], p->p[1], p->p[2]); 02339 gluSphere(quad, 0.02, 8, 8); 02340 glPopMatrix(); 02341 } 02342 02343 gluDeleteQuadric(quad); 02344 } 02345 #endif 02346 02347 glDisable(GL_DEPTH_TEST); 02348 02349 /* only draw gesture in active area */ 02350 if (sketch->gesture != NULL /*&& area_is_active_area(G.vd->area)*/) 02351 { 02352 float gesture_rgb[3] = {0, 0.5, 1}; 02353 sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1); 02354 } 02355 } 02356 02357 static int sk_finish_stroke(bContext *C, SK_Sketch *sketch) 02358 { 02359 ToolSettings *ts = CTX_data_tool_settings(C); 02360 02361 if (sketch->active_stroke != NULL) 02362 { 02363 SK_Stroke *stk = sketch->active_stroke; 02364 02365 sk_endStroke(C, sketch); 02366 02367 if (ts->bone_sketching & BONE_SKETCHING_QUICK) 02368 { 02369 if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) 02370 { 02371 sk_retargetStroke(C, stk); 02372 } 02373 else 02374 { 02375 sk_convertStroke(C, stk); 02376 } 02377 // XXX 02378 // BIF_undo_push("Convert Sketch"); 02379 sk_removeStroke(sketch, stk); 02380 // XXX 02381 // allqueue(REDRAWBUTSEDIT, 0); 02382 } 02383 02384 // XXX 02385 // allqueue(REDRAWVIEW3D, 0); 02386 return 1; 02387 } 02388 02389 return 0; 02390 } 02391 02392 static void sk_start_draw_stroke(SK_Sketch *sketch) 02393 { 02394 if (sketch->active_stroke == NULL) 02395 { 02396 sk_startStroke(sketch); 02397 sk_selectAllSketch(sketch, -1); 02398 02399 sketch->active_stroke->selected = 1; 02400 } 02401 } 02402 02403 static void sk_start_draw_gesture(SK_Sketch *sketch) 02404 { 02405 sketch->gesture = sk_createStroke(); 02406 } 02407 02408 static int sk_draw_stroke(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap) 02409 { 02410 if (sk_stroke_filtermval(dd)) 02411 { 02412 sk_addStrokePoint(C, sketch, stk, dd, snap); 02413 sk_updateDrawData(dd); 02414 sk_updateNextPoint(sketch, stk); 02415 02416 return 1; 02417 } 02418 02419 return 0; 02420 } 02421 02422 static int ValidSketchViewContext(ViewContext *vc) 02423 { 02424 Object *obedit = vc->obedit; 02425 Scene *scene= vc->scene; 02426 02427 if (obedit && 02428 obedit->type == OB_ARMATURE && 02429 scene->toolsettings->bone_sketching & BONE_SKETCHING) 02430 { 02431 return 1; 02432 } 02433 else 02434 { 02435 return 0; 02436 } 02437 } 02438 02439 int BDR_drawSketchNames(ViewContext *vc) 02440 { 02441 if (ValidSketchViewContext(vc)) 02442 { 02443 SK_Sketch *sketch = viewcontextSketch(vc, 0); 02444 if (sketch) 02445 { 02446 sk_drawSketch(vc->scene, vc->v3d, sketch, 1); 02447 return 1; 02448 } 02449 } 02450 02451 return 0; 02452 } 02453 02454 void BDR_drawSketch(const bContext *C) 02455 { 02456 if (ED_operator_sketch_mode(C)) 02457 { 02458 SK_Sketch *sketch = contextSketch(C, 0); 02459 if (sketch) 02460 { 02461 sk_drawSketch(CTX_data_scene(C), CTX_wm_view3d(C), sketch, 0); 02462 } 02463 } 02464 } 02465 02466 static int sketch_delete(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) 02467 { 02468 SK_Sketch *sketch = contextSketch(C, 0); 02469 if (sketch) 02470 { 02471 sk_deleteSelectedStrokes(sketch); 02472 // allqueue(REDRAWVIEW3D, 0); 02473 } 02474 WM_event_add_notifier(C, NC_SCREEN|ND_SKETCH|NA_REMOVED, NULL); 02475 return OPERATOR_FINISHED; 02476 } 02477 02478 void BIF_sk_selectStroke(bContext *C, const int mval[2], short extend) 02479 { 02480 ToolSettings *ts = CTX_data_tool_settings(C); 02481 SK_Sketch *sketch = contextSketch(C, 0); 02482 02483 if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING) 02484 { 02485 if (sk_selectStroke(C, sketch, mval, extend)) 02486 ED_area_tag_redraw(CTX_wm_area(C)); 02487 } 02488 } 02489 02490 void BIF_convertSketch(bContext *C) 02491 { 02492 if (ED_operator_sketch_full_mode(C)) 02493 { 02494 SK_Sketch *sketch = contextSketch(C, 0); 02495 if (sketch) 02496 { 02497 sk_convert(C, sketch); 02498 // BIF_undo_push("Convert Sketch"); 02499 // allqueue(REDRAWVIEW3D, 0); 02500 // allqueue(REDRAWBUTSEDIT, 0); 02501 } 02502 } 02503 } 02504 02505 void BIF_deleteSketch(bContext *C) 02506 { 02507 if (ED_operator_sketch_full_mode(C)) 02508 { 02509 SK_Sketch *sketch = contextSketch(C, 0); 02510 if (sketch) 02511 { 02512 sk_deleteSelectedStrokes(sketch); 02513 // BIF_undo_push("Convert Sketch"); 02514 // allqueue(REDRAWVIEW3D, 0); 02515 } 02516 } 02517 } 02518 02519 #if 0 02520 void BIF_selectAllSketch(bContext *C, int mode) 02521 { 02522 if (BIF_validSketchMode(C)) 02523 { 02524 SK_Sketch *sketch = contextSketch(C, 0); 02525 if (sketch) 02526 { 02527 sk_selectAllSketch(sketch, mode); 02528 // XXX 02529 // allqueue(REDRAWVIEW3D, 0); 02530 } 02531 } 02532 } 02533 #endif 02534 02535 SK_Sketch* contextSketch(const bContext *C, int create) 02536 { 02537 Object *obedit = CTX_data_edit_object(C); 02538 SK_Sketch *sketch = NULL; 02539 02540 if (obedit && obedit->type == OB_ARMATURE) 02541 { 02542 bArmature *arm = obedit->data; 02543 02544 if (arm->sketch == NULL && create) 02545 { 02546 arm->sketch = createSketch(); 02547 } 02548 sketch = arm->sketch; 02549 } 02550 02551 return sketch; 02552 } 02553 02554 SK_Sketch* viewcontextSketch(ViewContext *vc, int create) 02555 { 02556 Object *obedit = vc->obedit; 02557 SK_Sketch *sketch = NULL; 02558 02559 if (obedit && obedit->type == OB_ARMATURE) 02560 { 02561 bArmature *arm = obedit->data; 02562 02563 if (arm->sketch == NULL && create) 02564 { 02565 arm->sketch = createSketch(); 02566 } 02567 sketch = arm->sketch; 02568 } 02569 02570 return sketch; 02571 } 02572 02573 static int sketch_convert(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) 02574 { 02575 SK_Sketch *sketch = contextSketch(C, 0); 02576 if (sketch != NULL) 02577 { 02578 sk_convert(C, sketch); 02579 ED_area_tag_redraw(CTX_wm_area(C)); 02580 } 02581 return OPERATOR_FINISHED; 02582 } 02583 02584 static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) 02585 { 02586 SK_Sketch *sketch = contextSketch(C, 0); 02587 if (sketch != NULL) 02588 { 02589 sk_cancelStroke(sketch); 02590 ED_area_tag_redraw(CTX_wm_area(C)); 02591 return OPERATOR_FINISHED; 02592 } 02593 return OPERATOR_PASS_THROUGH; 02594 } 02595 02596 static int sketch_finish(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) 02597 { 02598 SK_Sketch *sketch = contextSketch(C, 0); 02599 if (sketch != NULL) 02600 { 02601 if (sk_finish_stroke(C, sketch)) 02602 { 02603 ED_area_tag_redraw(CTX_wm_area(C)); 02604 return OPERATOR_FINISHED; 02605 } 02606 } 02607 return OPERATOR_PASS_THROUGH; 02608 } 02609 02610 static int sketch_select(bContext *C, wmOperator *UNUSED(op), wmEvent *event) 02611 { 02612 SK_Sketch *sketch = contextSketch(C, 0); 02613 if (sketch) 02614 { 02615 short extend = 0; 02616 if (sk_selectStroke(C, sketch, event->mval, extend)) 02617 ED_area_tag_redraw(CTX_wm_area(C)); 02618 } 02619 02620 return OPERATOR_FINISHED; 02621 } 02622 02623 static int sketch_draw_stroke_cancel(bContext *C, wmOperator *op) 02624 { 02625 SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ 02626 sk_cancelStroke(sketch); 02627 MEM_freeN(op->customdata); 02628 return OPERATOR_CANCELLED; 02629 } 02630 02631 static int sketch_draw_stroke(bContext *C, wmOperator *op, wmEvent *event) 02632 { 02633 short snap = RNA_boolean_get(op->ptr, "snap"); 02634 SK_DrawData *dd; 02635 SK_Sketch *sketch = contextSketch(C, 1); 02636 02637 op->customdata = dd = MEM_callocN(sizeof("SK_DrawData"), "SketchDrawData"); 02638 sk_initDrawData(dd, event->mval); 02639 02640 sk_start_draw_stroke(sketch); 02641 02642 sk_draw_stroke(C, sketch, sketch->active_stroke, dd, snap); 02643 02644 WM_event_add_modal_handler(C, op); 02645 02646 return OPERATOR_RUNNING_MODAL; 02647 } 02648 02649 static int sketch_draw_gesture_cancel(bContext *C, wmOperator *op) 02650 { 02651 SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ 02652 sk_cancelStroke(sketch); 02653 MEM_freeN(op->customdata); 02654 return OPERATOR_CANCELLED; 02655 } 02656 02657 static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event) 02658 { 02659 short snap = RNA_boolean_get(op->ptr, "snap"); 02660 SK_DrawData *dd; 02661 SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ 02662 sk_cancelStroke(sketch); 02663 02664 op->customdata = dd = MEM_callocN(sizeof("SK_DrawData"), "SketchDrawData"); 02665 sk_initDrawData(dd, event->mval); 02666 02667 sk_start_draw_gesture(sketch); 02668 sk_draw_stroke(C, sketch, sketch->gesture, dd, snap); 02669 02670 WM_event_add_modal_handler(C, op); 02671 02672 return OPERATOR_RUNNING_MODAL; 02673 } 02674 02675 static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short gesture, SK_Stroke *stk) 02676 { 02677 short snap = RNA_boolean_get(op->ptr, "snap"); 02678 SK_DrawData *dd = op->customdata; 02679 SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ 02680 int retval = OPERATOR_RUNNING_MODAL; 02681 02682 switch (event->type) 02683 { 02684 case LEFTCTRLKEY: 02685 case RIGHTCTRLKEY: 02686 snap = event->ctrl; 02687 RNA_boolean_set(op->ptr, "snap", snap); 02688 break; 02689 case MOUSEMOVE: 02690 case INBETWEEN_MOUSEMOVE: 02691 dd->mval[0] = event->mval[0]; 02692 dd->mval[1] = event->mval[1]; 02693 sk_draw_stroke(C, sketch, stk, dd, snap); 02694 ED_area_tag_redraw(CTX_wm_area(C)); 02695 break; 02696 case ESCKEY: 02697 op->type->cancel(C, op); 02698 ED_area_tag_redraw(CTX_wm_area(C)); 02699 retval = OPERATOR_CANCELLED; 02700 break; 02701 case LEFTMOUSE: 02702 if (event->val == KM_RELEASE) 02703 { 02704 if (gesture == 0) 02705 { 02706 sk_endContinuousStroke(stk); 02707 sk_filterLastContinuousStroke(stk); 02708 sk_updateNextPoint(sketch, stk); 02709 ED_area_tag_redraw(CTX_wm_area(C)); 02710 MEM_freeN(op->customdata); 02711 retval = OPERATOR_FINISHED; 02712 } 02713 else 02714 { 02715 sk_endContinuousStroke(stk); 02716 sk_filterLastContinuousStroke(stk); 02717 02718 if (stk->nb_points > 1) 02719 { 02720 /* apply gesture here */ 02721 sk_applyGesture(C, sketch); 02722 } 02723 02724 sk_freeStroke(stk); 02725 sketch->gesture = NULL; 02726 02727 ED_area_tag_redraw(CTX_wm_area(C)); 02728 MEM_freeN(op->customdata); 02729 retval = OPERATOR_FINISHED; 02730 } 02731 } 02732 break; 02733 } 02734 02735 return retval; 02736 } 02737 02738 static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) 02739 { 02740 SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ 02741 return sketch_draw_modal(C, op, event, 0, sketch->active_stroke); 02742 } 02743 02744 static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, wmEvent *event) 02745 { 02746 SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ 02747 return sketch_draw_modal(C, op, event, 1, sketch->gesture); 02748 } 02749 02750 static int sketch_draw_preview(bContext *C, wmOperator *op, wmEvent *event) 02751 { 02752 short snap = RNA_boolean_get(op->ptr, "snap"); 02753 SK_Sketch *sketch = contextSketch(C, 0); 02754 02755 if (sketch) 02756 { 02757 SK_DrawData dd; 02758 02759 sk_initDrawData(&dd, event->mval); 02760 sk_getStrokePoint(C, &sketch->next_point, sketch, sketch->active_stroke, &dd, snap); 02761 ED_area_tag_redraw(CTX_wm_area(C)); 02762 } 02763 02764 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; 02765 } 02766 02767 /* ============================================== Poll Functions ============================================= */ 02768 02769 int ED_operator_sketch_mode_active_stroke(bContext *C) 02770 { 02771 ToolSettings *ts = CTX_data_tool_settings(C); 02772 SK_Sketch *sketch = contextSketch(C, 0); 02773 02774 if (ts->bone_sketching & BONE_SKETCHING && 02775 sketch != NULL && 02776 sketch->active_stroke != NULL) 02777 { 02778 return 1; 02779 } 02780 else 02781 { 02782 return 0; 02783 } 02784 } 02785 02786 static int ED_operator_sketch_mode_gesture(bContext *C) 02787 { 02788 ToolSettings *ts = CTX_data_tool_settings(C); 02789 SK_Sketch *sketch = contextSketch(C, 0); 02790 02791 if (ts->bone_sketching & BONE_SKETCHING && 02792 (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0 && 02793 sketch != NULL && 02794 sketch->active_stroke == NULL) 02795 { 02796 return 1; 02797 } 02798 else 02799 { 02800 return 0; 02801 } 02802 } 02803 02804 int ED_operator_sketch_full_mode(bContext *C) 02805 { 02806 Object *obedit = CTX_data_edit_object(C); 02807 ToolSettings *ts = CTX_data_tool_settings(C); 02808 02809 if (obedit && 02810 obedit->type == OB_ARMATURE && 02811 ts->bone_sketching & BONE_SKETCHING && 02812 (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0) 02813 { 02814 return 1; 02815 } 02816 else 02817 { 02818 return 0; 02819 } 02820 } 02821 02822 int ED_operator_sketch_mode(const bContext *C) 02823 { 02824 Object *obedit = CTX_data_edit_object(C); 02825 ToolSettings *ts = CTX_data_tool_settings(C); 02826 02827 if (obedit && 02828 obedit->type == OB_ARMATURE && 02829 ts->bone_sketching & BONE_SKETCHING) 02830 { 02831 return 1; 02832 } 02833 else 02834 { 02835 return 0; 02836 } 02837 } 02838 02839 /* ================================================ Operators ================================================ */ 02840 02841 void SKETCH_OT_delete(wmOperatorType *ot) 02842 { 02843 /* identifiers */ 02844 ot->name= "delete"; 02845 ot->idname= "SKETCH_OT_delete"; 02846 02847 /* api callbacks */ 02848 ot->invoke= sketch_delete; 02849 02850 ot->poll= ED_operator_sketch_full_mode; 02851 02852 /* flags */ 02853 // ot->flag= OPTYPE_UNDO; 02854 } 02855 02856 void SKETCH_OT_select(wmOperatorType *ot) 02857 { 02858 /* identifiers */ 02859 ot->name= "select"; 02860 ot->idname= "SKETCH_OT_select"; 02861 02862 /* api callbacks */ 02863 ot->invoke= sketch_select; 02864 02865 ot->poll= ED_operator_sketch_full_mode; 02866 02867 /* flags */ 02868 // ot->flag= OPTYPE_UNDO; 02869 } 02870 02871 void SKETCH_OT_cancel_stroke(wmOperatorType *ot) 02872 { 02873 /* identifiers */ 02874 ot->name= "cancel stroke"; 02875 ot->idname= "SKETCH_OT_cancel_stroke"; 02876 02877 /* api callbacks */ 02878 ot->invoke= sketch_cancel; 02879 02880 ot->poll= ED_operator_sketch_mode_active_stroke; 02881 02882 /* flags */ 02883 // ot->flag= OPTYPE_UNDO; 02884 } 02885 02886 void SKETCH_OT_convert(wmOperatorType *ot) 02887 { 02888 /* identifiers */ 02889 ot->name= "convert"; 02890 ot->idname= "SKETCH_OT_convert"; 02891 02892 /* api callbacks */ 02893 ot->invoke= sketch_convert; 02894 02895 ot->poll= ED_operator_sketch_full_mode; 02896 02897 /* flags */ 02898 ot->flag= OPTYPE_UNDO; 02899 } 02900 02901 void SKETCH_OT_finish_stroke(wmOperatorType *ot) 02902 { 02903 /* identifiers */ 02904 ot->name= "end stroke"; 02905 ot->idname= "SKETCH_OT_finish_stroke"; 02906 02907 /* api callbacks */ 02908 ot->invoke= sketch_finish; 02909 02910 ot->poll= ED_operator_sketch_mode_active_stroke; 02911 02912 /* flags */ 02913 // ot->flag= OPTYPE_UNDO; 02914 } 02915 02916 void SKETCH_OT_draw_preview(wmOperatorType *ot) 02917 { 02918 /* identifiers */ 02919 ot->name= "draw preview"; 02920 ot->idname= "SKETCH_OT_draw_preview"; 02921 02922 /* api callbacks */ 02923 ot->invoke= sketch_draw_preview; 02924 02925 ot->poll= ED_operator_sketch_mode_active_stroke; 02926 02927 RNA_def_boolean(ot->srna, "snap", 0, "Snap", ""); 02928 02929 /* flags */ 02930 // ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02931 } 02932 02933 void SKETCH_OT_draw_stroke(wmOperatorType *ot) 02934 { 02935 /* identifiers */ 02936 ot->name= "draw stroke"; 02937 ot->idname= "SKETCH_OT_draw_stroke"; 02938 02939 /* api callbacks */ 02940 ot->invoke = sketch_draw_stroke; 02941 ot->modal = sketch_draw_stroke_modal; 02942 ot->cancel = sketch_draw_stroke_cancel; 02943 02944 ot->poll= (int (*)(bContext *))ED_operator_sketch_mode; 02945 02946 RNA_def_boolean(ot->srna, "snap", 0, "Snap", ""); 02947 02948 /* flags */ 02949 ot->flag= OPTYPE_BLOCKING; // OPTYPE_REGISTER|OPTYPE_UNDO 02950 } 02951 02952 void SKETCH_OT_gesture(wmOperatorType *ot) 02953 { 02954 /* identifiers */ 02955 ot->name= "gesture"; 02956 ot->idname= "SKETCH_OT_gesture"; 02957 02958 /* api callbacks */ 02959 ot->invoke = sketch_draw_gesture; 02960 ot->modal = sketch_draw_gesture_modal; 02961 ot->cancel = sketch_draw_gesture_cancel; 02962 02963 ot->poll= ED_operator_sketch_mode_gesture; 02964 02965 RNA_def_boolean(ot->srna, "snap", 0, "Snap", ""); 02966 02967 /* flags */ 02968 ot->flag= OPTYPE_BLOCKING; // OPTYPE_UNDO 02969 } 02970