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