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