diff options
Diffstat (limited to 'source/blender/src')
41 files changed, 6758 insertions, 1501 deletions
diff --git a/source/blender/src/SConscript b/source/blender/src/SConscript index 47b269c85d7..c5edd711d0a 100644 --- a/source/blender/src/SConscript +++ b/source/blender/src/SConscript @@ -23,19 +23,22 @@ incs = ' #/intern/guardedalloc #/intern/memutil' incs += ' ../blenlib ../makesdna ../blenkernel' incs += ' ../include #/intern/bmfont ../imbuf ../render/extern/include' incs += ' #/intern/bsp/extern ../radiosity/extern/include' -incs += ' #/intern/decimation/extern ../blenloader ../python' +incs += ' #/intern/decimation/extern ../blenloader' incs += ' ../../kernel/gen_system #/intern/SoundSystem ../readstreamglue ../nodes' -incs += ' ../quicktime #/intern/elbeem/extern' +incs += ' #/intern/elbeem/extern' incs += ' #/intern/ghost #/intern/opennl/extern' incs += ' ../gpu #extern/glew/include' - -incs += ' ' + env['BF_PYTHON_INC'] -incs += ' ' + env['BF_SDL_INC'] incs += ' ' + env['BF_OPENGL_INC'] defs = [] +if env['WITH_BF_PYTHON']: + incs += ' ../python ' + env['BF_PYTHON_INC'] +else: + defs.append('DISABLE_PYTHON') + + if env['BF_TWEAK_MODE']: defs.append('TWEAK_MODE') @@ -58,9 +61,13 @@ if env['WITH_BF_QUICKTIME']: defs.append('WITH_QUICKTIME') if env['WITH_BF_ICONV']: + incs += ' ../quicktime' incs += ' ' + env['BF_ICONV_INC'] defs.append('WITH_ICONV') +if env['WITH_BF_GAMEENGINE']: + defs.append('GAMEBLENDER=1') + if env['WITH_BF_FFMPEG']: defs.append('WITH_FFMPEG') incs += ' ' + env['BF_FFMPEG_INC'] @@ -68,7 +75,7 @@ if env['WITH_BF_FFMPEG']: if env['WITH_BF_OGG']: defs.append('WITH_OGG') -if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'): +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross'): incs += ' ' + env['BF_PTHREADS_INC'] if env['WITH_BF_VERSE']: @@ -82,7 +89,9 @@ if env['BF_BUILDINFO']: if env['BF_NO_ELBEEM']: defs.append('DISABLE_ELBEEM') -if not env['WITH_BF_SDL']: +if env['WITH_BF_SDL']: + incs += ' ' + env['BF_SDL_INC'] +else: defs.append('DISABLE_SDL') if env['BF_SPLIT_SRC'] and (env['OURPLATFORM'] == 'win32-mingw'): diff --git a/source/blender/src/autoarmature.c b/source/blender/src/autoarmature.c new file mode 100644 index 00000000000..b0a7a2ab5cc --- /dev/null +++ b/source/blender/src/autoarmature.c @@ -0,0 +1,2968 @@ +/** + * $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. + * + * Contributor(s): Martin Poirier + * + * ***** END GPL LICENSE BLOCK ***** + * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...) + */ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "DNA_ID.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_ghash.h" +#include "BLI_graph.h" +#include "BLI_rand.h" +#include "BLI_threads.h" + +#include "BDR_editobject.h" + +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BKE_constraint.h" +#include "BKE_armature.h" + +#include "BIF_editarmature.h" +#include "BIF_space.h" + +#include "PIL_time.h" + +#include "mydevice.h" +#include "reeb.h" // FIX ME +#include "blendef.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; +} MemoNode; + +typedef struct RetargetParam { + RigGraph *rigg; + RigArc *iarc; + RigNode *inode_start; +} RetargetParam; + +typedef enum +{ + RETARGET_LENGTH, + RETARGET_AGGRESSIVE +} RetargetMode; + +typedef enum +{ + METHOD_BRUTE_FORCE = 0, + METHOD_MEMOIZE = 1, + METHOD_ANNEALING = 2 +} RetargetMethod; + +typedef enum +{ + ARC_FREE = 0, + ARC_TAKEN = 1, + ARC_USED = 2 +} ArcUsageFlags; + + +RigGraph *GLOBAL_RIGG = NULL; + +/*******************************************************************************************************/ + +void *exec_retargetArctoArc(void *param); + +static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second); + +/* two levels */ +#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX) + +/*********************************** EDITBONE UTILS ****************************************************/ + +int countEditBoneChildren(ListBase *list, EditBone *parent) +{ + EditBone *ebone; + int count = 0; + + for (ebone = list->first; ebone; ebone = ebone->next) + { + if (ebone->parent == parent) + { + count++; + } + } + + return count; +} + +EditBone* nextEditBoneChild(ListBase *list, EditBone *parent, int n) +{ + EditBone *ebone; + + for (ebone = list->first; ebone; ebone = ebone->next) + { + if (ebone->parent == parent) + { + if (n == 0) + { + return ebone; + } + n--; + } + } + + return NULL; +} + +void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3]) +{ + float mat[3][3], nor[3]; + + VecSubf(nor, bone->tail, bone->head); + + vec_roll_to_mat3(nor, roll, mat); + VECCOPY(up_axis, mat[2]); +} + +float getNewBoneRoll(EditBone *bone, float old_up_axis[3], float quat[4]) +{ + float mat[3][3]; + float nor[3], up_axis[3], new_up_axis[3], vec[3]; + float roll; + + VECCOPY(new_up_axis, old_up_axis); + QuatMulVecf(quat, new_up_axis); + + VecSubf(nor, bone->tail, bone->head); + + vec_roll_to_mat3(nor, 0, mat); + VECCOPY(up_axis, mat[2]); + + roll = NormalizedVecAngle2(new_up_axis, up_axis); + + Crossf(vec, up_axis, new_up_axis); + + if (Inpf(vec, nor) < 0) + { + roll = -roll; + } + + return roll; +} + +/************************************ DESTRUCTORS ******************************************************/ + +void RIG_freeRigArc(BArc *arc) +{ + BLI_freelistN(&((RigArc*)arc)->edges); +} + +void RIG_freeRigGraph(BGraph *rg) +{ + BNode *node; + BArc *arc; + +#ifdef USE_THREADS + BLI_destroy_worker(((RigGraph*)rg)->worker); +#endif + + REEB_freeGraph(((RigGraph*)rg)->link_mesh); + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + RIG_freeRigArc(arc); + } + BLI_freelistN(&rg->arcs); + + for (node = rg->nodes.first; node; node = node->next) + { + BLI_freeNode(rg, (BNode*)node); + } + BLI_freelistN(&rg->nodes); + + BLI_freelistN(&((RigGraph*)rg)->controls); + + BLI_ghash_free(((RigGraph*)rg)->bones_map, NULL, NULL); + BLI_ghash_free(((RigGraph*)rg)->controls_map, NULL, NULL); + + BLI_freelistN(&((RigGraph*)rg)->editbones); + + MEM_freeN(rg); +} + +/************************************* ALLOCATORS ******************************************************/ + +static RigGraph *newRigGraph() +{ + RigGraph *rg; + int totthread; + + rg = MEM_callocN(sizeof(RigGraph), "rig graph"); + + rg->head = NULL; + + rg->bones_map = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp); + rg->controls_map = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp); + + rg->free_arc = RIG_freeRigArc; + rg->free_node = NULL; + +#ifdef USE_THREADS + if(G.scene->r.mode & R_FIXED_THREADS) + { + totthread = G.scene->r.threads; + } + else + { + totthread = BLI_system_thread_count(); + } + + rg->worker = BLI_create_worker(exec_retargetArctoArc, totthread, 20); /* fix number of threads */ +#endif + + return rg; +} + +static RigArc *newRigArc(RigGraph *rg) +{ + RigArc *arc; + + arc = MEM_callocN(sizeof(RigArc), "rig arc"); + arc->count = 0; + BLI_addtail(&rg->arcs, arc); + + return arc; +} + +static RigControl *newRigControl(RigGraph *rg) +{ + RigControl *ctrl; + + ctrl = MEM_callocN(sizeof(RigControl), "rig control"); + + BLI_addtail(&rg->controls, ctrl); + + return ctrl; +} + +static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3]) +{ + RigNode *node; + node = MEM_callocN(sizeof(RigNode), "rig node"); + BLI_addtail(&rg->nodes, node); + + VECCOPY(node->p, p); + node->degree = 1; + node->arcs = NULL; + + arc->head = node; + + return node; +} + +static void addRigNodeHead(RigGraph *rg, RigArc *arc, RigNode *node) +{ + node->degree++; + + arc->head = node; +} + +static RigNode *newRigNode(RigGraph *rg, float p[3]) +{ + RigNode *node; + node = MEM_callocN(sizeof(RigNode), "rig node"); + BLI_addtail(&rg->nodes, node); + + VECCOPY(node->p, p); + node->degree = 0; + node->arcs = NULL; + + return node; +} + +static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3]) +{ + RigNode *node = newRigNode(rg, p); + + node->degree = 1; + arc->tail = node; + + return node; +} + +static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge) +{ + BLI_addtail(&arc->edges, edge); + + if (edge->prev == NULL) + { + VECCOPY(edge->head, arc->head->p); + } + else + { + RigEdge *last_edge = edge->prev; + VECCOPY(edge->head, last_edge->tail); + RIG_calculateEdgeAngle(last_edge, edge); + } + + edge->length = VecLenf(edge->head, edge->tail); + + arc->length += edge->length; + + arc->count += 1; +} + +static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone) +{ + RigEdge *edge; + + edge = MEM_callocN(sizeof(RigEdge), "rig edge"); + + VECCOPY(edge->tail, tail); + edge->bone = bone; + + if (bone) + { + getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis); + } + + RIG_appendEdgeToArc(arc, edge); +} + +/*******************************************************************************************************/ + +static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second) +{ + float vec_first[3], vec_second[3]; + + VecSubf(vec_first, edge_first->tail, edge_first->head); + VecSubf(vec_second, edge_second->tail, edge_second->head); + + Normalize(vec_first); + Normalize(vec_second); + + edge_first->angle = saacos(Inpf(vec_first, vec_second)); +} + +/************************************ CONTROL BONES ****************************************************/ + +static void RIG_addControlBone(RigGraph *rg, EditBone *bone) +{ + RigControl *ctrl = newRigControl(rg); + ctrl->bone = bone; + VECCOPY(ctrl->head, bone->head); + VECCOPY(ctrl->tail, bone->tail); + getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis); + + BLI_ghash_insert(rg->controls_map, bone->name, ctrl); +} + +static int RIG_parentControl(RigControl *ctrl, EditBone *link) +{ + if (link) + { + float offset[3]; + int flag = 0; + + VecSubf(offset, ctrl->bone->head, link->head); + + /* if root matches, check for direction too */ + if (Inpf(offset, offset) < 0.0001) + { + float vbone[3], vparent[3]; + + flag |= RIG_CTRL_FIT_ROOT; + + VecSubf(vbone, ctrl->bone->tail, ctrl->bone->head); + VecSubf(vparent, link->tail, link->head); + + /* test for opposite direction */ + if (Inpf(vbone, vparent) > 0) + { + float nor[3]; + float len; + + Crossf(nor, vbone, vparent); + + len = Inpf(nor, nor); + if (len < 0.0001) + { + flag |= RIG_CTRL_FIT_BONE; + } + } + } + + /* Bail out if old one is automatically better */ + if (flag < ctrl->flag) + { + return 0; + } + + /* if there's already a link + * overwrite only if new link is higher in the chain */ + if (ctrl->link && flag == ctrl->flag) + { + EditBone *bone = NULL; + + for (bone = ctrl->link; bone; bone = bone->parent) + { + /* if link is in the chain, break and use that one */ + if (bone == link) + { + break; + } + } + + /* not in chain, don't update link */ + if (bone == NULL) + { + return 0; + } + } + + + ctrl->link = link; + ctrl->flag = flag; + + VECCOPY(ctrl->offset, offset); + + return 1; + } + + return 0; +} + +static void RIG_reconnectControlBones(RigGraph *rg) +{ + RigControl *ctrl; + int change = 1; + + /* first pass, link to deform bones */ + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) + { + bPoseChannel *pchan; + bConstraint *con; + int found = 0; + + /* DO SOME MAGIC HERE */ + for (pchan= rg->ob->pose->chanbase.first; pchan; pchan= pchan->next) + { + for (con= pchan->constraints.first; con; con= con->next) + { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) + { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) + { + if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) + { + /* SET bone link to bone corresponding to pchan */ + EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name); + + found = RIG_parentControl(ctrl, link); + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + + /* if not found yet, check parent */ + if (found == 0) + { + if (ctrl->bone->parent) + { + /* make sure parent is a deforming bone + * NULL if not + * */ + EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name); + + found = RIG_parentControl(ctrl, link); + } + + /* check if bone is not superposed on another one */ + { + RigArc *arc; + RigArc *best_arc = NULL; + EditBone *link = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + RigEdge *edge; + for (edge = arc->edges.first; edge; edge = edge->next) + { + if (edge->bone) + { + int fit = 0; + + fit = VecLenf(ctrl->bone->head, edge->bone->head) < 0.0001; + fit = fit || VecLenf(ctrl->bone->tail, edge->bone->tail) < 0.0001; + + if (fit) + { + /* pick the bone on the arc with the lowest symmetry level + * means you connect control to the trunk of the skeleton */ + if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) + { + best_arc = arc; + link = edge->bone; + } + } + } + } + } + + found = RIG_parentControl(ctrl, link); + } + } + + /* if not found yet, check child */ + if (found == 0) + { + RigArc *arc; + RigArc *best_arc = NULL; + EditBone *link = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + RigEdge *edge; + for (edge = arc->edges.first; edge; edge = edge->next) + { + if (edge->bone && edge->bone->parent == ctrl->bone) + { + /* pick the bone on the arc with the lowest symmetry level + * means you connect control to the trunk of the skeleton */ + if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) + { + best_arc = arc; + link = edge->bone; + } + } + } + } + + found = RIG_parentControl(ctrl, link); + } + + } + + + /* second pass, make chains in control bones */ + while (change) + { + change = 0; + + printf("-------------------------\n"); + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) + { + /* if control is not linked yet */ + if (ctrl->link == NULL) + { + bPoseChannel *pchan; + bConstraint *con; + RigControl *ctrl_parent = NULL; + RigControl *ctrl_child; + int found = 0; + + if (ctrl->bone->parent) + { + ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name); + } + + /* check constraints first */ + + /* DO SOME MAGIC HERE */ + for (pchan= rg->ob->pose->chanbase.first; pchan; pchan= pchan->next) + { + for (con= pchan->constraints.first; con; con= con->next) + { + bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) + { + cti->get_constraint_targets(con, &targets); + + for (ct= targets.first; ct; ct= ct->next) + { + if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) + { + /* SET bone link to ctrl corresponding to pchan */ + RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name); + + /* 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; + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + + if (found == 0) + { + /* 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; + } + else + { + /* check childs */ + for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) + { + /* 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; + } + } + } + } + } + } + + } +} + +/*******************************************************************************************************/ + +static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2) +{ + RigEdge *edge, *next_edge; + + /* ignore cases where joint is at start or end */ + if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) + { + return; + } + + /* swap arcs to make sure arc1 is before arc2 */ + if (joined_arc1->head == joined_arc2->tail) + { + RigArc *tmp = joined_arc1; + joined_arc1 = joined_arc2; + joined_arc2 = tmp; + } + + for (edge = joined_arc2->edges.first; edge; edge = next_edge) + { + next_edge = edge->next; + + RIG_appendEdgeToArc(joined_arc1, edge); + } + + joined_arc1->tail = joined_arc2->tail; + + joined_arc2->edges.first = joined_arc2->edges.last = NULL; + + BLI_removeArc((BGraph*)rg, (BArc*)joined_arc2); + + BLI_removeNode((BGraph*)rg, (BNode*)node); +} + +static void RIG_removeNormalNodes(RigGraph *rg) +{ + RigNode *node, *next_node; + + for (node = rg->nodes.first; node; node = next_node) + { + next_node = node->next; + + if (node->degree == 2) + { + RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + if (arc->head == node || arc->tail == node) + { + if (joined_arc1 == NULL) + { + joined_arc1 = arc; + } + else + { + joined_arc2 = arc; + break; + } + } + } + + RIG_joinArcs(rg, node, joined_arc1, joined_arc2); + } + } +} + +static void RIG_removeUneededOffsets(RigGraph *rg) +{ + RigArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + RigEdge *first_edge, *last_edge; + + first_edge = arc->edges.first; + last_edge = arc->edges.last; + + if (first_edge->bone == NULL) + { + if (first_edge->bone == NULL && VecLenf(first_edge->tail, arc->head->p) <= 0.001) + { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + } + else if (arc->head->degree == 1) + { + RigNode *new_node = (RigNode*)BLI_FindNodeByPosition((BGraph*)rg, first_edge->tail, 0.001); + + if (new_node) + { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + BLI_replaceNodeInArc((BGraph*)rg, (BArc*)arc, (BNode*)new_node, (BNode*)arc->head); + } + else + { + RigEdge *next_edge = first_edge->next; + + if (next_edge) + { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + + VECCOPY(arc->head->p, next_edge->head); + } + } + } + else + { + /* check if all arc connected start with a null edge */ + RigArc *other_arc; + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) + { + if (other_arc != arc) + { + RigEdge *test_edge; + if (other_arc->head == arc->head) + { + test_edge = other_arc->edges.first; + + if (test_edge->bone != NULL) + { + break; + } + } + else if (other_arc->tail == arc->head) + { + test_edge = other_arc->edges.last; + + if (test_edge->bone != NULL) + { + break; + } + } + } + } + + if (other_arc == NULL) + { + RigNode *new_node = (RigNode*)BLI_FindNodeByPosition((BGraph*)rg, first_edge->tail, 0.001); + + if (new_node) + { + /* remove null edge in other arcs too */ + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) + { + if (other_arc != arc) + { + RigEdge *test_edge; + if (other_arc->head == arc->head) + { + BLI_replaceNodeInArc((BGraph*)rg, (BArc*)other_arc, (BNode*)new_node, (BNode*)other_arc->head); + test_edge = other_arc->edges.first; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + else if (other_arc->tail == arc->head) + { + BLI_replaceNodeInArc((BGraph*)rg, (BArc*)other_arc, (BNode*)new_node, (BNode*)other_arc->tail); + test_edge = other_arc->edges.last; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + } + } + + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + BLI_replaceNodeInArc((BGraph*)rg, (BArc*)arc, (BNode*)new_node, (BNode*)arc->head); + } + else + { + RigEdge *next_edge = first_edge->next; + + if (next_edge) + { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + + VECCOPY(arc->head->p, next_edge->head); + + /* remove null edge in other arcs too */ + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) + { + if (other_arc != arc) + { + RigEdge *test_edge; + if (other_arc->head == arc->head) + { + test_edge = other_arc->edges.first; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + else if (other_arc->tail == arc->head) + { + test_edge = other_arc->edges.last; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + } + } + } + } + } + } + } + + if (last_edge->bone == NULL) + { + if (VecLenf(last_edge->head, arc->tail->p) <= 0.001) + { + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + } + else if (arc->tail->degree == 1) + { + RigNode *new_node = (RigNode*)BLI_FindNodeByPosition((BGraph*)rg, last_edge->head, 0.001); + + if (new_node) + { + RigEdge *previous_edge = last_edge->prev; + + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + BLI_replaceNodeInArc((BGraph*)rg, (BArc*)arc, (BNode*)new_node, (BNode*)arc->tail); + + /* set previous angle to 0, since there's no following edges */ + if (previous_edge) + { + previous_edge->angle = 0; + } + } + else + { + RigEdge *previous_edge = last_edge->prev; + + if (previous_edge) + { + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + + VECCOPY(arc->tail->p, previous_edge->tail); + previous_edge->angle = 0; + } + } + } + } + } +} + +static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node) +{ + EditBone *bone, *last_bone = root_bone; + RigArc *arc = NULL; + int contain_head = 0; + + for(bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) + { + int nb_children; + + if ((bone->flag & BONE_NO_DEFORM) == 0) + { + 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 (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) + { + contain_head = 1; + } + } + else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) /* ignore locked bones */ + { + RIG_addControlBone(rg, bone); + } + + nb_children = countEditBoneChildren(list, bone); + if (nb_children > 1) + { + RigNode *end_node = NULL; + int i; + + if (arc != NULL) + { + end_node = newRigNodeTail(rg, arc, bone->tail); + } + else + { + end_node = newRigNode(rg, bone->tail); + } + + for (i = 0; i < nb_children; i++) + { + root_bone = nextEditBoneChild(list, bone, i); + RIG_arcFromBoneChain(rg, list, root_bone, end_node); + } + + /* arc ends here, break */ + break; + } + } + + /* If the loop exited without forking */ + if (arc != NULL && bone == NULL) + { + newRigNodeTail(rg, arc, last_bone->tail); + } + + if (contain_head) + { + rg->head = arc->tail; + } +} + +/*******************************************************************************************************/ +static void RIG_findHead(RigGraph *rg) +{ + if (rg->head == NULL) + { + if (BLI_countlist(&rg->arcs) == 1) + { + RigArc *arc = rg->arcs.first; + + rg->head = (RigNode*)arc->head; + } + else + { + RigArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + RigEdge *edge = arc->edges.last; + + if (edge->bone->flag & (BONE_TIPSEL|BONE_SELECTED)) + { + rg->head = arc->tail; + break; + } + } + } + + if (rg->head == NULL) + { + rg->head = rg->nodes.first; + } + } +} + +/*******************************************************************************************************/ + +void RIG_printNode(RigNode *node, char name[]) +{ + printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, node, node->degree, node->p[0], node->p[1], node->p[2]); + + if (node->symmetry_flag & SYM_TOPOLOGICAL) + { + if (node->symmetry_flag & SYM_AXIAL) + printf("Symmetry AXIAL\n"); + else if (node->symmetry_flag & SYM_RADIAL) + printf("Symmetry RADIAL\n"); + + printvecf("symmetry axis", node->symmetry_axis); + } +} + +void RIG_printArcBones(RigArc *arc) +{ + RigEdge *edge; + + for (edge = arc->edges.first; edge; edge = edge->next) + { + if (edge->bone) + printf("%s ", edge->bone->name); + else + printf("---- "); + } + printf("\n"); +} + +void RIG_printCtrl(RigControl *ctrl, char *indent) +{ + char text[128]; + + printf("%sBone: %s\n", indent, ctrl->bone->name); + printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!"); + + sprintf(text, "%soffset", indent); + printvecf(text, ctrl->offset); + + printf("%sFlag: %i\n", indent, ctrl->flag); +} + +void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs) +{ + RigControl *ctrl; + char indent[64]; + char *s = indent; + int i; + + for (i = 0; i < tabs; i++) + { + s[0] = '\t'; + s++; + } + s[0] = 0; + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) + { + if (ctrl->link == bone) + { + RIG_printCtrl(ctrl, indent); + RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1); + } + } +} + +void RIG_printArc(RigGraph *rg, RigArc *arc) +{ + RigEdge *edge; + + RIG_printNode((RigNode*)arc->head, "head"); + + for (edge = arc->edges.first; edge; edge = edge->next) + { + printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]); + printf("\t\tlength %f\n", edge->length); + printf("\t\tangle %f\n", edge->angle * 180 / M_PI); + if (edge->bone) + { + printf("\t\t%s\n", edge->bone->name); + RIG_printLinkedCtrl(rg, edge->bone, 3); + } + } + printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); + + RIG_printNode((RigNode*)arc->tail, "tail"); +} + +void RIG_printGraph(RigGraph *rg) +{ + RigArc *arc; + + printf("---- ARCS ----\n"); + for (arc = rg->arcs.first; arc; arc = arc->next) + { + RIG_printArc(rg, arc); + printf("\n"); + } + + if (rg->head) + { + RIG_printNode(rg->head, "HEAD NODE:"); + } + else + { + printf("HEAD NODE: NONE\n"); + } +} + +/*******************************************************************************************************/ + +static RigGraph *armatureToGraph(Object *ob, bArmature *arm) +{ + EditBone *ebone; + RigGraph *rg; + + rg = newRigGraph(); + + 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); + } + } + + 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); + + BLI_addtail(list, bone); + + bone->flag |= BONE_TIPSEL; + bone->weight= 1.0F; + bone->dist= 0.25F; + bone->xwidth= 0.1; + bone->zwidth= 0.1; + bone->ease1= 1.0; + bone->ease2= 1.0; + bone->rad_head= 0.10; + bone->rad_tail= 0.05; + bone->segments= 1; + bone->layer= 1;//arm->layer; + + return bone; +} + +EditBone * generateBonesForArc(RigGraph *rigg, ReebArc *arc, ReebNode *head, ReebNode *tail) +{ + ReebArcIterator iter; + float n[3]; + float ADAPTIVE_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit; + EditBone *lastBone = NULL; + + /* init iterator to get start and end from head */ + initArcIterator(&iter, arc, head); + + /* Calculate overall */ + VecSubf(n, arc->buckets[iter.end].p, head->p); + + if (1 /* G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION */ ) + { + EmbedBucket *bucket = NULL; + EmbedBucket *previous = NULL; + EditBone *child = NULL; + EditBone *parent = NULL; + float normal[3] = {0, 0, 0}; + float avg_normal[3]; + int total = 0; + int boneStart = iter.start; + + parent = add_editbonetolist("Bone", &rigg->editbones); + parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; + VECCOPY(parent->head, head->p); + + for (previous = nextBucket(&iter), bucket = nextBucket(&iter); + bucket; + previous = bucket, bucket = nextBucket(&iter)) + { + float btail[3]; + float value = 0; + + if (G.scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING) + { + VECCOPY(btail, bucket->p); + } + else + { + float length; + + /* Calculate normal */ + VecSubf(n, bucket->p, parent->head); + length = Normalize(n); + + total += 1; + VecAddf(normal, normal, n); + VECCOPY(avg_normal, normal); + VecMulf(avg_normal, 1.0f / total); + + VECCOPY(btail, avg_normal); + VecMulf(btail, length); + VecAddf(btail, btail, parent->head); + } + + if (G.scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE) + { + value = calcDistance(arc, boneStart, iter.index, parent->head, btail); + } + else + { + float n[3]; + + VecSubf(n, btail, parent->head); + value = calcVariance(arc, boneStart, iter.index, parent->head, n); + } + + if (value > ADAPTIVE_THRESHOLD) + { + VECCOPY(parent->tail, btail); + + child = add_editbonetolist("Bone", &rigg->editbones); + VECCOPY(child->head, parent->tail); + child->parent = parent; + child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; + + parent = child; // new child is next parent + boneStart = iter.index; // start from end + + normal[0] = normal[1] = normal[2] = 0; + total = 0; + } + } + + VECCOPY(parent->tail, tail->p); + + lastBone = parent; /* set last bone in the chain */ + } + + return lastBone; +} + +void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit) +{ + while (node->multi_level > multi_level_limit && node->link_up) + { + node = node->link_up; + } + + while (node->multi_level < multi_level_limit && node->link_down) + { + node = node->link_down; + } + + if (node->multi_level == multi_level_limit) + { + int i; + + for (i = 0; i < node->degree; i++) + { + ReebArc *earc = node->arcs[i]; + + if (earc->flag == ARC_FREE && earc->head == node) + { + ReebNode *other = BIF_otherNodeFromIndex(earc, node); + + earc->flag = ARC_USED; + + generateBonesForArc(rigg, earc, node, other); + generateMissingArcsFromNode(rigg, other, multi_level_limit); + } + } + } +} + +void generateMissingArcs(RigGraph *rigg) +{ + ReebGraph *reebg = rigg->link_mesh; + int multi_level_limit = 5; + + for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up) + { + ReebArc *earc; + + for (earc = reebg->arcs.first; earc; earc = earc->next) + { + if (earc->flag == ARC_USED) + { + generateMissingArcsFromNode(rigg, earc->head, multi_level_limit); + generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit); + } + } + } +} + +/************************************ RETARGETTING *****************************************************/ + +static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize) +{ + RigControl *ctrl_child; + float parent_offset[3], tail_offset[3]; + + VecSubf(tail_offset, ctrl->tail, ctrl->head); + VecMulf(tail_offset, resize); + + VECCOPY(parent_offset, ctrl->offset); + VecMulf(parent_offset, resize); + + QuatMulVecf(qrot, parent_offset); + QuatMulVecf(qrot, tail_offset); + + VecAddf(ctrl->bone->head, head, parent_offset); + VecAddf(ctrl->bone->tail, ctrl->bone->head, tail_offset); + ctrl->bone->roll = getNewBoneRoll(ctrl->bone, ctrl->up_axis, qrot); + + ctrl->flag |= RIG_CTRL_DONE; + + /* Cascade to connected control bones */ + for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) + { + if (ctrl_child->link == ctrl->bone) + { + repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, qrot, resize); + } + } + +} + +static void repositionBone(RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3]) +{ + EditBone *bone; + RigControl *ctrl; + float qrot[4], resize; + float v1[3], v2[3]; + float l1, l2; + + bone = edge->bone; + + VecSubf(v1, edge->tail, edge->head); + VecSubf(v2, vec1, vec0); + + l1 = Normalize(v1); + l2 = Normalize(v2); + + resize = l2 / l1; + + RotationBetweenVectorsToQuat(qrot, v1, v2); + + for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) + { + if (ctrl->link == bone) + { + repositionControl(rigg, ctrl, vec0, vec1, qrot, resize); + } + } + + VECCOPY(bone->head, vec0); + VECCOPY(bone->tail, vec1); + bone->roll = getNewBoneRoll(bone, edge->up_axis, qrot); +} + +static RetargetMode detectArcRetargetMode(RigArc *arc); +static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_start); + + +static RetargetMode detectArcRetargetMode(RigArc *iarc) +{ + RetargetMode mode = RETARGET_AGGRESSIVE; + ReebArc *earc = iarc->link_mesh; + RigEdge *edge; + int large_angle = 0; + float avg_angle = 0; + float avg_length = 0; + int nb_edges = 0; + + + for (edge = iarc->edges.first; edge; edge = edge->next) + { + avg_angle += edge->angle; + nb_edges++; + } + + avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */ + + avg_length = iarc->length / nb_edges; + + + if (nb_edges > 2) + { + for (edge = iarc->edges.first; edge; edge = edge->next) + { + if (fabs(edge->angle - avg_angle) > M_PI / 6) + { + large_angle = 1; + } + } + } + else if (nb_edges == 2 && avg_angle > 0) + { + large_angle = 1; + } + + + if (large_angle == 0) + { + mode = RETARGET_LENGTH; + } + + if (earc->bcount <= (iarc->count - 1)) + { + mode = RETARGET_LENGTH; + } + + mode = RETARGET_AGGRESSIVE; + + return mode; +} + +#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; + int i; + + for (i = 0; i < nb_positions; i++) + { + moves += positions[i] - (i + 1); + } + + printf("%i moves needed\n", moves); +} + +static void printPositions(int *positions, int nb_positions) +{ + int i; + + for (i = 0; i < nb_positions; i++) + { + printf("%i ", positions[i]); + } + printf("\n"); +} +#endif + +#define MAX_COST 100 /* FIX ME */ + +static float costDistance(ReebArcIterator *iter, float *vec0, float *vec1, int i0, int i1) +{ + EmbedBucket *bucket = NULL; + float max_dist = 0; + float v1[3], v2[3], c[3]; + float v1_inpf; + + if (G.scene->toolsettings->skgen_retarget_distance_weight > 0) + { + VecSubf(v1, vec0, vec1); + + v1_inpf = Inpf(v1, v1); + + if (v1_inpf > 0) + { + int j; + for (j = i0 + 1; j < i1 - 1; j++) + { + float dist; + + bucket = peekBucket(iter, j); + + VecSubf(v2, bucket->p, vec1); + + Crossf(c, v1, v2); + + dist = Inpf(c, c) / v1_inpf; + + max_dist = dist > max_dist ? dist : max_dist; + } + + return G.scene->toolsettings->skgen_retarget_distance_weight * max_dist; + } + else + { + return MAX_COST; + } + } + else + { + return 0; + } +} + +static float costAngle(float original_angle, float vec_first[3], float vec_second[3]) +{ + if (G.scene->toolsettings->skgen_retarget_angle_weight > 0) + { + float current_angle; + + if (!VecIsNull(vec_first) && !VecIsNull(vec_second)) + { + current_angle = saacos(Inpf(vec_first, vec_second)); + + return G.scene->toolsettings->skgen_retarget_angle_weight * fabs(current_angle - original_angle); + } + else + { + return G.scene->toolsettings->skgen_retarget_angle_weight * M_PI; + } + } + else + { + return 0; + } +} + +static float costLength(float original_length, float current_length) +{ + if (current_length == 0) + { + return MAX_COST; + } + else + { + float length_ratio = fabs((current_length - original_length) / original_length); + return G.scene->toolsettings->skgen_retarget_length_weight * length_ratio * length_ratio; + } +} + +static float calcCostLengthDistance(ReebArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2) +{ + float vec[3]; + float length; + + VecSubf(vec, vec2, vec1); + length = Normalize(vec); + + return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2); +} + +static float calcCostAngleLengthDistance(ReebArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2) +{ + float vec_second[3], vec_first[3]; + float length2; + float new_cost = 0; + + VecSubf(vec_second, vec2, vec1); + length2 = Normalize(vec_second); + + + /* Angle cost */ + if (edge->prev) + { + VecSubf(vec_first, vec1, vec0); + Normalize(vec_first); + + new_cost += costAngle(edge->prev->angle, vec_first, vec_second); + } + + /* Length cost */ + new_cost += costLength(edge->length, length2); + + /* Distance cost */ + new_cost += costDistance(iter, vec1, vec2, i1, i2); + + 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; +} + +static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left) +{ + int previous = 0, current = 0; + int i = 0; + + for (i = 0; joints_left > 0; joints_left--, i++) + { + MemoNode *node; + node = table + indexMemoNode(nb_positions, previous, current, joints_left); + + positions[i] = node->next; + + previous = current; + current = node->next; + } +} + +static MemoNode * solveJoints(MemoNode *table, ReebArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left) +{ + MemoNode *node; + int index = indexMemoNode(nb_positions, previous, current, joints_left); + + node = table + index; + + if (node->weight != 0) + { + return node; + } + else if (joints_left == 0) + { + float *vec1 = vec_cache[current]; + float *vec2 = vec_cache[nb_positions + 1]; + + node->weight = calcCostLengthDistance(iter, vec_cache, edge, vec1, vec2, current, iter->length); + + return node; + } + else + { + MemoNode *min_node = NULL; + float *vec0 = vec_cache[previous]; + float *vec1 = vec_cache[current]; + float min_weight; + int min_next; + int next; + + for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) + { + MemoNode *next_node; + float *vec2 = vec_cache[next]; + float weight = 0; + + /* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */ + weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next); + + if (weight >= MAX_COST) + { + continue; + } + + /* add node weight */ + next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1); + weight += next_node->weight; + + if (min_node == NULL || weight < min_weight) + { + min_weight = weight; + min_node = next_node; + min_next = next; + } + } + + if (min_node) + { + node->weight = min_weight; + node->next = min_next; + return node; + } + else + { + node->weight = MAX_COST; + return node; + } + } + +} + +static int testFlipArc(RigArc *iarc, RigNode *inode_start) +{ + ReebArc *earc = iarc->link_mesh; + ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh); + + /* no flip needed if both nodes are the same */ + if ((enode_start == earc->head && inode_start == iarc->head) || (enode_start == earc->tail && inode_start == iarc->tail)) + { + return 0; + } + else + { + return 1; + } +} + +static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + ReebArcIterator iter; + RigEdge *edge; + EmbedBucket *bucket = NULL; + ReebNode *node_start, *node_end; + ReebArc *earc = iarc->link_mesh; + float min_cost = FLT_MAX; + float *vec0, *vec1, *vec2; + float **vec_cache; + float *cost_cache; + int *best_positions; + int *positions; + int nb_edges = BLI_countlist(&iarc->edges); + int nb_joints = nb_edges - 1; + RetargetMethod method = G.scene->toolsettings->skgen_optimisation_method; + int i; + + if (nb_joints > earc->bcount) + { + printf("NOT ENOUGH BUCKETS!\n"); + 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"); + + if (testFlipArc(iarc, inode_start)) + { + node_start = earc->tail; + node_end = earc->head; + } + else + { + 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++) + { + cost_cache[i] = 0; + } + + vec_cache[0] = node_start->p; + vec_cache[nb_edges] = node_end->p; + + if (method == METHOD_MEMOIZE) + { + int nb_positions = earc->bcount; + int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1); + MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table"); + MemoNode *result; + float **positions_cache = MEM_callocN(sizeof(float*) * (nb_positions + 2), "positions cache"); + int i; + + positions_cache[0] = node_start->p; + positions_cache[nb_positions + 1] = node_end->p; + + initArcIterator(&iter, earc, node_start); + + for (i = 1; i <= nb_positions; i++) + { + EmbedBucket *bucket = peekBucket(&iter, i); + positions_cache[i] = bucket->p; + } + + result = solveJoints(table, &iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints); + + min_cost = result->weight; + copyMemoPositions(best_positions, table, earc->bcount, nb_joints); + + MEM_freeN(table); + MEM_freeN(positions_cache); + } + /* BRUTE FORCE */ + else if (method == METHOD_BRUTE_FORCE) + { + int last_index = 0; + int first_pass = 1; + int must_move = nb_joints - 1; + + while(1) + { + float cost = 0; + int need_calc = 0; + + /* increment to next possible solution */ + + i = nb_joints - 1; + + if (first_pass) + { + need_calc = 0; + first_pass = 0; + } + else + { + /* increment positions, starting from the last one + * until a valid increment is found + * */ + for (i = must_move; i >= 0; i--) + { + int remaining_joints = nb_joints - (i + 1); + + positions[i] += 1; + need_calc = i; + + if (positions[i] + remaining_joints <= earc->bcount) + { + break; + } + } + } + + if (i == -1) + { + break; + } + + /* reset joints following the last increment*/ + for (i = i + 1; i < nb_joints; i++) + { + positions[i] = positions[i - 1] + 1; + } + + /* calculating cost */ + initArcIterator(&iter, earc, node_start); + + vec0 = NULL; + vec1 = node_start->p; + vec2 = NULL; + + for (edge = iarc->edges.first, i = 0, last_index = 0; + edge; + edge = edge->next, i += 1) + { + + if (i >= need_calc) + { + float vec_first[3], vec_second[3]; + float length1, length2; + float new_cost = 0; + int i1, i2; + + if (i < nb_joints) + { + i2 = positions[i]; + bucket = peekBucket(&iter, positions[i]); + vec2 = bucket->p; + vec_cache[i + 1] = vec2; /* update cache for updated position */ + } + else + { + i2 = iter.length; + vec2 = node_end->p; + } + + if (i > 0) + { + i1 = positions[i - 1]; + } + else + { + i1 = 1; + } + + vec1 = vec_cache[i]; + + + VecSubf(vec_second, vec2, vec1); + length2 = Normalize(vec_second); + + /* check angle */ + if (i != 0 && G.scene->toolsettings->skgen_retarget_angle_weight > 0) + { + RigEdge *previous = edge->prev; + + vec0 = vec_cache[i - 1]; + VecSubf(vec_first, vec1, vec0); + length1 = Normalize(vec_first); + + /* Angle cost */ + new_cost += costAngle(previous->angle, vec_first, vec_second); + } + + /* Length Cost */ + new_cost += costLength(edge->length, length2); + + /* Distance Cost */ + new_cost += costDistance(&iter, vec1, vec2, i1, i2); + + cost_cache[i] = new_cost; + } + + cost += cost_cache[i]; + + if (cost > min_cost) + { + must_move = i; + break; + } + } + + if (must_move != i || must_move > nb_joints - 1) + { + must_move = nb_joints - 1; + } + + /* cost optimizing */ + if (cost < min_cost) + { + min_cost = cost; + 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); + } + + + vec0 = node_start->p; + initArcIterator(&iter, earc, node_start); + +#ifndef USE_THREADS + printPositions(best_positions, nb_joints); + printMovesNeeded(best_positions, nb_joints); + printf("min_cost %f\n", min_cost); + printf("buckets: %i\n", earc->bcount); +#endif + + /* set joints to best position */ + for (edge = iarc->edges.first, i = 0; + edge; + edge = edge->next, i++) + { + if (i < nb_joints) + { + bucket = peekBucket(&iter, best_positions[i]); + vec1 = bucket->p; + } + else + { + vec1 = node_end->p; + } + + if (edge->bone) + { + repositionBone(rigg, edge, vec0, vec1); + } + + vec0 = vec1; + } + + MEM_freeN(positions); + MEM_freeN(best_positions); + MEM_freeN(cost_cache); + MEM_freeN(vec_cache); +} + +static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + ReebArcIterator iter; + ReebArc *earc = iarc->link_mesh; + ReebNode *node_start, *node_end; + RigEdge *edge; + EmbedBucket *bucket = NULL; + float embedding_length = 0; + float *vec0 = NULL; + float *vec1 = NULL; + float *previous_vec = NULL; + + + if (testFlipArc(iarc, inode_start)) + { + node_start = (ReebNode*)earc->tail; + node_end = (ReebNode*)earc->head; + } + else + { + node_start = (ReebNode*)earc->head; + node_end = (ReebNode*)earc->tail; + } + + initArcIterator(&iter, earc, node_start); + + bucket = nextBucket(&iter); + + vec0 = node_start->p; + + while (bucket != NULL) + { + vec1 = bucket->p; + + embedding_length += VecLenf(vec0, vec1); + + vec0 = vec1; + bucket = nextBucket(&iter); + } + + embedding_length += VecLenf(node_end->p, vec1); + + /* fit bones */ + initArcIterator(&iter, earc, node_start); + + bucket = nextBucket(&iter); + + vec0 = node_start->p; + previous_vec = vec0; + vec1 = bucket->p; + + for (edge = iarc->edges.first; edge; edge = edge->next) + { + float new_bone_length = edge->length / iarc->length * embedding_length; + + float length = 0; + + while (bucket && new_bone_length > length) + { + length += VecLenf(previous_vec, vec1); + bucket = nextBucket(&iter); + previous_vec = vec1; + vec1 = bucket->p; + } + + if (bucket == NULL) + { + vec1 = node_end->p; + } + + /* no need to move virtual edges (space between unconnected bones) */ + if (edge->bone) + { + repositionBone(rigg, edge, vec0, vec1); + } + + vec0 = vec1; + previous_vec = vec1; + } +} + +static void retargetArctoArc(RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ +#ifdef USE_THREADS + RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam"); + + p->rigg = rigg; + p->iarc = iarc; + p->inode_start = inode_start; + + BLI_insert_work(rigg->worker, p); +#else + RetargetParam p; + + p.rigg = rigg; + p.iarc = iarc; + p.inode_start = inode_start; + + exec_retargetArctoArc(&p); +#endif +} + +void *exec_retargetArctoArc(void *param) +{ + RetargetParam *p = (RetargetParam*)param; + RigGraph *rigg = p->rigg; + RigArc *iarc = p->iarc; + RigNode *inode_start = p->inode_start; + ReebArc *earc = iarc->link_mesh; + + if (BLI_countlist(&iarc->edges) == 1) + { + RigEdge *edge = iarc->edges.first; + + if (testFlipArc(iarc, inode_start)) + { + repositionBone(rigg, edge, earc->tail->p, earc->head->p); + } + else + { + repositionBone(rigg, edge, earc->head->p, earc->tail->p); + } + } + else + { + RetargetMode mode = detectArcRetargetMode(iarc); + + if (mode == RETARGET_AGGRESSIVE) + { + retargetArctoArcAggresive(rigg, iarc, inode_start); + } + else + { + retargetArctoArcLength(rigg, iarc, inode_start); + } + } + +#ifdef USE_THREADS + MEM_freeN(p); +#endif + + return NULL; +} + +static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node) +{ + ReebNode *enode = top_node; + ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); + int ishape, eshape; + + ishape = BLI_subtreeShape((BGraph*)rigg, (BNode*)inode, NULL, 0) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; + + inode->link_mesh = enode; + + while (ishape == eshape && enode->link_down) + { + inode->link_mesh = enode; + + enode = enode->link_down; + reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */ + eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; + } +} + +static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode) +{ + int i; + + for(i = 0; i < enode->degree; i++) + { + ReebArc *earc = (ReebArc*)enode->arcs[i]; + + if (earc->flag == ARC_FREE) + { + earc->flag = ARC_TAKEN; + + if (earc->tail->degree > 1 && earc->tail != end_enode) + { + markMultiResolutionChildArc(end_enode, earc->tail); + } + break; + } + } +} + +static void markMultiResolutionArc(ReebArc *start_earc) +{ + if (start_earc->link_up) + { + ReebArc *earc; + for (earc = start_earc->link_up ; earc; earc = earc->link_up) + { + earc->flag = ARC_TAKEN; + + if (earc->tail->index != start_earc->tail->index) + { + markMultiResolutionChildArc(earc->tail, earc->tail); + } + } + } +} + +static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc) +{ + ReebNode *enode = next_earc->head; + ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); + int ishape, eshape; + + ishape = BLI_subtreeShape((BGraph*)rigg, (BNode*)start_node, (BArc*)next_iarc, 1) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, (BArc*)next_earc, 1) % SHAPE_LEVELS; + + while (ishape != eshape && next_earc->link_up) + { + next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels + + next_earc = next_earc->link_up; + reebg = reebg->link_up; + enode = next_earc->head; + eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, (BArc*)next_earc, 1) % SHAPE_LEVELS; + } + + next_earc->flag = ARC_USED; + next_iarc->link_mesh = next_earc; + + /* mark all higher levels as taken too */ + markMultiResolutionArc(next_earc); +// while (next_earc->link_up) +// { +// next_earc = next_earc->link_up; +// next_earc->flag = ARC_TAKEN; +// } +} + +static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode) +{ + ReebNode *enode; + int ishape, eshape; + + enode = reebg->nodes.first; + + ishape = BLI_subtreeShape((BGraph*)rigg, (BNode*)inode, NULL, 0) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph*)rigg->link_mesh, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; + + while (ishape != eshape && reebg->link_up) + { + reebg = reebg->link_up; + + enode = reebg->nodes.first; + + eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; + } + + inode->link_mesh = enode; +} + +static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root) +{ + ReebNode *enode = start_node->link_mesh; + ReebArc *next_earc; + int symmetry_level = next_iarc->symmetry_level; + int symmetry_group = next_iarc->symmetry_group; + int symmetry_flag = next_iarc->symmetry_flag; + int i; + + next_iarc->link_mesh = NULL; + +// if (root) +// { +// printf("-----------------------\n"); +// printf("MATCHING LIMB\n"); +// RIG_printArcBones(next_iarc); +// } + + for(i = 0; i < enode->degree; i++) + { + next_earc = (ReebArc*)enode->arcs[i]; + +// if (next_earc->flag == ARC_FREE) +// { +// printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n", +// symmetry_level, next_earc->symmetry_level, +// symmetry_flag, next_earc->symmetry_flag, +// symmetry_group, next_earc->symmetry_flag); +// } + + if (next_earc->flag == ARC_FREE && + next_earc->symmetry_flag == symmetry_flag && + next_earc->symmetry_group == symmetry_group && + next_earc->symmetry_level == symmetry_level) + { +// printf("CORRESPONDING ARC FOUND\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); + + matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); + break; + } + } + + /* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */ + if (next_iarc->link_mesh == NULL) + { +// printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n"); + + if (enode->link_up) + { + start_node->link_mesh = enode->link_up; + findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0); + } + } + + /* still not found, print debug info */ + if (root && next_iarc->link_mesh == NULL) + { + start_node->link_mesh = enode; /* linking back with root node */ + +// printf("NO CORRESPONDING ARC FOUND\n"); +// RIG_printArcBones(next_iarc); +// +// printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level); +// +// printf("LOOKING FOR\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group); +// +// printf("CANDIDATES\n"); +// for(i = 0; i < enode->degree; i++) +// { +// next_earc = (ReebArc*)enode->arcs[i]; +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); +// } + + /* Emergency matching */ + for(i = 0; i < enode->degree; i++) + { + next_earc = (ReebArc*)enode->arcs[i]; + + if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) + { +// printf("USING: \n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); + matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); + break; + } + } + } + +} + +static void retargetSubgraph(RigGraph *rigg, RigArc *start_arc, RigNode *start_node) +{ + RigNode *inode = start_node; + int i; + + /* no start arc on first node */ + if (start_arc) + { + ReebNode *enode = start_node->link_mesh; + ReebArc *earc = start_arc->link_mesh; + + retargetArctoArc(rigg, start_arc, start_node); + + enode = BIF_otherNodeFromIndex(earc, enode); + inode = (RigNode*)BLI_otherNode((BArc*)start_arc, (BNode*)inode); + + /* match with lowest node with correct shape */ + matchMultiResolutionNode(rigg, inode, enode); + } + + for(i = 0; i < inode->degree; i++) + { + RigArc *next_iarc = (RigArc*)inode->arcs[i]; + + /* no back tracking */ + if (next_iarc != start_arc) + { + findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1); + if (next_iarc->link_mesh) + { + retargetSubgraph(rigg, next_iarc, inode); + } + } + } +} + +static void adjustGraphs(RigGraph *rigg) +{ + RigArc *arc; + + for (arc = rigg->arcs.first; arc; arc = arc->next) + { + if (arc->link_mesh) + { + retargetArctoArc(rigg, arc, arc->head); + } + } + +#ifdef USE_THREADS + BLI_end_worker(rigg->worker); +#endif + + /* Turn the list into an armature */ + editbones_to_armature(&rigg->editbones, rigg->ob); + + BIF_undo_push("Retarget Skeleton"); +} + +static void retargetGraphs(RigGraph *rigg) +{ + ReebGraph *reebg = rigg->link_mesh; + RigNode *inode; + + /* flag all ReebArcs as free */ + BIF_flagMultiArcs(reebg, ARC_FREE); + + /* return to first level */ + reebg = rigg->link_mesh; + + inode = rigg->head; + + matchMultiResolutionStartingNode(rigg, reebg, inode); + + retargetSubgraph(rigg, NULL, inode); + + //generateMissingArcs(rigg); + +#ifdef USE_THREADS + BLI_end_worker(rigg->worker); +#endif + + /* Turn the list into an armature */ + editbones_to_armature(&rigg->editbones, rigg->ob); +} + + +void BIF_retargetArmature() +{ + Object *ob; + Base *base; + ReebGraph *reebg; + double start_time, end_time; + double gstart_time, gend_time; + double reeb_time, rig_time, retarget_time, total_time; + + gstart_time = start_time = PIL_check_seconds_timer(); + + reebg = BIF_ReebGraphMultiFromEditMesh(); + + end_time = PIL_check_seconds_timer(); + reeb_time = end_time - start_time; + + printf("Reeb Graph created\n"); + + base= FIRSTBASE; + for (base = FIRSTBASE; base; base = base->next) + { + if TESTBASELIB(base) { + ob = base->object; + + if (ob->type==OB_ARMATURE) + { + RigGraph *rigg; + bArmature *arm; + + arm = ob->data; + + /* Put the armature into editmode */ + + + start_time = PIL_check_seconds_timer(); + + rigg = armatureToGraph(ob, arm); + + end_time = PIL_check_seconds_timer(); + rig_time = end_time - start_time; + + printf("Armature graph created\n"); + + //RIG_printGraph(rigg); + + rigg->link_mesh = reebg; + + printf("retargetting %s\n", ob->id.name); + + start_time = PIL_check_seconds_timer(); + + retargetGraphs(rigg); + + end_time = PIL_check_seconds_timer(); + retarget_time = end_time - start_time; + + BIF_freeRetarget(); + + GLOBAL_RIGG = rigg; + + break; /* only one armature at a time */ + } + } + } + + gend_time = PIL_check_seconds_timer(); + + total_time = gend_time - gstart_time; + + printf("-----------\n"); + printf("runtime: \t%.3f\n", total_time); + printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100); + printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100); + printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100); + printf("-----------\n"); + + BIF_undo_push("Retarget Skeleton"); + + allqueue(REDRAWVIEW3D, 0); +} + +void BIF_adjustRetarget() +{ + if (GLOBAL_RIGG) + { + adjustGraphs(GLOBAL_RIGG); + } +} + +void BIF_freeRetarget() +{ + if (GLOBAL_RIGG) + { + RIG_freeRigGraph((BGraph*)GLOBAL_RIGG); + GLOBAL_RIGG = NULL; + } +} diff --git a/source/blender/src/butspace.c b/source/blender/src/butspace.c index f134e9a9650..2ca709184c5 100644 --- a/source/blender/src/butspace.c +++ b/source/blender/src/butspace.c @@ -511,7 +511,8 @@ void curvemap_buttons(uiBlock *block, CurveMapping *cumap, char labeltype, short static void do_node_buts(unsigned short event) { Material *ma; - + SpaceNode *snode = curarea->spacedata.first; + /* all operations default on active material layer here */ /* but this also gets called for lamp and world... */ ma= G.buts->lockpoin; @@ -523,6 +524,7 @@ static void do_node_buts(unsigned short event) if(event>=B_NODE_EXEC) { if(ma) end_render_material(ma); /// temporal... 3d preview BIF_preview_changed(ID_MA); + BIF_preview_changed(ID_TE); allqueue(REDRAWNODE, 0); allqueue(REDRAWBUTSSHADING, 0); } diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 3d60e9a8eea..b6dfd29d62a 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -180,6 +180,8 @@ #include "butspace.h" // own module #include "multires.h" +#include "reeb.h" + static float editbutweight= 1.0; float editbutvweight= 1; static int actmcol= 0, acttface= 0, acttface_rnd = 0, actmcol_rnd = 0; @@ -3244,6 +3246,7 @@ void do_curvebuts(unsigned short event) case B_CONVERTNURB: if(G.obedit) { setsplinetype(event-B_CONVERTPOLY); + BIF_undo_push("Convert type"); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); } @@ -3275,6 +3278,7 @@ void do_curvebuts(unsigned short event) } nu= nu->next; } + BIF_undo_push("Cyclic"); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); } @@ -3282,6 +3286,7 @@ void do_curvebuts(unsigned short event) case B_SETWEIGHT: if(G.obedit) { weightflagNurb(1, editbutweight, 0); + BIF_undo_push("Set weight"); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); } @@ -3315,6 +3320,7 @@ void do_curvebuts(unsigned short event) } makeknots(nu, 2, nu->flagv>>1); } + BIF_undo_push("Make knots"); DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); } @@ -3366,6 +3372,7 @@ void do_curvebuts(unsigned short event) nu= nu->next; } } + BIF_undo_push("Make 2D/3D"); DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); break; @@ -3381,6 +3388,7 @@ void do_curvebuts(unsigned short event) } } + BIF_undo_push("Set resolution"); DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSALL, 0); @@ -5052,6 +5060,9 @@ void do_meshbuts(unsigned short event) case B_GEN_SKELETON: generateSkeleton(); break; + case B_RETARGET_SKELETON: + BIF_retargetArmature(); + break; } /* WATCH IT: previous events only in editmode! */ @@ -5150,6 +5161,100 @@ static void skgen_reorder(void *option, void *arg2) } } +static void skgen_graphgen(void *arg1, void *arg2) +{ + BIF_GlobalReebGraphFromEditMesh(); + allqueue(REDRAWVIEW3D, 0); +} + +static void skgen_graphfree(void *arg1, void *arg2) +{ + BIF_GlobalReebFree(); + allqueue(REDRAWVIEW3D, 0); +} + +static void skgen_rigadjust(void *arg1, void *arg2) +{ + BIF_adjustRetarget(); +} + +static void skgen_rigfree(void *arg1, void *arg2) +{ + BIF_freeRetarget(); +} + +static void skgen_graph_block(uiBlock *block) +{ + uiBlockBeginAlign(block); + uiDefButS(block, NUM, B_DIFF, "Resolution:", 1025,150,225,19, &G.scene->toolsettings->skgen_resolution,10.0,1000.0, 0, 0, "Specifies the resolution of the graph's embedding"); + uiDefButBitS(block, TOG, SKGEN_HARMONIC, B_DIFF, "H", 1250,150, 25,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Apply harmonic smoothing to the weighting"); + uiDefButBitS(block, TOG, SKGEN_FILTER_INTERNAL, B_DIFF, "Filter In", 1025,130, 83,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Filter internal small arcs from graph"); + uiDefButF(block, NUM, B_DIFF, "", 1111,130,164,19, &G.scene->toolsettings->skgen_threshold_internal,0.0, 10.0, 10, 0, "Specify the threshold ratio for filtering internal arcs"); + uiDefButBitS(block, TOG, SKGEN_FILTER_EXTERNAL, B_DIFF, "Filter Ex", 1025,110, 53,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Filter external small arcs from graph"); + uiDefButBitS(block, TOG, SKGEN_FILTER_SMART, B_DIFF, "Sm", 1078,110, 30,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Smart Filtering"); + uiDefButF(block, NUM, B_DIFF, "", 1111,110,164,19, &G.scene->toolsettings->skgen_threshold_external,0.0, 10.0, 10, 0, "Specify the threshold ratio for filtering external arcs"); + + uiDefButBitS(block, TOG, SKGEN_SYMMETRY, B_DIFF, "Symmetry", 1025, 90,125,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Restore symmetries based on topology"); + uiDefButF(block, NUM, B_DIFF, "T:", 1150, 90,125,19, &G.scene->toolsettings->skgen_symmetry_limit,0.0, 1.0, 10, 0, "Specify the threshold distance for considering potential symmetric arcs"); + uiDefButC(block, NUM, B_DIFF, "P:", 1025, 70, 62,19, &G.scene->toolsettings->skgen_postpro_passes, 0, 10, 10, 0, "Specify the number of processing passes on the embeddings"); + uiDefButC(block, ROW, B_DIFF, "Smooth", 1087, 70, 63,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_SMOOTH, 0, 0, "Smooth embeddings"); + uiDefButC(block, ROW, B_DIFF, "Average", 1150, 70, 62,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_AVERAGE, 0, 0, "Average embeddings"); + uiDefButC(block, ROW, B_DIFF, "Sharpen", 1212, 70, 63,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_SHARPEN, 0, 0, "Sharpen embeddings"); + + uiBlockEndAlign(block); +} + +static void editing_panel_mesh_skgen_display(Object *ob, Mesh *me) +{ + uiBlock *block; + uiBut *but; + + block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_skgen_display", UI_EMBOSS, UI_HELV, curarea->win); + uiNewPanelTabbed("Mesh Tools More", "Skgen"); + if(uiNewPanel(curarea, block, "Graph", "Editing", 960, 0, 318, 204)==0) return; + + but = uiDefBut(block, BUT, B_DIFF, "Generate", 1025,170,125,19, 0, 0, 0, 0, 0, "Generate Graph from Mesh"); + uiButSetFunc(but, skgen_graphgen, NULL, NULL); + but = uiDefBut(block, BUT, B_DIFF, "Free", 1150,170,125,19, 0, 0, 0, 0, 0, "Free Graph from Mesh"); + uiButSetFunc(but, skgen_graphfree, NULL, NULL); + + skgen_graph_block(block); + + uiBlockBeginAlign(block); + uiDefButBitS(block, TOG, SKGEN_DISP_LENGTH, REDRAWVIEW3D, "Length", 1025, 40, 50,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Show Length"); + uiDefButBitS(block, TOG, SKGEN_DISP_WEIGHT, REDRAWVIEW3D, "Weight", 1075, 40, 50,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Show Weight"); + uiDefButBitS(block, TOG, SKGEN_DISP_EMBED, REDRAWVIEW3D, "Embed", 1125, 40, 50,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Show Arc Embedings"); + uiDefButBitS(block, TOG, SKGEN_DISP_INDEX, REDRAWVIEW3D, "Index", 1175, 40, 50,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Show Arc and Node indexes"); + uiDefButBitS(block, TOG, SKGEN_DISP_ORIG, REDRAWVIEW3D, "Original", 1225, 40, 50,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Show Original Graph"); + + uiBlockEndAlign(block); + + uiDefButC(block, NUM, REDRAWVIEW3D, "Level:", 1025, 20, 125,19, &G.scene->toolsettings->skgen_multi_level, 0, REEB_MAX_MULTI_LEVEL, 1, 0,"Specify the level to draw"); +} + +static void editing_panel_mesh_skgen_retarget(Object *ob, Mesh *me) +{ + uiBlock *block; + uiBut *but; + + block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_skgen_retarget", UI_EMBOSS, UI_HELV, curarea->win); + uiNewPanelTabbed("Mesh Tools More", "Skgen"); + if(uiNewPanel(curarea, block, "Retarget", "Editing", 960, 0, 318, 204)==0) return; + + uiDefBut(block, BUT, B_RETARGET_SKELETON, "Retarget Skeleton", 1025,170,100,19, 0, 0, 0, 0, 0, "Retarget Selected Armature to this Mesh"); + but = uiDefBut(block, BUT, B_DIFF, "Adjust", 1125,170,100,19, 0, 0, 0, 0, 0, "Adjust Retarget using new weights"); + uiButSetFunc(but, skgen_rigadjust, NULL, NULL); + but = uiDefBut(block, BUT, B_DIFF, "Free", 1225,170,50,19, 0, 0, 0, 0, 0, "Free Retarget structure"); + uiButSetFunc(but, skgen_rigfree, NULL, NULL); + + skgen_graph_block(block); + + 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) { uiBlock *block; @@ -5157,20 +5262,17 @@ static void editing_panel_mesh_skgen(Object *ob, Mesh *me) int i; block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_skgen", UI_EMBOSS, UI_HELV, curarea->win); - if(uiNewPanel(curarea, block, "Skeleton Generator", "Editing", 960, 0, 318, 204)==0) return; + uiNewPanelTabbed("Mesh Tools More", "Skgen"); + if(uiNewPanel(curarea, block, "Generator", "Editing", 960, 0, 318, 204)==0) return; - uiDefBut(block, BUT, B_GEN_SKELETON, "Generate Skeleton", 1025,170,250,19, 0, 0, 0, 0, 0, "Generate Skeleton from Mesh"); + uiDefBut(block, BUT, B_GEN_SKELETON, "Generate", 1025,170,250,19, 0, 0, 0, 0, 0, "Generate Skeleton from Mesh"); - uiBlockBeginAlign(block); - uiDefButS(block, NUM, B_DIFF, "Resolution:", 1025,150,250,19, &G.scene->toolsettings->skgen_resolution,10.0,1000.0, 0, 0, "Specifies the resolution of the graph's embedding"); - uiDefButBitS(block, TOG, SKGEN_FILTER_INTERNAL, B_DIFF, "Filter In", 1025,130, 83,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Filter internal small arcs from graph"); - uiDefButF(block, NUM, B_DIFF, "T:", 1111,130,164,19, &G.scene->toolsettings->skgen_threshold_internal,0.0, 1.0, 10, 0, "Specify the threshold ratio for filtering internal arcs"); - uiDefButBitS(block, TOG, SKGEN_FILTER_EXTERNAL, B_DIFF, "Filter Ex", 1025,110, 83,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Filter external small arcs from graph"); - uiDefButF(block, NUM, B_DIFF, "T:", 1111,110,164,19, &G.scene->toolsettings->skgen_threshold_external,0.0, 1.0, 10, 0, "Specify the threshold ratio for filtering external arcs"); + skgen_graph_block(block); + uiBlockBeginAlign(block); for(i = 0; i < SKGEN_SUB_TOTAL; i++) { - int y = 90 - 20 * i; + int y = 50 - 20 * i; but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_MOVE_DOWN, 1025, y, 16, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Change the order the subdivisions algorithm are applied"); uiButSetFunc(but, skgen_reorder, SET_INT_IN_POINTER(i), NULL); @@ -5187,18 +5289,14 @@ static void editing_panel_mesh_skgen(Object *ob, Mesh *me) uiDefButF(block, NUM, B_DIFF, "T:", 1111, y,164,19, &G.scene->toolsettings->skgen_angle_limit,0.0, 90.0, 10, 0, "Specify the threshold angle in degrees for subdivision"); break; case SKGEN_SUB_CORRELATION: - uiDefButBitS(block, TOG, SKGEN_CUT_CORRELATION, B_DIFF, "Correlation", 1041, y, 67,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Subdivide arcs based on correlation"); - uiDefButF(block, NUM, B_DIFF, "T:", 1111, y,164,19, &G.scene->toolsettings->skgen_correlation_limit,0.0, 1.0, 0.01, 0, "Specify the threshold correlation for subdivision"); + uiDefButBitS(block, TOG, SKGEN_CUT_CORRELATION, B_DIFF, "Adaptative", 1041, y, 67,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Subdivide arcs adaptatively"); + uiDefButF(block, NUM, B_DIFF, "T:", 1111, y,114,19, &G.scene->toolsettings->skgen_correlation_limit,0.0, 1.0, 0.01, 0, "Specify the adaptive threshold for subdivision"); + uiDefButBitS(block, TOG, SKGEN_STICK_TO_EMBEDDING, B_DIFF, "E", 1225, y, 25,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Stick endpoint to embedding"); + uiDefButBitS(block, TOG, SKGEN_ADAPTIVE_DISTANCE, B_DIFF, "D", 1250, y, 25,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Adaptive distance (on) or variance(off)"); break; } } - uiDefButBitS(block, TOG, SKGEN_SYMMETRY, B_DIFF, "Symmetry", 1025, 30,125,19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0, "Restore symmetries based on topology"); - uiDefButF(block, NUM, B_DIFF, "T:", 1150, 30,125,19, &G.scene->toolsettings->skgen_symmetry_limit,0.0, 1.0, 10, 0, "Specify the threshold distance for considering potential symmetric arcs"); - uiDefButC(block, NUM, B_DIFF, "P:", 1025, 10, 62,19, &G.scene->toolsettings->skgen_postpro_passes, 0, 10, 10, 0, "Specify the number of processing passes on the embeddings"); - uiDefButC(block, ROW, B_DIFF, "Smooth", 1087, 10, 63,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_SMOOTH, 0, 0, "Smooth embeddings"); - uiDefButC(block, ROW, B_DIFF, "Average", 1150, 10, 62,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_AVERAGE, 0, 0, "Average embeddings"); - uiDefButC(block, ROW, B_DIFF, "Sharpen", 1212, 10, 63,19, &G.scene->toolsettings->skgen_postpro, 5.0, (float)SKGEN_SHARPEN, 0, 0, "Sharpen embeddings"); uiBlockEndAlign(block); } @@ -5741,11 +5839,11 @@ void sculptmode_draw_interface_textures(uiBlock *block, unsigned short cx, unsig for(i=-1; i<8; i++) { char str[64]; int loos; - mtex= sd->mtex[i]; if(i==-1) strcpy(str, "Default"); else { + mtex= sd->mtex[i]; if(mtex && mtex->tex) splitIDname(mtex->tex->id.name+2, str, &loos); else strcpy(str, ""); } @@ -5756,13 +5854,15 @@ void sculptmode_draw_interface_textures(uiBlock *block, unsigned short cx, unsig cy= orig_y-20; cx+= 85; - mtex= sd->mtex[sd->texact]; if(sd->texact == -1) { uiBlockBeginAlign(block); uiDefBut(block,LABEL,B_NOP,"",cx,cy,115,20,0,0,0,0,0,""); /* Padding */ } else { - ID *id= NULL; + ID *id = NULL; + + mtex= sd->mtex[sd->texact]; + uiBlockBeginAlign(block); if(mtex && mtex->tex) id= &mtex->tex->id; @@ -6623,8 +6723,11 @@ void editing_panels() editing_panel_mesh_tools1(ob, ob->data); uiNewPanelTabbed("Mesh Tools 1", "Editing"); - if (G.rt == 42) /* hidden for now, no time for docs */ - editing_panel_mesh_skgen(ob, ob->data); + #ifdef WITH_BF_REEB + editing_panel_mesh_skgen(ob, ob->data); + editing_panel_mesh_skgen_retarget(ob, ob->data); + editing_panel_mesh_skgen_display(ob, ob->data); + #endif editing_panel_mesh_uvautocalculation(); if (EM_texFaceCheck()) diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c index 0dcdc36fdcd..8aca111f41f 100644 --- a/source/blender/src/buttons_logic.c +++ b/source/blender/src/buttons_logic.c @@ -3549,7 +3549,7 @@ void logic_buts(void) if(ob->controllers.first) uiSetCurFont(block, UI_HELV); uiDefButBitS(block, TOG, OB_ADDCONT, B_ADD_CONT, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Controller"); uiBlockEndAlign(block); - yco-=17; + yco-=20; /* mark all actuators linked to these controllers */ /* note that some of these actuators could be from objects that are not in the display list. diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index 763038adaae..748524f2fc8 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -152,7 +152,10 @@ #include "BSE_edit.h" #include "BDR_editobject.h" + +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif #include "butspace.h" // own module @@ -643,6 +646,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s } else { switch (con->type) { +#ifndef DISABLE_PYTHON case CONSTRAINT_TYPE_PYTHON: { bPythonConstraint *data = con->data; @@ -724,6 +728,7 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s draw_constraint_spaceselect(block, con, *xco, *yco-(73+theight), is_armature_owner(ob), -1); } break; +#endif /* DISABLE_PYTHON */ case CONSTRAINT_TYPE_ACTION: { bActionConstraint *data = con->data; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 3e5f5305033..55475e74450 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -286,6 +286,7 @@ void do_texbuts(unsigned short event) scrarea_queue_headredraw(curarea); BIF_preview_changed(ID_TE); allqueue(REDRAWBUTSSHADING, 0); + allqueue(REDRAWNODE, 0); if(G.buts->texfrom == 3) /* brush texture */ allqueue(REDRAWIMAGE, 0); break; @@ -414,6 +415,16 @@ void do_texbuts(unsigned short event) } } break; + case B_TEX_USENODES: + if(tex->use_nodes && tex->nodetree==NULL) { + node_texture_default(tex); + } + tex->type = 0; + BIF_preview_changed(ID_TE); + allqueue(REDRAWNODE, 0); + allqueue(REDRAWBUTSSHADING, 0); + allqueue(REDRAWIPO, 0); + break; default: if(event>=B_PLUGBUT && event<=B_PLUGBUT+23) { @@ -1848,11 +1859,13 @@ static void texture_panel_texture(MTex *actmtex, Material *ma, World *wrld, Lamp /* newnoise: all texture types as menu, not enough room for more buttons. * Can widen panel, but looks ugly when other panels overlap it */ + if( !tex->use_nodes ) { + sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|Point Density %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_POINTDENSITY); + uiDefBut(block, LABEL, 0, "Texture Type", 160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, ""); + uiDefButS(block, MENU, B_TEXTYPE, textypes, 160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type"); + } - sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|Point Density %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_POINTDENSITY); - uiDefBut(block, LABEL, 0, "Texture Type", 160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, ""); - uiDefButS(block, MENU, B_TEXTYPE, textypes, 160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type"); - + uiDefButC(block, TOG, B_TEX_USENODES, "Nodes", 160, 100, 140, 25, &tex->use_nodes, 0.0f, 0.0f, 0, 0, ""); } else { // label to avoid centering @@ -3860,6 +3873,12 @@ static void material_panel_texture(Object *ob, Material *ma) uiBlockSetCol(block, TH_AUTO); uiDefBut(block, BUT, B_TEXCLEAR, "Clear", 122, 130, 72, 20, 0, 0, 0, 0, 0, "Erases link to texture"); + if(mtex->tex->use_nodes) { + char *menustr = ntreeTexOutputMenu(mtex->tex->nodetree); + uiDefBut(block, LABEL, 0, "Use Output:", 100, 100, 163, 20, 0, 0, 0, 0, 0, ""); + uiDefButS(block, MENU, B_MATPRV, menustr, 100, 80, 163, 20, &mtex->which_output, 0, 0, 0, 0, "Which output to use, for multi-output textures"); + free(menustr); + } } else uiDefButS(block, TOG, B_EXTEXBROWSE, "Add New" ,100, 150, 163, 20, &(G.buts->texnr), -1.0, 32767.0, 0, 0, "Adds a new texture datablock"); diff --git a/source/blender/src/drawipo.c b/source/blender/src/drawipo.c index aee00baef8e..973782d7463 100644 --- a/source/blender/src/drawipo.c +++ b/source/blender/src/drawipo.c @@ -86,7 +86,9 @@ #include "BSE_editnla_types.h" #include "BSE_time.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif #include "mydevice.h" #include "blendef.h" @@ -1925,6 +1927,7 @@ void do_ipobuts(unsigned short event) ei= get_active_editipo(); if(ei) { if(ei->icu->driver) { +#ifndef DISABLE_PYTHON if (ei->icu->driver->type == IPO_DRIVER_TYPE_PYTHON) { /* first del pydriver's global dict, just in case * an available pydrivers.py module needs to be reloaded */ @@ -1933,7 +1936,9 @@ void do_ipobuts(unsigned short event) BPY_pydriver_eval(ei->icu->driver); DAG_scene_sort(G.scene); } - else if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC) + else +#endif + if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC) DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); else DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c index 7decec3f0e3..04407b8500a 100644 --- a/source/blender/src/drawnode.c +++ b/source/blender/src/drawnode.c @@ -451,6 +451,9 @@ static void node_browse_tex_cb(void *ntree_v, void *node_v) nodeSetActive(ntree, node); + if( ntree->type == NTREE_TEXTURE ) + ntreeTexCheckCyclics( ntree ); + allqueue(REDRAWBUTSSHADING, 0); allqueue(REDRAWNODE, 0); NodeTagChanged(ntree, node); @@ -491,29 +494,45 @@ static void node_dynamic_update_cb(void *ntree_v, void *node_v) static int node_buts_texture(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) { + short multi = ( + node->id && + ((Tex*)node->id)->use_nodes && + (node->type != CMP_NODE_TEXTURE) && + (node->type != TEX_NODE_TEXTURE) + ); + if(block) { uiBut *bt; char *strp; + short width = (short)(butr->xmax - butr->xmin); /* browse button texture */ uiBlockBeginAlign(block); IDnames_to_pupstring(&strp, NULL, "", &(G.main->tex), NULL, NULL); node->menunr= 0; bt= uiDefButS(block, MENU, B_NODE_EXEC+node->nr, strp, - butr->xmin, butr->ymin, 20, 19, + butr->xmin, butr->ymin+(multi?30:0), 20, 19, &node->menunr, 0, 0, 0, 0, "Browse texture"); uiButSetFunc(bt, node_browse_tex_cb, ntree, node); if(strp) MEM_freeN(strp); if(node->id) { bt= uiDefBut(block, TEX, B_NOP, "TE:", - butr->xmin+19, butr->ymin, butr->xmax-butr->xmin-19, 19, + butr->xmin+19, butr->ymin+(multi?30:0), butr->xmax-butr->xmin-19, 19, node->id->name+2, 0.0, 19.0, 0, 0, "Texture name"); uiButSetFunc(bt, node_ID_title_cb, node, NULL); } + uiBlockEndAlign(block); + if(multi) { + char *menustr = ntreeTexOutputMenu(((Tex*)node->id)->nodetree); + uiDefButS(block, MENU, B_MATPRV, menustr, butr->xmin, butr->ymin, width, 19, &node->custom1, 0, 0, 0, 0, "Which output to use, for multi-output textures"); + free(menustr); + return 50; + } + return 20; } - return 19; + else return multi? 50: 20; } static int node_buts_math(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) @@ -2183,6 +2202,261 @@ static void node_composit_set_butfunc(bNodeType *ntype) } } +/* ****************** BUTTON CALLBACKS FOR TEXTURE NODES ***************** */ + +static int node_texture_buts_bricks(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +{ + if(block) { + short w = butr->xmax-butr->xmin; + short ofw = 32; + + uiBlockBeginAlign(block); + + /* Offset */ + uiDefButF( + block, NUM, B_NODE_EXEC+node->nr, "Offset", + butr->xmin, butr->ymin+20, w-ofw, 20, + &node->custom3, + 0, 1, 0.25, 2, + "Offset amount" ); + uiDefButS( + block, NUM, B_NODE_EXEC+node->nr, "", + butr->xmin+w-ofw, butr->ymin+20, ofw, 20, + &node->custom1, + 2, 99, 0, 0, + "Offset every N rows" ); + + /* Squash */ + uiDefButF( + block, NUM, B_NODE_EXEC+node->nr, "Squash", + butr->xmin, butr->ymin+0, w-ofw, 20, + &node->custom4, + 0, 99, 0.25, 2, + "Stretch amount" ); + uiDefButS( + block, NUM, B_NODE_EXEC+node->nr, "", + butr->xmin+w-ofw, butr->ymin+0, ofw, 20, + &node->custom2, + 2, 99, 0, 0, + "Stretch every N rows" ); + + uiBlockEndAlign(block); + } + return 40; +} + +/* Copied from buttons_shading.c -- needs unifying */ +static char* noisebasis_menu() +{ + static char nbmenu[256]; + sprintf(nbmenu, "Noise Basis %%t|Blender Original %%x%d|Original Perlin %%x%d|Improved Perlin %%x%d|Voronoi F1 %%x%d|Voronoi F2 %%x%d|Voronoi F3 %%x%d|Voronoi F4 %%x%d|Voronoi F2-F1 %%x%d|Voronoi Crackle %%x%d|CellNoise %%x%d", TEX_BLENDER, TEX_STDPERLIN, TEX_NEWPERLIN, TEX_VORONOI_F1, TEX_VORONOI_F2, TEX_VORONOI_F3, TEX_VORONOI_F4, TEX_VORONOI_F2F1, TEX_VORONOI_CRACKLE, TEX_CELLNOISE); + return nbmenu; +} + +static int node_texture_buts_proc(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +{ + Tex *tex = (Tex *)node->storage; + short x,y,w,h; + + if( block ) { + x = butr->xmin; + y = butr->ymin; + w = butr->xmax - x; + h = butr->ymax - y; + } + + switch( tex->type ) { + case TEX_BLEND: + if( block ) { + uiBlockBeginAlign( block ); + uiDefButS( block, MENU, B_NODE_EXEC+node->nr, + "Linear %x0|Quad %x1|Ease %x2|Diag %x3|Sphere %x4|Halo %x5|Radial %x6", + x, y+20, w, 20, &tex->stype, 0, 1, 0, 0, "Blend Type" ); + uiDefButBitS(block, TOG, TEX_FLIPBLEND, B_NODE_EXEC+node->nr, "Flip XY", x, y, w, 20, + &tex->flag, 0, 0, 0, 0, "Flips the direction of the progression 90 degrees"); + uiBlockEndAlign( block ); + } + return 40; + + + case TEX_MARBLE: + if( block ) { + uiBlockBeginAlign(block); + + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Soft", 0*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SOFT, 0, 0, "Uses soft marble"); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Sharp", 1*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SHARP, 0, 0, "Uses more clearly defined marble"); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Sharper", 2*w/3+x, 40+y, w/3, 18, &tex->stype, 2.0, (float)TEX_SHARPER, 0, 0, "Uses very clearly defined marble"); + + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Soft noise", 0*w/2+x, 20+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Hard noise", 1*w/2+x, 20+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); + + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Sin", 0*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 0.0, 0, 0, "Uses a sine wave to produce bands."); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Saw", 1*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 1.0, 0, 0, "Uses a saw wave to produce bands"); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Tri", 2*w/3+x, 0+y, w/3, 18, &tex->noisebasis2, 8.0, 2.0, 0, 0, "Uses a triangle wave to produce bands"); + + uiBlockEndAlign(block); + } + return 60; + + case TEX_WOOD: + if( block ) { + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+64, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence"); + + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_TEXPRV, "Bands", x, 40+y, w/2, 18, &tex->stype, 2.0, (float)TEX_BANDNOISE, 0, 0, "Uses standard noise"); + uiDefButS(block, ROW, B_TEXPRV, "Rings", w/2+x, 40+y, w/2, 18, &tex->stype, 2.0, (float)TEX_RINGNOISE, 0, 0, "Lets Noise return RGB value"); + + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Sin", 0*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_SIN, 0, 0, "Uses a sine wave to produce bands."); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Saw", 1*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_SAW, 0, 0, "Uses a saw wave to produce bands"); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Tri", 2*w/3+x, 20+y, w/3, 18, &tex->noisebasis2, 8.0, (float)TEX_TRI, 0, 0, "Uses a triangle wave to produce bands"); + + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Soft noise", 0*w/2+x, 0+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); + uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Hard noise", 1*w/2+x, 0+y, w/2, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); + uiBlockEndAlign(block); + } + return 80; + + case TEX_CLOUDS: + if( block ) { + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+60, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence"); + + uiBlockBeginAlign(block); + uiDefButS(block, ROW, B_TEXPRV, "B/W", x, y+38, w/2, 18, &tex->stype, 2.0, (float)TEX_DEFAULT, 0, 0, "Uses standard noise"); + uiDefButS(block, ROW, B_TEXPRV, "Color", w/2+x, y+38, w/2, 18, &tex->stype, 2.0, (float)TEX_COLOR, 0, 0, "Lets Noise return RGB value"); + uiDefButS(block, ROW, B_TEXPRV, "Soft", x, y+20, w/2, 18, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise"); + uiDefButS(block, ROW, B_TEXPRV, "Hard", w/2+x, y+20, w/2, 18, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise"); + uiBlockEndAlign(block); + + uiDefButS(block, NUM, B_TEXPRV, "Depth:", x, y, w, 18, &tex->noisedepth, 0.0, 6.0, 0, 0, "Sets the depth of the cloud calculation"); + } + return 80; + + case TEX_DISTNOISE: + if( block ) { + uiBlockBeginAlign(block); + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y+18, w, 18, &tex->noisebasis2, 0,0,0,0, "Sets the noise basis to distort"); + uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), x, y, w, 18, &tex->noisebasis, 0,0,0,0, "Sets the noise basis which does the distortion"); + uiBlockEndAlign(block); + } + return 36; + } + return 0; +} + +static int node_texture_buts_image(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +{ + char *strp; + uiBut *bt; + + if( block ) { + uiBlockBeginAlign(block); + uiBlockSetCol(block, TH_BUT_SETTING2); + + /* browse button */ + IMAnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL); + node->menunr= 0; + bt= uiDefButS(block, MENU, B_NOP, strp, + butr->xmin, butr->ymin, 19, 19, + &node->menunr, 0, 0, 0, 0, "Browses existing choices"); + uiButSetFunc(bt, node_browse_image_cb, ntree, node); + if(strp) MEM_freeN(strp); + + /* Add New button */ + if(node->id==NULL) { + bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New", + butr->xmin+19, butr->ymin, (short)(butr->xmax-butr->xmin-19.0f), 19, + NULL, 0.0, 0.0, 0, 0, "Add new Image"); + uiButSetFunc(bt, node_active_cb, ntree, node); + uiBlockSetCol(block, TH_AUTO); + } + else { + /* name button */ + short xmin= (short)butr->xmin, xmax= (short)butr->xmax; + short width= xmax - xmin - 19; + + bt= uiDefBut(block, TEX, B_NOP, "IM:", + xmin+19, butr->ymin, width, 19, + node->id->name+2, 0.0, 19.0, 0, 0, "Image name"); + uiButSetFunc(bt, node_ID_title_cb, node, NULL); + } + } + return 20; +} + +static int node_texture_buts_output(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) +{ + if( block ) { + uiBut *bt; + short width; + char *name = ((TexNodeOutput*)node->storage)->name; + + uiBlockBeginAlign(block); + + width = (short)(butr->xmax - butr->xmin); + + bt = uiDefBut( + block, TEX, B_NOP, + "Name:", + butr->xmin, butr->ymin, + width, 19, + name, 0, 31, + 0, 0, + "Name this output" + ); + + uiBlockEndAlign(block); + } + return 19; +} + +/* only once called */ +static void node_texture_set_butfunc(bNodeType *ntype) +{ + if( ntype->type >= TEX_NODE_PROC && ntype->type < TEX_NODE_PROC_MAX ) { + ntype->butfunc = node_texture_buts_proc; + } + else switch(ntype->type) { + + case TEX_NODE_MATH: + ntype->butfunc = node_buts_math; + break; + + case TEX_NODE_MIX_RGB: + ntype->butfunc = node_buts_mix_rgb; + break; + + case TEX_NODE_VALTORGB: + ntype->butfunc = node_buts_valtorgb; + break; + + case TEX_NODE_CURVE_RGB: + ntype->butfunc= node_buts_curvecol; + break; + + case TEX_NODE_CURVE_TIME: + ntype->butfunc = node_buts_time; + break; + + case TEX_NODE_TEXTURE: + ntype->butfunc = node_buts_texture; + break; + + case TEX_NODE_BRICKS: + ntype->butfunc = node_texture_buts_bricks; + break; + + case TEX_NODE_IMAGE: + ntype->butfunc = node_texture_buts_image; + break; + + case TEX_NODE_OUTPUT: + ntype->butfunc = node_texture_buts_output; + break; + + default: + ntype->butfunc= NULL; + } +} /* ******* init draw callbacks for all tree types, only called in usiblender.c, once ************* */ @@ -2202,6 +2476,11 @@ void init_node_butfuncs(void) node_composit_set_butfunc(ntype); ntype= ntype->next; } + ntype = node_all_textures.first; + while(ntype) { + node_texture_set_butfunc(ntype); + ntype= ntype->next; + } } /* ************** Generic drawing ************** */ diff --git a/source/blender/src/drawscript.c b/source/blender/src/drawscript.c index c744449d1db..f9e2d138a78 100644 --- a/source/blender/src/drawscript.c +++ b/source/blender/src/drawscript.c @@ -55,7 +55,9 @@ #include "BKE_global.h" #include "BKE_main.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif #include "BIF_gl.h" #include "BIF_keyval.h" @@ -87,6 +89,9 @@ void drawscriptspace(ScrArea *sa, void *spacedata) glClear(GL_COLOR_BUFFER_BIT); myortho2(-0.5, curarea->winrct.xmax-curarea->winrct.xmin-0.5, -0.5, curarea->winrct.ymax-curarea->winrct.ymin-0.5); +#ifdef DISABLE_PYTHON + return; +#else if (!sc->script) return; script = sc->script; @@ -115,10 +120,12 @@ void drawscriptspace(ScrArea *sa, void *spacedata) addqueue(curarea->win, MOUSEX, 0); } } +#endif /* DISABLE_PYTHON */ } void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt) { +#ifndef DISABLE_PYTHON unsigned short event = evt->event; short val = evt->val; char ascii = evt->ascii; @@ -163,19 +170,21 @@ void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent * if (event == QKEY) if (val && (G.qual & LR_CTRLKEY) && okee("Quit Blender")) exit_usiblender(); } - +#endif return; + } void free_scriptspace (SpaceScript *sc) { if (!sc) return; - +#ifndef DISABLE_PYTHON /*free buttons references*/ if (sc->but_refs) { BPy_Set_DrawButtonsList(sc->but_refs); BPy_Free_DrawButtonsList(); sc->but_refs = NULL; } +#endif sc->script = NULL; } diff --git a/source/blender/src/drawtext.c b/source/blender/src/drawtext.c index ca1f6cff202..1c8380c7a7d 100644 --- a/source/blender/src/drawtext.c +++ b/source/blender/src/drawtext.c @@ -71,8 +71,10 @@ #include "BSE_filesel.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "mydevice.h" #include "blendef.h" @@ -1841,7 +1843,8 @@ void unlink_text(Text *text) bScreen *scr; ScrArea *area; SpaceLink *sl; - + +#ifndef DISABLE_PYTHON /* check if this text was used as script link: * this check function unsets the pointers and returns how many * script links used this Text */ @@ -1852,7 +1855,8 @@ void unlink_text(Text *text) if (nodeDynamicUnlinkText ((ID*)text)) { allqueue(REDRAWNODE, 0); } - +#endif + for (scr= G.main->screen.first; scr; scr= scr->id.next) { for (area= scr->areabase.first; area; area= area->next) { for (sl= area->spacedata.first; sl; sl= sl->next) { @@ -2050,7 +2054,9 @@ void run_python_script(SpaceText *st) { Text *text=st->text; char *py_filename; - +#ifdef DISABLE_PYTHON + error("python disabled in this build"); +#else if (!BPY_txt_do_python_Text(text)) { int lineno = BPY_Err_getLinenumber(); // jump to error if happened in current text: @@ -2072,6 +2078,7 @@ void run_python_script(SpaceText *st) "check console"); } } +#endif } static void set_tabs(Text *text) @@ -2929,8 +2936,10 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt) break; /* BREAK Q */ case RKEY: if (G.qual == LR_ALTKEY) { +#ifndef DISABLE_PYTHON if (text->compiled) BPY_free_compiled_text(text); text->compiled = NULL; +#endif if (okee("Reopen text")) { if (!reopen_text(text)) error("Could not reopen file"); @@ -3199,13 +3208,14 @@ void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt) } } +#ifndef DISABLE_PYTHON /* Run text plugin scripts if enabled */ if (st->doplugins && event && val) { if (BPY_menu_do_shortcut(PYMENU_TEXTPLUGIN, event, G.qual)) { do_draw= 1; } } - +#endif if (do_draw) redraw_alltext(); } diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c index 8f2623575aa..de3e464060d 100644 --- a/source/blender/src/drawview.c +++ b/source/blender/src/drawview.c @@ -153,7 +153,9 @@ #include "BSE_time.h" #include "BSE_view.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif #include "RE_render_ext.h" @@ -165,6 +167,8 @@ #include "RE_pipeline.h" // make_stars +#include "reeb.h" + #include "GPU_draw.h" #include "GPU_material.h" @@ -3238,6 +3242,8 @@ void drawview3dspace(ScrArea *sa, void *spacedata) BIF_drawPropCircle(); // only editmode and particles have proportional edit BIF_drawSnap(); } + + REEB_draw(); if(G.scene->radio) RAD_drawall(v3d->drawtype>=OB_SOLID); @@ -3350,6 +3356,7 @@ void drawview3dspace(ScrArea *sa, void *spacedata) } } +#ifndef DISABLE_PYTHON /* run any view3d draw handler script links */ if (sa->scriptlink.totscript) BPY_do_spacehandlers(sa, 0, 0, SPACEHANDLER_VIEW3D_DRAW); @@ -3359,7 +3366,7 @@ void drawview3dspace(ScrArea *sa, void *spacedata) !during_script()) { BPY_do_pyscript((ID *)G.scene, SCRIPT_REDRAW); } - +#endif } void drawview3d_render(struct View3D *v3d, float viewmat[][4], int winx, int winy, float winmat[][4], int shadow) diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 0b8c1339dae..ee5d56eaf43 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -1817,6 +1817,31 @@ void deselectall_armature(int toggle, int doundo) } } +/* adjust bone roll to align Z axis with vector + * vec is in local space and is normalized + */ +float rollBoneToVector(EditBone *bone, float new_up_axis[3]) +{ + float mat[3][3], nor[3], up_axis[3], vec[3]; + float roll; + + VecSubf(nor, bone->tail, bone->head); + + vec_roll_to_mat3(nor, 0, mat); + VECCOPY(up_axis, mat[2]); + + roll = NormalizedVecAngle2(new_up_axis, up_axis); + + Crossf(vec, up_axis, new_up_axis); + + if (Inpf(vec, nor) < 0) + { + roll = -roll; + } + + return roll; +} + /* Sets the roll value of selected bones, depending on the mode * mode == 0: their z-axes point upwards * mode == 1: their z-axes point towards 3d-cursor @@ -4514,542 +4539,7 @@ void transform_armature_mirror_update(void) /*************************************** SKELETON GENERATOR ******************************************/ /*****************************************************************************************************/ -/**************************************** SYMMETRY HANDLING ******************************************/ - -void markdownSymmetryArc(ReebArc *arc, ReebNode *node, int level); - -void mirrorAlongAxis(float v[3], float center[3], float axis[3]) -{ - float dv[3], pv[3]; - - VecSubf(dv, v, center); - Projf(pv, dv, axis); - VecMulf(pv, -2); - VecAddf(v, v, pv); -} - -/* Helper structure for radial symmetry */ -typedef struct RadialArc -{ - ReebArc *arc; - float n[3]; /* normalized vector joining the nodes of the arc */ -} RadialArc; - -void reestablishRadialSymmetry(ReebNode *node, int depth, float axis[3]) -{ - RadialArc *ring = NULL; - RadialArc *unit; - float limit = G.scene->toolsettings->skgen_symmetry_limit; - int symmetric = 1; - int count = 0; - int i; - - /* count the number of arcs in the symmetry ring */ - for (i = 0; node->arcs[i] != NULL; i++) - { - ReebArc *connectedArc = node->arcs[i]; - - /* depth is store as a negative in flag. symmetry level is positive */ - if (connectedArc->flags == -depth) - { - count++; - } - } - - ring = MEM_callocN(sizeof(RadialArc) * count, "radial symmetry ring"); - unit = ring; - - /* fill in the ring */ - for (unit = ring, i = 0; node->arcs[i] != NULL; i++) - { - ReebArc *connectedArc = node->arcs[i]; - - /* depth is store as a negative in flag. symmetry level is positive */ - if (connectedArc->flags == -depth) - { - ReebNode *otherNode = OTHER_NODE(connectedArc, node); - float vec[3]; - - unit->arc = connectedArc; - - /* project the node to node vector on the symmetry plane */ - VecSubf(unit->n, otherNode->p, node->p); - Projf(vec, unit->n, axis); - VecSubf(unit->n, unit->n, vec); - - Normalize(unit->n); - - unit++; - } - } - - /* sort ring */ - for (i = 0; i < count - 1; i++) - { - float minAngle = 3; /* arbitrary high value, higher than 2, at least */ - int minIndex = -1; - int j; - - for (j = i + 1; j < count; j++) - { - float angle = Inpf(ring[i].n, ring[j].n); - - /* map negative values to 1..2 */ - if (angle < 0) - { - angle = 1 - angle; - } - - if (angle < minAngle) - { - minIndex = j; - minAngle = angle; - } - } - - /* swap if needed */ - if (minIndex != i + 1) - { - RadialArc tmp; - tmp = ring[i + 1]; - ring[i + 1] = ring[minIndex]; - ring[minIndex] = tmp; - } - } - - for (i = 0; i < count && symmetric; i++) - { - ReebNode *node1, *node2; - float tangent[3]; - float normal[3]; - float p[3]; - int j = (i + 1) % count; /* next arc in the circular list */ - - VecAddf(tangent, ring[i].n, ring[j].n); - Crossf(normal, tangent, axis); - - node1 = OTHER_NODE(ring[i].arc, node); - node2 = OTHER_NODE(ring[j].arc, node); - - VECCOPY(p, node2->p); - mirrorAlongAxis(p, node->p, normal); - - /* check if it's within limit before continuing */ - if (VecLenf(node1->p, p) > limit) - { - symmetric = 0; - } - - } - - if (symmetric) - { - /* first pass, merge incrementally */ - for (i = 0; i < count - 1; i++) - { - ReebNode *node1, *node2; - float tangent[3]; - float normal[3]; - int j = i + 1; - - VecAddf(tangent, ring[i].n, ring[j].n); - Crossf(normal, tangent, axis); - - node1 = OTHER_NODE(ring[i].arc, node); - node2 = OTHER_NODE(ring[j].arc, node); - - /* mirror first node and mix with the second */ - mirrorAlongAxis(node1->p, node->p, normal); - VecLerpf(node2->p, node2->p, node1->p, 1.0f / (j + 1)); - - /* Merge buckets - * there shouldn't be any null arcs here, but just to be safe - * */ - if (ring[i].arc->bcount > 0 && ring[j].arc->bcount > 0) - { - ReebArcIterator iter1, iter2; - EmbedBucket *bucket1 = NULL, *bucket2 = NULL; - - initArcIterator(&iter1, ring[i].arc, node); - initArcIterator(&iter2, ring[j].arc, node); - - bucket1 = nextBucket(&iter1); - bucket2 = nextBucket(&iter2); - - /* Make sure they both start at the same value */ - while(bucket1 && bucket1->val < bucket2->val) - { - bucket1 = nextBucket(&iter1); - } - - while(bucket2 && bucket2->val < bucket1->val) - { - bucket2 = nextBucket(&iter2); - } - - - for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2)) - { - bucket2->nv += bucket1->nv; /* add counts */ - - /* mirror on axis */ - mirrorAlongAxis(bucket1->p, node->p, normal); - /* add bucket2 in bucket1 */ - VecLerpf(bucket2->p, bucket2->p, bucket1->p, (float)bucket1->nv / (float)(bucket2->nv)); - } - } - } - - /* second pass, mirror back on previous arcs */ - for (i = count - 1; i > 0; i--) - { - ReebNode *node1, *node2; - float tangent[3]; - float normal[3]; - int j = i - 1; - - VecAddf(tangent, ring[i].n, ring[j].n); - Crossf(normal, tangent, axis); - - node1 = OTHER_NODE(ring[i].arc, node); - node2 = OTHER_NODE(ring[j].arc, node); - - /* copy first node than mirror */ - VECCOPY(node2->p, node1->p); - mirrorAlongAxis(node2->p, node->p, normal); - - /* Copy buckets - * there shouldn't be any null arcs here, but just to be safe - * */ - if (ring[i].arc->bcount > 0 && ring[j].arc->bcount > 0) - { - ReebArcIterator iter1, iter2; - EmbedBucket *bucket1 = NULL, *bucket2 = NULL; - - initArcIterator(&iter1, ring[i].arc, node); - initArcIterator(&iter2, ring[j].arc, node); - - bucket1 = nextBucket(&iter1); - bucket2 = nextBucket(&iter2); - - /* Make sure they both start at the same value */ - while(bucket1 && bucket1->val < bucket2->val) - { - bucket1 = nextBucket(&iter1); - } - - while(bucket2 && bucket2->val < bucket1->val) - { - bucket2 = nextBucket(&iter2); - } - - - for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2)) - { - /* copy and mirror back to bucket2 */ - bucket2->nv = bucket1->nv; - VECCOPY(bucket2->p, bucket1->p); - mirrorAlongAxis(bucket2->p, node->p, normal); - } - } - } - } - - MEM_freeN(ring); -} - -void reestablishAxialSymmetry(ReebNode *node, int depth, float axis[3]) -{ - ReebArc *arc1 = NULL; - ReebArc *arc2 = NULL; - ReebNode *node1 = NULL, *node2 = NULL; - float limit = G.scene->toolsettings->skgen_symmetry_limit; - float nor[3], vec[3], p[3]; - int i; - - for (i = 0; node->arcs[i] != NULL; i++) - { - ReebArc *connectedArc = node->arcs[i]; - - /* depth is store as a negative in flag. symmetry level is positive */ - if (connectedArc->flags == -depth) - { - if (arc1 == NULL) - { - arc1 = connectedArc; - node1 = OTHER_NODE(arc1, node); - } - else - { - arc2 = connectedArc; - node2 = OTHER_NODE(arc2, node); - break; /* Can stop now, the two arcs have been found */ - } - } - } - - /* shouldn't happen, but just to be sure */ - if (node1 == NULL || node2 == NULL) - { - return; - } - - VecSubf(p, node1->p, node->p); - Crossf(vec, p, axis); - Crossf(nor, vec, axis); - - /* mirror node2 along axis */ - VECCOPY(p, node2->p); - mirrorAlongAxis(p, node->p, nor); - - /* check if it's within limit before continuing */ - if (VecLenf(node1->p, p) <= limit) - { - - /* average with node1 */ - VecAddf(node1->p, node1->p, p); - VecMulf(node1->p, 0.5f); - - /* mirror back on node2 */ - VECCOPY(node2->p, node1->p); - mirrorAlongAxis(node2->p, node->p, nor); - - /* Merge buckets - * there shouldn't be any null arcs here, but just to be safe - * */ - if (arc1->bcount > 0 && arc2->bcount > 0) - { - ReebArcIterator iter1, iter2; - EmbedBucket *bucket1 = NULL, *bucket2 = NULL; - - initArcIterator(&iter1, arc1, node); - initArcIterator(&iter2, arc2, node); - - bucket1 = nextBucket(&iter1); - bucket2 = nextBucket(&iter2); - - /* Make sure they both start at the same value */ - while(bucket1 && bucket1->val < bucket2->val) - { - bucket1 = nextBucket(&iter1); - } - - while(bucket2 && bucket2->val < bucket1->val) - { - bucket2 = nextBucket(&iter2); - } - - - for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2)) - { - bucket1->nv += bucket2->nv; /* add counts */ - - /* mirror on axis */ - mirrorAlongAxis(bucket2->p, node->p, nor); - /* add bucket2 in bucket1 */ - VecLerpf(bucket1->p, bucket1->p, bucket2->p, (float)bucket2->nv / (float)(bucket1->nv)); - - /* copy and mirror back to bucket2 */ - bucket2->nv = bucket1->nv; - VECCOPY(bucket2->p, bucket1->p); - mirrorAlongAxis(bucket2->p, node->p, nor); - } - } - } -} - -void markdownSecondarySymmetry(ReebNode *node, int depth, int level) -{ - float axis[3] = {0, 0, 0}; - int count = 0; - int i; - - /* Only reestablish spatial symmetry if needed */ - if (G.scene->toolsettings->skgen_options & SKGEN_SYMMETRY) - { - /* count the number of branches in this symmetry group - * and determinte the axis of symmetry - * */ - for (i = 0; node->arcs[i] != NULL; i++) - { - ReebArc *connectedArc = node->arcs[i]; - - /* depth is store as a negative in flag. symmetry level is positive */ - if (connectedArc->flags == -depth) - { - count++; - } - /* If arc is on the axis */ - else if (connectedArc->flags == level) - { - VecAddf(axis, axis, connectedArc->v1->p); - VecSubf(axis, axis, connectedArc->v2->p); - } - } - - Normalize(axis); - - /* Split between axial and radial symmetry */ - if (count == 2) - { - reestablishAxialSymmetry(node, depth, axis); - } - else - { - reestablishRadialSymmetry(node, depth, axis); - } - } - - /* markdown secondary symetries */ - for (i = 0; node->arcs[i] != NULL; i++) - { - ReebArc *connectedArc = node->arcs[i]; - - if (connectedArc->flags == -depth) - { - /* markdown symmetry for branches corresponding to the depth */ - markdownSymmetryArc(connectedArc, node, level + 1); - } - } -} -void markdownSymmetryArc(ReebArc *arc, ReebNode *node, int level) -{ - int i; - arc->flags = level; - - node = OTHER_NODE(arc, node); - - for (i = 0; node->arcs[i] != NULL; i++) - { - ReebArc *connectedArc = node->arcs[i]; - - if (connectedArc != arc) - { - ReebNode *connectedNode = OTHER_NODE(connectedArc, node); - - /* symmetry level is positive value, negative values is subtree depth */ - connectedArc->flags = -subtreeDepth(connectedNode, connectedArc); - } - } - - arc = NULL; - - for (i = 0; node->arcs[i] != NULL; i++) - { - int issymmetryAxis = 0; - ReebArc *connectedArc = node->arcs[i]; - - /* only arcs not already marked as symetric */ - if (connectedArc->flags < 0) - { - int j; - - /* true by default */ - issymmetryAxis = 1; - - for (j = 0; node->arcs[j] != NULL && issymmetryAxis == 1; j++) - { - ReebArc *otherArc = node->arcs[j]; - - /* different arc, same depth */ - if (otherArc != connectedArc && otherArc->flags == connectedArc->flags) - { - /* not on the symmetry axis */ - issymmetryAxis = 0; - } - } - } - - /* arc could be on the symmetry axis */ - if (issymmetryAxis == 1) - { - /* no arc as been marked previously, keep this one */ - if (arc == NULL) - { - arc = connectedArc; - } - else - { - /* there can't be more than one symmetry arc */ - arc = NULL; - break; - } - } - } - - /* go down the arc continuing the symmetry axis */ - if (arc) - { - markdownSymmetryArc(arc, node, level); - } - - - /* secondary symmetry */ - for (i = 0; node->arcs[i] != NULL; i++) - { - ReebArc *connectedArc = node->arcs[i]; - - /* only arcs not already marked as symetric and is not the next arc on the symmetry axis */ - if (connectedArc->flags < 0) - { - /* subtree depth is store as a negative value in the flag */ - markdownSecondarySymmetry(node, -connectedArc->flags, level); - } - } -} - -void markdownSymmetry(ReebGraph *rg) -{ - ReebNode *node; - ReebArc *arc; - /* only for Acyclic graphs */ - int cyclic = isGraphCyclic(rg); - - /* mark down all arcs as non-symetric */ - for (arc = rg->arcs.first; arc; arc = arc->next) - { - arc->flags = 0; - } - - /* mark down all nodes as not on the symmetry axis */ - for (node = rg->nodes.first; node; node = node->next) - { - node->flags = 0; - } - - /* node list is sorted, so lowest node is always the head (by design) */ - node = rg->nodes.first; - - /* only work on acyclic graphs and if only one arc is incident on the first node */ - if (cyclic == 0 && countConnectedArcs(rg, node) == 1) - { - arc = node->arcs[0]; - - markdownSymmetryArc(arc, node, 1); - - /* mark down non-symetric arcs */ - for (arc = rg->arcs.first; arc; arc = arc->next) - { - if (arc->flags < 0) - { - arc->flags = 0; - } - else - { - /* mark down nodes with the lowest level symmetry axis */ - if (arc->v1->flags == 0 || arc->v1->flags > arc->flags) - { - arc->v1->flags = arc->flags; - } - if (arc->v2->flags == 0 || arc->v2->flags > arc->flags) - { - arc->v2->flags = arc->flags; - } - } - } - } -} /**************************************** SUBDIVISION ALGOS ******************************************/ @@ -5114,7 +4604,7 @@ EditBone * subdivideByAngle(ReebArc *arc, ReebNode *head, ReebNode *tail) return lastBone; } -float calcCorrelation(ReebArc *arc, int start, int end, float v0[3], float n[3]) +float calcVariance(ReebArc *arc, int start, int end, float v0[3], float n[3]) { int len = 2 + abs(end - start); @@ -5162,19 +4652,47 @@ float calcCorrelation(ReebArc *arc, int start, int end, float v0[3], float n[3]) /* 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; + return s_xyz / s_t; } else { - return 1.0f; + return 0; } } +float calcDistance(ReebArc *arc, int start, int end, float head[3], float tail[3]) +{ + ReebArcIterator iter; + EmbedBucket *bucket = NULL; + float max_dist = 0; + + /* calculate maximum distance */ + for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter); + bucket; + bucket = nextBucket(&iter)) + { + float v1[3], v2[3], c[3]; + float dist; + + VecSubf(v1, head, tail); + VecSubf(v2, bucket->p, tail); + + Crossf(c, v1, v2); + + dist = Inpf(c, c) / Inpf(v1, v1); + + max_dist = dist > max_dist ? dist : max_dist; + } + + + return max_dist; +} + EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail) { ReebArcIterator iter; float n[3]; - float CORRELATION_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit; + float ADAPTIVE_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit; EditBone *lastBone = NULL; /* init iterator to get start and end from head */ @@ -5183,15 +4701,17 @@ EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail) /* Calculate overall */ VecSubf(n, arc->buckets[iter.end].p, head->p); - if (G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION && - calcCorrelation(arc, iter.start, iter.end, head->p, n) < CORRELATION_THRESHOLD) + if (G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION) { EmbedBucket *bucket = NULL; EmbedBucket *previous = NULL; EditBone *child = NULL; EditBone *parent = NULL; + float normal[3] = {0, 0, 0}; + float avg_normal[3]; + int total = 0; int boneStart = iter.start; - + parent = add_editbone("Bone"); parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL; VECCOPY(parent->head, head->p); @@ -5200,12 +4720,46 @@ EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail) bucket; previous = bucket, bucket = nextBucket(&iter)) { - /* Calculate normal */ - VecSubf(n, bucket->p, parent->head); + float btail[3]; + float value = 0; - if (calcCorrelation(arc, boneStart, iter.index, parent->head, n) < CORRELATION_THRESHOLD) + if (G.scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING) { - VECCOPY(parent->tail, previous->p); + VECCOPY(btail, bucket->p); + } + else + { + float length; + + /* Calculate normal */ + VecSubf(n, bucket->p, parent->head); + length = Normalize(n); + + total += 1; + VecAddf(normal, normal, n); + VECCOPY(avg_normal, normal); + VecMulf(avg_normal, 1.0f / total); + + VECCOPY(btail, avg_normal); + VecMulf(btail, length); + VecAddf(btail, btail, parent->head); + } + + if (G.scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE) + { + value = calcDistance(arc, boneStart, iter.index, parent->head, btail); + } + else + { + float n[3]; + + VecSubf(n, btail, parent->head); + value = calcVariance(arc, boneStart, iter.index, parent->head, n); + } + + if (value > ADAPTIVE_THRESHOLD) + { + VECCOPY(parent->tail, btail); child = add_editbone("Bone"); VECCOPY(child->head, parent->tail); @@ -5214,6 +4768,9 @@ EditBone * subdivideByCorrelation(ReebArc *arc, ReebNode *head, ReebNode *tail) parent = child; // new child is next parent boneStart = iter.index; // start from end + + normal[0] = normal[1] = normal[2] = 0; + total = 0; } } @@ -5231,7 +4788,7 @@ float arcLengthRatio(ReebArc *arc) float embedLength = 0.0f; int i; - arcLength = VecLenf(arc->v1->p, arc->v2->p); + arcLength = VecLenf(arc->head->p, arc->tail->p); if (arc->bcount > 0) { @@ -5241,8 +4798,8 @@ float arcLengthRatio(ReebArc *arc) embedLength += VecLenf(arc->buckets[i - 1].p, arc->buckets[i].p); } /* Add head and tail -> embedding vectors */ - embedLength += VecLenf(arc->v1->p, arc->buckets[0].p); - embedLength += VecLenf(arc->v2->p, arc->buckets[arc->bcount - 1].p); + embedLength += VecLenf(arc->head->p, arc->buckets[0].p); + embedLength += VecLenf(arc->tail->p, arc->buckets[arc->bcount - 1].p); } else { @@ -5374,8 +4931,6 @@ void generateSkeletonFromReebGraph(ReebGraph *rg) { exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); // freedata, and undo } - - setcursor_space(SPACE_VIEW3D, CURSOR_WAIT); dst = add_object(OB_ARMATURE); base_init_from_view3d(BASACT, G.vd); @@ -5392,7 +4947,7 @@ void generateSkeletonFromReebGraph(ReebGraph *rg) arcBoneMap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - markdownSymmetry(rg); + BLI_markdownSymmetry((BGraph*)rg, rg->nodes.first, G.scene->toolsettings->skgen_symmetry_limit); for (arc = rg->arcs.first; arc; arc = arc->next) { @@ -5402,43 +4957,43 @@ void generateSkeletonFromReebGraph(ReebGraph *rg) /* Find out the direction of the arc through simple heuristics (in order of priority) : * - * 1- Arcs on primary symmetry axis (flags == 1) point up (head: high weight -> tail: low weight) + * 1- Arcs on primary symmetry axis (symmetry == 1) point up (head: high weight -> tail: low weight) * 2- Arcs starting on a primary axis point away from it (head: node on primary axis) * 3- Arcs point down (head: low weight -> tail: high weight) * - * Finally, the arc direction is stored in its flags: 1 (low -> high), -1 (high -> low) + * Finally, the arc direction is stored in its flag: 1 (low -> high), -1 (high -> low) */ /* if arc is a symmetry axis, internal bones go up the tree */ - if (arc->flags == 1 && arc->v2->degree != 1) + if (arc->symmetry_level == 1 && arc->tail->degree != 1) { - head = arc->v2; - tail = arc->v1; + head = arc->tail; + tail = arc->head; - arc->flags = -1; /* mark arc direction */ + arc->flag = -1; /* mark arc direction */ } /* Bones point AWAY from the symmetry axis */ - else if (arc->v1->flags == 1) + else if (arc->head->symmetry_level == 1) { - head = arc->v1; - tail = arc->v2; + head = arc->head; + tail = arc->tail; - arc->flags = 1; /* mark arc direction */ + arc->flag = 1; /* mark arc direction */ } - else if (arc->v2->flags == 1) + else if (arc->tail->symmetry_level == 1) { - head = arc->v2; - tail = arc->v1; + head = arc->tail; + tail = arc->head; - arc->flags = -1; /* mark arc direction */ + arc->flag = -1; /* mark arc direction */ } /* otherwise, always go from low weight to high weight */ else { - head = arc->v1; - tail = arc->v2; + head = arc->head; + tail = arc->tail; - arc->flags = 1; /* mark arc direction */ + arc->flag = 1; /* mark arc direction */ } /* Loop over subdivision methods */ @@ -5480,12 +5035,12 @@ void generateSkeletonFromReebGraph(ReebGraph *rg) ReebArc *incomingArc = NULL; int i; - for (i = 0; node->arcs[i] != NULL; i++) + for (i = 0; i < node->degree; i++) { - arc = node->arcs[i]; + arc = (ReebArc*)node->arcs[i]; /* if arc is incoming into the node */ - if ((arc->v1 == node && arc->flags == -1) || (arc->v2 == node && arc->flags == 1)) + if ((arc->head == node && arc->flag == -1) || (arc->tail == node && arc->flag == 1)) { if (incomingArc == NULL) { @@ -5506,12 +5061,12 @@ void generateSkeletonFromReebGraph(ReebGraph *rg) EditBone *parentBone = BLI_ghash_lookup(arcBoneMap, incomingArc); /* Look for outgoing arcs and parent their bones */ - for (i = 0; node->arcs[i] != NULL; i++) + for (i = 0; i < node->degree; i++) { arc = node->arcs[i]; /* if arc is outgoing from the node */ - if ((arc->v1 == node && arc->flags == 1) || (arc->v2 == node && arc->flags == -1)) + if ((arc->head == node && arc->flag == 1) || (arc->tail == node && arc->flag == -1)) { EditBone *childBone = BLI_ghash_lookup(arcBoneMap, arc); @@ -5529,89 +5084,21 @@ void generateSkeletonFromReebGraph(ReebGraph *rg) } BLI_ghash_free(arcBoneMap, NULL, NULL); - - setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); BIF_undo_push("Generate Skeleton"); } void generateSkeleton(void) { - EditMesh *em = G.editMesh; - ReebGraph *rg = NULL; - int i; + ReebGraph *reebg; - if (em == NULL) - return; - setcursor_space(SPACE_VIEW3D, CURSOR_WAIT); - - if (weightFromDistance(em) == 0) - { - error("No selected vertex\n"); - return; - } - - renormalizeWeight(em, 1.0f); - - weightToHarmonic(em); - -#ifdef DEBUG_REEB - weightToVCol(em); -#endif - - rg = generateReebGraph(em, G.scene->toolsettings->skgen_resolution); - - verifyBuckets(rg); - - /* Remove arcs without embedding */ - filterNullReebGraph(rg); - - verifyBuckets(rg); - - - i = 1; - /* filter until there's nothing more to do */ - while (i == 1) - { - i = 0; /* no work done yet */ - - if (G.scene->toolsettings->skgen_options & SKGEN_FILTER_EXTERNAL) - { - i |= filterExternalReebGraph(rg, G.scene->toolsettings->skgen_threshold_external * G.scene->toolsettings->skgen_resolution); - } - - verifyBuckets(rg); - - if (G.scene->toolsettings->skgen_options & SKGEN_FILTER_INTERNAL) - { - i |= filterInternalReebGraph(rg, G.scene->toolsettings->skgen_threshold_internal * G.scene->toolsettings->skgen_resolution); - } - } - - verifyBuckets(rg); - - repositionNodes(rg); - verifyBuckets(rg); + reebg = BIF_ReebGraphFromEditMesh(); - /* Filtering might have created degree 2 nodes, so remove them */ - removeNormalNodes(rg); - - verifyBuckets(rg); - - for(i = 0; i < G.scene->toolsettings->skgen_postpro_passes; i++) - { - postprocessGraph(rg, G.scene->toolsettings->skgen_postpro); - } + generateSkeletonFromReebGraph(reebg); - buildAdjacencyList(rg); - - sortNodes(rg); - - sortArcs(rg); - - generateSkeletonFromReebGraph(rg); + REEB_freeGraph(reebg); - freeGraph(rg); + setcursor_space(SPACE_VIEW3D, CURSOR_EDIT); } diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c index b6243a33944..42972e4aa5d 100644 --- a/source/blender/src/editconstraint.c +++ b/source/blender/src/editconstraint.c @@ -65,7 +65,9 @@ #include "BIF_space.h" #include "BIF_toolbox.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif #include "blendef.h" #include "nla.h" @@ -444,7 +446,7 @@ void add_constraint (short only_IK) else if (nr==18) { char *menustr; int scriptint= 0; - +#ifndef DISABLE_PYTHON /* popup a list of usable scripts */ menustr = buildmenu_pyconstraints(NULL, &scriptint); scriptint = pupmenu(menustr); @@ -459,6 +461,7 @@ void add_constraint (short only_IK) /* make sure target allowance is set correctly */ BPY_pyconstraint_update(ob, con); } +#endif } else if (nr==19) { con = add_new_constraint(CONSTRAINT_TYPE_CHILDOF); @@ -700,7 +703,8 @@ static void test_constraints (Object *owner, const char substring[]) /* clear disabled-flag first */ curcon->flag &= ~CONSTRAINT_DISABLE; - + +#ifndef DISABLE_PYTHON /* Check specialised data (settings) for constraints that need this */ if (curcon->type == CONSTRAINT_TYPE_PYTHON) { bPythonConstraint *data = curcon->data; @@ -711,16 +715,16 @@ static void test_constraints (Object *owner, const char substring[]) } else if (BPY_is_pyconstraint(data->text)==0) { curcon->flag |= CONSTRAINT_DISABLE; - } - else { + } else { /* does the constraint require target input... also validates targets */ BPY_pyconstraint_update(owner, curcon); } - /* targets have already been checked for this */ continue; } - else if (curcon->type == CONSTRAINT_TYPE_KINEMATIC) { + else +#endif + if (curcon->type == CONSTRAINT_TYPE_KINEMATIC) { bKinematicConstraint *data = curcon->data; /* bad: we need a separate set of checks here as poletarget is @@ -869,6 +873,7 @@ void validate_pyconstraint_cb (void *arg1, void *arg2) data->text = text; } +#ifndef DISABLE_PYTHON /* this returns a string for the list of usable pyconstraint script names */ char *buildmenu_pyconstraints (Text *con_text, int *pyconindex) { @@ -909,15 +914,17 @@ char *buildmenu_pyconstraints (Text *con_text, int *pyconindex) return str; } +#endif /* DISABLE_PYTHON */ /* this callback gets called when the 'refresh' button of a pyconstraint gets pressed */ void update_pyconstraint_cb (void *arg1, void *arg2) { Object *owner= (Object *)arg1; bConstraint *con= (bConstraint *)arg2; - +#ifndef DISABLE_PYTHON if (owner && con) BPY_pyconstraint_update(owner, con); +#endif } /* ------------- Child-Of Constraint ------------------ */ diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c index 77c27dfa3db..53fb6dbffb1 100644 --- a/source/blender/src/editface.c +++ b/source/blender/src/editface.c @@ -99,8 +99,10 @@ #include "BDR_unwrapper.h" #include "BDR_editobject.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif /* Pupmenu codes: */ #define UV_CUBE_MAPPING 2 @@ -1238,7 +1240,9 @@ void face_borderselect() void uv_autocalc_tface() { short mode, i=0, has_pymenu=0; /* pymenu must be bigger then UV_*_MAPPING */ +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif char menu_number[3]; /* uvmenu, will add python items */ @@ -1253,7 +1257,7 @@ void uv_autocalc_tface() MENUSTRING("Project from View (Bounds)",UV_BOUNDS_MAPPING) "|%l|" MENUSTRING("Reset", UV_RESET_MAPPING); - +#ifndef DISABLE_PYTHON /* note that we account for the 10 previous entries with i+10: */ for (pym = BPyMenuTable[PYMENU_UVCALCULATION]; pym; pym = pym->next, i++) { @@ -1268,14 +1272,15 @@ void uv_autocalc_tface() sprintf(menu_number, "%d", i+10); strcat(uvmenu, menu_number); } +#endif mode= pupmenu(uvmenu); - +#ifndef DISABLE_PYTHON if (mode >= 10) { BPY_menu_do_python(PYMENU_UVCALCULATION, mode - 10); return; } - +#endif switch(mode) { case UV_CUBE_MAPPING: calculate_uv_map(B_UVAUTO_CUBE); break; diff --git a/source/blender/src/editmesh_add.c b/source/blender/src/editmesh_add.c index 4dc64b0f933..16a5b049da2 100644 --- a/source/blender/src/editmesh_add.c +++ b/source/blender/src/editmesh_add.c @@ -90,8 +90,10 @@ #include "editmesh.h" /* bpymenu */ +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif static float icovert[12][3] = { {0,0,-200}, @@ -686,14 +688,17 @@ void addedgeface_mesh(void) } else if(amount > 4) { +#ifndef DISABLE_PYTHON /* Python Menu */ BPyMenu *pym; +#endif char menu_number[3]; int i=0, has_pymenu=0, ret; /* facemenu, will add python items */ char facemenu[4096]= "Make Faces%t|Auto%x1|Make FGon%x2|Clear FGon%x3"; +#ifndef DISABLE_PYTHON /* note that we account for the 10 previous entries with i+4: */ for (pym = BPyMenuTable[PYMENU_MESHFACEKEY]; pym; pym = pym->next, i++) { @@ -708,16 +713,18 @@ void addedgeface_mesh(void) sprintf(menu_number, "%d", i+4); strcat(facemenu, menu_number); } - +#endif ret= pupmenu(facemenu); if(ret==1) addfaces_from_edgenet(); else if(ret==2) make_fgon(1); else if(ret==3) make_fgon(0); +#ifndef DISABLE_PYTHON else if (ret >= 4) { BPY_menu_do_python(PYMENU_MESHFACEKEY, ret - 4); return; } +#endif return; } else if(amount<2) { diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c index 81d0ffeeb3b..3dbbe7d7336 100644 --- a/source/blender/src/editmesh_mods.c +++ b/source/blender/src/editmesh_mods.c @@ -1864,7 +1864,7 @@ void faceloop_select(EditEdge *startedge, int select) looking= 0; for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e4 && efa->f1==0) { /* not done quad */ + if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */ if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */ /* if edge tagged, select opposing edge and mark face ok */ diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c index 23387673f95..f5de20891b4 100644 --- a/source/blender/src/editnode.c +++ b/source/blender/src/editnode.c @@ -40,6 +40,7 @@ #include "DNA_ipo_types.h" #include "DNA_object_types.h" #include "DNA_material_types.h" +#include "DNA_texture_types.h" #include "DNA_node_types.h" #include "DNA_space_types.h" #include "DNA_screen_types.h" @@ -53,6 +54,7 @@ #include "BKE_main.h" #include "BKE_node.h" #include "BKE_material.h" +#include "BKE_texture.h" #include "BKE_scene.h" #include "BKE_utildefines.h" @@ -176,6 +178,10 @@ static void snode_handle_recalc(SpaceNode *snode) allqueue(REDRAWNODE, 1); } + else if(snode->treetype==NTREE_TEXTURE) { + ntreeTexUpdatePreviews(snode->nodetree); + BIF_preview_changed(ID_TE); + } } static void shader_node_event(SpaceNode *snode, short event) @@ -423,6 +429,36 @@ static void composit_node_event(SpaceNode *snode, short event) } } +static void texture_node_event(SpaceNode *snode, short event) +{ + switch(event) { + case B_REDR: + allqueue(REDRAWNODE, 1); + break; + case B_NODE_LOADIMAGE: + { + bNode *node= nodeGetActive(snode->edittree); + char name[FILE_MAXDIR+FILE_MAXFILE]; + + if(node->id) + strcpy(name, ((Image *)node->id)->name); + else strcpy(name, U.textudir); + if (G.qual & LR_CTRLKEY) { + activate_imageselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image); + } else { + activate_fileselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image); + } + break; + } + default: + /* B_NODE_EXEC */ + ntreeTexCheckCyclics( snode->nodetree ); + snode_handle_recalc(snode); + allqueue(REDRAWNODE, 1); + break; + } +} + /* assumes nothing being done in ntree yet, sets the default in/out node */ /* called from shading buttons or header */ @@ -486,6 +522,36 @@ void node_composit_default(Scene *sce) ntreeCompositForceHidden(sce->nodetree); } +/* assumes nothing being done in ntree yet, sets the default in/out node */ +/* called from shading buttons or header */ +void node_texture_default(Tex *tx) +{ + bNode *in, *out; + bNodeSocket *fromsock, *tosock; + + /* but lets check it anyway */ + if(tx->nodetree) { + printf("error in texture initialize\n"); + return; + } + + tx->nodetree= ntreeAddTree(NTREE_TEXTURE); + + out= nodeAddNodeType(tx->nodetree, TEX_NODE_OUTPUT, NULL, NULL); + out->locx= 300.0f; out->locy= 300.0f; + + in= nodeAddNodeType(tx->nodetree, TEX_NODE_CHECKER, NULL, NULL); + in->locx= 10.0f; in->locy= 300.0f; + nodeSetActive(tx->nodetree, in); + + fromsock= in->outputs.first; + tosock= out->inputs.first; + nodeAddLink(tx->nodetree, in, fromsock, out, tosock); + + ntreeSolveOrder(tx->nodetree); /* needed for pointers */ + ntreeTexUpdatePreviews(tx->nodetree); +} + /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ void snode_set_context(SpaceNode *snode) { @@ -516,6 +582,16 @@ void snode_set_context(SpaceNode *snode) snode->nodetree= G.scene->nodetree; } + else if(snode->treetype==NTREE_TEXTURE) { + if(ob) { + Tex *tx= give_current_texture(ob, ob->actcol); + if(tx) { + snode->from= (ID*)ob; /* please check this; i have no idea what 'from' is. */ + snode->id= &tx->id; + snode->nodetree= tx->nodetree; + } + } + } /* find editable group */ if(snode->nodetree) @@ -608,6 +684,12 @@ static void node_set_active(SpaceNode *snode, bNode *node) } } } + else if(snode->treetype==NTREE_TEXTURE) { + if(node->id) + BIF_preview_changed(-1); + allqueue(REDRAWBUTSSHADING, 1); + allqueue(REDRAWIPO, 0); + } } } @@ -1188,6 +1270,9 @@ static void scale_node(SpaceNode *snode, bNode *node) BIF_undo_push("Scale Node"); allqueue(REDRAWNODE, 1); + + if(snode->nodetree->type == NTREE_TEXTURE) + ntreeTexUpdatePreviews(snode->nodetree); } /* ******************** rename ******************* */ @@ -1702,6 +1787,12 @@ bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy) NodeTagChanged(snode->edittree, node); } + + if(snode->nodetree->type==NTREE_TEXTURE) { + ntreeTexCheckCyclics(snode->edittree); + ntreeTexUpdatePreviews(snode->edittree); + } + return node; } @@ -2481,6 +2572,8 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt) shader_node_event(snode, val); else if(snode->treetype==NTREE_COMPOSIT) composit_node_event(snode, val); + else if(snode->treetype==NTREE_TEXTURE) + texture_node_event(snode, val); break; case RENDERPREVIEW: diff --git a/source/blender/src/editscreen.c b/source/blender/src/editscreen.c index 2557894d0e0..3cc306c8ea9 100644 --- a/source/blender/src/editscreen.c +++ b/source/blender/src/editscreen.c @@ -104,7 +104,10 @@ #include "BSE_seqaudio.h" #include "BSE_view.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif + #include "mydevice.h" #include "blendef.h" @@ -1378,11 +1381,13 @@ void screenmain(void) BIF_read_file(ext_load_str); sound_initialize_sounds(); } +#ifndef DISABLE_PYTHON else if ((event==ONLOAD_SCRIPT) && BPY_has_onload_script()) { /* event queued in setup_app_data() in blender.c, where G.f is checked */ onload_script = 1; firsttime = 1; /* see last 'if' in this function */ } +#endif else { towin= 1; } @@ -1518,13 +1523,14 @@ void screenmain(void) } /* Bizar hack. The event queue has mutated... */ if ( (firsttime) && (event == 0) ) { - +#ifndef DISABLE_PYTHON if (onload_script) { /* OnLoad scriptlink */ BPY_do_pyscript(&G.scene->id, SCRIPT_ONLOAD); onload_script = 0; - } - else if (G.fileflags & G_FILE_AUTOPLAY) { + } else +#endif + if (G.fileflags & G_FILE_AUTOPLAY) { // SET AUTOPLAY in G.flags for // other fileloads @@ -1887,9 +1893,9 @@ static void del_area(ScrArea *sa) uiFreeBlocks(&sa->uiblocks); uiFreePanels(&sa->panels); - +#ifndef DISABLE_PYTHON BPY_free_scriptlink(&sa->scriptlink); - +#endif if(sa==curarea) curarea= NULL; if(sa==g_activearea) g_activearea= NULL; } diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c index 497443edffd..fd8bd7dc014 100644 --- a/source/blender/src/gpencil.c +++ b/source/blender/src/gpencil.c @@ -267,6 +267,7 @@ bGPDframe *gpencil_frame_duplicate (bGPDframe *src) /* make a copy of the source frame */ dst= MEM_dupallocN(src); + dst->prev= dst->next= NULL; /* copy strokes */ dst->strokes.first = dst->strokes.last= NULL; @@ -294,13 +295,18 @@ bGPDlayer *gpencil_layer_duplicate (bGPDlayer *src) /* make a copy of source layer */ dst= MEM_dupallocN(src); + dst->prev= dst->next= NULL; /* copy frames */ dst->frames.first= dst->frames.last= NULL; for (gpf= src->frames.first; gpf; gpf= gpf->next) { - /* make a copy of source stroke */ + /* make a copy of source frame */ gpfd= gpencil_frame_duplicate(gpf); BLI_addtail(&dst->frames, gpfd); + + /* if source frame was the current layer's 'active' frame, reassign that too */ + if (gpf == dst->actframe) + dst->actframe= gpfd; } /* return new layer */ diff --git a/source/blender/src/header_image.c b/source/blender/src/header_image.c index 4ca287d81c5..cf8f3c5c99d 100644 --- a/source/blender/src/header_image.c +++ b/source/blender/src/header_image.c @@ -82,8 +82,10 @@ #include "BSE_trans_types.h" #include "BSE_edit.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "IMB_imbuf_types.h" @@ -658,8 +660,9 @@ static uiBlock *image_image_rtmappingmenu(void *arg_unused) static void do_image_imagemenu(void *arg, int event) { /* events >=20 are registered bpython scripts */ +#ifndef DISABLE_PYTHON if (event >= 20) BPY_menu_do_python(PYMENU_IMAGE, event - 20); - +#endif switch(event) { case 0: @@ -704,7 +707,9 @@ static uiBlock *image_imagemenu(void *arg_unused) ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser); uiBlock *block; short yco= 0, menuwidth=150; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i = 0; block= uiNewBlock(&curarea->uiblocks, "image_imagemenu", UI_EMBOSSP, UI_HELV, curarea->headwin); @@ -749,7 +754,7 @@ static uiBlock *image_imagemenu(void *arg_unused) uiDefIconTextBlockBut(block, image_image_rtmappingmenu, NULL, ICON_RIGHTARROW_THIN, "Realtime Texture Mapping", 0, yco-=20, 120, 19, ""); // uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Realtime Texture Animation|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, ""); } - +#ifndef DISABLE_PYTHON /* note that we acount for the N previous entries with i+20: */ for (pym = BPyMenuTable[PYMENU_IMAGE]; pym; pym = pym->next, i++) { @@ -757,7 +762,7 @@ static uiBlock *image_imagemenu(void *arg_unused) NULL, 0.0, 0.0, 1, i+20, pym->tooltip?pym->tooltip:pym->filename); } - +#endif if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -948,6 +953,7 @@ static uiBlock *image_uvs_weldalignmenu(void *arg_unused) return block; } +#ifndef DISABLE_PYTHON static void do_image_uvs_scriptsmenu(void *arg, int event) { BPY_menu_do_python(PYMENU_UV, event); @@ -978,6 +984,7 @@ static uiBlock *image_uvs_scriptsmenu (void *args_unused) return block; } +#endif /* DISABLE_PYTHON */ static void do_image_uvsmenu(void *arg, int event) { @@ -1088,10 +1095,12 @@ static uiBlock *image_uvsmenu(void *arg_unused) uiDefIconTextBlockBut(block, image_uvs_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Faces", 0, yco-=20, menuwidth, 19, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, image_uvs_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, ""); - +#endif + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } diff --git a/source/blender/src/header_info.c b/source/blender/src/header_info.c index 28248c052b3..b6bd00d2ad6 100644 --- a/source/blender/src/header_info.c +++ b/source/blender/src/header_info.c @@ -115,8 +115,10 @@ #include "MEM_guardedalloc.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "GPU_extensions.h" #include "GPU_material.h" @@ -332,8 +334,9 @@ Scene *copy_scene(Scene *sce, int level) obase= obase->next; base= base->next; } +#ifndef DISABLE_PYTHON BPY_copy_scriptlink(&sce->scriptlink); - +#endif /* sculpt data */ sce->sculptdata.session = NULL; if (sce->sculptdata.cumap) { @@ -650,12 +653,14 @@ static void do_info_file_importmenu(void *arg, int event) areawinset(sa->win); } +#ifndef DISABLE_PYTHON /* events >=3 are registered bpython scripts */ if (event >= 3) { BPY_menu_do_python(PYMENU_IMPORT, event - 3); BIF_undo_push("Import file"); - } - else { + } else +#endif + { switch(event) { case 0: /* DXF */ @@ -677,7 +682,9 @@ static uiBlock *info_file_importmenu(void *arg_unused) { uiBlock *block; short yco = 20, menuwidth = 120; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i = 0; block= uiNewBlock(&curarea->uiblocks, "importmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); @@ -690,13 +697,13 @@ static uiBlock *info_file_importmenu(void *arg_unused) 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "STL...", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 2, ""); - +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); for (pym = BPyMenuTable[PYMENU_IMPORT]; pym; pym = pym->next, i++) { uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+3, pym->tooltip?pym->tooltip:pym->filename); } - +#endif uiBlockSetDirection(block, UI_RIGHT); uiTextBoundsBlock(block, 60); @@ -712,11 +719,12 @@ static void do_info_file_exportmenu(void *arg, int event) if (!sa) sa= closest_bigger_area(); areawinset(sa->win); } - +#ifndef DISABLE_PYTHON /* events >=3 are registered bpython scripts */ if (event >= 3) BPY_menu_do_python(PYMENU_EXPORT, event - 3); - - else switch(event) { + else +#endif + switch(event) { case 0: write_vrml_fs(); @@ -735,7 +743,9 @@ static uiBlock *info_file_exportmenu(void *arg_unused) { uiBlock *block; short yco = 20, menuwidth = 120; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i = 0; block= uiNewBlock(&curarea->uiblocks, "exportmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); @@ -749,6 +759,7 @@ static uiBlock *info_file_exportmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "STL...", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 2, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); /* note that we acount for the 3 previous entries with i+3: */ @@ -757,7 +768,7 @@ static uiBlock *info_file_exportmenu(void *arg_unused) NULL, 0.0, 0.0, 1, i+3, pym->tooltip?pym->tooltip:pym->filename); } - +#endif uiBlockSetDirection(block, UI_RIGHT); uiTextBoundsBlock(block, 60); @@ -1160,9 +1171,12 @@ static uiBlock *info_filemenu(void *arg_unused) void do_info_add_meshmenu(void *arg, int event) { +#ifndef DISABLE_PYTHON if (event>=20) { BPY_menu_do_python(PYMENU_ADDMESH, event - 20); - } else { + } else +#endif + { switch(event) { case 0: /* Plane */ @@ -1214,7 +1228,9 @@ static uiBlock *info_add_meshmenu(void *arg_unused) short yco= 0; /* Python Menu */ +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i=0; block= uiNewBlock(&curarea->uiblocks, "add_meshmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); @@ -1231,7 +1247,7 @@ static uiBlock *info_add_meshmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grid|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 8, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Monkey|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 9, ""); - +#ifndef DISABLE_PYTHON pym = BPyMenuTable[PYMENU_ADDMESH]; if (pym) { uiDefIconTextBut(block, SEPR, 0, ICON_BLANK1, "", 0, yco-=6, 160, 6, NULL, 0.0, 0.0, 0, 0, ""); @@ -1240,7 +1256,8 @@ static uiBlock *info_add_meshmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, i+20, pym->tooltip?pym->tooltip:pym->filename); } } - +#endif + uiBlockSetDirection(block, UI_RIGHT); uiTextBoundsBlock(block, 50); @@ -1496,9 +1513,12 @@ static uiBlock *info_add_groupmenu(void *arg_unused) void do_info_addmenu(void *arg, int event) { +#ifndef DISABLE_PYTHON if (event>=20) { BPY_menu_do_python(PYMENU_ADD, event - 20); - } else { + } else +#endif + { switch(event) { case 0: /* Mesh */ @@ -1547,7 +1567,9 @@ static uiBlock *info_addmenu(void *arg_unused) { /* static short tog=0; */ uiBlock *block; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i=0; short yco= 0; @@ -1575,6 +1597,7 @@ static uiBlock *info_addmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Armature", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 8, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Lattice", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 9, ""); +#ifndef DISABLE_PYTHON pym = BPyMenuTable[PYMENU_ADD]; if (pym) { uiDefIconTextBut(block, SEPR, 0, ICON_BLANK1, "", 0, yco-=6, 1620, 6, NULL, 0.0, 0.0, 0, 0, ""); @@ -1583,7 +1606,8 @@ static uiBlock *info_addmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, i+20, pym->tooltip?pym->tooltip:pym->filename); } } - +#endif + uiBlockSetDirection(block, UI_DOWN); uiTextBoundsBlock(block, 80); @@ -1948,9 +1972,10 @@ static void do_info_rendermenu(void *arg, int event) if (!sa) sa= closest_bigger_area(); areawinset(sa->win); } - +#ifndef DISABLE_PYTHON BPY_menu_do_python(PYMENU_RENDER, event - 10); BIF_undo_push("Rendering Script"); +#endif } else { switch(event) { @@ -1998,7 +2023,9 @@ static void do_info_rendermenu(void *arg, int event) static uiBlock *info_rendermenu(void *arg_unused) { uiBlock *block; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif short yco= 0; short menuwidth=120; int i=0; @@ -2026,12 +2053,14 @@ static uiBlock *info_rendermenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Render Settings|F10", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); for (pym = BPyMenuTable[PYMENU_RENDER]; pym; pym = pym->next, i++) { uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+10, pym->tooltip?pym->tooltip:pym->filename); } - +#endif + uiBlockSetDirection(block, UI_DOWN); uiTextBoundsBlock(block, 80); @@ -2042,8 +2071,9 @@ static uiBlock *info_rendermenu(void *arg_unused) static void do_info_help_websitesmenu(void *arg, int event) { +#ifndef DISABLE_PYTHON BPY_menu_do_python(PYMENU_HELPWEBSITES, event); - +#endif allqueue(REDRAWVIEW3D, 0); } @@ -2051,17 +2081,19 @@ static void do_info_help_websitesmenu(void *arg, int event) static uiBlock *info_help_websitesmenu(void *arg_unused) { uiBlock *block; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif short yco = 20, menuwidth = 120; int i = 0; block= uiNewBlock(&curarea->uiblocks, "info_help_websitesmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); uiBlockSetButmFunc(block, do_info_help_websitesmenu, NULL); - +#ifndef DISABLE_PYTHON for (pym = BPyMenuTable[PYMENU_HELPWEBSITES]; pym; pym = pym->next, i++) { uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i, pym->tooltip?pym->tooltip:pym->filename); } - +#endif uiBlockSetDirection(block, UI_RIGHT); uiTextBoundsBlock(block, 60); @@ -2071,8 +2103,11 @@ static uiBlock *info_help_websitesmenu(void *arg_unused) static void do_info_help_systemmenu(void *arg, int event) { /* events >=10 are registered bpython scripts */ +#ifndef DISABLE_PYTHON if (event >= 10) BPY_menu_do_python(PYMENU_HELPSYSTEM, event - 10); - else { + else +#endif + { switch(event) { case 1: /* Benchmark */ @@ -2102,7 +2137,9 @@ static void do_info_help_systemmenu(void *arg, int event) static uiBlock *info_help_systemmenu(void *arg_unused) { uiBlock *block; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif short yco = 20, menuwidth = 120; int i = 0; @@ -2110,11 +2147,11 @@ static uiBlock *info_help_systemmenu(void *arg_unused) uiBlockSetButmFunc(block, do_info_help_systemmenu, NULL); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Benchmark", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); - +#ifndef DISABLE_PYTHON for (pym = BPyMenuTable[PYMENU_HELPSYSTEM]; pym; pym = pym->next, i++) { uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+10, pym->tooltip?pym->tooltip:pym->filename); } - +#endif uiBlockSetDirection(block, UI_RIGHT); uiTextBoundsBlock(block, 60); @@ -2132,8 +2169,11 @@ static void do_info_helpmenu(void *arg, int event) } /* events >=10 are registered bpython scripts */ +#ifndef DISABLE_PYTHON if (event >= 10) BPY_menu_do_python(PYMENU_HELP, event - 10); - else { + else +#endif + { switch(event) { case 0: /* About Blender */ @@ -2150,20 +2190,22 @@ static uiBlock *info_helpmenu(void *arg_unused) uiBlock *block; short yco= 0; short menuwidth=120; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i = 0; block= uiNewBlock(&curarea->uiblocks, "info_helpmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); uiBlockSetButmFunc(block, do_info_helpmenu, NULL); uiDefIconTextBut(block, BUTM, B_SHOWSPLASH, ICON_BLANK1, "About Blender...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, ""); - +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); for (pym = BPyMenuTable[PYMENU_HELP]; pym; pym = pym->next, i++) { uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+10, pym->tooltip?pym->tooltip:pym->filename); } - +#endif uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, info_help_websitesmenu, NULL, ICON_RIGHTARROW_THIN, "Websites", 0, yco-=20, 120, 19, ""); diff --git a/source/blender/src/header_node.c b/source/blender/src/header_node.c index d27a41c59f5..2bd028766d1 100644 --- a/source/blender/src/header_node.c +++ b/source/blender/src/header_node.c @@ -68,6 +68,7 @@ void do_node_buttons(ScrArea *sa, unsigned short event) { SpaceNode *snode= sa->spacedata.first; Material *ma; + Tex *tx; switch(event) { case B_NODE_USEMAT: @@ -93,6 +94,21 @@ void do_node_buttons(ScrArea *sa, unsigned short event) snode_set_context(snode); allqueue(REDRAWNODE, 0); break; + + case B_NODE_USETEX: + tx = (Tex *)snode->id; + if(tx) { + tx->type = 0; + if(tx->use_nodes && tx->nodetree==NULL) { + node_texture_default(tx); + snode_set_context(snode); + } + BIF_preview_changed(ID_TE); + allqueue(REDRAWNODE, 0); + allqueue(REDRAWBUTSSHADING, 0); + allqueue(REDRAWIPO, 0); + } + break; } } @@ -424,6 +440,36 @@ static uiBlock *node_add_distortmenu(void *arg_unused) return block; } +static uiBlock *node_add_patternmenu(void *arg_unused) +{ + SpaceNode *snode= curarea->spacedata.first; + uiBlock *block; + + block= uiNewBlock(&curarea->uiblocks, "node_add_patternmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); + uiBlockSetButmFunc(block, do_node_addmenu, NULL); + + node_make_addmenu(snode, NODE_CLASS_PATTERN, block); + + uiBlockSetDirection(block, UI_RIGHT); + uiTextBoundsBlock(block, 60); + + return block; +} +static uiBlock *node_add_texturemenu(void *arg_unused) +{ + SpaceNode *snode= curarea->spacedata.first; + uiBlock *block; + + block= uiNewBlock(&curarea->uiblocks, "node_add_texturemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); + uiBlockSetButmFunc(block, do_node_addmenu, NULL); + + node_make_addmenu(snode, NODE_CLASS_TEXTURE, block); + + uiBlockSetDirection(block, UI_RIGHT); + uiTextBoundsBlock(block, 60); + + return block; +} static uiBlock *node_add_groupmenu(void *arg_unused) { SpaceNode *snode= curarea->spacedata.first; @@ -486,7 +532,17 @@ static uiBlock *node_addmenu(void *arg_unused) uiDefIconTextBlockBut(block, node_add_distortmenu, NULL, ICON_RIGHTARROW_THIN, "Distort", 0, yco-=20, 120, 19, ""); uiDefIconTextBlockBut(block, node_add_groupmenu, NULL, ICON_RIGHTARROW_THIN, "Group", 0, yco-=20, 120, 19, ""); - } else + } else if(snode->treetype==NTREE_TEXTURE) { + uiDefIconTextBlockBut(block, node_add_inputmenu, NULL, ICON_RIGHTARROW_THIN, "Input", 0, yco-=20, 120, 19, ""); + uiDefIconTextBlockBut(block, node_add_outputmenu, NULL, ICON_RIGHTARROW_THIN, "Output", 0, yco-=20, 120, 19, ""); + uiDefIconTextBlockBut(block, node_add_colormenu, NULL, ICON_RIGHTARROW_THIN, "Color", 0, yco-=20, 120, 19, ""); + uiDefIconTextBlockBut(block, node_add_patternmenu, NULL, ICON_RIGHTARROW_THIN, "Patterns", 0, yco-=20, 120, 19, ""); + uiDefIconTextBlockBut(block, node_add_texturemenu, NULL, ICON_RIGHTARROW_THIN, "Textures", 0, yco-=20, 120, 19, ""); + uiDefIconTextBlockBut(block, node_add_convertermenu, NULL, ICON_RIGHTARROW_THIN, "Convertor", 0, yco-=20, 120, 19, ""); + uiDefIconTextBlockBut(block, node_add_distortmenu, NULL, ICON_RIGHTARROW_THIN, "Distort", 0, yco-=20, 120, 19, ""); + uiDefIconTextBlockBut(block, node_add_groupmenu, NULL, ICON_RIGHTARROW_THIN, "Group", 0, yco-=20, 120, 19, ""); + } + else uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); if(curarea->headertype==HEADERTOP) { @@ -696,6 +752,9 @@ void node_buttons(ScrArea *sa) xco+= XIC; uiDefIconButI(block, ROW, B_REDR, ICON_IMAGE_DEHLT, xco,2,XIC,YIC-2, &(snode->treetype), 2, 1, 0, 0, "Composite Nodes"); + xco+= XIC; + uiDefIconButI(block, ROW, B_REDR, ICON_TEXTURE_DEHLT, xco,2,XIC,YIC-2, + &(snode->treetype), 2, 2, 0, 0, "Texture Nodes"); xco+= 2*XIC; uiBlockEndAlign(block); @@ -723,6 +782,19 @@ void node_buttons(ScrArea *sa) uiDefButBitS(block, TOG, SNODE_BACKDRAW, REDRAWNODE, "Backdrop", xco+5,0,80,19, &snode->flag, 0.0f, 0.0f, 0, 0, "Use active Viewer Node output as backdrop"); xco+= 80; } + else if(snode->treetype==NTREE_TEXTURE) { + if(snode->from) { + + xco= std_libbuttons(block, xco, 0, 0, NULL, B_TEXBROWSE, ID_TE, 1, snode->id, snode->from, &(snode->menunr), + B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA); + + if(snode->id) { + Tex *tx= (Tex *)snode->id; + uiDefButC(block, TOG, B_NODE_USETEX, "Use Nodes", xco+5,0,70,19, &tx->use_nodes, 0.0f, 0.0f, 0, 0, ""); + xco+=80; + } + } + } /* always as last */ sa->headbutlen= xco+2*XIC; diff --git a/source/blender/src/header_oops.c b/source/blender/src/header_oops.c index 68326c330ad..b839029c139 100644 --- a/source/blender/src/header_oops.c +++ b/source/blender/src/header_oops.c @@ -63,8 +63,10 @@ #include "BKE_depsgraph.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif static int viewmovetemp = 0; diff --git a/source/blender/src/header_script.c b/source/blender/src/header_script.c index 53c4b9b5953..2bf58fb2873 100644 --- a/source/blender/src/header_script.c +++ b/source/blender/src/header_script.c @@ -57,8 +57,10 @@ #include "BKE_sca.h" #include "BSE_filesel.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "blendef.h" #include "mydevice.h" @@ -68,6 +70,7 @@ /* ********************** SCRIPT ****************************** */ /* action executed after clicking in Scripts menu */ +#ifndef DISABLE_PYTHON static void do_scripts_submenus(void *int_arg, int event) { int menutype = (intptr_t)int_arg; @@ -152,6 +155,7 @@ static uiBlock *script_scriptsmenu(void *arg_unused) uiTextBoundsBlock(block, 50); return block; } +#endif /* DISABLE_PYTHON */ void do_script_buttons(unsigned short event) { @@ -160,6 +164,7 @@ void do_script_buttons(unsigned short event) int nr= 1; Script *script = sc->script; +#ifndef DISABLE_PYTHON if (!sc) return; if (sc->spacetype != SPACE_SCRIPT) return; @@ -200,7 +205,7 @@ void do_script_buttons(unsigned short event) } break; } - +#endif return; } @@ -240,6 +245,7 @@ void script_buttons(void) uiBlockSetEmboss(block, UI_EMBOSS); xco+=XIC; +#ifndef DISABLE_PYTHON /* pull down menus */ if((curarea->flag & HEADER_NO_PULLDOWN)==0) { uiBlockSetEmboss(block, UI_EMBOSSP); @@ -248,7 +254,7 @@ void script_buttons(void) uiDefPulldownBut(block,script_scriptsmenu, NULL, "Scripts", xco, 0, xmax, 20, ""); xco+=xmax; } - +#endif uiBlockSetEmboss(block, UI_EMBOSS); uiBlockBeginAlign(block); diff --git a/source/blender/src/header_text.c b/source/blender/src/header_text.c index 9bb59a81192..9268642db2f 100644 --- a/source/blender/src/header_text.c +++ b/source/blender/src/header_text.c @@ -84,8 +84,10 @@ #include "BLI_blenlib.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "blendef.h" #include "mydevice.h" @@ -166,11 +168,12 @@ void do_text_buttons(unsigned short event) st->text = st->text->id.next; pop_space_text(st); } - + +#ifndef DISABLE_PYTHON BPY_clear_bad_scriptlinks(text); BPY_free_pyconstraint_links(text); free_text_controllers(text); - +#endif unlink_text(text); free_libblock(&G.main->text, text); @@ -231,7 +234,7 @@ void do_text_buttons(unsigned short event) break; } } - +#ifndef DISABLE_PYTHON static void do_text_template_scriptsmenu(void *arg, int event) { BPY_menu_do_python(PYMENU_SCRIPTTEMPLATE, event); @@ -293,6 +296,7 @@ static uiBlock *text_plugin_scriptsmenu (void *args_unused) return block; } +#endif /* action executed after clicking in File menu */ static void do_text_filemenu(void *arg, int event) @@ -316,8 +320,10 @@ static void do_text_filemenu(void *arg, int event) activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs); break; case 3: +#ifndef DISABLE_PYTHON if (text->compiled) BPY_free_compiled_text(text); text->compiled = NULL; +#endif if (okee("Reopen Text")) { if (!reopen_text(text)) { error("Could not reopen file"); @@ -339,6 +345,7 @@ static void do_text_filemenu(void *arg, int event) run_python_script(st); break; case 8: +#ifndef DISABLE_PYTHON { Object *ob; bConstraint *con; @@ -373,6 +380,7 @@ static void do_text_filemenu(void *arg, int event) } } } +#endif break; default: break; @@ -820,16 +828,18 @@ static uiBlock *text_filemenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Run Python Script|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, ""); - +#ifndef DISABLE_PYTHON if (BPY_is_pyconstraint(text)) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Refresh All PyConstraints", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, ""); - +#endif uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); } - + +#ifndef DISABLE_PYTHON uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, ""); uiDefIconTextBlockBut(block, text_plugin_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Text Plugins", 0, yco-=20, 120, 19, ""); - +#endif + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -924,8 +934,10 @@ static short do_modification_check(SpaceText *st_v) { } else { switch (pupmenu("File Modified Outside Blender %t|Reload from disk %x0|Make text internal (separate copy) %x1|Ignore %x2")) { case 0: +#ifndef DISABLE_PYTHON if (text->compiled) BPY_free_compiled_text(text); text->compiled = NULL; +#endif reopen_text(text); if (st->showsyntax) txt_format_text(st); return 1; diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index d57fa18a705..e2caf97df05 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -125,8 +125,10 @@ #include "BIF_verse.h" #endif +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "blendef.h" #include "multires.h" @@ -461,6 +463,7 @@ static uiBlock *view3d_view_alignviewmenu(void *arg_unused) return block; } +#ifndef DISABLE_PYTHON static void do_view3d_view_spacehandlers(void *arg, int event) { Text *text = G.main->text.first; @@ -548,6 +551,7 @@ static uiBlock *view3d_view_spacehandlers(void *arg_unused) return block; } +#endif /* DISABLE_PYTHON */ static void do_view3d_viewmenu(void *arg, int event) { @@ -691,8 +695,10 @@ static uiBlock *view3d_viewmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation|Alt A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, view3d_view_spacehandlers, NULL, ICON_RIGHTARROW_THIN, "Space Handler Scripts", 0, yco-=20, 120, 19, ""); +#endif if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); @@ -1468,8 +1474,10 @@ static uiBlock *view3d_select_pose_armaturemenu(void *arg_unused) void do_view3d_select_faceselmenu(void *arg, int event) { /* events >= 6 are registered bpython scripts */ +#ifndef DISABLE_PYTHON if (event >= 6) BPY_menu_do_python(PYMENU_FACESELECT, event - 6); - +#endif + switch(event) { case 0: /* border select */ borderselect(); @@ -1491,7 +1499,9 @@ static uiBlock *view3d_select_faceselmenu(void *arg_unused) { uiBlock *block; short yco= 0, menuwidth=120; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i = 0; block= uiNewBlock(&curarea->uiblocks, "view3d_select_faceselmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); @@ -1507,6 +1517,7 @@ static uiBlock *view3d_select_faceselmenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linked Faces|Ctrl L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); /* note that we account for the 6 previous entries with i+6: */ @@ -1515,7 +1526,8 @@ static uiBlock *view3d_select_faceselmenu(void *arg_unused) menuwidth, 19, NULL, 0.0, 0.0, 1, i+6, pym->tooltip?pym->tooltip:pym->filename); } - +#endif + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -2445,6 +2457,7 @@ static uiBlock *view3d_edit_object_showhidemenu(void *arg_unused) return block; } +#ifndef DISABLE_PYTHON static void do_view3d_edit_object_scriptsmenu(void *arg, int event) { BPY_menu_do_python(PYMENU_OBJECT, event); @@ -2471,6 +2484,7 @@ static uiBlock *view3d_edit_object_scriptsmenu(void *arg_unused) return block; } +#endif /* DISABLE_PYTHON */ #ifdef WITH_VERSE extern ListBase session_list; @@ -2610,9 +2624,10 @@ static uiBlock *view3d_edit_objectmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move to Layer...|M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, ""); uiDefIconTextBlockBut(block, view3d_edit_object_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Objects", 0, yco-=20, 120, 19, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, view3d_edit_object_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, ""); - +#endif if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); @@ -3078,6 +3093,7 @@ static uiBlock *view3d_edit_mesh_showhidemenu(void *arg_unused) return block; } +#ifndef DISABLE_PYTHON static void do_view3d_edit_mesh_scriptsmenu(void *arg, int event) { BPY_menu_do_python(PYMENU_MESH, event); @@ -3104,6 +3120,7 @@ static uiBlock *view3d_edit_mesh_scriptsmenu(void *arg_unused) return block; } +#endif /* DISABLE_PYTHON */ static void do_view3d_edit_meshmenu(void *arg, int event) { @@ -3248,9 +3265,11 @@ static uiBlock *view3d_edit_meshmenu(void *arg_unused) uiDefIconTextBlockBut(block, view3d_edit_mesh_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Vertices", 0, yco-=20, 120, 19, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, view3d_edit_mesh_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, ""); - +#endif + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -3965,7 +3984,7 @@ static void do_view3d_edit_armaturemenu(void *arg, int event) } - +#ifndef DISABLE_PYTHON static void do_view3d_scripts_armaturemenu(void *arg, int event) { BPY_menu_do_python(PYMENU_ARMATURE, event); @@ -3996,6 +4015,7 @@ static uiBlock *view3d_scripts_armaturemenu(void *args_unused) return block; } +#endif /* DISABLE_PYTHON */ static void do_view3d_armature_settingsmenu(void *arg, int event) { @@ -4077,10 +4097,11 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused) uiDefIconTextBlockBut(block, view3d_edit_armature_parentmenu, NULL, ICON_RIGHTARROW_THIN, "Parent", 0, yco-=20, 120, 19, ""); uiDefIconTextBlockBut(block, view3d_armature_settingsmenu, NULL, ICON_RIGHTARROW_THIN, "Bone Settings", 0, yco-=20, 120, 19, ""); +#ifndef DISABLE_PYTHON uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBlockBut(block, view3d_scripts_armaturemenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, ""); - +#endif if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -4486,8 +4507,9 @@ static uiBlock *view3d_pose_armaturemenu(void *arg_unused) static void do_view3d_vpaintmenu(void *arg, int event) { /* events >= 3 are registered bpython scripts */ +#ifndef DISABLE_PYTHON if (event >= 3) BPY_menu_do_python(PYMENU_VERTEXPAINT, event - 3); - +#endif switch(event) { case 0: /* undo vertex painting */ BIF_undo(); @@ -4509,7 +4531,9 @@ static uiBlock *view3d_vpaintmenu(void *arg_unused) { uiBlock *block; short yco= 0, menuwidth=120; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i=0; block= uiNewBlock(&curarea->uiblocks, "view3d_paintmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); @@ -4519,6 +4543,7 @@ static uiBlock *view3d_vpaintmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Vertex Colors|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Shaded Vertex Colors", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); +#ifndef DISABLE_PYTHON /* note that we account for the 3 previous entries with i+3: even if the last item isnt displayed, it dosent matter */ for (pym = BPyMenuTable[PYMENU_VERTEXPAINT]; pym; pym = pym->next, i++) { @@ -4526,7 +4551,8 @@ static uiBlock *view3d_vpaintmenu(void *arg_unused) menuwidth, 19, NULL, 0.0, 0.0, 1, i+3, pym->tooltip?pym->tooltip:pym->filename); } - +#endif + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -4581,8 +4607,9 @@ static void do_view3d_wpaintmenu(void *arg, int event) Object *ob= OBACT; /* events >= 3 are registered bpython scripts */ +#ifndef DISABLE_PYTHON if (event >= 4) BPY_menu_do_python(PYMENU_WEIGHTPAINT, event - 4); - +#endif switch(event) { case 0: /* undo weight painting */ BIF_undo(); @@ -4604,7 +4631,9 @@ static uiBlock *view3d_wpaintmenu(void *arg_unused) { uiBlock *block; short yco= 0, menuwidth=120, menunr=1; +#ifndef DISABLE_PYTHON BPyMenu *pym; +#endif int i=0; block= uiNewBlock(&curarea->uiblocks, "view3d_paintmenu", UI_EMBOSSP, UI_HELV, curarea->headwin); @@ -4624,7 +4653,8 @@ static uiBlock *view3d_wpaintmenu(void *arg_unused) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); menunr++; } - + +#ifndef DISABLE_PYTHON /* note that we account for the 4 previous entries with i+4: even if the last item isnt displayed, it dosent matter */ for (pym = BPyMenuTable[PYMENU_WEIGHTPAINT]; pym; pym = pym->next, i++) { @@ -4632,7 +4662,8 @@ static uiBlock *view3d_wpaintmenu(void *arg_unused) menuwidth, 19, NULL, 0.0, 0.0, 1, i+4, pym->tooltip?pym->tooltip:pym->filename); } - +#endif + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } @@ -4904,8 +4935,9 @@ static uiBlock *view3d_faceselmenu(void *arg_unused) void do_view3d_select_particlemenu(void *arg, int event) { /* events >= 6 are registered bpython scripts */ +#ifndef DISABLE_PYTHON if (event >= 6) BPY_menu_do_python(PYMENU_FACESELECT, event - 6); - +#endif switch(event) { case 0: PE_borderselect(); diff --git a/source/blender/src/headerbuttons.c b/source/blender/src/headerbuttons.c index 44044841a99..f4135071e3e 100644 --- a/source/blender/src/headerbuttons.c +++ b/source/blender/src/headerbuttons.c @@ -161,8 +161,10 @@ #include "BDR_editmball.h" #include "BDR_sculptmode.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "GPU_draw.h" @@ -425,6 +427,15 @@ static void do_update_for_newframe(int mute, int events) /* composite */ if(G.scene->use_nodes && G.scene->nodetree) ntreeCompositTagAnimated(G.scene->nodetree); + + /* update animated texture nodes */ + { + Tex *tex; + for(tex= G.main->tex.first; tex; tex= tex->id.next) + if( tex->use_nodes && tex->nodetree ) { + ntreeTexTagAnimated( tex->nodetree ); + } + } } void update_for_newframe(void) @@ -535,6 +546,7 @@ static void filesel_u_renderdir(char *name) allqueue(REDRAWALL, 0); } +#ifndef DISABLE_PYTHON static void filesel_u_pythondir(char *name) { char dir[FILE_MAXDIR], file[FILE_MAXFILE]; @@ -550,6 +562,7 @@ static void filesel_u_pythondir(char *name) error("Invalid scripts dir: check console"); } } +#endif static void filesel_u_sounddir(char *name) { @@ -854,10 +867,25 @@ void do_global_buttons(unsigned short event) break; case B_EXTEXBROWSE: case B_TEXBROWSE: - - if(G.buts->texnr== -2) { + { + void *lockpoin = NULL; + short *menunr = 0; + + /* this is called now from Node editor too, buttons might not exist */ + if(curarea->spacetype==SPACE_NODE) { + SpaceNode *snode = curarea->spacedata.first; + menunr = &snode->menunr; + lockpoin = snode->id; + } + else if(G.buts) { + menunr = &G.buts->texnr; + lockpoin = G.buts->lockpoin; + } + else return; + + if(*menunr == -2) { - id= G.buts->lockpoin; + id= lockpoin; if(event==B_EXTEXBROWSE) { id= NULL; ma= give_current_material(ob, ob->actcol); @@ -868,16 +896,16 @@ void do_global_buttons(unsigned short event) } } if(G.qual & LR_CTRLKEY) { - activate_databrowse_imasel(id, ID_TE, 0, B_TEXBROWSE, &G.buts->texnr, do_global_buttons); + activate_databrowse_imasel((ID*)lockpoin, ID_TE, 0, B_TEXBROWSE, menunr, do_global_buttons); } else { - activate_databrowse(id, ID_TE, 0, B_TEXBROWSE, &G.buts->texnr, do_global_buttons); + activate_databrowse((ID*)lockpoin, ID_TE, 0, B_TEXBROWSE, menunr, do_global_buttons); } return; } - if(G.buts->texnr < 0) break; + if(*menunr < 0) break; - if(G.buts->pin) { + if(G.buts && G.buts->pin) { } else { @@ -892,7 +920,7 @@ void do_global_buttons(unsigned short event) idtest= G.main->tex.first; while(idtest) { - if(nr==G.buts->texnr) { + if(nr==*menunr) { break; } nr++; @@ -915,10 +943,12 @@ void do_global_buttons(unsigned short event) allqueue(REDRAWBUTSSHADING, 0); allqueue(REDRAWIPO, 0); allqueue(REDRAWOOPS, 0); + allqueue(REDRAWNODE, 0); BIF_preview_changed(ID_MA); } } break; + } case B_ACTIONDELETE: /* only available when not pinned */ if (G.saction->pin == 0) { @@ -1525,7 +1555,7 @@ void do_global_buttons(unsigned short event) activate_fileselect(FILE_SPECIAL, "SELECT RENDER PATH", U.renderdir, filesel_u_renderdir); break; - +#ifndef DISABLE_PYTHON case B_PYMENUEVAL: /* is button from space.c *info* */ waitcursor( 1 ); /* can take some time */ if (BPY_path_update() == 0) { /* re-eval scripts registration in menus */ @@ -1542,7 +1572,7 @@ void do_global_buttons(unsigned short event) activate_fileselect(FILE_SPECIAL, "SELECT SCRIPT PATH", U.pythondir, filesel_u_pythondir); break; - +#endif case B_SOUNDDIRFILESEL: /* is button from space.c *info* */ if(curarea->spacetype==SPACE_INFO) { sa= closest_bigger_area(); diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index 7c1a4668a56..7417218f253 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -96,7 +96,9 @@ #include "BSE_view.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" /* for BPY_button_eval */ +#endif #include "GHOST_Types.h" /* for tablet data */ @@ -1806,7 +1808,7 @@ static int ui_do_but_TEX(uiBut *but) ((G.qual & LR_COMMANDKEY) || (G.qual & LR_CTRLKEY)) && ((dev==XKEY) || (dev==CKEY) || (dev==VKEY)) ) { - char buf[UI_MAX_DRAW_STR]={0}; + char buf[UI_MAX_DRAW_STR+1]={0}; /* paste */ if (dev==VKEY) { @@ -2144,15 +2146,19 @@ static int ui_act_as_text_but(uiBut *but) but->max= max; if(textleft==0) but->flag &= ~UI_TEXT_LEFT; +#ifndef DISABLE_PYTHON if(BPY_button_eval(str, &value)) { /* Uncomment this if you want to see an error message (and annoy users) */ /* error("Invalid Python expression, check console");*/ value = 0.0f; /* Zero out value on error */ if(str[0]) - retval = 0; /* invalidate return value if eval failed, except when string was null */ + retval = B_NOP; /* invalidate return value if eval failed, except when string was null */ } - +#else + value=atof(str); +#endif + if(but->pointype!=FLO) value= (int)value; if(but->type==NUMABS) value= fabs(value); diff --git a/source/blender/src/interface_draw.c b/source/blender/src/interface_draw.c index 83ae449b989..78e74442342 100644 --- a/source/blender/src/interface_draw.c +++ b/source/blender/src/interface_draw.c @@ -68,6 +68,7 @@ #include "BKE_global.h" #include "BKE_key.h" #include "BKE_utildefines.h" +#include "BKE_texture.h" #include "datatoc.h" /* std font */ @@ -1978,6 +1979,7 @@ static void ui_draw_but_COLORBAND(uiBut *but) CBData *cbd; float x1, y1, sizex, sizey; float dx, v3[2], v1[2], v2[2], v1a[2], v2a[2]; + float pos, colf[4]; int a; if(coba==NULL) return; @@ -1998,7 +2000,7 @@ static void ui_draw_but_COLORBAND(uiBut *but) v1[0]+= dx; } - glShadeModel(GL_SMOOTH); + glShadeModel(GL_FLAT); glEnable(GL_BLEND); cbd= coba->data; @@ -2012,17 +2014,16 @@ static void ui_draw_but_COLORBAND(uiBut *but) glColor4fv( &cbd->r ); glVertex2fv(v1); glVertex2fv(v2); - for(a=0; a<coba->tot; a++, cbd++) { - - v1[0]=v2[0]= x1+ cbd->pos*sizex; - - glColor4fv( &cbd->r ); + for( a = 1; a < sizex; a++ ) { + pos = ((float)a) / (sizex-1); + do_colorband( coba, pos, colf ); + + v1[0]=v2[0]= x1 + a; + + glColor4fv( colf ); glVertex2fv(v1); glVertex2fv(v2); } - - v1[0]=v2[0]= x1+ sizex; - glVertex2fv(v1); glVertex2fv(v2); - + glEnd(); glShadeModel(GL_FLAT); glDisable(GL_BLEND); diff --git a/source/blender/src/poselib.c b/source/blender/src/poselib.c index b819dd2a865..13520c94b87 100644 --- a/source/blender/src/poselib.c +++ b/source/blender/src/poselib.c @@ -508,7 +508,7 @@ void poselib_rename_pose (Object *ob) if (marker == NULL) return; /* get name of pose */ - sprintf(name, marker->name); + strncpy(name, marker->name, sizeof(name)); if (sbutton(name, 0, sizeof(name)-1, "Name: ") == 0) return; diff --git a/source/blender/src/reeb.c b/source/blender/src/reeb.c index 85fb5815c3e..b37087064cb 100644 --- a/source/blender/src/reeb.c +++ b/source/blender/src/reeb.c @@ -30,10 +30,13 @@ #include <stdio.h> #include <stdlib.h> // for qsort +#include "PIL_time.h" + #include "DNA_listBase.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" #include "DNA_meshdata_types.h" +#include "DNA_armature_types.h" #include "MEM_guardedalloc.h" @@ -41,14 +44,20 @@ #include "BLI_arithb.h" #include "BLI_editVert.h" #include "BLI_edgehash.h" +#include "BLI_ghash.h" +#include "BLI_heap.h" #include "BDR_editobject.h" +#include "BMF_Api.h" + #include "BIF_editmesh.h" #include "BIF_editarmature.h" #include "BIF_interface.h" #include "BIF_toolbox.h" #include "BIF_graphics.h" +#include "BIF_gl.h" +#include "BIF_resources.h" #include "BKE_global.h" #include "BKE_utildefines.h" @@ -60,6 +69,10 @@ #include "reeb.h" + +ReebGraph *GLOBAL_RG = NULL; +ReebGraph *FILTERED_RG = NULL; + /* * Skeleton generation algorithm based on: * "Harmonic Skeleton for Realistic Character Animation" @@ -72,11 +85,548 @@ * SIGGRAPH 2007 * * */ + +#define DEBUG_REEB +#define DEBUG_REEB_NODE + +typedef struct VertexData +{ + float w; /* weight */ + int i; /* index */ + ReebNode *n; +} VertexData; + +typedef struct EdgeIndex +{ + EditEdge **edges; + int *offset; +} EdgeIndex; + +typedef enum { + MERGE_LOWER, + MERGE_HIGHER, + MERGE_APPEND +} MergeDirection; int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1); +void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction); int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1); -EditEdge * NextEdgeForVert(EditMesh *em, EditVert *v); +EditEdge * NextEdgeForVert(EdgeIndex *indexed_edges, int index); +void mergeArcFaces(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc); +void addFacetoArc(ReebArc *arc, EditFace *efa); + +void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count); +void REEB_AxialSymmetry(BNode* root_node, BNode* node1, BNode* node2, struct BArc* barc1, BArc* barc2); + +void flipArcBuckets(ReebArc *arc); + + +/***************************************** UTILS **********************************************/ + +VertexData *allocVertexData(EditMesh *em) +{ + VertexData *data; + EditVert *eve; + int totvert, index; + + totvert = BLI_countlist(&em->verts); + + data = MEM_callocN(sizeof(VertexData) * totvert, "VertexData"); + + for(index = 0, eve = em->verts.first; eve; index++, eve = eve->next) + { + data[index].i = index; + data[index].w = 0; + eve->tmp.p = data + index; + } + + return data; +} + +int indexData(EditVert *eve) +{ + return ((VertexData*)eve->tmp.p)->i; +} + +float weightData(EditVert *eve) +{ + return ((VertexData*)eve->tmp.p)->w; +} + +void weightSetData(EditVert *eve, float w) +{ + ((VertexData*)eve->tmp.p)->w = w; +} + +ReebNode* nodeData(EditVert *eve) +{ + return ((VertexData*)eve->tmp.p)->n; +} + +void nodeSetData(EditVert *eve, ReebNode *n) +{ + ((VertexData*)eve->tmp.p)->n = n; +} + +void REEB_freeArc(BArc *barc) +{ + ReebArc *arc = (ReebArc*)barc; + BLI_freelistN(&arc->edges); + + if (arc->buckets) + MEM_freeN(arc->buckets); + + if (arc->faces) + BLI_ghash_free(arc->faces, NULL, NULL); + + MEM_freeN(arc); +} + +void REEB_freeGraph(ReebGraph *rg) +{ + ReebArc *arc; + ReebNode *node; + + // free nodes + for( node = rg->nodes.first; node; node = node->next ) + { + BLI_freeNode((BGraph*)rg, (BNode*)node); + } + BLI_freelistN(&rg->nodes); + + // free arcs + arc = rg->arcs.first; + while( arc ) + { + ReebArc *next = arc->next; + REEB_freeArc((BArc*)arc); + arc = next; + } + + // free edge map + BLI_edgehash_free(rg->emap, NULL); + + /* free linked graph */ + if (rg->link_up) + { + REEB_freeGraph(rg->link_up); + } + + MEM_freeN(rg); +} + +ReebGraph * newReebGraph() +{ + ReebGraph *rg; + rg = MEM_callocN(sizeof(ReebGraph), "reeb graph"); + + rg->totnodes = 0; + rg->emap = BLI_edgehash_new(); + + + rg->free_arc = REEB_freeArc; + rg->free_node = NULL; + rg->radial_symmetry = REEB_RadialSymmetry; + rg->axial_symmetry = REEB_AxialSymmetry; + + return rg; +} + +void BIF_flagMultiArcs(ReebGraph *rg, int flag) +{ + for ( ; rg; rg = rg->link_up) + { + BLI_flagArcs((BGraph*)rg, flag); + } +} + +ReebNode * addNode(ReebGraph *rg, EditVert *eve) +{ + float weight; + ReebNode *node = NULL; + + weight = weightData(eve); + + node = MEM_callocN(sizeof(ReebNode), "reeb node"); + + node->flag = 0; // clear flag on init + node->symmetry_level = 0; + node->arcs = NULL; + node->degree = 0; + node->weight = weight; + node->index = rg->totnodes; + VECCOPY(node->p, eve->co); + + BLI_addtail(&rg->nodes, node); + rg->totnodes++; + + nodeSetData(eve, node); + + return node; +} + +ReebNode * copyNode(ReebGraph *rg, ReebNode *node) +{ + ReebNode *cp_node = NULL; + + cp_node = MEM_callocN(sizeof(ReebNode), "reeb node copy"); + + memcpy(cp_node, node, sizeof(ReebNode)); + + cp_node->prev = NULL; + cp_node->next = NULL; + cp_node->arcs = NULL; + + cp_node->link_up = NULL; + cp_node->link_down = NULL; + + BLI_addtail(&rg->nodes, cp_node); + rg->totnodes++; + + return cp_node; +} + +void relinkNodes(ReebGraph *low_rg, ReebGraph *high_rg) +{ + ReebNode *low_node, *high_node; + + if (low_rg == NULL || high_rg == NULL) + { + return; + } + + for (low_node = low_rg->nodes.first; low_node; low_node = low_node->next) + { + for (high_node = high_rg->nodes.first; high_node; high_node = high_node->next) + { + if (low_node->index == high_node->index) + { + high_node->link_down = low_node; + low_node->link_up = high_node; + break; + } + } + } +} + +ReebNode *BIF_otherNodeFromIndex(ReebArc *arc, ReebNode *node) +{ + return (arc->head->index == node->index) ? arc->tail : arc->head; +} + +ReebNode *BIF_NodeFromIndex(ReebArc *arc, ReebNode *node) +{ + return (arc->head->index == node->index) ? arc->head : arc->tail; +} + +ReebNode *BIF_lowestLevelNode(ReebNode *node) +{ + while (node->link_down) + { + node = node->link_down; + } + + return node; +} + +ReebArc * copyArc(ReebGraph *rg, ReebArc *arc) +{ + ReebArc *cp_arc; + ReebNode *node; + + cp_arc = MEM_callocN(sizeof(ReebArc), "reeb arc copy"); + + memcpy(cp_arc, arc, sizeof(ReebArc)); + + cp_arc->link_up = arc; + + cp_arc->head = NULL; + cp_arc->tail = NULL; + + cp_arc->prev = NULL; + cp_arc->next = NULL; + + cp_arc->edges.first = NULL; + cp_arc->edges.last = NULL; + + /* copy buckets */ + cp_arc->buckets = MEM_callocN(sizeof(EmbedBucket) * cp_arc->bcount, "embed bucket"); + memcpy(cp_arc->buckets, arc->buckets, sizeof(EmbedBucket) * cp_arc->bcount); + + /* copy faces map */ + cp_arc->faces = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + mergeArcFaces(rg, cp_arc, arc); + + /* find corresponding head and tail */ + for (node = rg->nodes.first; node && (cp_arc->head == NULL || cp_arc->tail == NULL); node = node->next) + { + if (node->index == arc->head->index) + { + cp_arc->head = node; + } + else if (node->index == arc->tail->index) + { + cp_arc->tail = node; + } + } + + BLI_addtail(&rg->arcs, cp_arc); + + return cp_arc; +} + +ReebGraph * copyReebGraph(ReebGraph *rg, int level) +{ + ReebNode *node; + ReebArc *arc; + ReebGraph *cp_rg = newReebGraph(); + + cp_rg->resolution = rg->resolution; + cp_rg->length = rg->length; + cp_rg->link_up = rg; + cp_rg->multi_level = level; + + /* Copy nodes */ + for (node = rg->nodes.first; node; node = node->next) + { + ReebNode *cp_node = copyNode(cp_rg, node); + cp_node->multi_level = level; + } + + /* Copy arcs */ + for (arc = rg->arcs.first; arc; arc = arc->next) + { + copyArc(cp_rg, arc); + } + + BLI_buildAdjacencyList((BGraph*)cp_rg); + + return cp_rg; +} + +ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node) +{ + ReebGraph *multi_rg = rg; + + while(multi_rg && multi_rg->multi_level != node->multi_level) + { + multi_rg = multi_rg->link_up; + } + + return multi_rg; +} + +ReebEdge * copyEdge(ReebEdge *edge) +{ + ReebEdge *newEdge = NULL; + + newEdge = MEM_callocN(sizeof(ReebEdge), "reeb edge"); + memcpy(newEdge, edge, sizeof(ReebEdge)); + + newEdge->next = NULL; + newEdge->prev = NULL; + + return newEdge; +} + +void printArc(ReebArc *arc) +{ + ReebEdge *edge; + ReebNode *head = (ReebNode*)arc->head; + ReebNode *tail = (ReebNode*)arc->tail; + printf("arc: (%i) %f -> (%i) %f\n", head->index, head->weight, tail->index, tail->weight); + + for(edge = arc->edges.first; edge ; edge = edge->next) + { + printf("\tedge (%i, %i)\n", edge->v1->index, edge->v2->index); + } +} + +void flipArc(ReebArc *arc) +{ + ReebNode *tmp; + tmp = arc->head; + arc->head = arc->tail; + arc->tail = tmp; + + flipArcBuckets(arc); +} + +#ifdef DEBUG_REEB_NODE +void NodeDegreeDecrement(ReebGraph *rg, ReebNode *node) +{ + node->degree--; + +// if (node->degree == 0) +// { +// printf("would remove node %i\n", node->index); +// } +} + +void NodeDegreeIncrement(ReebGraph *rg, ReebNode *node) +{ +// if (node->degree == 0) +// { +// printf("first connect node %i\n", node->index); +// } + + node->degree++; +} + +#else +#define NodeDegreeDecrement(rg, node) {node->degree--;} +#define NodeDegreeIncrement(rg, node) {node->degree++;} +#endif +void repositionNodes(ReebGraph *rg) +{ + BArc *arc = NULL; + BNode *node = NULL; + + // Reset node positions + for(node = rg->nodes.first; node; node = node->next) + { + node->p[0] = node->p[1] = node->p[2] = 0; + } + + for(arc = rg->arcs.first; arc; arc = arc->next) + { + if (((ReebArc*)arc)->bcount > 0) + { + float p[3]; + + VECCOPY(p, ((ReebArc*)arc)->buckets[0].p); + VecMulf(p, 1.0f / arc->head->degree); + VecAddf(arc->head->p, arc->head->p, p); + + VECCOPY(p, ((ReebArc*)arc)->buckets[((ReebArc*)arc)->bcount - 1].p); + VecMulf(p, 1.0f / arc->tail->degree); + VecAddf(arc->tail->p, arc->tail->p, p); + } + } +} + +void verifyNodeDegree(ReebGraph *rg) +{ +#ifdef DEBUG_REEB + ReebNode *node = NULL; + ReebArc *arc = NULL; + + for(node = rg->nodes.first; node; node = node->next) + { + int count = 0; + for(arc = rg->arcs.first; arc; arc = arc->next) + { + if (arc->head == node || arc->tail == node) + { + count++; + } + } + if (count != node->degree) + { + printf("degree error in node %i: expected %i got %i\n", node->index, count, node->degree); + } + if (node->degree == 0) + { + printf("zero degree node %i with weight %f\n", node->index, node->weight); + } + } +#endif +} + +void verifyBucketsArc(ReebGraph *rg, ReebArc *arc) +{ + ReebNode *head = (ReebNode*)arc->head; + ReebNode *tail = (ReebNode*)arc->tail; + + if (arc->bcount > 0) + { + int i; + for(i = 0; i < arc->bcount; i++) + { + if (arc->buckets[i].nv == 0) + { + printArc(arc); + printf("count error in bucket %i/%i\n", i+1, arc->bcount); + } + } + + if (ceil(head->weight) != arc->buckets[0].val) + { + printArc(arc); + printf("alloc error in first bucket: %f should be %f \n", arc->buckets[0].val, ceil(head->weight)); + } + if (floor(tail->weight) != arc->buckets[arc->bcount - 1].val) + { + printArc(arc); + printf("alloc error in last bucket: %f should be %f \n", arc->buckets[arc->bcount - 1].val, floor(tail->weight)); + } + } +} + +void verifyBuckets(ReebGraph *rg) +{ +#ifdef DEBUG_REEB + ReebArc *arc = NULL; + for(arc = rg->arcs.first; arc; arc = arc->next) + { + verifyBucketsArc(rg, arc); + } +#endif +} + +void verifyFaces(ReebGraph *rg) +{ +#ifdef DEBUG_REEB + int total = 0; + ReebArc *arc = NULL; + for(arc = rg->arcs.first; arc; arc = arc->next) + { + total += BLI_ghash_size(arc->faces); + } + +#endif +} + +void verifyArcs(ReebGraph *rg) +{ + ReebArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + if (arc->head->weight > arc->tail->weight) + { + printf("FLIPPED ARC!\n"); + } + } +} + +void verifyMultiResolutionLinks(ReebGraph *rg, int level) +{ +#ifdef DEBUG_REEB + ReebGraph *lower_rg = rg->link_up; + + if (lower_rg) + { + ReebArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) + { + if (BLI_findindex(&lower_rg->arcs, arc->link_up) == -1) + { + printf("missing arc %p for level %i\n", arc->link_up, level); + printf("Source arc was ---\n"); + printArc(arc); + + arc->link_up = NULL; + } + } + + + verifyMultiResolutionLinks(lower_rg, level + 1); + } +#endif +} /***************************************** BUCKET UTILS **********************************************/ void addVertToBucket(EmbedBucket *b, float co[3]) @@ -137,11 +687,30 @@ void mergeArcBuckets(ReebArc *aDst, ReebArc *aSrc, float start, float end) } } +void flipArcBuckets(ReebArc *arc) +{ + int i, j; + + for (i = 0, j = arc->bcount - 1; i < j; i++, j--) + { + EmbedBucket tmp; + + tmp = arc->buckets[i]; + arc->buckets[i] = arc->buckets[j]; + arc->buckets[j] = tmp; + } +} + +int countArcBuckets(ReebArc *arc) +{ + return (int)(floor(arc->tail->weight) - ceil(arc->head->weight)) + 1; +} + void allocArcBuckets(ReebArc *arc) { int i; - float start = ceil(arc->v1->weight); - arc->bcount = (int)(floor(arc->v2->weight) - start) + 1; + float start = ceil(arc->head->weight); + arc->bcount = countArcBuckets(arc); if (arc->bcount > 0) { @@ -164,6 +733,11 @@ void resizeArcBuckets(ReebArc *arc) EmbedBucket *oldBuckets = arc->buckets; int oldBCount = arc->bcount; + if (countArcBuckets(arc) == oldBCount) + { + return; + } + allocArcBuckets(arc); if (oldBCount != 0 && arc->bcount != 0) @@ -195,234 +769,394 @@ void resizeArcBuckets(ReebArc *arc) MEM_freeN(oldBuckets); } } -/***************************************** UTILS **********************************************/ -ReebEdge * copyEdge(ReebEdge *edge) +void reweightBuckets(ReebArc *arc) { - ReebEdge *newEdge = NULL; - - newEdge = MEM_callocN(sizeof(ReebEdge), "reeb edge"); - memcpy(newEdge, edge, sizeof(ReebEdge)); - - newEdge->next = NULL; - newEdge->prev = NULL; + int i; + float start = ceil((arc->head)->weight); - return newEdge; + if (arc->bcount > 0) + { + for(i = 0; i < arc->bcount; i++) + { + arc->buckets[i].val = start + i; + } + } } -void printArc(ReebArc *arc) +static void interpolateBuckets(ReebArc *arc, float *start_p, float *end_p, int start_index, int end_index) { - ReebEdge *edge; - printf("arc: (%i)%f -> (%i)%f\n", arc->v1->index, arc->v1->weight, arc->v2->index, arc->v2->weight); + int total; + int j; - for(edge = arc->edges.first; edge ; edge = edge->next) + total = end_index - start_index + 2; + + for (j = start_index; j <= end_index; j++) { - printf("\tedge (%i, %i)\n", edge->v1->index, edge->v2->index); + EmbedBucket *empty = arc->buckets + j; + empty->nv = 1; + VecLerpf(empty->p, start_p, end_p, (float)(j - start_index + 1) / total); } } -void freeArc(ReebArc *arc) +void fillArcEmptyBuckets(ReebArc *arc) { - BLI_freelistN(&arc->edges); + float *start_p, *end_p; + int start_index = 0, end_index = 0; + int missing = 0; + int i; - if (arc->buckets) - MEM_freeN(arc->buckets); + start_p = arc->head->p; - MEM_freeN(arc); + for(i = 0; i < arc->bcount; i++) + { + EmbedBucket *bucket = arc->buckets + i; + + if (missing) + { + if (bucket->nv > 0) + { + missing = 0; + + end_p = bucket->p; + end_index = i - 1; + + interpolateBuckets(arc, start_p, end_p, start_index, end_index); + } + } + else + { + if (bucket->nv == 0) + { + missing = 1; + + if (i > 0) + { + start_p = arc->buckets[i - 1].p; + } + start_index = i; + } + } + } + + if (missing) + { + end_p = arc->tail->p; + end_index = arc->bcount - 1; + + interpolateBuckets(arc, start_p, end_p, start_index, end_index); + } } -void freeGraph(ReebGraph *rg) +static void ExtendArcBuckets(ReebArc *arc) { - ReebArc *arc; - ReebNode *node; + ReebArcIterator iter; + EmbedBucket *previous, *bucket, *last_bucket, *first_bucket; + float average_length = 0, length; + int padding_head = 0, padding_tail = 0; - // free nodes - for( node = rg->nodes.first; node; node = node->next ) + if (arc->bcount == 0) { - // Free adjacency lists - if (node->arcs != NULL) - { - MEM_freeN(node->arcs); - } + return; /* failsafe, shouldn't happen */ } - BLI_freelistN(&rg->nodes); - // free arcs - arc = rg->arcs.first; - while( arc ) + initArcIterator(&iter, arc, arc->head); + + for ( previous = nextBucket(&iter), bucket = nextBucket(&iter); + bucket; + previous = bucket, bucket = nextBucket(&iter) + ) { - ReebArc *next = arc->next; - freeArc(arc); - arc = next; + average_length += VecLenf(previous->p, bucket->p); } + average_length /= (arc->bcount - 1); - // free edge map - BLI_edgehash_free(rg->emap, NULL); + first_bucket = arc->buckets; + last_bucket = arc->buckets + (arc->bcount - 1); - MEM_freeN(rg); -} + length = VecLenf(first_bucket->p, arc->head->p); + if (length > 2 * average_length) + { + padding_head = (int)floor(length / average_length); + } -void repositionNodes(ReebGraph *rg) -{ - ReebArc *arc = NULL; - ReebNode *node = NULL; + length = VecLenf(last_bucket->p, arc->tail->p); + if (length > 2 * average_length) + { + padding_tail = (int)floor(length / average_length); + } - // Reset node positions - for(node = rg->nodes.first; node; node = node->next) + if (padding_head + padding_tail > 0) { - node->p[0] = node->p[1] = node->p[2] = 0; + EmbedBucket *old_buckets = arc->buckets; + + arc->buckets = MEM_callocN(sizeof(EmbedBucket) * (padding_head + arc->bcount + padding_tail), "embed bucket"); + memcpy(arc->buckets + padding_head, old_buckets, arc->bcount * sizeof(EmbedBucket)); + + arc->bcount = padding_head + arc->bcount + padding_tail; + + MEM_freeN(old_buckets); } - for(arc = rg->arcs.first; arc; arc = arc->next) + if (padding_head > 0) { - if (arc->bcount > 0) - { - float p[3]; - - VECCOPY(p, arc->buckets[0].p); - VecMulf(p, 1.0f / arc->v1->degree); - VecAddf(arc->v1->p, arc->v1->p, p); - - VECCOPY(p, arc->buckets[arc->bcount - 1].p); - VecMulf(p, 1.0f / arc->v2->degree); - VecAddf(arc->v2->p, arc->v2->p, p); - } + interpolateBuckets(arc, arc->head->p, first_bucket->p, 0, padding_head); } -} - -void verifyNodeDegree(ReebGraph *rg) -{ - ReebNode *node = NULL; - ReebArc *arc = NULL; - - for(node = rg->nodes.first; node; node = node->next) + + if (padding_tail > 0) { - int count = 0; - for(arc = rg->arcs.first; arc; arc = arc->next) - { - if (arc->v1 == node || arc->v2 == node) - { - count++; - } - } - if (count != node->degree) - { - printf("degree error in node %i: expected %i got %i\n", node->index, count, node->degree); - } + interpolateBuckets(arc, last_bucket->p, arc->tail->p, arc->bcount - padding_tail, arc->bcount - 1); } } -void verifyBuckets(ReebGraph *rg) +/* CALL THIS ONLY AFTER FILTERING, SINCE IT MESSES UP WEIGHT DISTRIBUTION */ +void extendGraphBuckets(ReebGraph *rg) { -#ifdef DEBUG_REEB - ReebArc *arc = NULL; - for(arc = rg->arcs.first; arc; arc = arc->next) + ReebArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) { - if (arc->bcount > 0) - { - int i; - for(i = 0; i < arc->bcount; i++) - { - if (arc->buckets[i].nv == 0) - { - printArc(arc); - printf("count error in bucket %i/%i\n", i+1, arc->bcount); - } - } - - if (ceil(arc->v1->weight) < arc->buckets[0].val) - { - printArc(arc); - printf("alloc error in first bucket: %f should be %f \n", arc->buckets[0].val, ceil(arc->v1->weight)); - } - if (floor(arc->v2->weight) < arc->buckets[arc->bcount - 1].val) - { - printArc(arc); - printf("alloc error in last bucket: %f should be %f \n", arc->buckets[arc->bcount - 1].val, floor(arc->v2->weight)); - } - } + ExtendArcBuckets(arc); } -#endif } -/************************************** ADJACENCY LIST *************************************************/ +/**************************************** LENGTH CALCULATIONS ****************************************/ -void addArcToNodeAdjacencyList(ReebNode *node, ReebArc *arc) +void calculateArcLength(ReebArc *arc) { - ReebArc **arclist; + ReebArcIterator iter; + EmbedBucket *bucket = NULL; + float *vec0, *vec1; - for(arclist = node->arcs; *arclist; arclist++) - { } + arc->length = 0; - *arclist = arc; -} - -void buildAdjacencyList(ReebGraph *rg) -{ - ReebNode *node = NULL; - ReebArc *arc = NULL; + initArcIterator(&iter, arc, arc->head); - for(node = rg->nodes.first; node; node = node->next) + bucket = nextBucket(&iter); + + vec0 = arc->head->p; + vec1 = arc->head->p; /* in case there's no embedding */ + + while (bucket != NULL) { - if (node->arcs != NULL) - { - MEM_freeN(node->arcs); - } + vec1 = bucket->p; + + arc->length += VecLenf(vec0, vec1); - node->arcs = MEM_callocN((node->degree + 1) * sizeof(ReebArc*), "adjacency list"); + vec0 = vec1; + bucket = nextBucket(&iter); } + + arc->length += VecLenf(arc->tail->p, vec1); +} - for(arc = rg->arcs.first; arc; arc= arc->next) +void calculateGraphLength(ReebGraph *rg) +{ + ReebArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) { - addArcToNodeAdjacencyList(arc->v1, arc); - addArcToNodeAdjacencyList(arc->v2, arc); + calculateArcLength(arc); } } -int hasAdjacencyList(ReebGraph *rg) +/**************************************** SYMMETRY HANDLING ******************************************/ + +void REEB_RadialSymmetry(BNode* root_node, RadialArc* ring, int count) { - ReebNode *node; + ReebNode *node = (ReebNode*)root_node; + float axis[3]; + int i; - for(node = rg->nodes.first; node; node = node->next) + VECCOPY(axis, root_node->symmetry_axis); + + /* first pass, merge incrementally */ + for (i = 0; i < count - 1; i++) { - if (node->arcs == NULL) + ReebNode *node1, *node2; + ReebArc *arc1, *arc2; + float tangent[3]; + float normal[3]; + int j = i + 1; + + VecAddf(tangent, ring[i].n, ring[j].n); + Crossf(normal, tangent, axis); + + node1 = (ReebNode*)BLI_otherNode(ring[i].arc, root_node); + node2 = (ReebNode*)BLI_otherNode(ring[j].arc, root_node); + + arc1 = (ReebArc*)ring[i].arc; + arc2 = (ReebArc*)ring[j].arc; + + /* mirror first node and mix with the second */ + BLI_mirrorAlongAxis(node1->p, root_node->p, normal); + VecLerpf(node2->p, node2->p, node1->p, 1.0f / (j + 1)); + + /* Merge buckets + * there shouldn't be any null arcs here, but just to be safe + * */ + if (arc1->bcount > 0 && arc2->bcount > 0) { - return 0; + ReebArcIterator iter1, iter2; + EmbedBucket *bucket1 = NULL, *bucket2 = NULL; + + initArcIterator(&iter1, arc1, (ReebNode*)root_node); + initArcIterator(&iter2, arc2, (ReebNode*)root_node); + + bucket1 = nextBucket(&iter1); + bucket2 = nextBucket(&iter2); + + /* Make sure they both start at the same value */ + while(bucket1 && bucket1->val < bucket2->val) + { + bucket1 = nextBucket(&iter1); + } + + while(bucket2 && bucket2->val < bucket1->val) + { + bucket2 = nextBucket(&iter2); + } + + + for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2)) + { + bucket2->nv += bucket1->nv; /* add counts */ + + /* mirror on axis */ + BLI_mirrorAlongAxis(bucket1->p, root_node->p, normal); + /* add bucket2 in bucket1 */ + VecLerpf(bucket2->p, bucket2->p, bucket1->p, (float)bucket1->nv / (float)(bucket2->nv)); + } } } - return 1; + /* second pass, mirror back on previous arcs */ + for (i = count - 1; i > 0; i--) + { + ReebNode *node1, *node2; + ReebArc *arc1, *arc2; + float tangent[3]; + float normal[3]; + int j = i - 1; + + VecAddf(tangent, ring[i].n, ring[j].n); + Crossf(normal, tangent, axis); + + node1 = (ReebNode*)BLI_otherNode(ring[i].arc, root_node); + node2 = (ReebNode*)BLI_otherNode(ring[j].arc, root_node); + + arc1 = (ReebArc*)ring[i].arc; + arc2 = (ReebArc*)ring[j].arc; + + /* copy first node than mirror */ + VECCOPY(node2->p, node1->p); + BLI_mirrorAlongAxis(node2->p, root_node->p, normal); + + /* Copy buckets + * there shouldn't be any null arcs here, but just to be safe + * */ + if (arc1->bcount > 0 && arc2->bcount > 0) + { + ReebArcIterator iter1, iter2; + EmbedBucket *bucket1 = NULL, *bucket2 = NULL; + + initArcIterator(&iter1, arc1, node); + initArcIterator(&iter2, arc2, node); + + bucket1 = nextBucket(&iter1); + bucket2 = nextBucket(&iter2); + + /* Make sure they both start at the same value */ + while(bucket1 && bucket1->val < bucket2->val) + { + bucket1 = nextBucket(&iter1); + } + + while(bucket2 && bucket2->val < bucket1->val) + { + bucket2 = nextBucket(&iter2); + } + + + for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2)) + { + /* copy and mirror back to bucket2 */ + bucket2->nv = bucket1->nv; + VECCOPY(bucket2->p, bucket1->p); + BLI_mirrorAlongAxis(bucket2->p, node->p, normal); + } + } + } } -int countConnectedArcs(ReebGraph *rg, ReebNode *node) +void REEB_AxialSymmetry(BNode* root_node, BNode* node1, BNode* node2, struct BArc* barc1, BArc* barc2) { - int count = 0; + ReebArc *arc1, *arc2; + float nor[3], p[3]; + + arc1 = (ReebArc*)barc1; + arc2 = (ReebArc*)barc2; + + VECCOPY(nor, root_node->symmetry_axis); - /* use adjacency list if present */ - if (node->arcs) + /* mirror node2 along axis */ + VECCOPY(p, node2->p); + BLI_mirrorAlongAxis(p, root_node->p, nor); + + /* average with node1 */ + VecAddf(node1->p, node1->p, p); + VecMulf(node1->p, 0.5f); + + /* mirror back on node2 */ + VECCOPY(node2->p, node1->p); + BLI_mirrorAlongAxis(node2->p, root_node->p, nor); + + /* Merge buckets + * there shouldn't be any null arcs here, but just to be safe + * */ + if (arc1->bcount > 0 && arc2->bcount > 0) { - ReebArc **arcs; + ReebArcIterator iter1, iter2; + EmbedBucket *bucket1 = NULL, *bucket2 = NULL; + + initArcIterator(&iter1, arc1, (ReebNode*)root_node); + initArcIterator(&iter2, arc2, (ReebNode*)root_node); + + bucket1 = nextBucket(&iter1); + bucket2 = nextBucket(&iter2); - for(arcs = node->arcs; *arcs; arcs++) + /* Make sure they both start at the same value */ + while(bucket1 && bucket1->val < bucket2->val) { - count++; + bucket1 = nextBucket(&iter1); } - } - else - { - ReebArc *arc; - for(arc = rg->arcs.first; arc; arc = arc->next) + + while(bucket2 && bucket2->val < bucket1->val) { - if (arc->v1 == node || arc->v2 == node) - { - count++; - } + bucket2 = nextBucket(&iter2); + } + + + for ( ;bucket1 && bucket2; bucket1 = nextBucket(&iter1), bucket2 = nextBucket(&iter2)) + { + bucket1->nv += bucket2->nv; /* add counts */ + + /* mirror on axis */ + BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor); + /* add bucket2 in bucket1 */ + VecLerpf(bucket1->p, bucket1->p, bucket2->p, (float)bucket2->nv / (float)(bucket1->nv)); + + /* copy and mirror back to bucket2 */ + bucket2->nv = bucket1->nv; + VECCOPY(bucket2->p, bucket1->p); + BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor); } } - - return count; } +/************************************** ADJACENCY LIST *************************************************/ + + /****************************************** SMOOTHING **************************************************/ void postprocessGraph(ReebGraph *rg, char mode) @@ -492,12 +1226,14 @@ int compareArcsWeight(void *varc1, void *varc2) { ReebArc *arc1 = (ReebArc*)varc1; ReebArc *arc2 = (ReebArc*)varc2; + ReebNode *node1 = (ReebNode*)arc1->head; + ReebNode *node2 = (ReebNode*)arc2->head; - if (arc1->v1->weight < arc2->v1->weight) + if (node1->weight < node2->weight) { return -1; } - if (arc1->v1->weight > arc2->v1->weight) + if (node1->weight > node2->weight) { return 1; } @@ -511,15 +1247,235 @@ void sortArcs(ReebGraph *rg) { BLI_sortlist(&rg->arcs, compareArcsWeight); } +/******************************************* JOINING ***************************************************/ + +void reweightArc(ReebGraph *rg, ReebArc *arc, ReebNode *start_node, float start_weight) +{ + ReebNode *node; + float old_weight; + float end_weight = start_weight + ABS(arc->tail->weight - arc->head->weight); + int i; + + node = (ReebNode*)BLI_otherNode((BArc*)arc, (BNode*)start_node); + + /* prevent backtracking */ + if (node->flag == 1) + { + return; + } + + if (arc->tail == start_node) + { + flipArc(arc); + } + + start_node->flag = 1; + + for (i = 0; i < node->degree; i++) + { + ReebArc *next_arc = node->arcs[i]; + + reweightArc(rg, next_arc, node, end_weight); + } + + /* update only if needed */ + if (arc->head->weight != start_weight || arc->tail->weight != end_weight) + { + old_weight = arc->head->weight; /* backup head weight, other arcs need it intact, it will be fixed by the source arc */ + + arc->head->weight = start_weight; + arc->tail->weight = end_weight; + + reweightBuckets(arc); + resizeArcBuckets(arc); + fillArcEmptyBuckets(arc); + + arc->head->weight = old_weight; + } +} + +void reweightSubgraph(ReebGraph *rg, ReebNode *start_node, float start_weight) +{ + int i; + + BLI_flagNodes((BGraph*)rg, 0); + + for (i = 0; i < start_node->degree; i++) + { + ReebArc *next_arc = start_node->arcs[i]; + + reweightArc(rg, next_arc, start_node, start_weight); + } + start_node->weight = start_weight; +} + +int joinSubgraphsEnds(ReebGraph *rg, float threshold, int nb_subgraphs) +{ + int joined = 0; + int subgraph; + + for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++) + { + ReebNode *start_node, *end_node; + ReebNode *min_node_start = NULL, *min_node_end = NULL; + float min_distance = FLT_MAX; + + for (start_node = rg->nodes.first; start_node; start_node = start_node->next) + { + if (start_node->subgraph_index == subgraph && start_node->degree == 1) + { + + for (end_node = rg->nodes.first; end_node; end_node = end_node->next) + { + if (end_node->subgraph_index != subgraph) + { + float distance = VecLenf(start_node->p, end_node->p); + + if (distance < threshold && distance < min_distance) + { + min_distance = distance; + min_node_end = end_node; + min_node_start = start_node; + } + } + } + } + } + + end_node = min_node_end; + start_node = min_node_start; + + if (end_node && start_node) + { + ReebArc *start_arc, *end_arc; + int merging = 0; + + start_arc = start_node->arcs[0]; + end_arc = end_node->arcs[0]; + + if (start_arc->tail == start_node) + { + reweightSubgraph(rg, end_node, start_node->weight); + + start_arc->tail = end_node; + + merging = 1; + } + else if (start_arc->head == start_node) + { + reweightSubgraph(rg, start_node, end_node->weight); + + start_arc->head = end_node; + + merging = 2; + } + + if (merging) + { + BLI_ReflagSubgraph((BGraph*)rg, end_node->flag, subgraph); + + resizeArcBuckets(start_arc); + fillArcEmptyBuckets(start_arc); + + NodeDegreeIncrement(rg, end_node); + BLI_rebuildAdjacencyListForNode((BGraph*)rg, (BNode*)end_node); + + BLI_removeNode((BGraph*)rg, (BNode*)start_node); + } + + joined = 1; + } + } + + return joined; +} + +/* Reweight graph from smallest node, fix fliped arcs */ +void fixSubgraphsOrientation(ReebGraph *rg, int nb_subgraphs) +{ + int subgraph; + + for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++) + { + ReebNode *node; + ReebNode *start_node = NULL; + + for (node = rg->nodes.first; node; node = node->next) + { + if (node->subgraph_index == subgraph) + { + if (start_node == NULL || node->weight < start_node->weight) + { + start_node = node; + } + } + } + + if (start_node) + { + reweightSubgraph(rg, start_node, start_node->weight); + } + } +} + +int joinSubgraphs(ReebGraph *rg, float threshold) +{ + int nb_subgraphs; + int joined = 0; + + BLI_buildAdjacencyList((BGraph*)rg); + + if (BLI_isGraphCyclic((BGraph*)rg)) + { + /* don't deal with cyclic graphs YET */ + return 0; + } + + /* sort nodes before flagging subgraphs to make sure root node is subgraph 0 */ + sortNodes(rg); + + nb_subgraphs = BLI_FlagSubgraphs((BGraph*)rg); + + /* Harmonic function can create flipped arcs, take the occasion to fix them */ + if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC) + { + fixSubgraphsOrientation(rg, nb_subgraphs); + } + + if (nb_subgraphs > 1) + { + joined |= joinSubgraphsEnds(rg, threshold, nb_subgraphs); + + if (joined) + { + removeNormalNodes(rg); + BLI_buildAdjacencyList((BGraph*)rg); + } + } + + return joined; +} /****************************************** FILTERING **************************************************/ +float lengthArc(ReebArc *arc) +{ +#if 0 + ReebNode *head = (ReebNode*)arc->head; + ReebNode *tail = (ReebNode*)arc->tail; + + return tail->weight - head->weight; +#else + return arc->length; +#endif +} + int compareArcs(void *varc1, void *varc2) { ReebArc *arc1 = (ReebArc*)varc1; ReebArc *arc2 = (ReebArc*)varc2; - float len1 = arc1->v2->weight - arc1->v1->weight; - float len2 = arc2->v2->weight - arc2->v1->weight; + float len1 = lengthArc(arc1); + float len2 = lengthArc(arc2); if (len1 < len2) { @@ -539,12 +1495,17 @@ void filterArc(ReebGraph *rg, ReebNode *newNode, ReebNode *removedNode, ReebArc { ReebArc *arc = NULL, *nextArc = NULL; - /* first pass, merge buckets for arcs that spawned the two nodes into the source arc*/ - for(arc = rg->arcs.first; arc; arc = arc->next) + if (merging) { - if (arc->v1 == srcArc->v1 && arc->v2 == srcArc->v2 && arc != srcArc) + /* first pass, merge buckets for arcs that spawned the two nodes into the source arc*/ + for(arc = rg->arcs.first; arc; arc = arc->next) { - mergeArcBuckets(srcArc, arc, srcArc->v1->weight, srcArc->v2->weight); + if (arc->head == srcArc->head && arc->tail == srcArc->tail && arc != srcArc) + { + ReebNode *head = srcArc->head; + ReebNode *tail = srcArc->tail; + mergeArcBuckets(srcArc, arc, head->weight, tail->weight); + } } } @@ -554,48 +1515,52 @@ void filterArc(ReebGraph *rg, ReebNode *newNode, ReebNode *removedNode, ReebArc { nextArc = arc->next; - if (arc->v1 == removedNode || arc->v2 == removedNode) + if (arc->head == removedNode || arc->tail == removedNode) { - if (arc->v1 == removedNode) + if (arc->head == removedNode) { - arc->v1 = newNode; + arc->head = newNode; } else { - arc->v2 = newNode; + arc->tail = newNode; } // Remove looped arcs - if (arc->v1 == arc->v2) + if (arc->head == arc->tail) { // v1 or v2 was already newNode, since we're removing an arc, decrement degree - newNode->degree--; + NodeDegreeDecrement(rg, newNode); - // If it's safeArc, it'll be removed later, so keep it for now + // If it's srcArc, it'll be removed later, so keep it for now if (arc != srcArc) { BLI_remlink(&rg->arcs, arc); - freeArc(arc); + REEB_freeArc((BArc*)arc); } } - // Remove flipped arcs - else if (arc->v1->weight > arc->v2->weight) - { - // Decrement degree from the other node - OTHER_NODE(arc, newNode)->degree--; - - BLI_remlink(&rg->arcs, arc); - freeArc(arc); - } else { - newNode->degree++; // incrementing degree since we're adding an arc + /* flip arcs that flipped, can happen on diamond shapes, mostly on null arcs */ + if (arc->head->weight > arc->tail->weight) + { + flipArc(arc); + } + //newNode->degree++; // incrementing degree since we're adding an arc + NodeDegreeIncrement(rg, newNode); + mergeArcFaces(rg, arc, srcArc); if (merging) { + ReebNode *head = arc->head; + ReebNode *tail = arc->tail; + // resize bucket list resizeArcBuckets(arc); - mergeArcBuckets(arc, srcArc, arc->v1->weight, arc->v2->weight); + mergeArcBuckets(arc, srcArc, head->weight, tail->weight); + + /* update length */ + arc->length += srcArc->length; } } } @@ -615,14 +1580,13 @@ void filterNullReebGraph(ReebGraph *rg) // Only collapse arcs too short to have any embed bucket if (arc->bcount == 0) { - ReebNode *newNode = arc->v1; - ReebNode *removedNode = arc->v2; + ReebNode *newNode = (ReebNode*)arc->head; + ReebNode *removedNode = (ReebNode*)arc->tail; float blend; blend = (float)newNode->degree / (float)(newNode->degree + removedNode->degree); // blending factors - //newNode->weight = FloatLerpf(newNode->weight, removedNode->weight, blend); - VecLerpf(newNode->p, newNode->p, removedNode->p, blend); + VecLerpf(newNode->p, removedNode->p, newNode->p, blend); filterArc(rg, newNode, removedNode, arc, 0); @@ -630,130 +1594,300 @@ void filterNullReebGraph(ReebGraph *rg) nextArc = arc->next; BLI_remlink(&rg->arcs, arc); - freeArc(arc); + REEB_freeArc((BArc*)arc); - BLI_freelinkN(&rg->nodes, removedNode); + BLI_removeNode((BGraph*)rg, (BNode*)removedNode); } arc = nextArc; } } -int filterInternalReebGraph(ReebGraph *rg, float threshold) +int filterInternalExternalReebGraph(ReebGraph *rg, float threshold_internal, float threshold_external) { ReebArc *arc = NULL, *nextArc = NULL; int value = 0; BLI_sortlist(&rg->arcs, compareArcs); - - arc = rg->arcs.first; - while(arc) + + for (arc = rg->arcs.first; arc; arc = nextArc) { nextArc = arc->next; // Only collapse non-terminal arcs that are shorter than threshold - if ((arc->v1->degree > 1 && arc->v2->degree > 1 && arc->v2->weight - arc->v1->weight < threshold)) + if (threshold_internal > 0 && arc->head->degree > 1 && arc->tail->degree > 1 && (lengthArc(arc) < threshold_internal)) { ReebNode *newNode = NULL; ReebNode *removedNode = NULL; - /* Keep the node with the highestn number of connected arcs */ - if (arc->v1->degree >= arc->v2->degree) + /* Always remove lower node, so arcs don't flip */ + newNode = arc->head; + removedNode = arc->tail; + + filterArc(rg, newNode, removedNode, arc, 1); + + // Reset nextArc, it might have changed + nextArc = arc->next; + + BLI_remlink(&rg->arcs, arc); + REEB_freeArc((BArc*)arc); + + BLI_removeNode((BGraph*)rg, (BNode*)removedNode); + value = 1; + } + + // Only collapse terminal arcs that are shorter than threshold + else if (threshold_external > 0 && (arc->head->degree == 1 || arc->tail->degree == 1) && (lengthArc(arc) < threshold_external)) + { + ReebNode *terminalNode = NULL; + ReebNode *middleNode = NULL; + ReebNode *removedNode = NULL; + + // Assign terminal and middle nodes + if (arc->head->degree == 1) { - newNode = arc->v1; - removedNode = arc->v2; + terminalNode = arc->head; + middleNode = arc->tail; } else { - newNode = arc->v2; - removedNode = arc->v1; + terminalNode = arc->tail; + middleNode = arc->head; } - filterArc(rg, newNode, removedNode, arc, 1); + if (middleNode->degree == 2) + { +#if 1 + // If middle node is a normal node, it will be removed later + /* USE THIS IF YOU WANT TO PROLONG ARCS TO THEIR TERMINAL NODES + * FOR HANDS, THIS IS NOT THE BEST RESULT + * */ + continue; +#else + removedNode = terminalNode; + + // removing arc, so we need to decrease the degree of the remaining node + NodeDegreeDecrement(rg, middleNode); +#endif + } + // Otherwise, just plain remove of the arc + else + { + removedNode = terminalNode; + + // removing arc, so we need to decrease the degree of the remaining node + NodeDegreeDecrement(rg, middleNode); + } // Reset nextArc, it might have changed nextArc = arc->next; BLI_remlink(&rg->arcs, arc); - freeArc(arc); + REEB_freeArc((BArc*)arc); - BLI_freelinkN(&rg->nodes, removedNode); + BLI_removeNode((BGraph*)rg, (BNode*)removedNode); value = 1; } - - arc = nextArc; } return value; } -int filterExternalReebGraph(ReebGraph *rg, float threshold) +int filterCyclesReebGraph(ReebGraph *rg, float distance_threshold) +{ + ReebArc *arc1, *arc2; + ReebArc *next2; + int filtered = 0; + + for (arc1 = rg->arcs.first; arc1; arc1 = arc1->next) + { + for (arc2 = arc1->next; arc2; arc2 = next2) + { + next2 = arc2->next; + if (arc1 != arc2 && arc1->head == arc2->head && arc1->tail == arc2->tail) + { + mergeArcEdges(rg, arc1, arc2, MERGE_APPEND); + mergeArcFaces(rg, arc1, arc2); + mergeArcBuckets(arc1, arc2, arc1->head->weight, arc1->tail->weight); + + NodeDegreeDecrement(rg, arc1->head); + NodeDegreeDecrement(rg, arc1->tail); + + BLI_remlink(&rg->arcs, arc2); + REEB_freeArc((BArc*)arc2); + + filtered = 1; + } + } + } + + return filtered; +} + +int filterSmartReebGraph(ReebGraph *rg, float threshold) { ReebArc *arc = NULL, *nextArc = NULL; int value = 0; BLI_sortlist(&rg->arcs, compareArcs); +#ifdef DEBUG_REEB + { + EditFace *efa; + for(efa=G.editMesh->faces.first; efa; efa=efa->next) { + efa->tmp.fp = -1; + } + } +#endif + arc = rg->arcs.first; while(arc) { nextArc = arc->next; + + /* need correct normals and center */ + recalc_editnormals(); - // Only collapse terminal arcs that are shorter than threshold - if ((arc->v1->degree == 1 || arc->v2->degree == 1) && arc->v2->weight - arc->v1->weight < threshold) + // Only test terminal arcs + if (arc->head->degree == 1 || arc->tail->degree == 1) { - ReebNode *terminalNode = NULL; - ReebNode *middleNode = NULL; - ReebNode *newNode = NULL; - ReebNode *removedNode = NULL; + GHashIterator ghi; int merging = 0; + int total = BLI_ghash_size(arc->faces); + float avg_angle = 0; + float avg_vec[3] = {0,0,0}; - // Assign terminal and middle nodes - if (arc->v1->degree == 1) - { - terminalNode = arc->v1; - middleNode = arc->v2; - } - else + for(BLI_ghashIterator_init(&ghi, arc->faces); + !BLI_ghashIterator_isDone(&ghi); + BLI_ghashIterator_step(&ghi)) { - terminalNode = arc->v2; - middleNode = arc->v1; + EditFace *efa = BLI_ghashIterator_getValue(&ghi); + +#if 0 + ReebArcIterator iter; + EmbedBucket *bucket = NULL; + EmbedBucket *previous = NULL; + float min_distance = -1; + float angle = 0; + + initArcIterator(&iter, arc, arc->head); + + bucket = nextBucket(&iter); + + while (bucket != NULL) + { + float *vec0 = NULL; + float *vec1 = bucket->p; + float midpoint[3], tangent[3]; + float distance; + + /* first bucket. Previous is head */ + if (previous == NULL) + { + vec0 = arc->head->p; + } + /* Previous is a valid bucket */ + else + { + vec0 = previous->p; + } + + VECCOPY(midpoint, vec1); + + distance = VecLenf(midpoint, efa->cent); + + if (min_distance == -1 || distance < min_distance) + { + min_distance = distance; + + VecSubf(tangent, vec1, vec0); + Normalize(tangent); + + angle = Inpf(tangent, efa->n); + } + + previous = bucket; + bucket = nextBucket(&iter); + } + + avg_angle += saacos(fabs(angle)); +#ifdef DEBUG_REEB + efa->tmp.fp = saacos(fabs(angle)); +#endif +#else + VecAddf(avg_vec, avg_vec, efa->n); +#endif } + + +#if 0 + avg_angle /= total; +#else + VecMulf(avg_vec, 1.0 / total); + avg_angle = Inpf(avg_vec, avg_vec); +#endif - // If middle node is a normal node, merge to terminal node - if (middleNode->degree == 2) - { + arc->angle = avg_angle; + + if (avg_angle > threshold) merging = 1; - newNode = terminalNode; - removedNode = middleNode; - } - // Otherwise, just plain remove of the arc - else - { - merging = 0; - newNode = middleNode; - removedNode = terminalNode; - } - // Merging arc if (merging) { - filterArc(rg, newNode, removedNode, arc, 1); - } - else - { - // removing arc, so we need to decrease the degree of the remaining node - newNode->degree--; + ReebNode *terminalNode = NULL; + ReebNode *middleNode = NULL; + ReebNode *newNode = NULL; + ReebNode *removedNode = NULL; + int merging = 0; + + // Assign terminal and middle nodes + if (arc->head->degree == 1) + { + terminalNode = arc->head; + middleNode = arc->tail; + } + else + { + terminalNode = arc->tail; + middleNode = arc->head; + } + + // If middle node is a normal node, merge to terminal node + if (middleNode->degree == 2) + { + merging = 1; + newNode = terminalNode; + removedNode = middleNode; + } + // Otherwise, just plain remove of the arc + else + { + merging = 0; + newNode = middleNode; + removedNode = terminalNode; + } + + // Merging arc + if (merging) + { + filterArc(rg, newNode, removedNode, arc, 1); + } + else + { + // removing arc, so we need to decrease the degree of the remaining node + //newNode->degree--; + NodeDegreeDecrement(rg, newNode); + } + + // Reset nextArc, it might have changed + nextArc = arc->next; + + BLI_remlink(&rg->arcs, arc); + REEB_freeArc((BArc*)arc); + + BLI_freelinkN(&rg->nodes, removedNode); + value = 1; } - - // Reset nextArc, it might have changed - nextArc = arc->next; - - BLI_remlink(&rg->arcs, arc); - freeArc(arc); - - BLI_freelinkN(&rg->nodes, removedNode); - value = 1; } arc = nextArc; @@ -762,6 +1896,63 @@ int filterExternalReebGraph(ReebGraph *rg, float threshold) return value; } +void filterGraph(ReebGraph *rg, short options, float threshold_internal, float threshold_external) +{ + int done = 1; + + calculateGraphLength(rg); + + if ((options & SKGEN_FILTER_EXTERNAL) == 0) + { + threshold_external = 0; + } + + if ((options & SKGEN_FILTER_INTERNAL) == 0) + { + threshold_internal = 0; + } + + if (threshold_internal > 0 || threshold_external > 0) + { + /* filter until there's nothing more to do */ + while (done == 1) + { + done = 0; /* no work done yet */ + + done = filterInternalExternalReebGraph(rg, threshold_internal, threshold_external); + } + } + + if (options & SKGEN_FILTER_SMART) + { + filterSmartReebGraph(rg, 0.5); + filterCyclesReebGraph(rg, 0.5); + } + + repositionNodes(rg); + + /* Filtering might have created degree 2 nodes, so remove them */ + removeNormalNodes(rg); +} + +void finalizeGraph(ReebGraph *rg, char passes, char method) +{ + int i; + + BLI_buildAdjacencyList((BGraph*)rg); + + sortNodes(rg); + + sortArcs(rg); + + for(i = 0; i < passes; i++) + { + postprocessGraph(rg, method); + } + + extendGraphBuckets(rg); +} + /************************************** WEIGHT SPREADING ***********************************************/ int compareVerts( const void* a, const void* b ) @@ -770,11 +1961,11 @@ int compareVerts( const void* a, const void* b ) EditVert *vb = *(EditVert**)b; int value = 0; - if (va->tmp.fp < vb->tmp.fp) + if (weightData(va) < weightData(vb)) { value = -1; } - else if (va->tmp.fp > vb->tmp.fp) + else if (weightData(va) > weightData(vb)) { value = 1; } @@ -806,109 +1997,21 @@ void spreadWeight(EditMesh *em) { eve = verts[i]; - if (i == 0 || (eve->tmp.fp - lastWeight) > FLT_EPSILON) + if (i == 0 || (weightData(eve) - lastWeight) > FLT_EPSILON) { - lastWeight = eve->tmp.fp; + lastWeight = weightData(eve); } else { work_needed = 1; - eve->tmp.fp = lastWeight + FLT_EPSILON * 2; - lastWeight = eve->tmp.fp; + weightSetData(eve, lastWeight + FLT_EPSILON * 2); + lastWeight = weightData(eve); } } } MEM_freeN(verts); } -/*********************************** GRAPH AS TREE FUNCTIONS *******************************************/ - -int subtreeDepth(ReebNode *node, ReebArc *rootArc) -{ - int depth = 0; - - /* Base case, no arcs leading away */ - if (node->arcs == NULL || *(node->arcs) == NULL) - { - return 0; - } - else - { - ReebArc ** pArc; - - for(pArc = node->arcs; *pArc; pArc++) - { - ReebArc *arc = *pArc; - - /* only arcs that go down the tree */ - if (arc != rootArc) - { - ReebNode *newNode = OTHER_NODE(arc, node); - depth = MAX2(depth, subtreeDepth(newNode, arc)); - } - } - } - - return depth + 1; -} - -/*************************************** CYCLE DETECTION ***********************************************/ - -int detectCycle(ReebNode *node, ReebArc *srcArc) -{ - int value = 0; - - if (node->flags == 0) - { - ReebArc ** pArc; - - /* mark node as visited */ - node->flags = 1; - - for(pArc = node->arcs; *pArc && value == 0; pArc++) - { - ReebArc *arc = *pArc; - - /* don't go back on the source arc */ - if (arc != srcArc) - { - value = detectCycle(OTHER_NODE(arc, node), arc); - } - } - } - else - { - value = 1; - } - - return value; -} - -int isGraphCyclic(ReebGraph *rg) -{ - ReebNode *node; - int value = 0; - - /* NEED TO CHECK IF ADJACENCY LIST EXIST */ - - /* Mark all nodes as not visited */ - for(node = rg->nodes.first; node; node = node->next) - { - node->flags = 0; - } - - /* detectCycles in subgraphs */ - for(node = rg->nodes.first; node && value == 0; node = node->next) - { - /* only for nodes in subgraphs that haven't been visited yet */ - if (node->flags == 0) - { - value = value || detectCycle(node, NULL); - } - } - - return value; -} /******************************************** EXPORT ***************************************************/ @@ -917,9 +2020,8 @@ void exportNode(FILE *f, char *text, ReebNode *node) fprintf(f, "%s i:%i w:%f d:%i %f %f %f\n", text, node->index, node->weight, node->degree, node->p[0], node->p[1], node->p[2]); } -void exportGraph(ReebGraph *rg, int count) +void REEB_exportGraph(ReebGraph *rg, int count) { -#ifdef DEBUG_REEB ReebArc *arc; char filename[128]; FILE *f; @@ -937,78 +2039,107 @@ void exportGraph(ReebGraph *rg, int count) for(arc = rg->arcs.first; arc; arc = arc->next) { int i; + float p[3]; - exportNode(f, "v1", arc->v1); + exportNode(f, "v1", arc->head); for(i = 0; i < arc->bcount; i++) { fprintf(f, "b nv:%i %f %f %f\n", arc->buckets[i].nv, arc->buckets[i].p[0], arc->buckets[i].p[1], arc->buckets[i].p[2]); } - exportNode(f, "v2", arc->v2); + VecAddf(p, arc->tail->p, arc->head->p); + VecMulf(p, 0.5f); + + fprintf(f, "angle %0.3f %0.3f %0.3f %0.3f %i\n", p[0], p[1], p[2], arc->angle, BLI_ghash_size(arc->faces)); + exportNode(f, "v2", arc->tail); } fclose(f); -#endif } /***************************************** MAIN ALGORITHM **********************************************/ -ReebArc * findConnectedArc(ReebGraph *rg, ReebArc *arc, ReebNode *v) +/* edges alone will create zero degree nodes, use this function to remove them */ +void removeZeroNodes(ReebGraph *rg) { - ReebArc *nextArc = arc->next; + ReebNode *node, *next_node; - for(nextArc = rg->arcs.first; nextArc; nextArc = nextArc->next) + for (node = rg->nodes.first; node; node = next_node) { - if (arc != nextArc && (nextArc->v1 == v || nextArc->v2 == v)) + next_node = node->next; + + if (node->degree == 0) { - break; + BLI_removeNode((BGraph*)rg, (BNode*)node); } } - - return nextArc; } void removeNormalNodes(ReebGraph *rg) { - ReebArc *arc; + ReebArc *arc, *nextArc; // Merge degree 2 nodes - for(arc = rg->arcs.first; arc; arc = arc->next) + for(arc = rg->arcs.first; arc; arc = nextArc) { - while (arc->v1->degree == 2 || arc->v2->degree == 2) + nextArc = arc->next; + + while (arc->head->degree == 2 || arc->tail->degree == 2) { // merge at v1 - if (arc->v1->degree == 2) + if (arc->head->degree == 2) { - ReebArc *nextArc = findConnectedArc(rg, arc, arc->v1); + ReebArc *connectedArc = (ReebArc*)BLI_findConnectedArc((BGraph*)rg, (BArc*)arc, (BNode*)arc->head); - // Merge arc only if needed - if (arc->v1 == nextArc->v2) - { - mergeConnectedArcs(rg, arc, nextArc); + /* If arcs are one after the other */ + if (arc->head == connectedArc->tail) + { + /* remove furthest arc */ + if (arc->tail->weight < connectedArc->head->weight) + { + mergeConnectedArcs(rg, arc, connectedArc); + nextArc = arc->next; + } + else + { + mergeConnectedArcs(rg, connectedArc, arc); + break; /* arc was removed, move to next */ + } } - // Otherwise, mark down vert + /* Otherwise, arcs are side by side */ else { - arc->v1->degree = 3; + /* Don't do anything, we need to keep the lowest node, even if degree 2 */ + break; } } // merge at v2 - if (arc->v2->degree == 2) + if (arc->tail->degree == 2) { - ReebArc *nextArc = findConnectedArc(rg, arc, arc->v2); + ReebArc *connectedArc = (ReebArc*)BLI_findConnectedArc((BGraph*)rg, (BArc*)arc, (BNode*)arc->tail); - // Merge arc only if needed - if (arc->v2 == nextArc->v1) + /* If arcs are one after the other */ + if (arc->tail == connectedArc->head) { - mergeConnectedArcs(rg, arc, nextArc); + /* remove furthest arc */ + if (arc->head->weight < connectedArc->tail->weight) + { + mergeConnectedArcs(rg, arc, connectedArc); + nextArc = arc->next; + } + else + { + mergeConnectedArcs(rg, connectedArc, arc); + break; /* arc was removed, move to next */ + } } - // Otherwise, mark down vert + /* Otherwise, arcs are side by side */ else { - arc->v2->degree = 3; + /* Don't do anything, we need to keep the lowest node, even if degree 2 */ + break; } } } @@ -1041,11 +2172,23 @@ ReebArc *nextArcMappedToEdge(ReebArc *arc, ReebEdge *e) return result; } -typedef enum { - MERGE_LOWER, - MERGE_HIGHER, - MERGE_APPEND -} MergeDirection; +void addFacetoArc(ReebArc *arc, EditFace *efa) +{ + BLI_ghash_insert(arc->faces, efa, efa); +} + +void mergeArcFaces(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc) +{ + GHashIterator ghi; + + for(BLI_ghashIterator_init(&ghi, aSrc->faces); + !BLI_ghashIterator_isDone(&ghi); + BLI_ghashIterator_step(&ghi)) + { + EditFace *efa = BLI_ghashIterator_getValue(&ghi); + BLI_ghash_insert(aDst->faces, efa, efa); + } +} void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction) { @@ -1109,29 +2252,32 @@ int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1) int result = 0; ReebNode *removedNode = NULL; + a0->length += a1->length; + mergeArcEdges(rg, a0, a1, MERGE_APPEND); + mergeArcFaces(rg, a0, a1); // Bring a0 to the combine length of both arcs - if (a0->v2 == a1->v1) + if (a0->tail == a1->head) { - removedNode = a0->v2; - a0->v2 = a1->v2; + removedNode = a0->tail; + a0->tail = a1->tail; } - else if (a0->v1 == a1->v2) + else if (a0->head == a1->tail) { - removedNode = a0->v1; - a0->v1 = a1->v1; + removedNode = a0->head; + a0->head = a1->head; } resizeArcBuckets(a0); // Merge a1 in a0 - mergeArcBuckets(a0, a1, a0->v1->weight, a0->v2->weight); + mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); // remove a1 from graph BLI_remlink(&rg->arcs, a1); - freeArc(a1); + REEB_freeArc((BArc*)a1); - BLI_freelinkN(&rg->nodes, removedNode); + BLI_removeNode((BGraph*)rg, (BNode*)removedNode); result = 1; return result; @@ -1141,74 +2287,89 @@ int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1) { int result = 0; // TRIANGLE POINTS DOWN - if (a0->v1->weight == a1->v1->weight) // heads are the same + if (a0->head->weight == a1->head->weight) // heads are the same { - if (a0->v2->weight == a1->v2->weight) // tails also the same, arcs can be totally merge together + if (a0->tail->weight == a1->tail->weight) // tails also the same, arcs can be totally merge together { mergeArcEdges(rg, a0, a1, MERGE_APPEND); + mergeArcFaces(rg, a0, a1); - mergeArcBuckets(a0, a1, a0->v1->weight, a0->v2->weight); + mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); // Adjust node degree - a1->v1->degree--; - a1->v2->degree--; + //a1->head->degree--; + NodeDegreeDecrement(rg, a1->head); + //a1->tail->degree--; + NodeDegreeDecrement(rg, a1->tail); // remove a1 from graph BLI_remlink(&rg->arcs, a1); - freeArc(a1); + REEB_freeArc((BArc*)a1); result = 1; } - else if (a0->v2->weight > a1->v2->weight) // a1->v2->weight is in the middle + else if (a0->tail->weight > a1->tail->weight) // a1->tail->weight is in the middle { mergeArcEdges(rg, a1, a0, MERGE_LOWER); + mergeArcFaces(rg, a1, a0); // Adjust node degree - a0->v1->degree--; - a1->v2->degree++; + //a0->head->degree--; + NodeDegreeDecrement(rg, a0->head); + //a1->tail->degree++; + NodeDegreeIncrement(rg, a1->tail); - mergeArcBuckets(a1, a0, a1->v1->weight, a1->v2->weight); - a0->v1 = a1->v2; + mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight); + a0->head = a1->tail; resizeArcBuckets(a0); } else // a0>n2 is in the middle { mergeArcEdges(rg, a0, a1, MERGE_LOWER); + mergeArcFaces(rg, a0, a1); // Adjust node degree - a1->v1->degree--; - a0->v2->degree++; + //a1->head->degree--; + NodeDegreeDecrement(rg, a1->head); + //a0->tail->degree++; + NodeDegreeIncrement(rg, a0->tail); - mergeArcBuckets(a0, a1, a0->v1->weight, a0->v2->weight); - a1->v1 = a0->v2; + mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); + a1->head = a0->tail; resizeArcBuckets(a1); } } // TRIANGLE POINTS UP - else if (a0->v2->weight == a1->v2->weight) // tails are the same + else if (a0->tail->weight == a1->tail->weight) // tails are the same { - if (a0->v1->weight > a1->v1->weight) // a0->v1->weight is in the middle + if (a0->head->weight > a1->head->weight) // a0->head->weight is in the middle { mergeArcEdges(rg, a0, a1, MERGE_HIGHER); + mergeArcFaces(rg, a0, a1); // Adjust node degree - a1->v2->degree--; - a0->v1->degree++; + //a1->tail->degree--; + NodeDegreeDecrement(rg, a1->tail); + //a0->head->degree++; + NodeDegreeIncrement(rg, a0->head); - mergeArcBuckets(a0, a1, a0->v1->weight, a0->v2->weight); - a1->v2 = a0->v1; + mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight); + a1->tail = a0->head; resizeArcBuckets(a1); } - else // a1->v1->weight is in the middle + else // a1->head->weight is in the middle { mergeArcEdges(rg, a1, a0, MERGE_HIGHER); + mergeArcFaces(rg, a1, a0); // Adjust node degree - a0->v2->degree--; - a1->v1->degree++; + //a0->tail->degree--; + NodeDegreeDecrement(rg, a0->tail); + //a1->head->degree++; + NodeDegreeIncrement(rg, a1->head); - mergeArcBuckets(a1, a0, a1->v1->weight, a1->v2->weight); - a0->v2 = a1->v1; + mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight); + a0->tail = a1->head; resizeArcBuckets(a0); } } @@ -1229,7 +2390,7 @@ void glueByMergeSort(ReebGraph *rg, ReebArc *a0, ReebArc *a1, ReebEdge *e0, Reeb if (total == 0) // if it wasn't a total merge, go forward { - if (a0->v2->weight < a1->v2->weight) + if (a0->tail->weight < a1->tail->weight) { a0 = nextArcMappedToEdge(a0, e0); } @@ -1252,25 +2413,6 @@ void mergePaths(ReebGraph *rg, ReebEdge *e0, ReebEdge *e1, ReebEdge *e2) glueByMergeSort(rg, a0, a2, e0, e2); } -ReebNode * addNode(ReebGraph *rg, EditVert *eve, float weight) -{ - ReebNode *node = NULL; - - node = MEM_callocN(sizeof(ReebNode), "reeb node"); - - node->flags = 0; // clear flags on init - node->arcs = NULL; - node->degree = 0; - node->weight = weight; - node->index = rg->totnodes; - VECCOPY(node->p, eve->co); - - BLI_addtail(&rg->nodes, node); - rg->totnodes++; - - return node; -} - ReebEdge * createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) { ReebEdge *edge; @@ -1288,7 +2430,9 @@ ReebEdge * createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) arc = MEM_callocN(sizeof(ReebArc), "reeb arc"); edge = MEM_callocN(sizeof(ReebEdge), "reeb edge"); - arc->flags = 0; // clear flags on init + arc->flag = 0; // clear flag on init + arc->symmetry_level = 0; + arc->faces = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); if (node1->weight <= node2->weight) { @@ -1301,12 +2445,14 @@ ReebEdge * createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) v2 = node1; } - arc->v1 = v1; - arc->v2 = v2; + arc->head = v1; + arc->tail = v2; // increase node degree - v1->degree++; - v2->degree++; + //v1->degree++; + NodeDegreeIncrement(rg, v1); + //v2->degree++; + NodeDegreeIncrement(rg, v2); BLI_edgehash_insert(rg->emap, node1->index, node2->index, edge); @@ -1321,8 +2467,8 @@ ReebEdge * createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) /* adding buckets for embedding */ allocArcBuckets(arc); - offset = arc->v1->weight; - len = arc->v2->weight - arc->v1->weight; + offset = arc->head->weight; + len = arc->tail->weight - arc->head->weight; #if 0 /* This is the actual embedding filling described in the paper @@ -1330,8 +2476,8 @@ ReebEdge * createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) */ if (arc->bcount > 0) { - addVertToBucket(&(arc->buckets[0]), arc->v1->co); - addVertToBucket(&(arc->buckets[arc->bcount - 1]), arc->v2->co); + addVertToBucket(&(arc->buckets[0]), arc->head->co); + addVertToBucket(&(arc->buckets[arc->bcount - 1]), arc->tail->co); } #else for(i = 0; i < arc->bcount; i++) @@ -1349,7 +2495,7 @@ ReebEdge * createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2) return edge; } -void addTriangleToGraph(ReebGraph *rg, ReebNode * n1, ReebNode * n2, ReebNode * n3) +void addTriangleToGraph(ReebGraph *rg, ReebNode * n1, ReebNode * n2, ReebNode * n3, EditFace *efa) { ReebEdge *re1, *re2, *re3; ReebEdge *e1, *e2, *e3; @@ -1359,6 +2505,10 @@ void addTriangleToGraph(ReebGraph *rg, ReebNode * n1, ReebNode * n2, ReebNode * re2 = createArc(rg, n2, n3); re3 = createArc(rg, n3, n1); + addFacetoArc(re1->arc, efa); + addFacetoArc(re2->arc, efa); + addFacetoArc(re3->arc, efa); + len1 = (float)fabs(n1->weight - n2->weight); len2 = (float)fabs(n2->weight - n3->weight); len3 = (float)fabs(n3->weight - n1->weight); @@ -1401,7 +2551,6 @@ void addTriangleToGraph(ReebGraph *rg, ReebNode * n1, ReebNode * n2, ReebNode * ReebGraph * generateReebGraph(EditMesh *em, int subdivisions) { ReebGraph *rg; - struct DynamicList * dlist; EditVert *eve; EditFace *efa; int index; @@ -1412,10 +2561,9 @@ ReebGraph * generateReebGraph(EditMesh *em, int subdivisions) int countfaces = 0; #endif - rg = MEM_callocN(sizeof(ReebGraph), "reeb graph"); + rg = newReebGraph(); - rg->totnodes = 0; - rg->emap = BLI_edgehash_new(); + rg->resolution = subdivisions; totvert = BLI_countlist(&em->verts); totfaces = BLI_countlist(&em->faces); @@ -1425,47 +2573,50 @@ ReebGraph * generateReebGraph(EditMesh *em, int subdivisions) /* Spread weight to minimize errors */ spreadWeight(em); - renormalizeWeight(em, (float)subdivisions); + renormalizeWeight(em, (float)rg->resolution); /* Adding vertice */ - for(index = 0, eve = em->verts.first; eve; index++, eve = eve->next) + for(index = 0, eve = em->verts.first; eve; eve = eve->next) { - eve->hash = index; - eve->f2 = 0; - eve->tmp.p = addNode(rg, eve, eve->tmp.fp); + if (eve->h == 0) + { + addNode(rg, eve); + eve->f2 = 0; + index++; + } } - /* Temporarely convert node list to dynamic list, for indexed access */ - dlist = BLI_dlist_from_listbase(&rg->nodes); - /* Adding face, edge per edge */ for(efa = em->faces.first; efa; efa = efa->next) { - ReebNode *n1, *n2, *n3; - - n1 = (ReebNode*)BLI_dlist_find_link(dlist, efa->v1->hash); - n2 = (ReebNode*)BLI_dlist_find_link(dlist, efa->v2->hash); - n3 = (ReebNode*)BLI_dlist_find_link(dlist, efa->v3->hash); - - addTriangleToGraph(rg, n1, n2, n3); - - if (efa->v4) + if (efa->h == 0) { - ReebNode *n4 = (ReebNode*)efa->v4->tmp.p; - addTriangleToGraph(rg, n1, n3, n4); - } - + ReebNode *n1, *n2, *n3; + + n1 = nodeData(efa->v1); + n2 = nodeData(efa->v2); + n3 = nodeData(efa->v3); + + addTriangleToGraph(rg, n1, n2, n3, efa); + + if (efa->v4) + { + ReebNode *n4 = nodeData(efa->v4); + addTriangleToGraph(rg, n1, n3, n4, efa); + } #ifdef DEBUG_REEB - countfaces++; - if (countfaces % 100 == 0) - { - printf("face %i of %i\n", countfaces, totfaces); - } + countfaces++; + if (countfaces % 100 == 0) + { + printf("\rface %i of %i", countfaces, totfaces); + } #endif - - + } } - BLI_listbase_from_dlist(dlist, &rg->nodes); + + printf("\n"); + + removeZeroNodes(rg); removeNormalNodes(rg); @@ -1484,12 +2635,12 @@ void renormalizeWeight(EditMesh *em, float newmax) /* First pass, determine maximum and minimum */ eve = em->verts.first; - minimum = eve->tmp.fp; - maximum = eve->tmp.fp; + minimum = weightData(eve); + maximum = minimum; for(eve = em->verts.first; eve; eve = eve->next) { - maximum = MAX2(maximum, eve->tmp.fp); - minimum = MIN2(minimum, eve->tmp.fp); + maximum = MAX2(maximum, weightData(eve)); + minimum = MIN2(minimum, weightData(eve)); } range = maximum - minimum; @@ -1497,7 +2648,8 @@ void renormalizeWeight(EditMesh *em, float newmax) /* Normalize weights */ for(eve = em->verts.first; eve; eve = eve->next) { - eve->tmp.fp = (eve->tmp.fp - minimum) / range * newmax; + float weight = (weightData(eve) - minimum) / range * newmax; + weightSetData(eve, weight); } } @@ -1512,7 +2664,7 @@ int weightFromLoc(EditMesh *em, int axis) /* Copy coordinate in weight */ for(eve = em->verts.first; eve; eve = eve->next) { - eve->tmp.fp = eve->co[axis]; + weightSetData(eve, eve->co[axis]); } return 1; @@ -1534,7 +2686,36 @@ static float cotan_weight(float *v1, float *v2, float *v3) return Inpf(a, b)/clen; } -int weightToHarmonic(EditMesh *em) +void addTriangle(EditVert *v1, EditVert *v2, EditVert *v3, long e1, long e2, long e3) +{ + /* Angle opposite e1 */ + float t1= cotan_weight(v1->co, v2->co, v3->co) / e2; + + /* Angle opposite e2 */ + float t2 = cotan_weight(v2->co, v3->co, v1->co) / e3; + + /* Angle opposite e3 */ + float t3 = cotan_weight(v3->co, v1->co, v2->co) / e1; + + int i1 = indexData(v1); + int i2 = indexData(v2); + int i3 = indexData(v3); + + nlMatrixAdd(i1, i1, t2+t3); + nlMatrixAdd(i2, i2, t1+t3); + nlMatrixAdd(i3, i3, t1+t2); + + nlMatrixAdd(i1, i2, -t3); + nlMatrixAdd(i2, i1, -t3); + + nlMatrixAdd(i2, i3, -t1); + nlMatrixAdd(i3, i2, -t1); + + nlMatrixAdd(i3, i1, -t2); + nlMatrixAdd(i1, i3, -t2); +} + +int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) { NLboolean success; EditVert *eve; @@ -1561,49 +2742,53 @@ int weightToHarmonic(EditMesh *em) /* Find local extrema */ for(index = 0, eve = em->verts.first; eve; index++, eve = eve->next) { - EditEdge *eed; - int maximum = 1; - int minimum = 1; - - eve->hash = index; /* Assign index to vertex */ - - NextEdgeForVert(NULL, NULL); /* Reset next edge */ - for(eed = NextEdgeForVert(em, eve); eed && (maximum || minimum); eed = NextEdgeForVert(em, eve)) + if (eve->h == 0) { - EditVert *eve2; + EditEdge *eed; + int maximum = 1; + int minimum = 1; - if (eed->v1 == eve) + NextEdgeForVert(indexed_edges, -1); /* Reset next edge */ + for(eed = NextEdgeForVert(indexed_edges, index); eed && (maximum || minimum); eed = NextEdgeForVert(indexed_edges, index)) { - eve2 = eed->v2; - } - else - { - eve2 = eed->v1; + EditVert *eve2; + + if (eed->v1 == eve) + { + eve2 = eed->v2; + } + else + { + eve2 = eed->v1; + } + + if (eve2->h == 0) + { + /* Adjacent vertex is bigger, not a local maximum */ + if (weightData(eve2) > weightData(eve)) + { + maximum = 0; + } + /* Adjacent vertex is smaller, not a local minimum */ + else if (weightData(eve2) < weightData(eve)) + { + minimum = 0; + } + } } - /* Adjacent vertex is bigger, not a local maximum */ - if (eve2->tmp.fp > eve->tmp.fp) + if (maximum || minimum) { - maximum = 0; + float w = weightData(eve); + eve->f1 = 0; + nlSetVariable(0, index, w); + nlLockVariable(index); } - /* Adjacent vertex is smaller, not a local minimum */ - else if (eve2->tmp.fp < eve->tmp.fp) + else { - minimum = 0; + eve->f1 = 1; } } - - if (maximum || minimum) - { - float w = eve->tmp.fp; - eve->f1 = 0; - nlSetVariable(0, index, w); - nlLockVariable(index); - } - else - { - eve->f1 = 1; - } } nlBegin(NL_MATRIX); @@ -1617,39 +2802,34 @@ int weightToHarmonic(EditMesh *em) /* Add faces count to the edge weight */ for(efa = em->faces.first; efa; efa = efa->next) { - efa->e1->tmp.l++; - efa->e2->tmp.l++; - efa->e3->tmp.l++; + if (efa->h == 0) + { + efa->e1->tmp.l++; + efa->e2->tmp.l++; + efa->e3->tmp.l++; + + if (efa->e4) + { + efa->e4->tmp.l++; + } + } } /* Add faces angle to the edge weight */ for(efa = em->faces.first; efa; efa = efa->next) { - /* Angle opposite e1 */ - float t1= cotan_weight(efa->v1->co, efa->v2->co, efa->v3->co) / efa->e2->tmp.l; - - /* Angle opposite e2 */ - float t2 = cotan_weight(efa->v2->co, efa->v3->co, efa->v1->co) / efa->e3->tmp.l; - - /* Angle opposite e3 */ - float t3 = cotan_weight(efa->v3->co, efa->v1->co, efa->v2->co) / efa->e1->tmp.l; - - int i1 = efa->v1->hash; - int i2 = efa->v2->hash; - int i3 = efa->v3->hash; - - nlMatrixAdd(i1, i1, t2+t3); - nlMatrixAdd(i2, i2, t1+t3); - nlMatrixAdd(i3, i3, t1+t2); - - nlMatrixAdd(i1, i2, -t3); - nlMatrixAdd(i2, i1, -t3); - - nlMatrixAdd(i2, i3, -t1); - nlMatrixAdd(i3, i2, -t1); - - nlMatrixAdd(i3, i1, -t2); - nlMatrixAdd(i1, i3, -t2); + if (efa->h == 0) + { + if (efa->v4 == NULL) + { + addTriangle(efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, efa->e3->tmp.l); + } + else + { + addTriangle(efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, 2); + addTriangle(efa->v3, efa->v4, efa->v1, efa->e3->tmp.l, efa->e4->tmp.l, 2); + } + } } nlEnd(NL_MATRIX); @@ -1663,7 +2843,7 @@ int weightToHarmonic(EditMesh *em) rval = 1; for(index = 0, eve = em->verts.first; eve; index++, eve = eve->next) { - eve->tmp.fp = nlGetVariable(0, index); + weightSetData(eve, nlGetVariable(0, index)); } } else @@ -1677,46 +2857,175 @@ int weightToHarmonic(EditMesh *em) } -EditEdge * NextEdgeForVert(EditMesh *em, EditVert *v) +EditEdge * NextEdgeForVert(EdgeIndex *indexed_edges, int index) { - static EditEdge *e = NULL; + static int offset = -1; /* Reset method, call with NULL mesh pointer */ - if (em == NULL) + if (index == -1) { - e = NULL; + offset = -1; return NULL; } /* first pass, start at the head of the list */ - if (e == NULL) + if (offset == -1) { - e = em->edges.first; + offset = indexed_edges->offset[index]; } /* subsequent passes, start on the next edge */ else { - e = e->next; + offset++; + } + + return indexed_edges->edges[offset]; +} + +void shortestPathsFromVert(EditMesh *em, EditVert *starting_vert, EdgeIndex *indexed_edges) +{ + Heap *edge_heap; + EditVert *current_eve = NULL; + EditEdge *eed = NULL; + EditEdge *select_eed = NULL; + + edge_heap = BLI_heap_new(); + + current_eve = starting_vert; + + /* insert guard in heap, when that is returned, no more edges */ + BLI_heap_insert(edge_heap, FLT_MAX, NULL); + + /* Initialize edge flag */ + for(eed= em->edges.first; eed; eed= eed->next) + { + eed->f1 = 0; + } + + while (BLI_heap_size(edge_heap) > 0) + { + float current_weight; + + current_eve->f1 = 1; /* mark vertex as selected */ + + /* Add all new edges connected to current_eve to the list */ + NextEdgeForVert(indexed_edges, -1); // Reset next edge + for(eed = NextEdgeForVert(indexed_edges, indexData(current_eve)); eed; eed = NextEdgeForVert(indexed_edges, indexData(current_eve))) + { + if (eed->f1 == 0) + { + BLI_heap_insert(edge_heap, weightData(current_eve) + eed->tmp.fp, eed); + eed->f1 = 1; + } + } + + /* Find next shortest edge with unselected verts */ + do + { + current_weight = BLI_heap_node_value(BLI_heap_top(edge_heap)); + select_eed = BLI_heap_popmin(edge_heap); + } while (select_eed != NULL && select_eed->v1->f1 != 0 && select_eed->v2->f1); + + if (select_eed != NULL) + { + select_eed->f1 = 2; + + if (select_eed->v1->f1 == 0) /* v1 is the new vertex */ + { + current_eve = select_eed->v1; + } + else /* otherwise, it's v2 */ + { + current_eve = select_eed->v2; + } + + weightSetData(current_eve, current_weight); + } } + + BLI_heap_free(edge_heap, NULL); +} + +void freeEdgeIndex(EdgeIndex *indexed_edges) +{ + MEM_freeN(indexed_edges->offset); + MEM_freeN(indexed_edges->edges); +} - for( ; e ; e = e->next) +void buildIndexedEdges(EditMesh *em, EdgeIndex *indexed_edges) +{ + EditVert *eve; + EditEdge *eed; + int totvert = 0; + int tot_indexed = 0; + int offset = 0; + + totvert = BLI_countlist(&em->verts); + + indexed_edges->offset = MEM_callocN(totvert * sizeof(int), "EdgeIndex offset"); + + for(eed = em->edges.first; eed; eed = eed->next) { - if (e->v1 == v || e->v2 == v) + if (eed->v1->h == 0 && eed->v2->h == 0) { - break; + tot_indexed += 2; + indexed_edges->offset[indexData(eed->v1)]++; + indexed_edges->offset[indexData(eed->v2)]++; } - } + } - return e; + tot_indexed += totvert; + + indexed_edges->edges = MEM_callocN(tot_indexed * sizeof(EditEdge*), "EdgeIndex edges"); + + /* setting vert offsets */ + for(eve = em->verts.first; eve; eve = eve->next) + { + if (eve->h == 0) + { + int d = indexed_edges->offset[indexData(eve)]; + indexed_edges->offset[indexData(eve)] = offset; + offset += d + 1; + } + } + + /* adding edges in array */ + for(eed = em->edges.first; eed; eed= eed->next) + { + if (eed->v1->h == 0 && eed->v2->h == 0) + { + int i; + for (i = indexed_edges->offset[indexData(eed->v1)]; i < tot_indexed; i++) + { + if (indexed_edges->edges[i] == NULL) + { + indexed_edges->edges[i] = eed; + break; + } + } + + for (i = indexed_edges->offset[indexData(eed->v2)]; i < tot_indexed; i++) + { + if (indexed_edges->edges[i] == NULL) + { + indexed_edges->edges[i] = eed; + break; + } + } + } + } } -int weightFromDistance(EditMesh *em) +int weightFromDistance(EditMesh *em, EdgeIndex *indexed_edges) { EditVert *eve; int totedge = 0; + int totvert = 0; int vCount = 0; - if (em == NULL || BLI_countlist(&em->verts) == 0) + totvert = BLI_countlist(&em->verts); + + if (em == NULL || totvert == 0) { return 0; } @@ -1727,9 +3036,9 @@ int weightFromDistance(EditMesh *em) { return 0; } - - /* Initialize vertice flags and find at least one selected vertex */ - for(eve = em->verts.first; eve && vCount == 0; eve = eve->next) + + /* Initialize vertice flag and find at least one selected vertex */ + for(eve = em->verts.first; eve; eve = eve->next) { eve->f1 = 0; if (eve->f & SELECT) @@ -1744,110 +3053,94 @@ int weightFromDistance(EditMesh *em) } else { - EditVert *eve, *current_eve = NULL; + EditEdge *eed; + int allDone = 0; + + /* Calculate edge weight */ + for(eed = em->edges.first; eed; eed= eed->next) + { + if (eed->v1->h == 0 && eed->v2->h == 0) + { + eed->tmp.fp = VecLenf(eed->v1->co, eed->v2->co); + } + } + /* Apply dijkstra spf for each selected vert */ for(eve = em->verts.first; eve; eve = eve->next) { if (eve->f & SELECT) { - current_eve = eve; - eve->f1 = 1; - + shortestPathsFromVert(em, eve, indexed_edges); + } + } + + /* connect unselected islands */ + while (allDone == 0) + { + EditVert *selected_eve = NULL; + float selected_weight = 0; + float min_distance = FLT_MAX; + + allDone = 1; + + for (eve = em->verts.first; eve; eve = eve->next) + { + /* for every vertex visible that hasn't been processed yet */ + if (eve->h == 0 && eve->f1 != 1) { - EditEdge *eed = NULL; - EditEdge *select_eed = NULL; - EditEdge **edges = NULL; - float currentWeight = 0; - int eIndex = 0; - - edges = MEM_callocN(totedge * sizeof(EditEdge*), "Edges"); + EditVert *closest_eve; - /* Calculate edge weight and initialize edge flags */ - for(eed= em->edges.first; eed; eed= eed->next) + /* find the closest processed vertex */ + for (closest_eve = em->verts.first; closest_eve; closest_eve = closest_eve->next) { - eed->tmp.fp = VecLenf(eed->v1->co, eed->v2->co); - eed->f1 = 0; - } - - do { - int i; - - current_eve->f1 = 1; /* mark vertex as selected */ - - /* Add all new edges connected to current_eve to the list */ - NextEdgeForVert(NULL, NULL); // Reset next edge - for(eed = NextEdgeForVert(em, current_eve); eed; eed = NextEdgeForVert(em, current_eve)) - { - if (eed->f1 == 0) - { - edges[eIndex] = eed; - eed->f1 = 1; - eIndex++; - } - } - - /* Find next shortest edge */ - select_eed = NULL; - for(i = 0; i < eIndex; i++) - { - eed = edges[i]; - - if (eed->f1 != 2 && (eed->v1->f1 == 0 || eed->v2->f1 == 0)) /* eed is not selected yet and leads to a new node */ - { - float newWeight = 0; - if (eed->v1->f1 == 1) - { - newWeight = eed->v1->tmp.fp + eed->tmp.fp; - } - else - { - newWeight = eed->v2->tmp.fp + eed->tmp.fp; - } - - if (select_eed == NULL || newWeight < currentWeight) /* no selected edge or current smaller than selected */ - { - currentWeight = newWeight; - select_eed = eed; - } - } - } - - if (select_eed != NULL) + /* vertex is already processed and distance is smaller than current minimum */ + if (closest_eve->f1 == 1) { - select_eed->f1 = 2; - - if (select_eed->v1->f1 == 0) /* v1 is the new vertex */ + float distance = VecLenf(closest_eve->co, eve->co); + if (distance < min_distance) { - current_eve = select_eed->v1; + min_distance = distance; + selected_eve = eve; + selected_weight = weightData(closest_eve); } - else /* otherwise, it's v2 */ - { - current_eve = select_eed->v2; - } - current_eve->tmp.fp = currentWeight; } - } while (select_eed != NULL); - - MEM_freeN(edges); + } } } + + if (selected_eve) + { + allDone = 0; + + weightSetData(selected_eve, selected_weight + min_distance); + shortestPathsFromVert(em, selected_eve, indexed_edges); + } } } + for(eve = em->verts.first; eve && vCount == 0; eve = eve->next) + { + if (eve->f1 == 0) + { + printf("vertex not reached\n"); + break; + } + } + return 1; } -MCol MColFromWeight(EditVert *eve) +MCol MColFromVal(float val) { MCol col; col.a = 255; - col.b = (char)(eve->tmp.fp * 255); + col.b = (char)(val * 255); col.g = 0; - col.r = (char)((1.0f - eve->tmp.fp) * 255); + col.r = (char)((1.0f - val) * 255); return col; } -void weightToVCol(EditMesh *em) +void weightToVCol(EditMesh *em, int index) { EditFace *efa; MCol *mcol; @@ -1856,14 +3149,148 @@ void weightToVCol(EditMesh *em) } for(efa=em->faces.first; efa; efa=efa->next) { + mcol = CustomData_em_get_n(&em->fdata, efa->data, CD_MCOL, index); + + if (mcol) + { + mcol[0] = MColFromVal(weightData(efa->v1)); + mcol[1] = MColFromVal(weightData(efa->v2)); + mcol[2] = MColFromVal(weightData(efa->v3)); + + if(efa->v4) { + mcol[3] = MColFromVal(weightData(efa->v4)); + } + } + } +} + +void angleToVCol(EditMesh *em, int index) +{ + EditFace *efa; + MCol *mcol; + + if (!EM_vertColorCheck()) { + return; + } + + for(efa=em->faces.first; efa; efa=efa->next) { + MCol col; + if (efa->tmp.fp > 0) + { + col = MColFromVal(efa->tmp.fp / (M_PI / 2 + 0.1)); + } + else + { + col.a = 255; + col.r = 0; + col.g = 255; + col.b = 0; + } + + mcol = CustomData_em_get_n(&em->fdata, efa->data, CD_MCOL, index); + + if (mcol) + { + mcol[0] = col; + mcol[1] = col; + mcol[2] = col; + + if(efa->v4) { + mcol[3] = col; + } + } + } +} + +void blendColor(MCol *dst, MCol *src) +{ +#if 1 + float blend_src = (float)src->a / (float)(src->a + dst->a); + float blend_dst = (float)dst->a / (float)(src->a + dst->a); + dst->a += src->a; + dst->r = (char)(dst->r * blend_dst + src->r * blend_src); + dst->g = (char)(dst->g * blend_dst + src->g * blend_src); + dst->b = (char)(dst->b * blend_dst + src->b * blend_src); +#else + dst->r = src->r; + dst->g = src->g; + dst->b = src->b; +#endif +} + +void arcToVCol(ReebGraph *rg, EditMesh *em, int index) +{ + GHashIterator ghi; + EditFace *efa; + ReebArc *arc; + MCol *mcol; + MCol col; + int total = BLI_countlist(&rg->arcs); + int i = 0; + + if (!EM_vertColorCheck()) { + return; + } + + col.a = 0; + + col.r = 0; + col.g = 0; + col.b = 0; + + for(efa=em->faces.first; efa; efa=efa->next) { + mcol = CustomData_em_get_n(&em->fdata, efa->data, CD_MCOL, index); + + if (mcol) + { + mcol[0] = col; + mcol[1] = col; + mcol[2] = col; + + if(efa->v4) { + mcol[3] = col; + } + } + } + + for (arc = rg->arcs.first; arc; arc = arc->next, i++) + { + float r,g,b; + col.a = 1; + + hsv_to_rgb((float)i / (float)total, 1, 1, &r, &g, &b); + + col.r = FTOCHAR(r); + col.g = FTOCHAR(g); + col.b = FTOCHAR(b); + + for(BLI_ghashIterator_init(&ghi, arc->faces); + !BLI_ghashIterator_isDone(&ghi); + BLI_ghashIterator_step(&ghi)) + { + efa = BLI_ghashIterator_getValue(&ghi); + + mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + + blendColor(&mcol[0], &col); + blendColor(&mcol[1], &col); + blendColor(&mcol[2], &col); + + if(efa->v4) { + blendColor(&mcol[3], &col); + } + } + } + + for(efa=em->faces.first; efa; efa=efa->next) { mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - mcol[0] = MColFromWeight(efa->v1); - mcol[1] = MColFromWeight(efa->v2); - mcol[2] = MColFromWeight(efa->v3); + mcol[0].a = 255; + mcol[1].a = 255; + mcol[2].a = 255; if(efa->v4) { - mcol[3] = MColFromWeight(efa->v4); + mcol[3].a = 255; } } } @@ -1874,7 +3301,7 @@ void initArcIterator(ReebArcIterator *iter, ReebArc *arc, ReebNode *head) { iter->arc = arc; - if (head == arc->v1) + if (head == arc->head) { iter->start = 0; iter->end = arc->bcount - 1; @@ -1887,7 +3314,36 @@ void initArcIterator(ReebArcIterator *iter, ReebArc *arc, ReebNode *head) iter->stride = -1; } + iter->length = arc->bcount; + + iter->index = iter->start - iter->stride; +} + +void initArcIteratorStart(struct ReebArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start) +{ + iter->arc = arc; + + if (head == arc->head) + { + iter->start = start; + iter->end = arc->bcount - 1; + iter->stride = 1; + } + else + { + iter->start = arc->bcount - 1 - start; + iter->end = 0; + iter->stride = -1; + } + iter->index = iter->start - iter->stride; + + iter->length = arc->bcount - start; + + if (start >= arc->bcount) + { + iter->start = iter->end; /* stop iterator since it's past its end */ + } } void initArcIterator2(ReebArcIterator *iter, ReebArc *arc, int start, int end) @@ -1907,6 +3363,8 @@ void initArcIterator2(ReebArcIterator *iter, ReebArc *arc, int start, int end) } iter->index = iter->start - iter->stride; + + iter->length = abs(iter->end - iter->start) + 1; } EmbedBucket * nextBucket(ReebArcIterator *iter) @@ -1921,3 +3379,412 @@ EmbedBucket * nextBucket(ReebArcIterator *iter) return result; } + +EmbedBucket * nextNBucket(ReebArcIterator *iter, int n) +{ + EmbedBucket *result = NULL; + + iter->index += n * iter->stride; + + /* check if passed end */ + if ((iter->stride == 1 && iter->index <= iter->end) || + (iter->stride == -1 && iter->index >= iter->end)) + { + result = &(iter->arc->buckets[iter->index]); + } + else + { + /* stop iterator if passed end */ + iter->index = iter->end; + } + + return result; +} + +EmbedBucket * peekBucket(ReebArcIterator *iter, int n) +{ + EmbedBucket *result = NULL; + int index = iter->index + n * iter->stride; + + /* check if passed end */ + if ((iter->stride == 1 && index <= iter->end && index >= iter->start) || + (iter->stride == -1 && index >= iter->end && index <= iter->start)) + { + result = &(iter->arc->buckets[index]); + } + + return result; +} + +EmbedBucket * previousBucket(struct ReebArcIterator *iter) +{ + EmbedBucket *result = NULL; + + if (iter->index != iter->start) + { + iter->index -= iter->stride; + result = &(iter->arc->buckets[iter->index]); + } + + return result; +} + +int iteratorStopped(struct ReebArcIterator *iter) +{ + if (iter->index == iter->end) + { + return 1; + } + else + { + return 0; + } +} + +struct EmbedBucket * currentBucket(struct ReebArcIterator *iter) +{ + EmbedBucket *result = NULL; + + if (iter->index != iter->end) + { + result = &(iter->arc->buckets[iter->index]); + } + + return result; +} + +/************************ PUBLIC FUNCTIONS *********************************************/ + +ReebGraph *BIF_ReebGraphMultiFromEditMesh(void) +{ + EditMesh *em = G.editMesh; + EdgeIndex indexed_edges; + VertexData *data; + ReebGraph *rg = NULL; + ReebGraph *rgi, *previous; + int i, nb_levels = REEB_MAX_MULTI_LEVEL; + + if (em == NULL) + return NULL; + + data = allocVertexData(em); + + buildIndexedEdges(em, &indexed_edges); + + if (weightFromDistance(em, &indexed_edges) == 0) + { + error("No selected vertex\n"); + freeEdgeIndex(&indexed_edges); + return NULL; + } + + renormalizeWeight(em, 1.0f); + + if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC) + { + weightToHarmonic(em, &indexed_edges); + } + + freeEdgeIndex(&indexed_edges); + +#ifdef DEBUG_REEB + weightToVCol(em, 0); +#endif + + rg = generateReebGraph(em, G.scene->toolsettings->skgen_resolution); + + /* Remove arcs without embedding */ + filterNullReebGraph(rg); + + /* smart filter and loop filter on basic level */ + filterGraph(rg, SKGEN_FILTER_SMART, 0, 0); + + repositionNodes(rg); + + /* Filtering might have created degree 2 nodes, so remove them */ + removeNormalNodes(rg); + + joinSubgraphs(rg, 1.0); + + BLI_buildAdjacencyList((BGraph*)rg); + + /* calc length before copy, so we have same length on all levels */ + BLI_calcGraphLength((BGraph*)rg); + + previous = NULL; + for (i = 0; i <= nb_levels; i++) + { + rgi = rg; + + /* don't filter last level */ + if (i > 0) + { + float internal_threshold; + float external_threshold; + + /* filter internal progressively in second half only*/ + if (i > nb_levels / 2) + { + internal_threshold = rg->length * G.scene->toolsettings->skgen_threshold_internal; + } + else + { + internal_threshold = rg->length * G.scene->toolsettings->skgen_threshold_internal * (2 * i / (float)nb_levels); + } + + external_threshold = rg->length * G.scene->toolsettings->skgen_threshold_external * (i / (float)nb_levels); + + filterGraph(rgi, G.scene->toolsettings->skgen_options, internal_threshold, external_threshold); + } + + if (i < nb_levels) + { + rg = copyReebGraph(rgi, i + 1); + } + + finalizeGraph(rgi, G.scene->toolsettings->skgen_postpro_passes, G.scene->toolsettings->skgen_postpro); + + BLI_markdownSymmetry((BGraph*)rgi, rgi->nodes.first, G.scene->toolsettings->skgen_symmetry_limit); + + if (previous != NULL) + { + relinkNodes(rgi, previous); + } + previous = rgi; + } + + verifyMultiResolutionLinks(rg, 0); + + MEM_freeN(data); + + return rg; +} + +ReebGraph *BIF_ReebGraphFromEditMesh(void) +{ + EditMesh *em = G.editMesh; + EdgeIndex indexed_edges; + VertexData *data; + ReebGraph *rg = NULL; + + if (em == NULL) + return NULL; + + data = allocVertexData(em); + + buildIndexedEdges(em, &indexed_edges); + + if (weightFromDistance(em, &indexed_edges) == 0) + { + error("No selected vertex\n"); + freeEdgeIndex(&indexed_edges); + freeEdgeIndex(&indexed_edges); + return NULL; + } + + renormalizeWeight(em, 1.0f); + + if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC) + { + weightToHarmonic(em, &indexed_edges); + } + + freeEdgeIndex(&indexed_edges); + +#ifdef DEBUG_REEB + weightToVCol(em, 1); +#endif + + rg = generateReebGraph(em, G.scene->toolsettings->skgen_resolution); + + REEB_exportGraph(rg, -1); + + printf("GENERATED\n"); + printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph*)rg)); + + /* Remove arcs without embedding */ + filterNullReebGraph(rg); + + BLI_freeAdjacencyList((BGraph*)rg); + + printf("NULL FILTERED\n"); + printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph*)rg)); + + filterGraph(rg, G.scene->toolsettings->skgen_options, G.scene->toolsettings->skgen_threshold_internal, G.scene->toolsettings->skgen_threshold_external); + + finalizeGraph(rg, G.scene->toolsettings->skgen_postpro_passes, G.scene->toolsettings->skgen_postpro); + + REEB_exportGraph(rg, -1); + +#ifdef DEBUG_REEB + arcToVCol(rg, em, 0); + //angleToVCol(em, 1); +#endif + + printf("DONE\n"); + printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph*)rg)); + + MEM_freeN(data); + + return rg; +} + +void BIF_GlobalReebFree() +{ + if (GLOBAL_RG != NULL) + { + REEB_freeGraph(GLOBAL_RG); + GLOBAL_RG = NULL; + } +} + +void BIF_GlobalReebGraphFromEditMesh(void) +{ + ReebGraph *rg; + + BIF_GlobalReebFree(); + + rg = BIF_ReebGraphMultiFromEditMesh(); + + GLOBAL_RG = rg; +} + +void REEB_draw() +{ + ReebGraph *rg; + ReebArc *arc; + int i = 0; + + if (GLOBAL_RG == NULL) + { + return; + } + + if (GLOBAL_RG->link_up && G.scene->toolsettings->skgen_options & SKGEN_DISP_ORIG) + { + for (rg = GLOBAL_RG; rg->link_up; rg = rg->link_up) ; + } + else + { + i = G.scene->toolsettings->skgen_multi_level; + + for (rg = GLOBAL_RG; rg->multi_level != i && rg->link_up; rg = rg->link_up) ; + } + + glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE)); + + glDisable(GL_DEPTH_TEST); + for (arc = rg->arcs.first; arc; arc = arc->next, i++) + { + ReebArcIterator iter; + EmbedBucket *bucket; + float vec[3]; + char text[128]; + char *s = text; + + glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE) + 2); + glColor3f(0, 0, 0); + glBegin(GL_LINE_STRIP); + glVertex3fv(arc->head->p); + + if (arc->bcount) + { + initArcIterator(&iter, arc, arc->head); + for (bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter)) + { + glVertex3fv(bucket->p); + } + } + + glVertex3fv(arc->tail->p); + glEnd(); + + glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE)); + + if (arc->symmetry_level == 1) + { + glColor3f(1, 0, 0); + } + else if (arc->symmetry_flag == SYM_SIDE_POSITIVE || arc->symmetry_flag == SYM_SIDE_NEGATIVE) + { + glColor3f(1, 0.5f, 0); + } + else if (arc->symmetry_flag >= SYM_SIDE_RADIAL) + { + glColor3f(0.5f, 1, 0); + } + else + { + glColor3f(1, 1, 0); + } + glBegin(GL_LINE_STRIP); + glVertex3fv(arc->head->p); + + if (arc->bcount) + { + initArcIterator(&iter, arc, arc->head); + for (bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter)) + { + glVertex3fv(bucket->p); + } + } + + glVertex3fv(arc->tail->p); + glEnd(); + + + if (G.scene->toolsettings->skgen_options & SKGEN_DISP_EMBED) + { + glColor3f(1, 1, 1); + glBegin(GL_POINTS); + glVertex3fv(arc->head->p); + glVertex3fv(arc->tail->p); + + glColor3f(0.5f, 0.5f, 1); + if (arc->bcount) + { + initArcIterator(&iter, arc, arc->head); + for (bucket = nextBucket(&iter); bucket; bucket = nextBucket(&iter)) + { + glVertex3fv(bucket->p); + } + } + glEnd(); + } + + if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX) + { + VecLerpf(vec, arc->head->p, arc->tail->p, 0.5f); + s += sprintf(s, "%i (%i-%i-%i) ", i, arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); + + if (G.scene->toolsettings->skgen_options & SKGEN_DISP_WEIGHT) + { + s += sprintf(s, "w:%0.3f ", arc->tail->weight - arc->head->weight); + } + + if (G.scene->toolsettings->skgen_options & SKGEN_DISP_LENGTH) + { + s += sprintf(s, "l:%0.3f", arc->length); + } + + glColor3f(0, 1, 0); + glRasterPos3fv(vec); + BMF_DrawString( G.fonts, text); + } + + if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX) + { + sprintf(text, " %i", arc->head->index); + glRasterPos3fv(arc->head->p); + BMF_DrawString( G.fonts, text); + + sprintf(text, " %i", arc->tail->index); + glRasterPos3fv(arc->tail->p); + BMF_DrawString( G.fonts, text); + } + } + glEnable(GL_DEPTH_TEST); + + glLineWidth(1.0); + glPointSize(1.0); +} diff --git a/source/blender/src/renderwin.c b/source/blender/src/renderwin.c index b4d78b7fa37..bbac70e9e5e 100644 --- a/source/blender/src/renderwin.c +++ b/source/blender/src/renderwin.c @@ -88,7 +88,10 @@ #include "BDR_sculptmode.h" #include "BDR_editobject.h" + +#ifndef DISABLE_PYTHON #include "BPY_extern.h" /* for BPY_do_all_scripts */ +#endif #include "BSE_view.h" #include "BSE_drawview.h" @@ -1273,8 +1276,10 @@ void BIF_store_spare(void) /* set up display, render an image or scene */ void BIF_do_render(int anim) { +#ifndef DISABLE_PYTHON if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_RENDER, anim); +#endif BIF_store_spare(); @@ -1286,8 +1291,9 @@ void BIF_do_render(int anim) } if(G.scene->r.dither_intensity != 0.0f) BIF_redraw_render_rect(); - +#ifndef DISABLE_PYTHON if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_POSTRENDER, anim); +#endif } void do_ogl_view3d_render(Render *re, View3D *v3d, int winx, int winy) diff --git a/source/blender/src/seqaudio.c b/source/blender/src/seqaudio.c index 9b4e3361625..0bc40674350 100644 --- a/source/blender/src/seqaudio.c +++ b/source/blender/src/seqaudio.c @@ -398,11 +398,7 @@ static void audio_fill_seq(Sequence * seq, void * mixdown, if (!seq->hdaudio) { char name[FILE_MAXDIR+FILE_MAXFILE]; - strncpy(name, seq->strip->dir, - FILE_MAXDIR-1); - strncat(name, - seq->strip->stripdata->name, - FILE_MAXFILE-1); + BLI_join_dirfile(name, seq->strip->dir, seq->strip->stripdata->name); BLI_convertstringcode(name, G.sce); seq->hdaudio= sound_open_hdaudio(name); diff --git a/source/blender/src/space.c b/source/blender/src/space.c index c26620ccbf2..b6221c2f84b 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -168,7 +168,9 @@ #include "PIL_time.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif #include "butspace.h" #include "mydevice.h" @@ -1079,7 +1081,9 @@ void BIF_undo(void) else { /* now also in faceselect mode */ if(U.uiflag & USER_GLOBALUNDO) { +#ifndef DISABLE_PYTHON BPY_scripts_clear_pyobjects(); +#endif BKE_undo_step(1); sound_initialize_sounds(); } @@ -1248,12 +1252,13 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) * - grease-pencil also defaults to leftmouse */ if(event==LEFTMOUSE) { +#ifndef DISABLE_PYTHON /* run any view3d event handler script links */ if (sa->scriptlink.totscript) { if (BPY_do_spacehandlers(sa, event, val, SPACEHANDLER_VIEW3D_EVENT)) return; /* return if event was processed (swallowed) by handler(s) */ } - +#endif if(gpencil_do_paint(sa, L_MOUSE)) return; if(BIF_do_manipulator(sa)) return; } @@ -1309,10 +1314,12 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) } } +#ifndef DISABLE_PYTHON /* run any view3d event handler script links */ if (event && sa->scriptlink.totscript) if (BPY_do_spacehandlers(sa, event, val, SPACEHANDLER_VIEW3D_EVENT)) return; /* return if event was processed (swallowed) by handler(s) */ +#endif /* TEXTEDITING?? */ if((G.obedit) && G.obedit->type==OB_FONT) { @@ -4324,7 +4331,8 @@ void drawinfospace(ScrArea *sa, void *spacedata) (xpos+edgsp+(1*mpref)+(1*midsp)),y2,mpref,buth, &(U.uiflag), 0, 0, 0, 0, "Allows all codecs for rendering (not guaranteed)"); #endif - + +#ifndef DISABLE_PYTHON uiDefBut(block, LABEL,0,"Auto Run Python Scripts", (xpos+edgsp+(1*midsp)+(1*mpref)),y6label,mpref,buth, 0, 0, 0, 0, 0, ""); @@ -4332,7 +4340,8 @@ void drawinfospace(ScrArea *sa, void *spacedata) uiDefButBitI(block, TOGN, USER_DONT_DOSCRIPTLINKS, REDRAWBUTSSCRIPT, "Enabled by Default", (xpos+edgsp+(1*mpref)+(1*midsp)),y5,mpref,buth, &(U.flag), 0, 0, 0, 0, "Allow any .blend file to run scripts automatically (unsafe with blend files from an untrusted source)"); - +#endif + uiDefBut(block, LABEL,0,"Keyboard:", (xpos+edgsp+(3*midsp)+(3*mpref)),y2label,mpref,buth, 0, 0, 0, 0, 0, ""); @@ -4511,6 +4520,7 @@ void drawinfospace(ScrArea *sa, void *spacedata) 0, 0, 0, 0, 0, "Select the default render output location"); uiBlockEndAlign(block); +#ifndef DISABLE_PYTHON uiBlockBeginAlign(block); uiDefBut(block, TEX, B_PYMENUEVAL, "Python Scripts: ", (xpos+edgsp+lpref+midsp),y1,(lpref-2*smfileselbut),buth, @@ -4522,7 +4532,7 @@ void drawinfospace(ScrArea *sa, void *spacedata) (xpos+edgsp+(2*lpref)+midsp-smfileselbut),y1,smfileselbut,buth, 0, 0, 0, 0, 0, "Select the default Python script location"); uiBlockEndAlign(block); - +#endif uiBlockBeginAlign(block); uiDefBut(block, TEX, 0, "Sounds: ", @@ -7081,6 +7091,7 @@ SpaceType *spacetext_get_type(void) static void spacescript_change(ScrArea *sa, void *spacedata) { +#ifndef DISABLE_PYTHON SpaceScript *sc = (SpaceScript*) spacedata; /*clear all temp button references*/ @@ -7089,6 +7100,7 @@ static void spacescript_change(ScrArea *sa, void *spacedata) BPy_Free_DrawButtonsList(); sc->but_refs = NULL; } +#endif } SpaceType *spacescript_get_type(void) diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c index 55feb4c0305..b675f6868f8 100644 --- a/source/blender/src/toolbox.c +++ b/source/blender/src/toolbox.c @@ -121,8 +121,10 @@ #include "mydevice.h" /* bpymenu */ +#ifndef DISABLE_PYTHON #include "BPY_extern.h" #include "BPY_menus.h" +#endif #include "BLO_sys_types.h" // for intptr_t support @@ -1593,6 +1595,17 @@ static TBitem tb_node_addcomp[]= { { 0, "Group", 9, NULL}, { 0, "Dynamic", 10, NULL}, { -1, "", 0, NULL}}; + +static TBitem tb_node_addtex[]= { + { 0, "Input", 1, NULL}, + { 0, "Output", 2, NULL}, + { 0, "Color", 3, NULL}, + { 0, "Convertor", 4, NULL}, + { 0, "Patterns", 5, NULL}, + { 0, "Textures", 6, NULL}, + { 0, "Distort", 7, NULL}, + { 0, "Group", 8, NULL}, + { -1, "", 0, NULL}}; /* do_node_addmenu() in header_node.c, prototype in BSE_headerbuttons.h */ @@ -1924,12 +1937,15 @@ static TBitem *create_mesh_sublevel(ListBase *storage) Link *link; TBitem *meshmenu, *mm; int totmenu= 10, totpymenu=0, a=0; - + +#ifndef DISABLE_PYTHON /* Python Menu */ BPyMenu *pym; /* count the python menu items*/ for (pym = BPyMenuTable[PYMENU_ADDMESH]; pym; pym = pym->next, totpymenu++) {} +#endif + if (totpymenu) totmenu += totpymenu+1; /* add 1 for the seperator */ link= MEM_callocN(sizeof(Link) + sizeof(TBitem)*(totmenu+1), "mesh menu"); @@ -1948,6 +1964,7 @@ static TBitem *create_mesh_sublevel(ListBase *storage) mm->icon = 0; mm->retval= a; mm->name = "Monkey"; mm++; a++; /* a == 10 */ +#ifndef DISABLE_PYTHON if (totpymenu) { int i=0; mm->icon = 0; mm->retval= 0; mm->name = "SEPR"; mm++; @@ -1960,7 +1977,8 @@ static TBitem *create_mesh_sublevel(ListBase *storage) mm++; a++; } } - +#endif + /* terminate the menu */ mm->icon= -1; mm->retval= a; mm->name= ""; mm->poin= do_info_add_meshmenu; @@ -2119,7 +2137,7 @@ void toolbox_n(void) menu3= tb__select; menu4= tb_edit; menu5= tb_transform_editmode2; - } + } else if(G.obedit->type==OB_LATTICE) { menu1= tb_empty;str1= "Lattice"; menu2= tb_empty; @@ -2138,8 +2156,11 @@ void toolbox_n(void) if(snode->treetype==NTREE_COMPOSIT) menu1= tb_node_addcomp; - else + else if(snode->treetype==NTREE_SHADER) menu1= tb_node_addsh; + else if(snode->treetype==NTREE_TEXTURE) + menu1= tb_node_addtex; + str1= "Add"; menu2= tb_node_node; str2= "Node"; menu3= tb_node_select; str3= "Select"; @@ -2166,8 +2187,17 @@ void toolbox_n(void) menu1[7].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_DISTORT); menu1[8].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_GROUP); menu1[9].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_DYNAMIC); - } + else if(snode->treetype==NTREE_TEXTURE) { + menu1[0].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_INPUT); + menu1[1].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OUTPUT); + menu1[2].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_COLOR); + menu1[3].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_CONVERTOR); + menu1[4].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_PATTERN); + menu1[5].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_TEXTURE); + menu1[6].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_DISTORT); + menu1[7].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_GROUP); + } dx= 96; tot= 5; diff --git a/source/blender/src/transform.c b/source/blender/src/transform.c index b9b8a4a21a9..7a13943d0e0 100644 --- a/source/blender/src/transform.c +++ b/source/blender/src/transform.c @@ -2486,25 +2486,28 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short Mat3CpyMat4(pmtx, t->poseobj->obmat); Mat3Inv(imtx, pmtx); - VecSubf(vec, td->center, center); - - Mat3MulVecfl(pmtx, vec); // To Global space - Mat3MulVecfl(mat, vec); // Applying rotation - Mat3MulVecfl(imtx, vec); // To Local space - - VecAddf(vec, vec, center); - /* vec now is the location where the object has to be */ - - VecSubf(vec, vec, td->center); // Translation needed from the initial location - - Mat3MulVecfl(pmtx, vec); // To Global space - Mat3MulVecfl(td->smtx, vec);// To Pose space - - protectedTransBits(td->protectflag, vec); - - VecAddf(td->loc, td->iloc, vec); - - constraintTransLim(t, td); + if ((td->flag & TD_NO_LOC) == 0) + { + VecSubf(vec, td->center, center); + + Mat3MulVecfl(pmtx, vec); // To Global space + Mat3MulVecfl(mat, vec); // Applying rotation + Mat3MulVecfl(imtx, vec); // To Local space + + VecAddf(vec, vec, center); + /* vec now is the location where the object has to be */ + + VecSubf(vec, vec, td->center); // Translation needed from the initial location + + Mat3MulVecfl(pmtx, vec); // To Global space + Mat3MulVecfl(td->smtx, vec);// To Pose space + + protectedTransBits(td->protectflag, vec); + + VecAddf(td->loc, td->iloc, vec); + + constraintTransLim(t, td); + } /* rotation */ if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself @@ -2520,23 +2523,28 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short } } else { - /* translation */ - VecSubf(vec, td->center, center); - Mat3MulVecfl(mat, vec); - VecAddf(vec, vec, center); - /* vec now is the location where the object has to be */ - VecSubf(vec, vec, td->center); - Mat3MulVecfl(td->smtx, vec); - - protectedTransBits(td->protectflag, vec); - if(td->tdi) { - TransDataIpokey *tdi= td->tdi; - add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]); - add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]); - add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]); + if ((td->flag & TD_NO_LOC) == 0) + { + /* translation */ + VecSubf(vec, td->center, center); + Mat3MulVecfl(mat, vec); + VecAddf(vec, vec, center); + /* vec now is the location where the object has to be */ + VecSubf(vec, vec, td->center); + Mat3MulVecfl(td->smtx, vec); + + protectedTransBits(td->protectflag, vec); + + if(td->tdi) { + TransDataIpokey *tdi= td->tdi; + add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]); + add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]); + add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]); + } + else VecAddf(td->loc, td->iloc, vec); } - else VecAddf(td->loc, td->iloc, vec); + constraintTransLim(t, td); diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c index 3465983d110..f58eaefc628 100644 --- a/source/blender/src/transform_conversions.c +++ b/source/blender/src/transform_conversions.c @@ -540,8 +540,17 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr td->ob = ob; td->flag= TD_SELECTED|TD_USEQUAT; - if(bone->flag & BONE_HINGE_CHILD_TRANSFORM) + if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) + { + td->flag |= TD_NOCENTER; + } + + if (bone->flag & BONE_TRANSFORM_CHILD) + { td->flag |= TD_NOCENTER; + td->flag |= TD_NO_LOC; + } + td->protectflag= pchan->protectflag; td->loc = pchan->loc; @@ -628,17 +637,25 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr td->con= pchan->constraints.first; } -static void bone_children_clear_transflag(ListBase *lb) +static void bone_children_clear_transflag(TransInfo *t, ListBase *lb) { Bone *bone= lb->first; for(;bone;bone= bone->next) { if((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED)) + { bone->flag |= BONE_HINGE_CHILD_TRANSFORM; + } + else if (bone->flag & BONE_TRANSFORM && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) + { + bone->flag |= BONE_TRANSFORM_CHILD; + } else + { bone->flag &= ~BONE_TRANSFORM; + } - bone_children_clear_transflag(&bone->childbase); + bone_children_clear_transflag(t, &bone->childbase); } } @@ -661,6 +678,7 @@ static void set_pose_transflags(TransInfo *t, Object *ob) bone->flag &= ~BONE_TRANSFORM; bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM; + bone->flag &= ~BONE_TRANSFORM_CHILD; } } @@ -670,7 +688,7 @@ static void set_pose_transflags(TransInfo *t, Object *ob) for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { bone= pchan->bone; if(bone->flag & BONE_TRANSFORM) - bone_children_clear_transflag(&bone->childbase); + bone_children_clear_transflag(t, &bone->childbase); } } /* now count, and check if we have autoIK or have to switch from translate to rotate */ @@ -1115,6 +1133,14 @@ static void createTransArmatureVerts(TransInfo *t) Mat3CpyMat3(td->smtx, smtx); Mat3CpyMat3(td->mtx, mtx); + VecSubf(delta, ebo->tail, ebo->head); + vec_roll_to_mat3(delta, ebo->roll, td->axismtx); + + if ((ebo->flag & BONE_ROOTSEL) == 0) + { + td->extra = ebo; + } + td->ext = NULL; td->tdi = NULL; td->val = NULL; @@ -1132,6 +1158,11 @@ static void createTransArmatureVerts(TransInfo *t) Mat3CpyMat3(td->smtx, smtx); Mat3CpyMat3(td->mtx, mtx); + VecSubf(delta, ebo->tail, ebo->head); + vec_roll_to_mat3(delta, ebo->roll, td->axismtx); + + td->extra = ebo; /* to fix roll */ + td->ext = NULL; td->tdi = NULL; td->val = NULL; @@ -1845,7 +1876,7 @@ static void VertsToTransData(TransData *td, EditVert *eve) td->ext = NULL; td->tdi = NULL; td->val = NULL; - td->tdmir = NULL; + td->extra = NULL; if (BIF_GetTransInfo()->mode == TFM_BWEIGHT) { td->val = &(eve->bweight); td->ival = eve->bweight; @@ -2198,7 +2229,7 @@ static void createTransEditVerts(TransInfo *t) /* Mirror? */ if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) { EditVert *vmir= editmesh_get_x_mirror_vert(G.obedit, tob->iloc); /* initializes octree on first call */ - if(vmir != eve) tob->tdmir = vmir; + if(vmir != eve) tob->extra = vmir; } tob++; } @@ -3497,9 +3528,17 @@ static void set_trans_object_base_flags(TransInfo *t) parsel= parsel->parent; } - if(parsel) { - base->flag &= ~SELECT; - base->flag |= BA_WAS_SEL; + if(parsel) + { + if (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) + { + base->flag |= BA_TRANSFORM_CHILD; + } + else + { + base->flag &= ~SELECT; + base->flag |= BA_WAS_SEL; + } } /* used for flush, depgraph will change recalcs if needed :) */ ob->recalc |= OB_RECALC_OB; @@ -3526,7 +3565,7 @@ static void clear_trans_object_base_flags(void) base= FIRSTBASE; while(base) { if(base->flag & BA_WAS_SEL) base->flag |= SELECT; - base->flag &= ~(BA_WAS_SEL|BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA|BA_DO_IPO); + base->flag &= ~(BA_WAS_SEL|BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA|BA_DO_IPO|BA_TRANSFORM_CHILD); base = base->next; } @@ -4097,6 +4136,12 @@ static void createTransObject(TransInfo *t) td->protectflag= ob->protectflag; td->ext = tx; + if (base->flag & BA_TRANSFORM_CHILD) + { + td->flag |= TD_NOCENTER; + td->flag |= TD_NO_LOC; + } + /* select linked objects, but skip them later */ if (ob->id.lib != 0) { td->flag |= TD_SKIP; diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c index a1440b8cbce..229889d15ff 100644 --- a/source/blender/src/transform_generics.c +++ b/source/blender/src/transform_generics.c @@ -254,7 +254,7 @@ static void editmesh_apply_to_mirror(TransInfo *t) if (td->flag & TD_SKIP) continue; - eve = td->tdmir; + eve = td->extra; if(eve) { eve->co[0]= -td->loc[0]; eve->co[1]= td->loc[1]; @@ -470,6 +470,8 @@ void recalcData(TransInfo *t) else if(G.obedit->type==OB_ARMATURE){ /* no recalc flag, does pose */ bArmature *arm= G.obedit->data; EditBone *ebo; + TransData *td = t->data; + int i; /* Ensure all bones are correctly adjusted */ for (ebo=G.edbo.first; ebo; ebo=ebo->next){ @@ -506,6 +508,38 @@ void recalcData(TransInfo *t) ebo->oldlength= ebo->length; } } + + + if (t->mode != TFM_BONE_ROLL) + { + /* fix roll */ + for(i = 0; i < t->total; i++, td++) + { + if (td->extra) + { + float vec[3], up_axis[3]; + float qrot[4]; + + ebo = td->extra; + VECCOPY(up_axis, td->axismtx[2]); + + if (t->mode != TFM_ROTATION) + { + VecSubf(vec, ebo->tail, ebo->head); + Normalize(vec); + RotationBetweenVectorsToQuat(qrot, td->axismtx[1], vec); + QuatMulVecf(qrot, up_axis); + } + else + { + Mat3MulVecfl(t->mat, up_axis); + } + + ebo->roll = rollBoneToVector(ebo, up_axis); + } + } + } + if(arm->flag & ARM_MIRROR_EDIT) transform_armature_mirror_update(); @@ -820,7 +854,10 @@ void restoreTransObjects(TransInfo *t) ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY; } #endif - } + } + + Mat3One(t->mat); + recalcData(t); } @@ -876,12 +913,16 @@ void calculateCenterCursor2D(TransInfo *t) void calculateCenterMedian(TransInfo *t) { float partial[3] = {0.0f, 0.0f, 0.0f}; + int total = 0; int i; for(i = 0; i < t->total; i++) { if (t->data[i].flag & TD_SELECTED) { if (!(t->data[i].flag & TD_NOCENTER)) + { VecAddf(partial, partial, t->data[i].center); + total++; + } } else { /* @@ -892,7 +933,7 @@ void calculateCenterMedian(TransInfo *t) } } if(i) - VecMulf(partial, 1.0f / i); + VecMulf(partial, 1.0f / total); VECCOPY(t->center, partial); calculateCenter2D(t); diff --git a/source/blender/src/transform_orientations.c b/source/blender/src/transform_orientations.c index fc9dfbb902e..0bc1ef5ca1f 100644 --- a/source/blender/src/transform_orientations.c +++ b/source/blender/src/transform_orientations.c @@ -40,6 +40,7 @@ #include "BKE_global.h" #include "BKE_utildefines.h" +#include "BKE_armature.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -680,21 +681,20 @@ int getTransformOrientation(float normal[3], float plane[3], int activeOnly) { if (ebone->flag & BONE_SELECTED) { + float mat[3][3]; float vec[3]; VecSubf(vec, ebone->tail, ebone->head); Normalize(vec); VecAddf(normal, normal, vec); + + vec_roll_to_mat3(vec, ebone->roll, mat); + VecAddf(plane, plane, mat[2]); } } } Normalize(normal); - Crossf(plane, G.obedit->obmat[0], normal); - - if (Inpf(plane, plane) < FLT_EPSILON) - { - Crossf(plane, G.obedit->obmat[1], normal); - } + Normalize(plane); if (plane[0] != 0 || plane[1] != 0 || plane[2] != 0) { diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index 7fdc6725964..16c26336b89 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -134,7 +134,9 @@ #include "BDR_imagepaint.h" #include "BDR_vpaint.h" +#ifndef DISABLE_PYTHON #include "BPY_extern.h" +#endif #include "blendef.h" @@ -147,6 +149,8 @@ #include "PIL_time.h" +#include "reeb.h" + #include "GPU_extensions.h" #include "GPU_draw.h" @@ -677,11 +681,13 @@ int BIF_read_homefile(int from_memory) undo_imagepaint_clear(); BKE_reset_undo(); BKE_write_undo("Original"); /* save current state */ - + +#ifndef DISABLE_PYTHON /* if from memory, need to refresh python scripts */ if (from_memory) { BPY_path_update(); } +#endif return success; } @@ -914,8 +920,10 @@ void BIF_write_file(char *target) return; } +#ifndef DISABLE_PYTHON /* send the OnSave event */ if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE); +#endif for (li= G.main->library.first; li; li= li->id.next) { if (li->parent==NULL && BLI_streq(li->name, target)) { @@ -1093,6 +1101,9 @@ void exit_usiblender(void) BIF_clear_tempfiles(); + BIF_GlobalReebFree(); + BIF_freeRetarget(); + tf= G.ttfdata.first; while(tf) { @@ -1125,9 +1136,11 @@ void exit_usiblender(void) free_editArmature(); free_posebuf(); +#ifndef DISABLE_PYTHON /* before free_blender so py's gc happens while library still exists */ /* needed at least for a rare sigsegv that can happen in pydrivers */ BPY_end_python(); +#endif fastshade_free_render(); /* shaded view */ free_blender(); /* blender.c, does entire library */ |