diff options
author | Martin Poirier <theeth@yahoo.com> | 2009-03-20 21:00:51 +0300 |
---|---|---|
committer | Martin Poirier <theeth@yahoo.com> | 2009-03-20 21:00:51 +0300 |
commit | 1af7bd439acf4dd08f7c0f66d91ef2238ff1db05 (patch) | |
tree | bd339b97d44ae35ca8a752c7989f2360a568b35b /source/blender/editors/armature/editarmature_sketch.c | |
parent | 884cfe25d34809a97e69d04c95800ae4e741259e (diff) |
merge more etch-a-ton code. nothing works, but it compiles. Will try to get it working this week end.
Diffstat (limited to 'source/blender/editors/armature/editarmature_sketch.c')
-rw-r--r-- | source/blender/editors/armature/editarmature_sketch.c | 3141 |
1 files changed, 3141 insertions, 0 deletions
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c new file mode 100644 index 00000000000..4ac599a0243 --- /dev/null +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -0,0 +1,3141 @@ +/** + * $Id: $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_armature_types.h" +#include "DNA_userdef_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_graph.h" +#include "BLI_ghash.h" + +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BKE_DerivedMesh.h" +#include "BKE_object.h" +#include "BKE_anim.h" +#include "BKE_context.h" + +#include "ED_view3d.h" + +#include "BIF_gl.h" +#include "UI_resources.h" +//#include "BIF_screen.h" +//#include "BIF_space.h" +//#include "BIF_mywindow.h" +#include "ED_armature.h" +#include "armature_intern.h" +//#include "BIF_sketch.h" +#include "BIF_retarget.h" +#include "BIF_generate.h" +//#include "BIF_interface.h" + +#include "BIF_transform.h" + +#include "WM_types.h" + +//#include "blendef.h" +//#include "mydevice.h" +#include "reeb.h" + +typedef enum SK_PType +{ + PT_CONTINUOUS, + PT_EXACT, +} SK_PType; + +typedef enum SK_PMode +{ + PT_SNAP, + PT_PROJECT, +} SK_PMode; + +typedef struct SK_Point +{ + float p[3]; + float no[3]; + SK_PType type; + SK_PMode mode; +} SK_Point; + +typedef struct SK_Stroke +{ + struct SK_Stroke *next, *prev; + + SK_Point *points; + int nb_points; + int buf_size; + int selected; +} SK_Stroke; + +#define SK_OVERDRAW_LIMIT 5 + +typedef struct SK_Overdraw +{ + SK_Stroke *target; + int start, end; + int count; +} SK_Overdraw; + +#define SK_Stroke_BUFFER_INIT_SIZE 20 + +typedef struct SK_DrawData +{ + short mval[2]; + short previous_mval[2]; + SK_PType type; +} SK_DrawData; + +typedef struct SK_Intersection +{ + struct SK_Intersection *next, *prev; + SK_Stroke *stroke; + int before; + int after; + int gesture_index; + float p[3]; + float lambda; /* used for sorting intersection points */ +} SK_Intersection; + +typedef struct SK_Sketch +{ + ListBase strokes; + SK_Stroke *active_stroke; + SK_Stroke *gesture; + SK_Point next_point; + SK_Overdraw over; +} SK_Sketch; + +typedef struct SK_StrokeIterator { + HeadFct head; + TailFct tail; + PeekFct peek; + NextFct next; + NextNFct nextN; + PreviousFct previous; + StoppedFct stopped; + + float *p, *no; + + int length; + int index; + /*********************************/ + SK_Stroke *stroke; + int start; + int end; + int stride; +} SK_StrokeIterator; + +typedef struct SK_Gesture { + SK_Stroke *stk; + SK_Stroke *segments; + + ListBase intersections; + ListBase self_intersections; + + int nb_self_intersections; + int nb_intersections; + int nb_segments; +} SK_Gesture; + +typedef int (*GestureDetectFct)(bContext*, SK_Gesture*, SK_Sketch *); +typedef void (*GestureApplyFct)(bContext*, SK_Gesture*, SK_Sketch *); + +typedef struct SK_GestureAction { + char name[64]; + GestureDetectFct detect; + GestureApplyFct apply; +} SK_GestureAction; + +SK_Sketch *GLOBAL_sketch = NULL; +SK_Point boneSnap; +int LAST_SNAP_POINT_VALID = 0; +float LAST_SNAP_POINT[3]; + +/******************** PROTOTYPES ******************************/ + +void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end); + +void sk_deleteSelectedStrokes(SK_Sketch *sketch); + +void sk_freeStroke(SK_Stroke *stk); +void sk_freeSketch(SK_Sketch *sketch); + +SK_Point *sk_lastStrokePoint(SK_Stroke *stk); + +int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); +void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch); + + +void sk_resetOverdraw(SK_Sketch *sketch); +int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk); + +/******************** GESTURE ACTIONS ******************************/ + +SK_GestureAction GESTURE_ACTIONS[] = + { + {"Cut", sk_detectCutGesture, sk_applyCutGesture}, + {"Trim", sk_detectTrimGesture, sk_applyTrimGesture}, + {"Command", sk_detectCommandGesture, sk_applyCommandGesture}, + {"Delete", sk_detectDeleteGesture, sk_applyDeleteGesture}, + {"Merge", sk_detectMergeGesture, sk_applyMergeGesture}, + {"Reverse", sk_detectReverseGesture, sk_applyReverseGesture}, + {"Convert", sk_detectConvertGesture, sk_applyConvertGesture}, + {"", NULL, NULL} + }; + +/******************** TEMPLATES UTILS *************************/ + +char *TEMPLATES_MENU = NULL; +int TEMPLATES_CURRENT = 0; +GHash *TEMPLATES_HASH = NULL; +RigGraph *TEMPLATE_RIGG = NULL; + +void BIF_makeListTemplates(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + Base *base; + int index = 0; + + if (TEMPLATES_HASH != NULL) + { + BLI_ghash_free(TEMPLATES_HASH, NULL, NULL); + } + + TEMPLATES_HASH = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + TEMPLATES_CURRENT = 0; + + for ( base = FIRSTBASE; base; base = base->next ) + { + Object *ob = base->object; + + if (ob != obedit && ob->type == OB_ARMATURE) + { + index++; + BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob); + + if (ob == scene->toolsettings->skgen_template) + { + TEMPLATES_CURRENT = index; + } + } + } +} + +char *BIF_listTemplates(bContext *C) +{ + GHashIterator ghi; + char menu_header[] = "Template%t|None%x0|"; + char *p; + + if (TEMPLATES_MENU != NULL) + { + MEM_freeN(TEMPLATES_MENU); + } + + TEMPLATES_MENU = MEM_callocN(sizeof(char) * (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30), "skeleton template menu"); + + p = TEMPLATES_MENU; + + p += sprintf(TEMPLATES_MENU, "%s", menu_header); + + BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); + + while (!BLI_ghashIterator_isDone(&ghi)) + { + Object *ob = BLI_ghashIterator_getValue(&ghi); + int key = (int)BLI_ghashIterator_getKey(&ghi); + + p += sprintf(p, "|%s%%x%i", ob->id.name+2, key); + + BLI_ghashIterator_step(&ghi); + } + + return TEMPLATES_MENU; +} + +int BIF_currentTemplate(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + if (TEMPLATES_CURRENT == 0 && scene->toolsettings->skgen_template != NULL) + { + GHashIterator ghi; + BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); + + while (!BLI_ghashIterator_isDone(&ghi)) + { + Object *ob = BLI_ghashIterator_getValue(&ghi); + int key = (int)BLI_ghashIterator_getKey(&ghi); + + if (ob == scene->toolsettings->skgen_template) + { + TEMPLATES_CURRENT = key; + break; + } + + BLI_ghashIterator_step(&ghi); + } + } + + return TEMPLATES_CURRENT; +} + +RigGraph* sk_makeTemplateGraph(bContext *C, Object *ob) +{ + Object *obedit = CTX_data_edit_object(C); + if (ob == obedit) + { + return NULL; + } + + if (ob != NULL) + { + if (TEMPLATE_RIGG && TEMPLATE_RIGG->ob != ob) + { + RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG); + TEMPLATE_RIGG = NULL; + } + + if (TEMPLATE_RIGG == NULL) + { + bArmature *arm; + + arm = ob->data; + + TEMPLATE_RIGG = RIG_graphFromArmature(C, ob, arm); + } + } + + return TEMPLATE_RIGG; +} + +int BIF_nbJointsTemplate(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + RigGraph *rg = sk_makeTemplateGraph(C, scene->toolsettings->skgen_template); + + if (rg) + { + return RIG_nbJoints(rg); + } + else + { + return -1; + } +} + +char * BIF_nameBoneTemplate(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + SK_Sketch *stk = GLOBAL_sketch; + RigGraph *rg; + int index = 0; + + if (stk && stk->active_stroke != NULL) + { + index = stk->active_stroke->nb_points; + } + + rg = sk_makeTemplateGraph(C, scene->toolsettings->skgen_template); + + if (rg == NULL) + { + return ""; + } + + return RIG_nameBone(rg, 0, index); +} + +void BIF_freeTemplates(bContext *C) +{ + if (TEMPLATES_MENU != NULL) + { + MEM_freeN(TEMPLATES_MENU); + TEMPLATES_MENU = NULL; + } + + if (TEMPLATES_HASH != NULL) + { + BLI_ghash_free(TEMPLATES_HASH, NULL, NULL); + TEMPLATES_HASH = NULL; + } + + if (TEMPLATE_RIGG != NULL) + { + RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG); + TEMPLATE_RIGG = NULL; + } +} + +void BIF_setTemplate(bContext *C, int index) +{ + Scene *scene = CTX_data_scene(C); + if (index > 0) + { + scene->toolsettings->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index)); + } + else + { + scene->toolsettings->skgen_template = NULL; + + if (TEMPLATE_RIGG != NULL) + { + RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG); + } + TEMPLATE_RIGG = NULL; + } +} + +/*********************** CONVERSION ***************************/ + +void sk_autoname(bContext *C, ReebArc *arc) +{ + Scene *scene = CTX_data_scene(C); + if (scene->toolsettings->skgen_retarget_options & SK_RETARGET_AUTONAME) + { + if (arc == NULL) + { + char *num = scene->toolsettings->skgen_num_string; + int i = atoi(num); + i++; + BLI_snprintf(num, 8, "%i", i); + } + else + { + char *side = scene->toolsettings->skgen_side_string; + int valid = 0; + int caps = 0; + + if (BLI_streq(side, "")) + { + valid = 1; + } + else if (BLI_streq(side, "R") || BLI_streq(side, "L")) + { + valid = 1; + caps = 1; + } + else if (BLI_streq(side, "r") || BLI_streq(side, "l")) + { + valid = 1; + caps = 0; + } + + if (valid) + { + if (arc->head->p[0] < 0) + { + BLI_snprintf(side, 8, caps?"R":"r"); + } + else + { + BLI_snprintf(side, 8, caps?"L":"l"); + } + } + } + } +} + +ReebNode *sk_pointToNode(SK_Point *pt, float imat[][4], float tmat[][3]) +{ + ReebNode *node; + + node = MEM_callocN(sizeof(ReebNode), "reeb node"); + VECCOPY(node->p, pt->p); + Mat4MulVecfl(imat, node->p); + + VECCOPY(node->no, pt->no); + Mat3MulVecfl(tmat, node->no); + + return node; +} + +ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[][4], float tmat[][3]) +{ + ReebArc *arc; + int i; + + arc = MEM_callocN(sizeof(ReebArc), "reeb arc"); + arc->head = sk_pointToNode(stk->points, imat, tmat); + arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat); + + arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */ + arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets"); + + for (i = 0; i < arc->bcount; i++) + { + VECCOPY(arc->buckets[i].p, stk->points[i + 1].p); + Mat4MulVecfl(imat, arc->buckets[i].p); + + VECCOPY(arc->buckets[i].no, stk->points[i + 1].no); + Mat3MulVecfl(tmat, arc->buckets[i].no); + } + + return arc; +} + +void sk_retargetStroke(bContext *C, SK_Stroke *stk) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + float imat[4][4]; + float tmat[3][3]; + ReebArc *arc; + RigGraph *rg; + + Mat4Invert(imat, obedit->obmat); + + Mat3CpyMat4(tmat, obedit->obmat); + Mat3Transp(tmat); + + arc = sk_strokeToArc(stk, imat, tmat); + + sk_autoname(C, arc); + + rg = sk_makeTemplateGraph(C, scene->toolsettings->skgen_template); + + BIF_retargetArc(C, arc, rg); + + sk_autoname(C, NULL); + + MEM_freeN(arc->head); + MEM_freeN(arc->tail); + REEB_freeArc((BArc*)arc); +} + +/**************************************************************/ + +void sk_freeSketch(SK_Sketch *sketch) +{ + SK_Stroke *stk, *next; + + for (stk = sketch->strokes.first; stk; stk = next) + { + next = stk->next; + + sk_freeStroke(stk); + } + + MEM_freeN(sketch); +} + +SK_Sketch* sk_createSketch() +{ + SK_Sketch *sketch; + + sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch"); + + sketch->active_stroke = NULL; + sketch->gesture = NULL; + + sketch->strokes.first = NULL; + sketch->strokes.last = NULL; + + return sketch; +} + +void sk_initPoint(bContext *C, SK_Point *pt) +{ + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + VECCOPY(pt->no, rv3d->viewinv[2]); + Normalize(pt->no); + /* more init code here */ +} + +void sk_copyPoint(SK_Point *dst, SK_Point *src) +{ + memcpy(dst, src, sizeof(SK_Point)); +} + +void sk_allocStrokeBuffer(SK_Stroke *stk) +{ + stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer"); +} + +void sk_freeStroke(SK_Stroke *stk) +{ + MEM_freeN(stk->points); + MEM_freeN(stk); +} + +SK_Stroke* sk_createStroke() +{ + SK_Stroke *stk; + + stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke"); + + stk->selected = 0; + stk->nb_points = 0; + stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE; + + sk_allocStrokeBuffer(stk); + + return stk; +} + +void sk_shrinkStrokeBuffer(SK_Stroke *stk) +{ + if (stk->nb_points < stk->buf_size) + { + SK_Point *old_points = stk->points; + + stk->buf_size = stk->nb_points; + + sk_allocStrokeBuffer(stk); + + memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); + + MEM_freeN(old_points); + } +} + +void sk_growStrokeBuffer(SK_Stroke *stk) +{ + if (stk->nb_points == stk->buf_size) + { + SK_Point *old_points = stk->points; + + stk->buf_size *= 2; + + sk_allocStrokeBuffer(stk); + + memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); + + MEM_freeN(old_points); + } +} + +void sk_growStrokeBufferN(SK_Stroke *stk, int n) +{ + if (stk->nb_points + n > stk->buf_size) + { + SK_Point *old_points = stk->points; + + while (stk->nb_points + n > stk->buf_size) + { + stk->buf_size *= 2; + } + + sk_allocStrokeBuffer(stk); + + memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); + + MEM_freeN(old_points); + } +} + + +void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n) +{ + memcpy(stk->points + n, pt, sizeof(SK_Point)); +} + +void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n) +{ + int size = stk->nb_points - n; + + sk_growStrokeBuffer(stk); + + memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point)); + + memcpy(stk->points + n, pt, sizeof(SK_Point)); + + stk->nb_points++; +} + +void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt) +{ + sk_growStrokeBuffer(stk); + + memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point)); + + stk->nb_points++; +} + +void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end) +{ + int size = end - start + 1; + + sk_growStrokeBufferN(stk, len - size); + + if (len != size) + { + int tail_size = stk->nb_points - end + 1; + + memmove(stk->points + start + len, stk->points + end + 1, tail_size * sizeof(SK_Point)); + } + + memcpy(stk->points + start, pts, len * sizeof(SK_Point)); + + stk->nb_points += len - size; +} + +void sk_trimStroke(SK_Stroke *stk, int start, int end) +{ + int size = end - start + 1; + + if (start > 0) + { + memmove(stk->points, stk->points + start, size * sizeof(SK_Point)); + } + + stk->nb_points = size; +} + +void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]) +{ + SK_Point pt1, pt2; + SK_Point *prev, *next; + float delta_p[3]; + int i, total; + + total = end - start; + + VecSubf(delta_p, p_end, p_start); + + prev = stk->points + start; + next = stk->points + end; + + VECCOPY(pt1.p, p_start); + VECCOPY(pt1.no, prev->no); + pt1.mode = prev->mode; + pt1.type = prev->type; + + VECCOPY(pt2.p, p_end); + VECCOPY(pt2.no, next->no); + pt2.mode = next->mode; + pt2.type = next->type; + + sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */ + sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */ + + for (i = 1; i < total; i++) + { + float delta = (float)i / (float)total; + float *p = stk->points[start + 1 + i].p; + + VECCOPY(p, delta_p); + VecMulf(p, delta); + VecAddf(p, p, p_start); + } +} + +void sk_polygonizeStroke(SK_Stroke *stk, int start, int end) +{ + int offset; + int i; + + /* find first exact points outside of range */ + for (;start > 0; start--) + { + if (stk->points[start].type == PT_EXACT) + { + break; + } + } + + for (;end < stk->nb_points - 1; end++) + { + if (stk->points[end].type == PT_EXACT) + { + break; + } + } + + offset = start + 1; + + for (i = start + 1; i < end; i++) + { + if (stk->points[i].type == PT_EXACT) + { + if (offset != i) + { + memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point)); + } + + offset++; + } + } + + /* some points were removes, move end of array */ + if (offset < end) + { + int size = stk->nb_points - end; + memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point)); + stk->nb_points = offset + size; + } +} + +void sk_flattenStroke(SK_Stroke *stk, int start, int end) +{ + float normal[3], distance[3]; + float limit; + int i, total; + + total = end - start + 1; + + VECCOPY(normal, stk->points[start].no); + + VecSubf(distance, stk->points[end].p, stk->points[start].p); + Projf(normal, distance, normal); + limit = Normalize(normal); + + for (i = 1; i < total - 1; i++) + { + float d = limit * i / total; + float offset[3]; + float *p = stk->points[start + i].p; + + VecSubf(distance, p, stk->points[start].p); + Projf(distance, distance, normal); + + VECCOPY(offset, normal); + VecMulf(offset, d); + + VecSubf(p, p, distance); + VecAddf(p, p, offset); + } +} + +void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk) +{ + if (sketch->active_stroke == stk) + { + sketch->active_stroke = NULL; + } + + BLI_remlink(&sketch->strokes, stk); + sk_freeStroke(stk); +} + +void sk_reverseStroke(SK_Stroke *stk) +{ + SK_Point *old_points = stk->points; + int i = 0; + + sk_allocStrokeBuffer(stk); + + for (i = 0; i < stk->nb_points; i++) + { + sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i); + } + + MEM_freeN(old_points); +} + + +void sk_cancelStroke(SK_Sketch *sketch) +{ + if (sketch->active_stroke != NULL) + { + sk_resetOverdraw(sketch); + sk_removeStroke(sketch, sketch->active_stroke); + } +} + +/* Apply reverse Chaikin filter to simplify the polyline + * */ +void sk_filterStroke(SK_Stroke *stk, int start, int end) +{ + SK_Point *old_points = stk->points; + int nb_points = stk->nb_points; + int i, j; + + return; + + if (start == -1) + { + start = 0; + end = stk->nb_points - 1; + } + + sk_allocStrokeBuffer(stk); + stk->nb_points = 0; + + /* adding points before range */ + for (i = 0; i < start; i++) + { + sk_appendStrokePoint(stk, old_points + i); + } + + for (i = start, j = start; i <= end; i++) + { + if (i - j == 3) + { + SK_Point pt; + float vec[3]; + + sk_copyPoint(&pt, &old_points[j+1]); + + pt.p[0] = 0; + pt.p[1] = 0; + pt.p[2] = 0; + + VECCOPY(vec, old_points[j].p); + VecMulf(vec, -0.25); + VecAddf(pt.p, pt.p, vec); + + VECCOPY(vec, old_points[j+1].p); + VecMulf(vec, 0.75); + VecAddf(pt.p, pt.p, vec); + + VECCOPY(vec, old_points[j+2].p); + VecMulf(vec, 0.75); + VecAddf(pt.p, pt.p, vec); + + VECCOPY(vec, old_points[j+3].p); + VecMulf(vec, -0.25); + VecAddf(pt.p, pt.p, vec); + + sk_appendStrokePoint(stk, &pt); + + j += 2; + } + + /* this might be uneeded when filtering last continuous stroke */ + if (old_points[i].type == PT_EXACT) + { + sk_appendStrokePoint(stk, old_points + i); + j = i; + } + } + + /* adding points after range */ + for (i = end + 1; i < nb_points; i++) + { + sk_appendStrokePoint(stk, old_points + i); + } + + MEM_freeN(old_points); + + sk_shrinkStrokeBuffer(stk); +} + +void sk_filterLastContinuousStroke(SK_Stroke *stk) +{ + int start, end; + + end = stk->nb_points -1; + + for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--) + { + /* nothing to do here*/ + } + + if (end - start > 1) + { + sk_filterStroke(stk, start, end); + } +} + +SK_Point *sk_lastStrokePoint(SK_Stroke *stk) +{ + SK_Point *pt = NULL; + + if (stk->nb_points > 0) + { + pt = stk->points + (stk->nb_points - 1); + } + + return pt; +} + +void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end) +{ + float rgb[3]; + int i; + + if (id != -1) + { + glLoadName(id); + + glBegin(GL_LINE_STRIP); + + for (i = 0; i < stk->nb_points; i++) + { + glVertex3fv(stk->points[i].p); + } + + glEnd(); + + } + else + { + float d_rgb[3] = {1, 1, 1}; + + VECCOPY(rgb, color); + VecSubf(d_rgb, d_rgb, rgb); + VecMulf(d_rgb, 1.0f / (float)stk->nb_points); + + glBegin(GL_LINE_STRIP); + + for (i = 0; i < stk->nb_points; i++) + { + if (i >= start && i <= end) + { + glColor3f(0.3, 0.3, 0.3); + } + else + { + glColor3fv(rgb); + } + glVertex3fv(stk->points[i].p); + VecAddf(rgb, rgb, d_rgb); + } + + glEnd(); + + glColor3f(0, 0, 0); + glBegin(GL_POINTS); + + for (i = 0; i < stk->nb_points; i++) + { + if (stk->points[i].type == PT_EXACT) + { + glVertex3fv(stk->points[i].p); + } + } + + glEnd(); + } + +// glColor3f(1, 1, 1); +// glBegin(GL_POINTS); +// +// for (i = 0; i < stk->nb_points; i++) +// { +// if (stk->points[i].type == PT_CONTINUOUS) +// { +// glVertex3fv(stk->points[i].p); +// } +// } +// +// glEnd(); +} + +void drawSubdividedStrokeBy(bContext *C, BArcIterator *iter, NextSubdivisionFunc next_subdividion) +{ + float head[3], tail[3]; + int bone_start = 0; + int end = iter->length; + int index; + + iter->head(iter); + VECCOPY(head, iter->p); + + glColor3f(0, 1, 0); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2); + glBegin(GL_POINTS); + + index = next_subdividion(C, iter, bone_start, end, head, tail); + while (index != -1) + { + glVertex3fv(tail); + + VECCOPY(head, tail); + bone_start = index; // start next bone from current index + + index = next_subdividion(C, iter, bone_start, end, head, tail); + } + + glEnd(); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); +} + +void sk_drawStrokeSubdivision(bContext *C, SK_Stroke *stk) +{ + Scene *scene = CTX_data_scene(C); + int head_index = -1; + int i; + + if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET) + { + return; + } + + + for (i = 0; i < stk->nb_points; i++) + { + SK_Point *pt = stk->points + i; + + if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */ + { + if (head_index == -1) + { + head_index = i; + } + else + { + if (i - head_index > 1) + { + SK_StrokeIterator sk_iter; + BArcIterator *iter = (BArcIterator*)&sk_iter; + + initStrokeIterator(iter, stk, head_index, i); + + if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) + { + drawSubdividedStrokeBy(C, iter, nextAdaptativeSubdivision); + } + else if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) + { + drawSubdividedStrokeBy(C, iter, nextLengthSubdivision); + } + else if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED) + { + drawSubdividedStrokeBy(C, iter, nextFixedSubdivision); + } + + } + + head_index = i; + } + } + } +} + +SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, short mval[2], int *dist, int *index, int all_pts) +{ + ARegion *ar = CTX_wm_region(C); + SK_Point *pt = NULL; + int i; + + for (i = 0; i < stk->nb_points; i++) + { + if (all_pts || stk->points[i].type == PT_EXACT) + { + short pval[2]; + int pdist; + + project_short_noclip(ar, stk->points[i].p, pval); + + pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); + + if (pdist < *dist) + { + *dist = pdist; + pt = stk->points + i; + + if (index != NULL) + { + *index = i; + } + } + } + } + + return pt; +} + +SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, short mval[2], int *dist) +{ + ARegion *ar = CTX_wm_region(C); + SK_Point *pt = NULL; + EditBone *bone; + + for (bone = ebones->first; bone; bone = bone->next) + { + float vec[3]; + short pval[2]; + int pdist; + + if ((bone->flag & BONE_CONNECTED) == 0) + { + VECCOPY(vec, bone->head); + Mat4MulVecfl(ob->obmat, vec); + project_short_noclip(ar, vec, pval); + + pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); + + if (pdist < *dist) + { + *dist = pdist; + pt = &boneSnap; + VECCOPY(pt->p, vec); + pt->type = PT_EXACT; + } + } + + + VECCOPY(vec, bone->tail); + Mat4MulVecfl(ob->obmat, vec); + project_short_noclip(ar, vec, pval); + + pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]); + + if (pdist < *dist) + { + *dist = pdist; + pt = &boneSnap; + VECCOPY(pt->p, vec); + pt->type = PT_EXACT; + } + } + + return pt; +} + +void sk_resetOverdraw(SK_Sketch *sketch) +{ + sketch->over.target = NULL; + sketch->over.start = -1; + sketch->over.end = -1; + sketch->over.count = 0; +} + +int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk) +{ + return sketch->over.target && + sketch->over.count >= SK_OVERDRAW_LIMIT && + (sketch->over.target == stk || stk == NULL) && + (sketch->over.start != -1 || sketch->over.end != -1); +} + +void sk_updateOverdraw(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) +{ + if (sketch->over.target == NULL) + { + SK_Stroke *target; + int closest_index = -1; + int dist = SNAP_MIN_DISTANCE * 2; + + /* If snapping, don't start overdraw */ + if (sk_lastStrokePoint(stk)->mode == PT_SNAP) + { + return; + } + + for (target = sketch->strokes.first; target; target = target->next) + { + if (target != stk) + { + int index; + + SK_Point *spt = sk_snapPointStroke(C, target, dd->mval, &dist, &index, 1); + + if (spt != NULL) + { + sketch->over.target = target; + closest_index = index; + } + } + } + + if (sketch->over.target != NULL) + { + if (closest_index > -1) + { + if (sk_lastStrokePoint(stk)->type == PT_EXACT) + { + sketch->over.count = SK_OVERDRAW_LIMIT; + } + else + { + sketch->over.count++; + } + } + + if (stk->nb_points == 1) + { + sketch->over.start = closest_index; + } + else + { + sketch->over.end = closest_index; + } + } + } + else if (sketch->over.target != NULL) + { + SK_Point *closest_pt = NULL; + int dist = SNAP_MIN_DISTANCE * 2; + int index; + + closest_pt = sk_snapPointStroke(C, sketch->over.target, dd->mval, &dist, &index, 1); + + if (closest_pt != NULL) + { + if (sk_lastStrokePoint(stk)->type == PT_EXACT) + { + sketch->over.count = SK_OVERDRAW_LIMIT; + } + else + { + sketch->over.count++; + } + + sketch->over.end = index; + } + else + { + sketch->over.end = -1; + } + } +} + +/* return 1 on reverse needed */ +int sk_adjustIndexes(SK_Sketch *sketch, int *start, int *end) +{ + int retval = 0; + + *start = sketch->over.start; + *end = sketch->over.end; + + if (*start == -1) + { + *start = 0; + } + + if (*end == -1) + { + *end = sketch->over.target->nb_points - 1; + } + + if (*end < *start) + { + int tmp = *start; + *start = *end; + *end = tmp; + retval = 1; + } + + return retval; +} + +void sk_endOverdraw(SK_Sketch *sketch) +{ + SK_Stroke *stk = sketch->active_stroke; + + if (sk_hasOverdraw(sketch, NULL)) + { + int start; + int end; + + if (sk_adjustIndexes(sketch, &start, &end)) + { + sk_reverseStroke(stk); + } + + if (stk->nb_points > 1) + { + stk->points->type = sketch->over.target->points[start].type; + sk_lastStrokePoint(stk)->type = sketch->over.target->points[end].type; + } + + sk_insertStrokePoints(sketch->over.target, stk->points, stk->nb_points, start, end); + + sk_removeStroke(sketch, stk); + + sk_resetOverdraw(sketch); + } +} + + +void sk_startStroke(SK_Sketch *sketch) +{ + SK_Stroke *stk = sk_createStroke(); + + BLI_addtail(&sketch->strokes, stk); + sketch->active_stroke = stk; + + sk_resetOverdraw(sketch); +} + +void sk_endStroke(bContext *C, SK_Sketch *sketch) +{ + Scene *scene = CTX_data_scene(C); + sk_shrinkStrokeBuffer(sketch->active_stroke); + + if (scene->toolsettings->bone_sketching & BONE_SKETCHING_ADJUST) + { + sk_endOverdraw(sketch); + } + + sketch->active_stroke = NULL; +} + +void sk_updateDrawData(SK_DrawData *dd) +{ + dd->type = PT_CONTINUOUS; + + dd->previous_mval[0] = dd->mval[0]; + dd->previous_mval[1] = dd->mval[1]; +} + +float sk_distanceDepth(bContext *C, float p1[3], float p2[3]) +{ + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + float vec[3]; + float distance; + + VecSubf(vec, p1, p2); + + Projf(vec, vec, rv3d->viewinv[2]); + + distance = VecLength(vec); + + if (Inpf(rv3d->viewinv[2], vec) > 0) + { + distance *= -1; + } + + return distance; +} + +void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float length, float distance) +{ + ARegion *ar = CTX_wm_region(C); + ScrArea *sa = CTX_wm_area(C); + View3D *v3d = sa->spacedata.first; + + float progress = 0; + int i; + + progress = VecLenf(stk->points[start].p, stk->points[start - 1].p); + + for (i = start; i <= end; i++) + { + float ray_start[3], ray_normal[3]; + float delta = VecLenf(stk->points[i].p, stk->points[i + 1].p); + short pval[2]; + + project_short_noclip(ar, stk->points[i].p, pval); + viewray(ar, v3d, pval, ray_start, ray_normal); + + VecMulf(ray_normal, distance * progress / length); + VecAddf(stk->points[i].p, stk->points[i].p, ray_normal); + + progress += delta ; + } +} + +void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_DrawData *dd) +{ + ARegion *ar = CTX_wm_region(C); + /* copied from grease pencil, need fixing */ + SK_Point *last = sk_lastStrokePoint(stk); + short cval[2]; + float fp[3] = {0, 0, 0}; + float dvec[3]; + + if (last != NULL) + { + VECCOPY(fp, last->p); + } + + initgrabz(ar->regiondata, fp[0], fp[1], fp[2]); + + /* method taken from editview.c - mouse_cursor() */ + project_short_noclip(ar, fp, cval); + window_to_3d(ar, dvec, cval[0] - dd->mval[0], cval[1] - dd->mval[1]); + VecSubf(vec, fp, dvec); +} + +int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) +{ + pt->type = dd->type; + pt->mode = PT_PROJECT; + sk_projectDrawPoint(C, pt->p, stk, dd); + + return 1; +} + +int sk_addStrokeDrawPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) +{ + SK_Point pt; + + sk_initPoint(C, &pt); + + sk_getStrokeDrawPoint(C, &pt, sketch, stk, dd); + + sk_appendStrokePoint(stk, &pt); + + return 1; +} + +int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) +{ + Scene *scene = CTX_data_scene(C); + int point_added = 0; + + if (scene->snap_mode == SCE_SNAP_MODE_VOLUME) + { + ListBase depth_peels; + DepthPeel *p1, *p2; + float *last_p = NULL; + float dist = FLT_MAX; + float p[3]; + + depth_peels.first = depth_peels.last = NULL; + + peelObjectsContext(C, &depth_peels, dd->mval); + + if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) + { + last_p = stk->points[stk->nb_points - 1].p; + } + else if (LAST_SNAP_POINT_VALID) + { + last_p = LAST_SNAP_POINT; + } + + + for (p1 = depth_peels.first; p1; p1 = p1->next) + { + if (p1->flag == 0) + { + float vec[3]; + float new_dist; + + p2 = NULL; + p1->flag = 1; + + /* if peeling objects, take the first and last from each object */ + if (scene->snap_flag & SCE_SNAP_PEEL_OBJECT) + { + DepthPeel *peel; + for (peel = p1->next; peel; peel = peel->next) + { + if (peel->ob == p1->ob) + { + peel->flag = 1; + p2 = peel; + } + } + } + /* otherwise, pair first with second and so on */ + else + { + for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next) + { + /* nothing to do here */ + } + } + + if (p2) + { + p2->flag = 1; + + VecAddf(vec, p1->p, p2->p); + VecMulf(vec, 0.5f); + } + else + { + VECCOPY(vec, p1->p); + } + + if (last_p == NULL) + { + VECCOPY(p, vec); + dist = 0; + break; + } + + new_dist = VecLenf(last_p, vec); + + if (new_dist < dist) + { + VECCOPY(p, vec); + dist = new_dist; + } + } + } + + if (dist != FLT_MAX) + { + pt->type = dd->type; + pt->mode = PT_SNAP; + VECCOPY(pt->p, p); + + point_added = 1; + } + + BLI_freelistN(&depth_peels); + } + else + { + SK_Stroke *snap_stk; + float vec[3]; + float no[3]; + int found = 0; + int dist = SNAP_MIN_DISTANCE; // Use a user defined value here + + /* snap to strokes */ + // if (scene->snap_mode == SCE_SNAP_MODE_VERTEX) /* snap all the time to strokes */ + for (snap_stk = sketch->strokes.first; snap_stk; snap_stk = snap_stk->next) + { + SK_Point *spt = NULL; + if (snap_stk == stk) + { + spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 0); + } + else + { + spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 1); + } + + if (spt != NULL) + { + VECCOPY(pt->p, spt->p); + point_added = 1; + } + } + + /* try to snap to closer object */ + found = snapObjectsContext(C, dd->mval, &dist, vec, no, SNAP_NOT_SELECTED); + if (found == 1) + { + pt->type = dd->type; + pt->mode = PT_SNAP; + VECCOPY(pt->p, vec); + + point_added = 1; + } + } + + return point_added; +} + +int sk_addStrokeSnapPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd) +{ + int point_added; + SK_Point pt; + + sk_initPoint(C, &pt); + + point_added = sk_getStrokeSnapPoint(C, &pt, sketch, stk, dd); + + if (point_added) + { + float final_p[3]; + float length, distance; + int total; + int i; + + VECCOPY(final_p, pt.p); + + sk_projectDrawPoint(C, pt.p, stk, dd); + sk_appendStrokePoint(stk, &pt); + + /* update all previous point to give smooth Z progresion */ + total = 0; + length = 0; + for (i = stk->nb_points - 2; i > 0; i--) + { + length += VecLenf(stk->points[i].p, stk->points[i + 1].p); + total++; + if (stk->points[i].mode == PT_SNAP || stk->points[i].type == PT_EXACT) + { + break; + } + } + + if (total > 1) + { + distance = sk_distanceDepth(C, final_p, stk->points[i].p); + + sk_interpolateDepth(C, stk, i + 1, stk->nb_points - 2, length, distance); + } + + VECCOPY(stk->points[stk->nb_points - 1].p, final_p); + + point_added = 1; + } + + return point_added; +} + +void sk_addStrokePoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short qual) +{ + Scene *scene = CTX_data_scene(C); + int point_added = 0; + + if (qual & KM_CTRL) + { + point_added = sk_addStrokeSnapPoint(C, sketch, stk, dd); + } + + if (point_added == 0) + { + point_added = sk_addStrokeDrawPoint(C, sketch, stk, dd); + } + + if (scene->toolsettings->bone_sketching & BONE_SKETCHING_ADJUST) + { + sk_updateOverdraw(C, sketch, stk, dd); + } +} + +void sk_getStrokePoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short qual) +{ + int point_added = 0; + + if (qual & KM_CTRL) + { + point_added = sk_getStrokeSnapPoint(C, pt, sketch, stk, dd); + LAST_SNAP_POINT_VALID = 1; + VECCOPY(LAST_SNAP_POINT, pt->p); + } + else + { + LAST_SNAP_POINT_VALID = 0; + } + + if (point_added == 0) + { + point_added = sk_getStrokeDrawPoint(C, pt, sketch, stk, dd); + } +} + +void sk_endContinuousStroke(SK_Stroke *stk) +{ + stk->points[stk->nb_points - 1].type = PT_EXACT; +} + +void sk_updateNextPoint(SK_Sketch *sketch) +{ + if (sketch->active_stroke) + { + SK_Stroke *stk = sketch->active_stroke; + memcpy(&sketch->next_point, stk->points[stk->nb_points - 1].p, sizeof(SK_Point)); + } +} + +int sk_stroke_filtermval(SK_DrawData *dd) +{ + int retval = 0; + if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist) + { + retval = 1; + } + + return retval; +} + +void sk_initDrawData(SK_DrawData *dd) +{ +// XXX +// getmouseco_areawin(dd->mval); + dd->previous_mval[0] = -1; + dd->previous_mval[1] = -1; + dd->type = PT_EXACT; +} +/********************************************/ + +static void* headPoint(void *arg); +static void* tailPoint(void *arg); +static void* nextPoint(void *arg); +static void* nextNPoint(void *arg, int n); +static void* peekPoint(void *arg, int n); +static void* previousPoint(void *arg); +static int iteratorStopped(void *arg); + +static void initIteratorFct(SK_StrokeIterator *iter) +{ + iter->head = headPoint; + iter->tail = tailPoint; + iter->peek = peekPoint; + iter->next = nextPoint; + iter->nextN = nextNPoint; + iter->previous = previousPoint; + iter->stopped = iteratorStopped; +} + +static SK_Point* setIteratorValues(SK_StrokeIterator *iter, int index) +{ + SK_Point *pt = NULL; + + if (index >= 0 && index < iter->length) + { + pt = &(iter->stroke->points[iter->start + (iter->stride * index)]); + iter->p = pt->p; + iter->no = pt->no; + } + else + { + iter->p = NULL; + iter->no = NULL; + } + + return pt; +} + +void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + + initIteratorFct(iter); + iter->stroke = stk; + + if (start < end) + { + iter->start = start + 1; + iter->end = end - 1; + iter->stride = 1; + } + else + { + iter->start = start - 1; + iter->end = end + 1; + iter->stride = -1; + } + + iter->length = iter->stride * (iter->end - iter->start + 1); + + iter->index = -1; +} + + +static void* headPoint(void *arg) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + SK_Point *result = NULL; + + result = &(iter->stroke->points[iter->start - iter->stride]); + iter->p = result->p; + iter->no = result->no; + + return result; +} + +static void* tailPoint(void *arg) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + SK_Point *result = NULL; + + result = &(iter->stroke->points[iter->end + iter->stride]); + iter->p = result->p; + iter->no = result->no; + + return result; +} + +static void* nextPoint(void *arg) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + SK_Point *result = NULL; + + iter->index++; + if (iter->index < iter->length) + { + result = setIteratorValues(iter, iter->index); + } + + return result; +} + +static void* nextNPoint(void *arg, int n) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + SK_Point *result = NULL; + + iter->index += n; + + /* check if passed end */ + if (iter->index < iter->length) + { + result = setIteratorValues(iter, iter->index); + } + + return result; +} + +static void* peekPoint(void *arg, int n) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + SK_Point *result = NULL; + int index = iter->index + n; + + /* check if passed end */ + if (index < iter->length) + { + result = setIteratorValues(iter, index); + } + + return result; +} + +static void* previousPoint(void *arg) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + SK_Point *result = NULL; + + if (iter->index > 0) + { + iter->index--; + result = setIteratorValues(iter, iter->index); + } + + return result; +} + +static int iteratorStopped(void *arg) +{ + SK_StrokeIterator *iter = (SK_StrokeIterator*)arg; + + if (iter->index >= iter->length) + { + return 1; + } + else + { + return 0; + } +} + +void sk_convertStroke(bContext *C, SK_Stroke *stk) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + bArmature *arm = obedit->data; + SK_Point *head; + EditBone *parent = NULL; + float invmat[4][4]; /* move in caller function */ + float tmat[3][3]; + int head_index = 0; + int i; + + head = NULL; + + Mat4Invert(invmat, obedit->obmat); + + Mat3CpyMat4(tmat, obedit->obmat); + Mat3Transp(tmat); + + for (i = 0; i < stk->nb_points; i++) + { + SK_Point *pt = stk->points + i; + + if (pt->type == PT_EXACT) + { + if (head == NULL) + { + head_index = i; + head = pt; + } + else + { + EditBone *bone = NULL; + EditBone *new_parent; + + if (i - head_index > 1) + { + SK_StrokeIterator sk_iter; + BArcIterator *iter = (BArcIterator*)&sk_iter; + + initStrokeIterator(iter, stk, head_index, i); + + if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) + { + bone = subdivideArcBy(C, arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision); + } + else if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) + { + bone = subdivideArcBy(C, arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision); + } + else if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED) + { + bone = subdivideArcBy(C, arm, arm->edbo, iter, invmat, tmat, nextFixedSubdivision); + } + } + + if (bone == NULL) + { + bone = addEditBone(arm, "Bone"); + + VECCOPY(bone->head, head->p); + VECCOPY(bone->tail, pt->p); + + Mat4MulVecfl(invmat, bone->head); + Mat4MulVecfl(invmat, bone->tail); + setBoneRollFromNormal(bone, pt->no, invmat, tmat); + } + + new_parent = bone; + bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; + + /* move to end of chain */ + while (bone->parent != NULL) + { + bone = bone->parent; + bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; + } + + if (parent != NULL) + { + bone->parent = parent; + bone->flag |= BONE_CONNECTED; + } + + parent = new_parent; + head_index = i; + head = pt; + } + } + } +} + +void sk_convert(bContext *C, SK_Sketch *sketch) +{ + Scene *scene = CTX_data_scene(C); + SK_Stroke *stk; + + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + if (stk->selected == 1) + { + if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET) + { + sk_retargetStroke(C, stk); + } + else + { + sk_convertStroke(C, stk); + } +// XXX +// allqueue(REDRAWBUTSEDIT, 0); + } + } +} +/******************* GESTURE *************************/ + + +/* returns the number of self intersections */ +int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gesture) +{ + ARegion *ar = CTX_wm_region(C); + int added = 0; + int s_i; + + for (s_i = 0; s_i < gesture->nb_points - 1; s_i++) + { + float s_p1[3] = {0, 0, 0}; + float s_p2[3] = {0, 0, 0}; + int g_i; + + project_float(ar, gesture->points[s_i].p, s_p1); + project_float(ar, gesture->points[s_i + 1].p, s_p2); + + /* start checking from second next, because two consecutive cannot intersect */ + for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++) + { + float g_p1[3] = {0, 0, 0}; + float g_p2[3] = {0, 0, 0}; + float vi[3]; + float lambda; + + project_float(ar, gesture->points[g_i].p, g_p1); + project_float(ar, gesture->points[g_i + 1].p, g_p2); + + if (LineIntersectLineStrict(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) + { + SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); + + isect->gesture_index = g_i; + isect->before = s_i; + isect->after = s_i + 1; + isect->stroke = gesture; + + VecSubf(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p); + VecMulf(isect->p, lambda); + VecAddf(isect->p, isect->p, gesture->points[s_i].p); + + BLI_addtail(list, isect); + + added++; + } + } + } + + return added; +} + +int cmpIntersections(void *i1, void *i2) +{ + SK_Intersection *isect1 = i1, *isect2 = i2; + + if (isect1->stroke == isect2->stroke) + { + if (isect1->before < isect2->before) + { + return -1; + } + else if (isect1->before > isect2->before) + { + return 1; + } + else + { + if (isect1->lambda < isect2->lambda) + { + return -1; + } + else if (isect1->lambda > isect2->lambda) + { + return 1; + } + } + } + + return 0; +} + + +/* returns the maximum number of intersections per stroke */ +int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture) +{ + ARegion *ar = CTX_wm_region(C); + ScrArea *sa = CTX_wm_area(C); + View3D *v3d = sa->spacedata.first; + SK_Stroke *stk; + int added = 0; + + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + int s_added = 0; + int s_i; + + for (s_i = 0; s_i < stk->nb_points - 1; s_i++) + { + float s_p1[3] = {0, 0, 0}; + float s_p2[3] = {0, 0, 0}; + int g_i; + + project_float(ar, stk->points[s_i].p, s_p1); + project_float(ar, stk->points[s_i + 1].p, s_p2); + + for (g_i = 0; g_i < gesture->nb_points - 1; g_i++) + { + float g_p1[3] = {0, 0, 0}; + float g_p2[3] = {0, 0, 0}; + float vi[3]; + float lambda; + + project_float(ar, gesture->points[g_i].p, g_p1); + project_float(ar, gesture->points[g_i + 1].p, g_p2); + + if (LineIntersectLineStrict(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) + { + SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection"); + float ray_start[3], ray_end[3]; + short mval[2]; + + isect->gesture_index = g_i; + isect->before = s_i; + isect->after = s_i + 1; + isect->stroke = stk; + isect->lambda = lambda; + + mval[0] = (short)(vi[0]); + mval[1] = (short)(vi[1]); + viewline(ar, v3d, mval, ray_start, ray_end); + + LineIntersectLine( stk->points[s_i].p, + stk->points[s_i + 1].p, + ray_start, + ray_end, + isect->p, + vi); + + BLI_addtail(list, isect); + + s_added++; + } + } + } + + added = MAX2(s_added, added); + } + + BLI_sortlist(list, cmpIntersections); + + return added; +} + +int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture) +{ + SK_StrokeIterator sk_iter; + BArcIterator *iter = (BArcIterator*)&sk_iter; + + float CORRELATION_THRESHOLD = 0.99f; + float *vec; + int i, j; + + sk_appendStrokePoint(segments, &gesture->points[0]); + vec = segments->points[segments->nb_points - 1].p; + + initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1); + + for (i = 1, j = 0; i < gesture->nb_points; i++) + { + float n[3]; + + /* Calculate normal */ + VecSubf(n, gesture->points[i].p, vec); + + if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD) + { + j = i - 1; + sk_appendStrokePoint(segments, &gesture->points[j]); + vec = segments->points[segments->nb_points - 1].p; + segments->points[segments->nb_points - 1].type = PT_EXACT; + } + } + + sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]); + + return segments->nb_points - 1; +} + +int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + if (gest->nb_segments == 1 && gest->nb_intersections == 1) + { + return 1; + } + + return 0; +} + +void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + SK_Intersection *isect; + + for (isect = gest->intersections.first; isect; isect = isect->next) + { + SK_Point pt; + + pt.type = PT_EXACT; + pt.mode = PT_PROJECT; /* take mode from neighbouring points */ + VECCOPY(pt.p, isect->p); + + sk_insertStrokePoint(isect->stroke, &pt, isect->after); + } +} + +int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + if (gest->nb_segments == 2 && gest->nb_intersections == 1 && gest->nb_self_intersections == 0) + { + float s1[3], s2[3]; + float angle; + + VecSubf(s1, gest->segments->points[1].p, gest->segments->points[0].p); + VecSubf(s2, gest->segments->points[2].p, gest->segments->points[1].p); + + angle = VecAngle2(s1, s2); + + if (angle > 60 && angle < 120) + { + return 1; + } + } + + return 0; +} + +void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + SK_Intersection *isect; + float trim_dir[3]; + + VecSubf(trim_dir, gest->segments->points[2].p, gest->segments->points[1].p); + + for (isect = gest->intersections.first; isect; isect = isect->next) + { + SK_Point pt; + float stroke_dir[3]; + + pt.type = PT_EXACT; + pt.mode = PT_PROJECT; /* take mode from neighbouring points */ + VECCOPY(pt.p, isect->p); + + VecSubf(stroke_dir, isect->stroke->points[isect->after].p, isect->stroke->points[isect->before].p); + + /* same direction, trim end */ + if (Inpf(stroke_dir, trim_dir) > 0) + { + sk_replaceStrokePoint(isect->stroke, &pt, isect->after); + sk_trimStroke(isect->stroke, 0, isect->after); + } + /* else, trim start */ + else + { + sk_replaceStrokePoint(isect->stroke, &pt, isect->before); + sk_trimStroke(isect->stroke, isect->before, isect->stroke->nb_points - 1); + } + + } +} + +int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1) + { + SK_Intersection *isect, *self_isect; + + /* get the the last intersection of the first pair */ + for( isect = gest->intersections.first; isect; isect = isect->next ) + { + if (isect->stroke == isect->next->stroke) + { + isect = isect->next; + break; + } + } + + self_isect = gest->self_intersections.first; + + if (isect && isect->gesture_index < self_isect->gesture_index) + { + return 1; + } + } + + return 0; +} + +void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + SK_Intersection *isect; + int command = 1; + +// XXX +// command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3"); + if(command < 1) return; + + for (isect = gest->intersections.first; isect; isect = isect->next) + { + SK_Intersection *i2; + + i2 = isect->next; + + if (i2 && i2->stroke == isect->stroke) + { + switch (command) + { + case 1: + sk_flattenStroke(isect->stroke, isect->before, i2->after); + break; + case 2: + sk_straightenStroke(isect->stroke, isect->before, i2->after, isect->p, i2->p); + break; + case 3: + sk_polygonizeStroke(isect->stroke, isect->before, i2->after); + break; + } + + isect = i2; + } + } +} + +int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + if (gest->nb_segments == 2 && gest->nb_intersections == 2) + { + float s1[3], s2[3]; + float angle; + + VecSubf(s1, gest->segments->points[1].p, gest->segments->points[0].p); + VecSubf(s2, gest->segments->points[2].p, gest->segments->points[1].p); + + angle = VecAngle2(s1, s2); + + if (angle > 120) + { + return 1; + } + } + + return 0; +} + +void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + SK_Intersection *isect; + + for (isect = gest->intersections.first; isect; isect = isect->next) + { + /* only delete strokes that are crossed twice */ + if (isect->next && isect->next->stroke == isect->stroke) + { + isect = isect->next; + + sk_removeStroke(sketch, isect->stroke); + } + } +} + +int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + ARegion *ar = CTX_wm_region(C); + if (gest->nb_segments > 2 && gest->nb_intersections == 2) + { + short start_val[2], end_val[2]; + short dist; + + project_short_noclip(ar, gest->stk->points[0].p, start_val); + project_short_noclip(ar, sk_lastStrokePoint(gest->stk)->p, end_val); + + dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1])); + + /* if gesture is a circle */ + if ( dist <= 20 ) + { + SK_Intersection *isect; + + /* check if it circled around an exact point */ + for (isect = gest->intersections.first; isect; isect = isect->next) + { + /* only delete strokes that are crossed twice */ + if (isect->next && isect->next->stroke == isect->stroke) + { + int start_index, end_index; + int i; + + start_index = MIN2(isect->after, isect->next->after); + end_index = MAX2(isect->before, isect->next->before); + + for (i = start_index; i <= end_index; i++) + { + if (isect->stroke->points[i].type == PT_EXACT) + { + return 1; /* at least one exact point found, stop detect here */ + } + } + + /* skip next */ + isect = isect->next; + } + } + } + } + + return 0; +} + +void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + SK_Intersection *isect; + + /* check if it circled around an exact point */ + for (isect = gest->intersections.first; isect; isect = isect->next) + { + /* only merge strokes that are crossed twice */ + if (isect->next && isect->next->stroke == isect->stroke) + { + int start_index, end_index; + int i; + + start_index = MIN2(isect->after, isect->next->after); + end_index = MAX2(isect->before, isect->next->before); + + for (i = start_index; i <= end_index; i++) + { + /* if exact, switch to continuous */ + if (isect->stroke->points[i].type == PT_EXACT) + { + isect->stroke->points[i].type = PT_CONTINUOUS; + } + } + + /* skip next */ + isect = isect->next; + } + } +} + +int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 0) + { + SK_Intersection *isect; + + /* check if it circled around an exact point */ + for (isect = gest->intersections.first; isect; isect = isect->next) + { + /* only delete strokes that are crossed twice */ + if (isect->next && isect->next->stroke == isect->stroke) + { + float start_v[3], end_v[3]; + float angle; + + if (isect->gesture_index < isect->next->gesture_index) + { + VecSubf(start_v, isect->p, gest->stk->points[0].p); + VecSubf(end_v, sk_lastStrokePoint(gest->stk)->p, isect->next->p); + } + else + { + VecSubf(start_v, isect->next->p, gest->stk->points[0].p); + VecSubf(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p); + } + + angle = VecAngle2(start_v, end_v); + + if (angle > 120) + { + return 1; + } + + /* skip next */ + isect = isect->next; + } + } + } + + return 0; +} + +void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + SK_Intersection *isect; + + for (isect = gest->intersections.first; isect; isect = isect->next) + { + /* only reverse strokes that are crossed twice */ + if (isect->next && isect->next->stroke == isect->stroke) + { + sk_reverseStroke(isect->stroke); + + /* skip next */ + isect = isect->next; + } + } +} + +int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + if (gest->nb_segments == 3 && gest->nb_self_intersections == 1) + { + return 1; + } + return 0; +} + +void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + sk_convert(C, sketch); +} + +static void sk_initGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch) +{ + gest->intersections.first = gest->intersections.last = NULL; + gest->self_intersections.first = gest->self_intersections.last = NULL; + + gest->segments = sk_createStroke(); + gest->stk = sketch->gesture; + + gest->nb_self_intersections = sk_getSelfIntersections(C, &gest->self_intersections, gest->stk); + gest->nb_intersections = sk_getIntersections(C, &gest->intersections, sketch, gest->stk); + gest->nb_segments = sk_getSegments(gest->segments, gest->stk); +} + +static void sk_freeGesture(SK_Gesture *gest) +{ + sk_freeStroke(gest->segments); + BLI_freelistN(&gest->intersections); + BLI_freelistN(&gest->self_intersections); +} + +void sk_applyGesture(bContext *C, SK_Sketch *sketch) +{ + SK_Gesture gest; + SK_GestureAction *act; + + sk_initGesture(C, &gest, sketch); + + /* detect and apply */ + for (act = GESTURE_ACTIONS; act->apply != NULL; act++) + { + if (act->detect(C, &gest, sketch)) + { + act->apply(C, &gest, sketch); + break; + } + } + + sk_freeGesture(&gest); +} + +/********************************************/ + +void sk_deleteSelectedStrokes(SK_Sketch *sketch) +{ + SK_Stroke *stk, *next; + + for (stk = sketch->strokes.first; stk; stk = next) + { + next = stk->next; + + if (stk->selected == 1) + { + sk_removeStroke(sketch, stk); + } + } +} + +void sk_selectAllSketch(SK_Sketch *sketch, int mode) +{ + SK_Stroke *stk = NULL; + + if (mode == -1) + { + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + stk->selected = 0; + } + } + else if (mode == 0) + { + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + stk->selected = 1; + } + } + else if (mode == 1) + { + int selected = 1; + + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + selected &= stk->selected; + } + + selected ^= 1; + + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + stk->selected = selected; + } + } +} + +void sk_selectStroke(SK_Sketch *sketch, short mval[2], int extend) +{ + unsigned int buffer[MAXPICKBUF]; + short hits; + +//XXX +#if 0 + persp(PERSP_VIEW); + + hits = view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5); + if(hits==0) + hits = view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-12, mval[1]-12, mval[0]+12, mval[1]+12); + + if (hits>0) + { + int besthitresult = -1; + + if(hits == 1) { + besthitresult = buffer[3]; + } + else { + besthitresult = buffer[3]; + /* loop and get best hit */ + } + + if (besthitresult > 0) + { + SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1); + + if (extend == 0) + { + sk_selectAllSketch(sketch, -1); + + selected_stk->selected = 1; + } + else + { + selected_stk->selected ^= 1; + } + + + } + } +#endif +} + +void sk_queueRedrawSketch(SK_Sketch *sketch) +{ + if (sketch->active_stroke != NULL) + { + SK_Point *last = sk_lastStrokePoint(sketch->active_stroke); + + if (last != NULL) + { +// XXX +// allqueue(REDRAWVIEW3D, 0); + } + } +} + +void sk_drawSketch(bContext *C, SK_Sketch *sketch, int with_names) +{ + Scene *scene = CTX_data_scene(C); + SK_Stroke *stk; + short qual = 0; + + glDisable(GL_DEPTH_TEST); + + glLineWidth(UI_GetThemeValuef(TH_VERTEX_SIZE)); + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + if (with_names) + { + int id; + for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next) + { + sk_drawStroke(stk, id, NULL, -1, -1); + } + + glLoadName(-1); + } + else + { + float selected_rgb[3] = {1, 0, 0}; + float unselected_rgb[3] = {1, 0.5, 0}; + + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + int start = -1; + int end = -1; + + if (sk_hasOverdraw(sketch, stk)) + { + sk_adjustIndexes(sketch, &start, &end); + } + + sk_drawStroke(stk, -1, (stk->selected==1?selected_rgb:unselected_rgb), start, end); + + if (stk->selected == 1) + { + sk_drawStrokeSubdivision(C, stk); + } + } + + /* only draw gesture in active area */ + if (sketch->gesture != NULL /*&& area_is_active_area(G.vd->area)*/) + { + float gesture_rgb[3] = {0, 0.5, 1}; + sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1); + } + + if (sketch->active_stroke != NULL) + { + SK_Point *last = sk_lastStrokePoint(sketch->active_stroke); + + if (scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK) + { + sk_drawStrokeSubdivision(C, sketch->active_stroke); + } + + if (last != NULL) + { + /* update point if in active area */ + if (1 /*area_is_active_area(G.vd->area)*/) + { + SK_DrawData dd; + + sk_initDrawData(&dd); + sk_getStrokePoint(C, &sketch->next_point, sketch, sketch->active_stroke, &dd, qual); + } + + glEnable(GL_LINE_STIPPLE); + glColor3fv(selected_rgb); + glBegin(GL_LINE_STRIP); + + glVertex3fv(last->p); + glVertex3fv(sketch->next_point.p); + + glEnd(); + + glDisable(GL_LINE_STIPPLE); + + switch (sketch->next_point.mode) + { + case PT_SNAP: + glColor3f(0, 1, 0); + break; + case PT_PROJECT: + glColor3f(0, 0, 0); + break; + } + + glBegin(GL_POINTS); + + glVertex3fv(sketch->next_point.p); + + glEnd(); + } + } + } + + glLineWidth(1.0); + glPointSize(1.0); + + glEnable(GL_DEPTH_TEST); +} + +int sk_paint(bContext *C, SK_Sketch *sketch, short mbut) +{ + Scene *scene = CTX_data_scene(C); + int retval = 1; + short qual = 0; + + if (mbut == LEFTMOUSE) + { + SK_DrawData dd; + if (sketch->active_stroke == NULL) + { + sk_startStroke(sketch); + sk_selectAllSketch(sketch, -1); + + sketch->active_stroke->selected = 1; + } + + sk_initDrawData(&dd); + + /* paint loop */ + do { + /* get current user input */ +// XXX +// getmouseco_areawin(dd.mval); + + /* only add current point to buffer if mouse moved (otherwise wait until it does) */ + if (sk_stroke_filtermval(&dd)) { + + sk_addStrokePoint(C, sketch, sketch->active_stroke, &dd, qual); + sk_updateDrawData(&dd); +// XXX +// force_draw(0); + } + else + { +// BIF_wait_for_statechange(); + } + +// while( qtest() ) { +// short event, val; +// event = extern_qread(&val); +// } + + /* do mouse checking at the end, so don't check twice, and potentially + * miss a short tap + */ + } while (0 /*get_mbut() & L_MOUSE*/); + + sk_endContinuousStroke(sketch->active_stroke); + sk_filterLastContinuousStroke(sketch->active_stroke); + sk_updateNextPoint(sketch); + } + else if (mbut == RIGHTMOUSE) + { + if (sketch->active_stroke != NULL) + { + SK_Stroke *stk = sketch->active_stroke; + + sk_endStroke(C, sketch); + + if (scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK) + { + if (scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET) + { + sk_retargetStroke(C, stk); + } + else + { + sk_convertStroke(C, stk); + } +// XXX +// BIF_undo_push("Convert Sketch"); + sk_removeStroke(sketch, stk); +// XXX +// allqueue(REDRAWBUTSEDIT, 0); + } + +// XXX +// allqueue(REDRAWVIEW3D, 0); + } + /* no gestures in quick mode */ + else if (scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK) + { + retval = 0; /* return zero for default click behavior */ + } + else + { + SK_DrawData dd; + sketch->gesture = sk_createStroke(); + + sk_initDrawData(&dd); + + /* paint loop */ + do { + /* get current user input */ +// XXX +// getmouseco_areawin(dd.mval); + + /* only add current point to buffer if mouse moved (otherwise wait until it does) */ + if (sk_stroke_filtermval(&dd)) { + + sk_addStrokeDrawPoint(C, sketch, sketch->gesture, &dd); + sk_updateDrawData(&dd); + + /* draw only if mouse has moved */ + if (sketch->gesture->nb_points > 1) + { +// XXX +// force_draw(0); + } + } + else + { +// BIF_wait_for_statechange(); + } + +// while( qtest() ) { +// short event, val; +// event = extern_qread(&val); +// } + + /* do mouse checking at the end, so don't check twice, and potentially + * miss a short tap + */ + } while (0 /*get_mbut() & R_MOUSE*/); + + sk_endContinuousStroke(sketch->gesture); + sk_filterLastContinuousStroke(sketch->gesture); + sk_filterLastContinuousStroke(sketch->gesture); + sk_filterLastContinuousStroke(sketch->gesture); + + if (sketch->gesture->nb_points > 1) + { + /* apply gesture here */ + sk_applyGesture(C, sketch); + } + + sk_freeStroke(sketch->gesture); + sketch->gesture = NULL; + +// XXX +// allqueue(REDRAWVIEW3D, 0); + } + } + + return retval; +} + +void BDR_drawSketchNames(bContext *C) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_drawSketch(C, GLOBAL_sketch, 1); + } + } +} + +void BDR_drawSketch(bContext *C) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_drawSketch(C, GLOBAL_sketch, 0); + } + } +} + +void BIF_endStrokeSketch(bContext *C) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_endStroke(C, GLOBAL_sketch); +// allqueue(REDRAWVIEW3D, 0); + } + } +} + +void BIF_cancelStrokeSketch(bContext *C) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_cancelStroke(GLOBAL_sketch); +// allqueue(REDRAWVIEW3D, 0); + } + } +} + +void BIF_deleteSketch(bContext *C) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_deleteSelectedStrokes(GLOBAL_sketch); +// allqueue(REDRAWVIEW3D, 0); + } + } +} + +void BIF_convertSketch(bContext *C) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_convert(C, GLOBAL_sketch); +// BIF_undo_push("Convert Sketch"); +// allqueue(REDRAWVIEW3D, 0); +// allqueue(REDRAWBUTSEDIT, 0); + } + } +} + +int BIF_paintSketch(bContext *C, short mbut) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch == NULL) + { + GLOBAL_sketch = sk_createSketch(); + } + + return sk_paint(C, GLOBAL_sketch, mbut); + } + else + { + return 0; + } +} + + +void BDR_queueDrawSketch(bContext *C) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_queueRedrawSketch(GLOBAL_sketch); + } + } +} + +void BIF_selectAllSketch(bContext *C, int mode) +{ + if (BIF_validSketchMode(C)) + { + if (GLOBAL_sketch != NULL) + { + sk_selectAllSketch(GLOBAL_sketch, mode); +// XXX +// allqueue(REDRAWVIEW3D, 0); + } + } +} + +int BIF_validSketchMode(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + + if (obedit && + obedit->type == OB_ARMATURE && + scene->toolsettings->bone_sketching & BONE_SKETCHING) + { + return 1; + } + else + { + return 0; + } +} + +int BIF_fullSketchMode(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + + if (obedit && + obedit->type == OB_ARMATURE && + scene->toolsettings->bone_sketching & BONE_SKETCHING && + (scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK) == 0) + { + return 1; + } + else + { + return 0; + } +} + +void BIF_freeSketch(bContext *C) +{ + if (GLOBAL_sketch != NULL) + { + sk_freeSketch(GLOBAL_sketch); + GLOBAL_sketch = NULL; + } +} + +void BIF_sk_selectStroke(bContext *C, short mval[2], int extend) +{ + if (GLOBAL_sketch != NULL) + { + sk_selectStroke(GLOBAL_sketch, mval, extend); + } +} |