|
Blender
V2.59
|
00001 /* 00002 * $Id: editarmature_retarget.c 36276 2011-04-21 15:53:30Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * Contributor(s): Martin Poirier 00021 * 00022 * ***** END GPL LICENSE BLOCK ***** 00023 * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...) 00024 */ 00025 00031 #include <ctype.h> 00032 #include <stdlib.h> 00033 #include <string.h> 00034 #include <math.h> 00035 #include <float.h> 00036 00037 #include "MEM_guardedalloc.h" 00038 00039 #include "PIL_time.h" 00040 00041 #include "DNA_armature_types.h" 00042 #include "DNA_constraint_types.h" 00043 #include "DNA_scene_types.h" 00044 #include "DNA_object_types.h" 00045 00046 #include "BLI_blenlib.h" 00047 #include "BLI_math.h" 00048 #include "BLI_editVert.h" 00049 #include "BLI_utildefines.h" 00050 #include "BLI_ghash.h" 00051 #include "BLI_graph.h" 00052 #include "BLI_rand.h" 00053 #include "BLI_threads.h" 00054 00055 //#include "BDR_editobject.h" 00056 00057 #include "BKE_constraint.h" 00058 #include "BKE_armature.h" 00059 #include "BKE_context.h" 00060 00061 #include "ED_armature.h" 00062 #include "ED_util.h" 00063 00064 #include "BIF_retarget.h" 00065 00066 00067 //#include "mydevice.h" 00068 #include "reeb.h" // FIX ME 00069 //#include "blendef.h" 00070 00071 #include "armature_intern.h" 00072 00073 /************ RIG RETARGET DATA STRUCTURES ***************/ 00074 00075 typedef struct MemoNode { 00076 float weight; 00077 int next; 00078 } MemoNode; 00079 00080 typedef struct RetargetParam { 00081 RigGraph *rigg; 00082 RigArc *iarc; 00083 RigNode *inode_start; 00084 bContext *context; 00085 } RetargetParam; 00086 00087 typedef enum 00088 { 00089 RETARGET_LENGTH, 00090 RETARGET_AGGRESSIVE 00091 } RetargetMode; 00092 00093 typedef enum 00094 { 00095 METHOD_BRUTE_FORCE = 0, 00096 METHOD_MEMOIZE = 1 00097 } RetargetMethod; 00098 00099 typedef enum 00100 { 00101 ARC_FREE = 0, 00102 ARC_TAKEN = 1, 00103 ARC_USED = 2 00104 } ArcUsageFlags; 00105 00106 static RigGraph *GLOBAL_RIGG = NULL; 00107 00108 /*******************************************************************************************************/ 00109 00110 void *exec_retargetArctoArc(void *param); 00111 00112 static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second); 00113 float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]); 00114 00115 /* two levels */ 00116 #define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX) 00117 00118 /*********************************** EDITBONE UTILS ****************************************************/ 00119 00120 static int countEditBoneChildren(ListBase *list, EditBone *parent) 00121 { 00122 EditBone *ebone; 00123 int count = 0; 00124 00125 for (ebone = list->first; ebone; ebone = ebone->next) 00126 { 00127 if (ebone->parent == parent) 00128 { 00129 count++; 00130 } 00131 } 00132 00133 return count; 00134 } 00135 00136 static EditBone* nextEditBoneChild(ListBase *list, EditBone *parent, int n) 00137 { 00138 EditBone *ebone; 00139 00140 for (ebone = list->first; ebone; ebone = ebone->next) 00141 { 00142 if (ebone->parent == parent) 00143 { 00144 if (n == 0) 00145 { 00146 return ebone; 00147 } 00148 n--; 00149 } 00150 } 00151 00152 return NULL; 00153 } 00154 00155 static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3]) 00156 { 00157 float mat[3][3], nor[3]; 00158 00159 sub_v3_v3v3(nor, bone->tail, bone->head); 00160 00161 vec_roll_to_mat3(nor, roll, mat); 00162 VECCOPY(up_axis, mat[2]); 00163 } 00164 00165 static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3]) 00166 { 00167 float nor[3], new_up_axis[3], x_axis[3], z_axis[3]; 00168 00169 VECCOPY(new_up_axis, old_up_axis); 00170 mul_qt_v3(qrot, new_up_axis); 00171 00172 sub_v3_v3v3(nor, bone->tail, bone->head); 00173 00174 cross_v3_v3v3(x_axis, nor, aligned_axis); 00175 cross_v3_v3v3(z_axis, x_axis, nor); 00176 00177 normalize_v3(new_up_axis); 00178 normalize_v3(x_axis); 00179 normalize_v3(z_axis); 00180 00181 if (dot_v3v3(new_up_axis, x_axis) < 0) 00182 { 00183 negate_v3(x_axis); 00184 } 00185 00186 if (dot_v3v3(new_up_axis, z_axis) < 0) 00187 { 00188 negate_v3(z_axis); 00189 } 00190 00191 if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) 00192 { 00193 rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */ 00194 return ED_rollBoneToVector(bone, x_axis, FALSE); 00195 } 00196 else 00197 { 00198 rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */ 00199 return ED_rollBoneToVector(bone, z_axis, FALSE); 00200 } 00201 } 00202 00203 static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3]) 00204 { 00205 if (previous == NULL) 00206 { 00207 /* default to up_axis if no previous */ 00208 return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); 00209 } 00210 else 00211 { 00212 float new_up_axis[3]; 00213 float vec_first[3], vec_second[3], normal[3]; 00214 00215 if (previous->bone) 00216 { 00217 sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head); 00218 } 00219 else if (previous->prev->bone) 00220 { 00221 sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail); 00222 } 00223 else 00224 { 00225 /* default to up_axis if first bone in the chain is an offset */ 00226 return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); 00227 } 00228 00229 sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head); 00230 00231 normalize_v3(vec_first); 00232 normalize_v3(vec_second); 00233 00234 cross_v3_v3v3(normal, vec_first, vec_second); 00235 normalize_v3(normal); 00236 00237 axis_angle_to_quat(qroll, vec_second, edge->up_angle); 00238 00239 mul_qt_v3(qroll, normal); 00240 00241 VECCOPY(new_up_axis, edge->up_axis); 00242 mul_qt_v3(qrot, new_up_axis); 00243 00244 normalize_v3(new_up_axis); 00245 00246 /* real qroll between normal and up_axis */ 00247 rotation_between_vecs_to_quat(qroll, new_up_axis, normal); 00248 00249 return ED_rollBoneToVector(edge->bone, normal, FALSE); 00250 } 00251 } 00252 00253 float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]) 00254 { 00255 float new_up_axis[3]; 00256 00257 VECCOPY(new_up_axis, old_up_axis); 00258 mul_qt_v3(qrot, new_up_axis); 00259 00260 return ED_rollBoneToVector(bone, new_up_axis, FALSE); 00261 } 00262 00263 /************************************ DESTRUCTORS ******************************************************/ 00264 00265 static void RIG_freeRigArc(BArc *arc) 00266 { 00267 BLI_freelistN(&((RigArc*)arc)->edges); 00268 } 00269 00270 void RIG_freeRigGraph(BGraph *rg) 00271 { 00272 RigGraph *rigg = (RigGraph*)rg; 00273 BNode *node; 00274 BArc *arc; 00275 00276 #ifdef USE_THREADS 00277 BLI_destroy_worker(rigg->worker); 00278 #endif 00279 00280 if (rigg->link_mesh) 00281 { 00282 REEB_freeGraph(rigg->link_mesh); 00283 } 00284 00285 for (arc = rg->arcs.first; arc; arc = arc->next) 00286 { 00287 RIG_freeRigArc(arc); 00288 } 00289 BLI_freelistN(&rg->arcs); 00290 00291 for (node = rg->nodes.first; node; node = node->next) 00292 { 00293 BLI_freeNode(rg, (BNode*)node); 00294 } 00295 BLI_freelistN(&rg->nodes); 00296 00297 BLI_freelistN(&rigg->controls); 00298 00299 BLI_ghash_free(rigg->bones_map, NULL, NULL); 00300 BLI_ghash_free(rigg->controls_map, NULL, NULL); 00301 00302 if (rigg->flag & RIG_FREE_BONELIST) 00303 { 00304 BLI_freelistN(rigg->editbones); 00305 MEM_freeN(rigg->editbones); 00306 } 00307 00308 MEM_freeN(rg); 00309 } 00310 00311 /************************************* ALLOCATORS ******************************************************/ 00312 00313 static RigGraph *newRigGraph(void) 00314 { 00315 RigGraph *rg; 00316 int totthread; 00317 00318 rg = MEM_callocN(sizeof(RigGraph), "rig graph"); 00319 00320 rg->head = NULL; 00321 00322 rg->bones_map = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "newRigGraph bones gh"); 00323 rg->controls_map = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "newRigGraph cont gh"); 00324 00325 rg->free_arc = RIG_freeRigArc; 00326 rg->free_node = NULL; 00327 00328 #ifdef USE_THREADS 00329 // if(G.scene->r.mode & R_FIXED_THREADS) 00330 // { 00331 // totthread = G.scene->r.threads; 00332 // } 00333 // else 00334 // { 00335 totthread = BLI_system_thread_count(); 00336 // } 00337 00338 rg->worker = BLI_create_worker(exec_retargetArctoArc, totthread, 20); /* fix number of threads */ 00339 #endif 00340 00341 return rg; 00342 } 00343 00344 static RigArc *newRigArc(RigGraph *rg) 00345 { 00346 RigArc *arc; 00347 00348 arc = MEM_callocN(sizeof(RigArc), "rig arc"); 00349 arc->count = 0; 00350 BLI_addtail(&rg->arcs, arc); 00351 00352 return arc; 00353 } 00354 00355 static RigControl *newRigControl(RigGraph *rg) 00356 { 00357 RigControl *ctrl; 00358 00359 ctrl = MEM_callocN(sizeof(RigControl), "rig control"); 00360 00361 BLI_addtail(&rg->controls, ctrl); 00362 00363 return ctrl; 00364 } 00365 00366 static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3]) 00367 { 00368 RigNode *node; 00369 node = MEM_callocN(sizeof(RigNode), "rig node"); 00370 BLI_addtail(&rg->nodes, node); 00371 00372 VECCOPY(node->p, p); 00373 node->degree = 1; 00374 node->arcs = NULL; 00375 00376 arc->head = node; 00377 00378 return node; 00379 } 00380 00381 static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node) 00382 { 00383 node->degree++; 00384 00385 arc->head = node; 00386 } 00387 00388 static RigNode *newRigNode(RigGraph *rg, float p[3]) 00389 { 00390 RigNode *node; 00391 node = MEM_callocN(sizeof(RigNode), "rig node"); 00392 BLI_addtail(&rg->nodes, node); 00393 00394 VECCOPY(node->p, p); 00395 node->degree = 0; 00396 node->arcs = NULL; 00397 00398 return node; 00399 } 00400 00401 static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3]) 00402 { 00403 RigNode *node = newRigNode(rg, p); 00404 00405 node->degree = 1; 00406 arc->tail = node; 00407 00408 return node; 00409 } 00410 00411 static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge) 00412 { 00413 BLI_addtail(&arc->edges, edge); 00414 00415 if (edge->prev == NULL) 00416 { 00417 VECCOPY(edge->head, arc->head->p); 00418 } 00419 else 00420 { 00421 RigEdge *last_edge = edge->prev; 00422 VECCOPY(edge->head, last_edge->tail); 00423 RIG_calculateEdgeAngles(last_edge, edge); 00424 } 00425 00426 edge->length = len_v3v3(edge->head, edge->tail); 00427 00428 arc->length += edge->length; 00429 00430 arc->count += 1; 00431 } 00432 00433 static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone) 00434 { 00435 RigEdge *edge; 00436 00437 edge = MEM_callocN(sizeof(RigEdge), "rig edge"); 00438 00439 VECCOPY(edge->tail, tail); 00440 edge->bone = bone; 00441 00442 if (bone) 00443 { 00444 getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis); 00445 } 00446 00447 RIG_appendEdgeToArc(arc, edge); 00448 } 00449 /************************************** CLONING TEMPLATES **********************************************/ 00450 00451 static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string) 00452 { 00453 int i, j; 00454 00455 for (i = 0, j = 0; template_name[i] != '\0' && i < 31 && j < 31; i++) 00456 { 00457 if (template_name[i] == '&') 00458 { 00459 if (template_name[i+1] == 'S' || template_name[i+1] == 's') 00460 { 00461 j += sprintf(name + j, "%s", side_string); 00462 i++; 00463 } 00464 else if (template_name[i+1] == 'N' || template_name[i+1] == 'n') 00465 { 00466 j += sprintf(name + j, "%s", num_string); 00467 i++; 00468 } 00469 else 00470 { 00471 name[j] = template_name[i]; 00472 j++; 00473 } 00474 } 00475 else 00476 { 00477 name[j] = template_name[i]; 00478 j++; 00479 } 00480 } 00481 00482 name[j] = '\0'; 00483 00484 unique_editbone_name(editbones, name, NULL); 00485 } 00486 00487 static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string) 00488 { 00489 RigControl *ctrl; 00490 char name[32]; 00491 00492 ctrl = newRigControl(rg); 00493 00494 VECCOPY(ctrl->head, src_ctrl->head); 00495 VECCOPY(ctrl->tail, src_ctrl->tail); 00496 VECCOPY(ctrl->up_axis, src_ctrl->up_axis); 00497 VECCOPY(ctrl->offset, src_ctrl->offset); 00498 00499 ctrl->tail_mode = src_ctrl->tail_mode; 00500 ctrl->flag = src_ctrl->flag; 00501 00502 renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string); 00503 ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob); 00504 ctrl->bone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL); 00505 BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone); 00506 00507 ctrl->link = src_ctrl->link; 00508 ctrl->link_tail = src_ctrl->link_tail; 00509 00510 return ctrl; 00511 } 00512 00513 static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string) 00514 { 00515 RigEdge *src_edge; 00516 RigArc *arc; 00517 00518 arc = newRigArc(rg); 00519 00520 arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head); 00521 arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail); 00522 00523 arc->head->degree++; 00524 arc->tail->degree++; 00525 00526 arc->length = src_arc->length; 00527 00528 arc->count = src_arc->count; 00529 00530 for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) 00531 { 00532 RigEdge *edge; 00533 00534 edge = MEM_callocN(sizeof(RigEdge), "rig edge"); 00535 00536 VECCOPY(edge->head, src_edge->head); 00537 VECCOPY(edge->tail, src_edge->tail); 00538 VECCOPY(edge->up_axis, src_edge->up_axis); 00539 00540 edge->length = src_edge->length; 00541 edge->angle = src_edge->angle; 00542 edge->up_angle = src_edge->up_angle; 00543 00544 if (src_edge->bone != NULL) 00545 { 00546 char name[32]; 00547 renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string); 00548 edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob); 00549 edge->bone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL); 00550 BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone); 00551 } 00552 00553 BLI_addtail(&arc->edges, edge); 00554 } 00555 00556 return arc; 00557 } 00558 00559 static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string) 00560 { 00561 GHash *ptr_hash; 00562 RigNode *node; 00563 RigArc *arc; 00564 RigControl *ctrl; 00565 RigGraph *rg; 00566 00567 ptr_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "cloneRigGraph gh"); 00568 00569 rg = newRigGraph(); 00570 00571 rg->ob = ob; 00572 rg->editbones = editbones; 00573 00574 preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */ 00575 preEditBoneDuplicate(src->editbones); /* prime bones for duplication */ 00576 00577 /* Clone nodes */ 00578 for (node = src->nodes.first; node; node = node->next) 00579 { 00580 RigNode *cloned_node = newRigNode(rg, node->p); 00581 BLI_ghash_insert(ptr_hash, node, cloned_node); 00582 } 00583 00584 rg->head = BLI_ghash_lookup(ptr_hash, src->head); 00585 00586 /* Clone arcs */ 00587 for (arc = src->arcs.first; arc; arc = arc->next) 00588 { 00589 cloneArc(rg, src, arc, ptr_hash, side_string, num_string); 00590 } 00591 00592 /* Clone controls */ 00593 for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) 00594 { 00595 cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string); 00596 } 00597 00598 /* Relink bones properly */ 00599 for (arc = rg->arcs.first; arc; arc = arc->next) 00600 { 00601 RigEdge *edge; 00602 00603 for (edge = arc->edges.first; edge; edge = edge->next) 00604 { 00605 if (edge->bone != NULL) 00606 { 00607 EditBone *bone; 00608 00609 updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob); 00610 00611 if (edge->bone->parent) 00612 { 00613 bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent); 00614 00615 if (bone != NULL) 00616 { 00617 edge->bone->parent = bone; 00618 } 00619 else 00620 { 00621 /* disconnect since parent isn't cloned 00622 * this will only happen when cloning from selected bones 00623 * */ 00624 edge->bone->flag &= ~BONE_CONNECTED; 00625 } 00626 } 00627 } 00628 } 00629 } 00630 00631 for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) 00632 { 00633 EditBone *bone; 00634 00635 updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob); 00636 00637 if (ctrl->bone->parent) 00638 { 00639 bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent); 00640 00641 if (bone != NULL) 00642 { 00643 ctrl->bone->parent = bone; 00644 } 00645 else 00646 { 00647 /* disconnect since parent isn't cloned 00648 * this will only happen when cloning from selected bones 00649 * */ 00650 ctrl->bone->flag &= ~BONE_CONNECTED; 00651 } 00652 } 00653 00654 ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link); 00655 ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail); 00656 } 00657 00658 BLI_ghash_free(ptr_hash, NULL, NULL); 00659 00660 return rg; 00661 } 00662 00663 00664 /*******************************************************************************************************/ 00665 00666 static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second) 00667 { 00668 float vec_first[3], vec_second[3]; 00669 00670 sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head); 00671 sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head); 00672 00673 normalize_v3(vec_first); 00674 normalize_v3(vec_second); 00675 00676 edge_first->angle = angle_normalized_v3v3(vec_first, vec_second); 00677 00678 if (edge_second->bone != NULL) 00679 { 00680 float normal[3]; 00681 00682 cross_v3_v3v3(normal, vec_first, vec_second); 00683 normalize_v3(normal); 00684 00685 edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis); 00686 } 00687 } 00688 00689 /************************************ CONTROL BONES ****************************************************/ 00690 00691 static void RIG_addControlBone(RigGraph *rg, EditBone *bone) 00692 { 00693 RigControl *ctrl = newRigControl(rg); 00694 ctrl->bone = bone; 00695 VECCOPY(ctrl->head, bone->head); 00696 VECCOPY(ctrl->tail, bone->tail); 00697 getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis); 00698 ctrl->tail_mode = TL_NONE; 00699 00700 BLI_ghash_insert(rg->controls_map, bone->name, ctrl); 00701 } 00702 00703 static int RIG_parentControl(RigControl *ctrl, EditBone *link) 00704 { 00705 if (link) 00706 { 00707 float offset[3]; 00708 int flag = 0; 00709 00710 sub_v3_v3v3(offset, ctrl->bone->head, link->head); 00711 00712 /* if root matches, check for direction too */ 00713 if (dot_v3v3(offset, offset) < 0.0001) 00714 { 00715 float vbone[3], vparent[3]; 00716 00717 flag |= RIG_CTRL_FIT_ROOT; 00718 00719 sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head); 00720 sub_v3_v3v3(vparent, link->tail, link->head); 00721 00722 /* test for opposite direction */ 00723 if (dot_v3v3(vbone, vparent) > 0) 00724 { 00725 float nor[3]; 00726 float len; 00727 00728 cross_v3_v3v3(nor, vbone, vparent); 00729 00730 len = dot_v3v3(nor, nor); 00731 if (len < 0.0001) 00732 { 00733 flag |= RIG_CTRL_FIT_BONE; 00734 } 00735 } 00736 } 00737 00738 /* Bail out if old one is automatically better */ 00739 if (flag < ctrl->flag) 00740 { 00741 return 0; 00742 } 00743 00744 /* if there's already a link 00745 * overwrite only if new link is higher in the chain */ 00746 if (ctrl->link && flag == ctrl->flag) 00747 { 00748 EditBone *bone = NULL; 00749 00750 for (bone = ctrl->link; bone; bone = bone->parent) 00751 { 00752 /* if link is in the chain, break and use that one */ 00753 if (bone == link) 00754 { 00755 break; 00756 } 00757 } 00758 00759 /* not in chain, don't update link */ 00760 if (bone == NULL) 00761 { 00762 return 0; 00763 } 00764 } 00765 00766 00767 ctrl->link = link; 00768 ctrl->flag = flag; 00769 00770 VECCOPY(ctrl->offset, offset); 00771 00772 return 1; 00773 } 00774 00775 return 0; 00776 } 00777 00778 static void RIG_reconnectControlBones(RigGraph *rg) 00779 { 00780 RigControl *ctrl; 00781 int change = 1; 00782 00783 /* first pass, link to deform bones */ 00784 for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) 00785 { 00786 bPoseChannel *pchan; 00787 bConstraint *con; 00788 int found = 0; 00789 00790 /* DO SOME MAGIC HERE */ 00791 for (pchan= rg->ob->pose->chanbase.first; pchan; pchan= pchan->next) 00792 { 00793 for (con= pchan->constraints.first; con; con= con->next) 00794 { 00795 bConstraintTypeInfo *cti= constraint_get_typeinfo(con); 00796 ListBase targets = {NULL, NULL}; 00797 bConstraintTarget *ct; 00798 00799 /* constraint targets */ 00800 if (cti && cti->get_constraint_targets) 00801 { 00802 int target_index; 00803 00804 cti->get_constraint_targets(con, &targets); 00805 00806 for (target_index = 0, ct= targets.first; ct; target_index++, ct= ct->next) 00807 { 00808 if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) 00809 { 00810 /* SET bone link to bone corresponding to pchan */ 00811 EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name); 00812 00813 /* Making sure bone is in this armature */ 00814 if (link != NULL) 00815 { 00816 /* for pole targets, link to parent bone instead, if possible */ 00817 if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) 00818 { 00819 if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) 00820 { 00821 link = link->parent; 00822 } 00823 } 00824 00825 found = RIG_parentControl(ctrl, link); 00826 } 00827 } 00828 } 00829 00830 if (cti->flush_constraint_targets) 00831 cti->flush_constraint_targets(con, &targets, 0); 00832 } 00833 } 00834 } 00835 00836 /* if not found yet, check parent */ 00837 if (found == 0) 00838 { 00839 if (ctrl->bone->parent) 00840 { 00841 /* make sure parent is a deforming bone 00842 * NULL if not 00843 * */ 00844 EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name); 00845 00846 found = RIG_parentControl(ctrl, link); 00847 } 00848 00849 /* check if bone is not superposed on another one */ 00850 { 00851 RigArc *arc; 00852 RigArc *best_arc = NULL; 00853 EditBone *link = NULL; 00854 00855 for (arc = rg->arcs.first; arc; arc = arc->next) 00856 { 00857 RigEdge *edge; 00858 for (edge = arc->edges.first; edge; edge = edge->next) 00859 { 00860 if (edge->bone) 00861 { 00862 int fit = 0; 00863 00864 fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001; 00865 fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001; 00866 00867 if (fit) 00868 { 00869 /* pick the bone on the arc with the lowest symmetry level 00870 * means you connect control to the trunk of the skeleton */ 00871 if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) 00872 { 00873 best_arc = arc; 00874 link = edge->bone; 00875 } 00876 } 00877 } 00878 } 00879 } 00880 00881 found = RIG_parentControl(ctrl, link); 00882 } 00883 } 00884 00885 /* if not found yet, check child */ 00886 if (found == 0) 00887 { 00888 RigArc *arc; 00889 RigArc *best_arc = NULL; 00890 EditBone *link = NULL; 00891 00892 for (arc = rg->arcs.first; arc; arc = arc->next) 00893 { 00894 RigEdge *edge; 00895 for (edge = arc->edges.first; edge; edge = edge->next) 00896 { 00897 if (edge->bone && edge->bone->parent == ctrl->bone) 00898 { 00899 /* pick the bone on the arc with the lowest symmetry level 00900 * means you connect control to the trunk of the skeleton */ 00901 if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) 00902 { 00903 best_arc = arc; 00904 link = edge->bone; 00905 } 00906 } 00907 } 00908 } 00909 00910 found = RIG_parentControl(ctrl, link); 00911 } 00912 00913 } 00914 00915 00916 /* second pass, make chains in control bones */ 00917 while (change) 00918 { 00919 change = 0; 00920 00921 for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) 00922 { 00923 /* if control is not linked yet */ 00924 if (ctrl->link == NULL) 00925 { 00926 bPoseChannel *pchan; 00927 bConstraint *con; 00928 RigControl *ctrl_parent = NULL; 00929 RigControl *ctrl_child; 00930 int found = 0; 00931 00932 if (ctrl->bone->parent) 00933 { 00934 ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name); 00935 } 00936 00937 /* check constraints first */ 00938 00939 /* DO SOME MAGIC HERE */ 00940 for (pchan= rg->ob->pose->chanbase.first; pchan; pchan= pchan->next) 00941 { 00942 for (con= pchan->constraints.first; con; con= con->next) 00943 { 00944 bConstraintTypeInfo *cti= constraint_get_typeinfo(con); 00945 ListBase targets = {NULL, NULL}; 00946 bConstraintTarget *ct; 00947 00948 /* constraint targets */ 00949 if (cti && cti->get_constraint_targets) 00950 { 00951 cti->get_constraint_targets(con, &targets); 00952 00953 for (ct= targets.first; ct; ct= ct->next) 00954 { 00955 if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) 00956 { 00957 /* SET bone link to ctrl corresponding to pchan */ 00958 RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name); 00959 00960 /* if owner is a control bone, link with it */ 00961 if (link && link->link) 00962 { 00963 RIG_parentControl(ctrl, link->bone); 00964 found = 1; 00965 break; 00966 } 00967 } 00968 } 00969 00970 if (cti->flush_constraint_targets) 00971 cti->flush_constraint_targets(con, &targets, 0); 00972 } 00973 } 00974 } 00975 00976 if (found == 0) 00977 { 00978 /* check if parent is already linked */ 00979 if (ctrl_parent && ctrl_parent->link) 00980 { 00981 RIG_parentControl(ctrl, ctrl_parent->bone); 00982 change = 1; 00983 } 00984 else 00985 { 00986 /* check childs */ 00987 for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) 00988 { 00989 /* if a child is linked, link to that one */ 00990 if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) 00991 { 00992 RIG_parentControl(ctrl, ctrl_child->bone); 00993 change = 1; 00994 break; 00995 } 00996 } 00997 } 00998 } 00999 } 01000 } 01001 } 01002 01003 /* third pass, link control tails */ 01004 for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) 01005 { 01006 /* fit bone already means full match, so skip those */ 01007 if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) 01008 { 01009 GHashIterator ghi; 01010 01011 /* look on deform bones first */ 01012 BLI_ghashIterator_init(&ghi, rg->bones_map); 01013 01014 for( ; !BLI_ghashIterator_isDone(&ghi); BLI_ghashIterator_step(&ghi)) 01015 { 01016 EditBone *bone = (EditBone*)BLI_ghashIterator_getValue(&ghi); 01017 01018 /* don't link with parent */ 01019 if (bone->parent != ctrl->bone) 01020 { 01021 if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01) 01022 { 01023 ctrl->tail_mode = TL_HEAD; 01024 ctrl->link_tail = bone; 01025 break; 01026 } 01027 else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01) 01028 { 01029 ctrl->tail_mode = TL_TAIL; 01030 ctrl->link_tail = bone; 01031 break; 01032 } 01033 } 01034 } 01035 01036 /* if we haven't found one yet, look in control bones */ 01037 if (ctrl->tail_mode == TL_NONE) 01038 { 01039 } 01040 } 01041 } 01042 01043 } 01044 01045 /*******************************************************************************************************/ 01046 01047 static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2) 01048 { 01049 RigEdge *edge, *next_edge; 01050 01051 /* ignore cases where joint is at start or end */ 01052 if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) 01053 { 01054 return; 01055 } 01056 01057 /* swap arcs to make sure arc1 is before arc2 */ 01058 if (joined_arc1->head == joined_arc2->tail) 01059 { 01060 RigArc *tmp = joined_arc1; 01061 joined_arc1 = joined_arc2; 01062 joined_arc2 = tmp; 01063 } 01064 01065 for (edge = joined_arc2->edges.first; edge; edge = next_edge) 01066 { 01067 next_edge = edge->next; 01068 01069 RIG_appendEdgeToArc(joined_arc1, edge); 01070 } 01071 01072 joined_arc1->tail = joined_arc2->tail; 01073 01074 joined_arc2->edges.first = joined_arc2->edges.last = NULL; 01075 01076 BLI_removeArc((BGraph*)rg, (BArc*)joined_arc2); 01077 01078 BLI_removeNode((BGraph*)rg, (BNode*)node); 01079 } 01080 01081 static void RIG_removeNormalNodes(RigGraph *rg) 01082 { 01083 RigNode *node, *next_node; 01084 01085 for (node = rg->nodes.first; node; node = next_node) 01086 { 01087 next_node = node->next; 01088 01089 if (node->degree == 2) 01090 { 01091 RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL; 01092 01093 for (arc = rg->arcs.first; arc; arc = arc->next) 01094 { 01095 if (arc->head == node || arc->tail == node) 01096 { 01097 if (joined_arc1 == NULL) 01098 { 01099 joined_arc1 = arc; 01100 } 01101 else 01102 { 01103 joined_arc2 = arc; 01104 break; 01105 } 01106 } 01107 } 01108 01109 RIG_joinArcs(rg, node, joined_arc1, joined_arc2); 01110 } 01111 } 01112 } 01113 01114 static void RIG_removeUneededOffsets(RigGraph *rg) 01115 { 01116 RigArc *arc; 01117 01118 for (arc = rg->arcs.first; arc; arc = arc->next) 01119 { 01120 RigEdge *first_edge, *last_edge; 01121 01122 first_edge = arc->edges.first; 01123 last_edge = arc->edges.last; 01124 01125 if (first_edge->bone == NULL) 01126 { 01127 if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001) 01128 { 01129 BLI_remlink(&arc->edges, first_edge); 01130 MEM_freeN(first_edge); 01131 } 01132 else if (arc->head->degree == 1) 01133 { 01134 RigNode *new_node = (RigNode*)BLI_FindNodeByPosition((BGraph*)rg, first_edge->tail, 0.001); 01135 01136 if (new_node) 01137 { 01138 BLI_remlink(&arc->edges, first_edge); 01139 MEM_freeN(first_edge); 01140 BLI_replaceNodeInArc((BGraph*)rg, (BArc*)arc, (BNode*)new_node, (BNode*)arc->head); 01141 } 01142 else 01143 { 01144 RigEdge *next_edge = first_edge->next; 01145 01146 if (next_edge) 01147 { 01148 BLI_remlink(&arc->edges, first_edge); 01149 MEM_freeN(first_edge); 01150 01151 VECCOPY(arc->head->p, next_edge->head); 01152 } 01153 } 01154 } 01155 else 01156 { 01157 /* check if all arc connected start with a null edge */ 01158 RigArc *other_arc; 01159 for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) 01160 { 01161 if (other_arc != arc) 01162 { 01163 RigEdge *test_edge; 01164 if (other_arc->head == arc->head) 01165 { 01166 test_edge = other_arc->edges.first; 01167 01168 if (test_edge->bone != NULL) 01169 { 01170 break; 01171 } 01172 } 01173 else if (other_arc->tail == arc->head) 01174 { 01175 test_edge = other_arc->edges.last; 01176 01177 if (test_edge->bone != NULL) 01178 { 01179 break; 01180 } 01181 } 01182 } 01183 } 01184 01185 if (other_arc == NULL) 01186 { 01187 RigNode *new_node = (RigNode*)BLI_FindNodeByPosition((BGraph*)rg, first_edge->tail, 0.001); 01188 01189 if (new_node) 01190 { 01191 /* remove null edge in other arcs too */ 01192 for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) 01193 { 01194 if (other_arc != arc) 01195 { 01196 RigEdge *test_edge; 01197 if (other_arc->head == arc->head) 01198 { 01199 BLI_replaceNodeInArc((BGraph*)rg, (BArc*)other_arc, (BNode*)new_node, (BNode*)other_arc->head); 01200 test_edge = other_arc->edges.first; 01201 BLI_remlink(&other_arc->edges, test_edge); 01202 MEM_freeN(test_edge); 01203 } 01204 else if (other_arc->tail == arc->head) 01205 { 01206 BLI_replaceNodeInArc((BGraph*)rg, (BArc*)other_arc, (BNode*)new_node, (BNode*)other_arc->tail); 01207 test_edge = other_arc->edges.last; 01208 BLI_remlink(&other_arc->edges, test_edge); 01209 MEM_freeN(test_edge); 01210 } 01211 } 01212 } 01213 01214 BLI_remlink(&arc->edges, first_edge); 01215 MEM_freeN(first_edge); 01216 BLI_replaceNodeInArc((BGraph*)rg, (BArc*)arc, (BNode*)new_node, (BNode*)arc->head); 01217 } 01218 else 01219 { 01220 RigEdge *next_edge = first_edge->next; 01221 01222 if (next_edge) 01223 { 01224 BLI_remlink(&arc->edges, first_edge); 01225 MEM_freeN(first_edge); 01226 01227 VECCOPY(arc->head->p, next_edge->head); 01228 01229 /* remove null edge in other arcs too */ 01230 for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) 01231 { 01232 if (other_arc != arc) 01233 { 01234 RigEdge *test_edge; 01235 if (other_arc->head == arc->head) 01236 { 01237 test_edge = other_arc->edges.first; 01238 BLI_remlink(&other_arc->edges, test_edge); 01239 MEM_freeN(test_edge); 01240 } 01241 else if (other_arc->tail == arc->head) 01242 { 01243 test_edge = other_arc->edges.last; 01244 BLI_remlink(&other_arc->edges, test_edge); 01245 MEM_freeN(test_edge); 01246 } 01247 } 01248 } 01249 } 01250 } 01251 } 01252 } 01253 } 01254 01255 if (last_edge->bone == NULL) 01256 { 01257 if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001) 01258 { 01259 BLI_remlink(&arc->edges, last_edge); 01260 MEM_freeN(last_edge); 01261 } 01262 else if (arc->tail->degree == 1) 01263 { 01264 RigNode *new_node = (RigNode*)BLI_FindNodeByPosition((BGraph*)rg, last_edge->head, 0.001); 01265 01266 if (new_node) 01267 { 01268 RigEdge *previous_edge = last_edge->prev; 01269 01270 BLI_remlink(&arc->edges, last_edge); 01271 MEM_freeN(last_edge); 01272 BLI_replaceNodeInArc((BGraph*)rg, (BArc*)arc, (BNode*)new_node, (BNode*)arc->tail); 01273 01274 /* set previous angle to 0, since there's no following edges */ 01275 if (previous_edge) 01276 { 01277 previous_edge->angle = 0; 01278 } 01279 } 01280 else 01281 { 01282 RigEdge *previous_edge = last_edge->prev; 01283 01284 if (previous_edge) 01285 { 01286 BLI_remlink(&arc->edges, last_edge); 01287 MEM_freeN(last_edge); 01288 01289 VECCOPY(arc->tail->p, previous_edge->tail); 01290 previous_edge->angle = 0; 01291 } 01292 } 01293 } 01294 } 01295 } 01296 } 01297 01298 static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, int selected) 01299 { 01300 EditBone *bone, *last_bone = root_bone; 01301 RigArc *arc = NULL; 01302 int contain_head = 0; 01303 01304 for(bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) 01305 { 01306 int nb_children; 01307 01308 if (selected == 0 || (bone->flag & BONE_SELECTED)) 01309 { 01310 if ((bone->flag & BONE_NO_DEFORM) == 0) 01311 { 01312 BLI_ghash_insert(rg->bones_map, bone->name, bone); 01313 01314 if (arc == NULL) 01315 { 01316 arc = newRigArc(rg); 01317 01318 if (starting_node == NULL) 01319 { 01320 starting_node = newRigNodeHead(rg, arc, root_bone->head); 01321 } 01322 else 01323 { 01324 addRigNodeHead(rg, arc, starting_node); 01325 } 01326 } 01327 01328 if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) 01329 { 01330 RIG_addEdgeToArc(arc, bone->head, NULL); 01331 } 01332 01333 RIG_addEdgeToArc(arc, bone->tail, bone); 01334 01335 last_bone = bone; 01336 01337 if (strcmp(bone->name, "head") == 0) 01338 { 01339 contain_head = 1; 01340 } 01341 } 01342 else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) /* ignore locked bones */ 01343 { 01344 RIG_addControlBone(rg, bone); 01345 } 01346 } 01347 01348 nb_children = countEditBoneChildren(list, bone); 01349 if (nb_children > 1) 01350 { 01351 RigNode *end_node = NULL; 01352 int i; 01353 01354 if (arc != NULL) 01355 { 01356 end_node = newRigNodeTail(rg, arc, bone->tail); 01357 } 01358 else 01359 { 01360 end_node = newRigNode(rg, bone->tail); 01361 } 01362 01363 for (i = 0; i < nb_children; i++) 01364 { 01365 root_bone = nextEditBoneChild(list, bone, i); 01366 RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected); 01367 } 01368 01369 /* arc ends here, break */ 01370 break; 01371 } 01372 } 01373 01374 /* If the loop exited without forking */ 01375 if (arc != NULL && bone == NULL) 01376 { 01377 newRigNodeTail(rg, arc, last_bone->tail); 01378 } 01379 01380 if (contain_head) 01381 { 01382 rg->head = arc->tail; 01383 } 01384 } 01385 01386 /*******************************************************************************************************/ 01387 static void RIG_findHead(RigGraph *rg) 01388 { 01389 if (rg->head == NULL) 01390 { 01391 if (BLI_countlist(&rg->arcs) == 1) 01392 { 01393 RigArc *arc = rg->arcs.first; 01394 01395 rg->head = (RigNode*)arc->head; 01396 } 01397 else 01398 { 01399 RigArc *arc; 01400 01401 for (arc = rg->arcs.first; arc; arc = arc->next) 01402 { 01403 RigEdge *edge = arc->edges.last; 01404 01405 if (edge->bone->flag & (BONE_TIPSEL|BONE_SELECTED)) 01406 { 01407 rg->head = arc->tail; 01408 break; 01409 } 01410 } 01411 } 01412 01413 if (rg->head == NULL) 01414 { 01415 rg->head = rg->nodes.first; 01416 } 01417 } 01418 } 01419 01420 /*******************************************************************************************************/ 01421 01422 static void RIG_printNode(RigNode *node, const char name[]) 01423 { 01424 printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]); 01425 01426 if (node->symmetry_flag & SYM_TOPOLOGICAL) 01427 { 01428 if (node->symmetry_flag & SYM_AXIAL) 01429 printf("Symmetry AXIAL\n"); 01430 else if (node->symmetry_flag & SYM_RADIAL) 01431 printf("Symmetry RADIAL\n"); 01432 01433 print_v3("symmetry axis", node->symmetry_axis); 01434 } 01435 } 01436 01437 void RIG_printArcBones(RigArc *arc) 01438 { 01439 RigEdge *edge; 01440 01441 for (edge = arc->edges.first; edge; edge = edge->next) 01442 { 01443 if (edge->bone) 01444 printf("%s ", edge->bone->name); 01445 else 01446 printf("---- "); 01447 } 01448 printf("\n"); 01449 } 01450 01451 static void RIG_printCtrl(RigControl *ctrl, char *indent) 01452 { 01453 char text[128]; 01454 01455 printf("%sBone: %s\n", indent, ctrl->bone->name); 01456 printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!"); 01457 01458 sprintf(text, "%soffset", indent); 01459 print_v3(text, ctrl->offset); 01460 01461 printf("%sFlag: %i\n", indent, ctrl->flag); 01462 } 01463 01464 static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs) 01465 { 01466 RigControl *ctrl; 01467 char indent[64]; 01468 char *s = indent; 01469 int i; 01470 01471 for (i = 0; i < tabs; i++) 01472 { 01473 s[0] = '\t'; 01474 s++; 01475 } 01476 s[0] = 0; 01477 01478 for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) 01479 { 01480 if (ctrl->link == bone) 01481 { 01482 RIG_printCtrl(ctrl, indent); 01483 RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1); 01484 } 01485 } 01486 } 01487 01488 void RIG_printArc(RigGraph *rg, RigArc *arc) 01489 { 01490 RigEdge *edge; 01491 01492 RIG_printNode((RigNode*)arc->head, "head"); 01493 01494 for (edge = arc->edges.first; edge; edge = edge->next) 01495 { 01496 printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]); 01497 printf("\t\tlength %f\n", edge->length); 01498 printf("\t\tangle %f\n", edge->angle * 180 / M_PI); 01499 if (edge->bone) 01500 { 01501 printf("\t\t%s\n", edge->bone->name); 01502 RIG_printLinkedCtrl(rg, edge->bone, 3); 01503 } 01504 } 01505 printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); 01506 01507 RIG_printNode((RigNode*)arc->tail, "tail"); 01508 } 01509 01510 void RIG_printGraph(RigGraph *rg) 01511 { 01512 RigArc *arc; 01513 01514 printf("---- ARCS ----\n"); 01515 for (arc = rg->arcs.first; arc; arc = arc->next) 01516 { 01517 RIG_printArc(rg, arc); 01518 printf("\n"); 01519 } 01520 01521 if (rg->head) 01522 { 01523 RIG_printNode(rg->head, "HEAD NODE:"); 01524 } 01525 else 01526 { 01527 printf("HEAD NODE: NONE\n"); 01528 } 01529 } 01530 01531 /*******************************************************************************************************/ 01532 01533 RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm) 01534 { 01535 Object *obedit = CTX_data_edit_object(C); 01536 Scene *scene = CTX_data_scene(C); 01537 EditBone *ebone; 01538 RigGraph *rg; 01539 01540 rg = newRigGraph(); 01541 01542 if (obedit == ob) 01543 { 01544 rg->editbones = ((bArmature *)obedit->data)->edbo; 01545 } 01546 else 01547 { 01548 rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); 01549 make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); 01550 rg->flag |= RIG_FREE_BONELIST; 01551 } 01552 01553 rg->ob = ob; 01554 01555 /* Do the rotations */ 01556 for (ebone = rg->editbones->first; ebone; ebone=ebone->next){ 01557 if (ebone->parent == NULL) 01558 { 01559 RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0); 01560 } 01561 } 01562 01563 BLI_removeDoubleNodes((BGraph*)rg, 0.001); 01564 01565 RIG_removeNormalNodes(rg); 01566 01567 RIG_removeUneededOffsets(rg); 01568 01569 BLI_buildAdjacencyList((BGraph*)rg); 01570 01571 RIG_findHead(rg); 01572 01573 BLI_markdownSymmetry((BGraph*)rg, (BNode*)rg->head, scene->toolsettings->skgen_symmetry_limit); 01574 01575 RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ 01576 01577 if (BLI_isGraphCyclic((BGraph*)rg)) 01578 { 01579 printf("armature cyclic\n"); 01580 } 01581 01582 return rg; 01583 } 01584 01585 static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm) 01586 { 01587 Object *obedit = CTX_data_edit_object(C); 01588 Scene *scene = CTX_data_scene(C); 01589 EditBone *ebone; 01590 RigGraph *rg; 01591 01592 rg = newRigGraph(); 01593 01594 if (obedit == ob) 01595 { 01596 rg->editbones = arm->edbo; 01597 } 01598 else 01599 { 01600 rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); 01601 make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); 01602 rg->flag |= RIG_FREE_BONELIST; 01603 } 01604 01605 rg->ob = ob; 01606 01607 /* Do the rotations */ 01608 for (ebone = rg->editbones->first; ebone; ebone=ebone->next){ 01609 if (ebone->parent == NULL) 01610 { 01611 RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1); 01612 } 01613 } 01614 01615 BLI_removeDoubleNodes((BGraph*)rg, 0.001); 01616 01617 RIG_removeNormalNodes(rg); 01618 01619 RIG_removeUneededOffsets(rg); 01620 01621 BLI_buildAdjacencyList((BGraph*)rg); 01622 01623 RIG_findHead(rg); 01624 01625 BLI_markdownSymmetry((BGraph*)rg, (BNode*)rg->head, scene->toolsettings->skgen_symmetry_limit); 01626 01627 RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ 01628 01629 if (BLI_isGraphCyclic((BGraph*)rg)) 01630 { 01631 printf("armature cyclic\n"); 01632 } 01633 01634 return rg; 01635 } 01636 /************************************ GENERATING *****************************************************/ 01637 01638 #if 0 01639 static EditBone *add_editbonetolist(char *name, ListBase *list) 01640 { 01641 EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone"); 01642 01643 BLI_strncpy(bone->name, name, sizeof(bone->name)); 01644 unique_editbone_name(list, bone->name, NULL); 01645 01646 BLI_addtail(list, bone); 01647 01648 bone->flag |= BONE_TIPSEL; 01649 bone->weight= 1.0F; 01650 bone->dist= 0.25F; 01651 bone->xwidth= 0.1; 01652 bone->zwidth= 0.1; 01653 bone->ease1= 1.0; 01654 bone->ease2= 1.0; 01655 bone->rad_head= 0.10; 01656 bone->rad_tail= 0.05; 01657 bone->segments= 1; 01658 bone->layer= 1;//arm->layer; 01659 01660 return bone; 01661 } 01662 #endif 01663 01664 #if 0 /* UNUSED */ 01665 static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit) 01666 { 01667 while (node->multi_level > multi_level_limit && node->link_up) 01668 { 01669 node = node->link_up; 01670 } 01671 01672 while (node->multi_level < multi_level_limit && node->link_down) 01673 { 01674 node = node->link_down; 01675 } 01676 01677 if (node->multi_level == multi_level_limit) 01678 { 01679 int i; 01680 01681 for (i = 0; i < node->degree; i++) 01682 { 01683 ReebArc *earc = node->arcs[i]; 01684 01685 if (earc->flag == ARC_FREE && earc->head == node) 01686 { 01687 ReebNode *other = BIF_otherNodeFromIndex(earc, node); 01688 01689 earc->flag = ARC_USED; 01690 01691 //generateBonesForArc(rigg, earc, node, other); 01692 generateMissingArcsFromNode(rigg, other, multi_level_limit); 01693 } 01694 } 01695 } 01696 } 01697 01698 static void generateMissingArcs(RigGraph *rigg) 01699 { 01700 ReebGraph *reebg; 01701 int multi_level_limit = 5; 01702 01703 for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up) 01704 { 01705 ReebArc *earc; 01706 01707 for (earc = reebg->arcs.first; earc; earc = earc->next) 01708 { 01709 if (earc->flag == ARC_USED) 01710 { 01711 generateMissingArcsFromNode(rigg, earc->head, multi_level_limit); 01712 generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit); 01713 } 01714 } 01715 } 01716 } 01717 #endif 01718 01719 /************************************ RETARGETTING *****************************************************/ 01720 01721 static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize); 01722 01723 static void repositionTailControl(RigGraph *rigg, RigControl *ctrl); 01724 01725 static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize) 01726 { 01727 if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) 01728 { 01729 RigControl *ctrl_child; 01730 01731 #if 0 01732 printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name); 01733 01734 if (ctrl->link_tail) 01735 { 01736 printf(" TAIL: %s", ctrl->link_tail->name); 01737 } 01738 01739 printf("\n"); 01740 #endif 01741 01742 /* if there was a tail link: apply link, recalc resize factor and qrot */ 01743 if (ctrl->tail_mode != TL_NONE) 01744 { 01745 float *tail_vec = NULL; 01746 float v1[3], v2[3], qtail[4]; 01747 01748 if (ctrl->tail_mode == TL_TAIL) 01749 { 01750 tail_vec = ctrl->link_tail->tail; 01751 } 01752 else if (ctrl->tail_mode == TL_HEAD) 01753 { 01754 tail_vec = ctrl->link_tail->head; 01755 } 01756 01757 sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head); 01758 sub_v3_v3v3(v2, tail_vec, ctrl->bone->head); 01759 01760 VECCOPY(ctrl->bone->tail, tail_vec); 01761 01762 rotation_between_vecs_to_quat(qtail, v1, v2); 01763 mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot); 01764 01765 resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail); 01766 } 01767 01768 ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot); 01769 01770 /* Cascade to connected control bones */ 01771 for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) 01772 { 01773 if (ctrl_child->link == ctrl->bone) 01774 { 01775 repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize); 01776 } 01777 if (ctrl_child->link_tail == ctrl->bone) 01778 { 01779 repositionTailControl(rigg, ctrl_child); 01780 } 01781 } 01782 } 01783 } 01784 01785 static void repositionTailControl(RigGraph *rigg, RigControl *ctrl) 01786 { 01787 ctrl->flag |= RIG_CTRL_TAIL_DONE; 01788 01789 finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */ 01790 } 01791 01792 static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize) 01793 { 01794 float parent_offset[3], tail_offset[3]; 01795 01796 VECCOPY(parent_offset, ctrl->offset); 01797 mul_v3_fl(parent_offset, resize); 01798 mul_qt_v3(qrot, parent_offset); 01799 01800 add_v3_v3v3(ctrl->bone->head, head, parent_offset); 01801 01802 ctrl->flag |= RIG_CTRL_HEAD_DONE; 01803 01804 QUATCOPY(ctrl->qrot, qrot); 01805 01806 if (ctrl->tail_mode == TL_NONE) 01807 { 01808 sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head); 01809 mul_v3_fl(tail_offset, resize); 01810 mul_qt_v3(qrot, tail_offset); 01811 01812 add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset); 01813 01814 ctrl->flag |= RIG_CTRL_TAIL_DONE; 01815 } 01816 01817 finalizeControl(rigg, ctrl, resize); 01818 } 01819 01820 static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3]) 01821 { 01822 Scene *scene = CTX_data_scene(C); 01823 EditBone *bone; 01824 RigControl *ctrl; 01825 float qrot[4], resize; 01826 float v1[3], v2[3]; 01827 float l1, l2; 01828 01829 bone = edge->bone; 01830 01831 sub_v3_v3v3(v1, edge->tail, edge->head); 01832 sub_v3_v3v3(v2, vec1, vec0); 01833 01834 l1 = normalize_v3(v1); 01835 l2 = normalize_v3(v2); 01836 01837 resize = l2 / l1; 01838 01839 rotation_between_vecs_to_quat(qrot, v1, v2); 01840 01841 VECCOPY(bone->head, vec0); 01842 VECCOPY(bone->tail, vec1); 01843 01844 if (!is_zero_v3(up_axis)) 01845 { 01846 float qroll[4]; 01847 01848 if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) 01849 { 01850 bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis); 01851 } 01852 else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) 01853 { 01854 bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis); 01855 } 01856 else 01857 { 01858 unit_qt(qroll); 01859 } 01860 01861 mul_qt_qtqt(qrot, qroll, qrot); 01862 } 01863 else 01864 { 01865 bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot); 01866 } 01867 01868 for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) 01869 { 01870 if (ctrl->link == bone) 01871 { 01872 repositionControl(rigg, ctrl, vec0, vec1, qrot, resize); 01873 } 01874 if (ctrl->link_tail == bone) 01875 { 01876 repositionTailControl(rigg, ctrl); 01877 } 01878 } 01879 } 01880 01881 static RetargetMode detectArcRetargetMode(RigArc *arc); 01882 static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start); 01883 01884 01885 static RetargetMode detectArcRetargetMode(RigArc *iarc) 01886 { 01887 RetargetMode mode = RETARGET_AGGRESSIVE; 01888 ReebArc *earc = iarc->link_mesh; 01889 RigEdge *edge; 01890 int large_angle = 0; 01891 float avg_angle = 0; 01892 float avg_length = 0; 01893 int nb_edges = 0; 01894 01895 01896 for (edge = iarc->edges.first; edge; edge = edge->next) 01897 { 01898 avg_angle += edge->angle; 01899 nb_edges++; 01900 } 01901 01902 avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */ 01903 01904 avg_length = iarc->length / nb_edges; 01905 01906 01907 if (nb_edges > 2) 01908 { 01909 for (edge = iarc->edges.first; edge; edge = edge->next) 01910 { 01911 if (fabs(edge->angle - avg_angle) > M_PI / 6) 01912 { 01913 large_angle = 1; 01914 } 01915 } 01916 } 01917 else if (nb_edges == 2 && avg_angle > 0) 01918 { 01919 large_angle = 1; 01920 } 01921 01922 01923 if (large_angle == 0) 01924 { 01925 mode = RETARGET_LENGTH; 01926 } 01927 01928 if (earc->bcount <= (iarc->count - 1)) 01929 { 01930 mode = RETARGET_LENGTH; 01931 } 01932 01933 return mode; 01934 } 01935 01936 #ifndef USE_THREADS 01937 static void printMovesNeeded(int *positions, int nb_positions) 01938 { 01939 int moves = 0; 01940 int i; 01941 01942 for (i = 0; i < nb_positions; i++) 01943 { 01944 moves += positions[i] - (i + 1); 01945 } 01946 01947 printf("%i moves needed\n", moves); 01948 } 01949 01950 static void printPositions(int *positions, int nb_positions) 01951 { 01952 int i; 01953 01954 for (i = 0; i < nb_positions; i++) 01955 { 01956 printf("%i ", positions[i]); 01957 } 01958 printf("\n"); 01959 } 01960 #endif 01961 01962 #define MAX_COST FLT_MAX /* FIX ME */ 01963 01964 static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight) 01965 { 01966 EmbedBucket *bucket = NULL; 01967 float max_dist = 0; 01968 float v1[3], v2[3], c[3]; 01969 float v1_inpf; 01970 01971 if (distance_weight > 0) 01972 { 01973 sub_v3_v3v3(v1, vec0, vec1); 01974 01975 v1_inpf = dot_v3v3(v1, v1); 01976 01977 if (v1_inpf > 0) 01978 { 01979 int j; 01980 for (j = i0 + 1; j < i1 - 1; j++) 01981 { 01982 float dist; 01983 01984 bucket = IT_peek(iter, j); 01985 01986 sub_v3_v3v3(v2, bucket->p, vec1); 01987 01988 cross_v3_v3v3(c, v1, v2); 01989 01990 dist = dot_v3v3(c, c) / v1_inpf; 01991 01992 max_dist = dist > max_dist ? dist : max_dist; 01993 } 01994 01995 return distance_weight * max_dist; 01996 } 01997 else 01998 { 01999 return MAX_COST; 02000 } 02001 } 02002 else 02003 { 02004 return 0; 02005 } 02006 } 02007 02008 static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight) 02009 { 02010 if (angle_weight > 0) 02011 { 02012 float current_angle; 02013 02014 if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) 02015 { 02016 current_angle = saacos(dot_v3v3(vec_first, vec_second)); 02017 02018 return angle_weight * fabs(current_angle - original_angle); 02019 } 02020 else 02021 { 02022 return angle_weight * M_PI; 02023 } 02024 } 02025 else 02026 { 02027 return 0; 02028 } 02029 } 02030 02031 static float costLength(float original_length, float current_length, float length_weight) 02032 { 02033 if (current_length == 0) 02034 { 02035 return MAX_COST; 02036 } 02037 else 02038 { 02039 float length_ratio = fabs((current_length - original_length) / original_length); 02040 return length_weight * length_ratio * length_ratio; 02041 } 02042 } 02043 02044 #if 0 02045 static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2) 02046 { 02047 float vec[3]; 02048 float length; 02049 02050 sub_v3_v3v3(vec, vec2, vec1); 02051 length = normalize_v3(vec); 02052 02053 return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2); 02054 } 02055 #endif 02056 02057 static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2, float angle_weight, float length_weight, float distance_weight) 02058 { 02059 float vec_second[3], vec_first[3]; 02060 float length2; 02061 float new_cost = 0; 02062 02063 sub_v3_v3v3(vec_second, vec2, vec1); 02064 length2 = normalize_v3(vec_second); 02065 02066 02067 /* Angle cost */ 02068 if (edge->prev) 02069 { 02070 sub_v3_v3v3(vec_first, vec1, vec0); 02071 normalize_v3(vec_first); 02072 02073 new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight); 02074 } 02075 02076 /* Length cost */ 02077 new_cost += costLength(edge->length, length2, length_weight); 02078 02079 /* Distance cost */ 02080 new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight); 02081 02082 return new_cost; 02083 } 02084 02085 static int indexMemoNode(int nb_positions, int previous, int current, int joints_left) 02086 { 02087 return joints_left * nb_positions * nb_positions + current * nb_positions + previous; 02088 } 02089 02090 static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left) 02091 { 02092 int previous = 0, current = 0; 02093 int i = 0; 02094 02095 for (i = 0; joints_left > 0; joints_left--, i++) 02096 { 02097 MemoNode *node; 02098 node = table + indexMemoNode(nb_positions, previous, current, joints_left); 02099 02100 positions[i] = node->next; 02101 02102 previous = current; 02103 current = node->next; 02104 } 02105 } 02106 02107 static MemoNode * solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left, float angle_weight, float length_weight, float distance_weight) 02108 { 02109 MemoNode *node; 02110 int index = indexMemoNode(nb_positions, previous, current, joints_left); 02111 02112 node = table + index; 02113 02114 if (node->weight != 0) 02115 { 02116 return node; 02117 } 02118 else if (joints_left == 0) 02119 { 02120 float *vec0 = vec_cache[previous]; 02121 float *vec1 = vec_cache[current]; 02122 float *vec2 = vec_cache[nb_positions + 1]; 02123 02124 node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight); 02125 02126 return node; 02127 } 02128 else 02129 { 02130 MemoNode *min_node = NULL; 02131 float *vec0 = vec_cache[previous]; 02132 float *vec1 = vec_cache[current]; 02133 float min_weight= 0.0f; 02134 int min_next= 0; 02135 int next; 02136 02137 for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) 02138 { 02139 MemoNode *next_node; 02140 float *vec2 = vec_cache[next]; 02141 float weight = 0.0f; 02142 02143 /* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */ 02144 weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight); 02145 02146 if (weight >= MAX_COST) 02147 { 02148 continue; 02149 } 02150 02151 /* add node weight */ 02152 next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight); 02153 weight += next_node->weight; 02154 02155 if (min_node == NULL || weight < min_weight) 02156 { 02157 min_weight = weight; 02158 min_node = next_node; 02159 min_next = next; 02160 } 02161 } 02162 02163 if (min_node) 02164 { 02165 node->weight = min_weight; 02166 node->next = min_next; 02167 return node; 02168 } 02169 else 02170 { 02171 node->weight = MAX_COST; 02172 return node; 02173 } 02174 } 02175 02176 } 02177 02178 static int testFlipArc(RigArc *iarc, RigNode *inode_start) 02179 { 02180 ReebArc *earc = iarc->link_mesh; 02181 ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh); 02182 02183 /* no flip needed if both nodes are the same */ 02184 if ((enode_start == earc->head && inode_start == iarc->head) || (enode_start == earc->tail && inode_start == iarc->tail)) 02185 { 02186 return 0; 02187 } 02188 else 02189 { 02190 return 1; 02191 } 02192 } 02193 02194 static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) 02195 { 02196 ReebArcIterator arc_iter; 02197 BArcIterator *iter = (BArcIterator*)&arc_iter; 02198 RigEdge *edge; 02199 EmbedBucket *bucket = NULL; 02200 ReebNode *node_start, *node_end; 02201 ReebArc *earc = iarc->link_mesh; 02202 float angle_weight = 1.0; // GET FROM CONTEXT 02203 float length_weight = 1.0; 02204 float distance_weight = 1.0; 02205 float min_cost = FLT_MAX; 02206 float *vec0, *vec1; 02207 int *best_positions; 02208 int nb_edges = BLI_countlist(&iarc->edges); 02209 int nb_joints = nb_edges - 1; 02210 RetargetMethod method = METHOD_MEMOIZE; 02211 int i; 02212 02213 if (nb_joints > earc->bcount) 02214 { 02215 printf("NOT ENOUGH BUCKETS!\n"); 02216 return; 02217 } 02218 02219 best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions"); 02220 02221 if (testFlipArc(iarc, inode_start)) 02222 { 02223 node_start = earc->tail; 02224 node_end = earc->head; 02225 } 02226 else 02227 { 02228 node_start = earc->head; 02229 node_end = earc->tail; 02230 } 02231 02232 /* equal number of joints and potential position, just fill them in */ 02233 if (nb_joints == earc->bcount) 02234 { 02235 int i; 02236 02237 /* init with first values */ 02238 for (i = 0; i < nb_joints; i++) 02239 { 02240 best_positions[i] = i + 1; 02241 } 02242 } 02243 if (method == METHOD_MEMOIZE) 02244 { 02245 int nb_positions = earc->bcount; 02246 int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1); 02247 MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table"); 02248 MemoNode *result; 02249 float **positions_cache = MEM_callocN(sizeof(float*) * (nb_positions + 2), "positions cache"); 02250 int i; 02251 02252 positions_cache[0] = node_start->p; 02253 positions_cache[nb_positions + 1] = node_end->p; 02254 02255 initArcIterator(iter, earc, node_start); 02256 02257 for (i = 1; i <= nb_positions; i++) 02258 { 02259 EmbedBucket *bucket = IT_peek(iter, i); 02260 positions_cache[i] = bucket->p; 02261 } 02262 02263 result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight); 02264 02265 min_cost = result->weight; 02266 copyMemoPositions(best_positions, table, earc->bcount, nb_joints); 02267 02268 MEM_freeN(table); 02269 MEM_freeN(positions_cache); 02270 } 02271 02272 vec0 = node_start->p; 02273 initArcIterator(iter, earc, node_start); 02274 02275 #ifndef USE_THREADS 02276 printPositions(best_positions, nb_joints); 02277 printMovesNeeded(best_positions, nb_joints); 02278 printf("min_cost %f\n", min_cost); 02279 printf("buckets: %i\n", earc->bcount); 02280 #endif 02281 02282 /* set joints to best position */ 02283 for (edge = iarc->edges.first, i = 0; 02284 edge; 02285 edge = edge->next, i++) 02286 { 02287 float *no = NULL; 02288 if (i < nb_joints) 02289 { 02290 bucket = IT_peek(iter, best_positions[i]); 02291 vec1 = bucket->p; 02292 no = bucket->no; 02293 } 02294 else 02295 { 02296 vec1 = node_end->p; 02297 no = node_end->no; 02298 } 02299 02300 if (edge->bone) 02301 { 02302 repositionBone(C, rigg, edge, vec0, vec1, no); 02303 } 02304 02305 vec0 = vec1; 02306 } 02307 02308 MEM_freeN(best_positions); 02309 } 02310 02311 static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) 02312 { 02313 ReebArcIterator arc_iter; 02314 BArcIterator *iter = (BArcIterator*)&arc_iter; 02315 ReebArc *earc = iarc->link_mesh; 02316 ReebNode *node_start, *node_end; 02317 RigEdge *edge; 02318 EmbedBucket *bucket = NULL; 02319 float embedding_length = 0; 02320 float *vec0 = NULL; 02321 float *vec1 = NULL; 02322 float *previous_vec = NULL; 02323 02324 02325 if (testFlipArc(iarc, inode_start)) 02326 { 02327 node_start = (ReebNode*)earc->tail; 02328 node_end = (ReebNode*)earc->head; 02329 } 02330 else 02331 { 02332 node_start = (ReebNode*)earc->head; 02333 node_end = (ReebNode*)earc->tail; 02334 } 02335 02336 initArcIterator(iter, earc, node_start); 02337 02338 bucket = IT_next(iter); 02339 02340 vec0 = node_start->p; 02341 02342 while (bucket != NULL) 02343 { 02344 vec1 = bucket->p; 02345 02346 embedding_length += len_v3v3(vec0, vec1); 02347 02348 vec0 = vec1; 02349 bucket = IT_next(iter); 02350 } 02351 02352 embedding_length += len_v3v3(node_end->p, vec1); 02353 02354 /* fit bones */ 02355 initArcIterator(iter, earc, node_start); 02356 02357 bucket = IT_next(iter); 02358 02359 vec0 = node_start->p; 02360 previous_vec = vec0; 02361 vec1 = bucket->p; 02362 02363 for (edge = iarc->edges.first; edge; edge = edge->next) 02364 { 02365 float new_bone_length = edge->length / iarc->length * embedding_length; 02366 float *no = NULL; 02367 float length = 0; 02368 02369 while (bucket && new_bone_length > length) 02370 { 02371 length += len_v3v3(previous_vec, vec1); 02372 bucket = IT_next(iter); 02373 previous_vec = vec1; 02374 vec1 = bucket->p; 02375 no = bucket->no; 02376 } 02377 02378 if (bucket == NULL) 02379 { 02380 vec1 = node_end->p; 02381 no = node_end->no; 02382 } 02383 02384 /* no need to move virtual edges (space between unconnected bones) */ 02385 if (edge->bone) 02386 { 02387 repositionBone(C, rigg, edge, vec0, vec1, no); 02388 } 02389 02390 vec0 = vec1; 02391 previous_vec = vec1; 02392 } 02393 } 02394 02395 static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) 02396 { 02397 #ifdef USE_THREADS 02398 RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam"); 02399 02400 p->rigg = rigg; 02401 p->iarc = iarc; 02402 p->inode_start = inode_start; 02403 p->context = C; 02404 02405 BLI_insert_work(rigg->worker, p); 02406 #else 02407 RetargetParam p; 02408 02409 p.rigg = rigg; 02410 p.iarc = iarc; 02411 p.inode_start = inode_start; 02412 p.context = C; 02413 02414 exec_retargetArctoArc(&p); 02415 #endif 02416 } 02417 02418 void *exec_retargetArctoArc(void *param) 02419 { 02420 RetargetParam *p = (RetargetParam*)param; 02421 RigGraph *rigg = p->rigg; 02422 RigArc *iarc = p->iarc; 02423 bContext *C = p->context; 02424 RigNode *inode_start = p->inode_start; 02425 ReebArc *earc = iarc->link_mesh; 02426 02427 if (BLI_countlist(&iarc->edges) == 1) 02428 { 02429 RigEdge *edge = iarc->edges.first; 02430 02431 if (testFlipArc(iarc, inode_start)) 02432 { 02433 repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no); 02434 } 02435 else 02436 { 02437 repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no); 02438 } 02439 } 02440 else 02441 { 02442 RetargetMode mode = detectArcRetargetMode(iarc); 02443 02444 if (mode == RETARGET_AGGRESSIVE) 02445 { 02446 retargetArctoArcAggresive(C, rigg, iarc, inode_start); 02447 } 02448 else 02449 { 02450 retargetArctoArcLength(C, rigg, iarc, inode_start); 02451 } 02452 } 02453 02454 #ifdef USE_THREADS 02455 MEM_freeN(p); 02456 #endif 02457 02458 return NULL; 02459 } 02460 02461 static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node) 02462 { 02463 ReebNode *enode = top_node; 02464 ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); 02465 int ishape, eshape; 02466 02467 ishape = BLI_subtreeShape((BGraph*)rigg, (BNode*)inode, NULL, 0) % SHAPE_LEVELS; 02468 eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; 02469 02470 inode->link_mesh = enode; 02471 02472 while (ishape == eshape && enode->link_down) 02473 { 02474 inode->link_mesh = enode; 02475 02476 enode = enode->link_down; 02477 reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */ 02478 eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; 02479 } 02480 } 02481 02482 static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode) 02483 { 02484 int i; 02485 02486 for(i = 0; i < enode->degree; i++) 02487 { 02488 ReebArc *earc = (ReebArc*)enode->arcs[i]; 02489 02490 if (earc->flag == ARC_FREE) 02491 { 02492 earc->flag = ARC_TAKEN; 02493 02494 if (earc->tail->degree > 1 && earc->tail != end_enode) 02495 { 02496 markMultiResolutionChildArc(end_enode, earc->tail); 02497 } 02498 break; 02499 } 02500 } 02501 } 02502 02503 static void markMultiResolutionArc(ReebArc *start_earc) 02504 { 02505 if (start_earc->link_up) 02506 { 02507 ReebArc *earc; 02508 for (earc = start_earc->link_up ; earc; earc = earc->link_up) 02509 { 02510 earc->flag = ARC_TAKEN; 02511 02512 if (earc->tail->index != start_earc->tail->index) 02513 { 02514 markMultiResolutionChildArc(earc->tail, earc->tail); 02515 } 02516 } 02517 } 02518 } 02519 02520 static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc) 02521 { 02522 ReebNode *enode = next_earc->head; 02523 ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); 02524 int ishape, eshape; 02525 02526 ishape = BLI_subtreeShape((BGraph*)rigg, (BNode*)start_node, (BArc*)next_iarc, 1) % SHAPE_LEVELS; 02527 eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, (BArc*)next_earc, 1) % SHAPE_LEVELS; 02528 02529 while (ishape != eshape && next_earc->link_up) 02530 { 02531 next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels 02532 02533 next_earc = next_earc->link_up; 02534 reebg = reebg->link_up; 02535 enode = next_earc->head; 02536 eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, (BArc*)next_earc, 1) % SHAPE_LEVELS; 02537 } 02538 02539 next_earc->flag = ARC_USED; 02540 next_iarc->link_mesh = next_earc; 02541 02542 /* mark all higher levels as taken too */ 02543 markMultiResolutionArc(next_earc); 02544 // while (next_earc->link_up) 02545 // { 02546 // next_earc = next_earc->link_up; 02547 // next_earc->flag = ARC_TAKEN; 02548 // } 02549 } 02550 02551 static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode) 02552 { 02553 ReebNode *enode; 02554 int ishape, eshape; 02555 02556 enode = reebg->nodes.first; 02557 02558 ishape = BLI_subtreeShape((BGraph*)rigg, (BNode*)inode, NULL, 0) % SHAPE_LEVELS; 02559 eshape = BLI_subtreeShape((BGraph*)rigg->link_mesh, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; 02560 02561 while (ishape != eshape && reebg->link_up) 02562 { 02563 reebg = reebg->link_up; 02564 02565 enode = reebg->nodes.first; 02566 02567 eshape = BLI_subtreeShape((BGraph*)reebg, (BNode*)enode, NULL, 0) % SHAPE_LEVELS; 02568 } 02569 02570 inode->link_mesh = enode; 02571 } 02572 02573 static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root) 02574 { 02575 ReebNode *enode = start_node->link_mesh; 02576 ReebArc *next_earc; 02577 int symmetry_level = next_iarc->symmetry_level; 02578 int symmetry_group = next_iarc->symmetry_group; 02579 int symmetry_flag = next_iarc->symmetry_flag; 02580 int i; 02581 02582 next_iarc->link_mesh = NULL; 02583 02584 // if (root) 02585 // { 02586 // printf("-----------------------\n"); 02587 // printf("MATCHING LIMB\n"); 02588 // RIG_printArcBones(next_iarc); 02589 // } 02590 02591 for(i = 0; i < enode->degree; i++) 02592 { 02593 next_earc = (ReebArc*)enode->arcs[i]; 02594 02595 // if (next_earc->flag == ARC_FREE) 02596 // { 02597 // printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n", 02598 // symmetry_level, next_earc->symmetry_level, 02599 // symmetry_flag, next_earc->symmetry_flag, 02600 // symmetry_group, next_earc->symmetry_flag); 02601 // } 02602 02603 if (next_earc->flag == ARC_FREE && 02604 next_earc->symmetry_flag == symmetry_flag && 02605 next_earc->symmetry_group == symmetry_group && 02606 next_earc->symmetry_level == symmetry_level) 02607 { 02608 // printf("CORRESPONDING ARC FOUND\n"); 02609 // 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); 02610 02611 matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); 02612 break; 02613 } 02614 } 02615 02616 /* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */ 02617 if (next_iarc->link_mesh == NULL) 02618 { 02619 // printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n"); 02620 02621 if (enode->link_up) 02622 { 02623 start_node->link_mesh = enode->link_up; 02624 findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0); 02625 } 02626 } 02627 02628 /* still not found, print debug info */ 02629 if (root && next_iarc->link_mesh == NULL) 02630 { 02631 start_node->link_mesh = enode; /* linking back with root node */ 02632 02633 // printf("NO CORRESPONDING ARC FOUND\n"); 02634 // RIG_printArcBones(next_iarc); 02635 // 02636 // printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level); 02637 // 02638 // printf("LOOKING FOR\n"); 02639 // printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group); 02640 // 02641 // printf("CANDIDATES\n"); 02642 // for(i = 0; i < enode->degree; i++) 02643 // { 02644 // next_earc = (ReebArc*)enode->arcs[i]; 02645 // 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); 02646 // } 02647 02648 /* Emergency matching */ 02649 for(i = 0; i < enode->degree; i++) 02650 { 02651 next_earc = (ReebArc*)enode->arcs[i]; 02652 02653 if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) 02654 { 02655 // printf("USING: \n"); 02656 // 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); 02657 matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); 02658 break; 02659 } 02660 } 02661 } 02662 02663 } 02664 02665 static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node) 02666 { 02667 RigNode *inode = start_node; 02668 int i; 02669 02670 /* no start arc on first node */ 02671 if (start_arc) 02672 { 02673 ReebNode *enode = start_node->link_mesh; 02674 ReebArc *earc = start_arc->link_mesh; 02675 02676 retargetArctoArc(C, rigg, start_arc, start_node); 02677 02678 enode = BIF_otherNodeFromIndex(earc, enode); 02679 inode = (RigNode*)BLI_otherNode((BArc*)start_arc, (BNode*)inode); 02680 02681 /* match with lowest node with correct shape */ 02682 matchMultiResolutionNode(rigg, inode, enode); 02683 } 02684 02685 for(i = 0; i < inode->degree; i++) 02686 { 02687 RigArc *next_iarc = (RigArc*)inode->arcs[i]; 02688 02689 /* no back tracking */ 02690 if (next_iarc != start_arc) 02691 { 02692 findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1); 02693 if (next_iarc->link_mesh) 02694 { 02695 retargetSubgraph(C, rigg, next_iarc, inode); 02696 } 02697 } 02698 } 02699 } 02700 02701 static void finishRetarget(RigGraph *rigg) 02702 { 02703 #ifdef USE_THREADS 02704 BLI_end_worker(rigg->worker); 02705 #endif 02706 } 02707 02708 static void adjustGraphs(bContext *C, RigGraph *rigg) 02709 { 02710 bArmature *arm= rigg->ob->data; 02711 RigArc *arc; 02712 02713 for (arc = rigg->arcs.first; arc; arc = arc->next) 02714 { 02715 if (arc->link_mesh) 02716 { 02717 retargetArctoArc(C, rigg, arc, arc->head); 02718 } 02719 } 02720 02721 finishRetarget(rigg); 02722 02723 /* Turn the list into an armature */ 02724 arm->edbo = rigg->editbones; 02725 ED_armature_from_edit(rigg->ob); 02726 02727 ED_undo_push(C, "Retarget Skeleton"); 02728 } 02729 02730 static void retargetGraphs(bContext *C, RigGraph *rigg) 02731 { 02732 bArmature *arm= rigg->ob->data; 02733 ReebGraph *reebg = rigg->link_mesh; 02734 RigNode *inode; 02735 02736 /* flag all ReebArcs as free */ 02737 BIF_flagMultiArcs(reebg, ARC_FREE); 02738 02739 /* return to first level */ 02740 inode = rigg->head; 02741 02742 matchMultiResolutionStartingNode(rigg, reebg, inode); 02743 02744 retargetSubgraph(C, rigg, NULL, inode); 02745 02746 //generateMissingArcs(rigg); 02747 02748 finishRetarget(rigg); 02749 02750 /* Turn the list into an armature */ 02751 arm->edbo = rigg->editbones; 02752 ED_armature_from_edit(rigg->ob); 02753 } 02754 02755 const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index) 02756 { 02757 RigArc *arc = BLI_findlink(&rg->arcs, arc_index); 02758 RigEdge *iedge; 02759 02760 if (arc == NULL) 02761 { 02762 return "None"; 02763 } 02764 02765 if (bone_index == BLI_countlist(&arc->edges)) 02766 { 02767 return "Last joint"; 02768 } 02769 02770 iedge = BLI_findlink(&arc->edges, bone_index); 02771 02772 if (iedge == NULL) 02773 { 02774 return "Done"; 02775 } 02776 02777 if (iedge->bone == NULL) 02778 { 02779 return "Bone offset"; 02780 } 02781 02782 return iedge->bone->name; 02783 } 02784 02785 int RIG_nbJoints(RigGraph *rg) 02786 { 02787 RigArc *arc; 02788 int total = 0; 02789 02790 total += BLI_countlist(&rg->nodes); 02791 02792 for (arc = rg->arcs.first; arc; arc = arc->next) 02793 { 02794 total += BLI_countlist(&arc->edges) - 1; /* -1 because end nodes are already counted */ 02795 } 02796 02797 return total; 02798 } 02799 02800 static void BIF_freeRetarget(void) 02801 { 02802 if (GLOBAL_RIGG) 02803 { 02804 RIG_freeRigGraph((BGraph*)GLOBAL_RIGG); 02805 GLOBAL_RIGG = NULL; 02806 } 02807 } 02808 02809 void BIF_retargetArmature(bContext *C) 02810 { 02811 ReebGraph *reebg; 02812 double start_time, end_time; 02813 double gstart_time, gend_time; 02814 double reeb_time, rig_time=0.0, retarget_time=0.0, total_time; 02815 02816 gstart_time = start_time = PIL_check_seconds_timer(); 02817 02818 reebg = BIF_ReebGraphMultiFromEditMesh(C); 02819 02820 end_time = PIL_check_seconds_timer(); 02821 reeb_time = end_time - start_time; 02822 02823 printf("Reeb Graph created\n"); 02824 02825 CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { 02826 Object *ob = base->object; 02827 02828 if (ob->type==OB_ARMATURE) 02829 { 02830 RigGraph *rigg; 02831 bArmature *arm; 02832 02833 arm = ob->data; 02834 02835 /* Put the armature into editmode */ 02836 02837 02838 start_time = PIL_check_seconds_timer(); 02839 02840 rigg = RIG_graphFromArmature(C, ob, arm); 02841 02842 end_time = PIL_check_seconds_timer(); 02843 rig_time = end_time - start_time; 02844 02845 printf("Armature graph created\n"); 02846 02847 //RIG_printGraph(rigg); 02848 02849 rigg->link_mesh = reebg; 02850 02851 printf("retargetting %s\n", ob->id.name); 02852 02853 start_time = PIL_check_seconds_timer(); 02854 02855 retargetGraphs(C, rigg); 02856 02857 end_time = PIL_check_seconds_timer(); 02858 retarget_time = end_time - start_time; 02859 02860 BIF_freeRetarget(); 02861 02862 GLOBAL_RIGG = rigg; 02863 02864 break; /* only one armature at a time */ 02865 } 02866 } 02867 CTX_DATA_END; 02868 02869 02870 gend_time = PIL_check_seconds_timer(); 02871 02872 total_time = gend_time - gstart_time; 02873 02874 printf("-----------\n"); 02875 printf("runtime: \t%.3f\n", total_time); 02876 printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100); 02877 printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100); 02878 printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100); 02879 printf("-----------\n"); 02880 02881 ED_undo_push(C, "Retarget Skeleton"); 02882 02883 // XXX 02884 // allqueue(REDRAWVIEW3D, 0); 02885 } 02886 02887 void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg) 02888 { 02889 Object *obedit = CTX_data_edit_object(C); 02890 Scene *scene = CTX_data_scene(C); 02891 bArmature *armedit = obedit->data; 02892 Object *ob; 02893 RigGraph *rigg; 02894 RigArc *iarc; 02895 char *side_string = scene->toolsettings->skgen_side_string; 02896 char *num_string = scene->toolsettings->skgen_num_string; 02897 int free_template = 0; 02898 02899 if (template_rigg) 02900 { 02901 ob = template_rigg->ob; 02902 } 02903 else 02904 { 02905 free_template = 1; 02906 ob = obedit; 02907 template_rigg = armatureSelectedToGraph(C, ob, ob->data); 02908 } 02909 02910 if (template_rigg->arcs.first == NULL) 02911 { 02912 // XXX 02913 // error("No Template and no deforming bones selected"); 02914 return; 02915 } 02916 02917 rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string); 02918 02919 iarc = rigg->arcs.first; 02920 02921 iarc->link_mesh = earc; 02922 iarc->head->link_mesh = earc->head; 02923 iarc->tail->link_mesh = earc->tail; 02924 02925 retargetArctoArc(C, rigg, iarc, iarc->head); 02926 02927 finishRetarget(rigg); 02928 02929 /* free template if it comes from the edit armature */ 02930 if (free_template) 02931 { 02932 RIG_freeRigGraph((BGraph*)template_rigg); 02933 } 02934 RIG_freeRigGraph((BGraph*)rigg); 02935 02936 ED_armature_validate_active(armedit); 02937 02938 // XXX 02939 // allqueue(REDRAWVIEW3D, 0); 02940 } 02941 02942 void BIF_adjustRetarget(bContext *C) 02943 { 02944 if (GLOBAL_RIGG) 02945 { 02946 adjustGraphs(C, GLOBAL_RIGG); 02947 } 02948 }