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