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