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