static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3]) { float cross[3], nstrand[3], vnor[3], blend; if (!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f))) return; if (ma->mode & MA_STR_SURFDIFF) { cross_v3_v3v3(cross, surfnor, nor); cross_v3_v3v3(nstrand, nor, cross); blend = dot_v3v3(nstrand, surfnor); CLAMP(blend, 0.0f, 1.0f); interp_v3_v3v3(vnor, nstrand, surfnor, blend); normalize_v3(vnor); } else { copy_v3_v3(vnor, nor); } if (ma->strand_surfnor > 0.0f) { if (ma->strand_surfnor > surfdist) { blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor; interp_v3_v3v3(vnor, vnor, surfnor, blend); normalize_v3(vnor); } } copy_v3_v3(nor, vnor); }
/* our own triangle intersection, so we can fully control the epsilons and * prevent corner case from going wrong*/ static int meshdeform_tri_intersect(const float orig[3], const float end[3], const float vert0[3], const float vert1[3], const float vert2[3], float r_isectco[3], float r_uvw[3]) { float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; float det, inv_det, u, v, dir[3], isectdir[3]; sub_v3_v3v3(dir, end, orig); /* find vectors for two edges sharing vert0 */ sub_v3_v3v3(edge1, vert1, vert0); sub_v3_v3v3(edge2, vert2, vert0); /* begin calculating determinant - also used to calculate U parameter */ cross_v3_v3v3(pvec, dir, edge2); /* if determinant is near zero, ray lies in plane of triangle */ det = dot_v3v3(edge1, pvec); if (UNLIKELY(det == 0.0f)) { return 0; } inv_det = 1.0f / det; /* calculate distance from vert0 to ray origin */ sub_v3_v3v3(tvec, orig, vert0); /* calculate U parameter and test bounds */ u = dot_v3v3(tvec, pvec) * inv_det; if (u < -EPSILON || u > 1.0f + EPSILON) return 0; /* prepare to test V parameter */ cross_v3_v3v3(qvec, tvec, edge1); /* calculate V parameter and test bounds */ v = dot_v3v3(dir, qvec) * inv_det; if (v < -EPSILON || u + v > 1.0f + EPSILON) return 0; r_isectco[0] = (1.0f - u - v) * vert0[0] + u * vert1[0] + v * vert2[0]; r_isectco[1] = (1.0f - u - v) * vert0[1] + u * vert1[1] + v * vert2[1]; r_isectco[2] = (1.0f - u - v) * vert0[2] + u * vert1[2] + v * vert2[2]; r_uvw[0] = 1.0f - u - v; r_uvw[1] = u; r_uvw[2] = v; /* check if it is within the length of the line segment */ sub_v3_v3v3(isectdir, r_isectco, orig); if (dot_v3v3(dir, isectdir) < -EPSILON) return 0; if (dot_v3v3(dir, dir) + EPSILON < dot_v3v3(isectdir, isectdir)) return 0; return 1; }
/** * Add randomness to stroke * \param gps: Stroke data * \param brush: Brush data */ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush) { bGPDspoint *pt1, *pt2, *pt3; float v1[3]; float v2[3]; if (gps->totpoints < 3) { return; } /* get two vectors using 3 points */ pt1 = &gps->points[0]; pt2 = &gps->points[1]; pt3 = &gps->points[(int)(gps->totpoints * 0.75)]; sub_v3_v3v3(v1, &pt2->x, &pt1->x); sub_v3_v3v3(v2, &pt3->x, &pt2->x); normalize_v3(v1); normalize_v3(v2); /* get normal vector to plane created by two vectors */ float normal[3]; cross_v3_v3v3(normal, v1, v2); normalize_v3(normal); /* get orthogonal vector to plane to rotate random effect */ float ortho[3]; cross_v3_v3v3(ortho, v1, normal); normalize_v3(ortho); /* Read all points and apply shift vector (first and last point not modified) */ for (int i = 1; i < gps->totpoints - 1; ++i) { bGPDspoint *pt = &gps->points[i]; /* get vector with shift (apply a division because random is too sensitive */ const float fac = BLI_frand() * (brush->draw_random_sub / 10.0f); float svec[3]; copy_v3_v3(svec, ortho); if (BLI_frand() > 0.5f) { mul_v3_fl(svec, -fac); } else { mul_v3_fl(svec, fac); } /* apply shift */ add_v3_v3(&pt->x, svec); } }
float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) { float v1_proj[3], v2_proj[3], tproj[3]; float angle; sub_v3_v3v3(v1_proj, v1, v2); sub_v3_v3v3(v2_proj, v3, v2); /* project the vectors onto the axis */ project_v3_v3v3(tproj, v1_proj, axis); sub_v3_v3(v1_proj, tproj); project_v3_v3v3(tproj, v2_proj, axis); sub_v3_v3(v2_proj, tproj); angle = angle_v3v3(v1_proj, v2_proj); /* calculate the sign (reuse 'tproj') */ cross_v3_v3v3(tproj, v2_proj, v1_proj); if (dot_v3v3(tproj, axis) < 0.0f) { angle = ((float)(M_PI * 2.0)) - angle; } return angle; }
/* adjust bone roll to align Z axis with vector * vec is in local space and is normalized */ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only) { float mat[3][3], nor[3]; sub_v3_v3v3(nor, bone->tail, bone->head); vec_roll_to_mat3(nor, 0.0f, mat); /* check the bone isn't aligned with the axis */ if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) { float vec[3], align_axis_proj[3], roll; /* project the new_up_axis along the normal */ project_v3_v3v3(vec, align_axis, nor); sub_v3_v3v3(align_axis_proj, align_axis, vec); if (axis_only) { if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) { negate_v3(align_axis_proj); } } roll = angle_v3v3(align_axis_proj, mat[2]); cross_v3_v3v3(vec, mat[2], align_axis_proj); if (dot_v3v3(vec, nor) < 0) { roll = -roll; } return roll; } return 0.0f; }
/** * finalize after accumulation. */ static void calc_tangent_ortho(float ts[3][3]) { float v_tan_a[3], v_tan_b[3]; float t_vec_a[3], t_vec_b[3]; normalize_v3(ts[2]); copy_v3_v3(v_tan_a, ts[0]); copy_v3_v3(v_tan_b, ts[1]); cross_v3_v3v3(ts[1], ts[2], v_tan_a); mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f); /* orthognalise tangent */ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a)); sub_v3_v3v3(ts[0], v_tan_a, t_vec_a); /* orthognalise bitangent */ mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1])); mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a)); sub_v3_v3(ts[1], t_vec_a); sub_v3_v3(ts[1], t_vec_b); normalize_v3(ts[0]); normalize_v3(ts[1]); }
/* adjust bone roll to align Z axis with vector * vec is in local space and is normalized */ float ED_armature_ebone_roll_to_vector(const EditBone *bone, const float align_axis[3], const bool axis_only) { float mat[3][3], nor[3]; float vec[3], align_axis_proj[3], roll = 0.0f; BLI_ASSERT_UNIT_V3(align_axis); sub_v3_v3v3(nor, bone->tail, bone->head); /* If tail == head or the bone is aligned with the axis... */ if (normalize_v3(nor) <= FLT_EPSILON || (fabsf(dot_v3v3(align_axis, nor)) >= (1.0f - FLT_EPSILON))) { return roll; } vec_roll_to_mat3_normalized(nor, 0.0f, mat); /* project the new_up_axis along the normal */ project_v3_v3v3_normalized(vec, align_axis, nor); sub_v3_v3v3(align_axis_proj, align_axis, vec); if (axis_only) { if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI_2)) { negate_v3(align_axis_proj); } } roll = angle_v3v3(align_axis_proj, mat[2]); cross_v3_v3v3(vec, mat[2], align_axis_proj); if (dot_v3v3(vec, nor) < 0.0f) { return -roll; } return roll; }
/** * Return true if the 2x axis are both aligned when projected into the view. * In this case, we can't usefully project the cursor onto the plane. */ static bool isPlaneProjectionViewAligned(const TransInfo *t) { const float eps = 0.001f; const float *constraint_vector[2]; int n = 0; for (int i = 0; i < 3; i++) { if (t->con.mode & (CON_AXIS0 << i)) { constraint_vector[n++] = t->con.mtx[i]; if (n == 2) { break; } } } BLI_assert(n == 2); float view_to_plane[3], plane_normal[3]; getViewVector(t, t->center_global, view_to_plane); cross_v3_v3v3(plane_normal, constraint_vector[0], constraint_vector[1]); normalize_v3(plane_normal); float factor = dot_v3v3(plane_normal, view_to_plane); return fabsf(factor) < eps; }
void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3]) { float alignaxis[3] = {0.0, 0.0, 0.0}; float norm[3], axis[3], angle, new_quat[4]; if(axisidx > 0) alignaxis[axisidx-1]= 1.0; else alignaxis[-axisidx-1]= -1.0; normalize_v3_v3(norm, vec); angle= (float)acos(dot_v3v3(alignaxis, norm)); cross_v3_v3v3(axis, alignaxis, norm); axis_angle_to_quat( new_quat,axis, -angle); rv3d->view= RV3D_VIEW_USER; if (rv3d->persp==RV3D_CAMOB && v3d->camera) { /* switch out of camera view */ float orig_ofs[3]; float orig_dist= rv3d->dist; float orig_lens= v3d->lens; copy_v3_v3(orig_ofs, rv3d->ofs); rv3d->persp= RV3D_PERSP; rv3d->dist= 0.0; ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens); smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX } else { if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */ smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX } }
static void testAxialSymmetry(BGraph *graph, BNode *root_node, BNode *node1, BNode *node2, BArc *arc1, BArc *arc2, float axis[3], float limit, int group) { const float limit_sq = limit * limit; float nor[3], vec[3], p[3]; sub_v3_v3v3(p, node1->p, root_node->p); cross_v3_v3v3(nor, p, axis); sub_v3_v3v3(p, root_node->p, node2->p); cross_v3_v3v3(vec, p, axis); add_v3_v3(vec, nor); cross_v3_v3v3(nor, vec, axis); if (fabsf(nor[0]) > fabsf(nor[1]) && fabsf(nor[0]) > fabsf(nor[2]) && nor[0] < 0) { negate_v3(nor); } else if (fabsf(nor[1]) > fabsf(nor[0]) && fabsf(nor[1]) > fabsf(nor[2]) && nor[1] < 0) { negate_v3(nor); } else if (fabsf(nor[2]) > fabsf(nor[1]) && fabsf(nor[2]) > fabsf(nor[0]) && nor[2] < 0) { negate_v3(nor); } /* mirror node2 along axis */ copy_v3_v3(p, node2->p); BLI_mirrorAlongAxis(p, root_node->p, nor); /* check if it's within limit before continuing */ if (len_squared_v3v3(node1->p, p) <= limit_sq) { /* mark node as symmetric physically */ copy_v3_v3(root_node->symmetry_axis, nor); root_node->symmetry_flag |= SYM_PHYSICAL; root_node->symmetry_flag |= SYM_AXIAL; /* flag side on arcs */ flagAxialSymmetry(root_node, node1, arc1, group); flagAxialSymmetry(root_node, node2, arc2, group); if (graph->axial_symmetry) { graph->axial_symmetry(root_node, node1, node2, arc1, arc2); } } else { /* NOT SYMMETRIC */ } }
static bool convex(const float p0[3], const float up[3], const float a[3], const float b[3]) { /* Vec3 va = a-p0, vb = b-p0; */ float va[3], vb[3], tmp[3]; sub_v3_v3v3(va, a, p0); sub_v3_v3v3(vb, b, p0); cross_v3_v3v3(tmp, va, vb); return dot_v3v3(up, tmp) >= 0; }
static int convex(float *p0, float *up, float *a, float *b) { // Vec3 va = a-p0, vb = b-p0; float va[3], vb[3], tmp[3]; sub_v3_v3v3(va, a, p0); sub_v3_v3v3(vb, b, p0); cross_v3_v3v3(tmp, va, vb); return dot_v3v3(up, tmp) >= 0; }
static bool depth_read_normal( const ViewContext *vc, const bglMats *mats, const int mval[2], float r_normal[3]) { /* pixels surrounding */ bool depths_valid[9] = {false}; float coords[9][3] = {{0}}; ARegion *ar = vc->ar; const ViewDepths *depths = vc->rv3d->depths; for (int x = 0, i = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; const double depth = (double)depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]); if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) { depths_valid[i] = true; } } i++; } } const int edges[2][6][2] = { /* x edges */ {{0, 1}, {1, 2}, {3, 4}, {4, 5}, {6, 7}, {7, 8}}, /* y edges */ {{0, 3}, {3, 6}, {1, 4}, {4, 7}, {2, 5}, {5, 8}}, }; float cross[2][3] = {{0.0f}}; for (int i = 0; i < 6; i++) { for (int axis = 0; axis < 2; axis++) { if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { float delta[3]; sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); add_v3_v3(cross[axis], delta); } } } cross_v3_v3v3(r_normal, cross[0], cross[1]); if (normalize_v3(r_normal) != 0.0f) { return true; } else { return false; } }
static void flush_pixel(const MResolvePixelData *data, const int x, const int y) { float st[2] = {(x + 0.5f) / data->w, (y + 0.5f) / data->h}; float *st0, *st1, *st2; float *tang0, *tang1, *tang2; float no0[3], no1[3], no2[3]; float fUV[2], from_tang[3][3], to_tang[3][3]; float u, v, w, sign; int r; const int i0 = data->i0; const int i1 = data->i1; const int i2 = data->i2; st0 = data->mtface[data->face_index].uv[i0]; st1 = data->mtface[data->face_index].uv[i1]; st2 = data->mtface[data->face_index].uv[i2]; multiresbake_get_normal(data, no0, data->face_index, i0); /* can optimize these 3 into one call */ multiresbake_get_normal(data, no1, data->face_index, i1); multiresbake_get_normal(data, no2, data->face_index, i2); resolve_tri_uv(fUV, st, st0, st1, st2); u = fUV[0]; v = fUV[1]; w = 1 - u - v; if (data->pvtangent) { tang0 = data->pvtangent + data->face_index * 16 + i0 * 4; tang1 = data->pvtangent + data->face_index * 16 + i1 * 4; tang2 = data->pvtangent + data->face_index * 16 + i2 * 4; /* the sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ sign = (tang0[3] * u + tang1[3] * v + tang2[3] * w) < 0 ? (-1.0f) : 1.0f; /* this sequence of math is designed specifically as is with great care * to be compatible with our shader. Please don't change without good reason. */ for (r = 0; r < 3; r++) { from_tang[0][r] = tang0[r] * u + tang1[r] * v + tang2[r] * w; from_tang[2][r] = no0[r] * u + no1[r] * v + no2[r] * w; } cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]); /* B = sign * cross(N, T) */ mul_v3_fl(from_tang[1], sign); invert_m3_m3(to_tang, from_tang); } else { zero_m3(to_tang); } data->pass_data(data->lores_dm, data->hires_dm, data->bake_data, data->ibuf, data->face_index, data->lvl, st, to_tang, x, y); }
/** * accumulate edge-vectors from all polys. */ static void calc_tangent_loop_accum(const float v_dir_prev[3], const float v_dir_next[3], float r_tspace[3][3]) { add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next); if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) { const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev))); float nor[3]; cross_v3_v3v3(nor, v_dir_prev, v_dir_next); normalize_v3(nor); cross_v3_v3v3(r_tspace[0], r_tspace[1], nor); mul_v3_fl(nor, weight); /* accumulate weighted normals */ add_v3_v3(r_tspace[2], nor); } }
/* builds an X and a Y axis from the given Z axis */ static void build_coordinate_frame(float axisX[3], float axisY[3], const float axisZ[3]) { const float faX = fabsf(axisZ[0]); const float faY = fabsf(axisZ[1]); const float faZ = fabsf(axisZ[2]); if (faX <= faY && faX <= faZ) { const float len = sqrtf(axisZ[1] * axisZ[1] + axisZ[2] * axisZ[2]); axisY[0] = 0; axisY[1] = axisZ[2] / len; axisY[2] = -axisZ[1] / len; cross_v3_v3v3(axisX, axisY, axisZ); } else if (faY <= faZ) { const float len = sqrtf(axisZ[0] * axisZ[0] + axisZ[2] * axisZ[2]); axisX[0] = axisZ[2] / len; axisX[1] = 0; axisX[2] = -axisZ[0] / len; cross_v3_v3v3(axisY, axisZ, axisX); } else { const float len = sqrtf(axisZ[0] * axisZ[0] + axisZ[1] * axisZ[1]); axisX[0] = axisZ[1] / len; axisX[1] = -axisZ[0] / len; axisX[2] = 0; cross_v3_v3v3(axisY, axisZ, axisX); } }
static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const float kink[3], float time, float freq, float shape, float amplitude, const float spiral_start[3]) { float result[3]; CLAMP(time, 0.f, 1.f); copy_v3_v3(result, state->co); { /* Creates a logarithmic spiral: * r(theta) = a * exp(b * theta) * * The "density" parameter b is defined by the shape parameter * and goes up to the Golden Spiral for 1.0 * https://en.wikipedia.org/wiki/Golden_spiral */ const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f; /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */ const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) : (float)-M_PI_2) + (b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2); float spiral_axis[3], rot[3][3]; float vec[3]; float theta = freq * time * 2.0f * (float)M_PI; float radius = amplitude * expf(b * theta); /* a bit more intuitive than using negative frequency for this */ if (amplitude < 0.0f) theta = -theta; cross_v3_v3v3(spiral_axis, dir, kink); normalize_v3(spiral_axis); mul_v3_v3fl(vec, kink, -radius); axis_angle_normalized_to_mat3(rot, spiral_axis, theta); mul_m3_v3(rot, vec); madd_v3_v3fl(vec, kink, amplitude); axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle); mul_m3_v3(rot, vec); add_v3_v3v3(result, spiral_start, vec); } copy_v3_v3(state->co, result); }
static float BME_bevel_get_angle(BME_Mesh *UNUSED(bm), BME_Edge *e, BME_Vert *v) { BME_Vert *v1, *v2; BME_Loop *l1, *l2; float vec1[3], vec2[3], vec3[3], vec4[3]; l1 = e->loop; l2 = e->loop->radial.next->data; if (l1->v == v) { v1 = l1->prev->v; v2 = l1->next->v; } else { v1 = l1->next->next->v; v2 = l1->v; } VECSUB(vec1,v1->co,v->co); VECSUB(vec2,v2->co,v->co); cross_v3_v3v3(vec3,vec1,vec2); l1 = l2; if (l1->v == v) { v1 = l1->prev->v; v2 = l1->next->v; } else { v1 = l1->next->next->v; v2 = l1->v; } VECSUB(vec1,v1->co,v->co); VECSUB(vec2,v2->co,v->co); cross_v3_v3v3(vec4,vec2,vec1); normalize_v3(vec3); normalize_v3(vec4); return dot_v3v3(vec3,vec4); }
static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3]) { float angle, start[3], end[3]; sub_v3_v3v3(start, p1, t->center_global); sub_v3_v3v3(end, p2, t->center_global); // Angle around a constraint axis (error prone, will need debug) if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { float axis[3], tmp[3]; t->con.applyRot(t, NULL, axis, NULL); project_v3_v3v3(tmp, end, axis); sub_v3_v3v3(end, end, tmp); project_v3_v3v3(tmp, start, axis); sub_v3_v3v3(start, start, tmp); normalize_v3(end); normalize_v3(start); cross_v3_v3v3(tmp, start, end); if (dot_v3v3(tmp, axis) < 0.0f) angle = -acosf(dot_v3v3(start, end)); else angle = acosf(dot_v3v3(start, end)); } else { float mtx[3][3]; copy_m3_m4(mtx, t->viewmat); mul_m3_v3(mtx, end); mul_m3_v3(mtx, start); angle = atan2f(start[1], start[0]) - atan2f(end[1], end[0]); } if (angle > (float)M_PI) { angle = angle - 2 * (float)M_PI; } else if (angle < -((float)M_PI)) { angle = 2.0f * (float)M_PI + angle; } return angle; }
/* "Projects" a vector perpendicular to vec2 against vec1, such that * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2. * note: the direction, is_forward, is used in conjunction with up_vec to determine * whether this is a convex or concave corner. If it is a concave corner, it will * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards). * vec1 is the vector to project onto (expected to be normalized) * vec2 is the direction of projection (pointing away from vec1) * up_vec is used for orientation (expected to be normalized) * returns the length of the projected vector that lies along vec1 */ static float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *UNUSED(td)) { float factor, vec3[3], tmp[3],c1,c2; cross_v3_v3v3(tmp,vec1,vec2); normalize_v3(tmp); factor = dot_v3v3(up_vec,tmp); if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) { cross_v3_v3v3(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */ } else { cross_v3_v3v3(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */ } normalize_v3(vec3); c1 = dot_v3v3(vec3,vec1); c2 = dot_v3v3(vec1,vec1); if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) { factor = 0.0f; } else { factor = c2/c1; } return factor; }
static float cotan_weight(float *v1, float *v2, float *v3) { float a[3], b[3], c[3], clen; sub_v3_v3v3(a, v2, v1); sub_v3_v3v3(b, v3, v1); cross_v3_v3v3(c, a, b); clen = len_v3(c); if (clen == 0.0f) return 0.0f; return dot_v3v3(a, b)/clen; }
static float cotan_weight(const float v1[3], const float v2[3], const float v3[3]) { float a[3], b[3], c[3], clen; sub_v3_v3v3(a, v2, v1); sub_v3_v3v3(b, v3, v1); cross_v3_v3v3(c, a, b); clen = len_v3(c); if (clen > FLT_EPSILON) { return dot_v3v3(a, b) / clen; } else { return 0.0f; } }
static bool mesh_bisect_interactive_calc( bContext *C, wmOperator *op, BMEditMesh *em, float plane_co[3], float plane_no[3]) { wmGesture *gesture = op->customdata; BisectData *opdata; ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ar->regiondata; int x_start = RNA_int_get(op->ptr, "xstart"); int y_start = RNA_int_get(op->ptr, "ystart"); int x_end = RNA_int_get(op->ptr, "xend"); int y_end = RNA_int_get(op->ptr, "yend"); /* reference location (some point in front of the view) for finding a point on a plane */ const float *co_ref = rv3d->ofs; float co_a_ss[2] = {x_start, y_start}, co_b_ss[2] = {x_end, y_end}, co_delta_ss[2]; float co_a[3], co_b[3]; const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL); opdata = gesture->userdata; /* view vector */ ED_view3d_win_to_vector(ar, co_a_ss, co_a); /* view delta */ sub_v2_v2v2(co_delta_ss, co_a_ss, co_b_ss); ED_view3d_win_to_delta(ar, co_delta_ss, co_b, zfac); /* cross both to get a normal */ cross_v3_v3v3(plane_no, co_a, co_b); normalize_v3(plane_no); /* not needed but nicer for user */ /* point on plane, can use either start or endpoint */ ED_view3d_win_to_3d(ar, co_ref, co_a_ss, plane_co); if (opdata->is_first == false) EDBM_redo_state_restore(opdata->mesh_backup, em, false); opdata->is_first = false; return true; }
static void rotate(float new_co[3], float a, float ax[3], float co[3]) { float para[3]; float perp[3]; float cp[3]; float cos_a = cos(a * 2 * M_PI); float sin_a = sin(a * 2 * M_PI); // x' = xcosa + n(n.x)(1-cosa) + (x*n)sina mul_v3_v3fl(perp, co, cos_a); mul_v3_v3fl(para, ax, dot_v3v3(co, ax)*(1 - cos_a)); cross_v3_v3v3(cp, ax, co); mul_v3_fl(cp, sin_a); new_co[0] = para[0] + perp[0] + cp[0]; new_co[1] = para[1] + perp[1] + cp[1]; new_co[2] = para[2] + perp[2] + cp[2]; }
/** * This function converts an object space normal map to a tangent space normal map for a given low poly mesh */ void RE_bake_normal_world_to_tangent( const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]) { size_t i; TriTessFace *triangles; DerivedMesh *dm = CDDM_from_mesh(me); triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh"); mesh_calc_tri_tessface(triangles, me, true, dm); BLI_assert(num_pixels >= 3); for (i = 0; i < num_pixels; i++) { TriTessFace *triangle; float tangents[3][3]; float normals[3][3]; float signs[3]; int j; float tangent[3]; float normal[3]; float binormal[3]; float sign; float u, v, w; float tsm[3][3]; /* tangent space matrix */ float itsm[3][3]; size_t offset; float nor[3]; /* texture normal */ bool is_smooth; int primitive_id = pixel_array[i].primitive_id; offset = i * depth; if (primitive_id == -1) { copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f); continue; } triangle = &triangles[primitive_id]; is_smooth = triangle->is_smooth; for (j = 0; j < 3; j++) { const TSpace *ts; if (is_smooth) normal_short_to_float_v3(normals[j], triangle->mverts[j]->no); else normal[j] = triangle->normal[j]; ts = triangle->tspace[j]; copy_v3_v3(tangents[j], ts->tangent); signs[j] = ts->sign; } u = pixel_array[i].uv[0]; v = pixel_array[i].uv[1]; w = 1.0f - u - v; /* normal */ if (is_smooth) interp_barycentric_tri_v3(normals, u, v, normal); /* tangent */ interp_barycentric_tri_v3(tangents, u, v, tangent); /* sign */ /* The sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ sign = (signs[0] * u + signs[1] * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f; /* binormal */ /* B = sign * cross(N, T) */ cross_v3_v3v3(binormal, normal, tangent); mul_v3_fl(binormal, sign); /* populate tangent space matrix */ copy_v3_v3(tsm[0], tangent); copy_v3_v3(tsm[1], binormal); copy_v3_v3(tsm[2], normal); /* texture values */ normal_uncompress(nor, &result[offset]); /* converts from world space to local space */ mul_transposed_mat3_m4_v3(mat, nor); invert_m3_m3(itsm, tsm); mul_m3_v3(itsm, nor); normalize_v3(nor); /* save back the values */ normal_compress(&result[offset], nor, normal_swizzle); } /* garbage collection */ MEM_freeN(triangles); if (dm) dm->release(dm); }
/* Evaluate spline IK for a given bone */ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, int index, float ctime) { bSplineIKConstraint *ikData = tree->ikData; float poseHead[3], poseTail[3], poseMat[4][4]; float splineVec[3], scaleFac, radius = 1.0f; /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); copy_v3_v3(poseHead, pchan->pose_head); copy_v3_v3(poseTail, pchan->pose_tail); /* step 1: determine the positions for the endpoints of the bone */ { float vec[4], dir[3], rad; float tailBlendFac = 1.0f; /* determine if the bone should still be affected by SplineIK */ if (tree->points[index + 1] >= 1.0f) { /* spline doesn't affect the bone anymore, so done... */ pchan->flag |= POSE_DONE; return; } else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) { /* blending factor depends on the amount of the bone still left on the chain */ tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]); } /* tail endpoint */ if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) { /* apply curve's object-mode transforms to the position * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) mul_m4_v3(ikData->tar->obmat, vec); /* convert the position to pose-space, then store it */ mul_m4_v3(ob->imat, vec); interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac); /* set the new radius */ radius = rad; } /* head endpoint */ if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) { /* apply curve's object-mode transforms to the position * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) mul_m4_v3(ikData->tar->obmat, vec); /* store the position, and convert it to pose space */ mul_m4_v3(ob->imat, vec); copy_v3_v3(poseHead, vec); /* set the new radius (it should be the average value) */ radius = (radius + rad) / 2; } } /* step 2: determine the implied transform from these endpoints * - splineVec: the vector direction that the spline applies on the bone * - scaleFac: the factor that the bone length is scaled by to get the desired amount */ sub_v3_v3v3(splineVec, poseTail, poseHead); scaleFac = len_v3(splineVec) / pchan->bone->length; /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis * - this uses the same method as is used for the Damped Track Constraint (see the code there for details) */ { float dmat[3][3], rmat[3][3], tmat[3][3]; float raxis[3], rangle; /* compute the raw rotation matrix from the bone's current matrix by extracting only the * orientation-relevant axes, and normalizing them */ copy_v3_v3(rmat[0], pchan->pose_mat[0]); copy_v3_v3(rmat[1], pchan->pose_mat[1]); copy_v3_v3(rmat[2], pchan->pose_mat[2]); normalize_m3(rmat); /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */ normalize_v3(splineVec); /* calculate smallest axis-angle rotation necessary for getting from the * current orientation of the bone, to the spline-imposed direction */ cross_v3_v3v3(raxis, rmat[1], splineVec); rangle = dot_v3v3(rmat[1], splineVec); CLAMP(rangle, -1.0f, 1.0f); rangle = acosf(rangle); /* multiply the magnitude of the angle by the influence of the constraint to * control the influence of the SplineIK effect */ rangle *= tree->con->enforce; /* construct rotation matrix from the axis-angle rotation found above * - this call takes care to make sure that the axis provided is a unit vector first */ axis_angle_to_mat3(dmat, raxis, rangle); /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates, * while still maintaining roll control from the existing bone animation */ mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */ normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */ copy_m4_m3(poseMat, tmat); } /* step 4: set the scaling factors for the axes */ { /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ mul_v3_fl(poseMat[1], scaleFac); /* set the scaling factors of the x and z axes from... */ switch (ikData->xzScaleMode) { case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: { /* original scales get used */ float scale; /* x-axis scale */ scale = len_v3(pchan->pose_mat[0]); mul_v3_fl(poseMat[0], scale); /* z-axis scale */ scale = len_v3(pchan->pose_mat[2]); mul_v3_fl(poseMat[2], scale); break; } case CONSTRAINT_SPLINEIK_XZS_INVERSE: { /* old 'volume preservation' method using the inverse scale */ float scale; /* calculate volume preservation factor which is * basically the inverse of the y-scaling factor */ if (fabsf(scaleFac) != 0.0f) { scale = 1.0f / fabsf(scaleFac); /* we need to clamp this within sensible values */ /* NOTE: these should be fine for now, but should get sanitised in future */ CLAMP(scale, 0.0001f, 100000.0f); } else scale = 1.0f; /* apply the scaling */ mul_v3_fl(poseMat[0], scale); mul_v3_fl(poseMat[2], scale); break; } case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: { /* improved volume preservation based on the Stretch To constraint */ float final_scale; /* as the basis for volume preservation, we use the inverse scale factor... */ if (fabsf(scaleFac) != 0.0f) { /* NOTE: The method here is taken wholesale from the Stretch To constraint */ float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); if (bulge > 1.0f) { if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { float bulge_max = max_ff(ikData->bulge_max, 1.0f); float hard = min_ff(bulge, bulge_max); float range = bulge_max - 1.0f; float scale = (range > 0.0f) ? 1.0f / range : 0.0f; float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2; bulge = interpf(soft, hard, ikData->bulge_smooth); } } if (bulge < 1.0f) { if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); float hard = max_ff(bulge, bulge_min); float range = 1.0f - bulge_min; float scale = (range > 0.0f) ? 1.0f / range : 0.0f; float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2; bulge = interpf(soft, hard, ikData->bulge_smooth); } } /* compute scale factor for xz axes from this value */ final_scale = sqrtf(bulge); } else { /* no scaling, so scale factor is simple */ final_scale = 1.0f; } /* apply the scaling (assuming normalised scale) */ mul_v3_fl(poseMat[0], final_scale); mul_v3_fl(poseMat[2], final_scale); break; } } /* finally, multiply the x and z scaling by the radius of the curve too, * to allow automatic scales to get tweaked still */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { mul_v3_fl(poseMat[0], radius); mul_v3_fl(poseMat[2], radius); } } /* step 5: set the location of the bone in the matrix */ if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) { /* when the 'no-root' option is affected, the chain can retain * the shape but be moved elsewhere */ copy_v3_v3(poseHead, pchan->pose_head); } else if (tree->con->enforce < 1.0f) { /* when the influence is too low * - blend the positions for the 'root' bone * - stick to the parent for any other */ if (pchan->parent) { copy_v3_v3(poseHead, pchan->pose_head); } else { /* FIXME: this introduces popping artifacts when we reach 0.0 */ interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce); } } copy_v3_v3(poseMat[3], poseHead); /* finally, store the new transform */ copy_m4_m4(pchan->pose_mat, poseMat); copy_v3_v3(pchan->pose_head, poseHead); /* recalculate tail, as it's now outdated after the head gets adjusted above! */ BKE_pose_where_is_bone_tail(pchan); /* done! */ pchan->flag |= POSE_DONE; }
static DerivedMesh * applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams), int UNUSED(isFinalCalc)) { DerivedMesh *dm = derivedData, *result; ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md; ParticleSimulationData sim; ParticleSystem *psys= NULL; ParticleData *pa= NULL, *pars= NULL; MFace *mface, *orig_mface; MVert *mvert, *orig_mvert; int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0; short track=ob->trackflag%3, trackneg, axis = pimd->axis; float max_co=0.0, min_co=0.0, temp_co[3], cross[3]; float *size=NULL; trackneg=((ob->trackflag>2)?1:0); if(pimd->ob==ob){ pimd->ob= NULL; return derivedData; } if(pimd->ob){ psys = BLI_findlink(&pimd->ob->particlesystem,pimd->psys-1); if(psys==NULL || psys->totpart==0) return derivedData; } else return derivedData; if(pimd->flag & eParticleInstanceFlag_Parents) totpart+=psys->totpart; if(pimd->flag & eParticleInstanceFlag_Children){ if(totpart==0) first_particle=psys->totpart; totpart+=psys->totchild; } if(totpart==0) return derivedData; sim.scene = md->scene; sim.ob = pimd->ob; sim.psys = psys; sim.psmd = psys_get_modifier(pimd->ob, psys); if(pimd->flag & eParticleInstanceFlag_UseSize) { int p; float *si; si = size = MEM_callocN(totpart * sizeof(float), "particle size array"); if(pimd->flag & eParticleInstanceFlag_Parents) { for(p=0, pa= psys->particles; p<psys->totpart; p++, pa++, si++) *si = pa->size; } if(pimd->flag & eParticleInstanceFlag_Children) { ChildParticle *cpa = psys->child; for(p=0; p<psys->totchild; p++, cpa++, si++) { *si = psys_get_child_size(psys, cpa, 0.0f, NULL); } } } pars=psys->particles; totvert=dm->getNumVerts(dm); totface=dm->getNumFaces(dm); maxvert=totvert*totpart; maxface=totface*totpart; psys->lattice=psys_get_lattice(&sim); if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED){ float min_r[3], max_r[3]; INIT_MINMAX(min_r, max_r); dm->getMinMax(dm, min_r, max_r); min_co=min_r[track]; max_co=max_r[track]; } result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface); mvert=result->getVertArray(result); orig_mvert=dm->getVertArray(dm); for(i=0; i<maxvert; i++){ MVert *inMV; MVert *mv = mvert + i; ParticleKey state; inMV = orig_mvert + i%totvert; DM_copy_vert_data(dm, result, i%totvert, i, 1); *mv = *inMV; /*change orientation based on object trackflag*/ copy_v3_v3(temp_co, mv->co); mv->co[axis]=temp_co[track]; mv->co[(axis+1)%3]=temp_co[(track+1)%3]; mv->co[(axis+2)%3]=temp_co[(track+2)%3]; if((psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && pimd->flag & eParticleInstanceFlag_Path){ float ran = 0.0f; if(pimd->random_position != 0.0f) { BLI_srandom(psys->seed + (i/totvert)%totpart); ran = pimd->random_position * BLI_frand(); } if(pimd->flag & eParticleInstanceFlag_KeepShape) { state.time = pimd->position * (1.0f - ran); } else { state.time=(mv->co[axis]-min_co)/(max_co-min_co) * pimd->position * (1.0f - ran); if(trackneg) state.time=1.0f-state.time; mv->co[axis] = 0.0; } psys_get_particle_on_path(&sim, first_particle + i/totvert, &state,1); normalize_v3(state.vel); /* TODO: incremental rotations somehow */ if(state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { state.rot[0] = 1; state.rot[1] = state.rot[2] = state.rot[3] = 0.0f; } else { float temp[3] = {0.0f,0.0f,0.0f}; temp[axis] = 1.0f; cross_v3_v3v3(cross, temp, state.vel); /* state.vel[axis] is the only component surviving from a dot product with the axis */ axis_angle_to_quat(state.rot,cross,saacos(state.vel[axis])); } } else{ state.time=-1.0; psys_get_particle_state(&sim, first_particle + i/totvert, &state,1); } mul_qt_v3(state.rot,mv->co); if(pimd->flag & eParticleInstanceFlag_UseSize) mul_v3_fl(mv->co, size[i/totvert]); VECADD(mv->co,mv->co,state.co); } mface=result->getFaceArray(result); orig_mface=dm->getFaceArray(dm); for(i=0; i<maxface; i++){ MFace *inMF; MFace *mf = mface + i; if(pimd->flag & eParticleInstanceFlag_Parents){ if(i/totface>=psys->totpart){ if(psys->part->childtype==PART_CHILD_PARTICLES) pa=psys->particles+(psys->child+i/totface-psys->totpart)->parent; else pa= NULL; } else pa=pars+i/totface; } else{ if(psys->part->childtype==PART_CHILD_PARTICLES) pa=psys->particles+(psys->child+i/totface)->parent; else pa= NULL; } if(pa){ if(pa->alive==PARS_UNBORN && (pimd->flag&eParticleInstanceFlag_Unborn)==0) continue; if(pa->alive==PARS_ALIVE && (pimd->flag&eParticleInstanceFlag_Alive)==0) continue; if(pa->alive==PARS_DEAD && (pimd->flag&eParticleInstanceFlag_Dead)==0) continue; } inMF = orig_mface + i%totface; DM_copy_face_data(dm, result, i%totface, i, 1); *mf = *inMF; mf->v1+=(i/totface)*totvert; mf->v2+=(i/totface)*totvert; mf->v3+=(i/totface)*totvert; if(mf->v4) mf->v4+=(i/totface)*totvert; } CDDM_calc_edges(result); CDDM_calc_normals(result); if(psys->lattice){ end_latt_deform(psys->lattice); psys->lattice= NULL; } if(size) MEM_freeN(size); return result; }
static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *arg) { Scene *scene = CTX_data_scene(C); UnitSettings *unit = &scene->unit; RulerItem *ruler_item; RulerInfo *ruler_info = arg; RegionView3D *rv3d = ruler_info->ar->regiondata; // ARegion *ar = ruler_info->ar; const float cap_size = 4.0f; const float bg_margin = 4.0f * U.pixelsize; const float bg_radius = 4.0f * U.pixelsize; const float arc_size = 64.0f * U.pixelsize; #define ARC_STEPS 24 const int arc_steps = ARC_STEPS; int i; //unsigned int color_act = 0x666600; unsigned int color_act = 0xffffff; unsigned int color_base = 0x0; unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80}; unsigned char color_text[3]; unsigned char color_wire[3]; /* anti-aliased lines for more consistent appearance */ glEnable(GL_LINE_SMOOTH); BLF_enable(blf_mono_font, BLF_ROTATION); BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); BLF_rotation(blf_mono_font, 0.0f); UI_GetThemeColor3ubv(TH_TEXT, color_text); UI_GetThemeColor3ubv(TH_WIRE, color_wire); for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) { const bool is_act = (i == ruler_info->item_active); float dir_ruler[2]; float co_ss[3][2]; int j; /* should these be checked? - ok for now not to */ for (j = 0; j < 3; j++) { ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); } glEnable(GL_BLEND); cpack(is_act ? color_act : color_base); if (ruler_item->flag & RULERITEM_USE_ANGLE) { glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j++) { glVertex2fv(co_ss[j]); } glEnd(); cpack(0xaaaaaa); setlinestyle(3); glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j++) { glVertex2fv(co_ss[j]); } glEnd(); setlinestyle(0); /* arc */ { float dir_tmp[3]; float co_tmp[3]; float arc_ss_coords[ARC_STEPS + 1][2]; float dir_a[3]; float dir_b[3]; float quat[4]; float axis[3]; float angle; const float px_scale = (ED_view3d_pixel_size(rv3d, ruler_item->co[1]) * min_fff(arc_size, len_v2v2(co_ss[0], co_ss[1]) / 2.0f, len_v2v2(co_ss[2], co_ss[1]) / 2.0f)); sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]); sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]); normalize_v3(dir_a); normalize_v3(dir_b); cross_v3_v3v3(axis, dir_a, dir_b); angle = angle_normalized_v3v3(dir_a, dir_b); axis_angle_to_quat(quat, axis, angle / arc_steps); copy_v3_v3(dir_tmp, dir_a); glColor3ubv(color_wire); for (j = 0; j <= arc_steps; j++) { madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP); mul_qt_v3(quat, dir_tmp); } glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords); glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1); glDisableClientState(GL_VERTEX_ARRAY); } /* text */ { char numstr[256]; float numstr_size[2]; float pos[2]; const int prec = 2; /* XXX, todo, make optional */ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); pos[0] = co_ss[1][0] + (cap_size * 2.0f); pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); /* draw text (bg) */ glColor4ubv(color_back); uiSetRoundBox(UI_CNR_ALL); uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin, pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], bg_radius); /* draw text */ glColor3ubv(color_text); BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); BLF_rotation(blf_mono_font, 0.0f); BLF_draw(blf_mono_font, numstr, sizeof(numstr)); } /* capping */ { float rot_90_vec_a[2]; float rot_90_vec_b[2]; float cap[2]; sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); rot_90_vec_a[0] = -dir_ruler[1]; rot_90_vec_a[1] = dir_ruler[0]; normalize_v2(rot_90_vec_a); sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]); rot_90_vec_b[0] = -dir_ruler[1]; rot_90_vec_b[1] = dir_ruler[0]; normalize_v2(rot_90_vec_b); glEnable(GL_BLEND); glColor3ubv(color_wire); glBegin(GL_LINES); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); glVertex2fv(cap); /* angle vertex */ glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); glEnd(); glDisable(GL_BLEND); } } else { glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j += 2) { glVertex2fv(co_ss[j]); } glEnd(); cpack(0xaaaaaa); setlinestyle(3); glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j += 2) { glVertex2fv(co_ss[j]); } glEnd(); setlinestyle(0); sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); /* text */ { char numstr[256]; float numstr_size[2]; const int prec = 6; /* XXX, todo, make optional */ float pos[2]; ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); mid_v2_v2v2(pos, co_ss[0], co_ss[2]); /* center text */ pos[0] -= numstr_size[0] / 2.0f; pos[1] -= numstr_size[1] / 2.0f; /* draw text (bg) */ glColor4ubv(color_back); uiSetRoundBox(UI_CNR_ALL); uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin, pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], bg_radius); /* draw text */ glColor3ubv(color_text); BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); BLF_draw(blf_mono_font, numstr, sizeof(numstr)); } /* capping */ { float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; float cap[2]; normalize_v2(rot_90_vec); glEnable(GL_BLEND); glColor3ubv(color_wire); glBegin(GL_LINES); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); glVertex2fv(cap); glEnd(); glDisable(GL_BLEND); } } } glDisable(GL_LINE_SMOOTH); BLF_disable(blf_mono_font, BLF_ROTATION); #undef ARC_STEPS /* draw snap */ if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG)) { ruler_item = ruler_item_active_get(ruler_info); if (ruler_item) { /* size from drawSnapping */ const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); float co_ss[3]; ED_view3d_project_float_global(ar, ruler_item->co[ruler_item->co_index], co_ss, V3D_PROJ_TEST_NOP); cpack(color_act); circ(co_ss[0], co_ss[1], size * U.pixelsize); } } }
static void axisProjection(TransInfo *t, const float axis[3], const float in[3], float out[3]) { float norm[3], vec[3], factor, angle; float t_con_center[3]; if (is_zero_v3(in)) { return; } copy_v3_v3(t_con_center, t->center_global); /* checks for center being too close to the view center */ viewAxisCorrectCenter(t, t_con_center); angle = fabsf(angle_v3v3(axis, t->viewinv[2])); if (angle > (float)M_PI_2) { angle = (float)M_PI - angle; } angle = RAD2DEGF(angle); /* For when view is parallel to constraint... will cause NaNs otherwise * So we take vertical motion in 3D space and apply it to the * constraint axis. Nice for camera grab + MMB */ if (angle < 5.0f) { project_v3_v3v3(vec, in, t->viewinv[1]); factor = dot_v3v3(t->viewinv[1], vec) * 2.0f; /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */ if (factor < 0.0f) factor *= -factor; else factor *= factor; copy_v3_v3(out, axis); normalize_v3(out); mul_v3_fl(out, -factor); /* -factor makes move down going backwards */ } else { float v[3], i1[3], i2[3]; float v2[3], v4[3]; float norm_center[3]; float plane[3]; getViewVector(t, t_con_center, norm_center); cross_v3_v3v3(plane, norm_center, axis); project_v3_v3v3(vec, in, plane); sub_v3_v3v3(vec, in, vec); add_v3_v3v3(v, vec, t_con_center); getViewVector(t, v, norm); /* give arbitrary large value if projection is impossible */ factor = dot_v3v3(axis, norm); if (1.0f - fabsf(factor) < 0.0002f) { copy_v3_v3(out, axis); if (factor > 0) { mul_v3_fl(out, 1000000000.0f); } else { mul_v3_fl(out, -1000000000.0f); } } else { add_v3_v3v3(v2, t_con_center, axis); add_v3_v3v3(v4, v, norm); isect_line_line_v3(t_con_center, v2, v, v4, i1, i2); sub_v3_v3v3(v, i2, v); sub_v3_v3v3(out, i1, t_con_center); /* possible some values become nan when * viewpoint and object are both zero */ if (!finite(out[0])) out[0] = 0.0f; if (!finite(out[1])) out[1] = 0.0f; if (!finite(out[2])) out[2] = 0.0f; } } }
static void testRadialSymmetry(BGraph *graph, BNode* root_node, RadialArc* ring, int total, float axis[3], float limit, int group) { int symmetric = 1; int i; /* sort ring by angle */ for (i = 0; i < total - 1; i++) { float minAngle = FLT_MAX; int minIndex = -1; int j; for (j = i + 1; j < total; j++) { float angle = dot_v3v3(ring[i].n, ring[j].n); /* map negative values to 1..2 */ if (angle < 0) { angle = 1 - angle; } if (angle < minAngle) { minIndex = j; minAngle = angle; } } /* swap if needed */ if (minIndex != i + 1) { RadialArc tmp; tmp = ring[i + 1]; ring[i + 1] = ring[minIndex]; ring[minIndex] = tmp; } } for (i = 0; i < total && symmetric; i++) { BNode *node1, *node2; float tangent[3]; float normal[3]; float p[3]; int j = (i + 1) % total; /* next arc in the circular list */ add_v3_v3v3(tangent, ring[i].n, ring[j].n); cross_v3_v3v3(normal, tangent, axis); node1 = BLI_otherNode(ring[i].arc, root_node); node2 = BLI_otherNode(ring[j].arc, root_node); copy_v3_v3(p, node2->p); BLI_mirrorAlongAxis(p, root_node->p, normal); /* check if it's within limit before continuing */ if (len_v3v3(node1->p, p) > limit) { symmetric = 0; } } if (symmetric) { /* mark node as symmetric physically */ copy_v3_v3(root_node->symmetry_axis, axis); root_node->symmetry_flag |= SYM_PHYSICAL; root_node->symmetry_flag |= SYM_RADIAL; /* FLAG SYMMETRY GROUP */ for (i = 0; i < total; i++) { ring[i].arc->symmetry_group = group; ring[i].arc->symmetry_flag = SYM_SIDE_RADIAL + i; } if (graph->radial_symmetry) { graph->radial_symmetry(root_node, ring, total); } } }