struct MemFile;
#define BLENDER_VERSION 248
-#define BLENDER_SUBVERSION 1
+#define BLENDER_SUBVERSION 2
#define BLENDER_MINVERSION 245
#define BLENDER_MINSUBVERSION 15
/* confusing... G.f and G.flags */
int flags;
-
} Global;
/* **************** GLOBAL ********************* */
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;
}
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 SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, float v0[3], float v1[3], float v2[3], float *lambda, float *ipoint);
}
}
+/* 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] &&
BNode *node;
BArc *arc;
+ if (root_node == NULL)
+ {
+ return;
+ }
+
if (BLI_isGraphCyclic(graph))
{
return;
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];
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;
}
}
+ if (main->versionfile < 248 || main->subversionfile < 2)
+ {
+ Scene *sce;
+
+ /* initialize skeleton generation toolsettings */
+ for(sce=main->scene.first; sce; sce = sce->id.next)
+ {
+ 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_options |= SK_RETARGET_ROLL;
+ }
+ }
+
+
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
--- /dev/null
+/**
+ * $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 */
} 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);
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);
--- /dev/null
+/**
+ * $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 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 */
+
+ 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_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];
+ EditBone *bone;
+ EditBone *link;
+ 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);
+
+#endif /* BIF_RETARGET_H */
--- /dev/null
+/**
+ * $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);
+
+#endif /* BIF_SKETCH_H */
#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
float val;
int nv;
float p[3];
+ float no[3]; /* if non-null, normal of the bucket */
} EmbedBucket;
typedef struct ReebNode {
int symmetry_flag;
float symmetry_axis[3];
/*********************************/
+
+ float no[3];
int index;
float weight;
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();
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_side_string[8];
+ char skgen_num_string[8];
/* Alt+RMB option */
char edge_mode;
+ char pad3[3];
} ToolSettings;
/* Used by all brushes to store their properties, which can be directly set
#define SKGEN_AVERAGE 1
#define SKGEN_SHARPEN 2
+/* toolsettings->bone_sketching */
+#define BONE_SKETCHING 1
+#define BONE_SKETCHING_QUICK 2
+
+/* toolsettings->bone_sketching_convert */
+#define SK_CONVERT_CUT_FIXED 1
+#define SK_CONVERT_CUT_LENGTH 2
+#define SK_CONVERT_CUT_CORRELATION 3
+#define SK_CONVERT_RETARGET 4
+
+/* toolsettings->skgen_retarget_options */
+#define SK_RETARGET_ROLL 1
+#define SK_RETARGET_AUTONAME 2
+
+
#ifdef __cplusplus
}
#endif
//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;
//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;
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)
#include "BIF_resources.h"
#include "BIF_retopo.h"
#include "BIF_screen.h"
+#include "BIF_sketch.h"
#include "BIF_space.h"
#ifdef WITH_VERSE
#include "BDR_vpaint.h"
#include "BDR_sculptmode.h"
#include "BDR_gpencil.h"
+#include "BDR_sketch.h"
#include "BSE_drawview.h"
#include "BSE_filesel.h"
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;
+ uiBlock *block;
+ uiBut *but;
+ int yco = 70, height = 140;
+// int index;
+
+ /* replace with check call to sketching lib */
+ if (G.obedit && G.obedit->type == OB_ARMATURE)
+ {
+ 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, 130, 20, &G.scene->toolsettings->bone_sketching, 0, 0, 0, 0, "Use sketching to create and edit bones");
+ uiDefButBitC(block, TOG, BONE_SKETCHING_QUICK, B_REDR, "Q", 140, 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,150,20, 0, 0, 0, 0, 0, "Convert sketch to armature");
+ uiButSetFunc(but, convert_sketch_armature, NULL, NULL);
+ yco -= 20;
+
+ but = uiDefBut(block, BUT, B_REDR, "Delete", 10,yco,150,20, 0, 0, 0, 0, 0, "Delete sketch");
+ uiButSetFunc(but, delete_sketch_armature, NULL, NULL);
+ yco -= 20;
+
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+
+ uiDefButC(block, ROW, B_REDR, "Length", 10, yco, 60, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_CUT_LENGTH, 0, 0, "Subdivide arcs in bones of equal length");
+ uiDefButF(block, NUM, B_REDR, "L:", 70, yco, 90, 19, &G.scene->toolsettings->skgen_length_limit,0.1,50.0, 10, 0, "Maximum length of the subdivided bones");
+ yco -= 20;
+
+ uiDefButC(block, ROW, B_REDR, "Correlation", 10, yco, 60, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_CUT_CORRELATION, 0, 0, "Subdivide arcs based on correlation");
+ uiDefButF(block, NUM, B_REDR, "T:", 70, yco, 90, 19, &G.scene->toolsettings->skgen_correlation_limit,0.0, 1.0, 0.01, 0, "Correlation threshold for subdivision");
+ yco -= 20;
+
+ uiDefButC(block, ROW, B_REDR, "Fixed", 10, yco, 60, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_CUT_FIXED, 0, 0, "Subdivide arcs based on a fixed number of bones");
+ uiDefButC(block, NUM, B_REDR, "N:", 70, yco, 90, 19, &G.scene->toolsettings->skgen_subdivision_number,1, 100, 1, 5, "Number of subdivided bones");
+ yco -= 20;
+
+ uiDefButC(block, ROW, B_REDR, "Retarget", 10, yco,80, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_RETARGET, 0, 0, "Retarget selected bones to stroke");
+ uiDefButBitC(block, TOG, SK_RETARGET_ROLL, B_DIFF, "Roll", 90, yco, 70,19, &G.scene->toolsettings->skgen_retarget_options, 0, 0, 0, 0, "Roll bones perpendicular to view");
+ /* button here to select what to do (copy or not), template, ...*/
+ yco -= 20;
+
+ uiBlockEndAlign(block);
+
+ yco -= 10;
+ uiBlockBeginAlign(block);
+
+ BIF_makeListTemplates();
+ template_index = BIF_currentTemplate();
+
+ but = uiDefButI(block, MENU, B_REDR, BIF_listTemplates(), 10,yco,150,19, &template_index, 0, 0, 0, 0, "Template");
+ uiButSetFunc(but, assign_template_sketch_armature, &template_index, NULL);
+
+ yco -= 20;
+
+ uiDefButF(block, NUM, B_DIFF, "Ang:", 10, yco, 50,19, &G.scene->toolsettings->skgen_retarget_angle_weight, 0, 10, 1, 0, "Angle Weight");
+ uiDefButF(block, NUM, B_DIFF, "Len:", 60, yco, 50,19, &G.scene->toolsettings->skgen_retarget_length_weight, 0, 10, 1, 0, "Length Weight");
+ uiDefButF(block, NUM, B_DIFF, "Dist:", 110,yco, 50,19, &G.scene->toolsettings->skgen_retarget_distance_weight, 0, 10, 1, 0, "Distance Weight");
+ yco -= 20;
+
+ uiDefBut(block, TEX,0,"S:", 10, yco, 65, 20, G.scene->toolsettings->skgen_side_string, 0.0, 8.0, 0, 0, "Text to replace %S with");
+ uiDefBut(block, TEX,0,"N:", 75, yco, 65, 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,140,yco,20,20, &G.scene->toolsettings->skgen_retarget_options, 0, 0, 0, 0, "Use Auto Naming");
+
+ /* auto renaming magic */
+
+ uiBlockEndAlign(block);
+
+ if(yco < 0) uiNewPanelHeight(block, height-yco);
+ }
+}
static void view3d_panel_object(short cntrl) // VIEW3D_HANDLER_OBJECT
{
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;
/* draw grease-pencil stuff */
if (v3d->flag2 & V3D_DISPGP)
draw_gpencil_3dview(sa, 1);
+
+ BDR_drawSketch();
persp(PERSP_WIN); // set ortho
#include "BIF_space.h"
#include "BIF_screen.h"
#include "BIF_toolbox.h"
+#include "BIF_sketch.h"
#ifdef WITH_VERSE
#include "BIF_verse.h"
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();
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 */
{
/* **************** 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;
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];
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;
}
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
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
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);
}
}
}
+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)
{
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) {
}
}
}
+
/* Find the selected bones and duplicate them as needed */
for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) {
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;
*/
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 {
/* Lets try to fix any constraint subtargets that might
have been duplicated */
- update_dup_subtarget(eBone);
+ updateDuplicateSubtarget(eBone, &G.edbo, OBACT);
}
}
}
}
/* 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])) {
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);
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) {
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;
#include "BKE_armature.h"
#include "BIF_editarmature.h"
+#include "BIF_retarget.h"
#include "BIF_space.h"
+#include "BIF_toolbox.h"
#include "PIL_time.h"
/************ 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;
typedef enum
{
METHOD_BRUTE_FORCE = 0,
- METHOD_MEMOIZE = 1,
- METHOD_ANNEALING = 2
+ METHOD_MEMOIZE = 1
} RetargetMethod;
typedef enum
ARC_USED = 2
} ArcUsageFlags;
-
RigGraph *GLOBAL_RIGG = NULL;
/*******************************************************************************************************/
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);
+
+ Normalize(new_up_axis);
+ Normalize(x_axis);
+ Normalize(z_axis);
- roll = NormalizedVecAngle2(new_up_axis, up_axis);
+ if (Inpf(new_up_axis, x_axis) < 0)
+ {
+ VecMulf(x_axis, -1);
+ }
- Crossf(vec, up_axis, new_up_axis);
+ if (Inpf(new_up_axis, z_axis) < 0)
+ {
+ VecMulf(z_axis, -1);
+ }
- if (Inpf(vec, nor) < 0)
+ if (NormalizedVecAngle2(x_axis, new_up_axis) < NormalizedVecAngle2(z_axis, new_up_axis))
{
- roll = -roll;
+ 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 rollBoneByQuat(EditBone *bone, float old_up_axis[3], float quat[4])
+{
+ float new_up_axis[3];
+
+ VECCOPY(new_up_axis, old_up_axis);
+ QuatMulVecf(quat, new_up_axis);
+
+ Normalize(new_up_axis);
- return roll;
+ return rollBoneToVector(bone, new_up_axis);
}
/************************************ DESTRUCTORS ******************************************************/
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)
{
}
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);
}
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')
+ {
+ j += sprintf(name + j, side_string);
+ i++;
+ }
+ else if (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;
+
+ 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);
+
+ bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent);
+
+ if (bone != NULL)
+ {
+ edge->bone->parent = bone;
+ }
+ }
+ }
+ }
+
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
+ {
+ EditBone *bone;
+
+ updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob);
+
+ bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent);
+
+ if (bone != NULL)
+ {
+ ctrl->bone->parent = bone;
+ }
+
+ 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;
+}
+
/*******************************************************************************************************/
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);
}
{
change = 0;
- printf("-------------------------\n");
-
for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
{
/* if control is not linked yet */
/* 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;
/* 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;
}
/* 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;
}
}
}
-
}
+
+ /* 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)
+ {
+ printf("%s -> %s: TL_HEAD\n", ctrl->bone->name, bone->name);
+ ctrl->tail_mode = TL_HEAD;
+ ctrl->link_tail = bone;
+ break;
+ }
+ else if (VecLenf(ctrl->bone->tail, bone->tail) < 0.01)
+ {
+ printf("%s -> %s: TL_TAIL\n", ctrl->bone->name, bone->name);
+ 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)
+ {
+ }
+ }
+ else
+ {
+ printf("%s FIT\n", ctrl->bone->name);
+ }
+ }
+
}
/*******************************************************************************************************/
}
}
-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;
{
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)
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 */
/*******************************************************************************************************/
-static RigGraph *armatureToGraph(Object *ob, bArmature *arm)
+RigGraph *armatureToGraph(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);
}
}
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)
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);
int total = 0;
int boneStart = iter.start;
- parent = add_editbonetolist("Bone", &rigg->editbones);
+ parent = add_editbonetolist("Bone", rigg->editbones);
parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
VECCOPY(parent->head, head->p);
{
VECCOPY(parent->tail, btail);
- child = add_editbonetolist("Bone", &rigg->editbones);
+ child = add_editbonetolist("Bone", rigg->editbones);
VECCOPY(child->head, parent->tail);
child->parent = parent;
child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
/************************************ RETARGETTING *****************************************************/
-static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize)
+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)
{
- 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);
+ if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE)
+ {
+ RigControl *ctrl_child;
+
+ /* 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)
+{
+ float parent_offset[3], tail_offset[3];
+ 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;
RotationBetweenVectorsToQuat(qrot, v1, v2);
+ VECCOPY(bone->head, vec0);
+ VECCOPY(bone->tail, vec1);
+
+ if (!VecIsNull(up_axis))
+ {
+ float qroll[4];
+
+ bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis);
+
+ 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);
}
#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;
}
#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)
{
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;
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)
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))
{
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;
/* 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;
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);
edge;
edge = edge->next, i++)
{
+ float *no = NULL;
if (i < nb_joints)
{
bucket = peekBucket(&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)
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)
bucket = nextBucket(&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;
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
}
}
+static void finishRetarget(RigGraph *rigg)
+{
+#ifdef USE_THREADS
+ BLI_end_worker(rigg->worker);
+#endif
+}
+
static void adjustGraphs(RigGraph *rigg)
{
RigArc *arc;
}
}
-#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");
}
//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);
}
allqueue(REDRAWVIEW3D, 0);
}
+void BIF_retargetArc(ReebArc *earc)
+{
+ Object *ob;
+ RigGraph *template_rigg;
+ RigGraph *rigg;
+ RigArc *iarc;
+ bArmature *arm;
+
+ if (G.scene->toolsettings->skgen_template &&
+ G.scene->toolsettings->skgen_template->type == OB_ARMATURE)
+ {
+ ob = G.scene->toolsettings->skgen_template;
+ arm = ob->data;
+ template_rigg = armatureToGraph(ob, arm);
+ }
+ 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);
+
+ RIG_freeRigGraph((BGraph*)template_rigg);
+ RIG_freeRigGraph((BGraph*)rigg);
+
+ BIF_undo_push("Retarget Arc");
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
void BIF_adjustRetarget()
{
if (GLOBAL_RIGG)
--- /dev/null
+/**
+ * $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 "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 "blendef.h"
+#include "mydevice.h"
+#include "reeb.h"
+
+typedef enum SK_PType
+{
+ PT_CONTINUOUS,
+ PT_EXACT,
+} SK_PType;
+
+typedef enum SK_PMode
+{
+ PT_EMBED,
+ 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_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];
+} SK_Intersection;
+
+typedef struct SK_Sketch
+{
+ ListBase strokes;
+ SK_Stroke *active_stroke;
+ SK_Stroke *gesture;
+ SK_Point next_point;
+} SK_Sketch;
+
+SK_Sketch *GLOBAL_sketch = NULL;
+SK_Point boneSnap;
+
+#define SNAP_MIN_DISTANCE 12
+
+/******************** PROTOTYPES ******************************/
+
+typedef int(NextSubdivisionFunc)(SK_Stroke*, int, int, float[3], float[3]);
+
+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 nextFixedSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
+int nextLengthSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
+int nextCorrelationSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
+
+/******************** TEMPLATES UTILS *************************/
+
+char *TEMPLATES_MENU = NULL;
+int TEMPLATES_CURRENT = 0;
+GHash *TEMPLATES_HASH = 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;
+ int index = 0;
+ BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
+
+ while (!BLI_ghashIterator_isDone(&ghi))
+ {
+ Object *ob = BLI_ghashIterator_getValue(&ghi);
+ int key = (int)BLI_ghashIterator_getKey(&ghi);
+
+ index++;
+
+ if (ob == G.scene->toolsettings->skgen_template)
+ {
+ TEMPLATES_CURRENT = index;
+ break;
+ }
+
+ BLI_ghashIterator_step(&ghi);
+ }
+ }
+
+ return TEMPLATES_CURRENT;
+}
+
+void BIF_freeTemplates()
+{
+ if (TEMPLATES_MENU != NULL)
+ {
+ MEM_freeN(TEMPLATES_MENU);
+ }
+
+ if (TEMPLATES_HASH != NULL)
+ {
+ BLI_ghash_free(TEMPLATES_HASH, NULL, 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;
+ }
+}
+
+/******************** PEELING *********************************/
+
+typedef struct SK_DepthPeel
+{
+ struct SK_DepthPeel *next, *prev;
+
+ float depth;
+ float p[3];
+ float no[3];
+ Object *ob;
+ int flag;
+} SK_DepthPeel;
+
+int cmpPeel(void *arg1, void *arg2)
+{
+ SK_DepthPeel *p1 = arg1;
+ SK_DepthPeel *p2 = arg2;
+ int val = 0;
+
+ if (p1->depth < p2->depth)
+ {
+ val = -1;
+ }
+ else if (p1->depth > p2->depth)
+ {
+ val = 1;
+ }
+
+ return val;
+}
+
+void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
+{
+ SK_DepthPeel *peel = MEM_callocN(sizeof(SK_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);
+
+ 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 = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL);
+
+ 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 = 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;
+
+ 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) ) {
+ 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;
+
+ if (ob->type == OB_MESH) {
+ DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ int val;
+
+ val = peelDerivedMesh(ob, dm, dupli_ob->mat, ray_start, ray_normal, mval, depth_peels);
+
+ retval = retval || val;
+
+ dm->release(dm);
+ }
+ }
+
+ free_object_duplilist(lb);
+ }
+
+ if (ob->type == OB_MESH) {
+ DerivedMesh *dm = NULL;
+ int val;
+
+ 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);
+ }
+ }
+ }
+
+ BLI_sortlist(depth_peels, cmpPeel);
+
+ return retval;
+}
+/*********************** 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);
+
+ if (G.scene->toolsettings->skgen_retarget_options & SK_RETARGET_ROLL)
+ {
+ 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);
+
+ if (G.scene->toolsettings->skgen_retarget_options & SK_RETARGET_ROLL)
+ {
+ 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;
+
+ Mat4Invert(imat, G.obedit->obmat);
+
+ Mat3CpyMat4(tmat, G.obedit->obmat);
+ Mat3Transp(tmat);
+
+ arc = sk_strokeToArc(stk, imat, tmat);
+
+ sk_autoname(arc);
+
+ BIF_retargetArc(arc);
+
+ 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_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_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_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_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;
+
+ 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])
+{
+ 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++)
+ {
+ 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(SK_Stroke *stk, int start, int end, NextSubdivisionFunc next_subdividion)
+{
+ float head[3], tail[3];
+ int bone_start = start;
+ int index;
+
+ VECCOPY(head, stk->points[start].p);
+
+ glColor3f(0, 1, 1);
+ glBegin(GL_POINTS);
+
+ index = next_subdividion(stk, 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(stk, bone_start, end, head, tail);
+ }
+
+ glEnd();
+}
+
+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)
+ {
+ if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_CORRELATION)
+ {
+ drawSubdividedStrokeBy(stk, head_index, i, nextCorrelationSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
+ {
+ drawSubdividedStrokeBy(stk, head_index, i, nextLengthSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
+ {
+ drawSubdividedStrokeBy(stk, head_index, i, nextFixedSubdivision);
+ }
+
+ }
+
+ head_index = i;
+ }
+ }
+ }
+}
+
+SK_Point *sk_snapPointStroke(SK_Stroke *stk, short mval[2], int *dist)
+{
+ SK_Point *pt = NULL;
+ int i;
+
+ for (i = 0; i < stk->nb_points; i++)
+ {
+ if (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;
+ }
+ }
+ }
+
+ 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_startStroke(SK_Sketch *sketch)
+{
+ SK_Stroke *stk = sk_createStroke();
+
+ BLI_addtail(&sketch->strokes, stk);
+ sketch->active_stroke = stk;
+}
+
+void sk_endStroke(SK_Sketch *sketch)
+{
+ sk_shrinkStrokeBuffer(sketch->active_stroke);
+ 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 *source_stk, SK_DrawData *dd)
+{
+ SK_Stroke *stk;
+ int dist = SNAP_MIN_DISTANCE;
+ int point_added = 0;
+
+ for (stk = sketch->strokes.first; stk; stk = stk->next)
+ {
+ SK_Point *spt = sk_snapPointStroke(stk, dd->mval, &dist);
+
+ if (spt != NULL)
+ {
+ VECCOPY(pt->p, spt->p);
+ point_added = 1;
+ }
+ }
+
+ /* check on bones */
+ {
+ SK_Point *spt = sk_snapPointArmature(G.obedit, &G.edbo, dd->mval, &dist);
+
+ if (spt != NULL)
+ {
+ VECCOPY(pt->p, spt->p);
+ point_added = 1;
+ }
+ }
+
+ if (point_added)
+ {
+ pt->type = PT_EXACT;
+ pt->mode = PT_SNAP;
+ }
+
+ return point_added;
+}
+
+int sk_addStrokeSnapPoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+ int point_added = 0;
+ SK_Point pt;
+
+ sk_initPoint(&pt);
+
+ point_added = sk_getStrokeSnapPoint(&pt, sketch, stk, dd);
+
+ if (point_added)
+ {
+ float final_p[3];
+ float distance;
+ float length;
+ int i, total;
+
+ 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].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);
+ }
+
+ return point_added;
+}
+
+int sk_getStrokeEmbedPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+ ListBase depth_peels;
+ SK_DepthPeel *p1, *p2;
+ SK_Point *last_pt = NULL;
+ float dist = FLT_MAX;
+ float p[3];
+ int point_added = 0;
+
+ 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_pt = stk->points + (stk->nb_points - 1);
+ }
+
+
+ for (p1 = depth_peels.first; p1; p1 = p1->next)
+ {
+ if (p1->flag == 0)
+ {
+ float vec[3];
+ float new_dist;
+
+ p1->flag = 0;
+
+ 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_pt == NULL)
+ {
+ VECCOPY(p, vec);
+ dist = 0;
+ break;
+ }
+
+ new_dist = VecLenf(last_pt->p, vec);
+
+ if (new_dist < dist)
+ {
+ VECCOPY(p, vec);
+ dist = new_dist;
+ }
+ }
+ }
+
+ if (dist != FLT_MAX)
+ {
+ pt->type = dd->type;
+ pt->mode = PT_EMBED;
+ VECCOPY(pt->p, p);
+
+ point_added = 1;
+ }
+
+ BLI_freelistN(&depth_peels);
+
+ return point_added;
+}
+
+int sk_addStrokeEmbedPoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+ int point_added;
+ SK_Point pt;
+
+ sk_initPoint(&pt);
+
+ point_added = sk_getStrokeEmbedPoint(&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_EMBED || 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 && qual & LR_SHIFTKEY)
+ {
+ point_added = sk_addStrokeEmbedPoint(sketch, stk, dd);
+ }
+
+ if (point_added == 0)
+ {
+ point_added = sk_addStrokeDrawPoint(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);
+ }
+
+ if (point_added == 0 && qual & LR_SHIFTKEY)
+ {
+ point_added = sk_getStrokeEmbedPoint(pt, sketch, stk, dd);
+ }
+
+ 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 (dd->mval[0] != dd->previous_mval[0] || dd->mval[1] != dd->previous_mval[1])
+ {
+ 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;
+}
+/********************************************/
+
+/* bone is assumed to be in GLOBAL space */
+void setBoneRollFromPoint(EditBone *bone, SK_Point *pt, float invmat[][4], float tmat[][3])
+{
+ float tangent[3], cotangent[3], normal[3];
+
+ VecSubf(tangent, bone->tail, bone->head);
+ Crossf(cotangent, tangent, pt->no);
+ Crossf(normal, cotangent, tangent);
+
+ Mat3MulVecfl(tmat, normal);
+ Normalize(normal);
+
+ bone->roll = rollBoneToVector(bone, normal);
+
+}
+
+float calcStrokeCorrelation(SK_Stroke *stk, 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];
+
+ VecSubf(v, stk->points[i].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;
+
+ VecSubf(v, stk->points[i].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(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+{
+ static float stroke_length = 0;
+ static float current_length;
+ static char n;
+ float length_threshold;
+ int i;
+
+ if (stroke_length == 0)
+ {
+ current_length = 0;
+ for (i = start + 1; i <= end; i++)
+ {
+ stroke_length += VecLenf(stk->points[i].p, stk->points[i - 1].p);
+ }
+
+ n = 0;
+ current_length = 0;
+ }
+
+ n++;
+
+ length_threshold = n * stroke_length / G.scene->toolsettings->skgen_subdivision_number;
+
+ /* < and not <= because we don't care about end, it is P_EXACT anyway */
+ for (i = start + 1; i < end; i++)
+ {
+ current_length += VecLenf(stk->points[i].p, stk->points[i - 1].p);
+
+ if (current_length >= length_threshold)
+ {
+ VECCOPY(p, stk->points[i].p);
+ return i;
+ }
+ }
+
+ stroke_length = 0;
+
+ return -1;
+}
+int nextCorrelationSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+{
+ float correlation_threshold = G.scene->toolsettings->skgen_correlation_limit;
+ float n[3];
+ int i;
+
+ for (i = start + 2; i <= end; i++)
+ {
+ /* Calculate normal */
+ VecSubf(n, stk->points[i].p, head);
+
+ if (calcStrokeCorrelation(stk, start, i, stk->points[start].p, n) < correlation_threshold)
+ {
+ VECCOPY(p, stk->points[i - 1].p);
+ return i - 1;
+ }
+ }
+
+ return -1;
+}
+
+int nextLengthSubdivision(SK_Stroke *stk, 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 = stk->points[i - 1].p;
+ float *vec1 = stk->points[i].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 * subdivideStrokeBy(SK_Stroke *stk, int start, int end, float invmat[][4], float tmat[][3], NextSubdivisionFunc next_subdividion)
+{
+ bArmature *arm = G.obedit->data;
+ EditBone *lastBone = NULL;
+ EditBone *child = NULL;
+ EditBone *parent = NULL;
+ int bone_start = start;
+ int index;
+
+ parent = addEditBone("Bone", &G.edbo, arm);
+ VECCOPY(parent->head, stk->points[start].p);
+
+ index = next_subdividion(stk, bone_start, end, parent->head, parent->tail);
+ while (index != -1)
+ {
+ setBoneRollFromPoint(parent, &stk->points[index], invmat, tmat);
+
+ child = addEditBone("Bone", &G.edbo, 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);
+
+ parent = child; // new child is next parent
+ bone_start = index; // start next bone from current index
+
+ index = next_subdividion(stk, bone_start, end, parent->head, parent->tail);
+ }
+
+ VECCOPY(parent->tail, stk->points[end].p);
+
+ setBoneRollFromPoint(parent, &stk->points[end], invmat, tmat);
+
+ /* fix last bone */
+ Mat4MulVecfl(invmat, parent->tail);
+ Mat4MulVecfl(invmat, parent->head);
+ lastBone = parent;
+
+ return lastBone;
+}
+
+
+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)
+ {
+ if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_CORRELATION)
+ {
+ bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextCorrelationSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
+ {
+ bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextLengthSubdivision);
+ }
+ else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
+ {
+ bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextFixedSubdivision);
+ }
+ }
+
+ if (bone == NULL)
+ {
+ bone = addEditBone("Bone", &G.edbo, arm);
+
+ VECCOPY(bone->head, head->p);
+ VECCOPY(bone->tail, pt->p);
+ setBoneRollFromPoint(bone, pt, invmat, tmat);
+
+ Mat4MulVecfl(invmat, bone->head);
+ Mat4MulVecfl(invmat, bone->tail);
+ }
+
+ 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)
+ {
+ sk_convertStroke(stk);
+ }
+ }
+}
+/******************* 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;
+}
+
+
+/* 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;
+
+ 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);
+ }
+
+
+ return added;
+}
+
+int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
+{
+ float CORRELATION_THRESHOLD = 0.99f;
+ float *vec;
+ int i, j;
+
+ sk_appendStrokePoint(segments, &gesture->points[0]);
+ vec = segments->points[segments->nb_points - 1].p;
+
+ for (i = 1, j = 0; i < gesture->nb_points; i++)
+ {
+ float n[3];
+
+ /* Calculate normal */
+ VecSubf(n, gesture->points[i].p, vec);
+
+ if (calcStrokeCorrelation(gesture, 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;
+}
+
+void sk_applyCutGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ SK_Intersection *isect;
+
+ for (isect = list->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_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ float s1[3], s2[3];
+ float angle;
+
+ VecSubf(s1, segments->points[1].p, segments->points[0].p);
+ VecSubf(s2, segments->points[2].p, segments->points[1].p);
+
+ angle = VecAngle2(s1, s2);
+
+ if (angle > 60 && angle < 120)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void sk_applyTrimGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ SK_Intersection *isect;
+ float trim_dir[3];
+
+ VecSubf(trim_dir, segments->points[2].p, segments->points[1].p);
+
+ for (isect = list->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_detectDeleteGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ float s1[3], s2[3];
+ float angle;
+
+ VecSubf(s1, segments->points[1].p, segments->points[0].p);
+ VecSubf(s2, segments->points[2].p, segments->points[1].p);
+
+ angle = VecAngle2(s1, s2);
+
+ if (angle > 120)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void sk_applyDeleteGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ SK_Intersection *isect;
+
+ for (isect = list->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_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ short start_val[2], end_val[2];
+ short dist;
+
+ project_short_noclip(gesture->points[0].p, start_val);
+ project_short_noclip(gesture->points[gesture->nb_points - 1].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 = list->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;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void sk_applyMergeGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ SK_Intersection *isect;
+
+ /* check if it circled around an exact point */
+ for (isect = list->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_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ SK_Intersection *isect;
+
+ /* check if it circled around an exact point */
+ for (isect = list->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, gesture->points[0].p);
+ VecSubf(end_v, sk_lastStrokePoint(gesture)->p, isect->next->p);
+ }
+ else
+ {
+ VecSubf(start_v, isect->next->p, gesture->points[0].p);
+ VecSubf(end_v, sk_lastStrokePoint(gesture)->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_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+ SK_Intersection *isect;
+
+ for (isect = list->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;
+ }
+ }
+}
+
+void sk_applyGesture(SK_Sketch *sketch)
+{
+ ListBase intersections;
+ ListBase self_intersections;
+ SK_Stroke *segments = sk_createStroke();
+ int nb_self_intersections, nb_intersections, nb_segments;
+
+ intersections.first = intersections.last = NULL;
+ self_intersections.first = self_intersections.last = NULL;
+
+ nb_self_intersections = sk_getSelfIntersections(&self_intersections, sketch->gesture);
+ nb_intersections = sk_getIntersections(&intersections, sketch, sketch->gesture);
+ nb_segments = sk_getSegments(segments, sketch->gesture);
+
+ /* detect and apply */
+ if (nb_segments == 1 && nb_intersections == 1)
+ {
+ sk_applyCutGesture(sketch, sketch->gesture, &intersections, segments);
+ }
+ else if (nb_segments == 2 && nb_intersections == 1 && sk_detectTrimGesture(sketch, sketch->gesture, &intersections, segments))
+ {
+ sk_applyTrimGesture(sketch, sketch->gesture, &intersections, segments);
+ }
+ else if (nb_segments == 2 && nb_intersections == 2 && sk_detectDeleteGesture(sketch, sketch->gesture, &intersections, segments))
+ {
+ sk_applyDeleteGesture(sketch, sketch->gesture, &intersections, segments);
+ }
+ else if (nb_segments > 2 && nb_intersections == 2 && sk_detectMergeGesture(sketch, sketch->gesture, &intersections, segments))
+ {
+ sk_applyMergeGesture(sketch, sketch->gesture, &intersections, segments);
+ }
+ else if (nb_segments > 2 && nb_intersections == 2 && sk_detectReverseGesture(sketch, sketch->gesture, &intersections, segments))
+ {
+ sk_applyReverseGesture(sketch, sketch->gesture, &intersections, segments);
+ }
+ else if (nb_segments > 2 && nb_self_intersections == 1)
+ {
+ sk_convert(sketch);
+ BIF_undo_push("Convert Sketch");
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ else if (nb_segments > 2 && nb_self_intersections == 2)
+ {
+ sk_deleteSelectedStrokes(sketch);
+ }
+
+ sk_freeStroke(segments);
+ BLI_freelistN(&intersections);
+ BLI_freelistN(&self_intersections);
+}
+
+/********************************************/
+
+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);
+ }
+
+ 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)
+ {
+ sk_drawStroke(stk, -1, (stk->selected==1?selected_rgb:unselected_rgb));
+
+ 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);
+ }
+
+ 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);
+ glColor3f(1, 0.5, 0);
+ 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, 0.5, 1);
+ break;
+ case PT_EMBED:
+ 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_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;
+ }
+}
/* 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);
case 22: /* separate */
separate_armature();
break;
+ case 23: /* bone sketching panel */
+ add_blockhandler(curarea, VIEW3D_HANDLER_BONESKETCH, UI_PNL_UNSTOW);
+ break;
}
allqueue(REDRAWVIEW3D, 0);
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, "");
#include "BIF_toolbox.h"
#include "BIF_usiblender.h"
#include "BIF_previewrender.h"
+#include "BIF_sketch.h"
#include "BSE_edit.h"
#include "BSE_view.h"
#include "BDR_sculptmode.h"
#include "BDR_unwrapper.h"
#include "BDR_gpencil.h"
+#include "BDR_sketch.h"
#include "BLO_readfile.h" /* for BLO_blendhandle_close */
return; /* return if event was processed (swallowed) by handler(s) */
}
#endif
+ 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 */
}
}
}
+
+ BDR_queueDrawSketch();
/* Handle retopo painting */
if(retopo_mesh_paint_check()) {
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);
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 */
}
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:
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;
BIF_GlobalReebFree();
BIF_freeRetarget();
+ BIF_freeTemplates();
tf= G.ttfdata.first;
while(tf)
#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 */
#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"
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;