diff options
Diffstat (limited to 'source/blender')
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; |