/* only valid for perspective cameras */ bool BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3]) { float shift[2]; float plane_tx[4][3]; float rot_obmat[3][3]; const float zero[3] = {0, 0, 0}; CameraViewFrameData data_cb; unsigned int i; BKE_camera_view_frame(scene, camera_ob->data, data_cb.frame_tx); copy_m3_m4(rot_obmat, camera_ob->obmat); normalize_m3(rot_obmat); for (i = 0; i < 4; i++) { /* normalize so Z is always 1.0f*/ mul_v3_fl(data_cb.frame_tx[i], 1.0f / data_cb.frame_tx[i][2]); } /* get the shift back out of the frame */ shift[0] = (data_cb.frame_tx[0][0] + data_cb.frame_tx[1][0] + data_cb.frame_tx[2][0] + data_cb.frame_tx[3][0]) / 4.0f; shift[1] = (data_cb.frame_tx[0][1] + data_cb.frame_tx[1][1] + data_cb.frame_tx[2][1] + data_cb.frame_tx[3][1]) / 4.0f; for (i = 0; i < 4; i++) { mul_m3_v3(rot_obmat, data_cb.frame_tx[i]); } for (i = 0; i < 4; i++) { normal_tri_v3(data_cb.normal_tx[i], zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]); plane_from_point_normal_v3(data_cb.plane_tx[i], data_cb.frame_tx[i], data_cb.normal_tx[i]); } /* initialize callback data */ copy_v4_fl(data_cb.dist_vals_sq, FLT_MAX); data_cb.tot = 0; /* run callback on all visible points */ BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb); if (data_cb.tot <= 1) { return false; } else { float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3]; float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3]; float plane_isect_pt_1[3], plane_isect_pt_2[3]; /* apply the dist-from-plane's to the transformed plane points */ for (i = 0; i < 4; i++) { mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], sqrtf_signed(data_cb.dist_vals_sq[i])); } if ((!isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, plane_tx[0], data_cb.normal_tx[0], plane_tx[2], data_cb.normal_tx[2])) || (!isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, plane_tx[1], data_cb.normal_tx[1], plane_tx[3], data_cb.normal_tx[3]))) { return false; } add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no); add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no); if (isect_line_line_v3(plane_isect_1, plane_isect_1_other, plane_isect_2, plane_isect_2_other, plane_isect_pt_1, plane_isect_pt_2) == 0) { return false; } else { float cam_plane_no[3] = {0.0f, 0.0f, -1.0f}; float plane_isect_delta[3]; float plane_isect_delta_len; mul_m3_v3(rot_obmat, cam_plane_no); sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1); plane_isect_delta_len = len_v3(plane_isect_delta); if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) { copy_v3_v3(r_co, plane_isect_pt_1); /* offset shift */ normalize_v3(plane_isect_1_no); madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len); } else { copy_v3_v3(r_co, plane_isect_pt_2); /* offset shift */ normalize_v3(plane_isect_2_no); madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len); } return true; } } }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; DerivedMesh *result; ScrewModifierData *ltmd = (ScrewModifierData *) md; const int useRenderParams = flag & MOD_APPLY_RENDER; int *origindex; int mpoly_index = 0; unsigned int step; unsigned int i, j; unsigned int i1, i2; unsigned int step_tot = useRenderParams ? ltmd->render_steps : ltmd->steps; const bool do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0; const int quad_ord[4] = { do_flip ? 3 : 0, do_flip ? 2 : 1, do_flip ? 1 : 2, do_flip ? 0 : 3, }; const int quad_ord_ofs[4] = { do_flip ? 2 : 0, do_flip ? 1 : 1, do_flip ? 0 : 2, do_flip ? 3 : 3, }; unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; const unsigned int totvert = (unsigned int)dm->getNumVerts(dm); const unsigned int totedge = (unsigned int)dm->getNumEdges(dm); const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm); unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */ unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */ /* UV Coords */ const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot); float uv_u_scale; float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX}; float uv_v_range_inv; float uv_axis_plane[4]; char axis_char = 'X'; bool close; float angle = ltmd->angle; float screw_ofs = ltmd->screw_ofs; float axis_vec[3] = {0.0f, 0.0f, 0.0f}; float tmp_vec1[3], tmp_vec2[3]; float mat3[3][3]; float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */ float mtx_tx_inv[4][4]; /* inverted */ float mtx_tmp_a[4][4]; unsigned int vc_tot_linked = 0; short other_axis_1, other_axis_2; const float *tmpf1, *tmpf2; unsigned int edge_offset; MPoly *mpoly_orig, *mpoly_new, *mp_new; MLoop *mloop_orig, *mloop_new, *ml_new; MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL; const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; /* don't do anything? */ if (!totvert) return CDDM_from_template(dm, 0, 0, 0, 0, 0); switch (ltmd->axis) { case 0: other_axis_1 = 1; other_axis_2 = 2; break; case 1: other_axis_1 = 0; other_axis_2 = 2; break; default: /* 2, use default to quiet warnings */ other_axis_1 = 0; other_axis_2 = 1; break; } axis_vec[ltmd->axis] = 1.0f; if (ltmd->ob_axis) { /* calc the matrix relative to the axis object */ invert_m4_m4(mtx_tmp_a, ob->obmat); copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat); mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); /* calc the axis vec */ mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */ normalize_v3(axis_vec); /* screw */ if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { /* find the offset along this axis relative to this objects matrix */ float totlen = len_v3(mtx_tx[3]); if (totlen != 0.0f) { float zero[3] = {0.0f, 0.0f, 0.0f}; float cp[3]; screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); } else { screw_ofs = 0.0f; } } /* angle */ #if 0 /* cant incluide this, not predictable enough, though quite fun. */ if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { float mtx3_tx[3][3]; copy_m3_m4(mtx3_tx, mtx_tx); float vec[3] = {0, 1, 0}; float cross1[3]; float cross2[3]; cross_v3_v3v3(cross1, vec, axis_vec); mul_v3_m3v3(cross2, mtx3_tx, cross1); { float c1[3]; float c2[3]; float axis_tmp[3]; cross_v3_v3v3(c1, cross2, axis_vec); cross_v3_v3v3(c2, axis_vec, c1); angle = angle_v3v3(cross1, c2); cross_v3_v3v3(axis_tmp, cross1, c2); normalize_v3(axis_tmp); if (len_v3v3(axis_tmp, axis_vec) > 1.0f) angle = -angle; } } #endif } else { /* exis char is used by i_rotate*/ axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */ /* useful to be able to use the axis vec in some cases still */ zero_v3(axis_vec); axis_vec[ltmd->axis] = 1.0f; } /* apply the multiplier */ angle *= (float)ltmd->iter; screw_ofs *= (float)ltmd->iter; uv_u_scale = 1.0f / (float)(step_tot); /* multiplying the steps is a bit tricky, this works best */ step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1); /* will the screw be closed? * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */ if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) && fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f)) { close = 1; step_tot--; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * step_tot) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * step_tot; screw_ofs = 0.0f; } else { close = 0; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * (step_tot - 1)) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * (step_tot - 1); } if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) { uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f)); } result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys); /* copy verts from mesh */ mvert_orig = dm->getVertArray(dm); medge_orig = dm->getEdgeArray(dm); mvert_new = result->getVertArray(result); mpoly_new = result->getPolyArray(result); mloop_new = result->getLoopArray(result); medge_new = result->getEdgeArray(result); if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) { CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); } origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */ if (mloopuv_layers_tot) { float zero_co[3] = {0}; plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec); } if (mloopuv_layers_tot) { unsigned int uv_lay; for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay); } if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) { const float v = dist_squared_to_plane_v3(mv_orig->co, uv_axis_plane); uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]); uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]); } uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]); uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]); } uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0]; uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f; } /* Set the locations of the first set of verts */ mv_new = mvert_new; mv_orig = mvert_orig; /* Copy the first set of edges */ med_orig = medge_orig; med_new = medge_new; for (i = 0; i < totedge; i++, med_orig++, med_new++) { med_new->v1 = med_orig->v1; med_new->v2 = med_orig->v2; med_new->crease = med_orig->crease; med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; } /* build polygon -> edge map */ if (totpoly) { MPoly *mp_orig; mpoly_orig = dm->getPolyArray(dm); mloop_orig = dm->getLoopArray(dm); edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__); memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge); vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__); memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { unsigned int loopstart = (unsigned int)mp_orig->loopstart; unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop; MLoop *ml_orig = &mloop_orig[loopstart]; unsigned int k; for (k = loopstart; k < loopend; k++, ml_orig++) { edge_poly_map[ml_orig->e] = i; vert_loop_map[ml_orig->v] = k; /* also order edges based on faces */ if (medge_new[ml_orig->e].v1 != ml_orig->v) { SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); } } } }
static bool camera_frame_fit_calc_from_data( CameraParams *params, CameraViewFrameData *data, float r_co[3], float *r_scale) { float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][3]; unsigned int i; if (data->tot <= 1) { return false; } if (params->is_ortho) { const float *cam_axis_x = data->camera_rotmat[0]; const float *cam_axis_y = data->camera_rotmat[1]; const float *cam_axis_z = data->camera_rotmat[2]; float dists[CAMERA_VIEWFRAME_NUM_PLANES]; float scale_diff; /* apply the dist-from-plane's to the transformed plane points */ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { dists[i] = sqrtf_signed(data->dist_vals_sq[i]); } if ((dists[0] + dists[2]) > (dists[1] + dists[3])) { scale_diff = (dists[1] + dists[3]) * (BLI_rctf_size_x(¶ms->viewplane) / BLI_rctf_size_y(¶ms->viewplane)); } else { scale_diff = (dists[0] + dists[2]) * (BLI_rctf_size_y(¶ms->viewplane) / BLI_rctf_size_x(¶ms->viewplane)); } *r_scale = params->ortho_scale - scale_diff; zero_v3(r_co); madd_v3_v3fl(r_co, cam_axis_x, (dists[2] - dists[0]) * 0.5f + params->shiftx * scale_diff); madd_v3_v3fl(r_co, cam_axis_y, (dists[1] - dists[3]) * 0.5f + params->shifty * scale_diff); madd_v3_v3fl(r_co, cam_axis_z, -(data->dist_to_cam - 1.0f - params->clipsta)); return true; } else { float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3]; float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3]; float plane_isect_pt_1[3], plane_isect_pt_2[3]; /* apply the dist-from-plane's to the transformed plane points */ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { mul_v3_v3fl(plane_tx[i], data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i])); } if ((!isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, plane_tx[0], data->normal_tx[0], plane_tx[2], data->normal_tx[2])) || (!isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, plane_tx[1], data->normal_tx[1], plane_tx[3], data->normal_tx[3]))) { return false; } add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no); add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no); if (isect_line_line_v3(plane_isect_1, plane_isect_1_other, plane_isect_2, plane_isect_2_other, plane_isect_pt_1, plane_isect_pt_2) != 0) { float cam_plane_no[3]; float plane_isect_delta[3]; float plane_isect_delta_len; float shift_fac = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y) / params->lens; /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */ negate_v3_v3(cam_plane_no, data->camera_rotmat[2]); sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1); plane_isect_delta_len = len_v3(plane_isect_delta); if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) { copy_v3_v3(r_co, plane_isect_pt_1); /* offset shift */ normalize_v3(plane_isect_1_no); madd_v3_v3fl(r_co, plane_isect_1_no, params->shifty * plane_isect_delta_len * shift_fac); } else { copy_v3_v3(r_co, plane_isect_pt_2); /* offset shift */ normalize_v3(plane_isect_2_no); madd_v3_v3fl(r_co, plane_isect_2_no, params->shiftx * plane_isect_delta_len * shift_fac); } return true; } } return false; }