c9effe404da46a84fb6cd01a2da87f06ae3fb7b7
[blender.git] / source / blender / editors / armature / editarmature_sketch.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file blender/editors/armature/editarmature_sketch.c
22  *  \ingroup edarmature
23  */
24
25 #include "MEM_guardedalloc.h"
26
27 #include "DNA_object_types.h"
28 #include "DNA_scene_types.h"
29 #include "DNA_armature_types.h"
30
31 #include "BLI_blenlib.h"
32 #include "BLI_math.h"
33
34 #include "BLF_translation.h"
35
36 #include "BKE_context.h"
37 #include "BKE_sketch.h"
38
39 #include "RNA_define.h"
40 #include "RNA_access.h"
41
42 #include "ED_view3d.h"
43 #include "ED_screen.h"
44
45 #include "BIF_gl.h"
46 #include "ED_armature.h"
47 #include "armature_intern.h"
48 #include "BIF_retarget.h"
49 #include "BIF_generate.h"
50
51 #include "ED_transform.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "GPU_select.h"
57
58 typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *);
59 typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *);
60
61 typedef struct SK_GestureAction {
62         char name[64];
63         GestureDetectFct detect;
64         GestureApplyFct apply;
65 } SK_GestureAction;
66
67 #if 0 /* UNUSED 2.5 */
68 static SK_Point boneSnap;
69 #endif
70
71 static int LAST_SNAP_POINT_VALID = 0;
72 static float LAST_SNAP_POINT[3];
73
74
75 typedef struct SK_StrokeIterator {
76         HeadFct     head;
77         TailFct     tail;
78         PeekFct     peek;
79         NextFct     next;
80         NextNFct    nextN;
81         PreviousFct previous;
82         StoppedFct  stopped;
83
84         float *p, *no;
85         float size;
86
87         int length;
88         int index;
89         /*********************************/
90         SK_Stroke *stroke;
91         int start;
92         int end;
93         int stride;
94 } SK_StrokeIterator;
95
96 /******************** PROTOTYPES ******************************/
97
98 void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end);
99
100 int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
101 void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
102 int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
103 void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
104 int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
105 void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
106 int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
107 void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
108 int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
109 void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
110 int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
111 void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
112 int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
113 void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
114
115 SK_Sketch *contextSketch(const bContext *c, int create);
116 SK_Sketch *viewcontextSketch(ViewContext *vc, int create);
117
118 void sk_resetOverdraw(SK_Sketch *sketch);
119 int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk);
120
121 /******************** GESTURE ACTIONS ******************************/
122
123 static SK_GestureAction GESTURE_ACTIONS[] = {
124         {"Cut", sk_detectCutGesture, sk_applyCutGesture},
125         {"Trim", sk_detectTrimGesture, sk_applyTrimGesture},
126         {"Command", sk_detectCommandGesture, sk_applyCommandGesture},
127         {"Delete", sk_detectDeleteGesture, sk_applyDeleteGesture},
128         {"Merge", sk_detectMergeGesture, sk_applyMergeGesture},
129         {"Reverse", sk_detectReverseGesture, sk_applyReverseGesture},
130         {"Convert", sk_detectConvertGesture, sk_applyConvertGesture},
131         {"", NULL, NULL}
132 };
133
134 /******************** TEMPLATES UTILS *************************/
135
136 static char  *TEMPLATES_MENU = NULL;
137 static int TEMPLATES_CURRENT = 0;
138 static GHash *TEMPLATES_HASH = NULL;
139 static RigGraph *TEMPLATE_RIGG = NULL;
140
141 void BIF_makeListTemplates(const bContext *C)
142 {
143         Object *obedit = CTX_data_edit_object(C);
144         Scene *scene = CTX_data_scene(C);
145         ToolSettings *ts = CTX_data_tool_settings(C);
146         Base *base;
147         int index = 0;
148
149         if (TEMPLATES_HASH != NULL) {
150                 BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
151         }
152
153         TEMPLATES_HASH = BLI_ghash_int_new("makeListTemplates gh");
154         TEMPLATES_CURRENT = 0;
155
156         for (base = FIRSTBASE; base; base = base->next) {
157                 Object *ob = base->object;
158
159                 if (ob != obedit && ob->type == OB_ARMATURE) {
160                         index++;
161                         BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob);
162
163                         if (ob == ts->skgen_template) {
164                                 TEMPLATES_CURRENT = index;
165                         }
166                 }
167         }
168 }
169
170 #if 0  /* UNUSED */
171 const char *BIF_listTemplates(const bContext *UNUSED(C))
172 {
173         GHashIterator ghi;
174         const char *menu_header = IFACE_("Template %t|None %x0|");
175         char *p;
176         const size_t template_size = (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30);
177
178         if (TEMPLATES_MENU != NULL) {
179                 MEM_freeN(TEMPLATES_MENU);
180         }
181
182         TEMPLATES_MENU = MEM_callocN(sizeof(char) * template_size, "skeleton template menu");
183
184         p = TEMPLATES_MENU;
185         p += BLI_strncpy_rlen(p, menu_header, template_size);
186
187         BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
188
189         while (!BLI_ghashIterator_done(&ghi)) {
190                 Object *ob = BLI_ghashIterator_getValue(&ghi);
191                 int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
192
193                 p += sprintf(p, "|%s %%x%i", ob->id.name + 2, key);
194
195                 BLI_ghashIterator_step(&ghi);
196         }
197
198         return TEMPLATES_MENU;
199 }
200 #endif
201
202 int   BIF_currentTemplate(const bContext *C)
203 {
204         ToolSettings *ts = CTX_data_tool_settings(C);
205
206         if (TEMPLATES_CURRENT == 0 && ts->skgen_template != NULL) {
207                 GHashIterator ghi;
208                 BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
209
210                 while (!BLI_ghashIterator_done(&ghi)) {
211                         Object *ob = BLI_ghashIterator_getValue(&ghi);
212                         int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
213
214                         if (ob == ts->skgen_template) {
215                                 TEMPLATES_CURRENT = key;
216                                 break;
217                         }
218
219                         BLI_ghashIterator_step(&ghi);
220                 }
221         }
222
223         return TEMPLATES_CURRENT;
224 }
225
226 static RigGraph *sk_makeTemplateGraph(const bContext *C, Object *ob)
227 {
228         Object *obedit = CTX_data_edit_object(C);
229         if (ob == obedit) {
230                 return NULL;
231         }
232
233         if (ob != NULL) {
234                 if (TEMPLATE_RIGG && TEMPLATE_RIGG->ob != ob) {
235                         RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG);
236                         TEMPLATE_RIGG = NULL;
237                 }
238
239                 if (TEMPLATE_RIGG == NULL) {
240                         bArmature *arm;
241
242                         arm = ob->data;
243
244                         TEMPLATE_RIGG = RIG_graphFromArmature(C, ob, arm);
245                 }
246         }
247
248         return TEMPLATE_RIGG;
249 }
250
251 int BIF_nbJointsTemplate(const bContext *C)
252 {
253         ToolSettings *ts = CTX_data_tool_settings(C);
254         RigGraph *rg = sk_makeTemplateGraph(C, ts->skgen_template);
255
256         if (rg) {
257                 return RIG_nbJoints(rg);
258         }
259         else {
260                 return -1;
261         }
262 }
263
264 const char *BIF_nameBoneTemplate(const bContext *C)
265 {
266         ToolSettings *ts = CTX_data_tool_settings(C);
267         SK_Sketch *stk = contextSketch(C, 1);
268         RigGraph *rg;
269         int index = 0;
270
271         if (stk && stk->active_stroke != NULL) {
272                 index = stk->active_stroke->nb_points;
273         }
274
275         rg = sk_makeTemplateGraph(C, ts->skgen_template);
276
277         if (rg == NULL) {
278                 return "";
279         }
280
281         return RIG_nameBone(rg, 0, index);
282 }
283
284 void  BIF_freeTemplates(bContext *UNUSED(C))
285 {
286         if (TEMPLATES_MENU != NULL) {
287                 MEM_freeN(TEMPLATES_MENU);
288                 TEMPLATES_MENU = NULL;
289         }
290
291         if (TEMPLATES_HASH != NULL) {
292                 BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
293                 TEMPLATES_HASH = NULL;
294         }
295
296         if (TEMPLATE_RIGG != NULL) {
297                 RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG);
298                 TEMPLATE_RIGG = NULL;
299         }
300 }
301
302 void  BIF_setTemplate(bContext *C, int index)
303 {
304         ToolSettings *ts = CTX_data_tool_settings(C);
305         if (index > 0) {
306                 ts->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index));
307         }
308         else {
309                 ts->skgen_template = NULL;
310
311                 if (TEMPLATE_RIGG != NULL) {
312                         RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG);
313                 }
314                 TEMPLATE_RIGG = NULL;
315         }
316 }
317
318 /*********************** CONVERSION ***************************/
319
320 static void sk_autoname(bContext *C, ReebArc *arc)
321 {
322         ToolSettings *ts = CTX_data_tool_settings(C);
323         if (ts->skgen_retarget_options & SK_RETARGET_AUTONAME) {
324                 if (arc == NULL) {
325                         char *num = ts->skgen_num_string;
326                         int i = atoi(num);
327                         i++;
328                         BLI_snprintf(num, 8, "%i", i);
329                 }
330                 else {
331                         char *side = ts->skgen_side_string;
332                         int valid = 0;
333                         int caps = 0;
334
335                         if (side[0] == '\0') {
336                                 valid = 1;
337                         }
338                         else if (strcmp(side, "R") == 0 || strcmp(side, "L") == 0) {
339                                 valid = 1;
340                                 caps = 1;
341                         }
342                         else if (strcmp(side, "r") == 0 || strcmp(side, "l") == 0) {
343                                 valid = 1;
344                                 caps = 0;
345                         }
346
347                         if (valid) {
348                                 if (arc->head->p[0] < 0) {
349                                         BLI_snprintf(side, 8, caps ? "R" : "r");
350                                 }
351                                 else {
352                                         BLI_snprintf(side, 8, caps ? "L" : "l");
353                                 }
354                         }
355                 }
356         }
357 }
358
359 static ReebNode *sk_pointToNode(SK_Point *pt, float imat[4][4], float tmat[3][3])
360 {
361         ReebNode *node;
362
363         node = MEM_callocN(sizeof(ReebNode), "reeb node");
364         copy_v3_v3(node->p, pt->p);
365         mul_m4_v3(imat, node->p);
366
367         copy_v3_v3(node->no, pt->no);
368         mul_m3_v3(tmat, node->no);
369
370         return node;
371 }
372
373 static ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[4][4], float tmat[3][3])
374 {
375         ReebArc *arc;
376         int i;
377
378         arc = MEM_callocN(sizeof(ReebArc), "reeb arc");
379         arc->head = sk_pointToNode(stk->points, imat, tmat);
380         arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat);
381
382         arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */
383         arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets");
384
385         for (i = 0; i < arc->bcount; i++) {
386                 copy_v3_v3(arc->buckets[i].p, stk->points[i + 1].p);
387                 mul_m4_v3(imat, arc->buckets[i].p);
388
389                 copy_v3_v3(arc->buckets[i].no, stk->points[i + 1].no);
390                 mul_m3_v3(tmat, arc->buckets[i].no);
391         }
392
393         return arc;
394 }
395
396 static void sk_retargetStroke(bContext *C, SK_Stroke *stk)
397 {
398         ToolSettings *ts = CTX_data_tool_settings(C);
399         Object *obedit = CTX_data_edit_object(C);
400         float imat[4][4];
401         float tmat[3][3];
402         ReebArc *arc;
403         RigGraph *rg;
404
405         invert_m4_m4(imat, obedit->obmat);
406
407         copy_m3_m4(tmat, obedit->obmat);
408         transpose_m3(tmat);
409
410         arc = sk_strokeToArc(stk, imat, tmat);
411
412         sk_autoname(C, arc);
413
414         rg = sk_makeTemplateGraph(C, ts->skgen_template);
415
416         BIF_retargetArc(C, arc, rg);
417
418         sk_autoname(C, NULL);
419
420         MEM_freeN(arc->head);
421         MEM_freeN(arc->tail);
422         REEB_freeArc((BArc *)arc);
423 }
424
425 /**************************************************************/
426
427 static void sk_cancelStroke(SK_Sketch *sketch)
428 {
429         if (sketch->active_stroke != NULL) {
430                 sk_resetOverdraw(sketch);
431                 sk_removeStroke(sketch, sketch->active_stroke);
432         }
433 }
434
435
436 static float sk_clampPointSize(SK_Point *pt, float size)
437 {
438         return max_ff(size * pt->size, size / 2);
439 }
440
441 static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size)
442 {
443         glTranslatef(pt->p[0], pt->p[1], pt->p[2]);
444         gluSphere(quad, sk_clampPointSize(pt, size), 8, 8);
445 }
446
447 static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float size)
448 {
449         float vec1[3], vec2[3] = {0, 0, 1}, axis[3];
450         float angle, length;
451
452         sub_v3_v3v3(vec1, pt1->p, pt0->p);
453         length = normalize_v3(vec1);
454         cross_v3_v3v3(axis, vec2, vec1);
455
456         if (is_zero_v3(axis)) {
457                 axis[1] = 1;
458         }
459
460         angle = angle_normalized_v3v3(vec2, vec1);
461
462         glRotatef(angle * (float)(180.0 / M_PI) + 180.0f, axis[0], axis[1], axis[2]);
463
464         gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8);
465 }
466
467 static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float height)
468 {
469         float vec2[3] = {0, 0, 1}, axis[3];
470         float angle;
471         
472         glPushMatrix();
473
474         cross_v3_v3v3(axis, vec2, pt->no);
475
476         if (is_zero_v3(axis)) {
477                 axis[1] = 1;
478         }
479
480         angle = angle_normalized_v3v3(vec2, pt->no);
481
482         glRotatef(angle * (float)(180.0 / M_PI), axis[0], axis[1], axis[2]);
483
484         glColor3f(0, 1, 1);
485         gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2);
486
487         glPopMatrix();
488 }
489
490 static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end)
491 {
492         float rgb[3];
493         int i;
494         GLUquadric *quad = gluNewQuadric();
495         gluQuadricNormals(quad, GLU_SMOOTH);
496
497         if (id != -1) {
498                 GPU_select_load_id(id);
499
500                 for (i = 0; i < stk->nb_points; i++) {
501                         glPushMatrix();
502
503                         sk_drawPoint(quad, stk->points + i, 0.1);
504
505                         if (i > 0) {
506                                 sk_drawEdge(quad, stk->points + i - 1, stk->points + i, 0.1);
507                         }
508
509                         glPopMatrix();
510                 }
511
512         }
513         else {
514                 float d_rgb[3] = {1, 1, 1};
515
516                 copy_v3_v3(rgb, color);
517                 sub_v3_v3(d_rgb, rgb);
518                 mul_v3_fl(d_rgb, 1.0f / (float)stk->nb_points);
519
520                 for (i = 0; i < stk->nb_points; i++) {
521                         SK_Point *pt = stk->points + i;
522
523                         glPushMatrix();
524
525                         if (pt->type == PT_EXACT) {
526                                 glColor3f(0, 0, 0);
527                                 sk_drawPoint(quad, pt, 0.15);
528                                 sk_drawNormal(quad, pt, 0.05, 0.9);
529                         }
530
531                         if (i >= start && i <= end) {
532                                 glColor3f(0.3, 0.3, 0.3);
533                         }
534                         else {
535                                 glColor3fv(rgb);
536                         }
537
538                         if (pt->type != PT_EXACT) {
539
540                                 sk_drawPoint(quad, pt, 0.1);
541                         }
542
543                         if (i > 0) {
544                                 sk_drawEdge(quad, pt - 1, pt, 0.1);
545                         }
546
547                         glPopMatrix();
548
549                         add_v3_v3(rgb, d_rgb);
550                 }
551         }
552
553         gluDeleteQuadric(quad);
554 }
555
556 static void drawSubdividedStrokeBy(ToolSettings *toolsettings, BArcIterator *iter, NextSubdivisionFunc next_subdividion)
557 {
558         SK_Stroke *stk = ((SK_StrokeIterator *)iter)->stroke;
559         float head[3], tail[3];
560         int bone_start = 0;
561         int end = iter->length;
562         int index;
563         GLUquadric *quad = gluNewQuadric();
564         gluQuadricNormals(quad, GLU_SMOOTH);
565
566         iter->head(iter);
567         copy_v3_v3(head, iter->p);
568
569         index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
570         while (index != -1) {
571                 SK_Point *pt = stk->points + index;
572
573                 glPushMatrix();
574
575                 glColor3f(0, 1, 0);
576                 sk_drawPoint(quad, pt, 0.15);
577
578                 sk_drawNormal(quad, pt, 0.05, 0.9);
579
580                 glPopMatrix();
581
582                 copy_v3_v3(head, tail);
583                 bone_start = index; // start next bone from current index
584
585                 index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
586         }
587
588         gluDeleteQuadric(quad);
589 }
590
591 static void sk_drawStrokeSubdivision(ToolSettings *toolsettings, SK_Stroke *stk)
592 {
593         int head_index = -1;
594         int i;
595
596         if (toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET) {
597                 return;
598         }
599
600
601         for (i = 0; i < stk->nb_points; i++) {
602                 SK_Point *pt = stk->points + i;
603
604                 if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */ {
605                         if (head_index == -1) {
606                                 head_index = i;
607                         }
608                         else {
609                                 if (i - head_index > 1) {
610                                         SK_StrokeIterator sk_iter;
611                                         BArcIterator *iter = (BArcIterator *)&sk_iter;
612
613                                         initStrokeIterator(iter, stk, head_index, i);
614
615                                         if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) {
616                                                 drawSubdividedStrokeBy(toolsettings, iter, nextAdaptativeSubdivision);
617                                         }
618                                         else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) {
619                                                 drawSubdividedStrokeBy(toolsettings, iter, nextLengthSubdivision);
620                                         }
621                                         else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED) {
622                                                 drawSubdividedStrokeBy(toolsettings, iter, nextFixedSubdivision);
623                                         }
624
625                                 }
626
627                                 head_index = i;
628                         }
629                 }
630         }
631 }
632
633 static SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, int mval[2], float *r_dist_px, int *index, int all_pts)
634 {
635         ARegion *ar = CTX_wm_region(C);
636         SK_Point *pt = NULL;
637         int i;
638
639         for (i = 0; i < stk->nb_points; i++) {
640                 if (all_pts || stk->points[i].type == PT_EXACT) {
641                         short pval[2];
642                         int pdist;
643
644                         if (ED_view3d_project_short_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
645
646                                 pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
647
648                                 if (pdist < *r_dist_px) {
649                                         *r_dist_px = pdist;
650                                         pt = stk->points + i;
651
652                                         if (index != NULL) {
653                                                 *index = i;
654                                         }
655                                 }
656                         }
657                 }
658         }
659
660         return pt;
661 }
662
663 #if 0 /* UNUSED 2.5 */
664 static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, int mval[2], int *dist)
665 {
666         ARegion *ar = CTX_wm_region(C);
667         SK_Point *pt = NULL;
668         EditBone *bone;
669
670         for (bone = ebones->first; bone; bone = bone->next)
671         {
672                 float vec[3];
673                 short pval[2];
674                 int pdist;
675
676                 if ((bone->flag & BONE_CONNECTED) == 0)
677                 {
678                         copy_v3_v3(vec, bone->head);
679                         mul_m4_v3(ob->obmat, vec);
680                         if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
681
682                                 pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
683
684                                 if (pdist < *dist)
685                                 {
686                                         *dist = pdist;
687                                         pt = &boneSnap;
688                                         copy_v3_v3(pt->p, vec);
689                                         pt->type = PT_EXACT;
690                                 }
691                         }
692                 }
693
694
695                 copy_v3_v3(vec, bone->tail);
696                 mul_m4_v3(ob->obmat, vec);
697                 if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
698
699                         pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
700
701                         if (pdist < *dist)
702                         {
703                                 *dist = pdist;
704                                 pt = &boneSnap;
705                                 copy_v3_v3(pt->p, vec);
706                                 pt->type = PT_EXACT;
707                         }
708                 }
709         }
710
711         return pt;
712 }
713 #endif
714
715 void sk_resetOverdraw(SK_Sketch *sketch)
716 {
717         sketch->over.target = NULL;
718         sketch->over.start = -1;
719         sketch->over.end = -1;
720         sketch->over.count = 0;
721 }
722
723 int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk)
724 {
725         return sketch->over.target &&
726                sketch->over.count >= SK_OVERDRAW_LIMIT &&
727                (sketch->over.target == stk || stk == NULL) &&
728                (sketch->over.start != -1 || sketch->over.end != -1);
729 }
730
731 static void sk_updateOverdraw(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
732 {
733         if (sketch->over.target == NULL) {
734                 SK_Stroke *target;
735                 int closest_index = -1;
736                 float dist_px = SNAP_MIN_DISTANCE * 2;
737
738                 for (target = sketch->strokes.first; target; target = target->next) {
739                         if (target != stk) {
740                                 int index;
741
742                                 SK_Point *spt = sk_snapPointStroke(C, target, dd->mval, &dist_px, &index, 1);
743
744                                 if (spt != NULL) {
745                                         sketch->over.target = target;
746                                         closest_index = index;
747                                 }
748                         }
749                 }
750
751                 if (sketch->over.target != NULL) {
752                         if (closest_index > -1) {
753                                 if (sk_lastStrokePoint(stk)->type == PT_EXACT) {
754                                         sketch->over.count = SK_OVERDRAW_LIMIT;
755                                 }
756                                 else {
757                                         sketch->over.count++;
758                                 }
759                         }
760
761                         if (stk->nb_points == 1) {
762                                 sketch->over.start = closest_index;
763                         }
764                         else {
765                                 sketch->over.end = closest_index;
766                         }
767                 }
768         }
769         else if (sketch->over.target != NULL) {
770                 SK_Point *closest_pt = NULL;
771                 float dist_px = SNAP_MIN_DISTANCE * 2;
772                 int index;
773
774                 closest_pt = sk_snapPointStroke(C, sketch->over.target, dd->mval, &dist_px, &index, 1);
775
776                 if (closest_pt != NULL) {
777                         if (sk_lastStrokePoint(stk)->type == PT_EXACT) {
778                                 sketch->over.count = SK_OVERDRAW_LIMIT;
779                         }
780                         else {
781                                 sketch->over.count++;
782                         }
783
784                         sketch->over.end = index;
785                 }
786                 else {
787                         sketch->over.end = -1;
788                 }
789         }
790 }
791
792 /* return 1 on reverse needed */
793 static int sk_adjustIndexes(SK_Sketch *sketch, int *start, int *end)
794 {
795         int retval = 0;
796
797         *start = sketch->over.start;
798         *end = sketch->over.end;
799
800         if (*start == -1) {
801                 *start = 0;
802         }
803
804         if (*end == -1) {
805                 *end = sketch->over.target->nb_points - 1;
806         }
807
808         if (*end < *start) {
809                 int tmp = *start;
810                 *start = *end;
811                 *end = tmp;
812                 retval = 1;
813         }
814
815         return retval;
816 }
817
818 static void sk_endOverdraw(SK_Sketch *sketch)
819 {
820         SK_Stroke *stk = sketch->active_stroke;
821
822         if (sk_hasOverdraw(sketch, NULL)) {
823                 int start;
824                 int end;
825
826                 if (sk_adjustIndexes(sketch, &start, &end)) {
827                         sk_reverseStroke(stk);
828                 }
829
830                 if (stk->nb_points > 1) {
831                         stk->points->type = sketch->over.target->points[start].type;
832                         sk_lastStrokePoint(stk)->type = sketch->over.target->points[end].type;
833                 }
834
835                 sk_insertStrokePoints(sketch->over.target, stk->points, stk->nb_points, start, end);
836
837                 sk_removeStroke(sketch, stk);
838
839                 sk_resetOverdraw(sketch);
840         }
841 }
842
843
844 static void sk_startStroke(SK_Sketch *sketch)
845 {
846         SK_Stroke *stk = sk_createStroke();
847
848         BLI_addtail(&sketch->strokes, stk);
849         sketch->active_stroke = stk;
850
851         sk_resetOverdraw(sketch);
852 }
853
854 static void sk_endStroke(bContext *C, SK_Sketch *sketch)
855 {
856         ToolSettings *ts = CTX_data_tool_settings(C);
857         sk_shrinkStrokeBuffer(sketch->active_stroke);
858
859         if (ts->bone_sketching & BONE_SKETCHING_ADJUST) {
860                 sk_endOverdraw(sketch);
861         }
862
863         sketch->active_stroke = NULL;
864 }
865
866 static void sk_updateDrawData(SK_DrawData *dd)
867 {
868         dd->type = PT_CONTINUOUS;
869
870         dd->previous_mval[0] = dd->mval[0];
871         dd->previous_mval[1] = dd->mval[1];
872 }
873
874 static float sk_distanceDepth(bContext *C, float p1[3], float p2[3])
875 {
876         ARegion *ar = CTX_wm_region(C);
877         RegionView3D *rv3d = ar->regiondata;
878         float vec[3];
879         float distance;
880
881         sub_v3_v3v3(vec, p1, p2);
882
883         project_v3_v3v3(vec, vec, rv3d->viewinv[2]);
884
885         distance = len_v3(vec);
886
887         if (dot_v3v3(rv3d->viewinv[2], vec) > 0) {
888                 distance *= -1;
889         }
890
891         return distance;
892 }
893
894 static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float length, float distance)
895 {
896         ARegion *ar = CTX_wm_region(C);
897         ScrArea *sa = CTX_wm_area(C);
898         View3D *v3d = sa->spacedata.first;
899
900         float progress = 0;
901         int i;
902
903         progress = len_v3v3(stk->points[start].p, stk->points[start - 1].p);
904
905         for (i = start; i <= end; i++) {
906                 float ray_start[3], ray_normal[3];
907                 float delta = len_v3v3(stk->points[i].p, stk->points[i + 1].p);
908                 float pval[2] = {0, 0};
909
910                 ED_view3d_project_float_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP);
911                 ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal, false);
912
913                 mul_v3_fl(ray_normal, distance * progress / length);
914                 add_v3_v3(stk->points[i].p, ray_normal);
915
916                 progress += delta;
917         }
918 }
919
920 static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_DrawData *dd)
921 {
922         ARegion *ar = CTX_wm_region(C);
923         /* copied from grease pencil, need fixing */
924         SK_Point *last = sk_lastStrokePoint(stk);
925         short cval[2];
926         float fp[3] = {0, 0, 0};
927         float dvec[3];
928         float mval_f[2];
929         float zfac;
930
931         if (last != NULL) {
932                 copy_v3_v3(fp, last->p);
933         }
934
935         zfac = ED_view3d_calc_zfac(ar->regiondata, fp, NULL);
936
937         if (ED_view3d_project_short_global(ar, fp, cval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
938                 VECSUB2D(mval_f, cval, dd->mval);
939                 ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
940                 sub_v3_v3v3(vec, fp, dvec);
941         }
942         else {
943                 zero_v3(vec);
944         }
945 }
946
947 static int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *UNUSED(sketch), SK_Stroke *stk, SK_DrawData *dd)
948 {
949         pt->type = dd->type;
950         pt->mode = PT_PROJECT;
951         sk_projectDrawPoint(C, pt->p, stk, dd);
952
953         return 1;
954 }
955
956 static int sk_addStrokeDrawPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
957 {
958         ARegion *ar = CTX_wm_region(C);
959         RegionView3D *rv3d = ar->regiondata;
960         SK_Point pt;
961
962         sk_initPoint(&pt, dd, rv3d->viewinv[2]);
963
964         sk_getStrokeDrawPoint(C, &pt, sketch, stk, dd);
965
966         sk_appendStrokePoint(stk, &pt);
967
968         return 1;
969 }
970
971 static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
972 {
973         ToolSettings *ts = CTX_data_tool_settings(C);
974         int point_added = 0;
975
976         if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) {
977                 DepthPeel *p1, *p2;
978                 float *last_p = NULL;
979                 float dist = FLT_MAX;
980                 float p[3] = {0};
981                 float size = 0;
982                 float mvalf[2];
983
984                 BLI_freelistN(&sketch->depth_peels);
985                 BLI_listbase_clear(&sketch->depth_peels);
986
987                 mvalf[0] = dd->mval[0];
988                 mvalf[1] = dd->mval[1];
989                 peelObjectsContext(C, &sketch->depth_peels, mvalf, SNAP_ALL);
990
991                 if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) {
992                         last_p = stk->points[stk->nb_points - 1].p;
993                 }
994                 else if (LAST_SNAP_POINT_VALID) {
995                         last_p = LAST_SNAP_POINT;
996                 }
997
998
999                 for (p1 = sketch->depth_peels.first; p1; p1 = p1->next) {
1000                         if (p1->flag == 0) {
1001                                 float vec[3];
1002                                 float new_dist;
1003                                 float new_size = 0;
1004
1005                                 p2 = NULL;
1006                                 p1->flag = 1;
1007
1008                                 /* if peeling objects, take the first and last from each object */
1009                                 if (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) {
1010                                         DepthPeel *peel;
1011                                         for (peel = p1->next; peel; peel = peel->next) {
1012                                                 if (peel->ob == p1->ob) {
1013                                                         peel->flag = 1;
1014                                                         p2 = peel;
1015                                                 }
1016                                         }
1017                                 }
1018                                 /* otherwise, pair first with second and so on */
1019                                 else {
1020                                         for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) {
1021                                                 /* nothing to do here */
1022                                         }
1023                                 }
1024
1025                                 if (p2) {
1026                                         p2->flag = 1;
1027
1028                                         add_v3_v3v3(vec, p1->p, p2->p);
1029                                         mul_v3_fl(vec, 0.5f);
1030                                         new_size = len_v3v3(p1->p, p2->p);
1031                                 }
1032                                 else {
1033                                         copy_v3_v3(vec, p1->p);
1034                                 }
1035
1036                                 if (last_p == NULL) {
1037                                         copy_v3_v3(p, vec);
1038                                         size = new_size;
1039                                         dist = 0;
1040                                         break;
1041                                 }
1042
1043                                 new_dist = len_v3v3(last_p, vec);
1044
1045                                 if (new_dist < dist) {
1046                                         copy_v3_v3(p, vec);
1047                                         dist = new_dist;
1048                                         size = new_size;
1049                                 }
1050                         }
1051                 }
1052
1053                 if (dist != FLT_MAX) {
1054                         pt->type = dd->type;
1055                         pt->mode = PT_SNAP;
1056                         pt->size = size / 2;
1057                         copy_v3_v3(pt->p, p);
1058
1059                         point_added = 1;
1060                 }
1061
1062                 //BLI_freelistN(&depth_peels);
1063         }
1064         else {
1065                 SK_Stroke *snap_stk;
1066                 float vec[3];
1067                 float no[3];
1068                 float mval[2];
1069                 int found = 0;
1070                 float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
1071
1072                 /* snap to strokes */
1073                 // if (ts->snap_mode == SCE_SNAP_MODE_VERTEX) /* snap all the time to strokes */
1074                 for (snap_stk = sketch->strokes.first; snap_stk; snap_stk = snap_stk->next) {
1075                         SK_Point *spt = NULL;
1076                         if (snap_stk == stk) {
1077                                 spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist_px, NULL, 0);
1078                         }
1079                         else {
1080                                 spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist_px, NULL, 1);
1081                         }
1082
1083                         if (spt != NULL) {
1084                                 copy_v3_v3(pt->p, spt->p);
1085                                 point_added = 1;
1086                         }
1087                 }
1088                 
1089                 mval[0] = dd->mval[0];
1090                 mval[1] = dd->mval[1];
1091
1092                 /* try to snap to closer object */
1093                 found = snapObjectsContext(C, mval, &dist_px, vec, no, SNAP_NOT_SELECTED);
1094                 if (found == 1) {
1095                         pt->type = dd->type;
1096                         pt->mode = PT_SNAP;
1097                         copy_v3_v3(pt->p, vec);
1098
1099                         point_added = 1;
1100                 }
1101         }
1102
1103         return point_added;
1104 }
1105
1106 static int sk_addStrokeSnapPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
1107 {
1108         int point_added;
1109         ARegion *ar = CTX_wm_region(C);
1110         RegionView3D *rv3d = ar->regiondata;
1111         SK_Point pt;
1112
1113         sk_initPoint(&pt, dd, rv3d->viewinv[2]);
1114
1115         point_added = sk_getStrokeSnapPoint(C, &pt, sketch, stk, dd);
1116
1117         if (point_added) {
1118                 float final_p[3];
1119                 float length, distance;
1120                 int total;
1121                 int i;
1122
1123                 copy_v3_v3(final_p, pt.p);
1124
1125                 sk_projectDrawPoint(C, pt.p, stk, dd);
1126                 sk_appendStrokePoint(stk, &pt);
1127
1128                 /* update all previous point to give smooth Z progresion */
1129                 total = 0;
1130                 length = 0;
1131                 for (i = stk->nb_points - 2; i > 0; i--) {
1132                         length += len_v3v3(stk->points[i].p, stk->points[i + 1].p);
1133                         total++;
1134                         if (stk->points[i].mode == PT_SNAP || stk->points[i].type == PT_EXACT) {
1135                                 break;
1136                         }
1137                 }
1138
1139                 if (total > 1) {
1140                         distance = sk_distanceDepth(C, final_p, stk->points[i].p);
1141
1142                         sk_interpolateDepth(C, stk, i + 1, stk->nb_points - 2, length, distance);
1143                 }
1144
1145                 copy_v3_v3(stk->points[stk->nb_points - 1].p, final_p);
1146
1147                 point_added = 1;
1148         }
1149
1150         return point_added;
1151 }
1152
1153 static void sk_addStrokePoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, const bool snap)
1154 {
1155         ToolSettings *ts = CTX_data_tool_settings(C);
1156         int point_added = 0;
1157
1158         if (snap) {
1159                 point_added = sk_addStrokeSnapPoint(C, sketch, stk, dd);
1160         }
1161
1162         if (point_added == 0) {
1163                 point_added = sk_addStrokeDrawPoint(C, sketch, stk, dd);
1164         }
1165
1166         if (stk == sketch->active_stroke && ts->bone_sketching & BONE_SKETCHING_ADJUST) {
1167                 sk_updateOverdraw(C, sketch, stk, dd);
1168         }
1169 }
1170
1171 static void sk_getStrokePoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, const bool snap)
1172 {
1173         int point_added = 0;
1174
1175         if (snap) {
1176                 point_added = sk_getStrokeSnapPoint(C, pt, sketch, stk, dd);
1177                 LAST_SNAP_POINT_VALID = 1;
1178                 copy_v3_v3(LAST_SNAP_POINT, pt->p);
1179         }
1180         else {
1181                 LAST_SNAP_POINT_VALID = 0;
1182         }
1183
1184         if (point_added == 0) {
1185                 point_added = sk_getStrokeDrawPoint(C, pt, sketch, stk, dd);
1186         }
1187 }
1188
1189 /********************************************/
1190
1191 static void *headPoint(void *arg);
1192 static void *tailPoint(void *arg);
1193 static void *nextPoint(void *arg);
1194 static void *nextNPoint(void *arg, int n);
1195 static void *peekPoint(void *arg, int n);
1196 static void *previousPoint(void *arg);
1197 static int   iteratorStopped(void *arg);
1198
1199 static void initIteratorFct(SK_StrokeIterator *iter)
1200 {
1201         iter->head = headPoint;
1202         iter->tail = tailPoint;
1203         iter->peek = peekPoint;
1204         iter->next = nextPoint;
1205         iter->nextN = nextNPoint;
1206         iter->previous = previousPoint;
1207         iter->stopped = iteratorStopped;
1208 }
1209
1210 static SK_Point *setIteratorValues(SK_StrokeIterator *iter, int index)
1211 {
1212         SK_Point *pt = NULL;
1213
1214         if (index >= 0 && index < iter->length) {
1215                 pt = &(iter->stroke->points[iter->start + (iter->stride * index)]);
1216                 iter->p = pt->p;
1217                 iter->no = pt->no;
1218                 iter->size = pt->size;
1219         }
1220         else {
1221                 iter->p = NULL;
1222                 iter->no = NULL;
1223                 iter->size = 0;
1224         }
1225
1226         return pt;
1227 }
1228
1229 void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end)
1230 {
1231         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1232
1233         initIteratorFct(iter);
1234         iter->stroke = stk;
1235
1236         if (start < end) {
1237                 iter->start = start + 1;
1238                 iter->end = end - 1;
1239                 iter->stride = 1;
1240         }
1241         else {
1242                 iter->start = start - 1;
1243                 iter->end = end + 1;
1244                 iter->stride = -1;
1245         }
1246
1247         iter->length = iter->stride * (iter->end - iter->start + 1);
1248
1249         iter->index = -1;
1250 }
1251
1252
1253 static void *headPoint(void *arg)
1254 {
1255         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1256         SK_Point *result = NULL;
1257
1258         result = &(iter->stroke->points[iter->start - iter->stride]);
1259         iter->p = result->p;
1260         iter->no = result->no;
1261         iter->size = result->size;
1262
1263         return result;
1264 }
1265
1266 static void *tailPoint(void *arg)
1267 {
1268         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1269         SK_Point *result = NULL;
1270
1271         result = &(iter->stroke->points[iter->end + iter->stride]);
1272         iter->p = result->p;
1273         iter->no = result->no;
1274         iter->size = result->size;
1275
1276         return result;
1277 }
1278
1279 static void *nextPoint(void *arg)
1280 {
1281         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1282         SK_Point *result = NULL;
1283
1284         iter->index++;
1285         if (iter->index < iter->length) {
1286                 result = setIteratorValues(iter, iter->index);
1287         }
1288
1289         return result;
1290 }
1291
1292 static void *nextNPoint(void *arg, int n)
1293 {
1294         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1295         SK_Point *result = NULL;
1296
1297         iter->index += n;
1298
1299         /* check if passed end */
1300         if (iter->index < iter->length) {
1301                 result = setIteratorValues(iter, iter->index);
1302         }
1303
1304         return result;
1305 }
1306
1307 static void *peekPoint(void *arg, int n)
1308 {
1309         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1310         SK_Point *result = NULL;
1311         int index = iter->index + n;
1312
1313         /* check if passed end */
1314         if (index < iter->length) {
1315                 result = setIteratorValues(iter, index);
1316         }
1317
1318         return result;
1319 }
1320
1321 static void *previousPoint(void *arg)
1322 {
1323         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1324         SK_Point *result = NULL;
1325
1326         if (iter->index > 0) {
1327                 iter->index--;
1328                 result = setIteratorValues(iter, iter->index);
1329         }
1330
1331         return result;
1332 }
1333
1334 static int iteratorStopped(void *arg)
1335 {
1336         SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
1337
1338         if (iter->index >= iter->length) {
1339                 return 1;
1340         }
1341         else {
1342                 return 0;
1343         }
1344 }
1345
1346 static void sk_convertStroke(bContext *C, SK_Stroke *stk)
1347 {
1348         Object *obedit = CTX_data_edit_object(C);
1349         ToolSettings *ts = CTX_data_tool_settings(C);
1350         bArmature *arm = obedit->data;
1351         SK_Point *head;
1352         EditBone *parent = NULL;
1353         float invmat[4][4]; /* move in caller function */
1354         float tmat[3][3];
1355         int head_index = 0;
1356         int i;
1357
1358         head = NULL;
1359
1360         invert_m4_m4(invmat, obedit->obmat);
1361
1362         copy_m3_m4(tmat, obedit->obmat);
1363         transpose_m3(tmat);
1364
1365         for (i = 0; i < stk->nb_points; i++) {
1366                 SK_Point *pt = stk->points + i;
1367
1368                 if (pt->type == PT_EXACT) {
1369                         if (head == NULL) {
1370                                 head_index = i;
1371                                 head = pt;
1372                         }
1373                         else {
1374                                 EditBone *bone = NULL;
1375                                 EditBone *new_parent;
1376
1377                                 if (i - head_index > 1) {
1378                                         SK_StrokeIterator sk_iter;
1379                                         BArcIterator *iter = (BArcIterator *)&sk_iter;
1380
1381                                         initStrokeIterator(iter, stk, head_index, i);
1382
1383                                         if (ts->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) {
1384                                                 bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
1385                                         }
1386                                         else if (ts->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) {
1387                                                 bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision);
1388                                         }
1389                                         else if (ts->bone_sketching_convert == SK_CONVERT_CUT_FIXED) {
1390                                                 bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextFixedSubdivision);
1391                                         }
1392                                 }
1393
1394                                 if (bone == NULL) {
1395                                         bone = ED_armature_edit_bone_add(arm, "Bone");
1396
1397                                         copy_v3_v3(bone->head, head->p);
1398                                         copy_v3_v3(bone->tail, pt->p);
1399
1400                                         mul_m4_v3(invmat, bone->head);
1401                                         mul_m4_v3(invmat, bone->tail);
1402                                         setBoneRollFromNormal(bone, head->no, invmat, tmat);
1403                                 }
1404
1405                                 new_parent = bone;
1406                                 bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
1407
1408                                 /* move to end of chain */
1409                                 while (bone->parent != NULL) {
1410                                         bone = bone->parent;
1411                                         bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
1412                                 }
1413
1414                                 if (parent != NULL) {
1415                                         bone->parent = parent;
1416                                         bone->flag |= BONE_CONNECTED;
1417                                 }
1418
1419                                 parent = new_parent;
1420                                 head_index = i;
1421                                 head = pt;
1422                         }
1423                 }
1424         }
1425 }
1426
1427 static void sk_convert(bContext *C, SK_Sketch *sketch)
1428 {
1429         ToolSettings *ts = CTX_data_tool_settings(C);
1430         SK_Stroke *stk;
1431
1432         for (stk = sketch->strokes.first; stk; stk = stk->next) {
1433                 if (stk->selected == 1) {
1434                         if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) {
1435                                 sk_retargetStroke(C, stk);
1436                         }
1437                         else {
1438                                 sk_convertStroke(C, stk);
1439                         }
1440 //                      XXX
1441 //                      allqueue(REDRAWBUTSEDIT, 0);
1442                 }
1443         }
1444 }
1445 /******************* GESTURE *************************/
1446
1447
1448 /* returns the number of self intersections */
1449 static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gesture)
1450 {
1451         ARegion *ar = CTX_wm_region(C);
1452         int added = 0;
1453         int s_i;
1454
1455         for (s_i = 0; s_i < gesture->nb_points - 1; s_i++) {
1456                 float s_p1[3] = {0, 0, 0};
1457                 float s_p2[3] = {0, 0, 0};
1458                 int g_i;
1459
1460                 ED_view3d_project_float_global(ar, gesture->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP);
1461                 ED_view3d_project_float_global(ar, gesture->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP);
1462
1463                 /* start checking from second next, because two consecutive cannot intersect */
1464                 for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++) {
1465                         float g_p1[3] = {0, 0, 0};
1466                         float g_p2[3] = {0, 0, 0};
1467                         float vi[3];
1468                         float lambda;
1469
1470                         ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP);
1471                         ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP);
1472
1473                         if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) {
1474                                 SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
1475
1476                                 isect->gesture_index = g_i;
1477                                 isect->before = s_i;
1478                                 isect->after = s_i + 1;
1479                                 isect->stroke = gesture;
1480
1481                                 sub_v3_v3v3(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p);
1482                                 mul_v3_fl(isect->p, lambda);
1483                                 add_v3_v3(isect->p, gesture->points[s_i].p);
1484
1485                                 BLI_addtail(list, isect);
1486
1487                                 added++;
1488                         }
1489                 }
1490         }
1491
1492         return added;
1493 }
1494
1495 static int cmpIntersections(const void *i1, const void *i2)
1496 {
1497         const SK_Intersection *isect1 = i1, *isect2 = i2;
1498
1499         if (isect1->stroke == isect2->stroke) {
1500                 if (isect1->before < isect2->before) {
1501                         return -1;
1502                 }
1503                 else if (isect1->before > isect2->before) {
1504                         return 1;
1505                 }
1506                 else {
1507                         if (isect1->lambda < isect2->lambda) {
1508                                 return -1;
1509                         }
1510                         else if (isect1->lambda > isect2->lambda) {
1511                                 return 1;
1512                         }
1513                 }
1514         }
1515
1516         return 0;
1517 }
1518
1519
1520 /* returns the maximum number of intersections per stroke */
1521 static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
1522 {
1523         ARegion *ar = CTX_wm_region(C);
1524         ScrArea *sa = CTX_wm_area(C);
1525         View3D *v3d = sa->spacedata.first;
1526         SK_Stroke *stk;
1527         int added = 0;
1528
1529         for (stk = sketch->strokes.first; stk; stk = stk->next) {
1530                 int s_added = 0;
1531                 int s_i;
1532
1533                 for (s_i = 0; s_i < stk->nb_points - 1; s_i++) {
1534                         float s_p1[3] = {0, 0, 0};
1535                         float s_p2[3] = {0, 0, 0};
1536                         int g_i;
1537
1538                         ED_view3d_project_float_global(ar, stk->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP);
1539                         ED_view3d_project_float_global(ar, stk->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP);
1540
1541                         for (g_i = 0; g_i < gesture->nb_points - 1; g_i++) {
1542                                 float g_p1[3] = {0, 0, 0};
1543                                 float g_p2[3] = {0, 0, 0};
1544                                 float vi[3];
1545                                 float lambda;
1546
1547                                 ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP);
1548                                 ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP);
1549
1550                                 if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) {
1551                                         SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
1552                                         float ray_start[3], ray_end[3];
1553                                         float mval[2];
1554
1555                                         isect->gesture_index = g_i;
1556                                         isect->before = s_i;
1557                                         isect->after = s_i + 1;
1558                                         isect->stroke = stk;
1559                                         isect->lambda = lambda;
1560
1561                                         mval[0] = vi[0];
1562                                         mval[1] = vi[1];
1563                                         ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end, true);
1564
1565                                         isect_line_line_v3(stk->points[s_i].p,
1566                                                            stk->points[s_i + 1].p,
1567                                                            ray_start,
1568                                                            ray_end,
1569                                                            isect->p,
1570                                                            vi);
1571
1572                                         BLI_addtail(list, isect);
1573
1574                                         s_added++;
1575                                 }
1576                         }
1577                 }
1578
1579                 added = MAX2(s_added, added);
1580         }
1581
1582         BLI_sortlist(list, cmpIntersections);
1583
1584         return added;
1585 }
1586
1587 static int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
1588 {
1589         SK_StrokeIterator sk_iter;
1590         BArcIterator *iter = (BArcIterator *)&sk_iter;
1591
1592         float CORRELATION_THRESHOLD = 0.99f;
1593         float *vec;
1594         int i, j;
1595
1596         sk_appendStrokePoint(segments, &gesture->points[0]);
1597         vec = segments->points[segments->nb_points - 1].p;
1598
1599         initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1);
1600
1601         for (i = 1, j = 0; i < gesture->nb_points; i++) {
1602                 float n[3];
1603
1604                 /* Calculate normal */
1605                 sub_v3_v3v3(n, gesture->points[i].p, vec);
1606
1607                 if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD) {
1608                         j = i - 1;
1609                         sk_appendStrokePoint(segments, &gesture->points[j]);
1610                         vec = segments->points[segments->nb_points - 1].p;
1611                         segments->points[segments->nb_points - 1].type = PT_EXACT;
1612                 }
1613         }
1614
1615         sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]);
1616
1617         return segments->nb_points - 1;
1618 }
1619
1620 int sk_detectCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1621 {
1622         if (gest->nb_segments == 1 && gest->nb_intersections == 1) {
1623                 return 1;
1624         }
1625
1626         return 0;
1627 }
1628
1629 void sk_applyCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1630 {
1631         SK_Intersection *isect;
1632
1633         for (isect = gest->intersections.first; isect; isect = isect->next) {
1634                 SK_Point pt;
1635
1636                 pt.type = PT_EXACT;
1637                 pt.mode = PT_PROJECT; /* take mode from neighboring points */
1638                 copy_v3_v3(pt.p, isect->p);
1639                 copy_v3_v3(pt.no, isect->stroke->points[isect->before].no);
1640
1641                 sk_insertStrokePoint(isect->stroke, &pt, isect->after);
1642         }
1643 }
1644
1645 int sk_detectTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1646 {
1647         if (gest->nb_segments == 2 && gest->nb_intersections == 1 && gest->nb_self_intersections == 0) {
1648                 float s1[3], s2[3];
1649                 float angle;
1650
1651                 sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
1652                 sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
1653
1654                 angle = RAD2DEGF(angle_v2v2(s1, s2));
1655
1656                 if (angle > 60 && angle < 120) {
1657                         return 1;
1658                 }
1659         }
1660
1661         return 0;
1662 }
1663
1664 void sk_applyTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1665 {
1666         SK_Intersection *isect;
1667         float trim_dir[3];
1668
1669         sub_v3_v3v3(trim_dir, gest->segments->points[2].p, gest->segments->points[1].p);
1670
1671         for (isect = gest->intersections.first; isect; isect = isect->next) {
1672                 SK_Point pt;
1673                 float stroke_dir[3];
1674
1675                 pt.type = PT_EXACT;
1676                 pt.mode = PT_PROJECT; /* take mode from neighboring points */
1677                 copy_v3_v3(pt.p, isect->p);
1678                 copy_v3_v3(pt.no, isect->stroke->points[isect->before].no);
1679
1680                 sub_v3_v3v3(stroke_dir, isect->stroke->points[isect->after].p, isect->stroke->points[isect->before].p);
1681
1682                 /* same direction, trim end */
1683                 if (dot_v3v3(stroke_dir, trim_dir) > 0) {
1684                         sk_replaceStrokePoint(isect->stroke, &pt, isect->after);
1685                         sk_trimStroke(isect->stroke, 0, isect->after);
1686                 }
1687                 /* else, trim start */
1688                 else {
1689                         sk_replaceStrokePoint(isect->stroke, &pt, isect->before);
1690                         sk_trimStroke(isect->stroke, isect->before, isect->stroke->nb_points - 1);
1691                 }
1692
1693         }
1694 }
1695
1696 int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1697 {
1698         if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1) {
1699                 SK_Intersection *isect, *self_isect;
1700
1701                 /* get the last intersection of the first pair */
1702                 for (isect = gest->intersections.first; isect; isect = isect->next) {
1703                         if (isect->stroke == isect->next->stroke) {
1704                                 isect = isect->next;
1705                                 break;
1706                         }
1707                 }
1708
1709                 self_isect = gest->self_intersections.first;
1710
1711                 if (isect && isect->gesture_index < self_isect->gesture_index) {
1712                         return 1;
1713                 }
1714         }
1715
1716         return 0;
1717 }
1718
1719 void sk_applyCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1720 {
1721         SK_Intersection *isect;
1722         int command = 1;
1723
1724 /*      XXX */
1725 /*      command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3"); */
1726         if (command < 1) return;
1727
1728         for (isect = gest->intersections.first; isect; isect = isect->next) {
1729                 SK_Intersection *i2;
1730
1731                 i2 = isect->next;
1732
1733                 if (i2 && i2->stroke == isect->stroke) {
1734                         switch (command) {
1735                                 case 1:
1736                                         sk_flattenStroke(isect->stroke, isect->before, i2->after);
1737                                         break;
1738                                 case 2:
1739                                         sk_straightenStroke(isect->stroke, isect->before, i2->after, isect->p, i2->p);
1740                                         break;
1741                                 case 3:
1742                                         sk_polygonizeStroke(isect->stroke, isect->before, i2->after);
1743                                         break;
1744                         }
1745
1746                         isect = i2;
1747                 }
1748         }
1749 }
1750
1751 int sk_detectDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1752 {
1753         if (gest->nb_segments == 2 && gest->nb_intersections == 2) {
1754                 float s1[3], s2[3];
1755                 float angle;
1756
1757                 sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
1758                 sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
1759
1760                 angle = RAD2DEGF(angle_v2v2(s1, s2));
1761
1762                 if (angle > 120) {
1763                         return 1;
1764                 }
1765         }
1766
1767         return 0;
1768 }
1769
1770 void sk_applyDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *sketch)
1771 {
1772         SK_Intersection *isect;
1773
1774         for (isect = gest->intersections.first; isect; isect = isect->next) {
1775                 /* only delete strokes that are crossed twice */
1776                 if (isect->next && isect->next->stroke == isect->stroke) {
1777                         isect = isect->next;
1778
1779                         sk_removeStroke(sketch, isect->stroke);
1780                 }
1781         }
1782 }
1783
1784 int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1785 {
1786         ARegion *ar = CTX_wm_region(C);
1787         if (gest->nb_segments > 2 && gest->nb_intersections == 2) {
1788                 short start_val[2], end_val[2];
1789                 short dist;
1790
1791                 if ((ED_view3d_project_short_global(ar, gest->stk->points[0].p,           start_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
1792                     (ED_view3d_project_short_global(ar, sk_lastStrokePoint(gest->stk)->p, end_val,   V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
1793                 {
1794
1795                         dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1]));
1796
1797                         /* if gesture is a circle */
1798                         if (dist <= 20) {
1799                                 SK_Intersection *isect;
1800
1801                                 /* check if it circled around an exact point */
1802                                 for (isect = gest->intersections.first; isect; isect = isect->next) {
1803                                         /* only delete strokes that are crossed twice */
1804                                         if (isect->next && isect->next->stroke == isect->stroke) {
1805                                                 int start_index, end_index;
1806                                                 int i;
1807
1808                                                 start_index = MIN2(isect->after, isect->next->after);
1809                                                 end_index = MAX2(isect->before, isect->next->before);
1810
1811                                                 for (i = start_index; i <= end_index; i++) {
1812                                                         if (isect->stroke->points[i].type == PT_EXACT) {
1813                                                                 return 1; /* at least one exact point found, stop detect here */
1814                                                         }
1815                                                 }
1816
1817                                                 /* skip next */
1818                                                 isect = isect->next;
1819                                         }
1820                                 }
1821                         }
1822                 }
1823         }
1824
1825         return 0;
1826 }
1827
1828 void sk_applyMergeGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1829 {
1830         SK_Intersection *isect;
1831
1832         /* check if it circled around an exact point */
1833         for (isect = gest->intersections.first; isect; isect = isect->next) {
1834                 /* only merge strokes that are crossed twice */
1835                 if (isect->next && isect->next->stroke == isect->stroke) {
1836                         int start_index, end_index;
1837                         int i;
1838
1839                         start_index = MIN2(isect->after, isect->next->after);
1840                         end_index = MAX2(isect->before, isect->next->before);
1841
1842                         for (i = start_index; i <= end_index; i++) {
1843                                 /* if exact, switch to continuous */
1844                                 if (isect->stroke->points[i].type == PT_EXACT) {
1845                                         isect->stroke->points[i].type = PT_CONTINUOUS;
1846                                 }
1847                         }
1848
1849                         /* skip next */
1850                         isect = isect->next;
1851                 }
1852         }
1853 }
1854
1855 int sk_detectReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1856 {
1857         if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 0) {
1858                 SK_Intersection *isect;
1859
1860                 /* check if it circled around an exact point */
1861                 for (isect = gest->intersections.first; isect; isect = isect->next) {
1862                         /* only delete strokes that are crossed twice */
1863                         if (isect->next && isect->next->stroke == isect->stroke) {
1864                                 float start_v[3], end_v[3];
1865                                 float angle;
1866
1867                                 if (isect->gesture_index < isect->next->gesture_index) {
1868                                         sub_v3_v3v3(start_v, isect->p, gest->stk->points[0].p);
1869                                         sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->next->p);
1870                                 }
1871                                 else {
1872                                         sub_v3_v3v3(start_v, isect->next->p, gest->stk->points[0].p);
1873                                         sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p);
1874                                 }
1875
1876                                 angle = RAD2DEGF(angle_v2v2(start_v, end_v));
1877
1878                                 if (angle > 120) {
1879                                         return 1;
1880                                 }
1881
1882                                 /* skip next */
1883                                 isect = isect->next;
1884                         }
1885                 }
1886         }
1887
1888         return 0;
1889 }
1890
1891 void sk_applyReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1892 {
1893         SK_Intersection *isect;
1894
1895         for (isect = gest->intersections.first; isect; isect = isect->next) {
1896                 /* only reverse strokes that are crossed twice */
1897                 if (isect->next && isect->next->stroke == isect->stroke) {
1898                         sk_reverseStroke(isect->stroke);
1899
1900                         /* skip next */
1901                         isect = isect->next;
1902                 }
1903         }
1904 }
1905
1906 int sk_detectConvertGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
1907 {
1908         if (gest->nb_segments == 3 && gest->nb_self_intersections == 1) {
1909                 return 1;
1910         }
1911         return 0;
1912 }
1913
1914 void sk_applyConvertGesture(bContext *C, SK_Gesture *UNUSED(gest), SK_Sketch *sketch)
1915 {
1916         sk_convert(C, sketch);
1917 }
1918
1919 static void sk_initGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch)
1920 {
1921         BLI_listbase_clear(&gest->intersections);
1922         BLI_listbase_clear(&gest->self_intersections);
1923
1924         gest->segments = sk_createStroke();
1925         gest->stk = sketch->gesture;
1926
1927         gest->nb_self_intersections = sk_getSelfIntersections(C, &gest->self_intersections, gest->stk);
1928         gest->nb_intersections = sk_getIntersections(C, &gest->intersections, sketch, gest->stk);
1929         gest->nb_segments = sk_getSegments(gest->segments, gest->stk);
1930 }
1931
1932 static void sk_freeGesture(SK_Gesture *gest)
1933 {
1934         sk_freeStroke(gest->segments);
1935         BLI_freelistN(&gest->intersections);
1936         BLI_freelistN(&gest->self_intersections);
1937 }
1938
1939 static void sk_applyGesture(bContext *C, SK_Sketch *sketch)
1940 {
1941         SK_Gesture gest;
1942         SK_GestureAction *act;
1943
1944         sk_initGesture(C, &gest, sketch);
1945
1946         /* detect and apply */
1947         for (act = GESTURE_ACTIONS; act->apply != NULL; act++) {
1948                 if (act->detect(C, &gest, sketch)) {
1949                         act->apply(C, &gest, sketch);
1950                         break;
1951                 }
1952         }
1953
1954         sk_freeGesture(&gest);
1955 }
1956
1957 /********************************************/
1958
1959
1960 static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], int extend)
1961 {
1962         ViewContext vc;
1963         rcti rect;
1964         unsigned int buffer[MAXPICKBUF];
1965         short hits;
1966
1967         view3d_set_viewcontext(C, &vc);
1968
1969         rect.xmin = mval[0] - 5;
1970         rect.xmax = mval[0] + 5;
1971         rect.ymin = mval[1] - 5;
1972         rect.ymax = mval[1] + 5;
1973
1974         hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
1975
1976         if (hits > 0) {
1977                 int besthitresult = -1;
1978
1979                 if (hits == 1) {
1980                         besthitresult = buffer[3];
1981                 }
1982                 else {
1983                         besthitresult = buffer[3];
1984                         /* loop and get best hit */
1985                 }
1986
1987                 if (besthitresult > 0) {
1988                         SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1);
1989
1990                         if (extend == 0) {
1991                                 sk_selectAllSketch(sketch, -1);
1992
1993                                 selected_stk->selected = 1;
1994                         }
1995                         else {
1996                                 selected_stk->selected ^= 1;
1997                         }
1998
1999
2000                 }
2001                 return 1;
2002         }
2003
2004         return 0;
2005 }
2006
2007 #if 0 /* UNUSED 2.5 */
2008 static void sk_queueRedrawSketch(SK_Sketch *sketch)
2009 {
2010         if (sketch->active_stroke != NULL)
2011         {
2012                 SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
2013
2014                 if (last != NULL)
2015                 {
2016 //                      XXX
2017 //                      allqueue(REDRAWVIEW3D, 0);
2018                 }
2019         }
2020 }
2021 #endif
2022
2023 static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, int with_names)
2024 {
2025         ToolSettings *ts = scene->toolsettings;
2026         SK_Stroke *stk;
2027
2028         glClear(GL_DEPTH_BUFFER_BIT);
2029         glEnable(GL_DEPTH_TEST);
2030
2031         if (with_names) {
2032                 int id;
2033                 for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next) {
2034                         sk_drawStroke(stk, id, NULL, -1, -1);
2035                 }
2036
2037                 GPU_select_load_id(-1);
2038         }
2039         else {
2040                 float selected_rgb[3] = {1, 0, 0};
2041                 float unselected_rgb[3] = {1, 0.5, 0};
2042
2043                 for (stk = sketch->strokes.first; stk; stk = stk->next) {
2044                         int start = -1;
2045                         int end = -1;
2046
2047                         if (sk_hasOverdraw(sketch, stk)) {
2048                                 sk_adjustIndexes(sketch, &start, &end);
2049                         }
2050
2051                         sk_drawStroke(stk, -1, (stk->selected == 1 ? selected_rgb : unselected_rgb), start, end);
2052
2053                         if (stk->selected == 1) {
2054                                 sk_drawStrokeSubdivision(ts, stk);
2055                         }
2056                 }
2057
2058                 if (sketch->active_stroke != NULL) {
2059                         SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
2060
2061                         if (ts->bone_sketching & BONE_SKETCHING_QUICK) {
2062                                 sk_drawStrokeSubdivision(ts, sketch->active_stroke);
2063                         }
2064
2065                         if (last != NULL) {
2066                                 GLUquadric *quad = gluNewQuadric();
2067                                 gluQuadricNormals(quad, GLU_SMOOTH);
2068
2069                                 glPushMatrix();
2070
2071                                 glEnable(GL_BLEND);
2072                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2073
2074                                 switch (sketch->next_point.mode) {
2075                                         case PT_SNAP:
2076                                                 glColor3f(0, 1, 0);
2077                                                 break;
2078                                         case PT_PROJECT:
2079                                                 glColor3f(0, 0, 0);
2080                                                 break;
2081                                 }
2082
2083                                 sk_drawPoint(quad, &sketch->next_point, 0.1);
2084
2085                                 glColor4f(selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3);
2086
2087                                 sk_drawEdge(quad, last, &sketch->next_point, 0.1);
2088
2089                                 glDisable(GL_BLEND);
2090
2091                                 glPopMatrix();
2092
2093                                 gluDeleteQuadric(quad);
2094                         }
2095                 }
2096         }
2097
2098 #if 0
2099         if (BLI_listbase_is_empty(&sketch->depth_peels) == false) {
2100                 float colors[8][3] = {
2101                         {1, 0, 0},
2102                         {0, 1, 0},
2103                         {0, 0, 1},
2104                         {1, 1, 0},
2105                         {1, 0, 1},
2106                         {0, 1, 1},
2107                         {1, 1, 1},
2108                         {0, 0, 0}
2109                 };
2110                 DepthPeel *p;
2111                 GLUquadric *quad = gluNewQuadric();
2112                 gluQuadricNormals(quad, GLU_SMOOTH);
2113
2114                 for (p = sketch->depth_peels.first; p; p = p->next)
2115                 {
2116                         int index = GET_INT_FROM_POINTER(p->ob);
2117                         index = (index >> 5) & 7;
2118
2119                         glColor3fv(colors[index]);
2120                         glPushMatrix();
2121                         glTranslatef(p->p[0], p->p[1], p->p[2]);
2122                         gluSphere(quad, 0.02, 8, 8);
2123                         glPopMatrix();
2124                 }
2125
2126                 gluDeleteQuadric(quad);
2127         }
2128 #endif
2129
2130         glDisable(GL_DEPTH_TEST);
2131
2132         /* only draw gesture in active area */
2133         if (sketch->gesture != NULL /* && area_is_active_area(G.vd->area) */) {
2134                 float gesture_rgb[3] = {0, 0.5, 1};
2135                 sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1);
2136         }
2137 }
2138
2139 static int sk_finish_stroke(bContext *C, SK_Sketch *sketch)
2140 {
2141         ToolSettings *ts = CTX_data_tool_settings(C);
2142
2143         if (sketch->active_stroke != NULL) {
2144                 SK_Stroke *stk = sketch->active_stroke;
2145
2146                 sk_endStroke(C, sketch);
2147
2148                 if (ts->bone_sketching & BONE_SKETCHING_QUICK) {
2149                         if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) {
2150                                 sk_retargetStroke(C, stk);
2151                         }
2152                         else {
2153                                 sk_convertStroke(C, stk);
2154                         }
2155 //                      XXX
2156 //                      BIF_undo_push("Convert Sketch");
2157                         sk_removeStroke(sketch, stk);
2158 //                      XXX
2159 //                      allqueue(REDRAWBUTSEDIT, 0);
2160                 }
2161
2162 //              XXX
2163 //              allqueue(REDRAWVIEW3D, 0);
2164                 return 1;
2165         }
2166
2167         return 0;
2168 }
2169
2170 static void sk_start_draw_stroke(SK_Sketch *sketch)
2171 {
2172         if (sketch->active_stroke == NULL) {
2173                 sk_startStroke(sketch);
2174                 sk_selectAllSketch(sketch, -1);
2175
2176                 sketch->active_stroke->selected = 1;
2177         }
2178 }
2179
2180 static void sk_start_draw_gesture(SK_Sketch *sketch)
2181 {
2182         sketch->gesture = sk_createStroke();
2183 }
2184
2185 static int sk_draw_stroke(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, bool snap)
2186 {
2187         if (sk_stroke_filtermval(dd)) {
2188                 sk_addStrokePoint(C, sketch, stk, dd, snap);
2189                 sk_updateDrawData(dd);
2190                 sk_updateNextPoint(sketch, stk);
2191                 
2192                 return 1;
2193         }
2194
2195         return 0;
2196 }
2197
2198 static int ValidSketchViewContext(ViewContext *vc)
2199 {
2200         Object *obedit = vc->obedit;
2201         Scene *scene = vc->scene;
2202
2203         if (obedit &&
2204             obedit->type == OB_ARMATURE &&
2205             scene->toolsettings->bone_sketching & BONE_SKETCHING)
2206         {
2207                 return 1;
2208         }
2209         else {
2210                 return 0;
2211         }
2212 }
2213
2214 int BDR_drawSketchNames(ViewContext *vc)
2215 {
2216         if (ValidSketchViewContext(vc)) {
2217                 SK_Sketch *sketch = viewcontextSketch(vc, 0);
2218                 if (sketch) {
2219                         sk_drawSketch(vc->scene, vc->v3d, sketch, 1);
2220                         return 1;
2221                 }
2222         }
2223
2224         return 0;
2225 }
2226
2227 void BDR_drawSketch(const bContext *C)
2228 {
2229         if (ED_operator_sketch_mode(C)) {
2230                 SK_Sketch *sketch = contextSketch(C, 0);
2231                 if (sketch) {
2232                         sk_drawSketch(CTX_data_scene(C), CTX_wm_view3d(C), sketch, 0);
2233                 }
2234         }
2235 }
2236
2237 static int sketch_delete(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
2238 {
2239         SK_Sketch *sketch = contextSketch(C, 0);
2240         if (sketch) {
2241                 sk_deleteSelectedStrokes(sketch);
2242 //                      allqueue(REDRAWVIEW3D, 0);
2243         }
2244         WM_event_add_notifier(C, NC_SCREEN | ND_SKETCH | NA_REMOVED, NULL);
2245         return OPERATOR_FINISHED;
2246 }
2247
2248 void BIF_sk_selectStroke(bContext *C, const int mval[2], short extend)
2249 {
2250         ToolSettings *ts = CTX_data_tool_settings(C);
2251         SK_Sketch *sketch = contextSketch(C, 0);
2252
2253         if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING) {
2254                 if (sk_selectStroke(C, sketch, mval, extend))
2255                         ED_area_tag_redraw(CTX_wm_area(C));
2256         }
2257 }
2258
2259 void BIF_convertSketch(bContext *C)
2260 {
2261         if (ED_operator_sketch_full_mode(C)) {
2262                 SK_Sketch *sketch = contextSketch(C, 0);
2263                 if (sketch) {
2264                         sk_convert(C, sketch);
2265 //                      BIF_undo_push("Convert Sketch");
2266 //                      allqueue(REDRAWVIEW3D, 0);
2267 //                      allqueue(REDRAWBUTSEDIT, 0);
2268                 }
2269         }
2270 }
2271
2272 void BIF_deleteSketch(bContext *C)
2273 {
2274         if (ED_operator_sketch_full_mode(C)) {
2275                 SK_Sketch *sketch = contextSketch(C, 0);
2276                 if (sketch) {
2277                         sk_deleteSelectedStrokes(sketch);
2278 //                      BIF_undo_push("Convert Sketch");
2279 //                      allqueue(REDRAWVIEW3D, 0);
2280                 }
2281         }
2282 }
2283
2284 #if 0
2285 void BIF_selectAllSketch(bContext *C, int mode)
2286 {
2287         if (BIF_validSketchMode(C))
2288         {
2289                 SK_Sketch *sketch = contextSketch(C, 0);
2290                 if (sketch)
2291                 {
2292                         sk_selectAllSketch(sketch, mode);
2293 //                      XXX
2294 //                      allqueue(REDRAWVIEW3D, 0);
2295                 }
2296         }
2297 }
2298 #endif
2299
2300 SK_Sketch *contextSketch(const bContext *C, int create)
2301 {
2302         Object *obedit = CTX_data_edit_object(C);
2303         SK_Sketch *sketch = NULL;
2304
2305         if (obedit && obedit->type == OB_ARMATURE) {
2306                 bArmature *arm = obedit->data;
2307         
2308                 if (arm->sketch == NULL && create) {
2309                         arm->sketch = createSketch();
2310                 }
2311                 sketch = arm->sketch;
2312         }
2313
2314         return sketch;
2315 }
2316
2317 SK_Sketch *viewcontextSketch(ViewContext *vc, int create)
2318 {
2319         Object *obedit = vc->obedit;
2320         SK_Sketch *sketch = NULL;
2321
2322         if (obedit && obedit->type == OB_ARMATURE) {
2323                 bArmature *arm = obedit->data;
2324         
2325                 if (arm->sketch == NULL && create) {
2326                         arm->sketch = createSketch();
2327                 }
2328                 sketch = arm->sketch;
2329         }
2330
2331         return sketch;
2332 }
2333
2334 static int sketch_convert(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
2335 {
2336         SK_Sketch *sketch = contextSketch(C, 0);
2337         if (sketch != NULL) {
2338                 sk_convert(C, sketch);
2339                 ED_area_tag_redraw(CTX_wm_area(C));
2340         }
2341         return OPERATOR_FINISHED;
2342 }
2343
2344 static int sketch_cancel_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
2345 {
2346         SK_Sketch *sketch = contextSketch(C, 0);
2347         if (sketch != NULL) {
2348                 sk_cancelStroke(sketch);
2349                 ED_area_tag_redraw(CTX_wm_area(C));
2350                 return OPERATOR_FINISHED;
2351         }
2352         return OPERATOR_PASS_THROUGH;
2353 }
2354
2355 static int sketch_finish(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
2356 {
2357         SK_Sketch *sketch = contextSketch(C, 0);
2358         if (sketch != NULL) {
2359                 if (sk_finish_stroke(C, sketch)) {
2360                         ED_area_tag_redraw(CTX_wm_area(C));
2361                         return OPERATOR_FINISHED;
2362                 }
2363         }
2364         return OPERATOR_PASS_THROUGH;
2365 }
2366
2367 static int sketch_select(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
2368 {
2369         SK_Sketch *sketch = contextSketch(C, 0);
2370         if (sketch) {
2371                 short extend = 0;
2372                 if (sk_selectStroke(C, sketch, event->mval, extend))
2373                         ED_area_tag_redraw(CTX_wm_area(C));
2374         }
2375
2376         return OPERATOR_FINISHED;
2377 }
2378
2379 static void sketch_draw_stroke_cancel(bContext *C, wmOperator *op)
2380 {
2381         SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
2382         sk_cancelStroke(sketch);
2383         MEM_freeN(op->customdata);
2384 }
2385
2386 static int sketch_draw_stroke(bContext *C, wmOperator *op, const wmEvent *event)
2387 {
2388         const bool snap = RNA_boolean_get(op->ptr, "snap");
2389         SK_DrawData *dd;
2390         SK_Sketch *sketch = contextSketch(C, 1);
2391
2392         op->customdata = dd = MEM_callocN(sizeof(SK_DrawData), "SketchDrawData");
2393         sk_initDrawData(dd, event->mval);
2394
2395         sk_start_draw_stroke(sketch);
2396
2397         sk_draw_stroke(C, sketch, sketch->active_stroke, dd, snap);
2398
2399         WM_event_add_modal_handler(C, op);
2400
2401         return OPERATOR_RUNNING_MODAL;
2402 }
2403
2404 static void sketch_draw_gesture_cancel(bContext *C, wmOperator *op)
2405 {
2406         SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
2407         sk_cancelStroke(sketch);
2408         MEM_freeN(op->customdata);
2409 }
2410
2411 static int sketch_draw_gesture(bContext *C, wmOperator *op, const wmEvent *event)
2412 {
2413         const bool snap = RNA_boolean_get(op->ptr, "snap");
2414         SK_DrawData *dd;
2415         SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
2416         sk_cancelStroke(sketch);
2417
2418         op->customdata = dd = MEM_callocN(sizeof(SK_DrawData), "SketchDrawData");
2419         sk_initDrawData(dd, event->mval);
2420
2421         sk_start_draw_gesture(sketch);
2422         sk_draw_stroke(C, sketch, sketch->gesture, dd, snap);
2423
2424         WM_event_add_modal_handler(C, op);
2425
2426         return OPERATOR_RUNNING_MODAL;
2427 }
2428
2429 static int sketch_draw_modal(bContext *C, wmOperator *op, const wmEvent *event, short gesture, SK_Stroke *stk)
2430 {
2431         bool snap = RNA_boolean_get(op->ptr, "snap");
2432         SK_DrawData *dd = op->customdata;
2433         SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
2434         int retval = OPERATOR_RUNNING_MODAL;
2435
2436         switch (event->type) {
2437                 case LEFTCTRLKEY:
2438                 case RIGHTCTRLKEY:
2439                         snap = event->ctrl != 0;
2440                         RNA_boolean_set(op->ptr, "snap", snap);
2441                         break;
2442                 case MOUSEMOVE:
2443                 case INBETWEEN_MOUSEMOVE:
2444                         dd->mval[0] = event->mval[0];
2445                         dd->mval[1] = event->mval[1];
2446                         sk_draw_stroke(C, sketch, stk, dd, snap);
2447                         ED_area_tag_redraw(CTX_wm_area(C));
2448                         break;
2449                 case ESCKEY:
2450                         op->type->cancel(C, op);
2451                         ED_area_tag_redraw(CTX_wm_area(C));
2452                         retval = OPERATOR_CANCELLED;
2453                         break;
2454                 case LEFTMOUSE:
2455                         if (event->val == KM_RELEASE) {
2456                                 if (gesture == 0) {
2457                                         sk_endContinuousStroke(stk);
2458                                         sk_filterLastContinuousStroke(stk);
2459                                         sk_updateNextPoint(sketch, stk);
2460                                         ED_area_tag_redraw(CTX_wm_area(C));
2461                                         MEM_freeN(op->customdata);
2462                                         retval = OPERATOR_FINISHED;
2463                                 }
2464                                 else {
2465                                         sk_endContinuousStroke(stk);
2466                                         sk_filterLastContinuousStroke(stk);
2467
2468                                         if (stk->nb_points > 1) {
2469                                                 /* apply gesture here */
2470                                                 sk_applyGesture(C, sketch);
2471                                         }
2472
2473                                         sk_freeStroke(stk);
2474                                         sketch->gesture = NULL;
2475
2476                                         ED_area_tag_redraw(CTX_wm_area(C));
2477                                         MEM_freeN(op->customdata);
2478                                         retval = OPERATOR_FINISHED;
2479                                 }
2480                         }
2481                         break;
2482         }
2483
2484         return retval;
2485 }
2486
2487 static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
2488 {
2489         SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
2490         return sketch_draw_modal(C, op, event, 0, sketch->active_stroke);
2491 }
2492
2493 static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, const wmEvent *event)
2494 {
2495         SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
2496         return sketch_draw_modal(C, op, event, 1, sketch->gesture);
2497 }
2498
2499 static int sketch_draw_preview(bContext *C, wmOperator *op, const wmEvent *event)
2500 {
2501         const bool snap = RNA_boolean_get(op->ptr, "snap");
2502         SK_Sketch *sketch = contextSketch(C, 0);
2503
2504         if (sketch) {
2505                 SK_DrawData dd;
2506
2507                 sk_initDrawData(&dd, event->mval);
2508                 sk_getStrokePoint(C, &sketch->next_point, sketch, sketch->active_stroke, &dd, snap);
2509                 ED_area_tag_redraw(CTX_wm_area(C));
2510         }
2511
2512         return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
2513 }
2514
2515 /* ============================================== Poll Functions ============================================= */
2516
2517 int ED_operator_sketch_mode_active_stroke(bContext *C)
2518 {
2519         ToolSettings *ts = CTX_data_tool_settings(C);
2520         SK_Sketch *sketch = contextSketch(C, 0);
2521
2522         if (ts->bone_sketching & BONE_SKETCHING &&
2523             sketch != NULL &&
2524             sketch->active_stroke != NULL)
2525         {
2526                 return 1;
2527         }
2528         else {
2529                 return 0;
2530         }
2531 }
2532
2533 static int ED_operator_sketch_mode_gesture(bContext *C)
2534 {
2535         ToolSettings *ts = CTX_data_tool_settings(C);
2536         SK_Sketch *sketch = contextSketch(C, 0);
2537
2538         if (ts->bone_sketching & BONE_SKETCHING &&
2539             (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0 &&
2540             sketch != NULL &&
2541             sketch->active_stroke == NULL)
2542         {
2543                 return 1;
2544         }
2545         else {
2546                 return 0;
2547         }
2548 }
2549
2550 int ED_operator_sketch_full_mode(bContext *C)
2551 {
2552         Object *obedit = CTX_data_edit_object(C);
2553         ToolSettings *ts = CTX_data_tool_settings(C);
2554
2555         if (obedit &&
2556             obedit->type == OB_ARMATURE &&
2557             ts->bone_sketching & BONE_SKETCHING &&
2558             (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0)
2559         {
2560                 return 1;
2561         }
2562         else {
2563                 return 0;
2564         }
2565 }
2566
2567 int ED_operator_sketch_mode(const bContext *C)
2568 {
2569         Object *obedit = CTX_data_edit_object(C);
2570         ToolSettings *ts = CTX_data_tool_settings(C);
2571
2572         if (obedit &&
2573             obedit->type == OB_ARMATURE &&
2574             ts->bone_sketching & BONE_SKETCHING)
2575         {
2576                 return 1;
2577         }
2578         else {
2579                 return 0;
2580         }
2581 }
2582
2583 /* ================================================ Operators ================================================ */
2584
2585 void SKETCH_OT_delete(wmOperatorType *ot)
2586 {
2587         /* identifiers */
2588         ot->name = "Delete";
2589         ot->idname = "SKETCH_OT_delete";
2590         ot->description = "Delete a sketch stroke";
2591
2592         /* api callbacks */
2593         ot->invoke = sketch_delete;
2594
2595         ot->poll = ED_operator_sketch_full_mode;
2596
2597         /* flags */
2598 //      ot->flag = OPTYPE_UNDO;
2599 }
2600
2601 void SKETCH_OT_select(wmOperatorType *ot)
2602 {
2603         /* identifiers */
2604         ot->name = "Select";
2605         ot->idname = "SKETCH_OT_select";
2606         ot->description = "Select a sketch stroke";
2607
2608         /* api callbacks */
2609         ot->invoke = sketch_select;
2610
2611         ot->poll = ED_operator_sketch_full_mode;
2612
2613         /* flags */
2614 //      ot->flag = OPTYPE_UNDO;
2615 }
2616
2617 void SKETCH_OT_cancel_stroke(wmOperatorType *ot)
2618 {
2619         /* identifiers */
2620         ot->name = "Cancel Stroke";
2621         ot->idname = "SKETCH_OT_cancel_stroke";
2622         ot->description = "Cancel the current sketch stroke";
2623
2624         /* api callbacks */
2625         ot->invoke = sketch_cancel_invoke;
2626
2627         ot->poll = ED_operator_sketch_mode_active_stroke;
2628
2629         /* flags */
2630 //      ot->flag = OPTYPE_UNDO;
2631 }
2632
2633 void SKETCH_OT_convert(wmOperatorType *ot)
2634 {
2635         /* identifiers */
2636         ot->name = "Convert";
2637         ot->idname = "SKETCH_OT_convert";
2638         ot->description = "Convert the selected sketch strokes to bone chains";
2639
2640         /* api callbacks */
2641         ot->invoke = sketch_convert;
2642
2643         ot->poll = ED_operator_sketch_full_mode;
2644
2645         /* flags */
2646         ot->flag = OPTYPE_UNDO;
2647 }
2648
2649 void SKETCH_OT_finish_stroke(wmOperatorType *ot)
2650 {
2651         /* identifiers */
2652         ot->name = "End Stroke";
2653         ot->idname = "SKETCH_OT_finish_stroke";
2654         ot->description = "End and keep the current sketch stroke";
2655
2656         /* api callbacks */
2657         ot->invoke = sketch_finish;
2658
2659         ot->poll = ED_operator_sketch_mode_active_stroke;
2660
2661         /* flags */
2662 //      ot->flag = OPTYPE_UNDO;
2663 }
2664
2665 void SKETCH_OT_draw_preview(wmOperatorType *ot)
2666 {
2667         /* identifiers */
2668         ot->name = "Draw Preview";
2669         ot->idname = "SKETCH_OT_draw_preview";
2670         ot->description = "Draw preview of current sketch stroke (internal use)";
2671
2672         /* api callbacks */
2673         ot->invoke = sketch_draw_preview;
2674
2675         ot->poll = ED_operator_sketch_mode_active_stroke;
2676
2677         RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
2678
2679         /* flags */
2680 //      ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2681 }
2682
2683 void SKETCH_OT_draw_stroke(wmOperatorType *ot)
2684 {
2685         /* identifiers */
2686         ot->name = "Draw Stroke";
2687         ot->idname = "SKETCH_OT_draw_stroke";
2688         ot->description = "Start to draw a sketch stroke";
2689
2690         /* api callbacks */
2691         ot->invoke = sketch_draw_stroke;
2692         ot->modal  = sketch_draw_stroke_modal;
2693         ot->cancel = sketch_draw_stroke_cancel;
2694
2695         ot->poll = (int (*)(bContext *))ED_operator_sketch_mode;
2696
2697         RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
2698
2699         /* flags */
2700         ot->flag = OPTYPE_BLOCKING; // OPTYPE_REGISTER|OPTYPE_UNDO
2701 }
2702
2703 void SKETCH_OT_gesture(wmOperatorType *ot)
2704 {
2705         /* identifiers */
2706         ot->name = "Gesture";
2707         ot->idname = "SKETCH_OT_gesture";
2708         ot->description = "Start to draw a gesture stroke";
2709
2710         /* api callbacks */
2711         ot->invoke = sketch_draw_gesture;
2712         ot->modal  = sketch_draw_gesture_modal;
2713         ot->cancel = sketch_draw_gesture_cancel;
2714
2715         ot->poll = ED_operator_sketch_mode_gesture;
2716
2717         RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
2718
2719         /* flags */
2720         ot->flag = OPTYPE_BLOCKING; // OPTYPE_UNDO
2721 }
2722