Blender V2.61 - r43446

editarmature_sketch.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * ***** END GPL LICENSE BLOCK *****
00019  */
00020 
00026 #include <string.h>
00027 #include <math.h>
00028 #include <float.h>
00029 
00030 #include "MEM_guardedalloc.h"
00031 
00032 #include "DNA_object_types.h"
00033 #include "DNA_scene_types.h"
00034 #include "DNA_armature_types.h"
00035 
00036 #include "RNA_define.h"
00037 #include "RNA_access.h"
00038 
00039 #include "BLI_blenlib.h"
00040 #include "BLI_math.h"
00041 #include "BLI_utildefines.h"
00042 #include "BLI_graph.h"
00043 #include "BLI_ghash.h"
00044 
00045 #include "BKE_context.h"
00046 #include "BKE_sketch.h"
00047 
00048 #include "ED_view3d.h"
00049 #include "ED_screen.h"
00050 
00051 #include "BIF_gl.h"
00052 //#include "BIF_screen.h"
00053 //#include "BIF_space.h"
00054 //#include "BIF_mywindow.h"
00055 #include "ED_armature.h"
00056 #include "armature_intern.h"
00057 //#include "BIF_sketch.h"
00058 #include "BIF_retarget.h"
00059 #include "BIF_generate.h"
00060 //#include "BIF_interface.h"
00061 
00062 #include "ED_transform.h"
00063 
00064 #include "WM_api.h"
00065 #include "WM_types.h"
00066 
00067 //#include "blendef.h"
00068 //#include "mydevice.h"
00069 #include "reeb.h"
00070 
00071 
00072 
00073 typedef int  (*GestureDetectFct)(bContext*, SK_Gesture*, SK_Sketch *);
00074 typedef void (*GestureApplyFct)(bContext*, SK_Gesture*, SK_Sketch *);
00075 
00076 typedef struct SK_GestureAction {
00077     char name[64];
00078     GestureDetectFct    detect;
00079     GestureApplyFct     apply;
00080 } SK_GestureAction;
00081 
00082 #if 0 /* UNUSED 2.5 */
00083 static SK_Point boneSnap;
00084 #endif
00085 
00086 static int    LAST_SNAP_POINT_VALID = 0;
00087 static float  LAST_SNAP_POINT[3];
00088 
00089 
00090 typedef struct SK_StrokeIterator {
00091     HeadFct     head;
00092     TailFct     tail;
00093     PeekFct     peek;
00094     NextFct     next;
00095     NextNFct    nextN;
00096     PreviousFct previous;
00097     StoppedFct  stopped;
00098 
00099     float *p, *no;
00100     float size;
00101 
00102     int length;
00103     int index;
00104     /*********************************/
00105     SK_Stroke *stroke;
00106     int start;
00107     int end;
00108     int stride;
00109 } SK_StrokeIterator;
00110 
00111 /******************** PROTOTYPES ******************************/
00112 
00113 void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end);
00114 
00115 int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00116 void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00117 int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00118 void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00119 int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00120 void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00121 int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00122 void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00123 int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00124 void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00125 int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00126 void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00127 int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00128 void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
00129 
00130 SK_Sketch* contextSketch(const bContext *c, int create);
00131 SK_Sketch* viewcontextSketch(ViewContext *vc, int create);
00132 
00133 void sk_resetOverdraw(SK_Sketch *sketch);
00134 int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk);
00135 
00136 /******************** GESTURE ACTIONS ******************************/
00137 
00138 static SK_GestureAction GESTURE_ACTIONS[] =
00139     {
00140         {"Cut", sk_detectCutGesture, sk_applyCutGesture},
00141         {"Trim", sk_detectTrimGesture, sk_applyTrimGesture},
00142         {"Command", sk_detectCommandGesture, sk_applyCommandGesture},
00143         {"Delete", sk_detectDeleteGesture, sk_applyDeleteGesture},
00144         {"Merge", sk_detectMergeGesture, sk_applyMergeGesture},
00145         {"Reverse", sk_detectReverseGesture, sk_applyReverseGesture},
00146         {"Convert", sk_detectConvertGesture, sk_applyConvertGesture},
00147         {"", NULL, NULL}
00148     };
00149 
00150 /******************** TEMPLATES UTILS *************************/
00151 
00152 static char  *TEMPLATES_MENU = NULL;
00153 static int    TEMPLATES_CURRENT = 0;
00154 static GHash *TEMPLATES_HASH = NULL;
00155 static RigGraph *TEMPLATE_RIGG = NULL;
00156 
00157 void BIF_makeListTemplates(const bContext *C)
00158 {
00159     Object *obedit = CTX_data_edit_object(C);
00160     Scene *scene = CTX_data_scene(C);
00161     ToolSettings *ts = CTX_data_tool_settings(C);
00162     Base *base;
00163     int index = 0;
00164 
00165     if (TEMPLATES_HASH != NULL)
00166     {
00167         BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
00168     }
00169 
00170     TEMPLATES_HASH = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "makeListTemplates gh");
00171     TEMPLATES_CURRENT = 0;
00172 
00173     for ( base = FIRSTBASE; base; base = base->next )
00174     {
00175         Object *ob = base->object;
00176 
00177         if (ob != obedit && ob->type == OB_ARMATURE)
00178         {
00179             index++;
00180             BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob);
00181 
00182             if (ob == ts->skgen_template)
00183             {
00184                 TEMPLATES_CURRENT = index;
00185             }
00186         }
00187     }
00188 }
00189 
00190 const char *BIF_listTemplates(const bContext *UNUSED(C))
00191 {
00192     GHashIterator ghi;
00193     char menu_header[] = "Template%t|None%x0|";
00194     char *p;
00195 
00196     if (TEMPLATES_MENU != NULL)
00197     {
00198         MEM_freeN(TEMPLATES_MENU);
00199     }
00200 
00201     TEMPLATES_MENU = MEM_callocN(sizeof(char) * (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30), "skeleton template menu");
00202 
00203     p = TEMPLATES_MENU;
00204 
00205     p += sprintf(TEMPLATES_MENU, "%s", menu_header);
00206 
00207     BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
00208 
00209     while (!BLI_ghashIterator_isDone(&ghi))
00210     {
00211         Object *ob = BLI_ghashIterator_getValue(&ghi);
00212         int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
00213 
00214         p += sprintf(p, "|%s%%x%i", ob->id.name+2, key);
00215 
00216         BLI_ghashIterator_step(&ghi);
00217     }
00218 
00219     return TEMPLATES_MENU;
00220 }
00221 
00222 int   BIF_currentTemplate(const bContext *C)
00223 {
00224     ToolSettings *ts = CTX_data_tool_settings(C);
00225 
00226     if (TEMPLATES_CURRENT == 0 && ts->skgen_template != NULL)
00227     {
00228         GHashIterator ghi;
00229         BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
00230 
00231         while (!BLI_ghashIterator_isDone(&ghi))
00232         {
00233             Object *ob = BLI_ghashIterator_getValue(&ghi);
00234             int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
00235 
00236             if (ob == ts->skgen_template)
00237             {
00238                 TEMPLATES_CURRENT = key;
00239                 break;
00240             }
00241 
00242             BLI_ghashIterator_step(&ghi);
00243         }
00244     }
00245 
00246     return TEMPLATES_CURRENT;
00247 }
00248 
00249 static RigGraph* sk_makeTemplateGraph(const bContext *C, Object *ob)
00250 {
00251     Object *obedit = CTX_data_edit_object(C);
00252     if (ob == obedit)
00253     {
00254         return NULL;
00255     }
00256 
00257     if (ob != NULL)
00258     {
00259         if (TEMPLATE_RIGG && TEMPLATE_RIGG->ob != ob)
00260         {
00261             RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG);
00262             TEMPLATE_RIGG = NULL;
00263         }
00264 
00265         if (TEMPLATE_RIGG == NULL)
00266         {
00267             bArmature *arm;
00268 
00269             arm = ob->data;
00270 
00271             TEMPLATE_RIGG = RIG_graphFromArmature(C, ob, arm);
00272         }
00273     }
00274 
00275     return TEMPLATE_RIGG;
00276 }
00277 
00278 int BIF_nbJointsTemplate(const bContext *C)
00279 {
00280     ToolSettings *ts = CTX_data_tool_settings(C);
00281     RigGraph *rg = sk_makeTemplateGraph(C, ts->skgen_template);
00282 
00283     if (rg)
00284     {
00285         return RIG_nbJoints(rg);
00286     }
00287     else
00288     {
00289         return -1;
00290     }
00291 }
00292 
00293 const char * BIF_nameBoneTemplate(const bContext *C)
00294 {
00295     ToolSettings *ts = CTX_data_tool_settings(C);
00296     SK_Sketch *stk = contextSketch(C, 1);
00297     RigGraph *rg;
00298     int index = 0;
00299 
00300     if (stk && stk->active_stroke != NULL)
00301     {
00302         index = stk->active_stroke->nb_points;
00303     }
00304 
00305     rg = sk_makeTemplateGraph(C, ts->skgen_template);
00306 
00307     if (rg == NULL)
00308     {
00309         return "";
00310     }
00311 
00312     return RIG_nameBone(rg, 0, index);
00313 }
00314 
00315 void  BIF_freeTemplates(bContext *UNUSED(C))
00316 {
00317     if (TEMPLATES_MENU != NULL)
00318     {
00319         MEM_freeN(TEMPLATES_MENU);
00320         TEMPLATES_MENU = NULL;
00321     }
00322 
00323     if (TEMPLATES_HASH != NULL)
00324     {
00325         BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
00326         TEMPLATES_HASH = NULL;
00327     }
00328 
00329     if (TEMPLATE_RIGG != NULL)
00330     {
00331         RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG);
00332         TEMPLATE_RIGG = NULL;
00333     }
00334 }
00335 
00336 void  BIF_setTemplate(bContext *C, int index)
00337 {
00338     ToolSettings *ts = CTX_data_tool_settings(C);
00339     if (index > 0)
00340     {
00341         ts->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index));
00342     }
00343     else
00344     {
00345         ts->skgen_template = NULL;
00346 
00347         if (TEMPLATE_RIGG != NULL)
00348         {
00349             RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG);
00350         }
00351         TEMPLATE_RIGG = NULL;
00352     }
00353 }
00354 
00355 /*********************** CONVERSION ***************************/
00356 
00357 static void sk_autoname(bContext *C, ReebArc *arc)
00358 {
00359     ToolSettings *ts = CTX_data_tool_settings(C);
00360     if (ts->skgen_retarget_options & SK_RETARGET_AUTONAME)
00361     {
00362         if (arc == NULL)
00363         {
00364             char *num = ts->skgen_num_string;
00365             int i = atoi(num);
00366             i++;
00367             BLI_snprintf(num, 8, "%i", i);
00368         }
00369         else
00370         {
00371             char *side = ts->skgen_side_string;
00372             int valid = 0;
00373             int caps = 0;
00374 
00375             if (side[0] == '\0')
00376             {
00377                 valid = 1;
00378             }
00379             else if (strcmp(side, "R")==0 || strcmp(side, "L")==0)
00380             {
00381                 valid = 1;
00382                 caps = 1;
00383             }
00384             else if (strcmp(side, "r")==0 || strcmp(side, "l")==0)
00385             {
00386                 valid = 1;
00387                 caps = 0;
00388             }
00389 
00390             if (valid)
00391             {
00392                 if (arc->head->p[0] < 0)
00393                 {
00394                     BLI_snprintf(side, 8, caps?"R":"r");
00395                 }
00396                 else
00397                 {
00398                     BLI_snprintf(side, 8, caps?"L":"l");
00399                 }
00400             }
00401         }
00402     }
00403 }
00404 
00405 static ReebNode *sk_pointToNode(SK_Point *pt, float imat[][4], float tmat[][3])
00406 {
00407     ReebNode *node;
00408 
00409     node = MEM_callocN(sizeof(ReebNode), "reeb node");
00410     copy_v3_v3(node->p, pt->p);
00411     mul_m4_v3(imat, node->p);
00412 
00413     copy_v3_v3(node->no, pt->no);
00414     mul_m3_v3(tmat, node->no);
00415 
00416     return node;
00417 }
00418 
00419 static ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[][4], float tmat[][3])
00420 {
00421     ReebArc *arc;
00422     int i;
00423 
00424     arc = MEM_callocN(sizeof(ReebArc), "reeb arc");
00425     arc->head = sk_pointToNode(stk->points, imat, tmat);
00426     arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat);
00427 
00428     arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */
00429     arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets");
00430 
00431     for (i = 0; i < arc->bcount; i++)
00432     {
00433         copy_v3_v3(arc->buckets[i].p, stk->points[i + 1].p);
00434         mul_m4_v3(imat, arc->buckets[i].p);
00435 
00436         copy_v3_v3(arc->buckets[i].no, stk->points[i + 1].no);
00437         mul_m3_v3(tmat, arc->buckets[i].no);
00438     }
00439 
00440     return arc;
00441 }
00442 
00443 static void sk_retargetStroke(bContext *C, SK_Stroke *stk)
00444 {
00445     ToolSettings *ts = CTX_data_tool_settings(C);
00446     Object *obedit = CTX_data_edit_object(C);
00447     float imat[4][4];
00448     float tmat[3][3];
00449     ReebArc *arc;
00450     RigGraph *rg;
00451 
00452     invert_m4_m4(imat, obedit->obmat);
00453 
00454     copy_m3_m4(tmat, obedit->obmat);
00455     transpose_m3(tmat);
00456 
00457     arc = sk_strokeToArc(stk, imat, tmat);
00458 
00459     sk_autoname(C, arc);
00460 
00461     rg = sk_makeTemplateGraph(C, ts->skgen_template);
00462 
00463     BIF_retargetArc(C, arc, rg);
00464 
00465     sk_autoname(C, NULL);
00466 
00467     MEM_freeN(arc->head);
00468     MEM_freeN(arc->tail);
00469     REEB_freeArc((BArc*)arc);
00470 }
00471 
00472 /**************************************************************/
00473 
00474 static void sk_cancelStroke(SK_Sketch *sketch)
00475 {
00476     if (sketch->active_stroke != NULL)
00477     {
00478         sk_resetOverdraw(sketch);
00479         sk_removeStroke(sketch, sketch->active_stroke);
00480     }
00481 }
00482 
00483 
00484 static float sk_clampPointSize(SK_Point *pt, float size)
00485 {
00486     return MAX2(size * pt->size, size / 2);
00487 }
00488 
00489 static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size)
00490 {
00491     glTranslatef(pt->p[0], pt->p[1], pt->p[2]);
00492     gluSphere(quad, sk_clampPointSize(pt, size), 8, 8);
00493 }
00494 
00495 static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float size)
00496 {
00497     float vec1[3], vec2[3] = {0, 0, 1}, axis[3];
00498     float angle, length;
00499 
00500     sub_v3_v3v3(vec1, pt1->p, pt0->p);
00501     length = normalize_v3(vec1);
00502     cross_v3_v3v3(axis, vec2, vec1);
00503 
00504     if (is_zero_v3(axis))
00505     {
00506         axis[1] = 1;
00507     }
00508 
00509     angle = angle_normalized_v3v3(vec2, vec1);
00510 
00511     glRotatef(angle * (float)(180.0/M_PI) + 180.0f, axis[0], axis[1], axis[2]);
00512 
00513     gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8);
00514 }
00515 
00516 static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float height)
00517 {
00518     float vec2[3] = {0, 0, 1}, axis[3];
00519     float angle;
00520     
00521     glPushMatrix();
00522 
00523     cross_v3_v3v3(axis, vec2, pt->no);
00524 
00525     if (is_zero_v3(axis))
00526     {
00527         axis[1] = 1;
00528     }
00529 
00530     angle = angle_normalized_v3v3(vec2, pt->no);
00531 
00532     glRotatef(angle * (float)(180.0/M_PI), axis[0], axis[1], axis[2]);
00533 
00534     glColor3f(0, 1, 1);
00535     gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2);
00536 
00537     glPopMatrix();
00538 }
00539 
00540 static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end)
00541 {
00542     float rgb[3];
00543     int i;
00544     GLUquadric *quad = gluNewQuadric();
00545     gluQuadricNormals(quad, GLU_SMOOTH);
00546 
00547     if (id != -1)
00548     {
00549         glLoadName(id);
00550 
00551         for (i = 0; i < stk->nb_points; i++)
00552         {
00553             glPushMatrix();
00554 
00555             sk_drawPoint(quad, stk->points + i, 0.1);
00556 
00557             if (i > 0)
00558             {
00559                 sk_drawEdge(quad, stk->points + i - 1, stk->points + i, 0.1);
00560             }
00561 
00562             glPopMatrix();
00563         }
00564 
00565     }
00566     else
00567     {
00568         float d_rgb[3] = {1, 1, 1};
00569 
00570         copy_v3_v3(rgb, color);
00571         sub_v3_v3(d_rgb, rgb);
00572         mul_v3_fl(d_rgb, 1.0f / (float)stk->nb_points);
00573 
00574         for (i = 0; i < stk->nb_points; i++)
00575         {
00576             SK_Point *pt = stk->points + i;
00577 
00578             glPushMatrix();
00579 
00580             if (pt->type == PT_EXACT)
00581             {
00582                 glColor3f(0, 0, 0);
00583                 sk_drawPoint(quad, pt, 0.15);
00584                 sk_drawNormal(quad, pt, 0.05, 0.9);
00585             }
00586 
00587             if (i >= start && i <= end)
00588             {
00589                 glColor3f(0.3, 0.3, 0.3);
00590             }
00591             else
00592             {
00593                 glColor3fv(rgb);
00594             }
00595 
00596             if (pt->type != PT_EXACT)
00597             {
00598 
00599                 sk_drawPoint(quad, pt, 0.1);
00600             }
00601 
00602             if (i > 0)
00603             {
00604                 sk_drawEdge(quad, pt - 1, pt, 0.1);
00605             }
00606 
00607             glPopMatrix();
00608 
00609             add_v3_v3(rgb, d_rgb);
00610         }
00611     }
00612 
00613     gluDeleteQuadric(quad);
00614 }
00615 
00616 static void drawSubdividedStrokeBy(ToolSettings *toolsettings, BArcIterator *iter, NextSubdivisionFunc next_subdividion)
00617 {
00618     SK_Stroke *stk = ((SK_StrokeIterator*)iter)->stroke;
00619     float head[3], tail[3];
00620     int bone_start = 0;
00621     int end = iter->length;
00622     int index;
00623     GLUquadric *quad = gluNewQuadric();
00624     gluQuadricNormals(quad, GLU_SMOOTH);
00625 
00626     iter->head(iter);
00627     copy_v3_v3(head, iter->p);
00628 
00629     index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
00630     while (index != -1)
00631     {
00632         SK_Point *pt = stk->points + index;
00633 
00634         glPushMatrix();
00635 
00636         glColor3f(0, 1, 0);
00637         sk_drawPoint(quad, pt, 0.15);
00638 
00639         sk_drawNormal(quad, pt, 0.05, 0.9);
00640 
00641         glPopMatrix();
00642 
00643         copy_v3_v3(head, tail);
00644         bone_start = index; // start next bone from current index
00645 
00646         index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
00647     }
00648 
00649     gluDeleteQuadric(quad);
00650 }
00651 
00652 static void sk_drawStrokeSubdivision(ToolSettings *toolsettings, SK_Stroke *stk)
00653 {
00654     int head_index = -1;
00655     int i;
00656 
00657     if (toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET)
00658     {
00659         return;
00660     }
00661 
00662 
00663     for (i = 0; i < stk->nb_points; i++)
00664     {
00665         SK_Point *pt = stk->points + i;
00666 
00667         if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */
00668         {
00669             if (head_index == -1)
00670             {
00671                 head_index = i;
00672             }
00673             else
00674             {
00675                 if (i - head_index > 1)
00676                 {
00677                     SK_StrokeIterator sk_iter;
00678                     BArcIterator *iter = (BArcIterator*)&sk_iter;
00679 
00680                     initStrokeIterator(iter, stk, head_index, i);
00681 
00682                     if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE)
00683                     {
00684                         drawSubdividedStrokeBy(toolsettings, iter, nextAdaptativeSubdivision);
00685                     }
00686                     else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
00687                     {
00688                         drawSubdividedStrokeBy(toolsettings, iter, nextLengthSubdivision);
00689                     }
00690                     else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
00691                     {
00692                         drawSubdividedStrokeBy(toolsettings, iter, nextFixedSubdivision);
00693                     }
00694 
00695                 }
00696 
00697                 head_index = i;
00698             }
00699         }
00700     }
00701 }
00702 
00703 static SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, int mval[2], int *dist, int *index, int all_pts)
00704 {
00705     ARegion *ar = CTX_wm_region(C);
00706     SK_Point *pt = NULL;
00707     int i;
00708 
00709     for (i = 0; i < stk->nb_points; i++)
00710     {
00711         if (all_pts || stk->points[i].type == PT_EXACT)
00712         {
00713             short pval[2];
00714             int pdist;
00715 
00716             project_short_noclip(ar, stk->points[i].p, pval);
00717 
00718             pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
00719 
00720             if (pdist < *dist)
00721             {
00722                 *dist = pdist;
00723                 pt = stk->points + i;
00724 
00725                 if (index != NULL)
00726                 {
00727                     *index = i;
00728                 }
00729             }
00730         }
00731     }
00732 
00733     return pt;
00734 }
00735 
00736 #if 0 /* UNUSED 2.5 */
00737 static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, int mval[2], int *dist)
00738 {
00739     ARegion *ar = CTX_wm_region(C);
00740     SK_Point *pt = NULL;
00741     EditBone *bone;
00742 
00743     for (bone = ebones->first; bone; bone = bone->next)
00744     {
00745         float vec[3];
00746         short pval[2];
00747         int pdist;
00748 
00749         if ((bone->flag & BONE_CONNECTED) == 0)
00750         {
00751             copy_v3_v3(vec, bone->head);
00752             mul_m4_v3(ob->obmat, vec);
00753             project_short_noclip(ar, vec, pval);
00754 
00755             pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
00756 
00757             if (pdist < *dist)
00758             {
00759                 *dist = pdist;
00760                 pt = &boneSnap;
00761                 copy_v3_v3(pt->p, vec);
00762                 pt->type = PT_EXACT;
00763             }
00764         }
00765 
00766 
00767         copy_v3_v3(vec, bone->tail);
00768         mul_m4_v3(ob->obmat, vec);
00769         project_short_noclip(ar, vec, pval);
00770 
00771         pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
00772 
00773         if (pdist < *dist)
00774         {
00775             *dist = pdist;
00776             pt = &boneSnap;
00777             copy_v3_v3(pt->p, vec);
00778             pt->type = PT_EXACT;
00779         }
00780     }
00781 
00782     return pt;
00783 }
00784 #endif
00785 
00786 void sk_resetOverdraw(SK_Sketch *sketch)
00787 {
00788     sketch->over.target = NULL;
00789     sketch->over.start = -1;
00790     sketch->over.end = -1;
00791     sketch->over.count = 0;
00792 }
00793 
00794 int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk)
00795 {
00796     return  sketch->over.target &&
00797             sketch->over.count >= SK_OVERDRAW_LIMIT &&
00798             (sketch->over.target == stk || stk == NULL) &&
00799             (sketch->over.start != -1 || sketch->over.end != -1);
00800 }
00801 
00802 static void sk_updateOverdraw(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
00803 {
00804     if (sketch->over.target == NULL)
00805     {
00806         SK_Stroke *target;
00807         int closest_index = -1;
00808         int dist = SNAP_MIN_DISTANCE * 2;
00809 
00810         for (target = sketch->strokes.first; target; target = target->next)
00811         {
00812             if (target != stk)
00813             {
00814                 int index;
00815 
00816                 SK_Point *spt = sk_snapPointStroke(C, target, dd->mval, &dist, &index, 1);
00817 
00818                 if (spt != NULL)
00819                 {
00820                     sketch->over.target = target;
00821                     closest_index = index;
00822                 }
00823             }
00824         }
00825 
00826         if (sketch->over.target != NULL)
00827         {
00828             if (closest_index > -1)
00829             {
00830                 if (sk_lastStrokePoint(stk)->type == PT_EXACT)
00831                 {
00832                     sketch->over.count = SK_OVERDRAW_LIMIT;
00833                 }
00834                 else
00835                 {
00836                     sketch->over.count++;
00837                 }
00838             }
00839 
00840             if (stk->nb_points == 1)
00841             {
00842                 sketch->over.start = closest_index;
00843             }
00844             else
00845             {
00846                 sketch->over.end = closest_index;
00847             }
00848         }
00849     }
00850     else if (sketch->over.target != NULL)
00851     {
00852         SK_Point *closest_pt = NULL;
00853         int dist = SNAP_MIN_DISTANCE * 2;
00854         int index;
00855 
00856         closest_pt = sk_snapPointStroke(C, sketch->over.target, dd->mval, &dist, &index, 1);
00857 
00858         if (closest_pt != NULL)
00859         {
00860             if (sk_lastStrokePoint(stk)->type == PT_EXACT)
00861             {
00862                 sketch->over.count = SK_OVERDRAW_LIMIT;
00863             }
00864             else
00865             {
00866                 sketch->over.count++;
00867             }
00868 
00869             sketch->over.end = index;
00870         }
00871         else
00872         {
00873             sketch->over.end = -1;
00874         }
00875     }
00876 }
00877 
00878 /* return 1 on reverse needed */
00879 static int sk_adjustIndexes(SK_Sketch *sketch, int *start, int *end)
00880 {
00881     int retval = 0;
00882 
00883     *start = sketch->over.start;
00884     *end = sketch->over.end;
00885 
00886     if (*start == -1)
00887     {
00888         *start = 0;
00889     }
00890 
00891     if (*end == -1)
00892     {
00893         *end = sketch->over.target->nb_points - 1;
00894     }
00895 
00896     if (*end < *start)
00897     {
00898         int tmp = *start;
00899         *start = *end;
00900         *end = tmp;
00901         retval = 1;
00902     }
00903 
00904     return retval;
00905 }
00906 
00907 static void sk_endOverdraw(SK_Sketch *sketch)
00908 {
00909     SK_Stroke *stk = sketch->active_stroke;
00910 
00911     if (sk_hasOverdraw(sketch, NULL))
00912     {
00913         int start;
00914         int end;
00915 
00916         if (sk_adjustIndexes(sketch, &start, &end))
00917         {
00918             sk_reverseStroke(stk);
00919         }
00920 
00921         if (stk->nb_points > 1)
00922         {
00923             stk->points->type = sketch->over.target->points[start].type;
00924             sk_lastStrokePoint(stk)->type = sketch->over.target->points[end].type;
00925         }
00926 
00927         sk_insertStrokePoints(sketch->over.target, stk->points, stk->nb_points, start, end);
00928 
00929         sk_removeStroke(sketch, stk);
00930 
00931         sk_resetOverdraw(sketch);
00932     }
00933 }
00934 
00935 
00936 static void sk_startStroke(SK_Sketch *sketch)
00937 {
00938     SK_Stroke *stk = sk_createStroke();
00939 
00940     BLI_addtail(&sketch->strokes, stk);
00941     sketch->active_stroke = stk;
00942 
00943     sk_resetOverdraw(sketch);
00944 }
00945 
00946 static void sk_endStroke(bContext *C, SK_Sketch *sketch)
00947 {
00948     ToolSettings *ts = CTX_data_tool_settings(C);
00949     sk_shrinkStrokeBuffer(sketch->active_stroke);
00950 
00951     if (ts->bone_sketching & BONE_SKETCHING_ADJUST)
00952     {
00953         sk_endOverdraw(sketch);
00954     }
00955 
00956     sketch->active_stroke = NULL;
00957 }
00958 
00959 static void sk_updateDrawData(SK_DrawData *dd)
00960 {
00961     dd->type = PT_CONTINUOUS;
00962 
00963     dd->previous_mval[0] = dd->mval[0];
00964     dd->previous_mval[1] = dd->mval[1];
00965 }
00966 
00967 static float sk_distanceDepth(bContext *C, float p1[3], float p2[3])
00968 {
00969     ARegion *ar = CTX_wm_region(C);
00970     RegionView3D *rv3d = ar->regiondata;
00971     float vec[3];
00972     float distance;
00973 
00974     sub_v3_v3v3(vec, p1, p2);
00975 
00976     project_v3_v3v3(vec, vec, rv3d->viewinv[2]);
00977 
00978     distance = len_v3(vec);
00979 
00980     if (dot_v3v3(rv3d->viewinv[2], vec) > 0)
00981     {
00982         distance *= -1;
00983     }
00984 
00985     return distance;
00986 }
00987 
00988 static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float length, float distance)
00989 {
00990     ARegion *ar = CTX_wm_region(C);
00991     ScrArea *sa = CTX_wm_area(C);
00992     View3D *v3d = sa->spacedata.first;
00993 
00994     float progress = 0;
00995     int i;
00996 
00997     progress = len_v3v3(stk->points[start].p, stk->points[start - 1].p);
00998 
00999     for (i = start; i <= end; i++)
01000     {
01001         float ray_start[3], ray_normal[3];
01002         float delta = len_v3v3(stk->points[i].p, stk->points[i + 1].p);
01003         float pval[2];
01004 
01005         project_float(ar, stk->points[i].p, pval);
01006         ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal);
01007 
01008         mul_v3_fl(ray_normal, distance * progress / length);
01009         add_v3_v3(stk->points[i].p, ray_normal);
01010 
01011         progress += delta ;
01012     }
01013 }
01014 
01015 static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_DrawData *dd)
01016 {
01017     ARegion *ar = CTX_wm_region(C);
01018     /* copied from grease pencil, need fixing */
01019     SK_Point *last = sk_lastStrokePoint(stk);
01020     short cval[2];
01021     float fp[3] = {0, 0, 0};
01022     float dvec[3];
01023     float mval_f[2];
01024 
01025     if (last != NULL)
01026     {
01027         copy_v3_v3(fp, last->p);
01028     }
01029 
01030     initgrabz(ar->regiondata, fp[0], fp[1], fp[2]);
01031 
01032     /* method taken from editview.c - mouse_cursor() */
01033     project_short_noclip(ar, fp, cval);
01034     VECSUB2D(mval_f, cval, dd->mval);
01035     ED_view3d_win_to_delta(ar, mval_f, dvec);
01036     sub_v3_v3v3(vec, fp, dvec);
01037 }
01038 
01039 static int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *UNUSED(sketch), SK_Stroke *stk, SK_DrawData *dd)
01040 {
01041     pt->type = dd->type;
01042     pt->mode = PT_PROJECT;
01043     sk_projectDrawPoint(C, pt->p, stk, dd);
01044 
01045     return 1;
01046 }
01047 
01048 static int sk_addStrokeDrawPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
01049 {
01050     ARegion *ar = CTX_wm_region(C);
01051     RegionView3D *rv3d = ar->regiondata;
01052     SK_Point pt;
01053 
01054     sk_initPoint(&pt, dd, rv3d->viewinv[2]);
01055 
01056     sk_getStrokeDrawPoint(C, &pt, sketch, stk, dd);
01057 
01058     sk_appendStrokePoint(stk, &pt);
01059 
01060     return 1;
01061 }
01062 
01063 static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
01064 {
01065     ToolSettings *ts = CTX_data_tool_settings(C);
01066     int point_added = 0;
01067 
01068     if (ts->snap_mode == SCE_SNAP_MODE_VOLUME)
01069     {
01070         DepthPeel *p1, *p2;
01071         float *last_p = NULL;
01072         float dist = FLT_MAX;
01073         float p[3] = {0};
01074         float size = 0;
01075         float mvalf[2];
01076 
01077         BLI_freelistN(&sketch->depth_peels);
01078         sketch->depth_peels.first = sketch->depth_peels.last = NULL;
01079 
01080         mvalf[0]= dd->mval[0];
01081         mvalf[1]= dd->mval[1];
01082         peelObjectsContext(C, &sketch->depth_peels, mvalf);
01083 
01084         if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS)
01085         {
01086             last_p = stk->points[stk->nb_points - 1].p;
01087         }
01088         else if (LAST_SNAP_POINT_VALID)
01089         {
01090             last_p = LAST_SNAP_POINT;
01091         }
01092 
01093 
01094         for (p1 = sketch->depth_peels.first; p1; p1 = p1->next)
01095         {
01096             if (p1->flag == 0)
01097             {
01098                 float vec[3];
01099                 float new_dist;
01100                 float new_size = 0;
01101 
01102                 p2 = NULL;
01103                 p1->flag = 1;
01104 
01105                 /* if peeling objects, take the first and last from each object */
01106                 if (ts->snap_flag & SCE_SNAP_PEEL_OBJECT)
01107                 {
01108                     DepthPeel *peel;
01109                     for (peel = p1->next; peel; peel = peel->next)
01110                     {
01111                         if (peel->ob == p1->ob)
01112                         {
01113                             peel->flag = 1;
01114                             p2 = peel;
01115                         }
01116                     }
01117                 }
01118                 /* otherwise, pair first with second and so on */
01119                 else
01120                 {
01121                     for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
01122                     {
01123                         /* nothing to do here */
01124                     }
01125                 }
01126 
01127                 if (p2)
01128                 {
01129                     p2->flag = 1;
01130 
01131                     add_v3_v3v3(vec, p1->p, p2->p);
01132                     mul_v3_fl(vec, 0.5f);
01133                     new_size = len_v3v3(p1->p, p2->p);
01134                 }
01135                 else
01136                 {
01137                     copy_v3_v3(vec, p1->p);
01138                 }
01139 
01140                 if (last_p == NULL)
01141                 {
01142                     copy_v3_v3(p, vec);
01143                     size = new_size;
01144                     dist = 0;
01145                     break;
01146                 }
01147 
01148                 new_dist = len_v3v3(last_p, vec);
01149 
01150                 if (new_dist < dist)
01151                 {
01152                     copy_v3_v3(p, vec);
01153                     dist = new_dist;
01154                     size = new_size;
01155                 }
01156             }
01157         }
01158 
01159         if (dist != FLT_MAX)
01160         {
01161             pt->type = dd->type;
01162             pt->mode = PT_SNAP;
01163             pt->size = size / 2;
01164             copy_v3_v3(pt->p, p);
01165 
01166             point_added = 1;
01167         }
01168 
01169         //BLI_freelistN(&depth_peels);
01170     }
01171     else
01172     {
01173         SK_Stroke *snap_stk;
01174         float vec[3];
01175         float no[3];
01176         float mval[2];
01177         int found = 0;
01178         int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
01179 
01180         /* snap to strokes */
01181         // if (ts->snap_mode == SCE_SNAP_MODE_VERTEX) /* snap all the time to strokes */
01182         for (snap_stk = sketch->strokes.first; snap_stk; snap_stk = snap_stk->next)
01183         {
01184             SK_Point *spt = NULL;
01185             if (snap_stk == stk)
01186             {
01187                 spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 0);
01188             }
01189             else
01190             {
01191                 spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 1);
01192             }
01193 
01194             if (spt != NULL)
01195             {
01196                 copy_v3_v3(pt->p, spt->p);
01197                 point_added = 1;
01198             }
01199         }
01200         
01201         mval[0] = dd->mval[0];
01202         mval[1] = dd->mval[1];
01203 
01204         /* try to snap to closer object */
01205         found = snapObjectsContext(C, mval, &dist, vec, no, SNAP_NOT_SELECTED);
01206         if (found == 1)
01207         {
01208             pt->type = dd->type;
01209             pt->mode = PT_SNAP;
01210             copy_v3_v3(pt->p, vec);
01211 
01212             point_added = 1;
01213         }
01214     }
01215 
01216     return point_added;
01217 }
01218 
01219 static int sk_addStrokeSnapPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
01220 {
01221     int point_added;
01222     ARegion *ar = CTX_wm_region(C);
01223     RegionView3D *rv3d = ar->regiondata;
01224     SK_Point pt;
01225 
01226     sk_initPoint(&pt, dd, rv3d->viewinv[2]);
01227 
01228     point_added = sk_getStrokeSnapPoint(C, &pt, sketch, stk, dd);
01229 
01230     if (point_added)
01231     {
01232         float final_p[3];
01233         float length, distance;
01234         int total;
01235         int i;
01236 
01237         copy_v3_v3(final_p, pt.p);
01238 
01239         sk_projectDrawPoint(C, pt.p, stk, dd);
01240         sk_appendStrokePoint(stk, &pt);
01241 
01242         /* update all previous point to give smooth Z progresion */
01243         total = 0;
01244         length = 0;
01245         for (i = stk->nb_points - 2; i > 0; i--)
01246         {
01247             length += len_v3v3(stk->points[i].p, stk->points[i + 1].p);
01248             total++;
01249             if (stk->points[i].mode == PT_SNAP || stk->points[i].type == PT_EXACT)
01250             {
01251                 break;
01252             }
01253         }
01254 
01255         if (total > 1)
01256         {
01257             distance = sk_distanceDepth(C, final_p, stk->points[i].p);
01258 
01259             sk_interpolateDepth(C, stk, i + 1, stk->nb_points - 2, length, distance);
01260         }
01261 
01262         copy_v3_v3(stk->points[stk->nb_points - 1].p, final_p);
01263 
01264         point_added = 1;
01265     }
01266 
01267     return point_added;
01268 }
01269 
01270 static void sk_addStrokePoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap)
01271 {
01272     ToolSettings *ts = CTX_data_tool_settings(C);
01273     int point_added = 0;
01274 
01275     if (snap)
01276     {
01277         point_added = sk_addStrokeSnapPoint(C, sketch, stk, dd);
01278     }
01279 
01280     if (point_added == 0)
01281     {
01282         point_added = sk_addStrokeDrawPoint(C, sketch, stk, dd);
01283     }
01284 
01285     if (stk == sketch->active_stroke && ts->bone_sketching & BONE_SKETCHING_ADJUST)
01286     {
01287         sk_updateOverdraw(C, sketch, stk, dd);
01288     }
01289 }
01290 
01291 static void sk_getStrokePoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap)
01292 {
01293     int point_added = 0;
01294 
01295     if (snap)
01296     {
01297         point_added = sk_getStrokeSnapPoint(C, pt, sketch, stk, dd);
01298         LAST_SNAP_POINT_VALID = 1;
01299         copy_v3_v3(LAST_SNAP_POINT, pt->p);
01300     }
01301     else
01302     {
01303         LAST_SNAP_POINT_VALID = 0;
01304     }
01305 
01306     if (point_added == 0)
01307     {
01308         point_added = sk_getStrokeDrawPoint(C, pt, sketch, stk, dd);
01309     }
01310 }
01311 
01312 /********************************************/
01313 
01314 static void* headPoint(void *arg);
01315 static void* tailPoint(void *arg);
01316 static void* nextPoint(void *arg);
01317 static void* nextNPoint(void *arg, int n);
01318 static void* peekPoint(void *arg, int n);
01319 static void* previousPoint(void *arg);
01320 static int   iteratorStopped(void *arg);
01321 
01322 static void initIteratorFct(SK_StrokeIterator *iter)
01323 {
01324     iter->head = headPoint;
01325     iter->tail = tailPoint;
01326     iter->peek = peekPoint;
01327     iter->next = nextPoint;
01328     iter->nextN = nextNPoint;
01329     iter->previous = previousPoint;
01330     iter->stopped = iteratorStopped;
01331 }
01332 
01333 static SK_Point* setIteratorValues(SK_StrokeIterator *iter, int index)
01334 {
01335     SK_Point *pt = NULL;
01336 
01337     if (index >= 0 && index < iter->length)
01338     {
01339         pt = &(iter->stroke->points[iter->start + (iter->stride * index)]);
01340         iter->p = pt->p;
01341         iter->no = pt->no;
01342         iter->size = pt->size;
01343     }
01344     else
01345     {
01346         iter->p = NULL;
01347         iter->no = NULL;
01348         iter->size = 0;
01349     }
01350 
01351     return pt;
01352 }
01353 
01354 void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end)
01355 {
01356     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01357 
01358     initIteratorFct(iter);
01359     iter->stroke = stk;
01360 
01361     if (start < end)
01362     {
01363         iter->start = start + 1;
01364         iter->end = end - 1;
01365         iter->stride = 1;
01366     }
01367     else
01368     {
01369         iter->start = start - 1;
01370         iter->end = end + 1;
01371         iter->stride = -1;
01372     }
01373 
01374     iter->length = iter->stride * (iter->end - iter->start + 1);
01375 
01376     iter->index = -1;
01377 }
01378 
01379 
01380 static void* headPoint(void *arg)
01381 {
01382     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01383     SK_Point *result = NULL;
01384 
01385     result = &(iter->stroke->points[iter->start - iter->stride]);
01386     iter->p = result->p;
01387     iter->no = result->no;
01388     iter->size = result->size;
01389 
01390     return result;
01391 }
01392 
01393 static void* tailPoint(void *arg)
01394 {
01395     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01396     SK_Point *result = NULL;
01397 
01398     result = &(iter->stroke->points[iter->end + iter->stride]);
01399     iter->p = result->p;
01400     iter->no = result->no;
01401     iter->size = result->size;
01402 
01403     return result;
01404 }
01405 
01406 static void* nextPoint(void *arg)
01407 {
01408     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01409     SK_Point *result = NULL;
01410 
01411     iter->index++;
01412     if (iter->index < iter->length)
01413     {
01414         result = setIteratorValues(iter, iter->index);
01415     }
01416 
01417     return result;
01418 }
01419 
01420 static void* nextNPoint(void *arg, int n)
01421 {
01422     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01423     SK_Point *result = NULL;
01424 
01425     iter->index += n;
01426 
01427     /* check if passed end */
01428     if (iter->index < iter->length)
01429     {
01430         result = setIteratorValues(iter, iter->index);
01431     }
01432 
01433     return result;
01434 }
01435 
01436 static void* peekPoint(void *arg, int n)
01437 {
01438     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01439     SK_Point *result = NULL;
01440     int index = iter->index + n;
01441 
01442     /* check if passed end */
01443     if (index < iter->length)
01444     {
01445         result = setIteratorValues(iter, index);
01446     }
01447 
01448     return result;
01449 }
01450 
01451 static void* previousPoint(void *arg)
01452 {
01453     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01454     SK_Point *result = NULL;
01455 
01456     if (iter->index > 0)
01457     {
01458         iter->index--;
01459         result = setIteratorValues(iter, iter->index);
01460     }
01461 
01462     return result;
01463 }
01464 
01465 static int iteratorStopped(void *arg)
01466 {
01467     SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
01468 
01469     if (iter->index >= iter->length)
01470     {
01471         return 1;
01472     }
01473     else
01474     {
01475         return 0;
01476     }
01477 }
01478 
01479 static void sk_convertStroke(bContext *C, SK_Stroke *stk)
01480 {
01481     Object *obedit = CTX_data_edit_object(C);
01482     ToolSettings *ts = CTX_data_tool_settings(C);
01483     bArmature *arm = obedit->data;
01484     SK_Point *head;
01485     EditBone *parent = NULL;
01486     float invmat[4][4]; /* move in caller function */
01487     float tmat[3][3];
01488     int head_index = 0;
01489     int i;
01490 
01491     head = NULL;
01492 
01493     invert_m4_m4(invmat, obedit->obmat);
01494 
01495     copy_m3_m4(tmat, obedit->obmat);
01496     transpose_m3(tmat);
01497 
01498     for (i = 0; i < stk->nb_points; i++)
01499     {
01500         SK_Point *pt = stk->points + i;
01501 
01502         if (pt->type == PT_EXACT)
01503         {
01504             if (head == NULL)
01505             {
01506                 head_index = i;
01507                 head = pt;
01508             }
01509             else
01510             {
01511                 EditBone *bone = NULL;
01512                 EditBone *new_parent;
01513 
01514                 if (i - head_index > 1)
01515                 {
01516                     SK_StrokeIterator sk_iter;
01517                     BArcIterator *iter = (BArcIterator*)&sk_iter;
01518 
01519                     initStrokeIterator(iter, stk, head_index, i);
01520 
01521                     if (ts->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE)
01522                     {
01523                         bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
01524                     }
01525                     else if (ts->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
01526                     {
01527                         bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision);
01528                     }
01529                     else if (ts->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
01530                     {
01531                         bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextFixedSubdivision);
01532                     }
01533                 }
01534 
01535                 if (bone == NULL)
01536                 {
01537                     bone = ED_armature_edit_bone_add(arm, "Bone");
01538 
01539                     copy_v3_v3(bone->head, head->p);
01540                     copy_v3_v3(bone->tail, pt->p);
01541 
01542                     mul_m4_v3(invmat, bone->head);
01543                     mul_m4_v3(invmat, bone->tail);
01544                     setBoneRollFromNormal(bone, head->no, invmat, tmat);
01545                 }
01546 
01547                 new_parent = bone;
01548                 bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
01549 
01550                 /* move to end of chain */
01551                 while (bone->parent != NULL)
01552                 {
01553                     bone = bone->parent;
01554                     bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
01555                 }
01556 
01557                 if (parent != NULL)
01558                 {
01559                     bone->parent = parent;
01560                     bone->flag |= BONE_CONNECTED;
01561                 }
01562 
01563                 parent = new_parent;
01564                 head_index = i;
01565                 head = pt;
01566             }
01567         }
01568     }
01569 }
01570 
01571 static void sk_convert(bContext *C, SK_Sketch *sketch)
01572 {
01573     ToolSettings *ts = CTX_data_tool_settings(C);
01574     SK_Stroke *stk;
01575 
01576     for (stk = sketch->strokes.first; stk; stk = stk->next)
01577     {
01578         if (stk->selected == 1)
01579         {
01580             if (ts->bone_sketching_convert == SK_CONVERT_RETARGET)
01581             {
01582                 sk_retargetStroke(C, stk);
01583             }
01584             else
01585             {
01586                 sk_convertStroke(C, stk);
01587             }
01588 //          XXX
01589 //          allqueue(REDRAWBUTSEDIT, 0);
01590         }
01591     }
01592 }
01593 /******************* GESTURE *************************/
01594 
01595 
01596 /* returns the number of self intersections */
01597 static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gesture)
01598 {
01599     ARegion *ar = CTX_wm_region(C);
01600     int added = 0;
01601     int s_i;
01602 
01603     for (s_i = 0; s_i < gesture->nb_points - 1; s_i++)
01604     {
01605         float s_p1[3] = {0, 0, 0};
01606         float s_p2[3] = {0, 0, 0};
01607         int g_i;
01608 
01609         project_float(ar, gesture->points[s_i].p, s_p1);
01610         project_float(ar, gesture->points[s_i + 1].p, s_p2);
01611 
01612         /* start checking from second next, because two consecutive cannot intersect */
01613         for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++)
01614         {
01615             float g_p1[3] = {0, 0, 0};
01616             float g_p2[3] = {0, 0, 0};
01617             float vi[3];
01618             float lambda;
01619 
01620             project_float(ar, gesture->points[g_i].p, g_p1);
01621             project_float(ar, gesture->points[g_i + 1].p, g_p2);
01622 
01623             if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda))
01624             {
01625                 SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
01626 
01627                 isect->gesture_index = g_i;
01628                 isect->before = s_i;
01629                 isect->after = s_i + 1;
01630                 isect->stroke = gesture;
01631 
01632                 sub_v3_v3v3(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p);
01633                 mul_v3_fl(isect->p, lambda);
01634                 add_v3_v3(isect->p, gesture->points[s_i].p);
01635 
01636                 BLI_addtail(list, isect);
01637 
01638                 added++;
01639             }
01640         }
01641     }
01642 
01643     return added;
01644 }
01645 
01646 static int cmpIntersections(void *i1, void *i2)
01647 {
01648     SK_Intersection *isect1 = i1, *isect2 = i2;
01649 
01650     if (isect1->stroke == isect2->stroke)
01651     {
01652         if (isect1->before < isect2->before)
01653         {
01654             return -1;
01655         }
01656         else if (isect1->before > isect2->before)
01657         {
01658             return 1;
01659         }
01660         else
01661         {
01662             if (isect1->lambda < isect2->lambda)
01663             {
01664                 return -1;
01665             }
01666             else if (isect1->lambda > isect2->lambda)
01667             {
01668                 return 1;
01669             }
01670         }
01671     }
01672 
01673     return 0;
01674 }
01675 
01676 
01677 /* returns the maximum number of intersections per stroke */
01678 static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
01679 {
01680     ARegion *ar = CTX_wm_region(C);
01681     ScrArea *sa = CTX_wm_area(C);
01682     View3D *v3d = sa->spacedata.first;
01683     SK_Stroke *stk;
01684     int added = 0;
01685 
01686     for (stk = sketch->strokes.first; stk; stk = stk->next)
01687     {
01688         int s_added = 0;
01689         int s_i;
01690 
01691         for (s_i = 0; s_i < stk->nb_points - 1; s_i++)
01692         {
01693             float s_p1[3] = {0, 0, 0};
01694             float s_p2[3] = {0, 0, 0};
01695             int g_i;
01696 
01697             project_float(ar, stk->points[s_i].p, s_p1);
01698             project_float(ar, stk->points[s_i + 1].p, s_p2);
01699 
01700             for (g_i = 0; g_i < gesture->nb_points - 1; g_i++)
01701             {
01702                 float g_p1[3] = {0, 0, 0};
01703                 float g_p2[3] = {0, 0, 0};
01704                 float vi[3];
01705                 float lambda;
01706 
01707                 project_float(ar, gesture->points[g_i].p, g_p1);
01708                 project_float(ar, gesture->points[g_i + 1].p, g_p2);
01709 
01710                 if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda))
01711                 {
01712                     SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
01713                     float ray_start[3], ray_end[3];
01714                     float mval[2];
01715 
01716                     isect->gesture_index = g_i;
01717                     isect->before = s_i;
01718                     isect->after = s_i + 1;
01719                     isect->stroke = stk;
01720                     isect->lambda = lambda;
01721 
01722                     mval[0] = vi[0];
01723                     mval[1] = vi[1];
01724                     ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end);
01725 
01726                     isect_line_line_v3( stk->points[s_i].p,
01727                                         stk->points[s_i + 1].p,
01728                                         ray_start,
01729                                         ray_end,
01730                                         isect->p,
01731                                         vi);
01732 
01733                     BLI_addtail(list, isect);
01734 
01735                     s_added++;
01736                 }
01737             }
01738         }
01739 
01740         added = MAX2(s_added, added);
01741     }
01742 
01743     BLI_sortlist(list, cmpIntersections);
01744 
01745     return added;
01746 }
01747 
01748 static int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
01749 {
01750     SK_StrokeIterator sk_iter;
01751     BArcIterator *iter = (BArcIterator*)&sk_iter;
01752 
01753     float CORRELATION_THRESHOLD = 0.99f;
01754     float *vec;
01755     int i, j;
01756 
01757     sk_appendStrokePoint(segments, &gesture->points[0]);
01758     vec = segments->points[segments->nb_points - 1].p;
01759 
01760     initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1);
01761 
01762     for (i = 1, j = 0; i < gesture->nb_points; i++)
01763     {
01764         float n[3];
01765 
01766         /* Calculate normal */
01767         sub_v3_v3v3(n, gesture->points[i].p, vec);
01768 
01769         if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD)
01770         {
01771             j = i - 1;
01772             sk_appendStrokePoint(segments, &gesture->points[j]);
01773             vec = segments->points[segments->nb_points - 1].p;
01774             segments->points[segments->nb_points - 1].type = PT_EXACT;
01775         }
01776     }
01777 
01778     sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]);
01779 
01780     return segments->nb_points - 1;
01781 }
01782 
01783 int sk_detectCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01784 {
01785     if (gest->nb_segments == 1 && gest->nb_intersections == 1)
01786     {
01787         return 1;
01788     }
01789 
01790     return 0;
01791 }
01792 
01793 void sk_applyCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01794 {
01795     SK_Intersection *isect;
01796 
01797     for (isect = gest->intersections.first; isect; isect = isect->next)
01798     {
01799         SK_Point pt;
01800 
01801         pt.type = PT_EXACT;
01802         pt.mode = PT_PROJECT; /* take mode from neighbouring points */
01803         copy_v3_v3(pt.p, isect->p);
01804         copy_v3_v3(pt.no, isect->stroke->points[isect->before].no);
01805 
01806         sk_insertStrokePoint(isect->stroke, &pt, isect->after);
01807     }
01808 }
01809 
01810 int sk_detectTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01811 {
01812     if (gest->nb_segments == 2 && gest->nb_intersections == 1 && gest->nb_self_intersections == 0)
01813     {
01814         float s1[3], s2[3];
01815         float angle;
01816 
01817         sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
01818         sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
01819 
01820         angle = RAD2DEGF(angle_v2v2(s1, s2));
01821 
01822         if (angle > 60 && angle < 120)
01823         {
01824             return 1;
01825         }
01826     }
01827 
01828     return 0;
01829 }
01830 
01831 void sk_applyTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01832 {
01833     SK_Intersection *isect;
01834     float trim_dir[3];
01835 
01836     sub_v3_v3v3(trim_dir, gest->segments->points[2].p, gest->segments->points[1].p);
01837 
01838     for (isect = gest->intersections.first; isect; isect = isect->next)
01839     {
01840         SK_Point pt;
01841         float stroke_dir[3];
01842 
01843         pt.type = PT_EXACT;
01844         pt.mode = PT_PROJECT; /* take mode from neighbouring points */
01845         copy_v3_v3(pt.p, isect->p);
01846         copy_v3_v3(pt.no, isect->stroke->points[isect->before].no);
01847 
01848         sub_v3_v3v3(stroke_dir, isect->stroke->points[isect->after].p, isect->stroke->points[isect->before].p);
01849 
01850         /* same direction, trim end */
01851         if (dot_v3v3(stroke_dir, trim_dir) > 0)
01852         {
01853             sk_replaceStrokePoint(isect->stroke, &pt, isect->after);
01854             sk_trimStroke(isect->stroke, 0, isect->after);
01855         }
01856         /* else, trim start */
01857         else
01858         {
01859             sk_replaceStrokePoint(isect->stroke, &pt, isect->before);
01860             sk_trimStroke(isect->stroke, isect->before, isect->stroke->nb_points - 1);
01861         }
01862 
01863     }
01864 }
01865 
01866 int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01867 {
01868     if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1)
01869     {
01870         SK_Intersection *isect, *self_isect;
01871 
01872         /* get the the last intersection of the first pair */
01873         for( isect = gest->intersections.first; isect; isect = isect->next )
01874         {
01875             if (isect->stroke == isect->next->stroke)
01876             {
01877                 isect = isect->next;
01878                 break;
01879             }
01880         }
01881 
01882         self_isect = gest->self_intersections.first;
01883 
01884         if (isect && isect->gesture_index < self_isect->gesture_index)
01885         {
01886             return 1;
01887         }
01888     }
01889 
01890     return 0;
01891 }
01892 
01893 void sk_applyCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01894 {
01895     SK_Intersection *isect;
01896     int command = 1;
01897 
01898 //  XXX
01899 //  command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3");
01900     if(command < 1) return;
01901 
01902     for (isect = gest->intersections.first; isect; isect = isect->next)
01903     {
01904         SK_Intersection *i2;
01905 
01906         i2 = isect->next;
01907 
01908         if (i2 && i2->stroke == isect->stroke)
01909         {
01910             switch (command)
01911             {
01912                 case 1:
01913                     sk_flattenStroke(isect->stroke, isect->before, i2->after);
01914                     break;
01915                 case 2:
01916                     sk_straightenStroke(isect->stroke, isect->before, i2->after, isect->p, i2->p);
01917                     break;
01918                 case 3:
01919                     sk_polygonizeStroke(isect->stroke, isect->before, i2->after);
01920                     break;
01921             }
01922 
01923             isect = i2;
01924         }
01925     }
01926 }
01927 
01928 int sk_detectDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01929 {
01930     if (gest->nb_segments == 2 && gest->nb_intersections == 2)
01931     {
01932         float s1[3], s2[3];
01933         float angle;
01934 
01935         sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
01936         sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
01937 
01938         angle = RAD2DEGF(angle_v2v2(s1, s2));
01939 
01940         if (angle > 120)
01941         {
01942             return 1;
01943         }
01944     }
01945 
01946     return 0;
01947 }
01948 
01949 void sk_applyDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *sketch)
01950 {
01951     SK_Intersection *isect;
01952 
01953     for (isect = gest->intersections.first; isect; isect = isect->next)
01954     {
01955         /* only delete strokes that are crossed twice */
01956         if (isect->next && isect->next->stroke == isect->stroke)
01957         {
01958             isect = isect->next;
01959 
01960             sk_removeStroke(sketch, isect->stroke);
01961         }
01962     }
01963 }
01964 
01965 int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
01966 {
01967     ARegion *ar = CTX_wm_region(C);
01968     if (gest->nb_segments > 2 && gest->nb_intersections == 2)
01969     {
01970         short start_val[2], end_val[2];
01971         short dist;
01972 
01973         project_short_noclip(ar, gest->stk->points[0].p, start_val);
01974         project_short_noclip(ar, sk_lastStrokePoint(gest->stk)->p, end_val);
01975 
01976         dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1]));
01977 
01978         /* if gesture is a circle */
01979         if ( dist <= 20 )
01980         {
01981             SK_Intersection *isect;
01982 
01983             /* check if it circled around an exact point */
01984             for (isect = gest->intersections.first; isect; isect = isect->next)
01985             {
01986                 /* only delete strokes that are crossed twice */
01987                 if (isect->next && isect->next->stroke == isect->stroke)
01988                 {
01989                     int start_index, end_index;
01990                     int i;
01991 
01992                     start_index = MIN2(isect->after, isect->next->after);
01993                     end_index = MAX2(isect->before, isect->next->before);
01994 
01995                     for (i = start_index; i <= end_index; i++)
01996                     {
01997                         if (isect->stroke->points[i].type == PT_EXACT)
01998                         {
01999                             return 1; /* at least one exact point found, stop detect here */
02000                         }
02001                     }
02002 
02003                     /* skip next */
02004                     isect = isect->next;
02005                 }
02006             }
02007         }
02008     }
02009 
02010     return 0;
02011 }
02012 
02013 void sk_applyMergeGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
02014 {
02015     SK_Intersection *isect;
02016 
02017     /* check if it circled around an exact point */
02018     for (isect = gest->intersections.first; isect; isect = isect->next)
02019     {
02020         /* only merge strokes that are crossed twice */
02021         if (isect->next && isect->next->stroke == isect->stroke)
02022         {
02023             int start_index, end_index;
02024             int i;
02025 
02026             start_index = MIN2(isect->after, isect->next->after);
02027             end_index = MAX2(isect->before, isect->next->before);
02028 
02029             for (i = start_index; i <= end_index; i++)
02030             {
02031                 /* if exact, switch to continuous */
02032                 if (isect->stroke->points[i].type == PT_EXACT)
02033                 {
02034                     isect->stroke->points[i].type = PT_CONTINUOUS;
02035                 }
02036             }
02037 
02038             /* skip next */
02039             isect = isect->next;
02040         }
02041     }
02042 }
02043 
02044 int sk_detectReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
02045 {
02046     if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 0)
02047     {
02048         SK_Intersection *isect;
02049 
02050         /* check if it circled around an exact point */
02051         for (isect = gest->intersections.first; isect; isect = isect->next)
02052         {
02053             /* only delete strokes that are crossed twice */
02054             if (isect->next && isect->next->stroke == isect->stroke)
02055             {
02056                 float start_v[3], end_v[3];
02057                 float angle;
02058 
02059                 if (isect->gesture_index < isect->next->gesture_index)
02060                 {
02061                     sub_v3_v3v3(start_v, isect->p, gest->stk->points[0].p);
02062                     sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->next->p);
02063                 }
02064                 else
02065                 {
02066                     sub_v3_v3v3(start_v, isect->next->p, gest->stk->points[0].p);
02067                     sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p);
02068                 }
02069 
02070                 angle = RAD2DEGF(angle_v2v2(start_v, end_v));
02071 
02072                 if (angle > 120)
02073                 {
02074                     return 1;
02075                 }
02076 
02077                 /* skip next */
02078                 isect = isect->next;
02079             }
02080         }
02081     }
02082 
02083     return 0;
02084 }
02085 
02086 void sk_applyReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
02087 {
02088     SK_Intersection *isect;
02089 
02090     for (isect = gest->intersections.first; isect; isect = isect->next)
02091     {
02092         /* only reverse strokes that are crossed twice */
02093         if (isect->next && isect->next->stroke == isect->stroke)
02094         {
02095             sk_reverseStroke(isect->stroke);
02096 
02097             /* skip next */
02098             isect = isect->next;
02099         }
02100     }
02101 }
02102 
02103 int sk_detectConvertGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
02104 {
02105     if (gest->nb_segments == 3 && gest->nb_self_intersections == 1)
02106     {
02107         return 1;
02108     }
02109     return 0;
02110 }
02111 
02112 void sk_applyConvertGesture(bContext *C, SK_Gesture *UNUSED(gest), SK_Sketch *sketch)
02113 {
02114     sk_convert(C, sketch);
02115 }
02116 
02117 static void sk_initGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch)
02118 {
02119     gest->intersections.first = gest->intersections.last = NULL;
02120     gest->self_intersections.first = gest->self_intersections.last = NULL;
02121 
02122     gest->segments = sk_createStroke();
02123     gest->stk = sketch->gesture;
02124 
02125     gest->nb_self_intersections = sk_getSelfIntersections(C, &gest->self_intersections, gest->stk);
02126     gest->nb_intersections = sk_getIntersections(C, &gest->intersections, sketch, gest->stk);
02127     gest->nb_segments = sk_getSegments(gest->segments, gest->stk);
02128 }
02129 
02130 static void sk_freeGesture(SK_Gesture *gest)
02131 {
02132     sk_freeStroke(gest->segments);
02133     BLI_freelistN(&gest->intersections);
02134     BLI_freelistN(&gest->self_intersections);
02135 }
02136 
02137 static void sk_applyGesture(bContext *C, SK_Sketch *sketch)
02138 {
02139     SK_Gesture gest;
02140     SK_GestureAction *act;
02141 
02142     sk_initGesture(C, &gest, sketch);
02143 
02144     /* detect and apply */
02145     for (act = GESTURE_ACTIONS; act->apply != NULL; act++)
02146     {
02147         if (act->detect(C, &gest, sketch))
02148         {
02149             act->apply(C, &gest, sketch);
02150             break;
02151         }
02152     }
02153 
02154     sk_freeGesture(&gest);
02155 }
02156 
02157 /********************************************/
02158 
02159 
02160 static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], int extend)
02161 {
02162     ViewContext vc;
02163     rcti rect;
02164     unsigned int buffer[MAXPICKBUF];
02165     short hits;
02166 
02167     view3d_set_viewcontext(C, &vc);
02168 
02169     rect.xmin= mval[0]-5;
02170     rect.xmax= mval[0]+5;
02171     rect.ymin= mval[1]-5;
02172     rect.ymax= mval[1]+5;
02173 
02174     hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
02175 
02176     if (hits>0)
02177     {
02178         int besthitresult = -1;
02179 
02180         if(hits == 1) {
02181             besthitresult = buffer[3];
02182         }
02183         else {
02184             besthitresult = buffer[3];
02185             /* loop and get best hit */
02186         }
02187 
02188         if (besthitresult > 0)
02189         {
02190             SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1);
02191 
02192             if (extend == 0)
02193             {
02194                 sk_selectAllSketch(sketch, -1);
02195 
02196                 selected_stk->selected = 1;
02197             }
02198             else
02199             {
02200                 selected_stk->selected ^= 1;
02201             }
02202 
02203 
02204         }
02205         return 1;
02206     }
02207 
02208     return 0;
02209 }
02210 
02211 #if 0 /* UNUSED 2.5 */
02212 static void sk_queueRedrawSketch(SK_Sketch *sketch)
02213 {
02214     if (sketch->active_stroke != NULL)
02215     {
02216         SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
02217 
02218         if (last != NULL)
02219         {
02220 //          XXX
02221 //          allqueue(REDRAWVIEW3D, 0);
02222         }
02223     }
02224 }
02225 #endif
02226 
02227 static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, int with_names)
02228 {
02229     ToolSettings *ts= scene->toolsettings;
02230     SK_Stroke *stk;
02231 
02232     glClear(GL_DEPTH_BUFFER_BIT);
02233     glEnable(GL_DEPTH_TEST);
02234 
02235     if (with_names)
02236     {
02237         int id;
02238         for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next)
02239         {
02240             sk_drawStroke(stk, id, NULL, -1, -1);
02241         }
02242 
02243         glLoadName(-1);
02244     }
02245     else
02246     {
02247         float selected_rgb[3] = {1, 0, 0};
02248         float unselected_rgb[3] = {1, 0.5, 0};
02249 
02250         for (stk = sketch->strokes.first; stk; stk = stk->next)
02251         {
02252             int start = -1;
02253             int end = -1;
02254 
02255             if (sk_hasOverdraw(sketch, stk))
02256             {
02257                 sk_adjustIndexes(sketch, &start, &end);
02258             }
02259 
02260             sk_drawStroke(stk, -1, (stk->selected==1?selected_rgb:unselected_rgb), start, end);
02261 
02262             if (stk->selected == 1)
02263             {
02264                 sk_drawStrokeSubdivision(ts, stk);
02265             }
02266         }
02267 
02268         if (sketch->active_stroke != NULL)
02269         {
02270             SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
02271 
02272             if (ts->bone_sketching & BONE_SKETCHING_QUICK)
02273             {
02274                 sk_drawStrokeSubdivision(ts, sketch->active_stroke);
02275             }
02276 
02277             if (last != NULL)
02278             {
02279                 GLUquadric *quad = gluNewQuadric();
02280                 gluQuadricNormals(quad, GLU_SMOOTH);
02281 
02282                 glPushMatrix();
02283 
02284                 glEnable(GL_BLEND);
02285                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02286 
02287                 switch (sketch->next_point.mode)
02288                 {
02289                     case PT_SNAP:
02290                         glColor3f(0, 1, 0);
02291                         break;
02292                     case PT_PROJECT:
02293                         glColor3f(0, 0, 0);
02294                         break;
02295                 }
02296 
02297                 sk_drawPoint(quad, &sketch->next_point, 0.1);
02298 
02299                 glColor4f(selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3);
02300 
02301                 sk_drawEdge(quad, last, &sketch->next_point, 0.1);
02302 
02303                 glDisable(GL_BLEND);
02304 
02305                 glPopMatrix();
02306 
02307                 gluDeleteQuadric(quad);
02308             }
02309         }
02310     }
02311 
02312 #if 0
02313     if (sketch->depth_peels.first != NULL)
02314     {
02315         float colors[8][3] = {
02316                                 {1, 0, 0},
02317                                 {0, 1, 0},
02318                                 {0, 0, 1},
02319                                 {1, 1, 0},
02320                                 {1, 0, 1},
02321                                 {0, 1, 1},
02322                                 {1, 1, 1},
02323                                 {0, 0, 0}
02324                             };
02325         DepthPeel *p;
02326         GLUquadric *quad = gluNewQuadric();
02327         gluQuadricNormals(quad, GLU_SMOOTH);
02328 
02329         for (p = sketch->depth_peels.first; p; p = p->next)
02330         {
02331             int index = GET_INT_FROM_POINTER(p->ob);
02332             index = (index >> 5) & 7;
02333 
02334             glColor3fv(colors[index]);
02335             glPushMatrix();
02336             glTranslatef(p->p[0], p->p[1], p->p[2]);
02337             gluSphere(quad, 0.02, 8, 8);
02338             glPopMatrix();
02339         }
02340 
02341         gluDeleteQuadric(quad);
02342     }
02343 #endif
02344 
02345     glDisable(GL_DEPTH_TEST);
02346 
02347     /* only draw gesture in active area */
02348     if (sketch->gesture != NULL /*&& area_is_active_area(G.vd->area)*/)
02349     {
02350         float gesture_rgb[3] = {0, 0.5, 1};
02351         sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1);
02352     }
02353 }
02354 
02355 static int sk_finish_stroke(bContext *C, SK_Sketch *sketch)
02356 {
02357     ToolSettings *ts = CTX_data_tool_settings(C);
02358 
02359     if (sketch->active_stroke != NULL)
02360     {
02361         SK_Stroke *stk = sketch->active_stroke;
02362 
02363         sk_endStroke(C, sketch);
02364 
02365         if (ts->bone_sketching & BONE_SKETCHING_QUICK)
02366         {
02367             if (ts->bone_sketching_convert == SK_CONVERT_RETARGET)
02368             {
02369                 sk_retargetStroke(C, stk);
02370             }
02371             else
02372             {
02373                 sk_convertStroke(C, stk);
02374             }
02375 //          XXX
02376 //          BIF_undo_push("Convert Sketch");
02377             sk_removeStroke(sketch, stk);
02378 //          XXX
02379 //          allqueue(REDRAWBUTSEDIT, 0);
02380         }
02381 
02382 //      XXX
02383 //      allqueue(REDRAWVIEW3D, 0);
02384         return 1;
02385     }
02386 
02387     return 0;
02388 }
02389 
02390 static void sk_start_draw_stroke(SK_Sketch *sketch)
02391 {
02392     if (sketch->active_stroke == NULL)
02393     {
02394         sk_startStroke(sketch);
02395         sk_selectAllSketch(sketch, -1);
02396 
02397         sketch->active_stroke->selected = 1;
02398     }
02399 }
02400 
02401 static void sk_start_draw_gesture(SK_Sketch *sketch)
02402 {
02403     sketch->gesture = sk_createStroke();
02404 }
02405 
02406 static int sk_draw_stroke(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap)
02407 {
02408     if (sk_stroke_filtermval(dd))
02409     {
02410         sk_addStrokePoint(C, sketch, stk, dd, snap);
02411         sk_updateDrawData(dd);
02412         sk_updateNextPoint(sketch, stk);
02413         
02414         return 1;
02415     }
02416 
02417     return 0;
02418 }
02419 
02420 static int ValidSketchViewContext(ViewContext *vc)
02421 {
02422     Object *obedit = vc->obedit;
02423     Scene *scene= vc->scene;
02424 
02425     if (obedit &&
02426         obedit->type == OB_ARMATURE &&
02427         scene->toolsettings->bone_sketching & BONE_SKETCHING)
02428     {
02429         return 1;
02430     }
02431     else
02432     {
02433         return 0;
02434     }
02435 }
02436 
02437 int BDR_drawSketchNames(ViewContext *vc)
02438 {
02439     if (ValidSketchViewContext(vc))
02440     {
02441         SK_Sketch *sketch = viewcontextSketch(vc, 0);
02442         if (sketch)
02443         {
02444             sk_drawSketch(vc->scene, vc->v3d, sketch, 1);
02445             return 1;
02446         }
02447     }
02448 
02449     return 0;
02450 }
02451 
02452 void BDR_drawSketch(const bContext *C)
02453 {
02454     if (ED_operator_sketch_mode(C))
02455     {
02456         SK_Sketch *sketch = contextSketch(C, 0);
02457         if (sketch)
02458         {
02459             sk_drawSketch(CTX_data_scene(C), CTX_wm_view3d(C), sketch, 0);
02460         }
02461     }
02462 }
02463 
02464 static int sketch_delete(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
02465 {
02466     SK_Sketch *sketch = contextSketch(C, 0);
02467     if (sketch)
02468     {
02469         sk_deleteSelectedStrokes(sketch);
02470 //          allqueue(REDRAWVIEW3D, 0);
02471     }
02472     WM_event_add_notifier(C, NC_SCREEN|ND_SKETCH|NA_REMOVED, NULL);
02473     return OPERATOR_FINISHED;
02474 }
02475 
02476 void BIF_sk_selectStroke(bContext *C, const int mval[2], short extend)
02477 {
02478     ToolSettings *ts = CTX_data_tool_settings(C);
02479     SK_Sketch *sketch = contextSketch(C, 0);
02480 
02481     if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING)
02482     {
02483         if (sk_selectStroke(C, sketch, mval, extend))
02484             ED_area_tag_redraw(CTX_wm_area(C));
02485     }
02486 }
02487 
02488 void BIF_convertSketch(bContext *C)
02489 {
02490     if (ED_operator_sketch_full_mode(C))
02491     {
02492         SK_Sketch *sketch = contextSketch(C, 0);
02493         if (sketch)
02494         {
02495             sk_convert(C, sketch);
02496 //          BIF_undo_push("Convert Sketch");
02497 //          allqueue(REDRAWVIEW3D, 0);
02498 //          allqueue(REDRAWBUTSEDIT, 0);
02499         }
02500     }
02501 }
02502 
02503 void BIF_deleteSketch(bContext *C)
02504 {
02505     if (ED_operator_sketch_full_mode(C))
02506     {
02507         SK_Sketch *sketch = contextSketch(C, 0);
02508         if (sketch)
02509         {
02510             sk_deleteSelectedStrokes(sketch);
02511 //          BIF_undo_push("Convert Sketch");
02512 //          allqueue(REDRAWVIEW3D, 0);
02513         }
02514     }
02515 }
02516 
02517 #if 0
02518 void BIF_selectAllSketch(bContext *C, int mode)
02519 {
02520     if (BIF_validSketchMode(C))
02521     {
02522         SK_Sketch *sketch = contextSketch(C, 0);
02523         if (sketch)
02524         {
02525             sk_selectAllSketch(sketch, mode);
02526 //          XXX
02527 //          allqueue(REDRAWVIEW3D, 0);
02528         }
02529     }
02530 }
02531 #endif
02532 
02533 SK_Sketch* contextSketch(const bContext *C, int create)
02534 {
02535     Object *obedit = CTX_data_edit_object(C);
02536     SK_Sketch *sketch = NULL;
02537 
02538     if (obedit && obedit->type == OB_ARMATURE)
02539     {
02540         bArmature *arm = obedit->data;
02541     
02542         if (arm->sketch == NULL && create)
02543         {
02544             arm->sketch = createSketch();
02545         }
02546         sketch = arm->sketch;
02547     }
02548 
02549     return sketch;
02550 }
02551 
02552 SK_Sketch* viewcontextSketch(ViewContext *vc, int create)
02553 {
02554     Object *obedit = vc->obedit;
02555     SK_Sketch *sketch = NULL;
02556 
02557     if (obedit && obedit->type == OB_ARMATURE)
02558     {
02559         bArmature *arm = obedit->data;
02560     
02561         if (arm->sketch == NULL && create)
02562         {
02563             arm->sketch = createSketch();
02564         }
02565         sketch = arm->sketch;
02566     }
02567 
02568     return sketch;
02569 }
02570 
02571 static int sketch_convert(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
02572 {
02573     SK_Sketch *sketch = contextSketch(C, 0);
02574     if (sketch != NULL)
02575     {
02576         sk_convert(C, sketch);
02577         ED_area_tag_redraw(CTX_wm_area(C));
02578     }
02579     return OPERATOR_FINISHED;
02580 }
02581 
02582 static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
02583 {
02584     SK_Sketch *sketch = contextSketch(C, 0);
02585     if (sketch != NULL)
02586     {
02587         sk_cancelStroke(sketch);
02588         ED_area_tag_redraw(CTX_wm_area(C));
02589         return OPERATOR_FINISHED;
02590     }
02591     return OPERATOR_PASS_THROUGH;
02592 }
02593 
02594 static int sketch_finish(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
02595 {
02596     SK_Sketch *sketch = contextSketch(C, 0);
02597     if (sketch != NULL)
02598     {
02599         if (sk_finish_stroke(C, sketch))
02600         {
02601             ED_area_tag_redraw(CTX_wm_area(C));
02602             return OPERATOR_FINISHED;
02603         }
02604     }
02605     return OPERATOR_PASS_THROUGH;
02606 }
02607 
02608 static int sketch_select(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
02609 {
02610     SK_Sketch *sketch = contextSketch(C, 0);
02611     if (sketch)
02612     {
02613         short extend = 0;
02614         if (sk_selectStroke(C, sketch, event->mval, extend))
02615             ED_area_tag_redraw(CTX_wm_area(C));
02616     }
02617 
02618     return OPERATOR_FINISHED;
02619 }
02620 
02621 static int sketch_draw_stroke_cancel(bContext *C, wmOperator *op)
02622 {
02623     SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
02624     sk_cancelStroke(sketch);
02625     MEM_freeN(op->customdata);
02626     return OPERATOR_CANCELLED;
02627 }
02628 
02629 static int sketch_draw_stroke(bContext *C, wmOperator *op, wmEvent *event)
02630 {
02631     short snap = RNA_boolean_get(op->ptr, "snap");
02632     SK_DrawData *dd;
02633     SK_Sketch *sketch = contextSketch(C, 1);
02634 
02635     op->customdata = dd = MEM_callocN(sizeof("SK_DrawData"), "SketchDrawData");
02636     sk_initDrawData(dd, event->mval);
02637 
02638     sk_start_draw_stroke(sketch);
02639 
02640     sk_draw_stroke(C, sketch, sketch->active_stroke, dd, snap);
02641 
02642     WM_event_add_modal_handler(C, op);
02643 
02644     return OPERATOR_RUNNING_MODAL;
02645 }
02646 
02647 static int sketch_draw_gesture_cancel(bContext *C, wmOperator *op)
02648 {
02649     SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
02650     sk_cancelStroke(sketch);
02651     MEM_freeN(op->customdata);
02652     return OPERATOR_CANCELLED;
02653 }
02654 
02655 static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event)
02656 {
02657     short snap = RNA_boolean_get(op->ptr, "snap");
02658     SK_DrawData *dd;
02659     SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
02660     sk_cancelStroke(sketch);
02661 
02662     op->customdata = dd = MEM_callocN(sizeof("SK_DrawData"), "SketchDrawData");
02663     sk_initDrawData(dd, event->mval);
02664 
02665     sk_start_draw_gesture(sketch);
02666     sk_draw_stroke(C, sketch, sketch->gesture, dd, snap);
02667 
02668     WM_event_add_modal_handler(C, op);
02669 
02670     return OPERATOR_RUNNING_MODAL;
02671 }
02672 
02673 static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short gesture, SK_Stroke *stk)
02674 {
02675     short snap = RNA_boolean_get(op->ptr, "snap");
02676     SK_DrawData *dd = op->customdata;
02677     SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
02678     int retval = OPERATOR_RUNNING_MODAL;
02679 
02680     switch (event->type)
02681     {
02682     case LEFTCTRLKEY:
02683     case RIGHTCTRLKEY:
02684         snap = event->ctrl;
02685         RNA_boolean_set(op->ptr, "snap", snap);
02686         break;
02687     case MOUSEMOVE:
02688     case INBETWEEN_MOUSEMOVE:
02689         dd->mval[0] = event->mval[0];
02690         dd->mval[1] = event->mval[1];
02691         sk_draw_stroke(C, sketch, stk, dd, snap);
02692         ED_area_tag_redraw(CTX_wm_area(C));
02693         break;
02694     case ESCKEY:
02695         op->type->cancel(C, op);
02696         ED_area_tag_redraw(CTX_wm_area(C));
02697         retval = OPERATOR_CANCELLED;
02698         break;
02699     case LEFTMOUSE:
02700         if (event->val == KM_RELEASE)
02701         {
02702             if (gesture == 0)
02703             {
02704                 sk_endContinuousStroke(stk);
02705                 sk_filterLastContinuousStroke(stk);
02706                 sk_updateNextPoint(sketch, stk);
02707                 ED_area_tag_redraw(CTX_wm_area(C));
02708                 MEM_freeN(op->customdata);
02709                 retval = OPERATOR_FINISHED;
02710             }
02711             else
02712             {
02713                 sk_endContinuousStroke(stk);
02714                 sk_filterLastContinuousStroke(stk);
02715 
02716                 if (stk->nb_points > 1)
02717                 {
02718                     /* apply gesture here */
02719                     sk_applyGesture(C, sketch);
02720                 }
02721 
02722                 sk_freeStroke(stk);
02723                 sketch->gesture = NULL;
02724 
02725                 ED_area_tag_redraw(CTX_wm_area(C));
02726                 MEM_freeN(op->customdata);
02727                 retval = OPERATOR_FINISHED;
02728             }
02729         }
02730         break;
02731     }
02732 
02733     return retval;
02734 }
02735 
02736 static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
02737 {
02738     SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
02739     return sketch_draw_modal(C, op, event, 0, sketch->active_stroke);
02740 }
02741 
02742 static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, wmEvent *event)
02743 {
02744     SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
02745     return sketch_draw_modal(C, op, event, 1, sketch->gesture);
02746 }
02747 
02748 static int sketch_draw_preview(bContext *C, wmOperator *op, wmEvent *event)
02749 {
02750     short snap = RNA_boolean_get(op->ptr, "snap");
02751     SK_Sketch *sketch = contextSketch(C, 0);
02752 
02753     if (sketch)
02754     {
02755         SK_DrawData dd;
02756 
02757         sk_initDrawData(&dd, event->mval);
02758         sk_getStrokePoint(C, &sketch->next_point, sketch, sketch->active_stroke, &dd, snap);
02759         ED_area_tag_redraw(CTX_wm_area(C));
02760     }
02761 
02762     return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
02763 }
02764 
02765 /* ============================================== Poll Functions ============================================= */
02766 
02767 int ED_operator_sketch_mode_active_stroke(bContext *C)
02768 {
02769     ToolSettings *ts = CTX_data_tool_settings(C);
02770     SK_Sketch *sketch = contextSketch(C, 0);
02771 
02772     if (ts->bone_sketching & BONE_SKETCHING &&
02773         sketch != NULL &&
02774         sketch->active_stroke != NULL)
02775     {
02776         return 1;
02777     }
02778     else
02779     {
02780         return 0;
02781     }
02782 }
02783 
02784 static int ED_operator_sketch_mode_gesture(bContext *C)
02785 {
02786     ToolSettings *ts = CTX_data_tool_settings(C);
02787     SK_Sketch *sketch = contextSketch(C, 0);
02788 
02789     if (ts->bone_sketching & BONE_SKETCHING &&
02790         (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0 &&
02791         sketch != NULL &&
02792         sketch->active_stroke == NULL)
02793     {
02794         return 1;
02795     }
02796     else
02797     {
02798         return 0;
02799     }
02800 }
02801 
02802 int ED_operator_sketch_full_mode(bContext *C)
02803 {
02804     Object *obedit = CTX_data_edit_object(C);
02805     ToolSettings *ts = CTX_data_tool_settings(C);
02806 
02807     if (obedit &&
02808         obedit->type == OB_ARMATURE &&
02809         ts->bone_sketching & BONE_SKETCHING &&
02810         (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0)
02811     {
02812         return 1;
02813     }
02814     else
02815     {
02816         return 0;
02817     }
02818 }
02819 
02820 int ED_operator_sketch_mode(const bContext *C)
02821 {
02822     Object *obedit = CTX_data_edit_object(C);
02823     ToolSettings *ts = CTX_data_tool_settings(C);
02824 
02825     if (obedit &&
02826         obedit->type == OB_ARMATURE &&
02827         ts->bone_sketching & BONE_SKETCHING)
02828     {
02829         return 1;
02830     }
02831     else
02832     {
02833         return 0;
02834     }
02835 }
02836 
02837 /* ================================================ Operators ================================================ */
02838 
02839 void SKETCH_OT_delete(wmOperatorType *ot)
02840 {
02841     /* identifiers */
02842     ot->name= "delete";
02843     ot->idname= "SKETCH_OT_delete";
02844 
02845     /* api callbacks */
02846     ot->invoke= sketch_delete;
02847 
02848     ot->poll= ED_operator_sketch_full_mode;
02849 
02850     /* flags */
02851 //  ot->flag= OPTYPE_UNDO;
02852 }
02853 
02854 void SKETCH_OT_select(wmOperatorType *ot)
02855 {
02856     /* identifiers */
02857     ot->name= "select";
02858     ot->idname= "SKETCH_OT_select";
02859 
02860     /* api callbacks */
02861     ot->invoke= sketch_select;
02862 
02863     ot->poll= ED_operator_sketch_full_mode;
02864 
02865     /* flags */
02866 //  ot->flag= OPTYPE_UNDO;
02867 }
02868 
02869 void SKETCH_OT_cancel_stroke(wmOperatorType *ot)
02870 {
02871     /* identifiers */
02872     ot->name= "cancel stroke";
02873     ot->idname= "SKETCH_OT_cancel_stroke";
02874 
02875     /* api callbacks */
02876     ot->invoke= sketch_cancel;
02877 
02878     ot->poll= ED_operator_sketch_mode_active_stroke;
02879 
02880     /* flags */
02881 //  ot->flag= OPTYPE_UNDO;
02882 }
02883 
02884 void SKETCH_OT_convert(wmOperatorType *ot)
02885 {
02886     /* identifiers */
02887     ot->name= "convert";
02888     ot->idname= "SKETCH_OT_convert";
02889 
02890     /* api callbacks */
02891     ot->invoke= sketch_convert;
02892 
02893     ot->poll= ED_operator_sketch_full_mode;
02894 
02895     /* flags */
02896     ot->flag= OPTYPE_UNDO;
02897 }
02898 
02899 void SKETCH_OT_finish_stroke(wmOperatorType *ot)
02900 {
02901     /* identifiers */
02902     ot->name= "end stroke";
02903     ot->idname= "SKETCH_OT_finish_stroke";
02904 
02905     /* api callbacks */
02906     ot->invoke= sketch_finish;
02907 
02908     ot->poll= ED_operator_sketch_mode_active_stroke;
02909 
02910     /* flags */
02911 //  ot->flag= OPTYPE_UNDO;
02912 }
02913 
02914 void SKETCH_OT_draw_preview(wmOperatorType *ot)
02915 {
02916     /* identifiers */
02917     ot->name= "draw preview";
02918     ot->idname= "SKETCH_OT_draw_preview";
02919 
02920     /* api callbacks */
02921     ot->invoke= sketch_draw_preview;
02922 
02923     ot->poll= ED_operator_sketch_mode_active_stroke;
02924 
02925     RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
02926 
02927     /* flags */
02928 //  ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02929 }
02930 
02931 void SKETCH_OT_draw_stroke(wmOperatorType *ot)
02932 {
02933     /* identifiers */
02934     ot->name= "draw stroke";
02935     ot->idname= "SKETCH_OT_draw_stroke";
02936 
02937     /* api callbacks */
02938     ot->invoke = sketch_draw_stroke;
02939     ot->modal  = sketch_draw_stroke_modal;
02940     ot->cancel = sketch_draw_stroke_cancel;
02941 
02942     ot->poll= (int (*)(bContext *))ED_operator_sketch_mode;
02943 
02944     RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
02945 
02946     /* flags */
02947     ot->flag= OPTYPE_BLOCKING; // OPTYPE_REGISTER|OPTYPE_UNDO
02948 }
02949 
02950 void SKETCH_OT_gesture(wmOperatorType *ot)
02951 {
02952     /* identifiers */
02953     ot->name= "gesture";
02954     ot->idname= "SKETCH_OT_gesture";
02955 
02956     /* api callbacks */
02957     ot->invoke = sketch_draw_gesture;
02958     ot->modal  = sketch_draw_gesture_modal;
02959     ot->cancel = sketch_draw_gesture_cancel;
02960 
02961     ot->poll= ED_operator_sketch_mode_gesture;
02962 
02963     RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
02964 
02965     /* flags */
02966     ot->flag= OPTYPE_BLOCKING; // OPTYPE_UNDO
02967 }
02968