Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_global.h1
-rw-r--r--source/blender/blenkernel/intern/object.c1
-rw-r--r--source/blender/blenlib/BLI_arithb.h2
-rw-r--r--source/blender/blenlib/BLI_graph.h33
-rw-r--r--source/blender/blenlib/intern/arithb.c112
-rw-r--r--source/blender/blenlib/intern/graph.c60
-rw-r--r--source/blender/blenloader/intern/readfile.c79
-rw-r--r--source/blender/include/BDR_sketch.h30
-rw-r--r--source/blender/include/BIF_editarmature.h25
-rw-r--r--source/blender/include/BIF_generate.h44
-rw-r--r--source/blender/include/BIF_retarget.h154
-rw-r--r--source/blender/include/BIF_sketch.h43
-rw-r--r--source/blender/include/BIF_space.h1
-rw-r--r--source/blender/include/BIF_transform.h28
-rw-r--r--source/blender/include/reeb.h35
-rw-r--r--source/blender/makesdna/DNA_scene_types.h33
-rw-r--r--source/blender/python/api2_2x/Armature.c2
-rw-r--r--source/blender/python/api2_2x/Bone.c2
-rw-r--r--source/blender/src/buttons_editing.c1
-rw-r--r--source/blender/src/drawview.c142
-rw-r--r--source/blender/src/edit.c7
-rw-r--r--source/blender/src/editarmature.c474
-rw-r--r--source/blender/src/editarmature_generate.c327
-rw-r--r--source/blender/src/editarmature_retarget.c (renamed from source/blender/src/autoarmature.c)1438
-rw-r--r--source/blender/src/editarmature_sketch.c3073
-rw-r--r--source/blender/src/gpencil.c2
-rw-r--r--source/blender/src/header_view3d.c5
-rw-r--r--source/blender/src/reeb.c313
-rw-r--r--source/blender/src/space.c35
-rw-r--r--source/blender/src/transform_snap.c940
-rw-r--r--source/blender/src/usiblender.c2
-rw-r--r--source/blender/src/view.c11
32 files changed, 6036 insertions, 1419 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index e8918bcdce6..eb89e1699ea 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -151,7 +151,6 @@ typedef struct Global {
/* confusing... G.f and G.flags */
int flags;
-
} Global;
/* **************** GLOBAL ********************* */
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index a25afeafaef..0b153c3c065 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -521,6 +521,7 @@ void unlink_object(Object *ob)
while(sce) {
if(sce->id.lib==NULL) {
if(sce->camera==ob) sce->camera= NULL;
+ if(sce->toolsettings->skgen_template==ob) sce->toolsettings->skgen_template = NULL;
}
sce= sce->id.next;
}
diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h
index fd58aa318da..092ed00fbe5 100644
--- a/source/blender/blenlib/BLI_arithb.h
+++ b/source/blender/blenlib/BLI_arithb.h
@@ -391,8 +391,10 @@ void tubemap(float x, float y, float z, float *u, float *v);
void spheremap(float x, float y, float z, float *u, float *v);
int LineIntersectLine(float v1[3], float v2[3], float v3[3], float v4[3], float i1[3], float i2[3]);
+int LineIntersectLineStrict(float v1[3], float v2[3], float v3[3], float v4[3], float vi[3], float *lambda);
int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv);
int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv);
+int RayIntersectsTriangleThreshold(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float threshold);
int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, float v0[3], float v1[3], float v2[3], float *lambda, float *ipoint);
int AxialLineIntersectsTriangle(int axis, float co1[3], float co2[3], float v0[3], float v1[3], float v2[3], float *lambda);
int AabbIntersectAabb(float min1[3], float max1[3], float min2[3], float max2[3]);
diff --git a/source/blender/blenlib/BLI_graph.h b/source/blender/blenlib/BLI_graph.h
index 160c2e04cf5..f4fccfcbb2c 100644
--- a/source/blender/blenlib/BLI_graph.h
+++ b/source/blender/blenlib/BLI_graph.h
@@ -60,6 +60,39 @@ typedef struct BArc {
int symmetry_flag;
} BArc;
+struct BArcIterator;
+
+void* IT_head(void* iter);
+void* IT_tail(void* iter);
+void* IT_peek(void* iter, int n);
+void* IT_next(void* iter);
+void* IT_nextN(void* iter, int n);
+void* IT_previous(void* iter);
+int IT_stopped(void* iter);
+
+typedef void* (*HeadFct)(void* iter);
+typedef void* (*TailFct)(void* iter);
+typedef void* (*PeekFct)(void* iter, int n);
+typedef void* (*NextFct)(void* iter);
+typedef void* (*NextNFct)(void* iter, int n);
+typedef void* (*PreviousFct)(void* iter);
+typedef int (*StoppedFct)(void* iter);
+
+typedef struct BArcIterator {
+ HeadFct head;
+ TailFct tail;
+ PeekFct peek;
+ NextFct next;
+ NextNFct nextN;
+ PreviousFct previous;
+ StoppedFct stopped;
+
+ float *p, *no;
+
+ int length;
+ int index;
+} BArcIterator;
+
/* Helper structure for radial symmetry */
typedef struct RadialArc
{
diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c
index 61cbf791bf1..ad1dc1ca12c 100644
--- a/source/blender/blenlib/intern/arithb.c
+++ b/source/blender/blenlib/intern/arithb.c
@@ -3896,6 +3896,57 @@ int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], flo
return 1;
}
+int RayIntersectsTriangleThreshold(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float threshold)
+{
+ float p[3], s[3], e1[3], e2[3], q[3];
+ float a, f, u, v;
+ float du = 0, dv = 0;
+
+ VecSubf(e1, v1, v0);
+ VecSubf(e2, v2, v0);
+
+ Crossf(p, d, e2);
+ a = Inpf(e1, p);
+ if ((a > -0.000001) && (a < 0.000001)) return 0;
+ f = 1.0f/a;
+
+ VecSubf(s, p1, v0);
+
+ Crossf(q, s, e1);
+ *lambda = f * Inpf(e2, q);
+ if ((*lambda < 0.0)) return 0;
+
+ u = f * Inpf(s, p);
+ v = f * Inpf(d, q);
+
+ if (u < 0) du = u;
+ if (u > 1) du = u - 1;
+ if (v < 0) dv = v;
+ if (v > 1) dv = v - 1;
+ if (u > 0 && v > 0 && u + v > 1)
+ {
+ float t = u + v - 1;
+ du = u - t/2;
+ dv = v - t/2;
+ }
+
+ VecMulf(e1, du);
+ VecMulf(e2, dv);
+
+ if (Inpf(e1, e1) + Inpf(e2, e2) > threshold * threshold)
+ {
+ return 0;
+ }
+
+ if(uv) {
+ uv[0]= u;
+ uv[1]= v;
+ }
+
+ return 1;
+}
+
+
/* Adapted from the paper by Kasper Fauerby */
/* "Improved Collision detection and Response" */
static int getLowestRoot(float a, float b, float c, float maxR, float* root)
@@ -4245,6 +4296,67 @@ int LineIntersectLine(float v1[3], float v2[3], float v3[3], float v4[3], float
}
}
+/* Intersection point strictly between the two lines
+ * 0 when no intersection is found
+ * */
+int LineIntersectLineStrict(float v1[3], float v2[3], float v3[3], float v4[3], float vi[3], float *lambda)
+{
+ float a[3], b[3], c[3], ab[3], cb[3], ca[3], dir1[3], dir2[3];
+ float d;
+ float d1;
+
+ VecSubf(c, v3, v1);
+ VecSubf(a, v2, v1);
+ VecSubf(b, v4, v3);
+
+ VecCopyf(dir1, a);
+ Normalize(dir1);
+ VecCopyf(dir2, b);
+ Normalize(dir2);
+ d = Inpf(dir1, dir2);
+ if (d == 1.0f || d == -1.0f || d == 0) {
+ /* colinear or one vector is zero-length*/
+ return 0;
+ }
+
+ d1 = d;
+
+ Crossf(ab, a, b);
+ d = Inpf(c, ab);
+
+ /* test if the two lines are coplanar */
+ if (d > -0.000001f && d < 0.000001f) {
+ float f1, f2;
+ Crossf(cb, c, b);
+ Crossf(ca, c, a);
+
+ f1 = Inpf(cb, ab) / Inpf(ab, ab);
+ f2 = Inpf(ca, ab) / Inpf(ab, ab);
+
+ if (f1 >= 0 && f1 <= 1 &&
+ f2 >= 0 && f2 <= 1)
+ {
+ VecMulf(a, f1);
+ VecAddf(vi, v1, a);
+
+ if (lambda != NULL)
+ {
+ *lambda = f1;
+ }
+
+ return 1; /* intersection found */
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return 0;
+ }
+}
+
int AabbIntersectAabb(float min1[3], float max1[3], float min2[3], float max2[3])
{
return (min1[0]<max2[0] && min1[1]<max2[1] && min1[2]<max2[2] &&
diff --git a/source/blender/blenlib/intern/graph.c b/source/blender/blenlib/intern/graph.c
index bcd8a2ce7cd..52277063a8f 100644
--- a/source/blender/blenlib/intern/graph.c
+++ b/source/blender/blenlib/intern/graph.c
@@ -465,8 +465,6 @@ int subtreeShape(BNode *node, BArc *rootArc, int include_root)
int BLI_subtreeShape(BGraph *graph, BNode *node, BArc *rootArc, int include_root)
{
- BNode *test_node;
-
BLI_flagNodes(graph, 0);
return subtreeShape(node, rootArc, include_root);
}
@@ -1033,6 +1031,11 @@ void BLI_markdownSymmetry(BGraph *graph, BNode *root_node, float limit)
BNode *node;
BArc *arc;
+ if (root_node == NULL)
+ {
+ return;
+ }
+
if (BLI_isGraphCyclic(graph))
{
return;
@@ -1085,3 +1088,56 @@ void BLI_markdownSymmetry(BGraph *graph, BNode *root_node, float limit)
}
}
+void* IT_head(void* arg)
+{
+ BArcIterator *iter = (BArcIterator*)arg;
+ return iter->head(iter);
+}
+
+void* IT_tail(void* arg)
+{
+ BArcIterator *iter = (BArcIterator*)arg;
+ return iter->tail(iter);
+}
+
+void* IT_peek(void* arg, int n)
+{
+ BArcIterator *iter = (BArcIterator*)arg;
+
+ if (iter->index + n < 0)
+ {
+ return iter->head(iter);
+ }
+ else if (iter->index + n >= iter->length)
+ {
+ return iter->tail(iter);
+ }
+ else
+ {
+ return iter->peek(iter, n);
+ }
+}
+
+void* IT_next(void* arg)
+{
+ BArcIterator *iter = (BArcIterator*)arg;
+ return iter->next(iter);
+}
+
+void* IT_nextN(void* arg, int n)
+{
+ BArcIterator *iter = (BArcIterator*)arg;
+ return iter->nextN(iter, n);
+}
+
+void* IT_previous(void* arg)
+{
+ BArcIterator *iter = (BArcIterator*)arg;
+ return iter->previous(iter);
+}
+
+int IT_stopped(void* arg)
+{
+ BArcIterator *iter = (BArcIterator*)arg;
+ return iter->stopped(iter);
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index dc9c97cb3f5..7fc2a995a2f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3477,6 +3477,9 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->toolsettings->imapaint.brush=
newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush);
+
+ sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
+
/* Sculptdata textures */
for(a=0; a<MAX_MTEX; ++a) {
MTex *mtex= sce->sculptdata.mtex[a];
@@ -7387,47 +7390,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
ima->flag |= IMA_DO_PREMUL;
}
}
-
- if (main->versionfile < 245 || main->subversionfile < 12)
- {
- /* initialize skeleton generation toolsettings */
- for(sce=main->scene.first; sce; sce = sce->id.next)
- {
- sce->toolsettings->skgen_resolution = 50;
- sce->toolsettings->skgen_threshold_internal = 0.01f;
- sce->toolsettings->skgen_threshold_external = 0.01f;
- sce->toolsettings->skgen_angle_limit = 45.0f;
- sce->toolsettings->skgen_length_ratio = 1.3f;
- sce->toolsettings->skgen_length_limit = 1.5f;
- sce->toolsettings->skgen_correlation_limit = 0.98f;
- sce->toolsettings->skgen_symmetry_limit = 0.1f;
- sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
- sce->toolsettings->skgen_postpro_passes = 1;
- sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL|SKGEN_FILTER_EXTERNAL|SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
- }
- }
- }
-
- /* sanity check for skgen
- * */
- {
- Scene *sce;
- for(sce=main->scene.first; sce; sce = sce->id.next)
- {
- if (sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[1] ||
- sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] ||
- sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2])
- {
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
- }
- }
}
-
if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 2)) {
Image *ima;
@@ -8009,17 +7972,43 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 2)) {
+ if (main->versionfile < 248 || main->subversionfile < 2)
+ {
Scene *sce;
- /* Note, these will need to be added for painting */
- for (sce= main->scene.first; sce; sce= sce->id.next) {
+ for(sce=main->scene.first; sce; sce = sce->id.next)
+ {
+ /* Note, these will need to be added for painting */
sce->toolsettings->imapaint.seam_bleed = 2;
sce->toolsettings->imapaint.normal_angle = 80;
+
+ /* initialize skeleton generation toolsettings */
+ sce->toolsettings->skgen_resolution = 250;
+ sce->toolsettings->skgen_threshold_internal = 0.1f;
+ sce->toolsettings->skgen_threshold_external = 0.1f;
+ sce->toolsettings->skgen_angle_limit = 30.0f;
+ sce->toolsettings->skgen_length_ratio = 1.3f;
+ sce->toolsettings->skgen_length_limit = 1.5f;
+ sce->toolsettings->skgen_correlation_limit = 0.98f;
+ sce->toolsettings->skgen_symmetry_limit = 0.1f;
+ sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
+ sce->toolsettings->skgen_postpro_passes = 3;
+ sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL|SKGEN_FILTER_EXTERNAL|SKGEN_FILTER_SMART|SKGEN_SUB_CORRELATION|SKGEN_HARMONIC;
+ sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
+ sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
+ sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+
+
+ sce->toolsettings->skgen_retarget_angle_weight = 1.0f;
+ sce->toolsettings->skgen_retarget_length_weight = 1.0f;
+ sce->toolsettings->skgen_retarget_distance_weight = 1.0f;
+
+ /* Skeleton Sketching */
+ sce->toolsettings->bone_sketching = 0;
+ sce->toolsettings->skgen_retarget_roll = SK_RETARGET_ROLL_VIEW;
}
}
-
-
+
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
diff --git a/source/blender/include/BDR_sketch.h b/source/blender/include/BDR_sketch.h
new file mode 100644
index 00000000000..55d6e1d80cf
--- /dev/null
+++ b/source/blender/include/BDR_sketch.h
@@ -0,0 +1,30 @@
+/**
+ * $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 *****
+ */
+
+#ifndef BDR_SKETCH_H
+#define BDR_SKETCH_H
+
+void BDR_queueDrawSketch();
+void BDR_drawSketch();
+void BDR_drawSketchNames();
+
+#endif /* BDR_SKETCH_H */
diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h
index ce275563a87..19d64f853e8 100644
--- a/source/blender/include/BIF_editarmature.h
+++ b/source/blender/include/BIF_editarmature.h
@@ -68,6 +68,23 @@ typedef struct EditBone
} EditBone;
+EditBone *addEditBone(char *name, struct ListBase *ebones, struct bArmature *arm);
+
+/* duplicate method */
+void preEditBoneDuplicate(struct ListBase *editbones);
+EditBone *duplicateEditBone(EditBone *curBone, char *name, struct ListBase *editbones, struct Object *ob);
+void updateDuplicateSubtarget(EditBone *dupBone, struct ListBase *editbones, struct Object *ob);
+
+/* duplicate method (cross objects */
+
+/* editbones is the target list */
+EditBone *duplicateEditBoneObjects(EditBone *curBone, char *name, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+
+/* editbones is the source list */
+void updateDuplicateSubtargetObjects(EditBone *dupBone, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+
+/* -- */
+
float rollBoneToVector(EditBone *bone, float new_up_axis[3]);
void make_boneList(struct ListBase *list, struct ListBase *bones, EditBone *parent);
@@ -117,7 +134,7 @@ void selectconnected_posearmature(void);
void armature_select_hierarchy(short direction, short add_to_sel);
void setflag_armature(short mode);
-void unique_editbone_name (struct ListBase *ebones, char *name);
+void unique_editbone_name (struct ListBase *ebones, char *name, EditBone *bone); /* if bone is already in list, pass it as param to ignore it */
void auto_align_armature(short mode);
void switch_direction_armature(void);
@@ -152,11 +169,15 @@ void align_selected_bones(void);
#define BONESEL_NOSEL 0x80000000 /* Indicates a negative number */
-/* from autoarmature */
+/* from editarmature_retarget */
void BIF_retargetArmature();
void BIF_adjustRetarget();
void BIF_freeRetarget();
+/* from editarmature_sketch */
+void BIF_freeSketch();
+void BIF_freeTemplates();
+
struct ReebArc;
float calcVariance(struct ReebArc *arc, int start, int end, float v0[3], float n[3]);
float calcDistance(struct ReebArc *arc, int start, int end, float head[3], float tail[3]);
diff --git a/source/blender/include/BIF_generate.h b/source/blender/include/BIF_generate.h
new file mode 100644
index 00000000000..e64edf99bdc
--- /dev/null
+++ b/source/blender/include/BIF_generate.h
@@ -0,0 +1,44 @@
+/**
+ * $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 *****
+ */
+
+#ifndef BIF_GENERATE_H
+#define BIF_GENERATE_H
+
+struct EditBone;
+struct BArcIterator;
+struct bArmature;
+struct ListBase;
+
+typedef int(NextSubdivisionFunc)(struct BArcIterator*, int, int, float[3], float[3]);
+
+float calcArcCorrelation(struct BArcIterator *iter, int start, int end, float v0[3], float n[3]);
+
+int nextFixedSubdivision(struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
+int nextLengthSubdivision(struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
+int nextAdaptativeSubdivision(struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
+
+struct EditBone * subdivideArcBy(struct bArmature *arm, ListBase *editbones, struct BArcIterator *iter, float invmat[][4], float tmat[][3], NextSubdivisionFunc next_subdividion);
+
+void setBoneRollFromNormal(struct EditBone *bone, float *no, float invmat[][4], float tmat[][3]);
+
+
+#endif /* BIF_GENERATE_H */
diff --git a/source/blender/include/BIF_retarget.h b/source/blender/include/BIF_retarget.h
new file mode 100644
index 00000000000..9de10fb2a38
--- /dev/null
+++ b/source/blender/include/BIF_retarget.h
@@ -0,0 +1,154 @@
+/**
+ * $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 *****
+ */
+
+#ifndef BIF_RETARGET_H
+#define BIF_RETARGET_H
+
+#include "DNA_listBase.h"
+
+#include "BLI_graph.h"
+#include "BLI_ghash.h"
+#include "BLI_threads.h"
+
+#include "reeb.h"
+
+struct Object;
+struct bArmature;
+
+struct EditBone;
+
+struct RigJoint;
+struct RigGraph;
+struct RigNode;
+struct RigArc;
+struct RigEdge;
+
+#define USE_THREADS
+
+typedef struct RigGraph {
+ ListBase arcs;
+ ListBase nodes;
+
+ float length;
+
+ FreeArc free_arc;
+ FreeNode free_node;
+ RadialSymmetry radial_symmetry;
+ AxialSymmetry axial_symmetry;
+ /*********************************/
+
+ ListBase controls;
+ ListBase* editbones;
+
+ struct RigNode *head;
+ ReebGraph *link_mesh;
+
+
+ struct ThreadedWorker *worker;
+
+ GHash *bones_map; /* map of editbones by name */
+ GHash *controls_map; /* map of rigcontrols by bone pointer */
+
+ struct Object *ob;
+} RigGraph;
+
+typedef struct RigNode {
+ void *next, *prev;
+ float p[3];
+ int flag;
+
+ int degree;
+ struct BArc **arcs;
+
+ int subgraph_index;
+
+ int symmetry_level;
+ int symmetry_flag;
+ float symmetry_axis[3];
+ /*********************************/
+
+ ReebNode *link_mesh;
+} RigNode;
+
+typedef struct RigArc {
+ void *next, *prev;
+ RigNode *head, *tail;
+ int flag;
+
+ float length;
+
+ int symmetry_level;
+ int symmetry_group;
+ int symmetry_flag;
+ /*********************************/
+
+ ListBase edges;
+ int count;
+ ReebArc *link_mesh;
+} RigArc;
+
+typedef struct RigEdge {
+ struct RigEdge *next, *prev;
+ float head[3], tail[3];
+ float length;
+ float angle; /* angle to next edge */
+ float up_angle; /* angle between up_axis and the joint normal (defined as Previous edge CrossProduct Current edge */
+ struct EditBone *bone;
+ float up_axis[3];
+} RigEdge;
+
+/* Control flags */
+#define RIG_CTRL_HEAD_DONE 1
+#define RIG_CTRL_TAIL_DONE 2
+#define RIG_CTRL_PARENT_DEFORM 4
+#define RIG_CTRL_FIT_ROOT 8
+#define RIG_CTRL_FIT_BONE 16
+
+#define RIG_CTRL_DONE (RIG_CTRL_HEAD_DONE|RIG_CTRL_TAIL_DONE)
+
+/* Control tail flags */
+typedef enum {
+ TL_NONE = 0,
+ TL_TAIL,
+ TL_HEAD
+} LinkTailMode;
+
+typedef struct RigControl {
+ struct RigControl *next, *prev;
+ float head[3], tail[3];
+ struct EditBone *bone;
+ struct EditBone *link;
+ struct EditBone *link_tail;
+ float up_axis[3];
+ float offset[3];
+ float qrot[4]; /* for dual linked bones, store the rotation of the linked bone for the finalization */
+ int flag;
+ LinkTailMode tail_mode;
+} RigControl;
+
+void BIF_retargetArc(ReebArc *earc, RigGraph *template_rigg);
+RigGraph *RIG_graphFromArmature(struct Object *ob, struct bArmature *arm);
+int RIG_nbJoints(RigGraph *rg);
+char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index);
+void RIG_freeRigGraph(BGraph *rg);
+
+#endif /* BIF_RETARGET_H */
diff --git a/source/blender/include/BIF_sketch.h b/source/blender/include/BIF_sketch.h
new file mode 100644
index 00000000000..9cd7393633e
--- /dev/null
+++ b/source/blender/include/BIF_sketch.h
@@ -0,0 +1,43 @@
+/**
+ * $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 *****
+ */
+
+#ifndef BIF_SKETCH_H
+#define BIF_SKETCH_H
+
+int BIF_paintSketch(short mbut);
+void BIF_endStrokeSketch();
+void BIF_convertSketch();
+void BIF_deleteSketch();
+void BIF_selectAllSketch(int mode); /* -1: deselect, 0: select, 1: toggle */
+int BIF_validSketchMode();
+int BIF_fullSketchMode(); /* full sketch turned on (not Quick) */
+void BIF_cancelStrokeSketch();
+
+void BIF_makeListTemplates();
+char *BIF_listTemplates();
+int BIF_currentTemplate();
+void BIF_freeTemplates();
+void BIF_setTemplate(int);
+int BIF_nbJointsTemplate();
+char * BIF_nameBoneTemplate();
+
+#endif /* BIF_SKETCH_H */
diff --git a/source/blender/include/BIF_space.h b/source/blender/include/BIF_space.h
index c7d0f4a1ada..a52b499e936 100644
--- a/source/blender/include/BIF_space.h
+++ b/source/blender/include/BIF_space.h
@@ -54,6 +54,7 @@ struct SpaceOops;
#define VIEW3D_HANDLER_MULTIRES 5
#define VIEW3D_HANDLER_TRANSFORM 6
#define VIEW3D_HANDLER_GREASEPENCIL 7
+#define VIEW3D_HANDLER_BONESKETCH 8
/* ipo handler codes */
#define IPO_HANDLER_PROPERTIES 20
diff --git a/source/blender/include/BIF_transform.h b/source/blender/include/BIF_transform.h
index 0e3985fc52c..096201f86d0 100644
--- a/source/blender/include/BIF_transform.h
+++ b/source/blender/include/BIF_transform.h
@@ -86,6 +86,7 @@ struct TransInfo;
struct ScrArea;
struct Base;
struct Scene;
+struct Object;
struct TransInfo * BIF_GetTransInfo(void);
void BIF_setSingleAxisConstraint(float vec[3], char *text);
@@ -125,5 +126,32 @@ void ManipulatorTransform();
int BIF_do_manipulator(struct ScrArea *sa);
void BIF_draw_manipulator(struct ScrArea *sa);
+/* Snapping */
+
+
+typedef struct DepthPeel
+{
+ struct DepthPeel *next, *prev;
+
+ float depth;
+ float p[3];
+ float no[3];
+ struct Object *ob;
+ int flag;
+} DepthPeel;
+
+struct ListBase;
+
+typedef enum SnapMode
+{
+ NOT_SELECTED = 0,
+ NOT_ACTIVE = 1
+} SnapMode;
+
+#define SNAP_MIN_DISTANCE 30
+
+int snapObjects(int *dist, float *loc, float *no, SnapMode mode);
+int peelObjects(struct ListBase *depth_peels, short mval[2]);
+
#endif
diff --git a/source/blender/include/reeb.h b/source/blender/include/reeb.h
index 57f7d1b60cf..eab0e2a8601 100644
--- a/source/blender/include/reeb.h
+++ b/source/blender/include/reeb.h
@@ -28,7 +28,7 @@
#ifndef REEB_H_
#define REEB_H_
-//#define WITH_BF_REEB
+#define WITH_BF_REEB
#include "DNA_listBase.h"
@@ -63,6 +63,7 @@ typedef struct EmbedBucket {
float val;
int nv;
float p[3];
+ float no[3]; /* if non-null, normal of the bucket */
} EmbedBucket;
typedef struct ReebNode {
@@ -79,6 +80,8 @@ typedef struct ReebNode {
int symmetry_flag;
float symmetry_axis[3];
/*********************************/
+
+ float no[3];
int index;
float weight;
@@ -117,12 +120,23 @@ typedef struct ReebArc {
} ReebArc;
typedef struct ReebArcIterator {
- struct ReebArc *arc;
+ HeadFct head;
+ TailFct tail;
+ PeekFct peek;
+ NextFct next;
+ NextNFct nextN;
+ PreviousFct previous;
+ StoppedFct stopped;
+
+ float *p, *no;
+
+ int length;
int index;
+ /*********************************/
+ struct ReebArc *arc;
int start;
int end;
- int stride;
- int length;
+ int stride;
} ReebArcIterator;
struct EditMesh;
@@ -139,15 +153,9 @@ void renormalizeWeight(struct EditMesh *em, float newmax);
ReebGraph * generateReebGraph(struct EditMesh *me, int subdivisions);
ReebGraph * newReebGraph();
-void initArcIterator(struct ReebArcIterator *iter, struct ReebArc *arc, struct ReebNode *head);
-void initArcIterator2(struct ReebArcIterator *iter, struct ReebArc *arc, int start, int end);
-void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start);
-struct EmbedBucket * nextBucket(struct ReebArcIterator *iter);
-struct EmbedBucket * nextNBucket(ReebArcIterator *iter, int n);
-struct EmbedBucket * peekBucket(ReebArcIterator *iter, int n);
-struct EmbedBucket * currentBucket(struct ReebArcIterator *iter);
-struct EmbedBucket * previousBucket(struct ReebArcIterator *iter);
-int iteratorStopped(struct ReebArcIterator *iter);
+void initArcIterator(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head);
+void initArcIterator2(BArcIterator *iter, struct ReebArc *arc, int start, int end);
+void initArcIteratorStart(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start);
/* Filtering */
void filterNullReebGraph(ReebGraph *rg);
@@ -185,6 +193,7 @@ ReebNode *BIF_lowestLevelNode(ReebNode *node);
ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node);
void REEB_freeGraph(ReebGraph *rg);
+void REEB_freeArc(BArc *barc);
void REEB_exportGraph(ReebGraph *rg, int count);
void REEB_draw();
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 09c2344d53a..35e086b418a 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -447,12 +447,20 @@ typedef struct ToolSettings {
char skgen_postpro_passes;
char skgen_subdivisions[3];
char skgen_multi_level;
- char skgen_optimisation_method;
- char tpad[6];
+ /* Skeleton Sketching */
+ struct Object *skgen_template;
+ char bone_sketching;
+ char bone_sketching_convert;
+ char skgen_subdivision_number;
+ char skgen_retarget_options;
+ char skgen_retarget_roll;
+ char skgen_side_string[8];
+ char skgen_num_string[8];
/* Alt+RMB option */
char edge_mode;
+ char pad3[2];
} ToolSettings;
/* Used by all brushes to store their properties, which can be directly set
@@ -734,6 +742,7 @@ typedef struct Scene {
/* scene->snap_flag */
#define SCE_SNAP 1
#define SCE_SNAP_ROTATE 2
+#define SCE_SNAP_PEEL_OBJECT 4
/* scene->snap_target */
#define SCE_SNAP_TARGET_CLOSEST 0
#define SCE_SNAP_TARGET_CENTER 1
@@ -743,6 +752,7 @@ typedef struct Scene {
#define SCE_SNAP_MODE_VERTEX 0
#define SCE_SNAP_MODE_EDGE 1
#define SCE_SNAP_MODE_FACE 2
+#define SCE_SNAP_MODE_VOLUME 3
/* sce->selectmode */
#define SCE_SELECT_VERTEX 1 /* for mesh */
@@ -892,6 +902,25 @@ typedef struct Scene {
#define SKGEN_AVERAGE 1
#define SKGEN_SHARPEN 2
+/* toolsettings->bone_sketching */
+#define BONE_SKETCHING 1
+#define BONE_SKETCHING_QUICK 2
+#define BONE_SKETCHING_ADJUST 4
+
+/* toolsettings->bone_sketching_convert */
+#define SK_CONVERT_CUT_FIXED 1
+#define SK_CONVERT_CUT_LENGTH 2
+#define SK_CONVERT_CUT_ADAPTATIVE 3
+#define SK_CONVERT_RETARGET 4
+
+/* toolsettings->skgen_retarget_options */
+#define SK_RETARGET_AUTONAME 1
+
+/* toolsettings->skgen_retarget_roll */
+#define SK_RETARGET_ROLL_VIEW 1
+#define SK_RETARGET_ROLL_JOINT 2
+
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/python/api2_2x/Armature.c b/source/blender/python/api2_2x/Armature.c
index 99a4398ec89..2ef0c2b4afe 100644
--- a/source/blender/python/api2_2x/Armature.c
+++ b/source/blender/python/api2_2x/Armature.c
@@ -280,7 +280,7 @@ static int BonesDict_SetItem(BPy_BonesDict *self, PyObject *key, PyObject *value
//create a new editbone
editbone = MEM_callocN(sizeof(EditBone), "eBone");
BLI_strncpy(editbone->name, key_str, 32);
- unique_editbone_name(NULL, editbone->name);
+ unique_editbone_name(NULL, editbone->name, NULL);
editbone->dist = ((BPy_EditBone*)value)->dist;
editbone->ease1 = ((BPy_EditBone*)value)->ease1;
editbone->ease2 = ((BPy_EditBone*)value)->ease2;
diff --git a/source/blender/python/api2_2x/Bone.c b/source/blender/python/api2_2x/Bone.c
index 948eb007803..cacb3584344 100644
--- a/source/blender/python/api2_2x/Bone.c
+++ b/source/blender/python/api2_2x/Bone.c
@@ -832,7 +832,7 @@ static PyObject *EditBone_new(PyTypeObject *type, PyObject *args, PyObject *kwds
//otherwise this will act as a py_object
py_editBone->editbone = NULL;
- unique_editbone_name(NULL, name);
+ unique_editbone_name(NULL, name, NULL);
BLI_strncpy(py_editBone->name, name, 32);
py_editBone->parent = NULL;
py_editBone->weight= 1.0f;
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index 953519416e1..7b564bdd7a3 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -5312,7 +5312,6 @@ static void editing_panel_mesh_skgen_retarget(Object *ob, Mesh *me)
uiDefButF(block, NUM, B_DIFF, "Ang:", 1025, 40, 83,19, &G.scene->toolsettings->skgen_retarget_angle_weight, 0, 10, 1, 0, "Angle Weight");
uiDefButF(block, NUM, B_DIFF, "Len:", 1108, 40, 83,19, &G.scene->toolsettings->skgen_retarget_length_weight, 0, 10, 1, 0, "Length Weight");
uiDefButF(block, NUM, B_DIFF, "Dist:", 1191, 40, 84,19, &G.scene->toolsettings->skgen_retarget_distance_weight, 0, 10, 1, 0, "Distance Weight");
- uiDefButC(block, NUM, B_DIFF, "Method:", 1025, 20, 125,19, &G.scene->toolsettings->skgen_optimisation_method, 0, 2, 1, 0,"Optimisation Method (0: brute, 1: memoize, 2: annealing max fixed");
}
static void editing_panel_mesh_skgen(Object *ob, Mesh *me)
diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c
index 44b61c816a5..cb4fa246562 100644
--- a/source/blender/src/drawview.c
+++ b/source/blender/src/drawview.c
@@ -130,6 +130,7 @@
#include "BIF_resources.h"
#include "BIF_retopo.h"
#include "BIF_screen.h"
+#include "BIF_sketch.h"
#include "BIF_space.h"
#ifdef WITH_VERSE
@@ -143,6 +144,7 @@
#include "BDR_vpaint.h"
#include "BDR_sculptmode.h"
#include "BDR_gpencil.h"
+#include "BDR_sketch.h"
#include "BSE_drawview.h"
#include "BSE_filesel.h"
@@ -2272,6 +2274,141 @@ static void view3d_panel_transform_spaces(short cntrl)
if(yco < 0) uiNewPanelHeight(block, height-yco);
}
+static void delete_sketch_armature(void *arg1, void *arg2)
+{
+ BIF_deleteSketch();
+}
+
+static void convert_sketch_armature(void *arg1, void *arg2)
+{
+ BIF_convertSketch();
+}
+
+static void assign_template_sketch_armature(void *arg1, void *arg2)
+{
+ int index = *(int*)arg1;
+ BIF_setTemplate(index);
+}
+static void view3d_panel_bonesketch_spaces(short cntrl)
+{
+ static int template_index;
+ static char joint_label[128];
+ uiBlock *block;
+ uiBut *but;
+ char *bone_name;
+ int yco = 130, height = 140;
+ int nb_joints;
+
+ /* replace with check call to sketching lib */
+ if (G.obedit && G.obedit->type == OB_ARMATURE)
+ {
+ static char subdiv_tooltip[4][64] = {
+ "Subdivide arcs based on a fixed number of bones",
+ "Subdivide arcs in bones of equal length",
+ "Subdivide arcs based on correlation",
+ "Retarget template to stroke"
+ };
+
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_panel_bonesketch_spaces", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(VIEW3D_HANDLER_BONESKETCH); // for close and esc
+
+ if(uiNewPanel(curarea, block, "Bone Sketching", "View3d", 10, 230, 250, height)==0) return;
+
+ uiNewPanelHeight(block, height);
+
+ uiBlockBeginAlign(block);
+
+ /* use real flag instead of 1 */
+ uiDefButBitC(block, TOG, BONE_SKETCHING, B_REDR, "Use Bone Sketching", 10, yco, 160, 20, &G.scene->toolsettings->bone_sketching, 0, 0, 0, 0, "Use sketching to create and edit bones");
+ uiDefButBitC(block, TOG, BONE_SKETCHING_ADJUST, B_REDR, "A", 170, yco, 20, 20, &G.scene->toolsettings->bone_sketching, 0, 0, 0, 0, "Adjust strokes by drawing near them");
+ uiDefButBitC(block, TOG, BONE_SKETCHING_QUICK, B_REDR, "Q", 190, yco, 20, 20, &G.scene->toolsettings->bone_sketching, 0, 0, 0, 0, "Automatically convert and delete on stroke end");
+ yco -= 20;
+
+ but = uiDefBut(block, BUT, B_REDR, "Convert", 10,yco,100,20, 0, 0, 0, 0, 0, "Convert sketch to armature");
+ uiButSetFunc(but, convert_sketch_armature, NULL, NULL);
+
+ but = uiDefBut(block, BUT, B_REDR, "Delete", 110,yco,100,20, 0, 0, 0, 0, 0, "Delete sketch");
+ uiButSetFunc(but, delete_sketch_armature, NULL, NULL);
+ yco -= 20;
+
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+
+ uiDefButC(block, MENU, B_REDR, "Subdivision Method%t|Length%x2|Adaptative%x3|Fixed%x1|Template%x4", 10,yco,60,19, &G.scene->toolsettings->bone_sketching_convert, 0, 0, 0, 0, subdiv_tooltip[(unsigned char)G.scene->toolsettings->bone_sketching_convert]);
+
+ switch(G.scene->toolsettings->bone_sketching_convert)
+ {
+ case SK_CONVERT_CUT_LENGTH:
+ uiDefButF(block, NUM, B_REDR, "Lim:", 70, yco, 140, 19, &G.scene->toolsettings->skgen_length_limit,0.1,50.0, 10, 0, "Maximum length of the subdivided bones");
+ yco -= 20;
+ break;
+ case SK_CONVERT_CUT_ADAPTATIVE:
+ uiDefButF(block, NUM, B_REDR, "Thres:", 70, yco, 140, 19, &G.scene->toolsettings->skgen_correlation_limit,0.0, 1.0, 0.01, 0, "Correlation threshold for subdivision");
+ yco -= 20;
+ break;
+ default:
+ case SK_CONVERT_CUT_FIXED:
+ uiDefButC(block, NUM, B_REDR, "Num:", 70, yco, 140, 19, &G.scene->toolsettings->skgen_subdivision_number,1, 100, 1, 5, "Number of subdivided bones");
+ yco -= 20;
+ break;
+ case SK_CONVERT_RETARGET:
+ uiDefButC(block, ROW, B_DIFF, "No", 70, yco, 40,19, &G.scene->toolsettings->skgen_retarget_roll, 0, 0, 0, 0, "No special roll treatment");
+ uiDefButC(block, ROW, B_DIFF, "View", 110, yco, 50,19, &G.scene->toolsettings->skgen_retarget_roll, 0, SK_RETARGET_ROLL_VIEW, 0, 0, "Roll bones perpendicular to view");
+ uiDefButC(block, ROW, B_DIFF, "Joint", 160, yco, 50,19, &G.scene->toolsettings->skgen_retarget_roll, 0, SK_RETARGET_ROLL_JOINT, 0, 0, "Roll bones relative to joint bend");
+ yco -= 30;
+
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ /* button here to select what to do (copy or not), template, ...*/
+
+ BIF_makeListTemplates();
+ template_index = BIF_currentTemplate();
+
+ but = uiDefButI(block, MENU, B_REDR, BIF_listTemplates(), 10,yco,200,19, &template_index, 0, 0, 0, 0, "Template");
+ uiButSetFunc(but, assign_template_sketch_armature, &template_index, NULL);
+
+ yco -= 20;
+
+ uiDefButF(block, NUM, B_DIFF, "A:", 10, yco, 66,19, &G.scene->toolsettings->skgen_retarget_angle_weight, 0, 10, 1, 0, "Angle Weight");
+ uiDefButF(block, NUM, B_DIFF, "L:", 76, yco, 67,19, &G.scene->toolsettings->skgen_retarget_length_weight, 0, 10, 1, 0, "Length Weight");
+ uiDefButF(block, NUM, B_DIFF, "D:", 143,yco, 67,19, &G.scene->toolsettings->skgen_retarget_distance_weight, 0, 10, 1, 0, "Distance Weight");
+ yco -= 20;
+
+ uiDefBut(block, TEX,B_DIFF,"S:", 10, yco, 90, 20, G.scene->toolsettings->skgen_side_string, 0.0, 8.0, 0, 0, "Text to replace &S with");
+ uiDefBut(block, TEX,B_DIFF,"N:", 100, yco, 90, 20, G.scene->toolsettings->skgen_num_string, 0.0, 8.0, 0, 0, "Text to replace &N with");
+ uiDefIconButBitC(block, TOG, SK_RETARGET_AUTONAME, B_DIFF, ICON_AUTO,190,yco,20,20, &G.scene->toolsettings->skgen_retarget_options, 0, 0, 0, 0, "Use Auto Naming");
+ yco -= 20;
+
+ /* auto renaming magic */
+ uiBlockEndAlign(block);
+
+ nb_joints = BIF_nbJointsTemplate();
+
+ if (nb_joints == -1)
+ {
+ nb_joints = G.totvertsel;
+ }
+
+ bone_name = BIF_nameBoneTemplate();
+
+ BLI_snprintf(joint_label, 32, "%i joints: %s", nb_joints, bone_name);
+
+ uiDefBut(block, LABEL, 1, joint_label, 10, yco, 200, 20, NULL, 0.0, 0.0, 0, 0, "");
+ yco -= 20;
+ break;
+ }
+
+ uiBlockEndAlign(block);
+
+ uiDefButBitS(block, TOG, SCE_SNAP_PEEL_OBJECT, B_DIFF, "Peel Objects", 10, yco, 200, 20, &G.scene->snap_flag, 0, 0, 0, 0, "Peel whole objects as one");
+
+ if(yco < 0) uiNewPanelHeight(block, height-yco);
+ }
+}
static void view3d_panel_object(short cntrl) // VIEW3D_HANDLER_OBJECT
{
@@ -2663,6 +2800,9 @@ static void view3d_blockhandlers(ScrArea *sa)
case VIEW3D_HANDLER_GREASEPENCIL:
view3d_panel_gpencil(v3d->blockhandler[a+1]);
break;
+ case VIEW3D_HANDLER_BONESKETCH:
+ view3d_panel_bonesketch_spaces(v3d->blockhandler[a+1]);
+ break;
}
/* clear action value for event */
v3d->blockhandler[a+1]= 0;
@@ -3271,6 +3411,8 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
/* draw grease-pencil stuff */
if (v3d->flag2 & V3D_DISPGP)
draw_gpencil_3dview(sa, 1);
+
+ BDR_drawSketch();
persp(PERSP_WIN); // set ortho
diff --git a/source/blender/src/edit.c b/source/blender/src/edit.c
index a80e7b6c360..f681b65925f 100644
--- a/source/blender/src/edit.c
+++ b/source/blender/src/edit.c
@@ -99,6 +99,7 @@
#include "BIF_space.h"
#include "BIF_screen.h"
#include "BIF_toolbox.h"
+#include "BIF_sketch.h"
#ifdef WITH_VERSE
#include "BIF_verse.h"
@@ -1838,7 +1839,11 @@ void mergemenu(void)
void delete_context_selected(void)
{
- if(G.obedit) {
+ if(BIF_fullSketchMode())
+ {
+ BIF_deleteSketch();
+ }
+ else if(G.obedit) {
if(G.obedit->type==OB_MESH) delete_mesh();
else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) delNurb();
else if(G.obedit->type==OB_MBALL) delete_mball();
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c
index ee5d56eaf43..ec14e2aabe2 100644
--- a/source/blender/src/editarmature.c
+++ b/source/blender/src/editarmature.c
@@ -93,6 +93,7 @@
#include "BIF_space.h"
#include "BIF_toolbox.h"
#include "BIF_transform.h"
+#include "BIF_generate.h"
#include "BDR_editobject.h"
#include "BDR_drawobject.h"
@@ -699,7 +700,7 @@ int join_armature(void)
curbone= editbone_name_exists(&eblist, pchan->name);
/* Get new name */
- unique_editbone_name(&ebbase, curbone->name);
+ unique_editbone_name(&ebbase, curbone->name, NULL);
/* Transform the bone */
{
@@ -1740,6 +1741,8 @@ void make_editArmature(void)
if (!arm) return;
make_boneList(&G.edbo, &arm->bonebase,NULL);
+
+ BIF_freeTemplates(); /* force template update when entering editmode */
}
/* put EditMode back in Object */
@@ -1994,17 +1997,14 @@ void undo_push_armature(char *name)
/* **************** END EditMode stuff ********************** */
/* *************** Adding stuff in editmode *************** */
-/* default bone add, returns it selected, but without tail set */
-static EditBone *add_editbone(char *name)
+EditBone *addEditBone(char *name, ListBase *ebones, bArmature *arm)
{
- bArmature *arm= G.obedit->data;
-
EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
BLI_strncpy(bone->name, name, 32);
- unique_editbone_name(&G.edbo, bone->name);
+ unique_editbone_name(ebones, bone->name, NULL);
- BLI_addtail(&G.edbo, bone);
+ BLI_addtail(ebones, bone);
bone->flag |= BONE_TIPSEL;
bone->weight= 1.0F;
@@ -2021,6 +2021,14 @@ static EditBone *add_editbone(char *name)
return bone;
}
+/* default bone add, returns it selected, but without tail set */
+static EditBone *add_editbone(char *name)
+{
+ bArmature *arm= G.obedit->data;
+
+ return addEditBone(name, &G.edbo, arm);
+}
+
static void add_primitive_bone(Object *ob, short newob)
{
float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
@@ -2192,13 +2200,12 @@ static EditBone *add_points_bone (float head[], float tail[])
return ebo;
}
-
-static EditBone *get_named_editbone(char *name)
+static EditBone *get_named_editbone_from_list(char *name, ListBase *editbones)
{
EditBone *eBone;
if (name) {
- for (eBone=G.edbo.first; eBone; eBone=eBone->next) {
+ for (eBone=editbones->first; eBone; eBone=eBone->next) {
if (!strcmp(name, eBone->name))
return eBone;
}
@@ -2207,7 +2214,29 @@ static EditBone *get_named_editbone(char *name)
return NULL;
}
-static void update_dup_subtarget(EditBone *dupBone)
+static EditBone *get_named_editbone(char *name)
+{
+ return get_named_editbone_from_list(name, &G.edbo);
+}
+
+/* Call this before doing any duplications
+ * */
+void preEditBoneDuplicate(ListBase *editbones)
+{
+ EditBone *eBone;
+
+ /* clear temp */
+ for (eBone = editbones->first; eBone; eBone = eBone->next)
+ {
+ eBone->temp = NULL;
+ }
+}
+
+/*
+ * Note: When duplicating cross objects, editbones here is the list of bones
+ * from the SOURCE object but ob is the DESTINATION object
+ * */
+void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
{
/* If an edit bone has been duplicated, lets
* update it's constraints if the subtarget
@@ -2218,7 +2247,7 @@ static void update_dup_subtarget(EditBone *dupBone)
bConstraint *curcon;
ListBase *conlist;
- if ( (chan = verify_pose_channel(OBACT->pose, dupBone->name)) ) {
+ if ( (chan = verify_pose_channel(dst_ob->pose, dupBone->name)) ) {
if ( (conlist = &chan->constraints) ) {
for (curcon = conlist->first; curcon; curcon=curcon->next) {
/* does this constraint have a subtarget in
@@ -2232,14 +2261,15 @@ static void update_dup_subtarget(EditBone *dupBone)
cti->get_constraint_targets(curcon, &targets);
for (ct= targets.first; ct; ct= ct->next) {
- if ((ct->tar == G.obedit) && (ct->subtarget[0])) {
- oldtarget = get_named_editbone(ct->subtarget);
+ if ((ct->tar == src_ob) && (ct->subtarget[0])) {
+ ct->tar = dst_ob; /* update target */
+ oldtarget = get_named_editbone_from_list(ct->subtarget, editbones);
if (oldtarget) {
/* was the subtarget bone duplicated too? If
* so, update the constraint to point at the
* duplicate of the old subtarget.
*/
- if (oldtarget->flag & BONE_SELECTED){
+ if (oldtarget->temp){
newtarget = (EditBone *) oldtarget->temp;
strcpy(ct->subtarget, newtarget->name);
}
@@ -2255,6 +2285,78 @@ static void update_dup_subtarget(EditBone *dupBone)
}
}
+void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+{
+ updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+}
+
+
+EditBone *duplicateEditBoneObjects(EditBone *curBone, char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+{
+ EditBone *eBone = MEM_callocN(sizeof(EditBone), "addup_editbone");
+
+ /* Copy data from old bone to new bone */
+ memcpy(eBone, curBone, sizeof(EditBone));
+
+ curBone->temp = eBone;
+ eBone->temp = curBone;
+
+ if (name != NULL)
+ {
+ BLI_strncpy(eBone->name, name, 32);
+ }
+
+ unique_editbone_name(editbones, eBone->name, NULL);
+ BLI_addtail(editbones, eBone);
+
+ /* Lets duplicate the list of constraints that the
+ * current bone has.
+ */
+ if (src_ob->pose) {
+ bPoseChannel *chanold, *channew;
+ ListBase *listold, *listnew;
+
+ chanold = verify_pose_channel(src_ob->pose, curBone->name);
+ if (chanold) {
+ listold = &chanold->constraints;
+ if (listold) {
+ /* WARNING: this creates a new posechannel, but there will not be an attached bone
+ * yet as the new bones created here are still 'EditBones' not 'Bones'.
+ */
+ channew =
+ verify_pose_channel(dst_ob->pose, eBone->name);
+ if (channew) {
+ /* copy transform locks */
+ channew->protectflag = chanold->protectflag;
+
+ /* copy bone group */
+ channew->agrp_index= chanold->agrp_index;
+
+ /* ik (dof) settings */
+ channew->ikflag = chanold->ikflag;
+ VECCOPY(channew->limitmin, chanold->limitmin);
+ VECCOPY(channew->limitmax, chanold->limitmax);
+ VECCOPY(channew->stiffness, chanold->stiffness);
+ channew->ikstretch= chanold->ikstretch;
+
+ /* constraints */
+ listnew = &channew->constraints;
+ copy_constraints(listnew, listold);
+
+ /* custom shape */
+ channew->custom= chanold->custom;
+ }
+ }
+ }
+ }
+
+ return eBone;
+}
+
+EditBone *duplicateEditBone(EditBone *curBone, char *name, ListBase *editbones, Object *ob)
+{
+ return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+}
void adduplicate_armature(void)
{
@@ -2264,6 +2366,8 @@ void adduplicate_armature(void)
EditBone *firstDup=NULL; /* The beginning of the duplicated bones in the edbo list */
countall(); // flushes selection!
+
+ preEditBoneDuplicate(&G.edbo);
/* Select mirrored bones */
if (arm->flag & ARM_MIRROR_EDIT) {
@@ -2277,6 +2381,7 @@ void adduplicate_armature(void)
}
}
}
+
/* Find the selected bones and duplicate them as needed */
for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) {
@@ -2291,7 +2396,7 @@ void adduplicate_armature(void)
curBone->temp = eBone;
eBone->temp = curBone;
- unique_editbone_name(&G.edbo, eBone->name);
+ unique_editbone_name(&G.edbo, eBone->name, NULL);
BLI_addtail(&G.edbo, eBone);
if (!firstDup)
firstDup=eBone;
@@ -2351,12 +2456,12 @@ void adduplicate_armature(void)
*/
if (!curBone->parent)
eBone->parent = NULL;
- /* If this bone has a parent that IS selected,
+ /* If this bone has a parent that was duplicated,
Set the duplicate->parent to the curBone->parent->duplicate
*/
- else if (curBone->parent->flag & BONE_SELECTED)
+ else if (curBone->parent->temp)
eBone->parent= (EditBone *)curBone->parent->temp;
- /* If this bone has a parent that IS not selected,
+ /* If this bone has a parent that was not duplicated,
Set the duplicate->parent to the curBone->parent
*/
else {
@@ -2366,7 +2471,7 @@ void adduplicate_armature(void)
/* Lets try to fix any constraint subtargets that might
have been duplicated */
- update_dup_subtarget(eBone);
+ updateDuplicateSubtarget(eBone, &G.edbo, OBACT);
}
}
}
@@ -3055,13 +3160,16 @@ static EditBone *editbone_name_exists (ListBase *ebones, char *name)
}
/* note: there's a unique_bone_name() too! */
-void unique_editbone_name (ListBase *ebones, char *name)
+void unique_editbone_name (ListBase *ebones, char *name, EditBone *bone)
{
+ EditBone *dupli;
char tempname[64];
int number;
char *dot;
- if (editbone_name_exists(ebones, name)) {
+ dupli = editbone_name_exists(ebones, name);
+
+ if (dupli && bone != dupli) {
/* Strip off the suffix, if it's a number */
number= strlen(name);
if (number && isdigit(name[number-1])) {
@@ -3182,7 +3290,7 @@ void extrude_armature(int forked)
else strcat(newbone->name, "_R");
}
}
- unique_editbone_name(&G.edbo, newbone->name);
+ unique_editbone_name(&G.edbo, newbone->name, NULL);
/* Add the new bone to the list */
BLI_addtail(&G.edbo, newbone);
@@ -3269,7 +3377,7 @@ void subdivide_armature(int numcuts)
newbone->flag |= BONE_CONNECTED;
- unique_editbone_name (&G.edbo, newbone->name);
+ unique_editbone_name (&G.edbo, newbone->name, NULL);
/* correct parent bones */
for (tbone = G.edbo.first; tbone; tbone=tbone->next) {
@@ -4303,7 +4411,7 @@ void armature_bone_rename(bArmature *arm, char *oldnamep, char *newnamep)
eBone= editbone_name_exists(&G.edbo, oldname);
if (eBone) {
- unique_editbone_name(&G.edbo, newname);
+ unique_editbone_name(&G.edbo, newname, NULL);
BLI_strncpy(eBone->name, newname, MAXBONENAME);
}
else return;
@@ -4548,9 +4656,9 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
EditBone *lastBone = NULL;
if (G.scene->toolsettings->skgen_options & SKGEN_CUT_ANGLE)
{
- ReebArcIterator iter;
- EmbedBucket *current = NULL;
- EmbedBucket *previous = NULL;
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
+ float *previous = NULL, *current = NULL;
EditBone *child = NULL;
EditBone *parent = NULL;
EditBone *root = NULL;
@@ -4562,22 +4670,28 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
root = parent;
- for (initArcIterator(&iter, arc, head), previous = nextBucket(&iter), current = nextBucket(&iter);
- current;
- previous = current, current = nextBucket(&iter))
+ initArcIterator(iter, arc, head);
+ IT_next(iter);
+ previous = iter->p;
+
+ for (IT_next(iter);
+ IT_stopped(iter) == 0;
+ previous = iter->p, IT_next(iter))
{
float vec1[3], vec2[3];
float len1, len2;
+
+ current = iter->p;
- VecSubf(vec1, previous->p, parent->head);
- VecSubf(vec2, current->p, previous->p);
+ VecSubf(vec1, previous, parent->head);
+ VecSubf(vec2, current, previous);
len1 = Normalize(vec1);
len2 = Normalize(vec2);
if (len1 > 0.0f && len2 > 0.0f && Inpf(vec1, vec2) < angleLimit)
{
- VECCOPY(parent->tail, previous->p);
+ VECCOPY(parent->tail, previous);
child = add_editbone("Bone");
VECCOPY(child->head, parent->tail);
@@ -4604,179 +4718,26 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail)
return lastBone;
}
-float calcVariance(ReebArc *arc, int start, int end, float v0[3], float n[3])
-{
- int len = 2 + abs(end - start);
-
- if (len > 2)
- {
- ReebArcIterator iter;
- EmbedBucket *bucket = NULL;
- float avg_t = 0.0f;
- float s_t = 0.0f;
- float s_xyz = 0.0f;
-
- /* First pass, calculate average */
- for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
- bucket;
- bucket = nextBucket(&iter))
- {
- float v[3];
-
- VecSubf(v, bucket->p, v0);
- avg_t += Inpf(v, n);
- }
-
- avg_t /= Inpf(n, n);
- avg_t += 1.0f; /* adding start (0) and end (1) values */
- avg_t /= len;
-
- /* Second pass, calculate s_xyz and s_t */
- for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
- bucket;
- bucket = nextBucket(&iter))
- {
- float v[3], d[3];
- float dt;
-
- VecSubf(v, bucket->p, v0);
- Projf(d, v, n);
- VecSubf(v, v, d);
-
- dt = VecLength(d) - avg_t;
-
- s_t += dt * dt;
- s_xyz += Inpf(v, v);
- }
-
- /* adding start(0) and end(1) values to s_t */
- s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t);
-
- return s_xyz / s_t;
- }
- else
- {
- return 0;
- }
-}
-
-float calcDistance(ReebArc *arc, int start, int end, float head[3], float tail[3])
-{
- ReebArcIterator iter;
- EmbedBucket *bucket = NULL;
- float max_dist = 0;
-
- /* calculate maximum distance */
- for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
- bucket;
- bucket = nextBucket(&iter))
- {
- float v1[3], v2[3], c[3];
- float dist;
-
- VecSubf(v1, head, tail);
- VecSubf(v2, bucket->p, tail);
-
- Crossf(c, v1, v2);
-
- dist = Inpf(c, c) / Inpf(v1, v1);
-
- max_dist = dist > max_dist ? dist : max_dist;
- }
-
-
- return max_dist;
-}
-
-EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail)
+EditBone * test_subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail)
{
- ReebArcIterator iter;
- float n[3];
- float ADAPTIVE_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit;
EditBone *lastBone = NULL;
-
- /* init iterator to get start and end from head */
- initArcIterator(&iter, arc, head);
-
- /* Calculate overall */
- VecSubf(n, arc->buckets[iter.end].p, head->p);
-
+
if (G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION)
{
- EmbedBucket *bucket = NULL;
- EmbedBucket *previous = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- float normal[3] = {0, 0, 0};
- float avg_normal[3];
- int total = 0;
- int boneStart = iter.start;
+ float invmat[4][4] = { {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}};
+ float tmat[3][3] = { {1, 0, 0},
+ {0, 1, 0},
+ {0, 0, 1}};
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
+ bArmature *arm= G.obedit->data;
- parent = add_editbone("Bone");
- parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
- VECCOPY(parent->head, head->p);
+ initArcIterator(iter, arc, head);
- for (previous = nextBucket(&iter), bucket = nextBucket(&iter);
- bucket;
- previous = bucket, bucket = nextBucket(&iter))
- {
- float btail[3];
- float value = 0;
-
- if (G.scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING)
- {
- VECCOPY(btail, bucket->p);
- }
- else
- {
- float length;
-
- /* Calculate normal */
- VecSubf(n, bucket->p, parent->head);
- length = Normalize(n);
-
- total += 1;
- VecAddf(normal, normal, n);
- VECCOPY(avg_normal, normal);
- VecMulf(avg_normal, 1.0f / total);
-
- VECCOPY(btail, avg_normal);
- VecMulf(btail, length);
- VecAddf(btail, btail, parent->head);
- }
-
- if (G.scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE)
- {
- value = calcDistance(arc, boneStart, iter.index, parent->head, btail);
- }
- else
- {
- float n[3];
-
- VecSubf(n, btail, parent->head);
- value = calcVariance(arc, boneStart, iter.index, parent->head, n);
- }
-
- if (value > ADAPTIVE_THRESHOLD)
- {
- VECCOPY(parent->tail, btail);
-
- child = add_editbone("Bone");
- VECCOPY(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-
- parent = child; // new child is next parent
- boneStart = iter.index; // start from end
-
- normal[0] = normal[1] = normal[2] = 0;
- total = 0;
- }
- }
-
- VECCOPY(parent->tail, tail->p);
-
- lastBone = parent; /* set last bone in the chain */
+ lastBone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
}
return lastBone;
@@ -4809,107 +4770,26 @@ float arcLengthRatio(ReebArc *arc)
return embedLength / arcLength;
}
-EditBone * subdivideByLength(ReebArc *arc, ReebNode *head, ReebNode *tail)
+EditBone * test_subdivideByLength(ReebArc *arc, ReebNode *head, ReebNode *tail)
{
EditBone *lastBone = NULL;
if ((G.scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH) &&
arcLengthRatio(arc) >= G.scene->toolsettings->skgen_length_ratio)
{
- ReebArcIterator iter;
- EmbedBucket *bucket = NULL;
- EmbedBucket *previous = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- float lengthLimit = G.scene->toolsettings->skgen_length_limit;
- int same = 0;
-
- parent = add_editbone("Bone");
- parent->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
- VECCOPY(parent->head, head->p);
-
- initArcIterator(&iter, arc, head);
-
- bucket = nextBucket(&iter);
+ float invmat[4][4] = { {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}};
+ float tmat[3][3] = { {1, 0, 0},
+ {0, 1, 0},
+ {0, 0, 1}};
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
+ bArmature *arm= G.obedit->data;
- while (bucket != NULL)
- {
- float *vec0 = NULL;
- float *vec1 = bucket->p;
-
- /* first bucket. Previous is head */
- if (previous == NULL)
- {
- vec0 = head->p;
- }
- /* Previous is a valid bucket */
- else
- {
- vec0 = previous->p;
- }
-
- /* If lengthLimit hits the current segment */
- if (VecLenf(vec1, parent->head) > lengthLimit)
- {
- if (same == 0)
- {
- float dv[3], off[3];
- float a, b, c, f;
-
- /* Solve quadratic distance equation */
- VecSubf(dv, vec1, vec0);
- a = Inpf(dv, dv);
-
- VecSubf(off, vec0, parent->head);
- b = 2 * Inpf(dv, off);
-
- c = Inpf(off, off) - (lengthLimit * lengthLimit);
-
- f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a);
-
- //printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
-
- if (isnan(f) == 0 && f < 1.0f)
- {
- VECCOPY(parent->tail, dv);
- VecMulf(parent->tail, f);
- VecAddf(parent->tail, parent->tail, vec0);
- }
- else
- {
- VECCOPY(parent->tail, vec1);
- }
- }
- else
- {
- float dv[3];
-
- VecSubf(dv, vec1, vec0);
- Normalize(dv);
-
- VECCOPY(parent->tail, dv);
- VecMulf(parent->tail, lengthLimit);
- VecAddf(parent->tail, parent->tail, parent->head);
- }
-
- child = add_editbone("Bone");
- VECCOPY(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-
- parent = child; // new child is next parent
-
- same = 1; // mark as same
- }
- else
- {
- previous = bucket;
- bucket = nextBucket(&iter);
- same = 0; // Reset same
- }
- }
- VECCOPY(parent->tail, tail->p);
+ initArcIterator(iter, arc, head);
- lastBone = parent; /* set last bone in the chain */
+ lastBone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextLengthSubdivision);
}
return lastBone;
@@ -5002,13 +4882,13 @@ void generateSkeletonFromReebGraph(ReebGraph *rg)
switch(G.scene->toolsettings->skgen_subdivisions[i])
{
case SKGEN_SUB_LENGTH:
- lastBone = subdivideByLength(arc, head, tail);
+ lastBone = test_subdivideByLength(arc, head, tail);
break;
case SKGEN_SUB_ANGLE:
lastBone = subdivideByAngle(arc, head, tail);
break;
case SKGEN_SUB_CORRELATION:
- lastBone = subdivideByCorrelation(arc, head, tail);
+ lastBone = test_subdivideByCorrelation(arc, head, tail);
break;
}
}
diff --git a/source/blender/src/editarmature_generate.c b/source/blender/src/editarmature_generate.c
new file mode 100644
index 00000000000..189a823ab98
--- /dev/null
+++ b/source/blender/src/editarmature_generate.c
@@ -0,0 +1,327 @@
+/**
+ * $Id: editarmature_generate.c $
+ *
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * editarmature.c: Interface for creating and posing armature objects
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+#include "DNA_armature_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_graph.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_editarmature.h"
+#include "BIF_generate.h"
+
+void setBoneRollFromNormal(EditBone *bone, float *no, float invmat[][4], float tmat[][3])
+{
+ if (no != NULL && !VecIsNull(no))
+ {
+ float tangent[3], cotangent[3], normal[3];
+
+ VECCOPY(normal, no);
+ Mat3MulVecfl(tmat, normal);
+
+ VecSubf(tangent, bone->tail, bone->head);
+ Crossf(cotangent, tangent, normal);
+ Crossf(normal, cotangent, tangent);
+
+ Normalize(normal);
+
+ bone->roll = rollBoneToVector(bone, normal);
+ }
+}
+
+float calcArcCorrelation(BArcIterator *iter, int start, int end, float v0[3], float n[3])
+{
+ int len = 2 + abs(end - start);
+
+ if (len > 2)
+ {
+ float avg_t = 0.0f;
+ float s_t = 0.0f;
+ float s_xyz = 0.0f;
+ int i;
+
+ /* First pass, calculate average */
+ for (i = start; i <= end; i++)
+ {
+ float v[3];
+
+ IT_peek(iter, i);
+ VecSubf(v, iter->p, v0);
+ avg_t += Inpf(v, n);
+ }
+
+ avg_t /= Inpf(n, n);
+ avg_t += 1.0f; /* adding start (0) and end (1) values */
+ avg_t /= len;
+
+ /* Second pass, calculate s_xyz and s_t */
+ for (i = start; i <= end; i++)
+ {
+ float v[3], d[3];
+ float dt;
+
+ IT_peek(iter, i);
+ VecSubf(v, iter->p, v0);
+ Projf(d, v, n);
+ VecSubf(v, v, d);
+
+ dt = VecLength(d) - avg_t;
+
+ s_t += dt * dt;
+ s_xyz += Inpf(v, v);
+ }
+
+ /* adding start(0) and end(1) values to s_t */
+ s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t);
+
+ return 1.0f - s_xyz / s_t;
+ }
+ else
+ {
+ return 1.0f;
+ }
+}
+
+int nextFixedSubdivision(BArcIterator *iter, int start, int end, float head[3], float p[3])
+{
+ static float stroke_length = 0;
+ static float current_length;
+ static char n;
+ float *v1, *v2;
+ float length_threshold;
+ int i;
+
+ if (stroke_length == 0)
+ {
+ current_length = 0;
+
+ IT_peek(iter, start);
+ v1 = iter->p;
+
+ for (i = start + 1; i <= end; i++)
+ {
+ IT_peek(iter, i);
+ v2 = iter->p;
+
+ stroke_length += VecLenf(v1, v2);
+
+ v1 = v2;
+ }
+
+ n = 0;
+ current_length = 0;
+ }
+
+ n++;
+
+ length_threshold = n * stroke_length / G.scene->toolsettings->skgen_subdivision_number;
+
+ IT_peek(iter, start);
+ v1 = iter->p;
+
+ /* < and not <= because we don't care about end, it is P_EXACT anyway */
+ for (i = start + 1; i < end; i++)
+ {
+ IT_peek(iter, i);
+ v2 = iter->p;
+
+ current_length += VecLenf(v1, v2);
+
+ if (current_length >= length_threshold)
+ {
+ VECCOPY(p, v2);
+ return i;
+ }
+
+ v1 = v2;
+ }
+
+ stroke_length = 0;
+
+ return -1;
+}
+int nextAdaptativeSubdivision(BArcIterator *iter, int start, int end, float head[3], float p[3])
+{
+ float correlation_threshold = G.scene->toolsettings->skgen_correlation_limit;
+ float *start_p;
+ float n[3];
+ int i;
+
+ IT_peek(iter, start);
+ start_p = iter->p;
+
+ for (i = start + 2; i <= end; i++)
+ {
+ /* Calculate normal */
+ IT_peek(iter, i);
+ VecSubf(n, iter->p, head);
+
+ if (calcArcCorrelation(iter, start, i, start_p, n) < correlation_threshold)
+ {
+ IT_peek(iter, i - 1);
+ VECCOPY(p, iter->p);
+ return i - 1;
+ }
+ }
+
+ return -1;
+}
+
+int nextLengthSubdivision(BArcIterator *iter, int start, int end, float head[3], float p[3])
+{
+ float lengthLimit = G.scene->toolsettings->skgen_length_limit;
+ int same = 1;
+ int i;
+
+ i = start + 1;
+ while (i <= end)
+ {
+ float *vec0;
+ float *vec1;
+
+ IT_peek(iter, i - 1);
+ vec0 = iter->p;
+
+ IT_peek(iter, i);
+ vec1 = iter->p;
+
+ /* If lengthLimit hits the current segment */
+ if (VecLenf(vec1, head) > lengthLimit)
+ {
+ if (same == 0)
+ {
+ float dv[3], off[3];
+ float a, b, c, f;
+
+ /* Solve quadratic distance equation */
+ VecSubf(dv, vec1, vec0);
+ a = Inpf(dv, dv);
+
+ VecSubf(off, vec0, head);
+ b = 2 * Inpf(dv, off);
+
+ c = Inpf(off, off) - (lengthLimit * lengthLimit);
+
+ f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a);
+
+ //printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
+
+ if (isnan(f) == 0 && f < 1.0f)
+ {
+ VECCOPY(p, dv);
+ VecMulf(p, f);
+ VecAddf(p, p, vec0);
+ }
+ else
+ {
+ VECCOPY(p, vec1);
+ }
+ }
+ else
+ {
+ float dv[3];
+
+ VecSubf(dv, vec1, vec0);
+ Normalize(dv);
+
+ VECCOPY(p, dv);
+ VecMulf(p, lengthLimit);
+ VecAddf(p, p, head);
+ }
+
+ return i - 1; /* restart at lower bound */
+ }
+ else
+ {
+ i++;
+ same = 0; // Reset same
+ }
+ }
+
+ return -1;
+}
+
+EditBone * subdivideArcBy(bArmature *arm, ListBase *editbones, BArcIterator *iter, float invmat[][4], float tmat[][3], NextSubdivisionFunc next_subdividion)
+{
+ EditBone *lastBone = NULL;
+ EditBone *child = NULL;
+ EditBone *parent = NULL;
+ int bone_start = 0;
+ int end = iter->length;
+ int index;
+
+ IT_head(iter);
+
+ parent = addEditBone("Bone", editbones, arm);
+ VECCOPY(parent->head, iter->p);
+
+ index = next_subdividion(iter, bone_start, end, parent->head, parent->tail);
+ while (index != -1)
+ {
+ IT_peek(iter, index);
+
+ child = addEditBone("Bone", editbones, arm);
+ VECCOPY(child->head, parent->tail);
+ child->parent = parent;
+ child->flag |= BONE_CONNECTED;
+
+ /* going to next bone, fix parent */
+ Mat4MulVecfl(invmat, parent->tail);
+ Mat4MulVecfl(invmat, parent->head);
+ setBoneRollFromNormal(parent, iter->no, invmat, tmat);
+
+ parent = child; // new child is next parent
+ bone_start = index; // start next bone from current index
+
+ index = next_subdividion(iter, bone_start, end, parent->head, parent->tail);
+ }
+
+ iter->tail(iter);
+
+ VECCOPY(parent->tail, iter->p);
+
+ /* fix last bone */
+ Mat4MulVecfl(invmat, parent->tail);
+ Mat4MulVecfl(invmat, parent->head);
+ setBoneRollFromNormal(parent, iter->no, invmat, tmat);
+ lastBone = parent;
+
+ return lastBone;
+}
diff --git a/source/blender/src/autoarmature.c b/source/blender/src/editarmature_retarget.c
index b0a7a2ab5cc..ad114868a69 100644
--- a/source/blender/src/autoarmature.c
+++ b/source/blender/src/editarmature_retarget.c
@@ -62,7 +62,9 @@
#include "BKE_armature.h"
#include "BIF_editarmature.h"
+#include "BIF_retarget.h"
#include "BIF_space.h"
+#include "BIF_toolbox.h"
#include "PIL_time.h"
@@ -72,100 +74,6 @@
/************ RIG RETARGET DATA STRUCTURES ***************/
-struct RigJoint;
-struct RigGraph;
-struct RigNode;
-struct RigArc;
-struct RigEdge;
-
-//#define USE_THREADS
-
-typedef struct RigGraph {
- ListBase arcs;
- ListBase nodes;
-
- float length;
-
- FreeArc free_arc;
- FreeNode free_node;
- RadialSymmetry radial_symmetry;
- AxialSymmetry axial_symmetry;
- /*********************************/
-
- struct RigNode *head;
- ReebGraph *link_mesh;
-
- ListBase editbones;
-
- ListBase controls;
- struct ThreadedWorker *worker;
-
- GHash *bones_map; /* map of editbones by name */
- GHash *controls_map; /* map of rigcontrols by bone pointer */
-
- Object *ob;
-} RigGraph;
-
-typedef struct RigNode {
- void *next, *prev;
- float p[3];
- int flag;
-
- int degree;
- struct BArc **arcs;
-
- int subgraph_index;
-
- int symmetry_level;
- int symmetry_flag;
- float symmetry_axis[3];
- /*********************************/
-
- ReebNode *link_mesh;
-} RigNode;
-
-typedef struct RigArc {
- void *next, *prev;
- RigNode *head, *tail;
- int flag;
-
- float length;
-
- int symmetry_level;
- int symmetry_group;
- int symmetry_flag;
- /*********************************/
-
- ListBase edges;
- int count;
- ReebArc *link_mesh;
-} RigArc;
-
-typedef struct RigEdge {
- struct RigEdge *next, *prev;
- float head[3], tail[3];
- float length;
- float angle;
- EditBone *bone;
- float up_axis[3];
-} RigEdge;
-
-/* Control flags */
-#define RIG_CTRL_DONE 1
-#define RIG_CTRL_PARENT_DEFORM 2
-#define RIG_CTRL_FIT_ROOT 4
-#define RIG_CTRL_FIT_BONE 8
-
-typedef struct RigControl {
- struct RigControl *next, *prev;
- float head[3], tail[3];
- EditBone *bone;
- EditBone *link;
- float up_axis[3];
- float offset[3];
- int flag;
-} RigControl;
-
typedef struct MemoNode {
float weight;
int next;
@@ -186,8 +94,7 @@ typedef enum
typedef enum
{
METHOD_BRUTE_FORCE = 0,
- METHOD_MEMOIZE = 1,
- METHOD_ANNEALING = 2
+ METHOD_MEMOIZE = 1
} RetargetMethod;
typedef enum
@@ -197,14 +104,14 @@ typedef enum
ARC_USED = 2
} ArcUsageFlags;
-
RigGraph *GLOBAL_RIGG = NULL;
/*******************************************************************************************************/
void *exec_retargetArctoArc(void *param);
-static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second);
+static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second);
+float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]);
/* two levels */
#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX)
@@ -256,30 +163,105 @@ void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3])
VECCOPY(up_axis, mat[2]);
}
-float getNewBoneRoll(EditBone *bone, float old_up_axis[3], float quat[4])
+float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3])
{
- float mat[3][3];
- float nor[3], up_axis[3], new_up_axis[3], vec[3];
- float roll;
+ float nor[3], new_up_axis[3], x_axis[3], z_axis[3];
VECCOPY(new_up_axis, old_up_axis);
- QuatMulVecf(quat, new_up_axis);
-
+ QuatMulVecf(qrot, new_up_axis);
+
VecSubf(nor, bone->tail, bone->head);
- vec_roll_to_mat3(nor, 0, mat);
- VECCOPY(up_axis, mat[2]);
+ Crossf(x_axis, nor, aligned_axis);
+ Crossf(z_axis, x_axis, nor);
- roll = NormalizedVecAngle2(new_up_axis, up_axis);
+ Normalize(new_up_axis);
+ Normalize(x_axis);
+ Normalize(z_axis);
- Crossf(vec, up_axis, new_up_axis);
+ if (Inpf(new_up_axis, x_axis) < 0)
+ {
+ VecMulf(x_axis, -1);
+ }
- if (Inpf(vec, nor) < 0)
+ if (Inpf(new_up_axis, z_axis) < 0)
+ {
+ VecMulf(z_axis, -1);
+ }
+
+ if (NormalizedVecAngle2(x_axis, new_up_axis) < NormalizedVecAngle2(z_axis, new_up_axis))
+ {
+ RotationBetweenVectorsToQuat(qroll, new_up_axis, x_axis); /* set roll rotation quat */
+ return rollBoneToVector(bone, x_axis);
+ }
+ else
+ {
+ RotationBetweenVectorsToQuat(qroll, new_up_axis, z_axis); /* set roll rotation quat */
+ return rollBoneToVector(bone, z_axis);
+ }
+}
+
+float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4])
+{
+ if (previous == NULL)
+ {
+ QuatOne(qroll);
+ return rollBoneByQuat(edge->bone, edge->up_axis, qrot);
+ }
+ else
{
- roll = -roll;
+ float new_up_axis[3];
+ float vec_first[3], vec_second[3], normal[3];
+
+ if (previous->bone)
+ {
+ VecSubf(vec_first, previous->bone->tail, previous->bone->head);
+ }
+ else if (previous->prev->bone)
+ {
+ VecSubf(vec_first, edge->bone->head, previous->prev->bone->tail);
+ }
+ else
+ {
+ /* SHOULDN'T BE HERE */
+ QuatOne(qroll);
+ return rollBoneByQuat(edge->bone, edge->up_axis, qrot);
+ }
+
+ VecSubf(vec_second, edge->bone->tail, edge->bone->head);
+
+ Normalize(vec_first);
+ Normalize(vec_second);
+
+ Crossf(normal, vec_first, vec_second);
+ Normalize(normal);
+
+ AxisAngleToQuat(qroll, vec_second, edge->up_angle);
+
+ QuatMulVecf(qroll, normal);
+
+ VECCOPY(new_up_axis, edge->up_axis);
+ QuatMulVecf(qrot, new_up_axis);
+
+ Normalize(new_up_axis);
+
+ /* real qroll between normal and up_axis */
+ RotationBetweenVectorsToQuat(qroll, new_up_axis, normal);
+
+ return rollBoneToVector(edge->bone, normal);
}
+}
+
+float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4])
+{
+ float new_up_axis[3];
+
+ VECCOPY(new_up_axis, old_up_axis);
+ QuatMulVecf(qrot, new_up_axis);
+
+ Normalize(new_up_axis);
- return roll;
+ return rollBoneToVector(bone, new_up_axis);
}
/************************************ DESTRUCTORS ******************************************************/
@@ -291,14 +273,18 @@ void RIG_freeRigArc(BArc *arc)
void RIG_freeRigGraph(BGraph *rg)
{
+ RigGraph *rigg = (RigGraph*)rg;
BNode *node;
BArc *arc;
#ifdef USE_THREADS
- BLI_destroy_worker(((RigGraph*)rg)->worker);
+ BLI_destroy_worker(rigg->worker);
#endif
- REEB_freeGraph(((RigGraph*)rg)->link_mesh);
+ if (rigg->link_mesh)
+ {
+ REEB_freeGraph(rigg->link_mesh);
+ }
for (arc = rg->arcs.first; arc; arc = arc->next)
{
@@ -312,12 +298,16 @@ void RIG_freeRigGraph(BGraph *rg)
}
BLI_freelistN(&rg->nodes);
- BLI_freelistN(&((RigGraph*)rg)->controls);
+ BLI_freelistN(&rigg->controls);
- BLI_ghash_free(((RigGraph*)rg)->bones_map, NULL, NULL);
- BLI_ghash_free(((RigGraph*)rg)->controls_map, NULL, NULL);
+ BLI_ghash_free(rigg->bones_map, NULL, NULL);
+ BLI_ghash_free(rigg->controls_map, NULL, NULL);
- BLI_freelistN(&((RigGraph*)rg)->editbones);
+ if (rigg->editbones != &G.edbo)
+ {
+ BLI_freelistN(rigg->editbones);
+ MEM_freeN(rigg->editbones);
+ }
MEM_freeN(rg);
}
@@ -434,7 +424,7 @@ static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge)
{
RigEdge *last_edge = edge->prev;
VECCOPY(edge->head, last_edge->tail);
- RIG_calculateEdgeAngle(last_edge, edge);
+ RIG_calculateEdgeAngles(last_edge, edge);
}
edge->length = VecLenf(edge->head, edge->tail);
@@ -460,10 +450,226 @@ static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone)
RIG_appendEdgeToArc(arc, edge);
}
+/************************************** CLONING TEMPLATES **********************************************/
+
+static void renameTemplateBone(char *name, char *template_name, ListBase *editbones)
+{
+ char *side_string = G.scene->toolsettings->skgen_side_string;
+ char *num_string = G.scene->toolsettings->skgen_num_string;
+ int i, j;
+
+ for (i = 0, j = 0; template_name[i] != '\0' && i < 31 && j < 31; i++)
+ {
+ if (template_name[i] == '&')
+ {
+ if (template_name[i+1] == 'S' || template_name[i+1] == 's')
+ {
+ j += sprintf(name + j, side_string);
+ i++;
+ }
+ else if (template_name[i+1] == 'N' || template_name[i+1] == 'n')
+ {
+ j += sprintf(name + j, num_string);
+ i++;
+ }
+ else
+ {
+ name[j] = template_name[i];
+ j++;
+ }
+ }
+ else
+ {
+ name[j] = template_name[i];
+ j++;
+ }
+ }
+
+ name[j] = '\0';
+
+ unique_editbone_name(editbones, name, NULL);
+}
+
+static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash)
+{
+ RigControl *ctrl;
+ char name[32];
+
+ ctrl = newRigControl(rg);
+
+ VECCOPY(ctrl->head, src_ctrl->head);
+ VECCOPY(ctrl->tail, src_ctrl->tail);
+ VECCOPY(ctrl->up_axis, src_ctrl->up_axis);
+ VECCOPY(ctrl->offset, src_ctrl->offset);
+
+ ctrl->tail_mode = src_ctrl->tail_mode;
+ ctrl->flag = src_ctrl->flag;
+
+ renameTemplateBone(name, src_ctrl->bone->name, rg->editbones);
+ ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob);
+ ctrl->bone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
+ BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone);
+
+ ctrl->link = src_ctrl->link;
+ ctrl->link_tail = src_ctrl->link_tail;
+
+ return ctrl;
+}
+
+static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash)
+{
+ RigEdge *src_edge;
+ RigArc *arc;
+
+ arc = newRigArc(rg);
+
+ arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head);
+ arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail);
+
+ arc->head->degree++;
+ arc->tail->degree++;
+
+ arc->length = src_arc->length;
+
+ arc->count = src_arc->count;
+
+ for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next)
+ {
+ RigEdge *edge;
+
+ edge = MEM_callocN(sizeof(RigEdge), "rig edge");
+
+ VECCOPY(edge->head, src_edge->head);
+ VECCOPY(edge->tail, src_edge->tail);
+ VECCOPY(edge->up_axis, src_edge->up_axis);
+
+ edge->length = src_edge->length;
+ edge->angle = src_edge->angle;
+ edge->up_angle = src_edge->up_angle;
+
+ if (src_edge->bone != NULL)
+ {
+ char name[32];
+ renameTemplateBone(name, src_edge->bone->name, rg->editbones);
+ edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob);
+ edge->bone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
+ BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone);
+ }
+
+ BLI_addtail(&arc->edges, edge);
+ }
+
+ return arc;
+}
+
+static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob)
+{
+ GHash *ptr_hash;
+ RigNode *node;
+ RigArc *arc;
+ RigControl *ctrl;
+ RigGraph *rg;
+
+ ptr_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ rg = newRigGraph();
+
+ rg->ob = ob;
+ rg->editbones = editbones;
+
+ preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */
+ preEditBoneDuplicate(src->editbones); /* prime bones for duplication */
+
+ /* Clone nodes */
+ for (node = src->nodes.first; node; node = node->next)
+ {
+ RigNode *cloned_node = newRigNode(rg, node->p);
+ BLI_ghash_insert(ptr_hash, node, cloned_node);
+ }
+
+ rg->head = BLI_ghash_lookup(ptr_hash, src->head);
+
+ /* Clone arcs */
+ for (arc = src->arcs.first; arc; arc = arc->next)
+ {
+ cloneArc(rg, src, arc, ptr_hash);
+ }
+
+ /* Clone controls */
+ for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next)
+ {
+ cloneControl(rg, src, ctrl, ptr_hash);
+ }
+
+ /* Relink bones properly */
+ for (arc = rg->arcs.first; arc; arc = arc->next)
+ {
+ RigEdge *edge;
+
+ for (edge = arc->edges.first; edge; edge = edge->next)
+ {
+ if (edge->bone != NULL)
+ {
+ EditBone *bone;
+
+ updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob);
+
+ if (edge->bone->parent)
+ {
+ bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent);
+
+ if (bone != NULL)
+ {
+ edge->bone->parent = bone;
+ }
+ else
+ {
+ /* disconnect since parent isn't cloned
+ * this will only happen when cloning from selected bones
+ * */
+ edge->bone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ }
+ }
+ }
+
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
+ {
+ EditBone *bone;
+
+ updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob);
+
+ if (ctrl->bone->parent)
+ {
+ bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent);
+
+ if (bone != NULL)
+ {
+ ctrl->bone->parent = bone;
+ }
+ else
+ {
+ /* disconnect since parent isn't cloned
+ * this will only happen when cloning from selected bones
+ * */
+ ctrl->bone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link);
+ ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail);
+ }
+
+ BLI_ghash_free(ptr_hash, NULL, NULL);
+
+ return rg;
+}
+
/*******************************************************************************************************/
-static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second)
+static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second)
{
float vec_first[3], vec_second[3];
@@ -473,7 +679,17 @@ static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second)
Normalize(vec_first);
Normalize(vec_second);
- edge_first->angle = saacos(Inpf(vec_first, vec_second));
+ edge_first->angle = NormalizedVecAngle2(vec_first, vec_second);
+
+ if (edge_second->bone != NULL)
+ {
+ float normal[3];
+
+ Crossf(normal, vec_first, vec_second);
+ Normalize(normal);
+
+ edge_second->up_angle = NormalizedVecAngle2(normal, edge_second->up_axis);
+ }
}
/************************************ CONTROL BONES ****************************************************/
@@ -485,6 +701,7 @@ static void RIG_addControlBone(RigGraph *rg, EditBone *bone)
VECCOPY(ctrl->head, bone->head);
VECCOPY(ctrl->tail, bone->tail);
getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis);
+ ctrl->tail_mode = TL_NONE;
BLI_ghash_insert(rg->controls_map, bone->name, ctrl);
}
@@ -588,16 +805,31 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* constraint targets */
if (cti && cti->get_constraint_targets)
{
+ int target_index;
+
cti->get_constraint_targets(con, &targets);
- for (ct= targets.first; ct; ct= ct->next)
+ for (target_index = 0, ct= targets.first; ct; target_index++, ct= ct->next)
{
if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0)
{
/* SET bone link to bone corresponding to pchan */
EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name);
- found = RIG_parentControl(ctrl, link);
+ /* Making sure bone is in this armature */
+ if (link != NULL)
+ {
+ /* for pole targets, link to parent bone instead, if possible */
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1)
+ {
+ if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name))
+ {
+ link = link->parent;
+ }
+ }
+
+ found = RIG_parentControl(ctrl, link);
+ }
}
}
@@ -692,8 +924,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
{
change = 0;
- printf("-------------------------\n");
-
for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
{
/* if control is not linked yet */
@@ -736,7 +966,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* if owner is a control bone, link with it */
if (link && link->link)
{
- printf("%s -constraint- %s\n", ctrl->bone->name, link->bone->name);
RIG_parentControl(ctrl, link->bone);
found = 1;
break;
@@ -755,7 +984,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* check if parent is already linked */
if (ctrl_parent && ctrl_parent->link)
{
- printf("%s -parent- %s\n", ctrl->bone->name, ctrl_parent->bone->name);
RIG_parentControl(ctrl, ctrl_parent->bone);
change = 1;
}
@@ -767,7 +995,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
/* if a child is linked, link to that one */
if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone)
{
- printf("%s -child- %s\n", ctrl->bone->name, ctrl_child->bone->name);
RIG_parentControl(ctrl, ctrl_child->bone);
change = 1;
break;
@@ -777,8 +1004,48 @@ static void RIG_reconnectControlBones(RigGraph *rg)
}
}
}
-
}
+
+ /* third pass, link control tails */
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
+ {
+ /* fit bone already means full match, so skip those */
+ if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0)
+ {
+ GHashIterator ghi;
+
+ /* look on deform bones first */
+ BLI_ghashIterator_init(&ghi, rg->bones_map);
+
+ for( ; !BLI_ghashIterator_isDone(&ghi); BLI_ghashIterator_step(&ghi))
+ {
+ EditBone *bone = (EditBone*)BLI_ghashIterator_getValue(&ghi);
+
+ /* don't link with parent */
+ if (bone->parent != ctrl->bone)
+ {
+ if (VecLenf(ctrl->bone->tail, bone->head) < 0.01)
+ {
+ ctrl->tail_mode = TL_HEAD;
+ ctrl->link_tail = bone;
+ break;
+ }
+ else if (VecLenf(ctrl->bone->tail, bone->tail) < 0.01)
+ {
+ ctrl->tail_mode = TL_TAIL;
+ ctrl->link_tail = bone;
+ break;
+ }
+ }
+ }
+
+ /* if we haven't found one yet, look in control bones */
+ if (ctrl->tail_mode == TL_NONE)
+ {
+ }
+ }
+ }
+
}
/*******************************************************************************************************/
@@ -1034,7 +1301,7 @@ static void RIG_removeUneededOffsets(RigGraph *rg)
}
}
-static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node)
+static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, int selected)
{
EditBone *bone, *last_bone = root_bone;
RigArc *arc = NULL;
@@ -1044,42 +1311,45 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo
{
int nb_children;
- if ((bone->flag & BONE_NO_DEFORM) == 0)
- {
- BLI_ghash_insert(rg->bones_map, bone->name, bone);
-
- if (arc == NULL)
+ if (selected == 0 || (bone->flag & BONE_SELECTED))
+ {
+ if ((bone->flag & BONE_NO_DEFORM) == 0)
{
- arc = newRigArc(rg);
+ BLI_ghash_insert(rg->bones_map, bone->name, bone);
+
+ if (arc == NULL)
+ {
+ arc = newRigArc(rg);
+
+ if (starting_node == NULL)
+ {
+ starting_node = newRigNodeHead(rg, arc, root_bone->head);
+ }
+ else
+ {
+ addRigNodeHead(rg, arc, starting_node);
+ }
+ }
- if (starting_node == NULL)
+ if (bone->parent && (bone->flag & BONE_CONNECTED) == 0)
{
- starting_node = newRigNodeHead(rg, arc, root_bone->head);
+ RIG_addEdgeToArc(arc, bone->head, NULL);
}
- else
+
+ RIG_addEdgeToArc(arc, bone->tail, bone);
+
+ last_bone = bone;
+
+ if (strcmp(bone->name, "head") == 0)
{
- addRigNodeHead(rg, arc, starting_node);
+ contain_head = 1;
}
}
-
- if (bone->parent && (bone->flag & BONE_CONNECTED) == 0)
- {
- RIG_addEdgeToArc(arc, bone->head, NULL);
- }
-
- RIG_addEdgeToArc(arc, bone->tail, bone);
-
- last_bone = bone;
-
- if (strcmp(bone->name, "head") == 0)
+ else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) /* ignore locked bones */
{
- contain_head = 1;
+ RIG_addControlBone(rg, bone);
}
}
- else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) /* ignore locked bones */
- {
- RIG_addControlBone(rg, bone);
- }
nb_children = countEditBoneChildren(list, bone);
if (nb_children > 1)
@@ -1099,7 +1369,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo
for (i = 0; i < nb_children; i++)
{
root_bone = nextEditBoneChild(list, bone, i);
- RIG_arcFromBoneChain(rg, list, root_bone, end_node);
+ RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected);
}
/* arc ends here, break */
@@ -1266,21 +1536,30 @@ void RIG_printGraph(RigGraph *rg)
/*******************************************************************************************************/
-static RigGraph *armatureToGraph(Object *ob, bArmature *arm)
+RigGraph *RIG_graphFromArmature(Object *ob, bArmature *arm)
{
EditBone *ebone;
RigGraph *rg;
rg = newRigGraph();
- make_boneList(&rg->editbones, &arm->bonebase, NULL);
+ if (G.obedit == ob)
+ {
+ rg->editbones = &G.edbo;
+ }
+ else
+ {
+ rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
+ make_boneList(rg->editbones, &arm->bonebase, NULL);
+ }
+
rg->ob = ob;
/* Do the rotations */
- for (ebone = rg->editbones.first; ebone; ebone=ebone->next){
+ for (ebone = rg->editbones->first; ebone; ebone=ebone->next){
if (ebone->parent == NULL)
{
- RIG_arcFromBoneChain(rg, &rg->editbones, ebone, NULL);
+ RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0);
}
}
@@ -1306,6 +1585,54 @@ static RigGraph *armatureToGraph(Object *ob, bArmature *arm)
return rg;
}
+RigGraph *armatureSelectedToGraph(Object *ob, bArmature *arm)
+{
+ EditBone *ebone;
+ RigGraph *rg;
+
+ rg = newRigGraph();
+
+ if (G.obedit == ob)
+ {
+ rg->editbones = &G.edbo;
+ }
+ else
+ {
+ rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
+ make_boneList(rg->editbones, &arm->bonebase, NULL);
+ }
+
+ rg->ob = ob;
+
+ /* Do the rotations */
+ for (ebone = rg->editbones->first; ebone; ebone=ebone->next){
+ if (ebone->parent == NULL)
+ {
+ RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1);
+ }
+ }
+
+ BLI_removeDoubleNodes((BGraph*)rg, 0.001);
+
+ RIG_removeNormalNodes(rg);
+
+ RIG_removeUneededOffsets(rg);
+
+ BLI_buildAdjacencyList((BGraph*)rg);
+
+ RIG_findHead(rg);
+
+ BLI_markdownSymmetry((BGraph*)rg, (BNode*)rg->head, G.scene->toolsettings->skgen_symmetry_limit);
+
+ RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
+
+ if (BLI_isGraphCyclic((BGraph*)rg))
+ {
+ printf("armature cyclic\n");
+ }
+
+ return rg;
+}
/************************************ GENERATING *****************************************************/
static EditBone *add_editbonetolist(char *name, ListBase *list)
@@ -1313,7 +1640,7 @@ static EditBone *add_editbonetolist(char *name, ListBase *list)
EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
BLI_strncpy(bone->name, name, 32);
- unique_editbone_name(list, bone->name);
+ unique_editbone_name(list, bone->name, NULL);
BLI_addtail(list, bone);
@@ -1332,100 +1659,6 @@ static EditBone *add_editbonetolist(char *name, ListBase *list)
return bone;
}
-EditBone * generateBonesForArc(RigGraph *rigg, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- ReebArcIterator iter;
- float n[3];
- float ADAPTIVE_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit;
- EditBone *lastBone = NULL;
-
- /* init iterator to get start and end from head */
- initArcIterator(&iter, arc, head);
-
- /* Calculate overall */
- VecSubf(n, arc->buckets[iter.end].p, head->p);
-
- if (1 /* G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION */ )
- {
- EmbedBucket *bucket = NULL;
- EmbedBucket *previous = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- float normal[3] = {0, 0, 0};
- float avg_normal[3];
- int total = 0;
- int boneStart = iter.start;
-
- parent = add_editbonetolist("Bone", &rigg->editbones);
- parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
- VECCOPY(parent->head, head->p);
-
- for (previous = nextBucket(&iter), bucket = nextBucket(&iter);
- bucket;
- previous = bucket, bucket = nextBucket(&iter))
- {
- float btail[3];
- float value = 0;
-
- if (G.scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING)
- {
- VECCOPY(btail, bucket->p);
- }
- else
- {
- float length;
-
- /* Calculate normal */
- VecSubf(n, bucket->p, parent->head);
- length = Normalize(n);
-
- total += 1;
- VecAddf(normal, normal, n);
- VECCOPY(avg_normal, normal);
- VecMulf(avg_normal, 1.0f / total);
-
- VECCOPY(btail, avg_normal);
- VecMulf(btail, length);
- VecAddf(btail, btail, parent->head);
- }
-
- if (G.scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE)
- {
- value = calcDistance(arc, boneStart, iter.index, parent->head, btail);
- }
- else
- {
- float n[3];
-
- VecSubf(n, btail, parent->head);
- value = calcVariance(arc, boneStart, iter.index, parent->head, n);
- }
-
- if (value > ADAPTIVE_THRESHOLD)
- {
- VECCOPY(parent->tail, btail);
-
- child = add_editbonetolist("Bone", &rigg->editbones);
- VECCOPY(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-
- parent = child; // new child is next parent
- boneStart = iter.index; // start from end
-
- normal[0] = normal[1] = normal[2] = 0;
- total = 0;
- }
- }
-
- VECCOPY(parent->tail, tail->p);
-
- lastBone = parent; /* set last bone in the chain */
- }
-
- return lastBone;
-}
-
void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit)
{
while (node->multi_level > multi_level_limit && node->link_up)
@@ -1452,7 +1685,7 @@ void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level
earc->flag = ARC_USED;
- generateBonesForArc(rigg, earc, node, other);
+ //generateBonesForArc(rigg, earc, node, other);
generateMissingArcsFromNode(rigg, other, multi_level_limit);
}
}
@@ -1481,38 +1714,106 @@ void generateMissingArcs(RigGraph *rigg)
/************************************ RETARGETTING *****************************************************/
+static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize);
+
+static void repositionTailControl(RigGraph *rigg, RigControl *ctrl);
+
+static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize)
+{
+ if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE)
+ {
+ RigControl *ctrl_child;
+
+#if 0
+ printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name);
+
+ if (ctrl->link_tail)
+ {
+ printf(" TAIL: %s", ctrl->link_tail->name);
+ }
+
+ printf("\n");
+#endif
+
+ /* if there was a tail link: apply link, recalc resize factor and qrot */
+ if (ctrl->tail_mode != TL_NONE)
+ {
+ float *tail_vec = NULL;
+ float v1[3], v2[3], qtail[4];
+
+ if (ctrl->tail_mode == TL_TAIL)
+ {
+ tail_vec = ctrl->link_tail->tail;
+ }
+ else if (ctrl->tail_mode == TL_HEAD)
+ {
+ tail_vec = ctrl->link_tail->head;
+ }
+
+ VecSubf(v1, ctrl->bone->tail, ctrl->bone->head);
+ VecSubf(v2, tail_vec, ctrl->bone->head);
+
+ VECCOPY(ctrl->bone->tail, tail_vec);
+
+ RotationBetweenVectorsToQuat(qtail, v1, v2);
+ QuatMul(ctrl->qrot, qtail, ctrl->qrot);
+
+ resize = VecLength(v2) / VecLenf(ctrl->head, ctrl->tail);
+ }
+
+ ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot);
+
+ /* Cascade to connected control bones */
+ for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next)
+ {
+ if (ctrl_child->link == ctrl->bone)
+ {
+ repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize);
+ }
+ if (ctrl_child->link_tail == ctrl->bone)
+ {
+ repositionTailControl(rigg, ctrl_child);
+ }
+ }
+ }
+}
+
+static void repositionTailControl(RigGraph *rigg, RigControl *ctrl)
+{
+ ctrl->flag |= RIG_CTRL_TAIL_DONE;
+
+ finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */
+}
+
static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize)
{
- RigControl *ctrl_child;
float parent_offset[3], tail_offset[3];
- VecSubf(tail_offset, ctrl->tail, ctrl->head);
- VecMulf(tail_offset, resize);
-
VECCOPY(parent_offset, ctrl->offset);
VecMulf(parent_offset, resize);
-
QuatMulVecf(qrot, parent_offset);
- QuatMulVecf(qrot, tail_offset);
VecAddf(ctrl->bone->head, head, parent_offset);
- VecAddf(ctrl->bone->tail, ctrl->bone->head, tail_offset);
- ctrl->bone->roll = getNewBoneRoll(ctrl->bone, ctrl->up_axis, qrot);
-
- ctrl->flag |= RIG_CTRL_DONE;
- /* Cascade to connected control bones */
- for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next)
+ ctrl->flag |= RIG_CTRL_HEAD_DONE;
+
+ QUATCOPY(ctrl->qrot, qrot);
+
+ if (ctrl->tail_mode == TL_NONE)
{
- if (ctrl_child->link == ctrl->bone)
- {
- repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, qrot, resize);
- }
+ VecSubf(tail_offset, ctrl->tail, ctrl->head);
+ VecMulf(tail_offset, resize);
+ QuatMulVecf(qrot, tail_offset);
+
+ VecAddf(ctrl->bone->tail, ctrl->bone->head, tail_offset);
+
+ ctrl->flag |= RIG_CTRL_TAIL_DONE;
}
+ finalizeControl(rigg, ctrl, resize);
}
-static void repositionBone(RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3])
+static void repositionBone(RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3])
{
EditBone *bone;
RigControl *ctrl;
@@ -1532,17 +1833,44 @@ static void repositionBone(RigGraph *rigg, RigEdge *edge, float vec0[3], float v
RotationBetweenVectorsToQuat(qrot, v1, v2);
+ VECCOPY(bone->head, vec0);
+ VECCOPY(bone->tail, vec1);
+
+ if (!VecIsNull(up_axis))
+ {
+ float qroll[4];
+
+ if (G.scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW)
+ {
+ bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis);
+ }
+ else if (G.scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT)
+ {
+ bone->roll = rollBoneByQuatJoint(edge, edge->next, qrot, qroll);
+ }
+ else
+ {
+ QuatOne(qroll);
+ }
+
+ QuatMul(qrot, qroll, qrot);
+ }
+ else
+ {
+ bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot);
+ }
+
for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next)
{
if (ctrl->link == bone)
{
repositionControl(rigg, ctrl, vec0, vec1, qrot, resize);
}
+ if (ctrl->link_tail == bone)
+ {
+ repositionTailControl(rigg, ctrl);
+ }
}
-
- VECCOPY(bone->head, vec0);
- VECCOPY(bone->tail, vec1);
- bone->roll = getNewBoneRoll(bone, edge->up_axis, qrot);
}
static RetargetMode detectArcRetargetMode(RigArc *arc);
@@ -1603,29 +1931,6 @@ static RetargetMode detectArcRetargetMode(RigArc *iarc)
}
#ifndef USE_THREADS
-static void printCostCube(float *cost_cube, int nb_joints)
-{
- int i;
-
- for (i = 0; i < nb_joints; i++)
- {
- printf("%0.3f ", cost_cube[3 * i]);
- }
- printf("\n");
-
- for (i = 0; i < nb_joints; i++)
- {
- printf("%0.3f ", cost_cube[3 * i + 1]);
- }
- printf("\n");
-
- for (i = 0; i < nb_joints; i++)
- {
- printf("%0.3f ", cost_cube[3 * i + 2]);
- }
- printf("\n");
-}
-
static void printMovesNeeded(int *positions, int nb_positions)
{
int moves = 0;
@@ -1651,9 +1956,9 @@ static void printPositions(int *positions, int nb_positions)
}
#endif
-#define MAX_COST 100 /* FIX ME */
+#define MAX_COST FLT_MAX /* FIX ME */
-static float costDistance(ReebArcIterator *iter, float *vec0, float *vec1, int i0, int i1)
+static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1)
{
EmbedBucket *bucket = NULL;
float max_dist = 0;
@@ -1673,7 +1978,7 @@ static float costDistance(ReebArcIterator *iter, float *vec0, float *vec1, int i
{
float dist;
- bucket = peekBucket(iter, j);
+ bucket = IT_peek(iter, j);
VecSubf(v2, bucket->p, vec1);
@@ -1733,7 +2038,7 @@ static float costLength(float original_length, float current_length)
}
}
-static float calcCostLengthDistance(ReebArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
+static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
{
float vec[3];
float length;
@@ -1744,7 +2049,7 @@ static float calcCostLengthDistance(ReebArcIterator *iter, float **vec_cache, Ri
return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2);
}
-static float calcCostAngleLengthDistance(ReebArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2)
+static float calcCostAngleLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2)
{
float vec_second[3], vec_first[3];
float length2;
@@ -1772,187 +2077,6 @@ static float calcCostAngleLengthDistance(ReebArcIterator *iter, float **vec_cach
return new_cost;
}
-static float calcCost(ReebArcIterator *iter, RigEdge *e1, RigEdge *e2, float *vec0, float *vec1, float *vec2, int i0, int i1, int i2)
-{
- float vec_second[3], vec_first[3];
- float length1, length2;
- float new_cost = 0;
-
- VecSubf(vec_second, vec2, vec1);
- length2 = Normalize(vec_second);
-
- VecSubf(vec_first, vec1, vec0);
- length1 = Normalize(vec_first);
-
- /* Angle cost */
- new_cost += costAngle(e1->angle, vec_first, vec_second);
-
- /* Length cost */
- new_cost += costLength(e1->length, length1);
- new_cost += costLength(e2->length, length2);
-
- /* Distance cost */
- new_cost += costDistance(iter, vec0, vec1, i0, i1);
- new_cost += costDistance(iter, vec1, vec2, i1, i2);
-
- return new_cost;
-}
-
-static void calcGradient(RigEdge *e1, RigEdge *e2, ReebArcIterator *iter, int index, int nb_joints, float *cost_cube, int *positions, float **vec_cache)
-{
- EmbedBucket *bucket = NULL;
- float *vec0, *vec1, *vec2;
- float current_cost;
- int i0, i1, i2;
- int next_position;
-
- vec0 = vec_cache[index];
- vec1 = vec_cache[index + 1];
- vec2 = vec_cache[index + 2];
-
- if (index == 0)
- {
- i0 = 0;
- }
- else
- {
- i0 = positions[index - 1];
- }
-
- i1 = positions[index];
-
- if (index +1 == nb_joints)
- {
- i2 = iter->length;
- }
- else
- {
- i2 = positions[index + 1];
- }
-
-
- current_cost = calcCost(iter, e1, e2, vec0, vec1, vec2, i0, i1, i2);
- cost_cube[index * 3 + 1] = current_cost;
-
- next_position = positions[index] + 1;
-
- if (index + 1 < nb_joints && next_position == positions[index + 1])
- {
- cost_cube[index * 3 + 2] = MAX_COST;
- }
- else if (next_position > iter->length) /* positions are indexed at 1, so length is last */
- {
- cost_cube[index * 3 + 2] = MAX_COST;
- }
- else
- {
- bucket = peekBucket(iter, next_position);
-
- if (bucket == NULL)
- {
- cost_cube[index * 3 + 2] = MAX_COST;
- }
- else
- {
- vec1 = bucket->p;
-
- cost_cube[index * 3 + 2] = calcCost(iter, e1, e2, vec0, vec1, vec2, i0, next_position, i2) - current_cost;
- }
- }
-
- next_position = positions[index] - 1;
-
- if (index - 1 > -1 && next_position == positions[index - 1])
- {
- cost_cube[index * 3] = MAX_COST;
- }
- else if (next_position < 1) /* positions are indexed at 1, so 1 is first */
- {
- cost_cube[index * 3] = MAX_COST;
- }
- else
- {
- bucket = peekBucket(iter, next_position);
-
- if (bucket == NULL)
- {
- cost_cube[index * 3] = MAX_COST;
- }
- else
- {
- vec1 = bucket->p;
-
- cost_cube[index * 3] = calcCost(iter, e1, e2, vec0, vec1, vec2, i0, next_position, i2) - current_cost;
- }
- }
-}
-
-static float probability(float delta_cost, float temperature)
-{
- if (delta_cost < 0)
- {
- return 1;
- }
- else
- {
- return (float)exp(delta_cost / temperature);
- }
-}
-
-static int neighbour(int nb_joints, float *cost_cube, int *moving_joint, int *moving_direction)
-{
- int total = 0;
- int chosen = 0;
- int i;
-
- for (i = 0; i < nb_joints; i++)
- {
- if (cost_cube[i * 3] < MAX_COST)
- {
- total++;
- }
-
- if (cost_cube[i * 3 + 2] < MAX_COST)
- {
- total++;
- }
- }
-
- if (total == 0)
- {
- return 0;
- }
-
- chosen = (int)(BLI_drand() * total);
-
- for (i = 0; i < nb_joints; i++)
- {
- if (cost_cube[i * 3] < MAX_COST)
- {
- if (chosen == 0)
- {
- *moving_joint = i;
- *moving_direction = -1;
- break;
- }
- chosen--;
- }
-
- if (cost_cube[i * 3 + 2] < MAX_COST)
- {
- if (chosen == 0)
- {
- *moving_joint = i;
- *moving_direction = 1;
- break;
- }
- chosen--;
- }
- }
-
- return 1;
-}
-
static int indexMemoNode(int nb_positions, int previous, int current, int joints_left)
{
return joints_left * nb_positions * nb_positions + current * nb_positions + previous;
@@ -1975,7 +2099,7 @@ static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions,
}
}
-static MemoNode * solveJoints(MemoNode *table, ReebArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left)
+static MemoNode * solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left)
{
MemoNode *node;
int index = indexMemoNode(nb_positions, previous, current, joints_left);
@@ -1988,10 +2112,11 @@ static MemoNode * solveJoints(MemoNode *table, ReebArcIterator *iter, float **ve
}
else if (joints_left == 0)
{
+ float *vec0 = vec_cache[previous];
float *vec1 = vec_cache[current];
float *vec2 = vec_cache[nb_positions + 1];
- node->weight = calcCostLengthDistance(iter, vec_cache, edge, vec1, vec2, current, iter->length);
+ node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length);
return node;
}
@@ -2063,20 +2188,18 @@ static int testFlipArc(RigArc *iarc, RigNode *inode_start)
static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
{
- ReebArcIterator iter;
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
RigEdge *edge;
EmbedBucket *bucket = NULL;
ReebNode *node_start, *node_end;
ReebArc *earc = iarc->link_mesh;
float min_cost = FLT_MAX;
float *vec0, *vec1, *vec2;
- float **vec_cache;
- float *cost_cache;
int *best_positions;
- int *positions;
int nb_edges = BLI_countlist(&iarc->edges);
int nb_joints = nb_edges - 1;
- RetargetMethod method = G.scene->toolsettings->skgen_optimisation_method;
+ RetargetMethod method = METHOD_MEMOIZE;
int i;
if (nb_joints > earc->bcount)
@@ -2085,10 +2208,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
return;
}
- positions = MEM_callocN(sizeof(int) * nb_joints, "Aggresive positions");
- best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best Aggresive positions");
- cost_cache = MEM_callocN(sizeof(float) * nb_edges, "Cost cache");
- vec_cache = MEM_callocN(sizeof(float*) * (nb_edges + 1), "Vec cache");
+ best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions");
if (testFlipArc(iarc, inode_start))
{
@@ -2100,23 +2220,18 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
node_start = earc->head;
node_end = earc->tail;
}
-
- /* init with first values */
- for (i = 0; i < nb_joints; i++)
- {
- positions[i] = i + 1;
- //positions[i] = (earc->bcount / nb_edges) * (i + 1);
- }
-
- /* init cost cache */
- for (i = 0; i < nb_edges; i++)
+
+ /* equal number of joints and potential position, just fill them in */
+ if (nb_joints == earc->bcount)
{
- cost_cache[i] = 0;
+ int i;
+
+ /* init with first values */
+ for (i = 0; i < nb_joints; i++)
+ {
+ best_positions[i] = i + 1;
+ }
}
-
- vec_cache[0] = node_start->p;
- vec_cache[nb_edges] = node_end->p;
-
if (method == METHOD_MEMOIZE)
{
int nb_positions = earc->bcount;
@@ -2129,15 +2244,15 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
positions_cache[0] = node_start->p;
positions_cache[nb_positions + 1] = node_end->p;
- initArcIterator(&iter, earc, node_start);
+ initArcIterator(iter, earc, node_start);
for (i = 1; i <= nb_positions; i++)
{
- EmbedBucket *bucket = peekBucket(&iter, i);
+ EmbedBucket *bucket = IT_peek(iter, i);
positions_cache[i] = bucket->p;
}
- result = solveJoints(table, &iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints);
+ result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints);
min_cost = result->weight;
copyMemoPositions(best_positions, table, earc->bcount, nb_joints);
@@ -2148,10 +2263,32 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
/* BRUTE FORCE */
else if (method == METHOD_BRUTE_FORCE)
{
+ float **vec_cache;
+ float *cost_cache;
+ int *positions;
int last_index = 0;
int first_pass = 1;
int must_move = nb_joints - 1;
+ positions = MEM_callocN(sizeof(int) * nb_joints, "Aggresive positions");
+ cost_cache = MEM_callocN(sizeof(float) * nb_edges, "Cost cache");
+ vec_cache = MEM_callocN(sizeof(float*) * (nb_edges + 1), "Vec cache");
+
+ /* init with first values */
+ for (i = 0; i < nb_joints; i++)
+ {
+ positions[i] = i + 1;
+ }
+
+ /* init cost cache */
+ for (i = 0; i < nb_edges; i++)
+ {
+ cost_cache[i] = 0;
+ }
+
+ vec_cache[0] = node_start->p;
+ vec_cache[nb_edges] = node_end->p;
+
while(1)
{
float cost = 0;
@@ -2197,7 +2334,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
}
/* calculating cost */
- initArcIterator(&iter, earc, node_start);
+ initArcIterator(iter, earc, node_start);
vec0 = NULL;
vec1 = node_start->p;
@@ -2218,13 +2355,13 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
if (i < nb_joints)
{
i2 = positions[i];
- bucket = peekBucket(&iter, positions[i]);
+ bucket = IT_peek(iter, positions[i]);
vec2 = bucket->p;
vec_cache[i + 1] = vec2; /* update cache for updated position */
}
else
{
- i2 = iter.length;
+ i2 = iter->length;
vec2 = node_end->p;
}
@@ -2260,7 +2397,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
new_cost += costLength(edge->length, length2);
/* Distance Cost */
- new_cost += costDistance(&iter, vec1, vec2, i1, i2);
+ new_cost += costDistance(iter, vec1, vec2, i1, i2);
cost_cache[i] = new_cost;
}
@@ -2286,118 +2423,14 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
memcpy(best_positions, positions, sizeof(int) * nb_joints);
}
}
- }
- /* SIMULATED ANNEALING */
- else if (method == METHOD_ANNEALING)
- {
- RigEdge *previous;
- float *cost_cube;
- float cost;
- int k;
- int kmax;
-
- kmax = 100000;
-
- BLI_srand(nb_joints);
-
- /* [joint: index][position: -1, 0, +1] */
- cost_cube = MEM_callocN(sizeof(float) * 3 * nb_joints, "Cost Cube");
-
- initArcIterator(&iter, earc, node_start);
-
- /* init vec_cache */
- for (i = 0; i < nb_joints; i++)
- {
- bucket = peekBucket(&iter, positions[i]);
- vec_cache[i + 1] = bucket->p;
- }
-
- cost = 0;
-
- /* init cost cube */
- for (previous = iarc->edges.first, edge = previous->next, i = 0;
- edge;
- previous = edge, edge = edge->next, i += 1)
- {
- calcGradient(previous, edge, &iter, i, nb_joints, cost_cube, positions, vec_cache);
-
- cost += cost_cube[3 * i + 1];
- }
-
-#ifndef USE_THREADS
- printf("initial cost: %f\n", cost);
- printf("kmax: %i\n", kmax);
-#endif
-
- for (k = 0; k < kmax; k++)
- {
- int status;
- int moving_joint = -1;
- int move_direction = -1;
- float delta_cost;
- float temperature;
-
- status = neighbour(nb_joints, cost_cube, &moving_joint, &move_direction);
-
- if (status == 0)
- {
- /* if current state is still a minimum, copy it */
- if (cost < min_cost)
- {
- min_cost = cost;
- memcpy(best_positions, positions, sizeof(int) * nb_joints);
- }
- break;
- }
-
- delta_cost = cost_cube[moving_joint * 3 + (1 + move_direction)];
-
- temperature = 1 - (float)k / (float)kmax;
- if (probability(delta_cost, temperature) > BLI_frand())
- {
- /* update position */
- positions[moving_joint] += move_direction;
-
- /* update vector cache */
- bucket = peekBucket(&iter, positions[moving_joint]);
- vec_cache[moving_joint + 1] = bucket->p;
-
- cost += delta_cost;
- /* cost optimizing */
- if (cost < min_cost)
- {
- min_cost = cost;
- memcpy(best_positions, positions, sizeof(int) * nb_joints);
- }
-
- /* update cost cube */
- for (previous = iarc->edges.first, edge = previous->next, i = 0;
- edge;
- previous = edge, edge = edge->next, i += 1)
- {
- if (i == moving_joint - 1 ||
- i == moving_joint ||
- i == moving_joint + 1)
- {
- calcGradient(previous, edge, &iter, i, nb_joints, cost_cube, positions, vec_cache);
- }
- }
- }
- }
-
- //min_cost = cost;
- //memcpy(best_positions, positions, sizeof(int) * nb_joints);
-
-// printf("k = %i\n", k);
-
-
- MEM_freeN(cost_cube);
- }
-
+ MEM_freeN(positions);
+ MEM_freeN(cost_cache);
+ MEM_freeN(vec_cache);
+ }
vec0 = node_start->p;
- initArcIterator(&iter, earc, node_start);
+ initArcIterator(iter, earc, node_start);
#ifndef USE_THREADS
printPositions(best_positions, nb_joints);
@@ -2411,33 +2444,34 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
edge;
edge = edge->next, i++)
{
+ float *no = NULL;
if (i < nb_joints)
{
- bucket = peekBucket(&iter, best_positions[i]);
+ bucket = IT_peek(iter, best_positions[i]);
vec1 = bucket->p;
+ no = bucket->no;
}
else
{
vec1 = node_end->p;
+ no = node_end->no;
}
if (edge->bone)
{
- repositionBone(rigg, edge, vec0, vec1);
+ repositionBone(rigg, edge, vec0, vec1, no);
}
vec0 = vec1;
}
-
- MEM_freeN(positions);
+
MEM_freeN(best_positions);
- MEM_freeN(cost_cache);
- MEM_freeN(vec_cache);
}
static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
{
- ReebArcIterator iter;
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
ReebArc *earc = iarc->link_mesh;
ReebNode *node_start, *node_end;
RigEdge *edge;
@@ -2459,9 +2493,9 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
node_end = (ReebNode*)earc->tail;
}
- initArcIterator(&iter, earc, node_start);
+ initArcIterator(iter, earc, node_start);
- bucket = nextBucket(&iter);
+ bucket = IT_next(iter);
vec0 = node_start->p;
@@ -2472,15 +2506,15 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
embedding_length += VecLenf(vec0, vec1);
vec0 = vec1;
- bucket = nextBucket(&iter);
+ bucket = IT_next(iter);
}
embedding_length += VecLenf(node_end->p, vec1);
/* fit bones */
- initArcIterator(&iter, earc, node_start);
+ initArcIterator(iter, earc, node_start);
- bucket = nextBucket(&iter);
+ bucket = IT_next(iter);
vec0 = node_start->p;
previous_vec = vec0;
@@ -2489,26 +2523,28 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
for (edge = iarc->edges.first; edge; edge = edge->next)
{
float new_bone_length = edge->length / iarc->length * embedding_length;
-
+ float *no = NULL;
float length = 0;
while (bucket && new_bone_length > length)
{
length += VecLenf(previous_vec, vec1);
- bucket = nextBucket(&iter);
+ bucket = IT_next(iter);
previous_vec = vec1;
vec1 = bucket->p;
+ no = bucket->no;
}
if (bucket == NULL)
{
vec1 = node_end->p;
+ no = node_end->no;
}
/* no need to move virtual edges (space between unconnected bones) */
if (edge->bone)
{
- repositionBone(rigg, edge, vec0, vec1);
+ repositionBone(rigg, edge, vec0, vec1, no);
}
vec0 = vec1;
@@ -2551,11 +2587,11 @@ void *exec_retargetArctoArc(void *param)
if (testFlipArc(iarc, inode_start))
{
- repositionBone(rigg, edge, earc->tail->p, earc->head->p);
+ repositionBone(rigg, edge, earc->tail->p, earc->head->p, earc->head->no);
}
else
{
- repositionBone(rigg, edge, earc->head->p, earc->tail->p);
+ repositionBone(rigg, edge, earc->head->p, earc->tail->p, earc->tail->no);
}
}
else
@@ -2819,6 +2855,13 @@ static void retargetSubgraph(RigGraph *rigg, RigArc *start_arc, RigNode *start_n
}
}
+static void finishRetarget(RigGraph *rigg)
+{
+#ifdef USE_THREADS
+ BLI_end_worker(rigg->worker);
+#endif
+}
+
static void adjustGraphs(RigGraph *rigg)
{
RigArc *arc;
@@ -2831,12 +2874,10 @@ static void adjustGraphs(RigGraph *rigg)
}
}
-#ifdef USE_THREADS
- BLI_end_worker(rigg->worker);
-#endif
+ finishRetarget(rigg);
/* Turn the list into an armature */
- editbones_to_armature(&rigg->editbones, rigg->ob);
+ editbones_to_armature(rigg->editbones, rigg->ob);
BIF_undo_push("Retarget Skeleton");
}
@@ -2860,14 +2901,56 @@ static void retargetGraphs(RigGraph *rigg)
//generateMissingArcs(rigg);
-#ifdef USE_THREADS
- BLI_end_worker(rigg->worker);
-#endif
+ finishRetarget(rigg);
/* Turn the list into an armature */
- editbones_to_armature(&rigg->editbones, rigg->ob);
+ editbones_to_armature(rigg->editbones, rigg->ob);
}
+char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index)
+{
+ RigArc *arc = BLI_findlink(&rg->arcs, arc_index);
+ RigEdge *iedge;
+
+ if (arc == NULL)
+ {
+ return "None";
+ }
+
+ if (bone_index == BLI_countlist(&arc->edges))
+ {
+ return "Last joint";
+ }
+
+ iedge = BLI_findlink(&arc->edges, bone_index);
+
+ if (iedge == NULL)
+ {
+ return "Done";
+ }
+
+ if (iedge->bone == NULL)
+ {
+ return "Bone offset";
+ }
+
+ return iedge->bone->name;
+}
+
+int RIG_nbJoints(RigGraph *rg)
+{
+ RigArc *arc;
+ int total = 0;
+
+ total += BLI_countlist(&rg->nodes);
+
+ for (arc = rg->arcs.first; arc; arc = arc->next)
+ {
+ total += BLI_countlist(&arc->edges) - 1; /* -1 because end nodes are already counted */
+ }
+
+ return total;
+}
void BIF_retargetArmature()
{
@@ -2905,7 +2988,7 @@ void BIF_retargetArmature()
start_time = PIL_check_seconds_timer();
- rigg = armatureToGraph(ob, arm);
+ rigg = RIG_graphFromArmature(ob, arm);
end_time = PIL_check_seconds_timer();
rig_time = end_time - start_time;
@@ -2950,6 +3033,53 @@ void BIF_retargetArmature()
allqueue(REDRAWVIEW3D, 0);
}
+void BIF_retargetArc(ReebArc *earc, RigGraph *template_rigg)
+{
+ Object *ob;
+ RigGraph *rigg;
+ RigArc *iarc;
+ bArmature *arm;
+
+ if (template_rigg)
+ {
+ ob = template_rigg->ob;
+ arm = ob->data;
+ }
+ else
+ {
+ ob = G.obedit;
+ arm = ob->data;
+ template_rigg = armatureSelectedToGraph(ob, arm);
+ }
+
+ if (template_rigg->arcs.first == NULL)
+ {
+ error("No Template and no deforming bones selected");
+ return;
+ }
+
+ rigg = cloneRigGraph(template_rigg, &G.edbo, G.obedit);
+
+ iarc = rigg->arcs.first;
+
+ iarc->link_mesh = earc;
+ iarc->head->link_mesh = earc->head;
+ iarc->tail->link_mesh = earc->tail;
+
+ retargetArctoArc(rigg, iarc, iarc->head);
+
+ finishRetarget(rigg);
+
+ /* free template if it comes from the edit armature */
+ if (ob == G.obedit)
+ {
+ RIG_freeRigGraph((BGraph*)template_rigg);
+ }
+ RIG_freeRigGraph((BGraph*)rigg);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
void BIF_adjustRetarget()
{
if (GLOBAL_RIGG)
diff --git a/source/blender/src/editarmature_sketch.c b/source/blender/src/editarmature_sketch.c
new file mode 100644
index 00000000000..1452a3d0441
--- /dev/null
+++ b/source/blender/src/editarmature_sketch.c
@@ -0,0 +1,3073 @@
+/**
+ * $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 "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_scene_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 "BSE_view.h"
+
+#include "BIF_gl.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+#include "BIF_editarmature.h"
+#include "BIF_sketch.h"
+#include "BIF_retarget.h"
+#include "BIF_generate.h"
+#include "BIF_interface.h"
+
+#include "BIF_transform.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)(SK_Gesture*, SK_Sketch *);
+typedef void (*GestureApplyFct)(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(SK_Gesture *gest, SK_Sketch *sketch);
+void sk_applyCutGesture(SK_Gesture *gest, SK_Sketch *sketch);
+int sk_detectTrimGesture(SK_Gesture *gest, SK_Sketch *sketch);
+void sk_applyTrimGesture(SK_Gesture *gest, SK_Sketch *sketch);
+int sk_detectCommandGesture(SK_Gesture *gest, SK_Sketch *sketch);
+void sk_applyCommandGesture(SK_Gesture *gest, SK_Sketch *sketch);
+int sk_detectDeleteGesture(SK_Gesture *gest, SK_Sketch *sketch);
+void sk_applyDeleteGesture(SK_Gesture *gest, SK_Sketch *sketch);
+int sk_detectMergeGesture(SK_Gesture *gest, SK_Sketch *sketch);
+void sk_applyMergeGesture(SK_Gesture *gest, SK_Sketch *sketch);
+int sk_detectReverseGesture(SK_Gesture *gest, SK_Sketch *sketch);
+void sk_applyReverseGesture(SK_Gesture *gest, SK_Sketch *sketch);
+int sk_detectConvertGesture(SK_Gesture *gest, SK_Sketch *sketch);
+void sk_applyConvertGesture(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()
+{
+ 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 != G.obedit && ob->type == OB_ARMATURE)
+ {
+ index++;
+ BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob);
+
+ if (ob == G.scene->toolsettings->skgen_template)
+ {
+ TEMPLATES_CURRENT = index;
+ }
+ }
+ }
+}
+
+char *BIF_listTemplates()
+{
+ 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()
+{
+ if (TEMPLATES_CURRENT == 0 && G.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 == G.scene->toolsettings->skgen_template)
+ {
+ TEMPLATES_CURRENT = key;
+ break;
+ }
+
+ BLI_ghashIterator_step(&ghi);
+ }
+ }
+
+ return TEMPLATES_CURRENT;
+}
+
+RigGraph* sk_makeTemplateGraph(Object *ob)
+{
+ if (ob == G.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(ob, arm);
+ }
+ }
+
+ return TEMPLATE_RIGG;
+}
+
+int BIF_nbJointsTemplate()
+{
+ RigGraph *rg = sk_makeTemplateGraph(G.scene->toolsettings->skgen_template);
+
+ if (rg)
+ {
+ return RIG_nbJoints(rg);
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+char * BIF_nameBoneTemplate()
+{
+ 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(G.scene->toolsettings->skgen_template);
+
+ if (rg == NULL)
+ {
+ return "";
+ }
+
+ return RIG_nameBone(rg, 0, index);
+}
+
+void BIF_freeTemplates()
+{
+ 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(int index)
+{
+ if (index > 0)
+ {
+ G.scene->toolsettings->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index));
+ }
+ else
+ {
+ G.scene->toolsettings->skgen_template = NULL;
+
+ if (TEMPLATE_RIGG != NULL)
+ {
+ RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG);
+ }
+ TEMPLATE_RIGG = NULL;
+ }
+}
+
+/*********************** CONVERSION ***************************/
+
+void sk_autoname(ReebArc *arc)
+{
+ if (G.scene->toolsettings->skgen_retarget_options & SK_RETARGET_AUTONAME)
+ {
+ if (arc == NULL)
+ {
+ char *num = G.scene->toolsettings->skgen_num_string;
+ int i = atoi(num);
+ i++;
+ BLI_snprintf(num, 8, "%i", i);
+ }
+ else
+ {
+ char *side = G.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(SK_Stroke *stk)
+{
+ float imat[4][4];
+ float tmat[3][3];
+ ReebArc *arc;
+ RigGraph *rg;
+
+ Mat4Invert(imat, G.obedit->obmat);
+
+ Mat3CpyMat4(tmat, G.obedit->obmat);
+ Mat3Transp(tmat);
+
+ arc = sk_strokeToArc(stk, imat, tmat);
+
+ sk_autoname(arc);
+
+ rg = sk_makeTemplateGraph(G.scene->toolsettings->skgen_template);
+
+ BIF_retargetArc(arc, rg);
+
+ sk_autoname(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(SK_Point *pt)
+{
+ VECCOPY(pt->no, G.vd->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(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(BIF_GetThemeValuef(TH_VERTEX_SIZE) * 2);
+ glBegin(GL_POINTS);
+
+ index = next_subdividion(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(iter, bone_start, end, head, tail);
+ }
+
+ glEnd();
+ glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+}
+
+void sk_drawStrokeSubdivision(SK_Stroke *stk)
+{
+ int head_index = -1;
+ int i;
+
+ if (G.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 (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE)
+ {
+ drawSubdividedStrokeBy(iter, nextAdaptativeSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
+ {
+ drawSubdividedStrokeBy(iter, nextLengthSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
+ {
+ drawSubdividedStrokeBy(iter, nextFixedSubdivision);
+ }
+
+ }
+
+ head_index = i;
+ }
+ }
+ }
+}
+
+SK_Point *sk_snapPointStroke(SK_Stroke *stk, short mval[2], int *dist, int *index, int all_pts)
+{
+ 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(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(Object *ob, ListBase *ebones, short mval[2], int *dist)
+{
+ 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(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(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(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(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(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(SK_Sketch *sketch)
+{
+ sk_shrinkStrokeBuffer(sketch->active_stroke);
+
+ if (G.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(float p1[3], float p2[3])
+{
+ float vec[3];
+ float distance;
+
+ VecSubf(vec, p1, p2);
+
+ Projf(vec, vec, G.vd->viewinv[2]);
+
+ distance = VecLength(vec);
+
+ if (Inpf(G.vd->viewinv[2], vec) > 0)
+ {
+ distance *= -1;
+ }
+
+ return distance;
+}
+
+void sk_interpolateDepth(SK_Stroke *stk, int start, int end, float length, float distance)
+{
+ 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(stk->points[i].p, pval);
+ viewray(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(float vec[3], SK_Stroke *stk, SK_DrawData *dd)
+{
+ /* copied from grease pencil, need fixing */
+ SK_Point *last = sk_lastStrokePoint(stk);
+ short cval[2];
+ //float *fp = give_cursor();
+ float fp[3] = {0, 0, 0};
+ float dvec[3];
+
+ if (last != NULL)
+ {
+ VECCOPY(fp, last->p);
+ }
+
+ initgrabz(fp[0], fp[1], fp[2]);
+
+ /* method taken from editview.c - mouse_cursor() */
+ project_short_noclip(fp, cval);
+ window_to_3d(dvec, cval[0] - dd->mval[0], cval[1] - dd->mval[1]);
+ VecSubf(vec, fp, dvec);
+}
+
+int sk_getStrokeDrawPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+ pt->type = dd->type;
+ pt->mode = PT_PROJECT;
+ sk_projectDrawPoint(pt->p, stk, dd);
+
+ return 1;
+}
+
+int sk_addStrokeDrawPoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+ SK_Point pt;
+
+ sk_initPoint(&pt);
+
+ sk_getStrokeDrawPoint(&pt, sketch, stk, dd);
+
+ sk_appendStrokePoint(stk, &pt);
+
+ return 1;
+}
+
+int sk_getStrokeSnapPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+ int point_added = 0;
+
+ if (G.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;
+
+ peelObjects(&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 (G.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 (G.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(snap_stk, dd->mval, &dist, NULL, 0);
+ }
+ else
+ {
+ spt = sk_snapPointStroke(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 = snapObjects(&dist, vec, no, 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(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+ int point_added;
+ SK_Point pt;
+
+ sk_initPoint(&pt);
+
+ point_added = sk_getStrokeSnapPoint(&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(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(final_p, stk->points[i].p);
+
+ sk_interpolateDepth(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(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short qual)
+{
+ int point_added = 0;
+
+ if (qual & LR_CTRLKEY)
+ {
+ point_added = sk_addStrokeSnapPoint(sketch, stk, dd);
+ }
+
+ if (point_added == 0)
+ {
+ point_added = sk_addStrokeDrawPoint(sketch, stk, dd);
+ }
+
+ if (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_ADJUST)
+ {
+ sk_updateOverdraw(sketch, stk, dd);
+ }
+}
+
+void sk_getStrokePoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short qual)
+{
+ int point_added = 0;
+
+ if (qual & LR_CTRLKEY)
+ {
+ point_added = sk_getStrokeSnapPoint(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(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)
+{
+ 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(SK_Stroke *stk)
+{
+ bArmature *arm = G.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, G.obedit->obmat);
+
+ Mat3CpyMat4(tmat, G.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 (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE)
+ {
+ bone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
+ {
+ bone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextLengthSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
+ {
+ bone = subdivideArcBy(arm, &G.edbo, iter, invmat, tmat, nextFixedSubdivision);
+ }
+ }
+
+ if (bone == NULL)
+ {
+ bone = addEditBone("Bone", &G.edbo, arm);
+
+ 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(SK_Sketch *sketch)
+{
+ SK_Stroke *stk;
+
+ for (stk = sketch->strokes.first; stk; stk = stk->next)
+ {
+ if (stk->selected == 1)
+ {
+ if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET)
+ {
+ sk_retargetStroke(stk);
+ }
+ else
+ {
+ sk_convertStroke(stk);
+ }
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+}
+/******************* GESTURE *************************/
+
+
+/* returns the number of self intersections */
+int sk_getSelfIntersections(ListBase *list, SK_Stroke *gesture)
+{
+ 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(gesture->points[s_i].p, s_p1);
+ project_float(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(gesture->points[g_i].p, g_p1);
+ project_float(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(ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
+{
+ 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(stk->points[s_i].p, s_p1);
+ project_float(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(gesture->points[g_i].p, g_p1);
+ project_float(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(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(SK_Gesture *gest, SK_Sketch *sketch)
+{
+ if (gest->nb_segments == 1 && gest->nb_intersections == 1)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+void sk_applyCutGesture(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(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(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(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(SK_Gesture *gest, SK_Sketch *sketch)
+{
+ SK_Intersection *isect;
+ int command;
+
+ 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(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(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(SK_Gesture *gest, SK_Sketch *sketch)
+{
+ if (gest->nb_segments > 2 && gest->nb_intersections == 2)
+ {
+ short start_val[2], end_val[2];
+ short dist;
+
+ project_short_noclip(gest->stk->points[0].p, start_val);
+ project_short_noclip(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(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(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(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(SK_Gesture *gest, SK_Sketch *sketch)
+{
+ if (gest->nb_segments == 3 && gest->nb_self_intersections == 1)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+void sk_applyConvertGesture(SK_Gesture *gest, SK_Sketch *sketch)
+{
+ sk_convert(sketch);
+}
+
+static void sk_initGesture(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(&gest->self_intersections, gest->stk);
+ gest->nb_intersections = sk_getIntersections(&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(SK_Sketch *sketch)
+{
+ SK_Gesture gest;
+ SK_GestureAction *act;
+
+ sk_initGesture(&gest, sketch);
+
+ /* detect and apply */
+ for (act = GESTURE_ACTIONS; act->apply != NULL; act++)
+ {
+ if (act->detect(&gest, sketch))
+ {
+ act->apply(&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)
+{
+ unsigned int buffer[MAXPICKBUF];
+ short hits, mval[2];
+
+ persp(PERSP_VIEW);
+
+ getmouseco_areawin(mval);
+ 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 ((G.qual & LR_SHIFTKEY) == 0)
+ {
+ sk_selectAllSketch(sketch, -1);
+
+ selected_stk->selected = 1;
+ }
+ else
+ {
+ selected_stk->selected ^= 1;
+ }
+
+
+ }
+ }
+}
+
+void sk_queueRedrawSketch(SK_Sketch *sketch)
+{
+ if (sketch->active_stroke != NULL)
+ {
+ SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
+
+ if (last != NULL)
+ {
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+void sk_drawSketch(SK_Sketch *sketch, int with_names)
+{
+ SK_Stroke *stk;
+
+ glDisable(GL_DEPTH_TEST);
+
+ glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+ glPointSize(BIF_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(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 (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK)
+ {
+ sk_drawStrokeSubdivision(sketch->active_stroke);
+ }
+
+ if (last != NULL)
+ {
+ /* update point if in active area */
+ if (area_is_active_area(G.vd->area))
+ {
+ SK_DrawData dd;
+
+ sk_initDrawData(&dd);
+ sk_getStrokePoint(&sketch->next_point, sketch, sketch->active_stroke, &dd, G.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(SK_Sketch *sketch, short mbut)
+{
+ int retval = 1;
+
+ 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 */
+ 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(sketch, sketch->active_stroke, &dd, G.qual);
+ sk_updateDrawData(&dd);
+ 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 (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(sketch);
+
+ if (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK)
+ {
+ if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET)
+ {
+ sk_retargetStroke(stk);
+ }
+ else
+ {
+ sk_convertStroke(stk);
+ }
+ BIF_undo_push("Convert Sketch");
+ sk_removeStroke(sketch, stk);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ /* no gestures in quick mode */
+ else if (G.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 */
+ 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(sketch, sketch->gesture, &dd);
+ sk_updateDrawData(&dd);
+
+ /* draw only if mouse has moved */
+ if (sketch->gesture->nb_points > 1)
+ {
+ 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 (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)
+ {
+ sk_selectStroke(sketch);
+ }
+ else
+ {
+ /* apply gesture here */
+ sk_applyGesture(sketch);
+ }
+
+ sk_freeStroke(sketch->gesture);
+ sketch->gesture = NULL;
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+
+ return retval;
+}
+
+void BDR_drawSketchNames()
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_drawSketch(GLOBAL_sketch, 1);
+ }
+ }
+}
+
+void BDR_drawSketch()
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_drawSketch(GLOBAL_sketch, 0);
+ }
+ }
+}
+
+void BIF_endStrokeSketch()
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_endStroke(GLOBAL_sketch);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+void BIF_cancelStrokeSketch()
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_cancelStroke(GLOBAL_sketch);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+void BIF_deleteSketch()
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_deleteSelectedStrokes(GLOBAL_sketch);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+void BIF_convertSketch()
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_convert(GLOBAL_sketch);
+ BIF_undo_push("Convert Sketch");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+}
+
+int BIF_paintSketch(short mbut)
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch == NULL)
+ {
+ GLOBAL_sketch = sk_createSketch();
+ }
+
+ return sk_paint(GLOBAL_sketch, mbut);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+void BDR_queueDrawSketch()
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_queueRedrawSketch(GLOBAL_sketch);
+ }
+ }
+}
+
+void BIF_selectAllSketch(int mode)
+{
+ if (BIF_validSketchMode())
+ {
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_selectAllSketch(GLOBAL_sketch, mode);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+int BIF_validSketchMode()
+{
+ if (G.obedit &&
+ G.obedit->type == OB_ARMATURE &&
+ G.scene->toolsettings->bone_sketching & BONE_SKETCHING)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int BIF_fullSketchMode()
+{
+ if (G.obedit &&
+ G.obedit->type == OB_ARMATURE &&
+ G.scene->toolsettings->bone_sketching & BONE_SKETCHING &&
+ (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK) == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void BIF_freeSketch()
+{
+ if (GLOBAL_sketch != NULL)
+ {
+ sk_freeSketch(GLOBAL_sketch);
+ GLOBAL_sketch = NULL;
+ }
+}
diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c
index fd8bd7dc014..f4cfc0c0dd6 100644
--- a/source/blender/src/gpencil.c
+++ b/source/blender/src/gpencil.c
@@ -939,7 +939,7 @@ static void gp_stroke_to_bonechain (bGPDlayer *gpl, bGPDstroke *gps, bArmature *
/* add new bone - note: sync with editarmature.c::add_editbone() */
{
BLI_strncpy(ebo->name, "Stroke", 32);
- unique_editbone_name(bones, ebo->name);
+ unique_editbone_name(bones, ebo->name, NULL);
BLI_addtail(bones, ebo);
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index 60c5854f1a5..53be105f7a8 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -3980,6 +3980,9 @@ static void do_view3d_edit_armaturemenu(void *arg, int event)
case 22: /* separate */
separate_armature();
break;
+ case 23: /* bone sketching panel */
+ add_blockhandler(curarea, VIEW3D_HANDLER_BONESKETCH, UI_PNL_UNSTOW);
+ break;
}
allqueue(REDRAWVIEW3D, 0);
@@ -4057,6 +4060,7 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused)
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Bone Sketching|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 23, "");
uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
@@ -5214,6 +5218,7 @@ static char *snapmode_pup(void)
str += sprintf(str, "%s", "|Vertex%x0");
str += sprintf(str, "%s", "|Edge%x1");
str += sprintf(str, "%s", "|Face%x2");
+ str += sprintf(str, "%s", "|Volume%x3");
return string;
}
diff --git a/source/blender/src/reeb.c b/source/blender/src/reeb.c
index b37087064cb..67cfce55907 100644
--- a/source/blender/src/reeb.c
+++ b/source/blender/src/reeb.c
@@ -850,8 +850,10 @@ void fillArcEmptyBuckets(ReebArc *arc)
static void ExtendArcBuckets(ReebArc *arc)
{
- ReebArcIterator iter;
- EmbedBucket *previous, *bucket, *last_bucket, *first_bucket;
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
+ EmbedBucket *last_bucket, *first_bucket;
+ float *previous = NULL;
float average_length = 0, length;
int padding_head = 0, padding_tail = 0;
@@ -860,14 +862,16 @@ static void ExtendArcBuckets(ReebArc *arc)
return; /* failsafe, shouldn't happen */
}
- initArcIterator(&iter, arc, arc->head);
+ initArcIterator(iter, arc, arc->head);
+ IT_next(iter);
+ previous = iter->p;
- for ( previous = nextBucket(&iter), bucket = nextBucket(&iter);
- bucket;
- previous = bucket, bucket = nextBucket(&iter)
+ for ( IT_next(iter);
+ IT_stopped(iter) == 0;
+ previous = iter->p, IT_next(iter)
)
{
- average_length += VecLenf(previous->p, bucket->p);
+ average_length += VecLenf(previous, iter->p);
}
average_length /= (arc->bcount - 1);
@@ -924,27 +928,24 @@ void extendGraphBuckets(ReebGraph *rg)
void calculateArcLength(ReebArc *arc)
{
- ReebArcIterator iter;
- EmbedBucket *bucket = NULL;
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
float *vec0, *vec1;
arc->length = 0;
- initArcIterator(&iter, arc, arc->head);
+ initArcIterator(iter, arc, arc->head);
- bucket = nextBucket(&iter);
-
vec0 = arc->head->p;
vec1 = arc->head->p; /* in case there's no embedding */
-
- while (bucket != NULL)
+
+ while (IT_next(iter))
{
- vec1 = bucket->p;
+ vec1 = iter->p;
arc->length += VecLenf(vec0, vec1);
vec0 = vec1;
- bucket = nextBucket(&iter);
}
arc->length += VecLenf(arc->tail->p, vec1);
@@ -997,28 +998,30 @@ void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count)
* */
if (arc1->bcount > 0 && arc2->bcount > 0)
{
- ReebArcIterator iter1, iter2;
+ ReebArcIterator arc_iter1, arc_iter2;
+ BArcIterator *iter1 = (BArcIterator*)&arc_iter1;
+ BArcIterator *iter2 = (BArcIterator*)&arc_iter2;
EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
- initArcIterator(&iter1, arc1, (ReebNode*)root_node);
- initArcIterator(&iter2, arc2, (ReebNode*)root_node);
+ initArcIterator(iter1, arc1, (ReebNode*)root_node);
+ initArcIterator(iter2, arc2, (ReebNode*)root_node);
- bucket1 = nextBucket(&iter1);
- bucket2 = nextBucket(&iter2);
+ bucket1 = IT_next(iter1);
+ bucket2 = IT_next(iter2);
/* Make sure they both start at the same value */
- while(bucket1 && bucket1->val < bucket2->val)
+ while(bucket1 && bucket2 && bucket1->val < bucket2->val)
{
- bucket1 = nextBucket(&iter1);
+ bucket1 = IT_next(iter1);
}
- while(bucket2 && bucket2->val < bucket1->val)
+ while(bucket1 && bucket2 && bucket2->val < bucket1->val)
{
- bucket2 = nextBucket(&iter2);
+ bucket2 = IT_next(iter2);
}
- for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2))
+ for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2))
{
bucket2->nv += bucket1->nv; /* add counts */
@@ -1057,28 +1060,30 @@ void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count)
* */
if (arc1->bcount > 0 && arc2->bcount > 0)
{
- ReebArcIterator iter1, iter2;
+ ReebArcIterator arc_iter1, arc_iter2;
+ BArcIterator *iter1 = (BArcIterator*)&arc_iter1;
+ BArcIterator *iter2 = (BArcIterator*)&arc_iter2;
EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
- initArcIterator(&iter1, arc1, node);
- initArcIterator(&iter2, arc2, node);
+ initArcIterator(iter1, arc1, node);
+ initArcIterator(iter2, arc2, node);
- bucket1 = nextBucket(&iter1);
- bucket2 = nextBucket(&iter2);
+ bucket1 = IT_next(iter1);
+ bucket2 = IT_next(iter2);
/* Make sure they both start at the same value */
while(bucket1 && bucket1->val < bucket2->val)
{
- bucket1 = nextBucket(&iter1);
+ bucket1 = IT_next(iter1);
}
while(bucket2 && bucket2->val < bucket1->val)
{
- bucket2 = nextBucket(&iter2);
+ bucket2 = IT_next(iter2);
}
- for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2))
+ for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2))
{
/* copy and mirror back to bucket2 */
bucket2->nv = bucket1->nv;
@@ -1116,28 +1121,30 @@ void REEB_AxialSymmetry(BNode* root_node, BNode* node1, BNode* node2, struct BAr
* */
if (arc1->bcount > 0 && arc2->bcount > 0)
{
- ReebArcIterator iter1, iter2;
+ ReebArcIterator arc_iter1, arc_iter2;
+ BArcIterator *iter1 = (BArcIterator*)&arc_iter1;
+ BArcIterator *iter2 = (BArcIterator*)&arc_iter2;
EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
- initArcIterator(&iter1, arc1, (ReebNode*)root_node);
- initArcIterator(&iter2, arc2, (ReebNode*)root_node);
+ initArcIterator(iter1, arc1, (ReebNode*)root_node);
+ initArcIterator(iter2, arc2, (ReebNode*)root_node);
- bucket1 = nextBucket(&iter1);
- bucket2 = nextBucket(&iter2);
+ bucket1 = IT_next(iter1);
+ bucket2 = IT_next(iter2);
/* Make sure they both start at the same value */
while(bucket1 && bucket1->val < bucket2->val)
{
- bucket1 = nextBucket(&iter1);
+ bucket1 = IT_next(iter1);
}
while(bucket2 && bucket2->val < bucket1->val)
{
- bucket2 = nextBucket(&iter2);
+ bucket2 = IT_next(iter2);
}
- for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2))
+ for ( ;bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2))
{
bucket1->nv += bucket2->nv; /* add counts */
@@ -1655,10 +1662,11 @@ int filterInternalExternalReebGraph(ReebGraph *rg, float threshold_internal, flo
middleNode = arc->head;
}
- if (middleNode->degree == 2)
+ if (middleNode->degree == 2 && middleNode != rg->nodes.first)
{
#if 1
// If middle node is a normal node, it will be removed later
+ // Only if middle node is not the root node
/* USE THIS IF YOU WANT TO PROLONG ARCS TO THEIR TERMINAL NODES
* FOR HANDS, THIS IS NOT THE BEST RESULT
* */
@@ -1764,15 +1772,16 @@ int filterSmartReebGraph(ReebGraph *rg, float threshold)
EditFace *efa = BLI_ghashIterator_getValue(&ghi);
#if 0
- ReebArcIterator iter;
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
EmbedBucket *bucket = NULL;
EmbedBucket *previous = NULL;
float min_distance = -1;
float angle = 0;
- initArcIterator(&iter, arc, arc->head);
+ initArcIterator(iter, arc, arc->head);
- bucket = nextBucket(&iter);
+ bucket = nextBucket(iter);
while (bucket != NULL)
{
@@ -1807,7 +1816,7 @@ int filterSmartReebGraph(ReebGraph *rg, float threshold)
}
previous = bucket;
- bucket = nextBucket(&iter);
+ bucket = nextBucket(iter);
}
avg_angle += saacos(fabs(angle));
@@ -3297,8 +3306,44 @@ void arcToVCol(ReebGraph *rg, EditMesh *em, int index)
/****************************************** BUCKET ITERATOR **************************************************/
-void initArcIterator(ReebArcIterator *iter, ReebArc *arc, ReebNode *head)
+static void* headNode(void *arg);
+static void* tailNode(void *arg);
+static void* nextBucket(void *arg);
+static void* nextNBucket(void *arg, int n);
+static void* peekBucket(void *arg, int n);
+static void* previousBucket(void *arg);
+static int iteratorStopped(void *arg);
+
+static void initIteratorFct(ReebArcIterator *iter)
+{
+ iter->head = headNode;
+ iter->tail = tailNode;
+ iter->peek = peekBucket;
+ iter->next = nextBucket;
+ iter->nextN = nextNBucket;
+ iter->previous = previousBucket;
+ iter->stopped = iteratorStopped;
+}
+
+static void setIteratorValues(ReebArcIterator *iter, EmbedBucket *bucket)
+{
+ if (bucket)
+ {
+ iter->p = bucket->p;
+ iter->no = bucket->no;
+ }
+ else
+ {
+ iter->p = NULL;
+ iter->no = NULL;
+ }
+}
+
+void initArcIterator(BArcIterator *arg, ReebArc *arc, ReebNode *head)
{
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
+
+ initIteratorFct(iter);
iter->arc = arc;
if (head == arc->head)
@@ -3316,11 +3361,14 @@ void initArcIterator(ReebArcIterator *iter, ReebArc *arc, ReebNode *head)
iter->length = arc->bcount;
- iter->index = iter->start - iter->stride;
+ iter->index = -1;
}
-void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start)
+void initArcIteratorStart(BArcIterator *arg, struct ReebArc *arc, struct ReebNode *head, int start)
{
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
+
+ initIteratorFct(iter);
iter->arc = arc;
if (head == arc->head)
@@ -3336,7 +3384,7 @@ void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, str
iter->stride = -1;
}
- iter->index = iter->start - iter->stride;
+ iter->index = -1;
iter->length = arc->bcount - start;
@@ -3346,8 +3394,11 @@ void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, str
}
}
-void initArcIterator2(ReebArcIterator *iter, ReebArc *arc, int start, int end)
+void initArcIterator2(BArcIterator *arg, ReebArc *arc, int start, int end)
{
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
+
+ initIteratorFct(iter);
iter->arc = arc;
iter->start = start;
@@ -3362,97 +3413,129 @@ void initArcIterator2(ReebArcIterator *iter, ReebArc *arc, int start, int end)
iter->stride = -1;
}
- iter->index = iter->start - iter->stride;
+ iter->index = -1;
iter->length = abs(iter->end - iter->start) + 1;
}
-EmbedBucket * nextBucket(ReebArcIterator *iter)
+static void* headNode(void *arg)
{
- EmbedBucket *result = NULL;
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
+ ReebNode *node;
- if (iter->index != iter->end)
+ if (iter->start < iter->end)
{
- iter->index += iter->stride;
- result = &(iter->arc->buckets[iter->index]);
+ node = iter->arc->head;
+ }
+ else
+ {
+ node = iter->arc->tail;
}
- return result;
+ iter->p = node->p;
+ iter->no = node->no;
+
+ return node;
}
-EmbedBucket * nextNBucket(ReebArcIterator *iter, int n)
+static void* tailNode(void *arg)
{
- EmbedBucket *result = NULL;
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
+ ReebNode *node;
- iter->index += n * iter->stride;
-
- /* check if passed end */
- if ((iter->stride == 1 && iter->index <= iter->end) ||
- (iter->stride == -1 && iter->index >= iter->end))
+ if (iter->start < iter->end)
{
- result = &(iter->arc->buckets[iter->index]);
+ node = iter->arc->tail;
}
else
{
- /* stop iterator if passed end */
- iter->index = iter->end;
+ node = iter->arc->head;
}
- return result;
+ iter->p = node->p;
+ iter->no = node->no;
+
+ return node;
}
-EmbedBucket * peekBucket(ReebArcIterator *iter, int n)
+static void* nextBucket(void *arg)
{
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
EmbedBucket *result = NULL;
- int index = iter->index + n * iter->stride;
-
- /* check if passed end */
- if ((iter->stride == 1 && index <= iter->end && index >= iter->start) ||
- (iter->stride == -1 && index >= iter->end && index <= iter->start))
+
+ iter->index++;
+
+ if (iter->index < iter->length)
{
- result = &(iter->arc->buckets[index]);
+ result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
}
+ setIteratorValues(iter, result);
return result;
}
-EmbedBucket * previousBucket(struct ReebArcIterator *iter)
+static void* nextNBucket(void *arg, int n)
{
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
EmbedBucket *result = NULL;
-
- if (iter->index != iter->start)
+
+ iter->index += n;
+
+ /* check if passed end */
+ if (iter->index < iter->length)
{
- iter->index -= iter->stride;
- result = &(iter->arc->buckets[iter->index]);
+ result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
}
+ setIteratorValues(iter, result);
return result;
}
-int iteratorStopped(struct ReebArcIterator *iter)
+static void* peekBucket(void *arg, int n)
{
- if (iter->index == iter->end)
- {
- return 1;
- }
- else
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
+ EmbedBucket *result = NULL;
+ int index = iter->index + n;
+
+ /* check if passed end */
+ if (index < iter->length)
{
- return 0;
+ result = &(iter->arc->buckets[iter->start + (iter->stride * index)]);
}
+
+ setIteratorValues(iter, result);
+ return result;
}
-struct EmbedBucket * currentBucket(struct ReebArcIterator *iter)
+static void* previousBucket(void *arg)
{
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
EmbedBucket *result = NULL;
- if (iter->index != iter->end)
+ if (iter->index > 0)
{
- result = &(iter->arc->buckets[iter->index]);
+ iter->index--;
+ result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
}
-
+
+ setIteratorValues(iter, result);
return result;
}
+static int iteratorStopped(void *arg)
+{
+ ReebArcIterator *iter = (ReebArcIterator*)arg;
+
+ if (iter->index >= iter->length)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
/************************ PUBLIC FUNCTIONS *********************************************/
ReebGraph *BIF_ReebGraphMultiFromEditMesh(void)
@@ -3597,26 +3680,32 @@ ReebGraph *BIF_ReebGraphFromEditMesh(void)
rg = generateReebGraph(em, G.scene->toolsettings->skgen_resolution);
- REEB_exportGraph(rg, -1);
-
- printf("GENERATED\n");
- printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph*)rg));
/* Remove arcs without embedding */
filterNullReebGraph(rg);
- BLI_freeAdjacencyList((BGraph*)rg);
+ /* smart filter and loop filter on basic level */
+ filterGraph(rg, SKGEN_FILTER_SMART, 0, 0);
- printf("NULL FILTERED\n");
- printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph*)rg));
+ repositionNodes(rg);
+ /* Filtering might have created degree 2 nodes, so remove them */
+ removeNormalNodes(rg);
+
+ joinSubgraphs(rg, 1.0);
+
+ BLI_buildAdjacencyList((BGraph*)rg);
+
+ /* calc length before copy, so we have same length on all levels */
+ BLI_calcGraphLength((BGraph*)rg);
+
filterGraph(rg, G.scene->toolsettings->skgen_options, G.scene->toolsettings->skgen_threshold_internal, G.scene->toolsettings->skgen_threshold_external);
finalizeGraph(rg, G.scene->toolsettings->skgen_postpro_passes, G.scene->toolsettings->skgen_postpro);
+#ifdef DEBUG_REEB
REEB_exportGraph(rg, -1);
-#ifdef DEBUG_REEB
arcToVCol(rg, em, 0);
//angleToVCol(em, 1);
#endif
@@ -3676,8 +3765,8 @@ void REEB_draw()
glDisable(GL_DEPTH_TEST);
for (arc = rg->arcs.first; arc; arc = arc->next, i++)
{
- ReebArcIterator iter;
- EmbedBucket *bucket;
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator*)&arc_iter;
float vec[3];
char text[128];
char *s = text;
@@ -3689,10 +3778,10 @@ void REEB_draw()
if (arc->bcount)
{
- initArcIterator(&iter, arc, arc->head);
- for (bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter))
+ initArcIterator(iter, arc, arc->head);
+ for (IT_next(iter); IT_stopped(iter) == 0; IT_next(iter))
{
- glVertex3fv(bucket->p);
+ glVertex3fv(iter->p);
}
}
@@ -3722,10 +3811,10 @@ void REEB_draw()
if (arc->bcount)
{
- initArcIterator(&iter, arc, arc->head);
- for (bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter))
+ initArcIterator(iter, arc, arc->head);
+ for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter))
{
- glVertex3fv(bucket->p);
+ glVertex3fv(iter->p);
}
}
@@ -3743,10 +3832,10 @@ void REEB_draw()
glColor3f(0.5f, 0.5f, 1);
if (arc->bcount)
{
- initArcIterator(&iter, arc, arc->head);
- for (bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter))
+ initArcIterator(iter, arc, arc->head);
+ for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter))
{
- glVertex3fv(bucket->p);
+ glVertex3fv(iter->p);
}
}
glEnd();
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index a132a58cfbf..c6510b780d8 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -139,6 +139,7 @@
#include "BIF_toolbox.h"
#include "BIF_usiblender.h"
#include "BIF_previewrender.h"
+#include "BIF_sketch.h"
#include "BSE_edit.h"
#include "BSE_view.h"
@@ -163,6 +164,7 @@
#include "BDR_sculptmode.h"
#include "BDR_unwrapper.h"
#include "BDR_gpencil.h"
+#include "BDR_sketch.h"
#include "BLO_readfile.h" /* for BLO_blendhandle_close */
@@ -1263,11 +1265,13 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
* - grease-pencil also defaults to leftmouse
*/
if(event==LEFTMOUSE) {
+ if(BIF_paintSketch(LEFTMOUSE)) return;
if(gpencil_do_paint(sa, L_MOUSE)) return;
if(BIF_do_manipulator(sa)) return;
}
else if(event==RIGHTMOUSE) {
if(gpencil_do_paint(sa, R_MOUSE)) return;
+ if(BIF_paintSketch(RIGHTMOUSE)) return;
}
/* swap mouse buttons based on user preference */
@@ -1318,6 +1322,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
}
}
+ BDR_queueDrawSketch();
/* Handle retopo painting */
if(retopo_mesh_paint_check()) {
@@ -1913,7 +1918,16 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
else if(G.obedit->type==OB_LATTICE)
deselectall_Latt();
else if(G.obedit->type==OB_ARMATURE)
- deselectall_armature(1, 1); /* 1 == toggle */
+ {
+ if (BIF_fullSketchMode())
+ {
+ BIF_selectAllSketch(1);
+ }
+ else
+ {
+ deselectall_armature(1, 1); /* 1 == toggle */
+ }
+ }
}
else if (ob && (ob->flag & OB_POSEMODE)){
deselectall_posearmature(ob, 1, 1);
@@ -1981,6 +1995,10 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
else if(G.qual==LR_ALTKEY) {
if(ob && (ob->flag & OB_POSEMODE))
pose_clear_constraints(); /* poseobject.c */
+ else if (BIF_fullSketchMode())
+ {
+ BIF_convertSketch();
+ }
else
convertmenu(); /* editobject.c */
}
@@ -2502,8 +2520,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
else if(G.qual==LR_ALTKEY && G.obedit->type==OB_ARMATURE)
clear_bone_parent();
- else if((G.qual==0) && (G.obedit->type==OB_ARMATURE))
- armature_select_hierarchy(BONE_SELECT_PARENT, 1); // 1 = add to selection
+ else if((G.qual==0) && (G.obedit->type==OB_ARMATURE))
+ {
+ toggle_blockhandler(curarea, VIEW3D_HANDLER_BONESKETCH, UI_PNL_TO_MOUSE);
+ allqueue(REDRAWVIEW3D, 0);
+ }
else if((G.qual==(LR_CTRLKEY|LR_ALTKEY)) && (G.obedit->type==OB_ARMATURE))
separate_armature();
else if((G.qual==0) && G.obedit->type==OB_MESH)
@@ -2788,7 +2809,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
case DELKEY:
if(G.qual==0 || G.qual==LR_SHIFTKEY)
delete_context_selected();
- if(G.qual==LR_ALTKEY)
+ else if(G.qual==LR_ALTKEY)
gpencil_delete_menu();
break;
case YKEY:
@@ -2950,7 +2971,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
break;
case ESCKEY:
- if(G.qual==0) {
+ if (G.qual == 0 && BIF_validSketchMode())
+ {
+ BIF_cancelStrokeSketch();
+ }
+ else if(G.qual==0) {
if (G.vd->flag & V3D_DISPIMAGE) {
G.vd->flag &= ~V3D_DISPIMAGE;
doredraw= 1;
diff --git a/source/blender/src/transform_snap.c b/source/blender/src/transform_snap.c
index eeb5eaeec10..6be8b0e881a 100644
--- a/source/blender/src/transform_snap.c
+++ b/source/blender/src/transform_snap.c
@@ -33,6 +33,8 @@
#include "PIL_time.h"
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_meshdata_types.h" // Temporary, for snapping to other unselected meshes
@@ -43,11 +45,13 @@
#include "BLI_arithb.h"
#include "BLI_editVert.h"
+#include "BLI_blenlib.h"
#include "BDR_drawobject.h"
#include "editmesh.h"
#include "BIF_editsima.h"
+#include "BIF_editarmature.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BIF_mywindow.h"
@@ -57,6 +61,8 @@
#include "BIF_drawimage.h"
#include "BIF_editmesh.h"
+#include "BIF_transform.h"
+
#include "BKE_global.h"
#include "BKE_utildefines.h"
#include "BKE_DerivedMesh.h"
@@ -91,11 +97,6 @@ float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
float ResizeBetween(TransInfo *t, float p1[3], float p2[3]);
-/* Modes */
-#define NOT_SELECTED 0
-#define NOT_ACTIVE 1
-int snapObjects(int *dist, float *loc, float *no, int mode);
-
/****************** IMPLEMENTATIONS *********************/
@@ -103,7 +104,7 @@ int BIF_snappingSupported(void)
{
int status = 0;
- if (G.obedit == NULL || G.obedit->type==OB_MESH) /* only support object or mesh */
+ if (G.obedit == NULL || ELEM(G.obedit->type, OB_MESH, OB_ARMATURE)) /* only support object, mesh, armature */
{
status = 1;
}
@@ -277,7 +278,7 @@ void initSnapping(TransInfo *t)
/* Edit mode */
if (t->tsnap.applySnap != NULL && // A snapping function actually exist
(G.scene->snap_flag & SCE_SNAP) && // Only if the snap flag is on
- (G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes
+ (G.obedit != NULL && ELEM(G.obedit->type, OB_MESH, OB_ARMATURE)) && // Temporary limited to edit mode meshes and armatures
((t->flag & T_PROP_EDIT) == 0) ) // No PET, obviously
{
t->tsnap.status |= SNAP_ON;
@@ -481,87 +482,167 @@ void CalcSnapGrid(TransInfo *t, float *vec)
void CalcSnapGeometry(TransInfo *t, float *vec)
{
- /* Object mode */
- if (G.obedit == NULL)
+ if (t->spacetype == SPACE_VIEW3D)
{
- if (t->spacetype == SPACE_VIEW3D)
+ float loc[3];
+ float no[3];
+ int found = 0;
+ int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
+ SnapMode mode;
+
+ if (G.scene->snap_mode == SCE_SNAP_MODE_VOLUME)
{
- float vec[3];
- float no[3];
- int found = 0;
- int dist = 40; // Use a user defined value here
+ ListBase depth_peels;
+ DepthPeel *p1, *p2;
+ float *last_p = NULL;
+ float dist = FLT_MAX;
+ float p[3];
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ depth_peels.first = depth_peels.last = NULL;
+
+ peelObjects(&depth_peels, mval);
- found = snapObjects(&dist, vec, no, NOT_SELECTED);
- if (found == 1)
+// 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)
{
- float tangent[3];
-
- VecSubf(tangent, vec, t->tsnap.snapPoint);
- tangent[2] = 0;
-
- if (Inpf(tangent, tangent) > 0)
+ if (p1->flag == 0)
{
- VECCOPY(t->tsnap.snapTangent, tangent);
+ float vec[3];
+ float new_dist;
+
+ p2 = NULL;
+ p1->flag = 1;
+
+ /* if peeling objects, take the first and last from each object */
+ if (G.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;
+ }
}
-
- VECCOPY(t->tsnap.snapPoint, vec);
- VECCOPY(t->tsnap.snapNormal, no);
-
- t->tsnap.status |= POINT_INIT;
}
- else
+
+ if (dist != FLT_MAX)
{
- t->tsnap.status &= ~POINT_INIT;
+ VECCOPY(loc, p);
+ found = 1;
}
+
+ BLI_freelistN(&depth_peels);
}
- }
- /* Mesh edit mode */
- else if (G.obedit != NULL && G.obedit->type==OB_MESH)
- {
- if (t->spacetype == SPACE_VIEW3D)
+ else
{
- float vec[3];
- float no[3];
- int found = 0;
- int dist = 40; // Use a user defined value here
-
- found = snapObjects(&dist, vec, no, NOT_ACTIVE);
- if (found == 1)
+ if (G.obedit == NULL)
{
- VECCOPY(t->tsnap.snapPoint, vec);
- VECCOPY(t->tsnap.snapNormal, no);
-
- t->tsnap.status |= POINT_INIT;
+ mode = NOT_SELECTED;
}
else
{
- t->tsnap.status &= ~POINT_INIT;
+ mode = NOT_ACTIVE;
}
+
+ found = snapObjects(&dist, loc, no, mode);
}
- else if (t->spacetype == SPACE_IMAGE)
- { /* same as above but for UV's */
- MTFace *nearesttf=NULL;
- float aspx, aspy;
- int face_corner;
+
+ if (found == 1)
+ {
+ float tangent[3];
- find_nearest_uv(&nearesttf, NULL, NULL, &face_corner);
-
- if (nearesttf != NULL)
+ VecSubf(tangent, loc, t->tsnap.snapPoint);
+ tangent[2] = 0;
+
+ if (Inpf(tangent, tangent) > 0)
{
- VECCOPY2D(t->tsnap.snapPoint, nearesttf->uv[face_corner]);
+ VECCOPY(t->tsnap.snapTangent, tangent);
+ }
+
+ VECCOPY(t->tsnap.snapPoint, loc);
+ VECCOPY(t->tsnap.snapNormal, no);
- transform_aspect_ratio_tface_uv(&aspx, &aspy);
- t->tsnap.snapPoint[0] *= aspx;
- t->tsnap.snapPoint[1] *= aspy;
+ t->tsnap.status |= POINT_INIT;
+ }
+ else
+ {
+ t->tsnap.status &= ~POINT_INIT;
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE && G.obedit != NULL && G.obedit->type==OB_MESH)
+ { /* same as above but for UV's */
+ MTFace *nearesttf=NULL;
+ float aspx, aspy;
+ int face_corner;
+
+ find_nearest_uv(&nearesttf, NULL, NULL, &face_corner);
- //Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint);
-
- t->tsnap.status |= POINT_INIT;
- }
- else
- {
- t->tsnap.status &= ~POINT_INIT;
- }
+ if (nearesttf != NULL)
+ {
+ VECCOPY2D(t->tsnap.snapPoint, nearesttf->uv[face_corner]);
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+ t->tsnap.snapPoint[0] *= aspx;
+ t->tsnap.snapPoint[1] *= aspy;
+
+ //Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint);
+
+ t->tsnap.status |= POINT_INIT;
+ }
+ else
+ {
+ t->tsnap.status &= ~POINT_INIT;
}
}
}
@@ -737,6 +818,251 @@ void TargetSnapClosest(TransInfo *t)
}
/*================================================================*/
+int snapFace(float v1co[3], float v2co[3], float v3co[3], float *v4co, short mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
+{
+ float lambda;
+ int result;
+ int retval = 0;
+
+ result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, v1co, v2co, v3co, &lambda, NULL, 0.001);
+
+ if (result) {
+ float location[3], normal[3];
+ float intersect[3];
+ float new_depth;
+ int screen_loc[2];
+ int new_dist;
+
+ VECCOPY(intersect, ray_normal_local);
+ VecMulf(intersect, lambda);
+ VecAddf(intersect, intersect, ray_start_local);
+
+ VECCOPY(location, intersect);
+
+ if (v4co)
+ CalcNormFloat4(v1co, v2co, v3co, v4co, normal);
+ else
+ CalcNormFloat(v1co, v2co, v3co, normal);
+
+ Mat4MulVecfl(obmat, location);
+
+ new_depth = VecLenf(location, ray_start);
+
+ project_int(location, screen_loc);
+ new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]);
+
+ if (new_dist <= *dist && new_depth < *depth)
+ {
+ *depth = new_depth;
+ retval = 1;
+
+ VECCOPY(loc, location);
+ VECCOPY(no, normal);
+
+ Mat3MulVecfl(timat, no);
+ Normalize(no);
+
+ *dist = new_dist;
+ }
+ }
+
+ return retval;
+}
+
+int snapEdge(float v1co[3], short v1no[3], float v2co[3], short v2no[3], short mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
+{
+ float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
+ int result;
+ int retval = 0;
+
+ VECCOPY(ray_end, ray_normal_local);
+ VecMulf(ray_end, 2000);
+ VecAddf(ray_end, ray_start_local, ray_end);
+
+ result = LineIntersectLine(v1co, v2co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */
+
+ if (result)
+ {
+ float edge_loc[3], vec[3];
+ float mul;
+
+ /* check for behind ray_start */
+ VecSubf(dvec, intersect, ray_start_local);
+
+ VecSubf(edge_loc, v1co, v2co);
+ VecSubf(vec, intersect, v2co);
+
+ mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc);
+
+ if (mul > 1) {
+ mul = 1;
+ VECCOPY(intersect, v1co);
+ }
+ else if (mul < 0) {
+ mul = 0;
+ VECCOPY(intersect, v2co);
+ }
+
+ if (Inpf(ray_normal_local, dvec) > 0)
+ {
+ float location[3];
+ float new_depth;
+ int screen_loc[2];
+ int new_dist;
+
+ VECCOPY(location, intersect);
+
+ Mat4MulVecfl(obmat, location);
+
+ new_depth = VecLenf(location, ray_start);
+
+ project_int(location, screen_loc);
+ new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]);
+
+ /* 10% threshold if edge is closer but a bit further
+ * this takes care of series of connected edges a bit slanted w.r.t the viewport
+ * otherwise, it would stick to the verts of the closest edge and not slide along merrily
+ * */
+ if (new_dist <= *dist && new_depth < *depth * 1.001)
+ {
+ float n1[3], n2[3];
+
+ *depth = new_depth;
+ retval = 1;
+
+ VecSubf(edge_loc, v1co, v2co);
+ VecSubf(vec, intersect, v2co);
+
+ mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc);
+
+ if (no)
+ {
+ NormalShortToFloat(n1, v1no);
+ NormalShortToFloat(n2, v2no);
+ VecLerpf(no, n2, n1, mul);
+ Mat3MulVecfl(timat, no);
+ Normalize(no);
+ }
+
+ VECCOPY(loc, location);
+
+ *dist = new_dist;
+ }
+ }
+ }
+
+ return retval;
+}
+
+int snapVertex(float vco[3], short vno[3], short mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
+{
+ int retval = 0;
+ float dvec[3];
+
+ VecSubf(dvec, vco, ray_start_local);
+
+ if (Inpf(ray_normal_local, dvec) > 0)
+ {
+ float location[3];
+ float new_depth;
+ int screen_loc[2];
+ int new_dist;
+
+ VECCOPY(location, vco);
+
+ Mat4MulVecfl(obmat, location);
+
+ new_depth = VecLenf(location, ray_start);
+
+ project_int(location, screen_loc);
+ new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]);
+
+ if (new_dist <= *dist && new_depth < *depth)
+ {
+ *depth = new_depth;
+ retval = 1;
+
+ VECCOPY(loc, location);
+
+ if (no)
+ {
+ NormalShortToFloat(no, vno);
+ Mat3MulVecfl(timat, no);
+ Normalize(no);
+ }
+
+ *dist = new_dist;
+ }
+ }
+
+ return retval;
+}
+
+int snapArmature(Object *ob, bArmature *arm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth, int editarmature)
+{
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ int retval = 0;
+
+ Mat4Invert(imat, obmat);
+
+ VECCOPY(ray_start_local, ray_start);
+ VECCOPY(ray_normal_local, ray_normal);
+
+ Mat4MulVecfl(imat, ray_start_local);
+ Mat4Mul3Vecfl(imat, ray_normal_local);
+
+ if(editarmature)
+ {
+ EditBone *eBone;
+
+ for (eBone=G.edbo.first; eBone; eBone=eBone->next) {
+ if (eBone->layer & arm->layer) {
+ /* skip hidden or moving (selected) bones */
+ if ((eBone->flag & (BONE_HIDDEN_A|BONE_ROOTSEL|BONE_TIPSEL))==0) {
+ switch (G.scene->snap_mode)
+ {
+ case SCE_SNAP_MODE_VERTEX:
+ retval |= snapVertex(eBone->head, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
+ retval |= snapVertex(eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ retval |= snapEdge(eBone->head, NULL, eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (ob->pose && ob->pose->chanbase.first)
+ {
+ bPoseChannel *pchan;
+ Bone *bone;
+
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ /* skip hidden bones */
+ if (bone && !(bone->flag & (BONE_HIDDEN_P|BONE_HIDDEN_PG))) {
+ float *head_vec = pchan->pose_head;
+ float *tail_vec = pchan->pose_tail;
+
+ switch (G.scene->snap_mode)
+ {
+ case SCE_SNAP_MODE_VERTEX:
+ retval |= snapVertex(head_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
+ retval |= snapVertex(tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
+ break;
+ case SCE_SNAP_MODE_EDGE:
+ retval |= snapEdge(head_vec, NULL, tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth, short EditMesh)
{
int retval = 0;
@@ -790,8 +1116,6 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta
for( i = 0; i < totface; i++) {
EditFace *efa = NULL;
MFace *f = faces + i;
- float lambda;
- int result;
test = 1; /* reset for every face */
@@ -824,91 +1148,20 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta
if (test)
{
- result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL);
+ int result;
+ float *v4co = NULL;
- if (result) {
- float location[3], normal[3];
- float intersect[3];
- float new_depth;
- int screen_loc[2];
- int new_dist;
-
- VECCOPY(intersect, ray_normal_local);
- VecMulf(intersect, lambda);
- VecAddf(intersect, intersect, ray_start_local);
-
- VECCOPY(location, intersect);
-
- if (f->v4)
- CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
- else
- CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
-
- Mat4MulVecfl(obmat, location);
-
- new_depth = VecLenf(location, ray_start);
-
- project_int(location, screen_loc);
- new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]);
-
- if (new_dist <= *dist && new_depth < *depth)
- {
- *depth = new_depth;
- retval = 1;
-
- VECCOPY(loc, location);
- VECCOPY(no, normal);
-
- Mat3MulVecfl(timat, no);
- Normalize(no);
-
- *dist = new_dist;
- }
+ if (f->v4)
+ {
+ v4co = verts[f->v4].co;
}
-
+
+ result = snapFace(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, v4co, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
+ retval |= result;
+
if (f->v4 && result == 0)
{
- result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL);
-
- if (result) {
- float location[3], normal[3];
- float intersect[3];
- float new_depth;
- int screen_loc[2];
- int new_dist;
-
- VECCOPY(intersect, ray_normal_local);
- VecMulf(intersect, lambda);
- VecAddf(intersect, intersect, ray_start_local);
-
- VECCOPY(location, intersect);
-
- if (f->v4)
- CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
- else
- CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
-
- Mat4MulVecfl(obmat, location);
-
- new_depth = VecLenf(location, ray_start);
-
- project_int(location, screen_loc);
- new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]);
-
- if (new_dist <= *dist && new_depth < *depth)
- {
- *depth = new_depth;
- retval = 1;
-
- VECCOPY(loc, location);
- VECCOPY(no, normal);
-
- Mat3MulVecfl(timat, no);
- Normalize(no);
-
- *dist = new_dist;
- }
- }
+ retval |= snapFace(verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, verts[f->v2].co, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
}
}
}
@@ -967,40 +1220,7 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta
if (test)
{
- float dvec[3];
-
- VecSubf(dvec, v->co, ray_start_local);
-
- if (Inpf(ray_normal_local, dvec) > 0)
- {
- float location[3];
- float new_depth;
- int screen_loc[2];
- int new_dist;
-
- VECCOPY(location, v->co);
-
- Mat4MulVecfl(obmat, location);
-
- new_depth = VecLenf(location, ray_start);
-
- project_int(location, screen_loc);
- new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]);
-
- if (new_dist <= *dist && new_depth < *depth)
- {
- *depth = new_depth;
- retval = 1;
-
- VECCOPY(loc, location);
-
- NormalShortToFloat(no, v->no);
- Mat3MulVecfl(timat, no);
- Normalize(no);
-
- *dist = new_dist;
- }
- }
+ retval |= snapVertex(v->co, v->no, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
}
}
@@ -1060,79 +1280,7 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta
if (test)
{
- float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
- int result;
-
- VECCOPY(ray_end, ray_normal_local);
- VecMulf(ray_end, 2000);
- VecAddf(ray_end, ray_start_local, ray_end);
-
- result = LineIntersectLine(verts[e->v1].co, verts[e->v2].co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */
-
- if (result)
- {
- float edge_loc[3], vec[3];
- float mul;
-
- /* check for behind ray_start */
- VecSubf(dvec, intersect, ray_start_local);
-
- VecSubf(edge_loc, verts[e->v1].co, verts[e->v2].co);
- VecSubf(vec, intersect, verts[e->v2].co);
-
- mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc);
-
- if (mul > 1) {
- mul = 1;
- VECCOPY(intersect, verts[e->v1].co);
- }
- else if (mul < 0) {
- mul = 0;
- VECCOPY(intersect, verts[e->v2].co);
- }
-
- if (Inpf(ray_normal_local, dvec) > 0)
- {
- float location[3];
- float new_depth;
- int screen_loc[2];
- int new_dist;
-
- VECCOPY(location, intersect);
-
- Mat4MulVecfl(obmat, location);
-
- new_depth = VecLenf(location, ray_start);
-
- project_int(location, screen_loc);
- new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]);
-
- if (new_dist <= *dist && new_depth < *depth)
- {
- float n1[3], n2[3];
-
- *depth = new_depth;
- retval = 1;
-
- VecSubf(edge_loc, verts[e->v1].co, verts[e->v2].co);
- VecSubf(vec, intersect, verts[e->v2].co);
-
- mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc);
-
- NormalShortToFloat(n1, verts[e->v1].no);
- NormalShortToFloat(n2, verts[e->v2].no);
- VecLerpf(no, n2, n1, mul);
- Normalize(no);
-
- VECCOPY(loc, location);
-
- Mat3MulVecfl(timat, no);
- Normalize(no);
-
- *dist = new_dist;
- }
- }
- }
+ retval |= snapEdge(verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
}
}
@@ -1149,7 +1297,41 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta
return retval;
}
-int snapObjects(int *dist, float *loc, float *no, int mode) {
+int snapObject(Object *ob, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth)
+{
+ int editobject = 0;
+ int retval = 0;
+
+ if (ob == G.obedit)
+ {
+ editobject = 1;
+ }
+
+ if (ob->type == OB_MESH) {
+ DerivedMesh *dm;
+
+ if (editobject)
+ {
+ dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+ }
+ else
+ {
+ dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ }
+
+ retval = snapDerivedMesh(ob, dm, obmat, ray_start, ray_normal, mval, loc, no, dist, depth, editobject);
+
+ dm->release(dm);
+ }
+ else if (ob->type == OB_ARMATURE)
+ {
+ retval = snapArmature(ob, ob->data, obmat, ray_start, ray_normal, mval, loc, no, dist, depth, editobject);
+ }
+
+ return retval;
+}
+
+int snapObjects(int *dist, float *loc, float *no, SnapMode mode) {
Base *base;
float depth = FLT_MAX;
int retval = 0;
@@ -1161,19 +1343,214 @@ int snapObjects(int *dist, float *loc, float *no, int mode) {
if (mode == NOT_ACTIVE)
{
- DerivedMesh *dm;
Object *ob = G.obedit;
- dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+ retval |= snapObject(ob, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
+ }
+
+ base= FIRSTBASE;
+ for ( base = FIRSTBASE; base != NULL; base = base->next ) {
+ if ( BASE_SELECTABLE(base) && (base->flag & (BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA)) == 0 && ((mode == NOT_SELECTED && (base->flag & (SELECT|BA_WAS_SEL)) == 0) || (mode == NOT_ACTIVE && base != BASACT)) ) {
+ Object *ob = base->object;
+
+ if (ob->transflag & OB_DUPLI)
+ {
+ DupliObject *dupli_ob;
+ ListBase *lb = object_duplilist(G.scene, ob);
+
+ for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
+ {
+ Object *ob = dupli_ob->ob;
+
+ retval |= snapObject(ob, dupli_ob->mat, ray_start, ray_normal, mval, loc, no, dist, &depth);
+ }
+
+ free_object_duplilist(lb);
+ }
+
+ retval |= snapObject(ob, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
+ }
+ }
+
+ return retval;
+}
+
+/******************** PEELING *********************************/
+
+
+int cmpPeel(void *arg1, void *arg2)
+{
+ DepthPeel *p1 = arg1;
+ DepthPeel *p2 = arg2;
+ int val = 0;
+
+ if (p1->depth < p2->depth)
+ {
+ val = -1;
+ }
+ else if (p1->depth > p2->depth)
+ {
+ val = 1;
+ }
+
+ return val;
+}
+
+void removeDoublesPeel(ListBase *depth_peels)
+{
+ DepthPeel *peel;
+
+ for (peel = depth_peels->first; peel; peel = peel->next)
+ {
+ DepthPeel *next_peel = peel->next;
- retval = snapDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth, 1);
+ if (peel && next_peel && ABS(peel->depth - next_peel->depth) < 0.0015)
+ {
+ peel->next = next_peel->next;
+
+ if (next_peel->next)
+ {
+ next_peel->next->prev = peel;
+ }
+
+ MEM_freeN(next_peel);
+ }
+ }
+}
+
+void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
+{
+ DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel");
+
+ peel->depth = depth;
+ peel->ob = ob;
+ VECCOPY(peel->p, p);
+ VECCOPY(peel->no, no);
+
+ BLI_addtail(depth_peels, peel);
+
+ peel->flag = 0;
+}
+
+int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], ListBase *depth_peels)
+{
+ int retval = 0;
+ int totvert = dm->getNumVerts(dm);
+ int totface = dm->getNumFaces(dm);
+
+ if (totvert > 0) {
+ float imat[4][4];
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ float ray_start_local[3], ray_normal_local[3];
+ int test = 1;
+
+ Mat4Invert(imat, obmat);
+
+ Mat3CpyMat4(timat, imat);
+ Mat3Transp(timat);
- dm->release(dm);
+ VECCOPY(ray_start_local, ray_start);
+ VECCOPY(ray_normal_local, ray_normal);
+
+ Mat4MulVecfl(imat, ray_start_local);
+ Mat4Mul3Vecfl(imat, ray_normal_local);
+
+
+ /* If number of vert is more than an arbitrary limit,
+ * test against boundbox first
+ * */
+ if (totface > 16) {
+ struct BoundBox *bb = object_get_boundbox(ob);
+ test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
+ }
+
+ if (test == 1) {
+ MVert *verts = dm->getVertArray(dm);
+ MFace *faces = dm->getFaceArray(dm);
+ int i;
+
+ for( i = 0; i < totface; i++) {
+ MFace *f = faces + i;
+ float lambda;
+ int result;
+
+
+ result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL, 0.001);
+
+ if (result) {
+ float location[3], normal[3];
+ float intersect[3];
+ float new_depth;
+
+ VECCOPY(intersect, ray_normal_local);
+ VecMulf(intersect, lambda);
+ VecAddf(intersect, intersect, ray_start_local);
+
+ VECCOPY(location, intersect);
+
+ if (f->v4)
+ CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
+ else
+ CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
+
+ Mat4MulVecfl(obmat, location);
+
+ new_depth = VecLenf(location, ray_start);
+
+ Mat3MulVecfl(timat, normal);
+ Normalize(normal);
+
+ addDepthPeel(depth_peels, new_depth, location, normal, ob);
+ }
+
+ if (f->v4 && result == 0)
+ {
+ result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL, 0.001);
+
+ if (result) {
+ float location[3], normal[3];
+ float intersect[3];
+ float new_depth;
+
+ VECCOPY(intersect, ray_normal_local);
+ VecMulf(intersect, lambda);
+ VecAddf(intersect, intersect, ray_start_local);
+
+ VECCOPY(location, intersect);
+
+ if (f->v4)
+ CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
+ else
+ CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
+
+ Mat4MulVecfl(obmat, location);
+
+ new_depth = VecLenf(location, ray_start);
+
+ Mat3MulVecfl(timat, normal);
+ Normalize(normal);
+
+ addDepthPeel(depth_peels, new_depth, location, normal, ob);
+ }
+ }
+ }
+ }
}
+
+ return retval;
+}
+
+int peelObjects(ListBase *depth_peels, short mval[2])
+{
+ Base *base;
+ int retval = 0;
+ float ray_start[3], ray_normal[3];
+ viewray(mval, ray_start, ray_normal);
+
base= FIRSTBASE;
for ( base = FIRSTBASE; base != NULL; base = base->next ) {
- if ( BASE_SELECTABLE(base) && (base->flag & (BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA)) == 0 && ((mode == NOT_SELECTED && (base->flag & (SELECT|BA_WAS_SEL)) == 0) || (mode == NOT_ACTIVE && base != BASACT)) ) {
+ if ( BASE_SELECTABLE(base) ) {
Object *ob = base->object;
if (ob->transflag & OB_DUPLI)
@@ -1186,21 +1563,10 @@ int snapObjects(int *dist, float *loc, float *no, int mode) {
Object *ob = dupli_ob->ob;
if (ob->type == OB_MESH) {
- DerivedMesh *dm;
- int editmesh = 0;
+ DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
int val;
- if (ob == G.obedit)
- {
- dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
- editmesh = 1;
- }
- else
- {
- dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
- }
-
- val = snapDerivedMesh(ob, dm, dupli_ob->mat, ray_start, ray_normal, mval, loc, no, dist, &depth, editmesh);
+ val = peelDerivedMesh(ob, dm, dupli_ob->mat, ray_start, ray_normal, mval, depth_peels);
retval = retval || val;
@@ -1212,11 +1578,22 @@ int snapObjects(int *dist, float *loc, float *no, int mode) {
}
if (ob->type == OB_MESH) {
- DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ DerivedMesh *dm = NULL;
int val;
-
- val = snapDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth, 0);
-
+
+ if (ob != G.obedit)
+ {
+ dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+
+ val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+ }
+ else
+ {
+ dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+ }
+
retval = retval || val;
dm->release(dm);
@@ -1224,6 +1601,9 @@ int snapObjects(int *dist, float *loc, float *no, int mode) {
}
}
+ BLI_sortlist(depth_peels, cmpPeel);
+ removeDoublesPeel(depth_peels);
+
return retval;
}
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
index 6a4c72d1d4b..da331ea2df2 100644
--- a/source/blender/src/usiblender.c
+++ b/source/blender/src/usiblender.c
@@ -1109,6 +1109,8 @@ void exit_usiblender(void)
BIF_GlobalReebFree();
BIF_freeRetarget();
+ BIF_freeTemplates();
+ BIF_freeSketch();
tf= G.ttfdata.first;
while(tf)
diff --git a/source/blender/src/view.c b/source/blender/src/view.c
index 0ce1512e2de..128f95715a8 100644
--- a/source/blender/src/view.c
+++ b/source/blender/src/view.c
@@ -75,6 +75,7 @@
#include "BIF_space.h"
#include "BIF_screen.h"
#include "BIF_toolbox.h"
+#include "BIF_sketch.h"
#include "BSE_view.h"
#include "BSE_edit.h" /* For countall */
@@ -83,6 +84,7 @@
#include "BDR_drawobject.h" /* For draw_object */
#include "BDR_editface.h" /* For minmax_tface */
#include "BDR_sculptmode.h"
+#include "BDR_sketch.h"
#include "mydevice.h"
#include "blendef.h"
@@ -1907,7 +1909,14 @@ short view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1
draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
}
else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
- draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
+ if (BIF_fullSketchMode())
+ {
+ BDR_drawSketchNames();
+ }
+ else
+ {
+ draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
+ }
}
else {
Base *base;