383
382
/* ************* B-Bone support ******************* */
385
#define MAX_BBONE_SUBDIV 32
384
#define MAX_BBONE_SUBDIV 32
387
386
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
388
387
static void equalize_bezier(float *data, int desired)
390
389
float *fp, totdist, ddist, dist, fac1, fac2;
391
float pdist[MAX_BBONE_SUBDIV+1];
392
float temp[MAX_BBONE_SUBDIV+1][4];
390
float pdist[MAX_BBONE_SUBDIV + 1];
391
float temp[MAX_BBONE_SUBDIV + 1][4];
396
395
for (a = 0, fp = data; a < MAX_BBONE_SUBDIV; a++, fp += 4) {
397
396
copy_qt_qt(temp[a], fp);
398
pdist[a+1] = pdist[a] + len_v3v3(fp, fp+4);
397
pdist[a + 1] = pdist[a] + len_v3v3(fp, fp + 4);
400
399
/* do last point */
401
400
copy_qt_qt(temp[a], fp);
402
401
totdist = pdist[a];
404
403
/* go over distances and calculate new points */
405
ddist = totdist/((float)desired);
404
ddist = totdist / ((float)desired);
407
for (a = 1, fp = data+4; a < desired; a++, fp += 4) {
408
dist = ((float)a)*ddist;
406
for (a = 1, fp = data + 4; a < desired; a++, fp += 4) {
407
dist = ((float)a) * ddist;
410
409
/* we're looking for location (distance) 'dist' in the array */
411
410
while ((dist >= pdist[nr]) && nr < MAX_BBONE_SUBDIV)
414
fac1 = pdist[nr] - pdist[nr-1];
413
fac1 = pdist[nr] - pdist[nr - 1];
415
414
fac2 = pdist[nr] - dist;
416
415
fac1 = fac2 / fac1;
417
416
fac2 = 1.0f - fac1;
419
fp[0] = fac1*temp[nr-1][0] + fac2*temp[nr][0];
420
fp[1] = fac1*temp[nr-1][1] + fac2*temp[nr][1];
421
fp[2] = fac1*temp[nr-1][2] + fac2*temp[nr][2];
422
fp[3] = fac1*temp[nr-1][3] + fac2*temp[nr][3];
418
fp[0] = fac1 * temp[nr - 1][0] + fac2 * temp[nr][0];
419
fp[1] = fac1 * temp[nr - 1][1] + fac2 * temp[nr][1];
420
fp[2] = fac1 * temp[nr - 1][2] + fac2 * temp[nr][2];
421
fp[3] = fac1 * temp[nr - 1][3] + fac2 * temp[nr][3];
424
423
/* set last point, needed for orientation calculus */
425
424
copy_qt_qt(fp, temp[MAX_BBONE_SUBDIV]);
566
567
if (bone->segments > MAX_BBONE_SUBDIV)
567
568
bone->segments = MAX_BBONE_SUBDIV;
569
forward_diff_bezier(0.0, h1[0], h2[0], 0.0, data[0],
570
MAX_BBONE_SUBDIV, 4*sizeof(float));
571
forward_diff_bezier(0.0, h1[1], length + h2[1], length, data[0]+1,
572
MAX_BBONE_SUBDIV, 4*sizeof(float));
573
forward_diff_bezier(0.0, h1[2], h2[2], 0.0, data[0]+2,
574
MAX_BBONE_SUBDIV, 4*sizeof(float));
575
forward_diff_bezier(roll1, roll1 + 0.390464f*(roll2-roll1), roll2 - 0.390464f*(roll2-roll1), roll2, data[0]+3,
576
MAX_BBONE_SUBDIV, 4*sizeof(float));
570
BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
571
BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
572
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
573
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
578
575
equalize_bezier(data[0], bone->segments); /* note: does stride 4! */
580
577
/* make transformation matrices for the segments for drawing */
581
578
for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
582
sub_v3_v3v3(h1, fp+4, fp);
579
sub_v3_v3v3(h1, fp + 4, fp);
583
580
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
585
582
copy_m4_m3(result_array[a].mat, mat3);
586
583
copy_v3_v3(result_array[a].mat[3], fp);
589
586
/* correct for scaling when this matrix is used in scaled space */
590
587
mul_serie_m4(result_array[a].mat, iscalemat, result_array[a].mat, scalemat, NULL, NULL, NULL, NULL, NULL);
1230
1227
mult_m4_m4m4(loc_mat, bone_loc, tmat4);
1232
1229
/* Those flags do not affect position, use plain parent transform space! */
1233
else if (bone->flag & (BONE_HINGE|BONE_NO_SCALE)) {
1230
else if (bone->flag & (BONE_HINGE | BONE_NO_SCALE)) {
1234
1231
mult_m4_m4m4(loc_mat, parchan->pose_mat, offs_bone);
1236
1233
/* Else (i.e. default, usual case), just use the same matrix for rotation/scaling, and location. */
1238
1235
copy_m4_m4(loc_mat, rotscale_mat);
1241
/* Compose the loc matrix for this bone. */
1242
/* NOTE: That version modifies bone's loc when HINGE/NO_SCALE options are set. */
1244
/* In these cases we need to compute location separately */
1245
if (bone->flag & (BONE_HINGE|BONE_NO_SCALE|BONE_NO_LOCAL_LOCATION)) {
1246
float bone_loc[4][4], bone_rotscale[3][3], tmat4[4][4], tmat3[3][3];
1251
mul_v3_m4v3(bone_loc[3], parchan->pose_mat, offs_bone[3]);
1253
/* "No local location" is not transformed by bone matrix. */
1254
/* This only affects orientations (rotations), as scale is always 1.0 here. */
1255
if (bone->flag & BONE_NO_LOCAL_LOCATION)
1256
unit_m3(bone_rotscale);
1258
/* We could also use bone->bone_mat directly, here... */
1259
copy_m3_m4(bone_rotscale, offs_bone);
1261
if (bone->flag & BONE_HINGE) {
1262
copy_m3_m4(tmat3, parbone->arm_mat);
1263
/* for hinge-only, we use armature *rotation*, but pose mat *scale*! */
1264
if (!(bone->flag & BONE_NO_SCALE)) {
1265
float size[3], tsmat[3][3];
1266
mat4_to_size(size, parchan->pose_mat);
1267
size_to_mat3(tsmat, size);
1268
mul_m3_m3m3(tmat3, tsmat, tmat3);
1270
mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale);
1272
else if (bone->flag & BONE_NO_SCALE) {
1273
/* For no-scale only, normalized parent pose mat is enough! */
1274
copy_m3_m4(tmat3, parchan->pose_mat);
1275
normalize_m3(tmat3);
1276
mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale);
1278
/* NO_LOCAL_LOCATION only. */
1280
copy_m3_m4(tmat3, parchan->pose_mat);
1281
mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale);
1284
copy_m4_m3(tmat4, bone_rotscale);
1285
mult_m4_m4m4(loc_mat, bone_loc, tmat4);
1287
/* Else, just use the same matrix for rotation/scaling, and location. */
1289
copy_m4_m4(loc_mat, rotscale_mat);
1292
1237
/* Root bones. */
1348
1293
copy_v3_v3(xLocMat[3], inloc);
1350
1295
/* get bone-space cursor matrix and extract location */
1351
armature_mat_pose_to_bone(pchan, xLocMat, nLocMat);
1296
BKE_armature_mat_pose_to_bone(pchan, xLocMat, nLocMat);
1352
1297
copy_v3_v3(outloc, nLocMat[3]);
1355
void armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[][4], float outmat[][4])
1300
void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
1357
1302
bPoseChannel work_pchan = *pchan;
1359
1304
/* recalculate pose matrix with only parent transformations,
1360
1305
* bone loc/sca/rot is ignored, scene and frame are not used. */
1361
where_is_pose_bone(NULL, ob, &work_pchan, 0.0f, FALSE);
1306
BKE_pose_where_is_bone(NULL, ob, &work_pchan, 0.0f, FALSE);
1363
1308
/* find the matrix, need to remove the bone transforms first so this is
1364
1309
* calculated as a matrix to set rather then a difference ontop of whats
1365
1310
* already there. */
1366
1311
unit_m4(outmat);
1367
pchan_apply_mat4(&work_pchan, outmat, FALSE);
1312
BKE_pchan_apply_mat4(&work_pchan, outmat, FALSE);
1369
armature_mat_pose_to_bone(&work_pchan, inmat, outmat);
1314
BKE_armature_mat_pose_to_bone(&work_pchan, inmat, outmat);
1372
/* same as object_mat3_to_rot() */
1373
void pchan_mat3_to_rot(bPoseChannel *pchan, float mat[][3], short use_compat)
1317
/* same as BKE_object_mat3_to_rot() */
1318
void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, float mat[3][3], short use_compat)
1375
switch(pchan->rotmode) {
1320
switch (pchan->rotmode) {
1376
1321
case ROT_MODE_QUAT:
1377
1322
mat3_to_quat(pchan->quat, mat);
1632
1578
/* clear all transformation values from library */
1633
rest_pose(frompose);
1579
BKE_pose_rest(frompose);
1635
1581
/* copy over all of the proxy's bone groups */
1637
* - implement 'local' bone groups as for constraints
1638
* Note: this isn't trivial, as bones reference groups by index not by pointer,
1639
* so syncing things correctly needs careful attention */
1583
* - implement 'local' bone groups as for constraints
1584
* Note: this isn't trivial, as bones reference groups by index not by pointer,
1585
* so syncing things correctly needs careful attention */
1640
1586
BLI_freelistN(&pose->agroups);
1641
1587
BLI_duplicatelist(&pose->agroups, &frompose->agroups);
1642
1588
pose->active_group = frompose->active_group;
1644
1590
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
1645
pchanp = get_pose_channel(frompose, pchan->name);
1647
if (pchan->bone->layer & layer_protected) {
1591
pchanp = BKE_pose_channel_find_name(frompose, pchan->name);
1593
if (UNLIKELY(pchanp == NULL)) {
1594
/* happens for proxies that become invalid because of a missing link
1595
* for regular cases it shouldn't happen at all */
1597
else if (pchan->bone->layer & layer_protected) {
1648
1598
ListBase proxylocal_constraints = {NULL, NULL};
1599
bPoseChannel pchanw = {NULL};
1650
1601
/* copy posechannel to temp, but restore important pointers */
1651
1602
pchanw = *pchanp;
1652
1603
pchanw.prev = pchan->prev;
1653
1604
pchanw.next = pchan->next;
1654
1605
pchanw.parent = pchan->parent;
1655
1606
pchanw.child = pchan->child;
1657
1608
/* this is freed so copy a copy, else undo crashes */
1658
1609
if (pchanw.prop) {
1659
1610
pchanw.prop = IDP_CopyProperty(pchanw.prop);
1661
1612
/* use the values from the the existing props */
1662
1613
if (pchan->prop) {
1663
1614
IDP_SyncGroupValues(pchanw.prop, pchan->prop);
1667
1618
/* constraints - proxy constraints are flushed... local ones are added after
1668
1619
* 1. extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints
1669
1620
* 2. copy proxy-pchan's constraints on-to new
1670
1621
* 3. add extracted local constraints back on top
1672
* Note for copy_constraints: when copying constraints, disable 'do_extern' otherwise
1673
* we get the libs direct linked in this blend. */
1674
extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints);
1675
copy_constraints(&pchanw.constraints, &pchanp->constraints, FALSE);
1623
* Note for BKE_copy_constraints: when copying constraints, disable 'do_extern' otherwise
1624
* we get the libs direct linked in this blend.
1626
BKE_extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints);
1627
BKE_copy_constraints(&pchanw.constraints, &pchanp->constraints, FALSE);
1676
1628
BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints);
1678
1630
/* constraints - set target ob pointer to own object */
1679
1631
for (con = pchanw.constraints.first; con; con = con->next) {
1680
bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
1632
bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
1681
1633
ListBase targets = {NULL, NULL};
1682
1634
bConstraintTarget *ct;
1684
1636
if (cti && cti->get_constraint_targets) {
1685
1637
cti->get_constraint_targets(con, &targets);
1687
1639
for (ct = targets.first; ct; ct = ct->next) {
1688
1640
if (ct->tar == from)
1692
1644
if (cti->flush_constraint_targets)
1693
1645
cti->flush_constraint_targets(con, &targets, 0);
1697
1649
/* free stuff from current channel */
1698
free_pose_channel(pchan);
1700
/* the final copy */
1650
BKE_pose_channel_free(pchan);
1652
/* copy data in temp back over to the cleaned-out (but still allocated) original channel */
1701
1653
*pchan = pchanw;
1704
1656
/* always copy custom shape */
1705
1657
pchan->custom = pchanp->custom;
1706
pchan->custom_tx = pchanp->custom_tx;
1658
if (pchanp->custom_tx)
1659
pchan->custom_tx = BKE_pose_channel_find_name(pose, pchanp->custom_tx->name);
1708
1661
/* ID-Property Syncing */
2299
2260
bActionModifier *amod;
2300
2261
bActionStrip *strip, *strip2;
2301
float scene_cfra= (float)scene->r.cfra;
2262
float scene_cfra = BKE_scene_frame_get(scene);
2304
for (strip=armob->nlastrips.first; strip; strip=strip->next) {
2265
for (strip = armob->nlastrips.first; strip; strip = strip->next) {
2307
if (scene_cfra>=strip->start && scene_cfra<=strip->end)
2268
if (scene_cfra >= strip->start && scene_cfra <= strip->end)
2310
2271
if ((scene_cfra > strip->end) && (strip->flag & ACTSTRIP_HOLDLASTFRAME)) {
2313
2274
/* if there are any other strips active, ignore modifiers for this strip -
2314
2275
* 'hold' option should only hold action modifiers if there are
2315
2276
* no other active strips */
2316
for (strip2=strip->next; strip2; strip2=strip2->next) {
2277
for (strip2 = strip->next; strip2; strip2 = strip2->next) {
2317
2278
if (strip2 == strip) continue;
2319
if (scene_cfra>=strip2->start && scene_cfra<=strip2->end) {
2280
if (scene_cfra >= strip2->start && scene_cfra <= strip2->end) {
2320
2281
if (!(strip2->flag & ACTSTRIP_MUTE))
2325
2286
/* if there are any later, activated, strips with 'hold' set, they take precedence,
2326
2287
* so ignore modifiers for this strip */
2327
for (strip2=strip->next; strip2; strip2=strip2->next) {
2288
for (strip2 = strip->next; strip2; strip2 = strip2->next) {
2328
2289
if (scene_cfra < strip2->start) continue;
2329
2290
if ((strip2->flag & ACTSTRIP_HOLDLASTFRAME) && !(strip2->flag & ACTSTRIP_MUTE)) {
2335
2296
if (do_modif) {
2336
2297
/* temporal solution to prevent 2 strips accumulating */
2337
if (scene_cfra==strip->end && strip->next && strip->next->start==scene_cfra)
2298
if (scene_cfra == strip->end && strip->next && strip->next->start == scene_cfra)
2340
for (amod= strip->modifiers.first; amod; amod= amod->next) {
2301
for (amod = strip->modifiers.first; amod; amod = amod->next) {
2341
2302
switch (amod->type) {
2342
case ACTSTRIP_MOD_DEFORM:
2344
/* validate first */
2345
if (amod->ob && amod->ob->type==OB_CURVE && amod->channel[0]) {
2347
if ( strcmp(pchan->name, amod->channel)==0 ) {
2348
float mat4[4][4], mat3[3][3];
2350
curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
2351
copy_m4_m4(mat4, pchan->pose_mat);
2352
mul_m4_m3m4(pchan->pose_mat, mat3, mat4);
2303
case ACTSTRIP_MOD_DEFORM:
2305
/* validate first */
2306
if (amod->ob && amod->ob->type == OB_CURVE && amod->channel[0]) {
2308
if (strcmp(pchan->name, amod->channel) == 0) {
2309
float mat4[4][4], mat3[3][3];
2311
curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
2312
copy_m4_m4(mat4, pchan->pose_mat);
2313
mul_m4_m3m4(pchan->pose_mat, mat3, mat4);
2358
case ACTSTRIP_MOD_NOISE:
2360
if ( strcmp(pchan->name, amod->channel)==0 ) {
2361
float nor[3], loc[3], ofs;
2362
float eul[3], size[3], eulo[3], sizeo[3];
2364
/* calculate turbulance */
2365
ofs = amod->turbul / 200.0f;
2367
/* make a copy of starting conditions */
2368
copy_v3_v3(loc, pchan->pose_mat[3]);
2369
mat4_to_eul( eul,pchan->pose_mat);
2370
mat4_to_size( size,pchan->pose_mat);
2371
copy_v3_v3(eulo, eul);
2372
copy_v3_v3(sizeo, size);
2374
/* apply noise to each set of channels */
2375
if (amod->channels & 4) {
2377
nor[0] = BLI_gNoise(amod->noisesize, size[0]+ofs, size[1], size[2], 0, 0) - ofs;
2378
nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1]+ofs, size[2], 0, 0) - ofs;
2379
nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2]+ofs, 0, 0) - ofs;
2380
add_v3_v3(size, nor);
2383
mul_v3_fl(pchan->pose_mat[0], size[0] / sizeo[0]);
2385
mul_v3_fl(pchan->pose_mat[1], size[1] / sizeo[1]);
2387
mul_v3_fl(pchan->pose_mat[2], size[2] / sizeo[2]);
2389
if (amod->channels & 2) {
2391
nor[0] = BLI_gNoise(amod->noisesize, eul[0]+ofs, eul[1], eul[2], 0, 0) - ofs;
2392
nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1]+ofs, eul[2], 0, 0) - ofs;
2393
nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2]+ofs, 0, 0) - ofs;
2395
compatible_eul(nor, eulo);
2396
add_v3_v3(eul, nor);
2397
compatible_eul(eul, eulo);
2399
loc_eul_size_to_mat4(pchan->pose_mat, loc, eul, size);
2401
if (amod->channels & 1) {
2403
nor[0] = BLI_gNoise(amod->noisesize, loc[0]+ofs, loc[1], loc[2], 0, 0) - ofs;
2404
nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1]+ofs, loc[2], 0, 0) - ofs;
2405
nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2]+ofs, 0, 0) - ofs;
2407
add_v3_v3v3(pchan->pose_mat[3], loc, nor);
2319
case ACTSTRIP_MOD_NOISE:
2321
if (strcmp(pchan->name, amod->channel) == 0) {
2322
float nor[3], loc[3], ofs;
2323
float eul[3], size[3], eulo[3], sizeo[3];
2325
/* calculate turbulance */
2326
ofs = amod->turbul / 200.0f;
2328
/* make a copy of starting conditions */
2329
copy_v3_v3(loc, pchan->pose_mat[3]);
2330
mat4_to_eul(eul, pchan->pose_mat);
2331
mat4_to_size(size, pchan->pose_mat);
2332
copy_v3_v3(eulo, eul);
2333
copy_v3_v3(sizeo, size);
2335
/* apply noise to each set of channels */
2336
if (amod->channels & 4) {
2338
nor[0] = BLI_gNoise(amod->noisesize, size[0] + ofs, size[1], size[2], 0, 0) - ofs;
2339
nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1] + ofs, size[2], 0, 0) - ofs;
2340
nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2] + ofs, 0, 0) - ofs;
2341
add_v3_v3(size, nor);
2344
mul_v3_fl(pchan->pose_mat[0], size[0] / sizeo[0]);
2346
mul_v3_fl(pchan->pose_mat[1], size[1] / sizeo[1]);
2348
mul_v3_fl(pchan->pose_mat[2], size[2] / sizeo[2]);
2350
if (amod->channels & 2) {
2352
nor[0] = BLI_gNoise(amod->noisesize, eul[0] + ofs, eul[1], eul[2], 0, 0) - ofs;
2353
nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1] + ofs, eul[2], 0, 0) - ofs;
2354
nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2] + ofs, 0, 0) - ofs;
2356
compatible_eul(nor, eulo);
2357
add_v3_v3(eul, nor);
2358
compatible_eul(eul, eulo);
2360
loc_eul_size_to_mat4(pchan->pose_mat, loc, eul, size);
2362
if (amod->channels & 1) {
2364
nor[0] = BLI_gNoise(amod->noisesize, loc[0] + ofs, loc[1], loc[2], 0, 0) - ofs;
2365
nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1] + ofs, loc[2], 0, 0) - ofs;
2366
nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2] + ofs, 0, 0) - ofs;
2368
add_v3_v3v3(pchan->pose_mat[3], loc, nor);
2581
/* Returns total selected vgroups,
2582
* wpi.defbase_sel is assumed malloc'd, all values are set */
2583
int get_selected_defgroups(Object *ob, char *dg_selection, int defbase_tot)
2585
bDeformGroup *defgroup;
2587
Object *armob = object_pose_armature_get(ob);
2588
int dg_flags_sel_tot = 0;
2591
bPose *pose = armob->pose;
2592
for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
2593
bPoseChannel *pchan = get_pose_channel(pose, defgroup->name);
2594
if (pchan && (pchan->bone->flag & BONE_SELECTED)) {
2595
dg_selection[i] = TRUE;
2599
dg_selection[i] = FALSE;
2604
memset(dg_selection, FALSE, sizeof(char) * defbase_tot);
2607
return dg_flags_sel_tot;
2610
2531
/************** Bounding box ********************/
2611
int minmax_armature(Object *ob, float min[3], float max[3])
2532
static int minmax_armature(Object *ob, float r_min[3], float r_max[3])
2613
2534
bPoseChannel *pchan;
2615
/* For now, we assume where_is_pose has already been called (hence we have valid data in pachan). */
2536
/* For now, we assume BKE_pose_where_is has already been called (hence we have valid data in pachan). */
2616
2537
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
2617
DO_MINMAX(pchan->pose_head, min, max);
2618
DO_MINMAX(pchan->pose_tail, min, max);
2538
minmax_v3v3_v3(r_min, r_max, pchan->pose_head);
2539
minmax_v3v3_v3(r_min, r_max, pchan->pose_tail);
2621
2542
return (ob->pose->chanbase.first != NULL);
2624
void boundbox_armature(Object *ob, float *loc, float *size)
2545
static void boundbox_armature(Object *ob, float loc[3], float size[3])
2627
2548
float min[3], max[3];