void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) { Material *ma; StrandBuffer *strandbuf; float *simplify; float p[4][3], data[4], cross[3], w, dx, dy, t; int type; strandbuf= sseg->buffer; ma= sseg->buffer->ma; t= spoint->t; type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL; copy_v3_v3(p[0], sseg->v[0]->co); copy_v3_v3(p[1], sseg->v[1]->co); copy_v3_v3(p[2], sseg->v[2]->co); copy_v3_v3(p[3], sseg->v[3]->co); if (sseg->obi->flag & R_TRANSFORMED) { mul_m4_v3(sseg->obi->mat, p[0]); mul_m4_v3(sseg->obi->mat, p[1]); mul_m4_v3(sseg->obi->mat, p[2]); mul_m4_v3(sseg->obi->mat, p[3]); } if (t == 0.0f) { copy_v3_v3(spoint->co, p[1]); spoint->strandco= sseg->v[1]->strandco; spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco); if (sseg->v[0] != sseg->v[1]) spoint->dtstrandco *= 0.5f; } else if (t == 1.0f) { copy_v3_v3(spoint->co, p[2]); spoint->strandco= sseg->v[2]->strandco; spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco); if (sseg->v[3] != sseg->v[2]) spoint->dtstrandco *= 0.5f; } else { key_curve_position_weights(t, data, type); spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco; } key_curve_tangent_weights(t, data, type); spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; normalize_v3_v3(spoint->tan, spoint->dtco); normalize_v3_v3(spoint->nor, spoint->co); negate_v3(spoint->nor); spoint->width= strand_eval_width(ma, spoint->strandco); /* simplification */ simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0); spoint->alpha= (simplify)? simplify[1]: 1.0f; /* outer points */ cross_v3_v3v3(cross, spoint->co, spoint->tan); w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3]; dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w; dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w; w= sqrt(dx*dx + dy*dy); if (w > 0.0f) { if (strandbuf->flag & R_STRAND_B_UNITS) { const float crosslen= len_v3(cross); w= 2.0f*crosslen*strandbuf->minwidth/w; if (spoint->width < w) { spoint->alpha= spoint->width/w; spoint->width= w; } if (simplify) /* squared because we only change width, not length */ spoint->width *= simplify[0]*simplify[0]; mul_v3_fl(cross, spoint->width*0.5f/crosslen); } else mul_v3_fl(cross, spoint->width/w); } sub_v3_v3v3(spoint->co1, spoint->co, cross); add_v3_v3v3(spoint->co2, spoint->co, cross); copy_v3_v3(spoint->dsco, cross); }
/* calculate the deformation implied by the curve path at a given parametric position, * and returns whether this operation succeeded. * * note: ctime is normalized range <0-1> * * returns OK: 1/0 */ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius, float *weight) { Curve *cu; Nurb *nu; BevList *bl; Path *path; PathPoint *pp, *p0, *p1, *p2, *p3; float fac; float data[4]; int cycl=0, s0, s1, s2, s3; if (ob==NULL || ob->type != OB_CURVE) return 0; cu= ob->data; if (cu->path==NULL || cu->path->data==NULL) { printf("no path!\n"); return 0; } path= cu->path; pp= path->data; /* test for cyclic */ bl= cu->bev.first; if (!bl) return 0; if (!bl->nr) return 0; if (bl->poly> -1) cycl= 1; ctime *= (path->len-1); s1= (int)floor(ctime); fac= (float)(s1+1)-ctime; /* path->len is corected for cyclic */ s0= interval_test(0, path->len-1-cycl, s1-1, cycl); s1= interval_test(0, path->len-1-cycl, s1, cycl); s2= interval_test(0, path->len-1-cycl, s1+1, cycl); s3= interval_test(0, path->len-1-cycl, s1+2, cycl); p0= pp + s0; p1= pp + s1; p2= pp + s2; p3= pp + s3; /* note, commented out for follow constraint */ //if (cu->flag & CU_FOLLOW) { key_curve_tangent_weights(1.0f-fac, data, KEY_BSPLINE); interp_v3_v3v3v3v3(dir, p0->vec, p1->vec, p2->vec, p3->vec, data); /* make compatible with vectoquat */ negate_v3(dir); //} nu= cu->nurb.first; /* make sure that first and last frame are included in the vectors here */ if (nu->type == CU_POLY) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR); else if (nu->type == CU_BEZIER) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR); else if (s0==s1 || p2==p3) key_curve_position_weights(1.0f-fac, data, KEY_CARDINAL); else key_curve_position_weights(1.0f-fac, data, KEY_BSPLINE); vec[0]= data[0]*p0->vec[0] + data[1]*p1->vec[0] + data[2]*p2->vec[0] + data[3]*p3->vec[0] ; /* X */ vec[1]= data[0]*p0->vec[1] + data[1]*p1->vec[1] + data[2]*p2->vec[1] + data[3]*p3->vec[1] ; /* Y */ vec[2]= data[0]*p0->vec[2] + data[1]*p1->vec[2] + data[2]*p2->vec[2] + data[3]*p3->vec[2] ; /* Z */ vec[3]= data[0]*p0->vec[3] + data[1]*p1->vec[3] + data[2]*p2->vec[3] + data[3]*p3->vec[3] ; /* Tilt, should not be needed since we have quat still used */ if (quat) { float totfac, q1[4], q2[4]; totfac= data[0]+data[3]; if (totfac>FLT_EPSILON) interp_qt_qtqt(q1, p0->quat, p3->quat, data[3] / totfac); else copy_qt_qt(q1, p1->quat); totfac= data[1]+data[2]; if (totfac>FLT_EPSILON) interp_qt_qtqt(q2, p1->quat, p2->quat, data[2] / totfac); else copy_qt_qt(q2, p3->quat); totfac = data[0]+data[1]+data[2]+data[3]; if (totfac>FLT_EPSILON) interp_qt_qtqt(quat, q1, q2, (data[1]+data[2]) / totfac); else copy_qt_qt(quat, q2); } if (radius) *radius= data[0]*p0->radius + data[1]*p1->radius + data[2]*p2->radius + data[3]*p3->radius; if (weight) *weight= data[0]*p0->weight + data[1]*p1->weight + data[2]*p2->weight + data[3]*p3->weight; return 1; }
/* ctime is normalized range <0-1> */ int where_on_path(Object *ob, float ctime, float *vec, float *dir, float *quat, float *radius) /* returns OK */ { Curve *cu; Nurb *nu; BevList *bl; Path *path; PathPoint *pp, *p0, *p1, *p2, *p3; float fac; float data[4]; int cycl=0, s0, s1, s2, s3; if(ob==NULL || ob->type != OB_CURVE) return 0; cu= ob->data; if(cu->path==NULL || cu->path->data==NULL) { printf("no path!\n"); return 0; } path= cu->path; pp= path->data; /* test for cyclic */ bl= cu->bev.first; if (!bl) return 0; if (!bl->nr) return 0; if(bl->poly> -1) cycl= 1; ctime *= (path->len-1); s1= (int)floor(ctime); fac= (float)(s1+1)-ctime; /* path->len is corected for cyclic */ s0= interval_test(0, path->len-1-cycl, s1-1, cycl); s1= interval_test(0, path->len-1-cycl, s1, cycl); s2= interval_test(0, path->len-1-cycl, s1+1, cycl); s3= interval_test(0, path->len-1-cycl, s1+2, cycl); p0= pp + s0; p1= pp + s1; p2= pp + s2; p3= pp + s3; /* note, commented out for follow constraint */ //if(cu->flag & CU_FOLLOW) { key_curve_tangent_weights(1.0f-fac, data, KEY_BSPLINE); dir[0]= data[0]*p0->vec[0] + data[1]*p1->vec[0] + data[2]*p2->vec[0] + data[3]*p3->vec[0] ; dir[1]= data[0]*p0->vec[1] + data[1]*p1->vec[1] + data[2]*p2->vec[1] + data[3]*p3->vec[1] ; dir[2]= data[0]*p0->vec[2] + data[1]*p1->vec[2] + data[2]*p2->vec[2] + data[3]*p3->vec[2] ; /* make compatible with vectoquat */ dir[0]= -dir[0]; dir[1]= -dir[1]; dir[2]= -dir[2]; //} nu= cu->nurb.first; /* make sure that first and last frame are included in the vectors here */ if(nu->type == CU_POLY) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR); else if(nu->type == CU_BEZIER) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR); else if(s0==s1 || p2==p3) key_curve_position_weights(1.0f-fac, data, KEY_CARDINAL); else key_curve_position_weights(1.0f-fac, data, KEY_BSPLINE); vec[0]= data[0]*p0->vec[0] + data[1]*p1->vec[0] + data[2]*p2->vec[0] + data[3]*p3->vec[0] ; /* X */ vec[1]= data[0]*p0->vec[1] + data[1]*p1->vec[1] + data[2]*p2->vec[1] + data[3]*p3->vec[1] ; /* Y */ vec[2]= data[0]*p0->vec[2] + data[1]*p1->vec[2] + data[2]*p2->vec[2] + data[3]*p3->vec[2] ; /* Z */ vec[3]= data[0]*p0->vec[3] + data[1]*p1->vec[3] + data[2]*p2->vec[3] + data[3]*p3->vec[3] ; /* Tilt, should not be needed since we have quat still used */ /* Need to verify the quat interpolation is correct - XXX */ if (quat) { //float totfac, q1[4], q2[4]; /* checks for totfac are needed when 'fac' is 1.0 key_curve_position_weights can assign zero * to more then one index in data which can give divide by zero error */ /* totfac= data[0]+data[1]; if(totfac>0.000001) QuatInterpol(q1, p0->quat, p1->quat, data[0] / totfac); else QUATCOPY(q1, p1->quat); NormalQuat(q1); totfac= data[2]+data[3]; if(totfac>0.000001) QuatInterpol(q2, p2->quat, p3->quat, data[2] / totfac); else QUATCOPY(q1, p3->quat); NormalQuat(q2); totfac = data[0]+data[1]+data[2]+data[3]; if(totfac>0.000001) QuatInterpol(quat, q1, q2, (data[0]+data[1]) / totfac); else QUATCOPY(quat, q2); NormalQuat(quat); */ // XXX - find some way to make quat interpolation work correctly, above code fails in rare but nasty cases. QUATCOPY(quat, p1->quat); } if(radius) *radius= data[0]*p0->radius + data[1]*p1->radius + data[2]*p2->radius + data[3]*p3->radius; return 1; }