static int mesh_bisect_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); /* both can be NULL, fallbacks values are used */ View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ED_view3d_context_rv3d(C); Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm; BMOperator bmop; float plane_co[3]; float plane_no[3]; float imat[4][4]; const float thresh = RNA_float_get(op->ptr, "threshold"); const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner"); const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer"); PropertyRNA *prop_plane_co; PropertyRNA *prop_plane_no; prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); if (RNA_property_is_set(op->ptr, prop_plane_co)) { RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co); } else { copy_v3_v3(plane_co, ED_view3d_cursor3d_get(scene, v3d)); RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); } prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); if (RNA_property_is_set(op->ptr, prop_plane_no)) { RNA_property_float_get_array(op->ptr, prop_plane_no, plane_no); } else { if (rv3d) { copy_v3_v3(plane_no, rv3d->viewinv[1]); } else { /* fallback... */ plane_no[0] = plane_no[1] = 0.0f; plane_no[2] = 1.0f; } RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); } /* -------------------------------------------------------------------- */ /* Modal support */ /* Note: keep this isolated, exec can work wihout this */ if ((op->customdata != NULL) && mesh_bisect_interactive_calc(C, op, em, plane_co, plane_no)) { /* write back to the props */ RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); } /* End Modal */ /* -------------------------------------------------------------------- */ bm = em->bm; invert_m4_m4(imat, obedit->obmat); mul_m4_v3(imat, plane_co); mul_mat3_m4_v3(imat, plane_no); EDBM_op_init(em, &bmop, op, "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b", BM_ELEM_SELECT, plane_co, plane_no, thresh, clear_inner, clear_outer); BMO_op_exec(bm, &bmop); EDBM_flag_disable_all(em, BM_ELEM_SELECT); if (use_fill) { float normal_fill[3]; BMOperator bmop_fill; BMOperator bmop_attr; normalize_v3_v3(normal_fill, plane_no); if (clear_outer == true && clear_inner == false) { negate_v3(normal_fill); } /* Fill */ BMO_op_initf( bm, &bmop_fill, op->flag, "triangle_fill edges=%S normal=%v use_dissolve=%b", &bmop, "geom_cut.out", normal_fill, true); BMO_op_exec(bm, &bmop_fill); /* Copy Attributes */ BMO_op_initf(bm, &bmop_attr, op->flag, "face_attribute_fill faces=%S use_normals=%b use_data=%b", &bmop_fill, "geom.out", false, true); BMO_op_exec(bm, &bmop_attr); BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); BMO_op_finish(bm, &bmop_attr); BMO_op_finish(bm, &bmop_fill); } BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; } else { EDBM_update_generic(em, true, true); EDBM_selectmode_flush(em); return OPERATOR_FINISHED; } }
/* called from within the core where_is_pose loop, all animsystems and constraints were executed & assigned. Now as last we do an IK pass */ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) { float R_parmat[3][3], identity[3][3]; float iR_parmat[3][3]; float R_bonemat[3][3]; float goalrot[3][3], goalpos[3]; float rootmat[4][4], imat[4][4]; float goal[4][4], goalinv[4][4]; float irest_basis[3][3], full_basis[3][3]; float end_pose[4][4], world_pose[4][4]; float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL; float resultinf=0.0f; int a, flag, hasstretch=0, resultblend=0; bPoseChannel *pchan; IK_Segment *seg, *parent, **iktree, *iktarget; IK_Solver *solver; PoseTarget *target; bKinematicConstraint *data, *poleangledata=NULL; Bone *bone; if (tree->totchannel == 0) return; iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree"); for(a=0; a<tree->totchannel; a++) { pchan= tree->pchan[a]; bone= pchan->bone; /* set DoF flag */ flag= 0; if(!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP)) flag |= IK_XDOF; if(!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP)) flag |= IK_YDOF; if(!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP)) flag |= IK_ZDOF; if(tree->stretch && (pchan->ikstretch > 0.0)) { flag |= IK_TRANS_YDOF; hasstretch = 1; } seg= iktree[a]= IK_CreateSegment(flag); /* find parent */ if(a == 0) parent= NULL; else parent= iktree[tree->parent[a]]; IK_SetParent(seg, parent); /* get the matrix that transforms from prevbone into this bone */ copy_m3_m4(R_bonemat, pchan->pose_mat); /* gather transformations for this IK segment */ if (pchan->parent) copy_m3_m4(R_parmat, pchan->parent->pose_mat); else unit_m3(R_parmat); /* bone offset */ if (pchan->parent && (a > 0)) sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail); else /* only root bone (a = 0) has no parent */ start[0]= start[1]= start[2]= 0.0f; /* change length based on bone size */ length= bone->length*len_v3(R_bonemat[1]); /* compute rest basis and its inverse */ copy_m3_m3(rest_basis, bone->bone_mat); copy_m3_m3(irest_basis, bone->bone_mat); transpose_m3(irest_basis); /* compute basis with rest_basis removed */ invert_m3_m3(iR_parmat, R_parmat); mul_m3_m3m3(full_basis, iR_parmat, R_bonemat); mul_m3_m3m3(basis, irest_basis, full_basis); /* basis must be pure rotation */ normalize_m3(basis); /* transform offset into local bone space */ normalize_m3(iR_parmat); mul_m3_v3(iR_parmat, start); IK_SetTransform(seg, start, rest_basis, basis, length); if (pchan->ikflag & BONE_IK_XLIMIT) IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); if (pchan->ikflag & BONE_IK_YLIMIT) IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); if (pchan->ikflag & BONE_IK_ZLIMIT) IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); if(tree->stretch && (pchan->ikstretch > 0.0)) { float ikstretch = pchan->ikstretch*pchan->ikstretch; IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99)); IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10); } } solver= IK_CreateSolver(iktree[0]); /* set solver goals */ /* first set the goal inverse transform, assuming the root of tree was done ok! */ pchan= tree->pchan[0]; if (pchan->parent) /* transform goal by parent mat, so this rotation is not part of the segment's basis. otherwise rotation limits do not work on the local transform of the segment itself. */ copy_m4_m4(rootmat, pchan->parent->pose_mat); else unit_m4(rootmat); VECCOPY(rootmat[3], pchan->pose_head); mul_m4_m4m4(imat, rootmat, ob->obmat); invert_m4_m4(goalinv, imat); for (target=tree->targets.first; target; target=target->next) { float polepos[3]; int poleconstrain= 0; data= (bKinematicConstraint*)target->con->data; /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though * strictly speaking, it is a posechannel) */ get_constraint_target_matrix(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); /* and set and transform goal */ mul_m4_m4m4(goal, rootmat, goalinv); VECCOPY(goalpos, goal[3]); copy_m3_m4(goalrot, goal); /* same for pole vector target */ if(data->poletar) { get_constraint_target_matrix(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); if(data->flag & CONSTRAINT_IK_SETANGLE) { /* don't solve IK when we are setting the pole angle */ break; } else { mul_m4_m4m4(goal, rootmat, goalinv); VECCOPY(polepos, goal[3]); poleconstrain= 1; /* for pole targets, we blend the result of the ik solver * instead of the target position, otherwise we can't get * a smooth transition */ resultblend= 1; resultinf= target->con->enforce; if(data->flag & CONSTRAINT_IK_GETANGLE) { poleangledata= data; data->flag &= ~CONSTRAINT_IK_GETANGLE; } } } /* do we need blending? */ if (!resultblend && target->con->enforce!=1.0) { float q1[4], q2[4], q[4]; float fac= target->con->enforce; float mfac= 1.0-fac; pchan= tree->pchan[target->tip]; /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); VECCOPY(end_pose[3], pchan->pose_tail); mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL); /* blend position */ goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0]; goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1]; goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2]; /* blend rotation */ mat3_to_quat( q1,goalrot); mat4_to_quat( q2,world_pose); interp_qt_qtqt(q, q1, q2, mfac); quat_to_mat3( goalrot,q); } iktarget= iktree[target->tip]; if(data->weight != 0.0) { if(poleconstrain) IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, polepos, data->poleangle, (poleangledata == data)); IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); } if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0)) if((data->flag & CONSTRAINT_IK_AUTO)==0) IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight); } /* solve */ IK_Solve(solver, 0.0f, tree->iterations); if(poleangledata) poleangledata->poleangle= IK_SolverGetPoleAngle(solver); IK_FreeSolver(solver); /* gather basis changes */ tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change"); if(hasstretch) ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch"); for(a=0; a<tree->totchannel; a++) { IK_GetBasisChange(iktree[a], tree->basis_change[a]); if(hasstretch) { /* have to compensate for scaling received from parent */ float parentstretch, stretch; pchan= tree->pchan[a]; parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0; if(tree->stretch && (pchan->ikstretch > 0.0)) { float trans[3], length; IK_GetTranslationChange(iktree[a], trans); length= pchan->bone->length*len_v3(pchan->pose_mat[1]); ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length; } else ikstretch[a] = 1.0; stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch; mul_v3_fl(tree->basis_change[a][0], stretch); mul_v3_fl(tree->basis_change[a][1], stretch); mul_v3_fl(tree->basis_change[a][2], stretch); } if(resultblend && resultinf!=1.0f) { unit_m3(identity); blend_m3_m3m3(tree->basis_change[a], identity, tree->basis_change[a], resultinf); } IK_FreeSegment(iktree[a]); } MEM_freeN(iktree); if(ikstretch) MEM_freeN(ikstretch); }
/* 0 == do center, 1 == center new, 2 == center cursor */ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around) { Object *obedit = scene->obedit; // XXX get from context EditBone *ebone; bArmature *arm = ob->data; float cent[3]; /* Put the armature into editmode */ if (ob != obedit) { ED_armature_to_edit(arm); obedit = NULL; /* we cant use this so behave as if there is no obedit */ } /* Find the centerpoint */ if (centermode == 2) { copy_v3_v3(cent, cursor); invert_m4_m4(ob->imat, ob->obmat); mul_m4_v3(ob->imat, cent); } else { if (around == V3D_AROUND_CENTER_MEAN) { int total = 0; zero_v3(cent); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { total += 2; add_v3_v3(cent, ebone->head); add_v3_v3(cent, ebone->tail); } if (total) { mul_v3_fl(cent, 1.0f / (float)total); } } else { float min[3], max[3]; INIT_MINMAX(min, max); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { minmax_v3v3_v3(min, max, ebone->head); minmax_v3v3_v3(min, max, ebone->tail); } mid_v3_v3v3(cent, min, max); } } /* Do the adjustments */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { sub_v3_v3(ebone->head, cent); sub_v3_v3(ebone->tail, cent); } /* Turn the list into an armature */ if (obedit == NULL) { ED_armature_from_edit(arm); ED_armature_edit_free(arm); } /* Adjust object location for new centerpoint */ if (centermode && obedit == NULL) { mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */ add_v3_v3(ob->loc, cent); } }
/* don't set windows active in here, is used by renderwin too */ void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d) { if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */ if (v3d->camera) { BKE_object_where_is_calc(scene, v3d->camera); obmat_to_viewmat(rv3d, v3d->camera); } else { quat_to_mat4(rv3d->viewmat, rv3d->viewquat); rv3d->viewmat[3][2] -= rv3d->dist; } } else { bool use_lock_ofs = false; /* should be moved to better initialize later on XXX */ if (rv3d->viewlock & RV3D_LOCKED) ED_view3d_lock(rv3d); quat_to_mat4(rv3d->viewmat, rv3d->viewquat); if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist; if (v3d->ob_centre) { Object *ob = v3d->ob_centre; float vec[3]; copy_v3_v3(vec, ob->obmat[3]); if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone); if (pchan) { copy_v3_v3(vec, pchan->pose_mat[3]); mul_m4_v3(ob->obmat, vec); } } translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); use_lock_ofs = true; } else if (v3d->ob_centre_cursor) { float vec[3]; copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d)); translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); use_lock_ofs = true; } else { translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]); } /* lock offset */ if (use_lock_ofs) { float persmat[4][4], persinv[4][4]; float vec[3]; /* we could calculate the real persmat/persinv here * but it would be unreliable so better to later */ mul_m4_m4m4(persmat, rv3d->winmat, rv3d->viewmat); invert_m4_m4(persinv, persmat); mul_v2_v2fl(vec, rv3d->ofs_lock, rv3d->is_persp ? rv3d->dist : 1.0f); vec[2] = 0.0f; mul_mat3_m4_v3(persinv, vec); translate_m4(rv3d->viewmat, vec[0], vec[1], vec[2]); } /* end lock offset */ } }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; DerivedMesh *result; ScrewModifierData *ltmd = (ScrewModifierData *) md; const bool use_render_params = (flag & MOD_APPLY_RENDER) != 0; int *origindex; int mpoly_index = 0; unsigned int step; unsigned int i, j; unsigned int i1, i2; unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps; const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 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, 1, do_flip ? 0 : 2, 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_signed_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); } } } }
LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob) { /* we make an array with all differences */ Lattice *lt = oblatt->data; BPoint *bp; DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL; const float *co = dl ? dl->verts : NULL; float *fp, imat[4][4]; float fu, fv, fw; int u, v, w; float *latticedata; float latmat[4][4]; LatticeDeformData *lattice_deform_data; if (lt->editlatt) lt = lt->editlatt->latt; bp = lt->def; fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw, "latticedata"); /* for example with a particle system: (ob == NULL) */ if (ob == NULL) { /* in deformspace, calc matrix */ invert_m4_m4(latmat, oblatt->obmat); /* back: put in deform array */ invert_m4_m4(imat, latmat); } else { /* in deformspace, calc matrix */ invert_m4_m4(imat, oblatt->obmat); mul_m4_m4m4(latmat, imat, ob->obmat); /* back: put in deform array */ invert_m4_m4(imat, latmat); } for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) { for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) { for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) { if (dl) { fp[0] = co[0] - fu; fp[1] = co[1] - fv; fp[2] = co[2] - fw; } else { fp[0] = bp->vec[0] - fu; fp[1] = bp->vec[1] - fv; fp[2] = bp->vec[2] - fw; } mul_mat3_m4_v3(imat, fp); } } } lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data"); lattice_deform_data->latticedata = latticedata; lattice_deform_data->object = oblatt; copy_m4_m4(lattice_deform_data->latmat, latmat); return lattice_deform_data; }
static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, Object *ob, DerivedMesh *dm) { float (*coords)[3], (*co)[3]; MLoopUV *mloop_uv; MTexPoly *mtexpoly, *mt = NULL; int i, numVerts, numPolys, numLoops; Image *image = umd->image; MPoly *mpoly, *mp; MLoop *mloop; const bool override_image = (umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0; Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; int num_projectors = 0; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float aspx = umd->aspectx ? umd->aspectx : 1.0f; float aspy = umd->aspecty ? umd->aspecty : 1.0f; float scax = umd->scalex ? umd->scalex : 1.0f; float scay = umd->scaley ? umd->scaley : 1.0f; int free_uci = 0; for (i = 0; i < umd->num_projectors; ++i) if (umd->projectors[i]) projectors[num_projectors++].ob = umd->projectors[i]; if (num_projectors == 0) return dm; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) return dm; /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); /* calculate a projection matrix and normal for each projector */ for (i = 0; i < num_projectors; ++i) { float tmpmat[4][4]; float offsetmat[4][4]; Camera *cam = NULL; /* calculate projection matrix */ invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat); projectors[i].uci = NULL; if (projectors[i].ob->type == OB_CAMERA) { cam = (Camera *)projectors[i].ob->data; if (cam->type == CAM_PANO) { projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy); BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay); free_uci = 1; } else { CameraParams params; /* setup parameters */ BKE_camera_params_init(¶ms); BKE_camera_params_from_object(¶ms, projectors[i].ob); /* compute matrix, viewplane, .. */ BKE_camera_params_compute_viewplane(¶ms, 1, 1, aspx, aspy); /* scale the view-plane */ params.viewplane.xmin *= scax; params.viewplane.xmax *= scax; params.viewplane.ymin *= scay; params.viewplane.ymax *= scay; BKE_camera_params_compute_matrix(¶ms); mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat); } } else { copy_m4_m4(tmpmat, projectors[i].projmat); } unit_m4(offsetmat); mul_mat3_m4_fl(offsetmat, 0.5); offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); /* calculate worldspace projector normal (for best projector test) */ projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal); } numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); /* make sure we are not modifying the original UV map */ mloop_uv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); /* can be NULL */ mt = mtexpoly = CustomData_duplicate_referenced_layer_named(&dm->polyData, CD_MTEXPOLY, uvname, numPolys); numVerts = dm->getNumVerts(dm); coords = MEM_malloc_arrayN(numVerts, sizeof(*coords), "uvprojectModifier_do coords"); dm->getVertCos(dm, coords); /* convert coords to world space */ for (i = 0, co = coords; i < numVerts; ++i, ++co) mul_m4_v3(ob->obmat, *co); /* if only one projector, project coords to UVs */ if (num_projectors == 1 && projectors[0].uci == NULL) for (i = 0, co = coords; i < numVerts; ++i, ++co) mul_project_m4_v3(projectors[0].projmat, *co); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* apply coords as UVs, and apply image if tfaces are new */ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp, ++mt) { if (override_image || !image || (mtexpoly == NULL || mt->tpage == image)) { if (num_projectors == 1) { if (projectors[0].uci) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci); } while (fidx--); } else { /* apply transformed coords as UVs */ unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]); } while (fidx--); } } else { /* multiple projectors, select the closest to face normal direction */ float face_no[3]; int j; Projector *best_projector; float best_dot; /* get the untransformed face normal */ BKE_mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no); /* find the projector which the face points at most directly * (projector normal with largest dot product is best) */ best_dot = dot_v3v3(projectors[0].normal, face_no); best_projector = &projectors[0]; for (j = 1; j < num_projectors; ++j) { float tmp_dot = dot_v3v3(projectors[j].normal, face_no); if (tmp_dot > best_dot) { best_dot = tmp_dot; best_projector = &projectors[j]; } } if (best_projector->uci) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci); } while (fidx--); } else { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]); } while (fidx--); } } } if (override_image && mtexpoly) { mt->tpage = image; } } MEM_freeN(coords); if (free_uci) { int j; for (j = 0; j < num_projectors; ++j) { if (projectors[j].uci) { MEM_freeN(projectors[j].uci); } } } /* Mark tessellated CD layers as dirty. */ dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id) { std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX; int totjoint = 0; for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) { if (is_bone_defgroup(ob_arm, def)) totjoint++; } COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(totjoint); //BLI_countlist(defbase)); source.setAccessorStride(16); source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); param.push_back("TRANSFORM"); source.prepareToAppendValues(); bPose *pose = ob_arm->pose; bArmature *arm = (bArmature *)ob_arm->data; int flag = arm->flag; // put armature in rest position if (!(arm->flag & ARM_RESTPOS)) { arm->flag |= ARM_RESTPOS; BKE_pose_where_is(scene, ob_arm); } for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) { if (is_bone_defgroup(ob_arm, def)) { bPoseChannel *pchan = BKE_pose_channel_find_name(pose, def->name); float mat[4][4]; float world[4][4]; float inv_bind_mat[4][4]; // OPEN_SIM_COMPATIBILITY if (export_settings->open_sim) { // Only translations, no rotation vs armature float temp[4][4]; unit_m4(temp); copy_v3_v3(temp[3], pchan->bone->arm_mat[3]); mul_m4_m4m4(world, ob_arm->obmat, temp); } else { // make world-space matrix, arm_mat is armature-space mul_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat); } invert_m4_m4(mat, world); converter.mat4_to_dae(inv_bind_mat, mat); source.appendValues(inv_bind_mat); } } // back from rest positon if (!(flag & ARM_RESTPOS)) { arm->flag = flag; BKE_pose_where_is(scene, ob_arm); } source.finish(); return source_id; }
static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object, MovieTrackingTrack *track, char axis) { Object *camera = get_camera_with_movieclip(scene, clip); const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0; bool flip = false; float mat[4][4], vec[3], obmat[4][4], dvec[3]; BKE_object_to_mat4(ob, obmat); BKE_tracking_get_camera_object_matrix(scene, camera, mat); mul_v3_m4v3(vec, mat, track->bundle_pos); copy_v3_v3(dvec, vec); if (!is_camera) { float imat[4][4]; object_solver_inverted_matrix(scene, ob, imat); mul_v3_m4v3(vec, imat, vec); invert_m4_m4(imat, obmat); mul_v3_m4v3(dvec, imat, vec); sub_v3_v3(vec, obmat[3]); } if (len_squared_v2(vec) < (1e-3f * 1e-3f)) { return; } unit_m4(mat); if (axis == 'X') { if (fabsf(dvec[1]) < 1e-3f) { flip = true; mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f; mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f; mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f; } else { copy_v3_v3(mat[0], vec); if (is_camera || fabsf(vec[2]) < 1e-3f) { mat[0][2] = 0.0f; mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f; cross_v3_v3v3(mat[1], mat[2], mat[0]); } else { vec[2] = 0.0f; cross_v3_v3v3(mat[1], mat[0], vec); cross_v3_v3v3(mat[2], mat[0], mat[1]); } } } else { if (fabsf(dvec[0]) < 1e-3f) { flip = true; mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f; mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f; mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f; } else { copy_v3_v3(mat[1], vec); if (is_camera || fabsf(vec[2]) < 1e-3f) { mat[1][2] = 0.0f; mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f; cross_v3_v3v3(mat[0], mat[1], mat[2]); } else { vec[2] = 0.0f; cross_v3_v3v3(mat[0], vec, mat[1]); cross_v3_v3v3(mat[2], mat[0], mat[1]); } } } normalize_v3(mat[0]); normalize_v3(mat[1]); normalize_v3(mat[2]); if (is_camera) { invert_m4(mat); mul_m4_m4m4(mat, mat, obmat); } else { if (!flip) { float lmat[4][4], ilmat[4][4], rmat[3][3]; BKE_object_rot_to_mat3(ob, rmat, true); invert_m3(rmat); mul_m4_m4m3(mat, mat, rmat); unit_m4(lmat); copy_v3_v3(lmat[3], obmat[3]); invert_m4_m4(ilmat, lmat); mul_m4_series(mat, lmat, mat, ilmat, obmat); } else { mul_m4_m4m4(mat, obmat, mat); } } BKE_object_apply_mat4(ob, mat, 0, 0); }
static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget); float vec[3], mat[4][4], dmat[4][4]; int i, *index_pt; const float falloff_squared = hmd->falloff * hmd->falloff; /* for faster comparisons */ MDeformVert *dvert; int defgrp_index, max_dvert; /* get world-space matrix of target, corrected for the space the verts are in */ if (hmd->subtarget[0] && pchan) { /* bone target if there's a matching pose-channel */ mul_m4_m4m4(dmat, hmd->object->obmat, pchan->pose_mat); } else { /* just object target */ copy_m4_m4(dmat, hmd->object->obmat); } invert_m4_m4(ob->imat, ob->obmat); mul_serie_m4(mat, ob->imat, dmat, hmd->parentinv, NULL, NULL, NULL, NULL, NULL); modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index); max_dvert = (dvert) ? numVerts : 0; /* Regarding index range checking below. * * This should always be true and I don't generally like * "paranoid" style code like this, but old files can have * indices that are out of range because old blender did * not correct them on exit editmode. - zr */ if (hmd->force == 0.0f) { /* do nothing, avoid annoying checks in the loop */ } else if (hmd->indexar) { /* vertex indices? */ const float fac_orig = hmd->force; float fac; const int *origindex_ar; /* if DerivedMesh is present and has original index data, use it */ if (dm && (origindex_ar = dm->getVertDataArray(dm, CD_ORIGINDEX))) { for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { if (*index_pt < numVerts) { int j; for (j = 0; j < numVerts; j++) { if (origindex_ar[j] == *index_pt) { float *co = vertexCos[j]; if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) { if (dvert) fac *= defvert_find_weight(dvert + j, defgrp_index); if (fac) { mul_v3_m4v3(vec, mat, co); interp_v3_v3v3(co, co, vec, fac); } } } } } } } else { /* missing dm or ORIGINDEX */ for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) { if (*index_pt < numVerts) { float *co = vertexCos[*index_pt]; if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) { if (dvert) fac *= defvert_find_weight(dvert + (*index_pt), defgrp_index); if (fac) { mul_v3_m4v3(vec, mat, co); interp_v3_v3v3(co, co, vec, fac); } } } } } } else if (dvert) { /* vertex group hook */ const float fac_orig = hmd->force; for (i = 0; i < max_dvert; i++, dvert++) { float fac; float *co = vertexCos[i]; if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) { fac *= defvert_find_weight(dvert, defgrp_index); if (fac) { mul_v3_m4v3(vec, mat, co); interp_v3_v3v3(co, co, vec, fac); } } } } }
void get_texture_coords(MappingInfoModifierData *dmd, Object *ob, DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts) { int i; int texmapping = dmd->texmapping; float mapob_imat[4][4]; if (texmapping == MOD_DISP_MAP_OBJECT) { if (dmd->map_object) invert_m4_m4(mapob_imat, dmd->map_object->obmat); else /* if there is no map object, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } /* UVs need special handling, since they come from faces */ if (texmapping == MOD_DISP_MAP_UV) { if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { MPoly *mpoly = dm->getPolyArray(dm); MPoly *mp; MLoop *mloop = dm->getLoopArray(dm); char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); int numPolys = dm->getNumPolys(dm); char uvname[MAX_CUSTOMDATA_LAYER_NAME]; MLoopUV *mloop_uv; CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, dmd->uvlayer_name, uvname); mloop_uv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname); /* verts are given the UV from the first face that uses them */ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) { unsigned int fidx = mp->totloop - 1; do { unsigned int lidx = mp->loopstart + fidx; unsigned int vidx = mloop[lidx].v; if (done[vidx] == 0) { /* remap UVs from [0, 1] to [-1, 1] */ texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f; texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f; done[vidx] = 1; } } while (fidx--); } MEM_freeN(done); return; } else /* if there are no UVs, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } for (i = 0; i < numVerts; ++i, ++co, ++texco) { switch (texmapping) { case MOD_DISP_MAP_LOCAL: copy_v3_v3(*texco, *co); break; case MOD_DISP_MAP_GLOBAL: mul_v3_m4v3(*texco, ob->obmat, *co); break; case MOD_DISP_MAP_OBJECT: mul_v3_m4v3(*texco, ob->obmat, *co); mul_m4_v3(mapob_imat, *texco); break; } } }
static DerivedMesh *explodeMesh(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Scene *scene, Object *ob, DerivedMesh *to_explode) { DerivedMesh *explode, *dm = to_explode; MFace *mf = NULL, *mface; /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL, *pars = psmd->psys->particles; ParticleKey state, birth; EdgeHash *vertpahash; EdgeHashIterator *ehi; float *vertco = NULL, imat[4][4]; float rot[4]; float cfra; /* float timestep; */ const int *facepa = emd->facepa; int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; int i, v, u; unsigned int ed_v1, ed_v2, mindex = 0; MTFace *mtface = NULL, *mtf; totface = dm->getNumTessFaces(dm); totvert = dm->getNumVerts(dm); mface = dm->getTessFaceArray(dm); totpart = psmd->psys->totpart; sim.scene = scene; sim.ob = ob; sim.psys = psmd->psys; sim.psmd = psmd; /* timestep = psys_get_timestep(&sim); */ cfra = BKE_scene_frame_get(scene); /* hash table for vertice <-> particle relations */ vertpahash = BLI_edgehash_new(__func__); for (i = 0; i < totface; i++) { if (facepa[i] != totpart) { pa = pars + facepa[i]; if ((pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) || (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) || (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0)) { delface++; continue; } } /* do mindex + totvert to ensure the vertex index to be the first * with BLI_edgehashIterator_getKey */ if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) mindex = totvert + totpart; else mindex = totvert + facepa[i]; mf = &mface[i]; /* set face vertices to exist in particle group */ BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL); if (mf->v4) BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL); } /* make new vertice indexes & count total vertices after duplication */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(totdup)); totdup++; } BLI_edgehashIterator_free(ehi); /* the final duplicated vertices */ explode = CDDM_from_template(dm, totdup, 0, totface - delface, 0, 0); mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname); /*dupvert = CDDM_get_verts(explode);*/ /* getting back to object space */ invert_m4_m4(imat, ob->obmat); psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* duplicate & displace vertices */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { MVert source; MVert *dest; /* get particle + vertex from hash */ BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); ed_v2 -= totvert; v = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi)); dm->getVert(dm, ed_v1, &source); dest = CDDM_get_vert(explode, v); DM_copy_vert_data(dm, explode, ed_v1, v, 1); *dest = source; if (ed_v2 != totpart) { /* get particle */ pa = pars + ed_v2; psys_get_birth_coordinates(&sim, pa, &birth, 0, 0); state.time = cfra; psys_get_particle_state(&sim, ed_v2, &state, 1); vertco = CDDM_get_vert(explode, v)->co; mul_m4_v3(ob->obmat, vertco); sub_v3_v3(vertco, birth.co); /* apply rotation, size & location */ sub_qt_qtqt(rot, state.rot, birth.rot); mul_qt_v3(rot, vertco); if (emd->flag & eExplodeFlag_PaSize) mul_v3_fl(vertco, pa->size); add_v3_v3(vertco, state.co); mul_m4_v3(imat, vertco); } } BLI_edgehashIterator_free(ehi); /*map new vertices to faces*/ for (i = 0, u = 0; i < totface; i++) { MFace source; int orig_v4; if (facepa[i] != totpart) { pa = pars + facepa[i]; if (pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) continue; if (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) continue; if (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0) continue; } dm->getTessFace(dm, i, &source); mf = CDDM_get_tessface(explode, u); orig_v4 = source.v4; if (facepa[i] != totpart && cfra < pa->time) mindex = totvert + totpart; else mindex = totvert + facepa[i]; source.v1 = edgecut_get(vertpahash, source.v1, mindex); source.v2 = edgecut_get(vertpahash, source.v2, mindex); source.v3 = edgecut_get(vertpahash, source.v3, mindex); if (source.v4) source.v4 = edgecut_get(vertpahash, source.v4, mindex); DM_copy_tessface_data(dm, explode, i, u, 1); *mf = source; /* override uv channel for particle age */ if (mtface) { float age = (cfra - pa->time) / pa->lifetime; /* Clamp to this range to avoid flipping to the other side of the coordinates. */ CLAMP(age, 0.001f, 0.999f); mtf = mtface + u; mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age; mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f; } test_index_face(mf, &explode->faceData, u, (orig_v4 ? 4 : 3)); u++; } /* cleanup */ BLI_edgehash_free(vertpahash, NULL); /* finalization */ CDDM_calc_edges_tessface(explode); CDDM_tessfaces_to_faces(explode); explode->dirty |= DM_DIRTY_NORMALS; if (psmd->psys->lattice_deform_data) { end_latt_deform(psmd->psys->lattice_deform_data); psmd->psys->lattice_deform_data = NULL; } return explode; }
int join_mesh_exec(bContext *C, wmOperator *op) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); Material **matar, *ma; Mesh *me; MVert *mvert, *mv; MEdge *medge = NULL; MFace *mface = NULL; Key *key, *nkey=NULL; KeyBlock *kb, *okb, *kbn; float imat[4][4], cmat[4][4], *fp1, *fp2, curpos; int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0; int vertofs, *matmap=NULL; int i, j, index, haskey=0, edgeofs, faceofs; bDeformGroup *dg, *odg; MDeformVert *dvert; CustomData vdata, edata, fdata; if(scene->obedit) { BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode"); return OPERATOR_CANCELLED; } /* ob is the object we are adding geometry to */ if(!ob || ob->type!=OB_MESH) { BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh"); return OPERATOR_CANCELLED; } /* count & check */ CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { if(base->object->type==OB_MESH) { me= base->object->data; totvert+= me->totvert; totedge+= me->totedge; totface+= me->totface; totmat+= base->object->totcol; if(base->object == ob) ok= 1; /* check for shapekeys */ if(me->key) haskey++; } } CTX_DATA_END; /* that way the active object is always selected */ if(ok==0) { BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh"); return OPERATOR_CANCELLED; } /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */ me= (Mesh *)ob->data; key= me->key; if(totvert==0 || totvert==me->totvert) { BKE_report(op->reports, RPT_WARNING, "No mesh data to join"); return OPERATOR_CANCELLED; } if(totvert > MESH_MAX_VERTS) { BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert); return OPERATOR_CANCELLED; } /* new material indices and material array */ matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar"); if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap"); totcol= ob->totcol; /* obact materials in new main array, is nicer start! */ for(a=0; a<ob->totcol; a++) { matar[a]= give_current_material(ob, a+1); id_us_plus((ID *)matar[a]); /* increase id->us : will be lowered later */ } /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders * with arrays that are large enough to hold shapekey data for all meshes * - if destination mesh didn't have shapekeys, but we encountered some in the meshes we're * joining, set up a new keyblock and assign to the mesh */ if(key) { /* make a duplicate copy that will only be used here... (must remember to free it!) */ nkey= copy_key(key); /* for all keys in old block, clear data-arrays */ for(kb= key->block.first; kb; kb= kb->next) { if(kb->data) MEM_freeN(kb->data); kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey"); kb->totelem= totvert; kb->weights= NULL; } } else if(haskey) { /* add a new key-block and add to the mesh */ key= me->key= add_key((ID *)me); key->type = KEY_RELATIVE; } /* first pass over objects - copying materials and vertexgroups across */ CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { /* only act if a mesh, and not the one we're joining to */ if((ob!=base->object) && (base->object->type==OB_MESH)) { me= base->object->data; /* Join this object's vertex groups to the base one's */ for(dg=base->object->defbase.first; dg; dg=dg->next) { /* See if this group exists in the object (if it doesn't, add it to the end) */ if(!defgroup_find_name(ob, dg->name)) { odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup"); memcpy(odg, dg, sizeof(bDeformGroup)); BLI_addtail(&ob->defbase, odg); } } if(ob->defbase.first && ob->actdef==0) ob->actdef=1; if(me->totvert) { /* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */ if(totcol < MAXMAT-1) { for(a=1; a<=base->object->totcol; a++) { ma= give_current_material(base->object, a); for(b=0; b<totcol; b++) { if(ma == matar[b]) break; } if(b==totcol) { matar[b]= ma; if(ma) ma->id.us++; totcol++; } if(totcol>=MAXMAT-1) break; } } /* if this mesh has shapekeys, check if destination mesh already has matching entries too */ if(me->key && key) { for(kb= me->key->block.first; kb; kb= kb->next) { /* if key doesn't exist in destination mesh, add it */ if(key_get_named_keyblock(key, kb->name) == NULL) { /* copy this existing one over to the new shapekey block */ kbn= MEM_dupallocN(kb); kbn->prev= kbn->next= NULL; /* adjust adrcode and other settings to fit (allocate a new data-array) */ kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey"); kbn->totelem= totvert; kbn->weights= NULL; okb= key->block.last; curpos= (okb) ? okb->pos : -0.1f; if(key->type == KEY_RELATIVE) kbn->pos= curpos + 0.1f; else kbn->pos= curpos; BLI_addtail(&key->block, kbn); kbn->adrcode= key->totkey; key->totkey++; if(key->totkey==1) key->refkey= kbn; // XXX 2.5 Animato #if 0 /* also, copy corresponding ipo-curve to ipo-block if applicable */ if(me->key->ipo && key->ipo) { // FIXME... this is a luxury item! puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now..."); } #endif } } } } } } CTX_DATA_END; /* setup new data for destination mesh */ memset(&vdata, 0, sizeof(vdata)); memset(&edata, 0, sizeof(edata)); memset(&fdata, 0, sizeof(fdata)); mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface); vertofs= 0; edgeofs= 0; faceofs= 0; /* inverse transform for all selected meshes in this object */ invert_m4_m4(imat, ob->obmat); CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) { /* only join if this is a mesh */ if(base->object->type==OB_MESH) { me= base->object->data; if(me->totvert) { /* standard data */ CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert); /* vertex groups */ dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT); /* NB: vertex groups here are new version */ if(dvert) { for(i=0; i<me->totvert; i++) { for(j=0; j<dvert[i].totweight; j++) { /* Find the old vertex group */ odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr); if(odg) { /* Search for a match in the new object, and set new index */ for(dg=ob->defbase.first, index=0; dg; dg=dg->next, index++) { if(!strcmp(dg->name, odg->name)) { dvert[i].dw[j].def_nr = index; break; } } } } } } /* if this is the object we're merging into, no need to do anything */ if(base->object != ob) { /* watch this: switch matmul order really goes wrong */ mul_m4_m4m4(cmat, base->object->obmat, imat); /* transform vertex coordinates into new space */ for(a=0, mv=mvert; a < me->totvert; a++, mv++) { mul_m4_v3(cmat, mv->co); } /* for each shapekey in destination mesh: * - if there's a matching one, copy it across (will need to transform vertices into new space...) * - otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space) */ if(key) { /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */ for(kb= key->block.first; kb; kb= kb->next) { /* get pointer to where to write data for this mesh in shapekey's data array */ fp1= ((float *)kb->data) + (vertofs*3); /* check if this mesh has such a shapekey */ okb= key_get_named_keyblock(me->key, kb->name); if(okb) { /* copy this mesh's shapekey to the destination shapekey (need to transform first) */ fp2= ((float *)(okb->data)); for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) { VECCOPY(fp1, fp2); mul_m4_v3(cmat, fp1); } } else { /* copy this mesh's vertex coordinates to the destination shapekey */ mv= mvert; for(a=0; a < me->totvert; a++, fp1+=3, mv++) { VECCOPY(fp1, mv->co); } } } } } else { /* for each shapekey in destination mesh: * - if it was an 'original', copy the appropriate data from nkey * - otherwise, copy across plain coordinates (no need to transform coordinates) */ if(key) { for(kb= key->block.first; kb; kb= kb->next) { /* get pointer to where to write data for this mesh in shapekey's data array */ fp1= ((float *)kb->data) + (vertofs*3); /* check if this was one of the original shapekeys */ okb= key_get_named_keyblock(nkey, kb->name); if(okb) { /* copy this mesh's shapekey to the destination shapekey */ fp2= ((float *)(okb->data)); for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) { VECCOPY(fp1, fp2); } } else { /* copy base-coordinates to the destination shapekey */ mv= mvert; for(a=0; a < me->totvert; a++, fp1+=3, mv++) { VECCOPY(fp1, mv->co); } } } } } /* advance mvert pointer to end of base mesh's data */ mvert+= me->totvert; } if(me->totface) { /* make mapping for materials */ for(a=1; a<=base->object->totcol; a++) { ma= give_current_material(base->object, a); for(b=0; b<totcol; b++) { if(ma == matar[b]) { matmap[a-1]= b; break; } } } if(base->object!=ob) multiresModifier_prepare_join(scene, base->object, ob); CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface); CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface); for(a=0; a<me->totface; a++, mface++) { mface->v1+= vertofs; mface->v2+= vertofs; mface->v3+= vertofs; if(mface->v4) mface->v4+= vertofs; if (matmap) mface->mat_nr= matmap[(int)mface->mat_nr]; else mface->mat_nr= 0; } faceofs += me->totface; } if(me->totedge) { CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge); for(a=0; a<me->totedge; a++, medge++) { medge->v1+= vertofs; medge->v2+= vertofs; } edgeofs += me->totedge; } /* vertofs is used to help newly added verts be reattached to their edge/face * (cannot be set earlier, or else reattaching goes wrong) */ vertofs += me->totvert; /* free base, now that data is merged */ if(base->object != ob) ED_base_object_free_and_unlink(bmain, scene, base); } } CTX_DATA_END; /* return to mesh we're merging to */ me= ob->data; CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); me->totvert= totvert; me->totedge= totedge; me->totface= totface; me->vdata= vdata; me->edata= edata; me->fdata= fdata; mesh_update_customdata_pointers(me); /* old material array */ for(a=1; a<=ob->totcol; a++) { ma= ob->mat[a-1]; if(ma) ma->id.us--; } for(a=1; a<=me->totcol; a++) { ma= me->mat[a-1]; if(ma) ma->id.us--; } if(ob->mat) MEM_freeN(ob->mat); if(ob->matbits) MEM_freeN(ob->matbits); if(me->mat) MEM_freeN(me->mat); ob->mat= me->mat= NULL; ob->matbits= NULL; if(totcol) { me->mat= matar; ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar"); ob->matbits= MEM_callocN(sizeof(char)*totcol, "join obmatbits"); } else MEM_freeN(matar); ob->totcol= me->totcol= totcol; ob->colbits= 0; if (matmap) MEM_freeN(matmap); /* other mesh users */ test_object_materials((ID *)me); /* free temp copy of destination shapekeys (if applicable) */ if(nkey) { // XXX 2.5 Animato #if 0 /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */ if(nkey->ipo) { free_ipo(nkey->ipo); BLI_remlink(&bmain->ipo, nkey->ipo); MEM_freeN(nkey->ipo); } #endif free_key(nkey); BLI_remlink(&bmain->key, nkey); MEM_freeN(nkey); } DAG_scene_sort(bmain, scene); // removed objects, need to rebuild dag before editmode call #if 0 ED_object_enter_editmode(C, EM_WAITCURSOR); ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO); #else /* toggle editmode using lower level functions so this can be called from python */ make_editMesh(scene, ob); load_editMesh(scene, ob); free_editMesh(me->edit_mesh); MEM_freeN(me->edit_mesh); me->edit_mesh= NULL; DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA); #endif WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; }
static int bake( Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, const eScenePassType pass_type, const int pass_filter, const int margin, const eBakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, const float cage_extrusion, const int normal_space, const eBakeNormalSwizzle normal_swizzle[], const char *custom_cage, const char *filepath, const int width, const int height, const char *identifier, ScrArea *sa, const char *uv_layer) { int op_result = OPERATOR_CANCELLED; bool ok = false; Object *ob_cage = NULL; BakeHighPolyData *highpoly = NULL; int tot_highpoly = 0; char restrict_flag_low = ob_low->restrictflag; char restrict_flag_cage = 0; Mesh *me_low = NULL; Mesh *me_cage = NULL; MultiresModifierData *mmd_low = NULL; int mmd_flags_low = 0; float *result = NULL; BakePixel *pixel_array_low = NULL; BakePixel *pixel_array_high = NULL; const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); const bool is_noncolor = is_noncolor_pass(pass_type); const int depth = RE_pass_depth(pass_type); BakeImages bake_images = {NULL}; size_t num_pixels; int tot_materials; RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } tot_materials = ob_low->totcol; if (uv_layer && uv_layer[0] != '\0') { Mesh *me = (Mesh *)ob_low->data; if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) { BKE_reportf(reports, RPT_ERROR, "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2); goto cleanup; } } if (tot_materials == 0) { if (is_save_internal) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake to an external file"); goto cleanup; } else if (is_split_materials) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake without the Split Materials option"); goto cleanup; } else { /* baking externally without splitting materials */ tot_materials = 1; } } /* we overallocate in case there is more materials than images */ bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); build_image_lookup(bmain, ob_low, &bake_images); if (is_save_internal) { num_pixels = initialize_internal_images(&bake_images, reports); if (num_pixels == 0) { goto cleanup; } } else { /* when saving extenally always use the size specified in the UI */ num_pixels = (size_t)width * (size_t)height * bake_images.size; for (int i = 0; i < bake_images.size; i++) { bake_images.data[i].width = width; bake_images.data[i].height = height; bake_images.data[i].offset = (is_split_materials ? num_pixels : 0); bake_images.data[i].image = NULL; } if (!is_split_materials) { /* saving a single image */ for (int i = 0; i < tot_materials; i++) { bake_images.lookup[i] = 0; } } } if (is_selected_to_active) { CollectionPointerLink *link; tot_highpoly = 0; for (link = selected_objects->first; link; link = link->next) { Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; tot_highpoly ++; } if (is_cage && custom_cage[0] != '\0') { ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); if (ob_cage == NULL || ob_cage->type != OB_MESH) { BKE_report(reports, RPT_ERROR, "No valid cage object"); goto cleanup; } else { restrict_flag_cage = ob_cage->restrictflag; ob_cage->restrictflag |= OB_RESTRICT_RENDER; } } } pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); /* for multires bake, use linear UV subdivision to match low res UVs */ if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT && !is_selected_to_active) { mmd_low = (MultiresModifierData *) modifiers_findByType(ob_low, eModifierType_Multires); if (mmd_low) { mmd_flags_low = mmd_low->flags; mmd_low->flags |= eMultiresModifierFlag_PlainUv; } } /* get the mesh as it arrives in the renderer */ me_low = bake_mesh_new_from_object(bmain, scene, ob_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer); /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ if (is_selected_to_active) { CollectionPointerLink *link; ModifierData *md, *nmd; ListBase modifiers_tmp, modifiers_original; int i = 0; /* prepare cage mesh */ if (ob_cage) { me_cage = bake_mesh_new_from_object(bmain, scene, ob_cage); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, "Invalid cage object, the cage mesh must have the same number " "of faces as the active object"); goto cleanup; } } else if (is_cage) { modifiers_original = ob_low->modifiers; BLI_listbase_clear(&modifiers_tmp); for (md = ob_low->modifiers.first; md; md = md->next) { /* Edge Split cannot be applied in the cage, * the cage is supposed to have interpolated normals * between the faces unless the geometry is physically * split. So we create a copy of the low poly mesh without * the eventual edge split.*/ if (md->type == eModifierType_EdgeSplit) continue; nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); modifier_copyData(md, nmd); BLI_addtail(&modifiers_tmp, nmd); } /* temporarily replace the modifiers */ ob_low->modifiers = modifiers_tmp; /* get the cage mesh as it arrives in the renderer */ me_cage = bake_mesh_new_from_object(bmain, scene, ob_low); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); /* populate highpoly array */ for (link = selected_objects->first; link; link = link->next) { TriangulateModifierData *tmd; Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; /* initialize highpoly_data */ highpoly[i].ob = ob_iter; highpoly[i].restrict_flag = ob_iter->restrictflag; /* triangulating so BVH returns the primitive_id that will be used for rendering */ highpoly[i].tri_mod = ED_object_modifier_add( reports, bmain, scene, highpoly[i].ob, "TmpTriangulate", eModifierType_Triangulate); tmd = (TriangulateModifierData *)highpoly[i].tri_mod; tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; highpoly[i].me = bake_mesh_new_from_object(bmain, scene, highpoly[i].ob); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); i++; } BLI_assert(i == tot_highpoly); ob_low->restrictflag |= OB_RESTRICT_RENDER; /* populate the pixel arrays with the corresponding face data for each high poly object */ if (!RE_bake_pixels_populate_from_objects( me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL, cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cage_cleanup; } /* the baking itself */ for (i = 0; i < tot_highpoly; i++) { ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, num_pixels, depth, pass_type, pass_filter, result); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); goto cage_cleanup; } } cage_cleanup: /* reverting data back */ if ((ob_cage == NULL) && is_cage) { ob_low->modifiers = modifiers_original; while ((md = BLI_pophead(&modifiers_tmp))) { modifier_free(md); } } if (!ok) { goto cleanup; } } else { /* make sure low poly renders */ ob_low->restrictflag &= ~OB_RESTRICT_RENDER; if (RE_bake_has_engine(re)) { ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, pass_filter, result); } else { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } } /* normal space conversion * the normals are expected to be in world space, +X +Y +Z */ if (ok && pass_type == SCE_PASS_NORMAL) { switch (normal_space) { case R_BAKE_SPACE_WORLD: { /* Cycles internal format */ if ((normal_swizzle[0] == R_BAKE_POSX) && (normal_swizzle[1] == R_BAKE_POSY) && (normal_swizzle[2] == R_BAKE_POSZ)) { break; } else { RE_bake_normal_world_to_world(pixel_array_low, num_pixels, depth, result, normal_swizzle); } break; } case R_BAKE_SPACE_OBJECT: { RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle); break; } case R_BAKE_SPACE_TANGENT: { if (is_selected_to_active) { RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat); } else { /* from multiresolution */ Mesh *me_nores = NULL; ModifierData *md = NULL; int mode; md = modifiers_findByType(ob_low, eModifierType_Multires); if (md) { mode = md->mode; md->mode &= ~eModifierMode_Render; } me_nores = bake_mesh_new_from_object(bmain, scene, ob_low); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat); BKE_libblock_free(bmain, me_nores); if (md) md->mode = mode; } break; } default: break; } } if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { /* save the results */ for (int i = 0; i < bake_images.size; i++) { BakeImage *bk_image = &bake_images.data[i]; if (is_save_internal) { ok = write_internal_bake_pixels( bk_image->image, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, is_clear, is_noncolor); /* might be read by UI to set active image for display */ bake_update_image(sa, bk_image->image); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { BKE_report(reports, RPT_INFO, "Baking map saved to internal image, save it externally or pack it"); op_result = OPERATOR_FINISHED; } } /* save externally */ else { BakeData *bake = &scene->r.bake; char name[FILE_MAX]; BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL); if (is_automatic_name) { BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); BLI_path_suffix(name, FILE_MAX, identifier, "_"); } if (is_split_materials) { if (bk_image->image) { BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); } else { if (ob_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_"); } else if (me_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_"); } else { /* if everything else fails, use the material index */ char tmp[5]; sprintf(tmp, "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } } } /* save it externally */ ok = write_external_bake_pixels( name, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, &bake->im_format, is_noncolor); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); op_result = OPERATOR_CANCELLED; } else { BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name); op_result = OPERATOR_FINISHED; } if (!is_split_materials) { break; } } } } if (is_save_internal) refresh_images(&bake_images); cleanup: if (highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { highpoly[i].ob->restrictflag = highpoly[i].restrict_flag; if (highpoly[i].tri_mod) ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod); if (highpoly[i].me) BKE_libblock_free(bmain, highpoly[i].me); } MEM_freeN(highpoly); } ob_low->restrictflag = restrict_flag_low; if (mmd_low) mmd_low->flags = mmd_flags_low; if (ob_cage) ob_cage->restrictflag = restrict_flag_cage; if (pixel_array_low) MEM_freeN(pixel_array_low); if (pixel_array_high) MEM_freeN(pixel_array_high); if (bake_images.data) MEM_freeN(bake_images.data); if (bake_images.lookup) MEM_freeN(bake_images.lookup); if (result) MEM_freeN(result); if (me_low) BKE_libblock_free(bmain, me_low); if (me_cage) BKE_libblock_free(bmain, me_cage); return op_result; }
/* Retrieve reconstructed tracks from libmv to blender. * Actually, this also copies reconstructed cameras * from libmv to movie clip datablock. */ static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking) { struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction; MovieTrackingReconstruction *reconstruction = NULL; MovieReconstructedCamera *reconstructed; MovieTrackingTrack *track; ListBase *tracksbase = NULL; int tracknr = 0, a; bool ok = true; bool origin_set = false; int sfra = context->sfra, efra = context->efra; float imat[4][4]; if (context->is_camera) { tracksbase = &tracking->tracks; reconstruction = &tracking->reconstruction; } else { MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, context->object_name); tracksbase = &object->tracks; reconstruction = &object->reconstruction; } unit_m4(imat); track = tracksbase->first; while (track) { double pos[3]; if (libmv_reprojectionPointForTrack(libmv_reconstruction, tracknr, pos)) { track->bundle_pos[0] = pos[0]; track->bundle_pos[1] = pos[1]; track->bundle_pos[2] = pos[2]; track->flag |= TRACK_HAS_BUNDLE; track->error = libmv_reprojectionErrorForTrack(libmv_reconstruction, tracknr); } else { track->flag &= ~TRACK_HAS_BUNDLE; ok = false; printf("Unable to reconstruct position for track #%d '%s'\n", tracknr, track->name); } track = track->next; tracknr++; } if (reconstruction->cameras) MEM_freeN(reconstruction->cameras); reconstruction->camnr = 0; reconstruction->cameras = NULL; reconstructed = MEM_callocN((efra - sfra + 1) * sizeof(MovieReconstructedCamera), "temp reconstructed camera"); for (a = sfra; a <= efra; a++) { double matd[4][4]; if (libmv_reprojectionCameraForImage(libmv_reconstruction, a, matd)) { int i, j; float mat[4][4]; float error = libmv_reprojectionErrorForImage(libmv_reconstruction, a); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) mat[i][j] = matd[i][j]; } /* Ensure first camera has got zero rotation and transform. * This is essential for object tracking to work -- this way * we'll always know object and environment are properly * oriented. * * There's one weak part tho, which is requirement object * motion starts at the same frame as camera motion does, * otherwise that;' be a russian roulette whether object is * aligned correct or not. */ if (!origin_set) { invert_m4_m4(imat, mat); unit_m4(mat); origin_set = true; } else { mul_m4_m4m4(mat, imat, mat); } copy_m4_m4(reconstructed[reconstruction->camnr].mat, mat); reconstructed[reconstruction->camnr].framenr = a; reconstructed[reconstruction->camnr].error = error; reconstruction->camnr++; } else { ok = false; printf("No camera for frame %d\n", a); } } if (reconstruction->camnr) { int size = reconstruction->camnr * sizeof(MovieReconstructedCamera); reconstruction->cameras = MEM_callocN(size, "reconstructed camera"); memcpy(reconstruction->cameras, reconstructed, size); } if (origin_set) { track = tracksbase->first; while (track) { if (track->flag & TRACK_HAS_BUNDLE) mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos); track = track->next; } } MEM_freeN(reconstructed); return ok; }
static void pointdensity_cache_psys(Scene *scene, PointDensity *pd, Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy) { DerivedMesh *dm; ParticleKey state; ParticleCacheKey *cache; ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL; float cfra = BKE_scene_frame_get(scene); int i /*, childexists*/ /* UNUSED */; int total_particles, offset = 0; int data_used = point_data_used(pd); float partco[3]; /* init everything */ if (!psys || !ob || !pd) { return; } /* Just to create a valid rendering context for particles */ psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0); dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); if ( !psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); return; } sim.scene = scene; sim.ob = ob; sim.psys = psys; sim.psmd = psys_get_modifier(ob, psys); /* in case ob->imat isn't up-to-date */ invert_m4_m4(ob->imat, ob->obmat); total_particles = psys->totpart + psys->totchild; psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); alloc_point_data(pd, total_particles, data_used); pd->totpoints = total_particles; if (data_used & POINT_DATA_VEL) { offset = pd->totpoints * 3; } #if 0 /* UNUSED */ if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; #endif for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) { if (psys->part->type == PART_HAIR) { /* hair particles */ if (i < psys->totpart && psys->pathcache) cache = psys->pathcache[i]; else if (i >= psys->totpart && psys->childcache) cache = psys->childcache[i - psys->totpart]; else continue; cache += cache->segments; /* use endpoint */ copy_v3_v3(state.co, cache->co); zero_v3(state.vel); state.time = 0.0f; } else { /* emitter particles */ state.time = cfra; if (!psys_get_particle_state(&sim, i, &state, 0)) continue; if (data_used & POINT_DATA_LIFE) { if (i < psys->totpart) { state.time = (cfra - pa->time) / pa->lifetime; } else { ChildParticle *cpa = (psys->child + i) - psys->totpart; float pa_birthtime, pa_dietime; state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); } } } copy_v3_v3(partco, state.co); if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) mul_m4_v3(ob->imat, partco); else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { sub_v3_v3(partco, ob->loc); } else { /* TEX_PD_WORLDSPACE */ } BLI_bvhtree_insert(pd->point_tree, i, partco, 1); if (data_used & POINT_DATA_VEL) { pd->point_data[i * 3 + 0] = state.vel[0]; pd->point_data[i * 3 + 1] = state.vel[1]; pd->point_data[i * 3 + 2] = state.vel[2]; } if (data_used & POINT_DATA_LIFE) { pd->point_data[offset + i] = state.time; } } BLI_bvhtree_balance(pd->point_tree); dm->release(dm); if (psys->lattice_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } psys_render_restore(ob, psys); }
static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys) { DerivedMesh* dm; ParticleKey state; ParticleSimulationData sim= {NULL}; ParticleData *pa=NULL; float cfra = BKE_curframe(re->scene); int i /*, childexists*/ /* UNUSED */; int total_particles, offset=0; int data_used = point_data_used(pd); float partco[3]; float obview[4][4]; /* init everything */ if (!psys || !ob || !pd) return; mul_m4_m4m4(obview, re->viewinv, ob->obmat); /* Just to create a valid rendering context for particles */ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); dm = mesh_create_derived_render(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); if ( !psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); return; } sim.scene= re->scene; sim.ob= ob; sim.psys= psys; /* in case ob->imat isn't up-to-date */ invert_m4_m4(ob->imat, ob->obmat); total_particles = psys->totpart+psys->totchild; psys->lattice=psys_get_lattice(&sim); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); alloc_point_data(pd, total_particles, data_used); pd->totpoints = total_particles; if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3; #if 0 /* UNUSED */ if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; #endif for (i=0, pa=psys->particles; i < total_particles; i++, pa++) { state.time = cfra; if(psys_get_particle_state(&sim, i, &state, 0)) { copy_v3_v3(partco, state.co); if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) mul_m4_v3(ob->imat, partco); else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { sub_v3_v3(partco, ob->loc); } else { /* TEX_PD_WORLDSPACE */ } BLI_bvhtree_insert(pd->point_tree, i, partco, 1); if (data_used & POINT_DATA_VEL) { pd->point_data[i*3 + 0] = state.vel[0]; pd->point_data[i*3 + 1] = state.vel[1]; pd->point_data[i*3 + 2] = state.vel[2]; } if (data_used & POINT_DATA_LIFE) { float pa_time; if (i < psys->totpart) { pa_time = (cfra - pa->time)/pa->lifetime; } else { ChildParticle *cpa= (psys->child + i) - psys->totpart; float pa_birthtime, pa_dietime; pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); } pd->point_data[offset + i] = pa_time; } } } BLI_bvhtree_balance(pd->point_tree); dm->release(dm); if(psys->lattice){ end_latt_deform(psys->lattice); psys->lattice=0; } psys_render_restore(ob, psys); }
static void normalEditModifier_do_directional( NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm, short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3], const short mix_mode, const float mix_factor, const float mix_limit, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, MVert *mvert, const int num_verts, MEdge *medge, const int num_edges, MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys) { const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0; float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__); float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__); float target_co[3]; int i; dm->getVertCos(dm, cos); /* Get target's center coordinates in ob local coordinates. */ { float mat[4][4]; invert_m4_m4(mat, ob->obmat); mul_m4_m4m4(mat, mat, enmd->target->obmat); copy_v3_v3(target_co, mat[3]); } if (use_parallel_normals) { float no[3]; sub_v3_v3v3(no, target_co, enmd->offset); normalize_v3(no); for (i = num_loops; i--; ) { copy_v3_v3(nos[i], no); } } else { BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__); MLoop *ml; float (*no)[3]; /* We reuse cos to now store the 'to target' normal of the verts! */ for (i = num_loops, no = nos, ml = mloop; i--; no++, ml++) { const int vidx = ml->v; float *co = cos[vidx]; if (!BLI_BITMAP_TEST(done_verts, vidx)) { sub_v3_v3v3(co, target_co, co); normalize_v3(co); BLI_BITMAP_ENABLE(done_verts, vidx); } copy_v3_v3(*no, co); } MEM_freeN(done_verts); } if (loopnors) { mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup, mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops); } if (do_polynors_fix && polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) { dm->dirty |= DM_DIRTY_TESS_CDLAYERS; } BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops, mpoly, (const float(*)[3])polynors, num_polys, clnors); MEM_freeN(cos); MEM_freeN(nos); }
void get_texture_coords(MappingInfoModifierData *dmd, Object *ob, DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts) { int i; int texmapping = dmd->texmapping; float mapob_imat[4][4]; if(texmapping == MOD_DISP_MAP_OBJECT) { if(dmd->map_object) invert_m4_m4(mapob_imat, dmd->map_object->obmat); else /* if there is no map object, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } /* UVs need special handling, since they come from faces */ if(texmapping == MOD_DISP_MAP_UV) { if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) { MFace *mface = dm->getFaceArray(dm); MFace *mf; char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); int numFaces = dm->getNumFaces(dm); char uvname[32]; MTFace *tf; validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name, uvname); tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); /* verts are given the UV from the first face that uses them */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { if(!done[mf->v1]) { texco[mf->v1][0] = tf->uv[0][0]; texco[mf->v1][1] = tf->uv[0][1]; texco[mf->v1][2] = 0; done[mf->v1] = 1; } if(!done[mf->v2]) { texco[mf->v2][0] = tf->uv[1][0]; texco[mf->v2][1] = tf->uv[1][1]; texco[mf->v2][2] = 0; done[mf->v2] = 1; } if(!done[mf->v3]) { texco[mf->v3][0] = tf->uv[2][0]; texco[mf->v3][1] = tf->uv[2][1]; texco[mf->v3][2] = 0; done[mf->v3] = 1; } if(!done[mf->v4]) { texco[mf->v4][0] = tf->uv[3][0]; texco[mf->v4][1] = tf->uv[3][1]; texco[mf->v4][2] = 0; done[mf->v4] = 1; } } /* remap UVs from [0, 1] to [-1, 1] */ for(i = 0; i < numVerts; ++i) { texco[i][0] = texco[i][0] * 2 - 1; texco[i][1] = texco[i][1] * 2 - 1; } MEM_freeN(done); return; } else /* if there are no UVs, default to local */ texmapping = MOD_DISP_MAP_LOCAL; } for(i = 0; i < numVerts; ++i, ++co, ++texco) { switch(texmapping) { case MOD_DISP_MAP_LOCAL: copy_v3_v3(*texco, *co); break; case MOD_DISP_MAP_GLOBAL: mul_v3_m4v3(*texco, ob->obmat, *co); break; case MOD_DISP_MAP_OBJECT: mul_v3_m4v3(*texco, ob->obmat, *co); mul_m4_v3(mapob_imat, *texco); break; } } }
static void meshdeformModifier_do( ModifierData *md, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MeshDeformModifierData *mmd = (MeshDeformModifierData *) md; struct Mesh *me = (mmd->object) ? mmd->object->data : NULL; BMEditMesh *em = me ? me->edit_btmesh : NULL; DerivedMesh *tmpdm, *cagedm; MDeformVert *dvert = NULL; MDefInfluence *influences; int *offsets; float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; float weight, totweight, fac, co[3], (*dco)[3], (*bindcagecos)[3]; int a, b, totvert, totcagevert, defgrp_index; float (*cagecos)[3]; if (!mmd->object || (!mmd->bindcagecos && !mmd->bindfunc)) return; /* get cage derivedmesh */ if (em) { tmpdm = editbmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0); if (tmpdm) tmpdm->release(tmpdm); } else cagedm = mmd->object->derivedFinal; /* if we don't have one computed, use derivedmesh from data * without any modifiers */ if (!cagedm) { cagedm = get_dm(mmd->object, NULL, NULL, NULL, false, false); if (cagedm) cagedm->needsFree = 1; } if (!cagedm) { modifier_setError(md, "Cannot get mesh from cage object"); return; } /* compute matrices to go in and out of cage object space */ invert_m4_m4(imat, mmd->object->obmat); mul_m4_m4m4(cagemat, imat, ob->obmat); mul_m4_m4m4(cmat, mmd->bindmat, cagemat); invert_m4_m4(iobmat, cmat); copy_m3_m4(icagemat, iobmat); /* bind weights if needed */ if (!mmd->bindcagecos) { static int recursive = 0; /* progress bar redraw can make this recursive .. */ if (!recursive) { recursive = 1; mmd->bindfunc(md->scene, mmd, (float *)vertexCos, numVerts, cagemat); recursive = 0; } } /* verify we have compatible weights */ totvert = numVerts; totcagevert = cagedm->getNumVerts(cagedm); if (mmd->totvert != totvert) { modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert); cagedm->release(cagedm); return; } else if (mmd->totcagevert != totcagevert) { modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert); cagedm->release(cagedm); return; } else if (mmd->bindcagecos == NULL) { modifier_setError(md, "Bind data missing"); cagedm->release(cagedm); return; } cagecos = MEM_callocN(sizeof(*cagecos) * totcagevert, "meshdeformModifier vertCos"); /* setup deformation data */ cagedm->getVertCos(cagedm, cagecos); influences = mmd->bindinfluences; offsets = mmd->bindoffsets; bindcagecos = (float(*)[3])mmd->bindcagecos; dco = MEM_callocN(sizeof(*dco) * totcagevert, "MDefDco"); for (a = 0; a < totcagevert; a++) { /* get cage vertex in world space with binding transform */ copy_v3_v3(co, cagecos[a]); if (G.debug_value != 527) { mul_m4_v3(mmd->bindmat, co); /* compute difference with world space bind coord */ sub_v3_v3v3(dco[a], co, bindcagecos[a]); } else copy_v3_v3(dco[a], co); } modifier_get_vgroup(ob, dm, mmd->defgrp_name, &dvert, &defgrp_index); /* do deformation */ fac = 1.0f; for (b = 0; b < totvert; b++) { if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) if (!mmd->dynverts[b]) continue; if (dvert) { fac = defvert_find_weight(&dvert[b], defgrp_index); if (mmd->flag & MOD_MDEF_INVERT_VGROUP) { fac = 1.0f - fac; } if (fac <= 0.0f) { continue; } } if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) { /* transform coordinate into cage's local space */ mul_v3_m4v3(co, cagemat, vertexCos[b]); totweight = meshdeform_dynamic_bind(mmd, dco, co); } else { totweight = 0.0f; zero_v3(co); for (a = offsets[b]; a < offsets[b + 1]; a++) { weight = influences[a].weight; madd_v3_v3fl(co, dco[influences[a].vertex], weight); totweight += weight; } } if (totweight > 0.0f) { mul_v3_fl(co, fac / totweight); mul_m3_v3(icagemat, co); if (G.debug_value != 527) add_v3_v3(vertexCos[b], co); else copy_v3_v3(vertexCos[b], co); } } /* release cage derivedmesh */ MEM_freeN(dco); MEM_freeN(cagecos); cagedm->release(cagedm); }
void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& joint_by_uid, TransformReader *tm) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature); ArmatureModifierData *amd = (ArmatureModifierData *)md; amd->object = ob_arm; copy_m4_m4(ob->obmat, bind_shape_matrix); BKE_object_apply_mat4(ob, ob->obmat, 0, 0); #if 1 bc_set_parent(ob, ob_arm, C); #else Object workob; ob->parent = ob_arm; ob->partype = PAROBJECT; BKE_object_workob_calc_parent(scene, ob, &workob); invert_m4_m4(ob->parentinv, workob.obmat); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA); DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); #endif amd->deformflag = ARM_DEF_VGROUP; // create all vertex groups std::vector<JointData>::iterator it; int joint_index; for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) { const char *name = "Group"; // skip joints that have invalid UID if ((*it).joint_uid == COLLADAFW::UniqueId::INVALID) continue; // name group by joint node name if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) { name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]); } ED_vgroup_add_name(ob, (char *)name); } // <vcount> - number of joints per vertex - joints_per_vertex // <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices // ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender? // for each vertex in weight indices // for each bone index in vertex // add vertex to group at group index // treat group index -1 specially // get def group by index with BLI_findlink for (unsigned int vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) { unsigned int limit = weight + joints_per_vertex[vertex]; for (; weight < limit; weight++) { int joint = joint_indices[weight], joint_weight = weight_indices[weight]; // -1 means "weight towards the bind shape", we just don't assign it to any group if (joint != -1) { bDeformGroup *def = (bDeformGroup *)BLI_findlink(&ob->defbase, joint); ED_vgroup_vert_add(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE); } } } }
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id) { COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::Float4x4Source source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(frames.size()); source.setAccessorStride(16); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, false, NULL, true); source.prepareToAppendValues(); bPoseChannel *parchan = NULL; bPoseChannel *pchan = NULL; if (ob->type == OB_ARMATURE && bone) { bPose *pose = ob->pose; pchan = BKE_pose_channel_find_name(pose, bone->name); if (!pchan) return ""; parchan = pchan->parent; enable_fcurves(ob->adt->action, bone->name); } std::vector<float>::iterator it; int j = 0; for (it = frames.begin(); it != frames.end(); it++) { float mat[4][4], ipar[4][4]; float ctime = BKE_scene_frame_get_from_ctime(scene, *it); CFRA = BKE_scene_frame_get_from_ctime(scene, *it); //BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene,scene->lay); BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); if (bone) { if (pchan->flag & POSE_CHAIN) { enable_fcurves(ob->adt->action, NULL); BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL); BKE_pose_where_is(scene, ob); } else { BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); } // compute bone local mat if (bone->parent) { invert_m4_m4(ipar, parchan->pose_mat); mul_m4_m4m4(mat, ipar, pchan->pose_mat); } else copy_m4_m4(mat, pchan->pose_mat); // OPEN_SIM_COMPATIBILITY // AFAIK animation to second life is via BVH, but no // reason to not have the collada-animation be correct if (export_settings->open_sim) { float temp[4][4]; copy_m4_m4(temp, bone->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; invert_m4(temp); mul_m4_m4m4(mat, mat, temp); if (bone->parent) { copy_m4_m4(temp, bone->parent->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; mul_m4_m4m4(mat, temp, mat); } } } else { calc_ob_mat_at_time(ob, ctime, mat); } UnitConverter converter; double outmat[4][4]; converter.mat4_to_dae_double(outmat, mat); source.appendValues(outmat); j++; BIK_release_tree(scene, ob, ctime); } if (ob->adt) { enable_fcurves(ob->adt->action, NULL); } source.finish(); return source_id; }
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) { GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa = NULL; ParticleKey state; ParticleCacheKey *cache; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4], (*oldobmat)[4]; int a, b, counter, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; if (psys == NULL) return; /* simple preventing of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; part = psys->part; if (part == NULL) return; if (!psys_check_enabled(par, psys)) return; if (G.rendering == 0) no_draw_flag |= PARS_NO_DISP; ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; BLI_srandom(31415926 + psys->seed); if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; sim.scene = scene; sim.ob = par; sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* make sure emitter imat is in global coordinates instead of render view coordinates */ invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->dup_ob, NULL, par)) return; } else { /*PART_DRAW_GR */ if (part->dup_group == NULL || part->dup_group->gobject.first == NULL) return; for (go = part->dup_group->gobject.first; go; go = go->next) if (go->ob == par) return; } /* if we have a hair particle system, use the path cache */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) hair = (totchild == 0 || psys->childcache) && psys->pathcache; if (!hair) return; /* we use cache, update totchild according to cached data */ totchild = psys->totchildcache; totpart = psys->totcached; } psys_check_group_weights(part); psys->lattice = psys_get_lattice(&sim); /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { group_handle_recalc_and_update(scene, par, part->dup_group); if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) totgroup += dw->count; } else { for (go = part->dup_group->gobject.first; go; go = go->next) totgroup++; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ oblist = MEM_callocN(totgroup * sizeof(Object *), "dupgroup object list"); obcopylist = MEM_callocN(totgroup * sizeof(Object), "dupgroup copy list"); if (part->draw & PART_DRAW_COUNT_GR && totgroup) { dw = part->dupliweights.first; for (a = 0; a < totgroup; dw = dw->next) { for (b = 0; b < dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; } } } else { go = part->dup_group->gobject.first; for (a = 0; a < totgroup; a++, go = go->next) { oblist[a] = go->ob; obcopylist[a] = *go->ob; } } } else { ob = part->dup_ob; obcopy = *ob; } if (totchild == 0 || part->draw & PART_DRAW_PARENT) a = 0; else a = totpart; for (pa = psys->particles, counter = 0; a < totpart + totchild; a++, pa++, counter++) { if (a < totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) continue; /* pa_num = pa->num; */ /* UNUSED */ pa_time = pa->time; size = pa->size; } else { /* handle child particle */ cpa = &psys->child[a - totpart]; /* pa_num = a; */ /* UNUSED */ pa_time = psys->particles[cpa->parent].time; size = psys_get_child_size(psys, cpa, ctime, NULL); } /* some hair paths might be non-existent so they can't be used for duplication */ if (hair && ((a < totpart && psys->pathcache[a]->steps < 0) || (a >= totpart && psys->childcache[a - totpart]->steps < 0))) { continue; } if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ if (totgroup == 0) continue; /* for groups, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) b = BLI_rand() % totgroup; else b = a % totgroup; ob = oblist[b]; obmat = oblist[b]->obmat; oldobmat = obcopylist[b].obmat; } else { obmat = ob->obmat; oldobmat = obcopy.obmat; } if (hair) { /* hair we handle separate and compute transform based on hair keys */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); } else { cache = psys->childcache[a - totpart]; psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale); } copy_v3_v3(pamat[3], cache->co); pamat[3][3] = 1.0f; } else { /* first key */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; } else { float tquat[4]; normalize_qt_qt(tquat, state.rot); quat_to_mat4(pamat, tquat); copy_v3_v3(pamat[3], state.co); pamat[3][3] = 1.0f; } } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { copy_m4_m4(tmat, oblist[b]->obmat); /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); /* group dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs); /* individual particle transform */ mult_m4_m4m4(tmat, pamat, tmat); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, obcopylist[b].obmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { /* to give ipos in object correct offset */ BKE_object_where_is_calc_time(scene, ob, ctime - pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { float xvec[3], q[4]; xvec[0] = -1.f; xvec[1] = xvec[2] = 0; vec_to_quat(q, xvec, ob->trackflag, ob->upflag); quat_to_mat4(obmat, q); obmat[3][3] = 1.0f; } /* Normal particles and cached hair live in global space so we need to * remove the real emitter's transformation before 2nd order duplication. */ if (par_space_mat && GS(id->name) != ID_GR) mult_m4_m4m4(mat, psys->imat, pamat); else copy_m4_m4(mat, pamat); mult_m4_m4m4(tmat, mat, obmat); mul_mat3_m4_fl(tmat, size * scale); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); dob = new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, oldobmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { for (a = 0; a < totgroup; a++) *(oblist[a]) = obcopylist[a]; } else *ob = obcopy; } /* clean up */ if (oblist) MEM_freeN(oblist); if (obcopylist) MEM_freeN(obcopylist); if (psys->lattice) { end_latt_deform(psys->lattice); psys->lattice = NULL; } }
struct CharTrans *BKE_vfont_to_curve(Main *bmain, Scene *scene, Object *ob, int mode) { VFont *vfont, *oldvfont; VFontData *vfd = NULL; Curve *cu; CharInfo *info = NULL, *custrinfo; TextBox *tb; VChar *che; struct CharTrans *chartransdata = NULL, *ct; float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4; float twidth, maxlen = 0; int i, slen, j; int curbox; int selstart, selend; int utf8len; short cnr = 0, lnr = 0, wsnr = 0; wchar_t *mem, *tmp, ascii; /* remark: do calculations including the trailing '\0' of a string * because the cursor can be at that location */ if (ob->type != OB_FONT) return NULL; /* Set font data */ cu = (Curve *) ob->data; vfont = cu->vfont; if (cu->str == NULL) return NULL; if (vfont == NULL) return NULL; /* Create unicode string */ utf8len = BLI_strlen_utf8(cu->str); mem = MEM_mallocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem"); BLI_strncpy_wchar_from_utf8(mem, cu->str, utf8len + 1); /* Count the wchar_t string length */ slen = wcslen(mem); if (cu->ulheight == 0.0f) cu->ulheight = 0.05f; if (cu->strinfo == NULL) /* old file */ cu->strinfo = MEM_callocN((slen + 4) * sizeof(CharInfo), "strinfo compat"); custrinfo = cu->strinfo; if (cu->editfont) custrinfo = cu->editfont->textbufinfo; if (cu->tb == NULL) cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "TextBox compat"); vfd = vfont_get_data(bmain, vfont); /* The VFont Data can not be found */ if (!vfd) { if (mem) MEM_freeN(mem); return NULL; } /* calc offset and rotation of each char */ ct = chartransdata = (struct CharTrans *)MEM_callocN((slen + 1) * sizeof(struct CharTrans), "buildtext"); /* We assume the worst case: 1 character per line (is freed at end anyway) */ linedata = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext2"); linedata2 = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext3"); linedata3 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext4"); linedata4 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext5"); linedist = cu->linedist; xof = cu->xof + (cu->tb[0].x / cu->fsize); yof = cu->yof + (cu->tb[0].y / cu->fsize); xtrax = 0.5f * cu->spacing - 0.5f; oldvfont = NULL; for (i = 0; i < slen; i++) custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK); if (cu->selboxes) MEM_freeN(cu->selboxes); cu->selboxes = NULL; if (BKE_vfont_select_get(ob, &selstart, &selend)) cu->selboxes = MEM_callocN((selend - selstart + 1) * sizeof(SelBox), "font selboxes"); tb = &(cu->tb[0]); curbox = 0; for (i = 0; i <= slen; i++) { makebreak: /* Characters in the list */ info = &(custrinfo[i]); ascii = mem[i]; if (info->flag & CU_CHINFO_SMALLCAPS) { ascii = towupper(ascii); if (mem[i] != ascii) { mem[i] = ascii; info->flag |= CU_CHINFO_SMALLCAPS_CHECK; } } vfont = which_vfont(cu, info); if (vfont == NULL) break; che = find_vfont_char(vfd, ascii); /* * The character wasn't in the current curve base so load it * But if the font is built-in then do not try loading since * whole font is in the memory already */ if (che == NULL && BKE_vfont_is_builtin(vfont) == FALSE) { BLI_vfontchar_from_freetypefont(vfont, ascii); } /* Try getting the character again from the list */ che = find_vfont_char(vfd, ascii); /* No VFont found */ if (vfont == NULL) { if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; } if (vfont != oldvfont) { vfd = vfont_get_data(bmain, vfont); oldvfont = vfont; } /* VFont Data for VFont couldn't be found */ if (!vfd) { if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; } twidth = char_width(cu, che, info); /* Calculate positions */ if ((tb->w != 0.0f) && (ct->dobreak == 0) && (((xof - (tb->x / cu->fsize) + twidth) * cu->fsize) > tb->w + cu->xof * cu->fsize)) { // fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]); for (j = i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak == 0); j--) { if (mem[j] == ' ' || mem[j] == '-') { ct -= (i - (j - 1)); cnr -= (i - (j - 1)); if (mem[j] == ' ') wsnr--; if (mem[j] == '-') wsnr++; i = j - 1; xof = ct->xof; ct[1].dobreak = 1; custrinfo[i + 1].flag |= CU_CHINFO_WRAP; goto makebreak; } if (chartransdata[j].dobreak) { // fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]); ct->dobreak = 1; custrinfo[i + 1].flag |= CU_CHINFO_WRAP; ct -= 1; cnr -= 1; i--; xof = ct->xof; goto makebreak; } } } if (ascii == '\n' || ascii == '\r' || ascii == 0 || ct->dobreak) { ct->xof = xof; ct->yof = yof; ct->linenr = lnr; ct->charnr = cnr; yof -= linedist; maxlen = max_ff(maxlen, (xof - tb->x / cu->fsize)); linedata[lnr] = xof - tb->x / cu->fsize; linedata2[lnr] = cnr; linedata3[lnr] = tb->w / cu->fsize; linedata4[lnr] = wsnr; if ((tb->h != 0.0f) && ((-(yof - (tb->y / cu->fsize))) > ((tb->h / cu->fsize) - (linedist * cu->fsize)) - cu->yof) && (cu->totbox > (curbox + 1)) ) { maxlen = 0; tb++; curbox++; yof = cu->yof + tb->y / cu->fsize; } /* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */ #if 0 if (ascii == '\n' || ascii == '\r') xof = cu->xof; else xof = cu->xof + (tb->x / cu->fsize); #else xof = cu->xof + (tb->x / cu->fsize); #endif lnr++; cnr = 0; wsnr = 0; } else if (ascii == 9) { /* TAB */ float tabfac; ct->xof = xof; ct->yof = yof; ct->linenr = lnr; ct->charnr = cnr++; tabfac = (xof - cu->xof + 0.01f); tabfac = 2.0f * ceilf(tabfac / 2.0f); xof = cu->xof + tabfac; } else { SelBox *sb = NULL; float wsfac; ct->xof = xof; ct->yof = yof; ct->linenr = lnr; ct->charnr = cnr++; if (cu->selboxes && (i >= selstart) && (i <= selend)) { sb = &(cu->selboxes[i - selstart]); sb->y = yof * cu->fsize - linedist * cu->fsize * 0.1f; sb->h = linedist * cu->fsize; sb->w = xof * cu->fsize; } if (ascii == 32) { wsfac = cu->wordspace; wsnr++; } else { wsfac = 1.0f; } /* Set the width of the character */ twidth = char_width(cu, che, info); xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f)) ) + xtrax; if (sb) { sb->w = (xof * cu->fsize) - sb->w; } } ct++; } cu->lines = 1; ct = chartransdata; tmp = mem; for (i = 0; i <= slen; i++, tmp++, ct++) { ascii = *tmp; if (ascii == '\n' || ascii == '\r' || ct->dobreak) cu->lines++; } /* linedata is now: width of line * linedata2 is now: number of characters * linedata3 is now: maxlen of that line * linedata4 is now: number of whitespaces of line */ if (cu->spacemode != CU_LEFT) { ct = chartransdata; if (cu->spacemode == CU_RIGHT) { for (i = 0; i < lnr; i++) linedata[i] = linedata3[i] - linedata[i]; for (i = 0; i <= slen; i++) { ct->xof += linedata[ct->linenr]; ct++; } } else if (cu->spacemode == CU_MIDDLE) { for (i = 0; i < lnr; i++) linedata[i] = (linedata3[i] - linedata[i]) / 2; for (i = 0; i <= slen; i++) { ct->xof += linedata[ct->linenr]; ct++; } } else if ((cu->spacemode == CU_FLUSH) && (cu->tb[0].w != 0.0f)) { for (i = 0; i < lnr; i++) if (linedata2[i] > 1) linedata[i] = (linedata3[i] - linedata[i]) / (linedata2[i] - 1); for (i = 0; i <= slen; i++) { for (j = i; (!ELEM3(mem[j], '\0', '\n', '\r')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) { /* do nothing */ } // if ((mem[j] != '\r') && (mem[j] != '\n') && (mem[j])) { ct->xof += ct->charnr * linedata[ct->linenr]; // } ct++; } } else if ((cu->spacemode == CU_JUSTIFY) && (cu->tb[0].w != 0.0f)) { float curofs = 0.0f; for (i = 0; i <= slen; i++) { for (j = i; (mem[j]) && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak == 0) && (j < slen); j++) { /* pass */ } if ((mem[j] != '\r') && (mem[j] != '\n') && ((chartransdata[j].dobreak != 0))) { if (mem[i] == ' ') curofs += (linedata3[ct->linenr] - linedata[ct->linenr]) / linedata4[ct->linenr]; ct->xof += curofs; } if (mem[i] == '\n' || mem[i] == '\r' || chartransdata[i].dobreak) curofs = 0; ct++; } } } /* TEXT ON CURVE */ /* Note: Only OB_CURVE objects could have a path */ if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) { Curve *cucu = cu->textoncurve->data; int oldflag = cucu->flag; cucu->flag |= (CU_PATH + CU_FOLLOW); if (cu->textoncurve->curve_cache == NULL || cu->textoncurve->curve_cache->path == NULL) { BKE_displist_make_curveTypes(scene, cu->textoncurve, 0); } if (cu->textoncurve->curve_cache->path) { float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; invert_m4_m4(imat, ob->obmat); copy_m3_m4(imat3, imat); copy_m3_m4(cmat, cu->textoncurve->obmat); mul_m3_m3m3(cmat, cmat, imat3); sizefac = normalize_v3(cmat[0]) / cu->fsize; minx = miny = 1.0e20f; maxx = maxy = -1.0e20f; ct = chartransdata; for (i = 0; i <= slen; i++, ct++) { if (minx > ct->xof) minx = ct->xof; if (maxx < ct->xof) maxx = ct->xof; if (miny > ct->yof) miny = ct->yof; if (maxy < ct->yof) maxy = ct->yof; } /* we put the x-coordinaat exact at the curve, the y is rotated */ /* length correction */ distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx); timeofs = 0.0f; if (distfac > 1.0f) { /* path longer than text: spacemode involves */ distfac = 1.0f / distfac; if (cu->spacemode == CU_RIGHT) { timeofs = 1.0f - distfac; } else if (cu->spacemode == CU_MIDDLE) { timeofs = (1.0f - distfac) / 2.0f; } else if (cu->spacemode == CU_FLUSH) { distfac = 1.0f; } } else { distfac = 1.0; } distfac /= (maxx - minx); timeofs += distfac * cu->xof; /* not cyclic */ ct = chartransdata; for (i = 0; i <= slen; i++, ct++) { float ctime, dtime, vec[4], tvec[4], rotvec[3]; float si, co; /* rotate around center character */ ascii = mem[i]; che = find_vfont_char(vfd, ascii); twidth = char_width(cu, che, info); dtime = distfac * 0.5f * twidth; ctime = timeofs + distfac * (ct->xof - minx); CLAMP(ctime, 0.0f, 1.0f); /* calc the right loc AND the right rot separately */ /* vec, tvec need 4 items */ where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL); where_on_path(cu->textoncurve, ctime + dtime, tvec, rotvec, NULL, NULL, NULL); mul_v3_fl(vec, sizefac); ct->rot = (float)M_PI - atan2f(rotvec[1], rotvec[0]); si = sinf(ct->rot); co = cosf(ct->rot); yof = ct->yof; ct->xof = vec[0] + si * yof; ct->yof = vec[1] + co * yof; } cucu->flag = oldflag; } } if (cu->selboxes) { ct = chartransdata; for (i = 0; i <= selend; i++, ct++) { if (i >= selstart) { cu->selboxes[i - selstart].x = ct->xof * cu->fsize; cu->selboxes[i - selstart].y = ct->yof * cu->fsize; } } } if (mode == FO_CURSUP || mode == FO_CURSDOWN || mode == FO_PAGEUP || mode == FO_PAGEDOWN) { /* 2: curs up * 3: curs down */ ct = chartransdata + cu->pos; if ((mode == FO_CURSUP || mode == FO_PAGEUP) && ct->linenr == 0) { /* pass */ } else if ((mode == FO_CURSDOWN || mode == FO_PAGEDOWN) && ct->linenr == lnr) { /* pass */ } else { switch (mode) { case FO_CURSUP: lnr = ct->linenr - 1; break; case FO_CURSDOWN: lnr = ct->linenr + 1; break; case FO_PAGEUP: lnr = ct->linenr - 10; break; case FO_PAGEDOWN: lnr = ct->linenr + 10; break; } cnr = ct->charnr; /* seek for char with lnr en cnr */ cu->pos = 0; ct = chartransdata; for (i = 0; i < slen; i++) { if (ct->linenr == lnr) { if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) { break; } } else if (ct->linenr > lnr) { break; } cu->pos++; ct++; } } } /* cursor first */ if (cu->editfont) { float si, co; ct = chartransdata + cu->pos; si = sinf(ct->rot); co = cosf(ct->rot); f = cu->editfont->textcurs[0]; f[0] = cu->fsize * (-0.1f * co + ct->xof); f[1] = cu->fsize * ( 0.1f * si + ct->yof); f[2] = cu->fsize * ( 0.1f * co + ct->xof); f[3] = cu->fsize * (-0.1f * si + ct->yof); f[4] = cu->fsize * ( 0.1f * co + 0.8f * si + ct->xof); f[5] = cu->fsize * (-0.1f * si + 0.8f * co + ct->yof); f[6] = cu->fsize * (-0.1f * co + 0.8f * si + ct->xof); f[7] = cu->fsize * ( 0.1f * si + 0.8f * co + ct->yof); } MEM_freeN(linedata); MEM_freeN(linedata2); MEM_freeN(linedata3); MEM_freeN(linedata4); if (mode == FO_SELCHANGE) { MEM_freeN(chartransdata); MEM_freeN(mem); return NULL; } if (mode == FO_EDIT) { /* make nurbdata */ BKE_nurbList_free(&cu->nurb); ct = chartransdata; if (cu->sepchar == 0) { for (i = 0; i < slen; i++) { unsigned long cha = (uintptr_t) mem[i]; info = &(custrinfo[i]); if (info->mat_nr > (ob->totcol)) { /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ info->mat_nr = 0; } /* We do not want to see any character for \n or \r */ if (cha != '\n' && cha != '\r') buildchar(bmain, cu, cha, info, ct->xof, ct->yof, ct->rot, i); if ((info->flag & CU_CHINFO_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) { float ulwidth, uloverlap = 0.0f; if ((i < (slen - 1)) && (mem[i + 1] != '\n') && (mem[i + 1] != '\r') && ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) && ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0)) { uloverlap = xtrax + 0.1f; } /* Find the character, the characters has to be in the memory already * since character checking has been done earlier already. */ che = find_vfont_char(vfd, cha); twidth = char_width(cu, che, info); ulwidth = cu->fsize * ((twidth * (1.0f + (info->kern / 40.0f))) + uloverlap); build_underline(cu, ct->xof * cu->fsize, ct->yof * cu->fsize + (cu->ulpos - 0.05f) * cu->fsize, ct->xof * cu->fsize + ulwidth, ct->yof * cu->fsize + (cu->ulpos - 0.05f) * cu->fsize - cu->ulheight * cu->fsize, i, info->mat_nr); } ct++; } } else { int outta = 0; for (i = 0; (i < slen) && (outta == 0); i++) { ascii = mem[i]; info = &(custrinfo[i]); if (cu->sepchar == (i + 1)) { float vecyo[3]; vecyo[0] = ct->xof; vecyo[1] = ct->yof; vecyo[2] = 0.0f; mem[0] = ascii; mem[1] = 0; custrinfo[0] = *info; cu->pos = 1; cu->len = 1; mul_v3_m4v3(ob->loc, ob->obmat, vecyo); outta = 1; cu->sepchar = 0; } ct++; } } } if (mode == FO_DUPLI) { MEM_freeN(mem); return chartransdata; } if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; }
static DerivedMesh *arrayModifier_doArray( ArrayModifierData *amd, Scene *scene, Object *ob, DerivedMesh *dm, ModifierApplyFlag flag) { const float eps = 1e-6f; const MVert *src_mvert; MVert *mv, *mv_prev, *result_dm_verts; MEdge *me; MLoop *ml; MPoly *mp; int i, j, c, count; float length = amd->length; /* offset matrix */ float offset[4][4]; float scale[3]; bool offset_has_scale; float current_offset[4][4]; float final_offset[4][4]; int *full_doubles_map = NULL; int tot_doubles; const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0; const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge; const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob); /* allow pole vertices to be used by many faces */ const bool with_follow = use_offset_ob; int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0; int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0; int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0; int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys; int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts; DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL; chunk_nverts = dm->getNumVerts(dm); chunk_nedges = dm->getNumEdges(dm); chunk_nloops = dm->getNumLoops(dm); chunk_npolys = dm->getNumPolys(dm); count = amd->count; if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) { start_cap_dm = get_dm_for_modifier(amd->start_cap, flag); if (start_cap_dm) { start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm); start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm); start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm); start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm); } } if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) { end_cap_dm = get_dm_for_modifier(amd->end_cap, flag); if (end_cap_dm) { end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm); end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm); end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm); end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm); } } /* Build up offset array, cumulating all settings options */ unit_m4(offset); src_mvert = dm->getVertArray(dm); if (amd->offset_type & MOD_ARR_OFF_CONST) add_v3_v3v3(offset[3], offset[3], amd->offset); if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { for (j = 0; j < 3; j++) offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j); } if (use_offset_ob) { float obinv[4][4]; float result_mat[4][4]; if (ob) invert_m4_m4(obinv, ob->obmat); else unit_m4(obinv); mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); copy_m4_m4(offset, result_mat); } /* Check if there is some scaling. If scaling, then we will not translate mapping */ mat4_to_size(scale, offset); offset_has_scale = !is_one_v3(scale); if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { Curve *cu = amd->curve_ob->data; if (cu) { #ifdef CYCLIC_DEPENDENCY_WORKAROUND if (amd->curve_ob->curve_cache == NULL) { BKE_displist_make_curveTypes(scene, amd->curve_ob, false); } #endif if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) { float scale = mat4_to_scale(amd->curve_ob->obmat); length = scale * amd->curve_ob->curve_cache->path->totdist; } } } /* calculate the maximum number of copies which will fit within the * prescribed length */ if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { float dist = len_v3(offset[3]); if (dist > eps) { /* this gives length = first copy start to last copy end * add a tiny offset for floating point rounding errors */ count = (length + eps) / dist + 1; } else { /* if the offset has no translation, just make one copy */ count = 1; } } if (count < 1) count = 1; /* The number of verts, edges, loops, polys, before eventually merging doubles */ result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts; result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges; result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops; result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys; /* Initialize a result dm */ result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys); result_dm_verts = CDDM_get_verts(result); if (use_merge) { /* Will need full_doubles_map for handling merge */ full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map"); copy_vn_i(full_doubles_map, result_nverts, -1); } /* copy customdata to original geometry */ DM_copy_vert_data(dm, result, 0, 0, chunk_nverts); DM_copy_edge_data(dm, result, 0, 0, chunk_nedges); DM_copy_loop_data(dm, result, 0, 0, chunk_nloops); DM_copy_poly_data(dm, result, 0, 0, chunk_npolys); /* subsurf for eg wont have mesh data in the * now add mvert/medge/mface layers */ if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) { dm->copyVertArray(dm, result_dm_verts); } if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) { dm->copyEdgeArray(dm, CDDM_get_edges(result)); } if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) { dm->copyLoopArray(dm, CDDM_get_loops(result)); dm->copyPolyArray(dm, CDDM_get_polys(result)); } /* Remember first chunk, in case of cap merge */ first_chunk_start = 0; first_chunk_nverts = chunk_nverts; unit_m4(current_offset); for (c = 1; c < count; c++) { /* copy customdata to new geometry */ DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts); DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges); DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops); DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys); mv_prev = result_dm_verts; mv = mv_prev + c * chunk_nverts; /* recalculate cumulative offset here */ mul_m4_m4m4(current_offset, current_offset, offset); /* apply offset to all new verts */ for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) { mul_m4_v3(current_offset, mv->co); /* We have to correct normals too, if we do not tag them as dirty! */ if (!use_recalc_normals) { float no[3]; normal_short_to_float_v3(no, mv->no); mul_mat3_m4_v3(current_offset, no); normalize_v3(no); normal_float_to_short_v3(mv->no, no); } } /* adjust edge vertex indices */ me = CDDM_get_edges(result) + c * chunk_nedges; for (i = 0; i < chunk_nedges; i++, me++) { me->v1 += c * chunk_nverts; me->v2 += c * chunk_nverts; } mp = CDDM_get_polys(result) + c * chunk_npolys; for (i = 0; i < chunk_npolys; i++, mp++) { mp->loopstart += c * chunk_nloops; } /* adjust loop vertex and edge indices */ ml = CDDM_get_loops(result) + c * chunk_nloops; for (i = 0; i < chunk_nloops; i++, ml++) { ml->v += c * chunk_nverts; ml->e += c * chunk_nedges; } /* Handle merge between chunk n and n-1 */ if (use_merge && (c >= 1)) { if (!offset_has_scale && (c >= 2)) { /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1 * ... that is except if scaling makes the distance grow */ int k; int this_chunk_index = c * chunk_nverts; int prev_chunk_index = (c - 1) * chunk_nverts; for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) { int target = full_doubles_map[prev_chunk_index]; if (target != -1) { target += chunk_nverts; /* translate mapping */ if (full_doubles_map[target] != -1) { if (with_follow) { target = full_doubles_map[target]; } else { /* The rule here is to not follow mapping to chunk N-2, which could be too far * so if target vertex was itself mapped, then this vertex is not mapped */ target = -1; } } } full_doubles_map[this_chunk_index] = target; } } else { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, (c - 1) * chunk_nverts, chunk_nverts, c * chunk_nverts, chunk_nverts, amd->merge_dist, with_follow); } } } last_chunk_start = (count - 1) * chunk_nverts; last_chunk_nverts = chunk_nverts; copy_m4_m4(final_offset, current_offset); if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) { /* Merge first and last copies */ dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, first_chunk_start, first_chunk_nverts, amd->merge_dist, with_follow); } /* start capping */ if (start_cap_dm) { float start_offset[4][4]; int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts; invert_m4_m4(start_offset, offset); dm_merge_transform( result, start_cap_dm, start_offset, result_nverts - start_cap_nverts - end_cap_nverts, result_nedges - start_cap_nedges - end_cap_nedges, result_nloops - start_cap_nloops - end_cap_nloops, result_npolys - start_cap_npolys - end_cap_npolys, start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys); /* Identify doubles with first chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, first_chunk_start, first_chunk_nverts, start_cap_start, start_cap_nverts, amd->merge_dist, false); } } if (end_cap_dm) { float end_offset[4][4]; int end_cap_start = result_nverts - end_cap_nverts; mul_m4_m4m4(end_offset, current_offset, offset); dm_merge_transform( result, end_cap_dm, end_offset, result_nverts - end_cap_nverts, result_nedges - end_cap_nedges, result_nloops - end_cap_nloops, result_npolys - end_cap_npolys, end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys); /* Identify doubles with last chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, end_cap_start, end_cap_nverts, amd->merge_dist, false); } } /* done capping */ /* Handle merging */ tot_doubles = 0; if (use_merge) { for (i = 0; i < result_nverts; i++) { if (full_doubles_map[i] != -1) { if (i == full_doubles_map[i]) { full_doubles_map[i] = -1; } else { tot_doubles++; } } } if (tot_doubles > 0) { result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL); } MEM_freeN(full_doubles_map); } /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm! * TODO: we may need to set other dirty flags as well? */ if (use_recalc_normals) { result->dirty |= DM_DIRTY_NORMALS; } return result; }
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames , Object * ob_arm, Bone *bone , const std::string& anim_id) { COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::Float4x4Source source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(frames.size()); source.setAccessorStride(16); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, false, NULL, true); source.prepareToAppendValues(); bPoseChannel *parchan = NULL; bPoseChannel *pchan = NULL; bPose *pose = ob_arm->pose; pchan = get_pose_channel(pose, bone->name); if (!pchan) return ""; parchan = pchan->parent; enable_fcurves(ob_arm->adt->action, bone->name); std::vector<float>::iterator it; int j = 0; for (it = frames.begin(); it != frames.end(); it++) { float mat[4][4], ipar[4][4]; float ctime = BKE_frame_to_ctime(scene, *it); BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM); where_is_pose_bone(scene, ob_arm, pchan, ctime, 1); // compute bone local mat if (bone->parent) { invert_m4_m4(ipar, parchan->pose_mat); mult_m4_m4m4(mat, ipar, pchan->pose_mat); } else copy_m4_m4(mat, pchan->pose_mat); UnitConverter converter; // SECOND_LIFE_COMPATIBILITY // AFAIK animation to second life is via BVH, but no // reason to not have the collada-animation be correct if(export_settings->second_life) { float temp[4][4]; copy_m4_m4(temp, bone->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; invert_m4(temp); mult_m4_m4m4(mat, mat, temp); if(bone->parent) { copy_m4_m4(temp, bone->parent->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; mult_m4_m4m4(mat, temp, mat); } } float outmat[4][4]; converter.mat4_to_dae(outmat,mat); source.appendValues(outmat); j++; } enable_fcurves(ob_arm->adt->action, NULL); source.finish(); return source_id; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { UVWarpModifierData *umd = (UVWarpModifierData *) md; int numPolys, numLoops; MPoly *mpoly; MLoop *mloop; MLoopUV *mloopuv; MDeformVert *dvert; int defgrp_index; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; float mat_src[4][4]; float mat_dst[4][4]; float imat_dst[4][4]; float warp_mat[4][4]; const int axis_u = umd->axis_u; const int axis_v = umd->axis_v; /* make sure there are UV Maps available */ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { return dm; } else if (ELEM(NULL, umd->object_src, umd->object_dst)) { modifier_setError(md, "From/To objects must be set"); return dm; } /* make sure anything moving UVs is available */ matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src); matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst); invert_m4_m4(imat_dst, mat_dst); mul_m4_m4m4(warp_mat, imat_dst, mat_src); /* apply warp */ if (!is_zero_v2(umd->center)) { float mat_cent[4][4]; float imat_cent[4][4]; unit_m4(mat_cent); mat_cent[3][axis_u] = umd->center[0]; mat_cent[3][axis_v] = umd->center[1]; invert_m4_m4(imat_cent, mat_cent); mul_m4_m4m4(warp_mat, warp_mat, imat_cent); mul_m4_m4m4(warp_mat, mat_cent, warp_mat); } /* make sure we're using an existing layer */ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname); numPolys = dm->getNumPolys(dm); numLoops = dm->getNumLoops(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); /* make sure we are not modifying the original UV map */ mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops); modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index); UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv, .dvert = dvert, .defgrp_index = defgrp_index, .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v}; BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000); dm->dirty |= DM_DIRTY_TESS_CDLAYERS; return dm; }
static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); ParticleData *pa; PTCacheEdit *edit; PTCacheEditPoint *point; PTCacheEditKey *ekey = NULL; HairKey *key; BVHTreeFromMesh bvhtree= {NULL}; BVHTreeNearest nearest; MFace *mface; DerivedMesh *dm = NULL; int numverts; int i, k; float hairmat[4][4], imat[4][4]; float v[4][3], vec[3]; if(!psys || !psys->part || psys->part->type != PART_HAIR) return; edit= psys->edit; point= edit ? edit->points : NULL; if(psmd->dm->deformedOnly) /* we don't want to mess up psmd->dm when converting to global coordinates below */ dm= CDDM_copy(psmd->dm); else dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); numverts = dm->getNumVerts (dm); /* convert to global coordinates */ for (i=0; i<numverts; i++) mul_m4_v3(ob->obmat, CDDM_get_vert(dm, i)->co); bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6); for(i=0, pa= psys->particles; i<psys->totpart; i++,pa++) { key = pa->hair; nearest.index = -1; nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree); if(nearest.index == -1) { if (G.f & G_DEBUG) printf("No nearest point found for hair root!"); continue; } mface = CDDM_get_face(dm,nearest.index); copy_v3_v3(v[0], CDDM_get_vert(dm,mface->v1)->co); copy_v3_v3(v[1], CDDM_get_vert(dm,mface->v2)->co); copy_v3_v3(v[2], CDDM_get_vert(dm,mface->v3)->co); if(mface->v4) { copy_v3_v3(v[3], CDDM_get_vert(dm,mface->v4)->co); interp_weights_poly_v3( pa->fuv,v, 4, nearest.co); } else interp_weights_poly_v3( pa->fuv,v, 3, nearest.co); pa->num = nearest.index; pa->num_dmcache = psys_particle_dm_face_lookup(ob,psmd->dm,pa->num,pa->fuv,NULL); psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); invert_m4_m4(imat,hairmat); VECSUB(vec, nearest.co, key->co); if(point) { ekey = point->keys; point++; } for(k=0,key=pa->hair; k<pa->totkey; k++,key++) { VECADD(key->co, key->co, vec); mul_m4_v3(imat,key->co); if(ekey) { ekey->flag |= PEK_USE_WCO; ekey++; } } } free_bvhtree_from_mesh(&bvhtree); dm->release(dm); psys_free_path_cache(psys, psys->edit); psys->flag &= ~PSYS_GLOBAL_HAIR; PE_update_object(scene, ob, 0); }
static int armature_calc_roll_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); eCalcRollTypes type = RNA_enum_get(op->ptr, "type"); const bool axis_only = RNA_boolean_get(op->ptr, "axis_only"); /* axis_flip when matching the active bone never makes sense */ bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") : (type >= CALC_ROLL_TAN_NEG_X) ? true : false); float imat[3][3]; bArmature *arm = ob->data; EditBone *ebone; if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) { type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X); axis_flip = true; } copy_m3_m4(imat, ob->obmat); invert_m3(imat); if (type == CALC_ROLL_CURSOR) { /* Cursor */ Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); /* can be NULL */ float cursor_local[3]; const float *cursor = ED_view3d_cursor3d_get(scene, v3d); invert_m4_m4(ob->imat, ob->obmat); copy_v3_v3(cursor_local, cursor); mul_m4_v3(ob->imat, cursor_local); /* cursor */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) { float cursor_rel[3]; sub_v3_v3v3(cursor_rel, cursor_local, ebone->head); if (axis_flip) negate_v3(cursor_rel); if (normalize_v3(cursor_rel) != 0.0f) { ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only); } } } } else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) { for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (ebone->parent) { bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)); bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) && EBONE_EDITABLE(ebone->parent)); if (is_edit || is_edit_parent) { EditBone *ebone_other = ebone->parent; float dir_a[3]; float dir_b[3]; float vec[3]; bool is_vec_zero; sub_v3_v3v3(dir_a, ebone->tail, ebone->head); normalize_v3(dir_a); /* find the first bone in the chane with a different direction */ do { sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail); normalize_v3(dir_b); if (type == CALC_ROLL_TAN_POS_Z) { cross_v3_v3v3(vec, dir_a, dir_b); } else { add_v3_v3v3(vec, dir_a, dir_b); } } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) && (ebone_other = ebone_other->parent)); if (!is_vec_zero) { if (axis_flip) negate_v3(vec); if (is_edit) { ebone->roll = ED_rollBoneToVector(ebone, vec, axis_only); } /* parentless bones use cross product with child */ if (is_edit_parent) { if (ebone->parent->parent == NULL) { ebone->parent->roll = ED_rollBoneToVector(ebone->parent, vec, axis_only); } } } } } } } else { float vec[3] = {0.0f, 0.0f, 0.0f}; if (type == CALC_ROLL_VIEW) { /* View */ RegionView3D *rv3d = CTX_wm_region_view3d(C); if (rv3d == NULL) { BKE_report(op->reports, RPT_ERROR, "No region view3d available"); return OPERATOR_CANCELLED; } copy_v3_v3(vec, rv3d->viewinv[2]); mul_m3_v3(imat, vec); } else if (type == CALC_ROLL_ACTIVE) { float mat[3][3]; ebone = (EditBone *)arm->act_edbone; if (ebone == NULL) { BKE_report(op->reports, RPT_ERROR, "No active bone set"); return OPERATOR_CANCELLED; } ED_armature_ebone_to_mat3(ebone, mat); copy_v3_v3(vec, mat[2]); } else { /* Axis */ assert(type <= 5); if (type < 3) vec[type] = 1.0f; else vec[type - 2] = -1.0f; mul_m3_v3(imat, vec); normalize_v3(vec); } if (axis_flip) negate_v3(vec); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) { /* roll func is a callback which assumes that all is well */ ebone->roll = ED_rollBoneToVector(ebone, vec, axis_only); } } } if (arm->flag & ARM_MIRROR_EDIT) { for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) { EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, ebone); if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) { ebone->roll = -ebone_mirr->roll; } } } } /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); return OPERATOR_FINISHED; }
static DerivedMesh *arrayModifier_doArray( ArrayModifierData *amd, Scene *scene, Object *ob, DerivedMesh *dm, ModifierApplyFlag flag) { const float eps = 1e-6f; const MVert *src_mvert; MVert *mv, *mv_prev, *result_dm_verts; MEdge *me; MLoop *ml; MPoly *mp; int i, j, c, count; float length = amd->length; /* offset matrix */ float offset[4][4]; float scale[3]; bool offset_has_scale; float current_offset[4][4]; float final_offset[4][4]; int *full_doubles_map = NULL; int tot_doubles; const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0; const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge; const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob); int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0; int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0; int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0; int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys; int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts; DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL; int *vgroup_start_cap_remap = NULL; int vgroup_start_cap_remap_len = 0; int *vgroup_end_cap_remap = NULL; int vgroup_end_cap_remap_len = 0; chunk_nverts = dm->getNumVerts(dm); chunk_nedges = dm->getNumEdges(dm); chunk_nloops = dm->getNumLoops(dm); chunk_npolys = dm->getNumPolys(dm); count = amd->count; if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) { vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(amd->start_cap, ob, &vgroup_start_cap_remap_len); start_cap_dm = get_dm_for_modifier(amd->start_cap, flag); if (start_cap_dm) { start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm); start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm); start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm); start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm); } } if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) { vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(amd->end_cap, ob, &vgroup_end_cap_remap_len); end_cap_dm = get_dm_for_modifier(amd->end_cap, flag); if (end_cap_dm) { end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm); end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm); end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm); end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm); } } /* Build up offset array, cumulating all settings options */ unit_m4(offset); src_mvert = dm->getVertArray(dm); if (amd->offset_type & MOD_ARR_OFF_CONST) { add_v3_v3(offset[3], amd->offset); } if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { float min[3], max[3]; const MVert *src_mv; INIT_MINMAX(min, max); for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) { minmax_v3v3_v3(min, max, src_mv->co); } for (j = 3; j--; ) { offset[3][j] += amd->scale[j] * (max[j] - min[j]); } } if (use_offset_ob) { float obinv[4][4]; float result_mat[4][4]; if (ob) invert_m4_m4(obinv, ob->obmat); else unit_m4(obinv); mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); copy_m4_m4(offset, result_mat); } /* Check if there is some scaling. If scaling, then we will not translate mapping */ mat4_to_size(scale, offset); offset_has_scale = !is_one_v3(scale); if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { Curve *cu = amd->curve_ob->data; if (cu) { #ifdef CYCLIC_DEPENDENCY_WORKAROUND if (amd->curve_ob->curve_cache == NULL) { BKE_displist_make_curveTypes(scene, amd->curve_ob, false); } #endif if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) { float scale_fac = mat4_to_scale(amd->curve_ob->obmat); length = scale_fac * amd->curve_ob->curve_cache->path->totdist; } } } /* calculate the maximum number of copies which will fit within the * prescribed length */ if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { float dist = len_v3(offset[3]); if (dist > eps) { /* this gives length = first copy start to last copy end * add a tiny offset for floating point rounding errors */ count = (length + eps) / dist + 1; } else { /* if the offset has no translation, just make one copy */ count = 1; } } if (count < 1) count = 1; /* The number of verts, edges, loops, polys, before eventually merging doubles */ result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts; result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges; result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops; result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys; /* Initialize a result dm */ result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys); result_dm_verts = CDDM_get_verts(result); if (use_merge) { /* Will need full_doubles_map for handling merge */ full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map"); copy_vn_i(full_doubles_map, result_nverts, -1); } /* copy customdata to original geometry */ DM_copy_vert_data(dm, result, 0, 0, chunk_nverts); DM_copy_edge_data(dm, result, 0, 0, chunk_nedges); DM_copy_loop_data(dm, result, 0, 0, chunk_nloops); DM_copy_poly_data(dm, result, 0, 0, chunk_npolys); /* Subsurf for eg won't have mesh data in the custom data arrays. * now add mvert/medge/mpoly layers. */ if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) { dm->copyVertArray(dm, result_dm_verts); } if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) { dm->copyEdgeArray(dm, CDDM_get_edges(result)); } if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) { dm->copyLoopArray(dm, CDDM_get_loops(result)); dm->copyPolyArray(dm, CDDM_get_polys(result)); } /* Remember first chunk, in case of cap merge */ first_chunk_start = 0; first_chunk_nverts = chunk_nverts; unit_m4(current_offset); for (c = 1; c < count; c++) { /* copy customdata to new geometry */ DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts); DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges); DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops); DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys); mv_prev = result_dm_verts; mv = mv_prev + c * chunk_nverts; /* recalculate cumulative offset here */ mul_m4_m4m4(current_offset, current_offset, offset); /* apply offset to all new verts */ for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) { mul_m4_v3(current_offset, mv->co); /* We have to correct normals too, if we do not tag them as dirty! */ if (!use_recalc_normals) { float no[3]; normal_short_to_float_v3(no, mv->no); mul_mat3_m4_v3(current_offset, no); normalize_v3(no); normal_float_to_short_v3(mv->no, no); } } /* adjust edge vertex indices */ me = CDDM_get_edges(result) + c * chunk_nedges; for (i = 0; i < chunk_nedges; i++, me++) { me->v1 += c * chunk_nverts; me->v2 += c * chunk_nverts; } mp = CDDM_get_polys(result) + c * chunk_npolys; for (i = 0; i < chunk_npolys; i++, mp++) { mp->loopstart += c * chunk_nloops; } /* adjust loop vertex and edge indices */ ml = CDDM_get_loops(result) + c * chunk_nloops; for (i = 0; i < chunk_nloops; i++, ml++) { ml->v += c * chunk_nverts; ml->e += c * chunk_nedges; } /* Handle merge between chunk n and n-1 */ if (use_merge && (c >= 1)) { if (!offset_has_scale && (c >= 2)) { /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1 * ... that is except if scaling makes the distance grow */ int k; int this_chunk_index = c * chunk_nverts; int prev_chunk_index = (c - 1) * chunk_nverts; for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) { int target = full_doubles_map[prev_chunk_index]; if (target != -1) { target += chunk_nverts; /* translate mapping */ while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) { /* If target is already mapped, we only follow that mapping if final target remains * close enough from current vert (otherwise no mapping at all). */ if (compare_len_v3v3(result_dm_verts[this_chunk_index].co, result_dm_verts[full_doubles_map[target]].co, amd->merge_dist)) { target = full_doubles_map[target]; } else { target = -1; } } } full_doubles_map[this_chunk_index] = target; } } else { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, (c - 1) * chunk_nverts, chunk_nverts, c * chunk_nverts, chunk_nverts, amd->merge_dist); } } } /* handle UVs */ if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) { const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV); for (i = 0; i < totuv; i++) { MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, i); dmloopuv += chunk_nloops; for (c = 1; c < count; c++) { const float uv_offset[2] = { amd->uv_offset[0] * (float)c, amd->uv_offset[1] * (float)c, }; int l_index = chunk_nloops; for (; l_index-- != 0; dmloopuv++) { dmloopuv->uv[0] += uv_offset[0]; dmloopuv->uv[1] += uv_offset[1]; } } } } last_chunk_start = (count - 1) * chunk_nverts; last_chunk_nverts = chunk_nverts; copy_m4_m4(final_offset, current_offset); if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) { /* Merge first and last copies */ dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, first_chunk_start, first_chunk_nverts, amd->merge_dist); } /* start capping */ if (start_cap_dm) { float start_offset[4][4]; int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts; invert_m4_m4(start_offset, offset); dm_merge_transform( result, start_cap_dm, start_offset, result_nverts - start_cap_nverts - end_cap_nverts, result_nedges - start_cap_nedges - end_cap_nedges, result_nloops - start_cap_nloops - end_cap_nloops, result_npolys - start_cap_npolys - end_cap_npolys, start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys, vgroup_start_cap_remap, vgroup_start_cap_remap_len); /* Identify doubles with first chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, first_chunk_start, first_chunk_nverts, start_cap_start, start_cap_nverts, amd->merge_dist); } } if (end_cap_dm) { float end_offset[4][4]; int end_cap_start = result_nverts - end_cap_nverts; mul_m4_m4m4(end_offset, current_offset, offset); dm_merge_transform( result, end_cap_dm, end_offset, result_nverts - end_cap_nverts, result_nedges - end_cap_nedges, result_nloops - end_cap_nloops, result_npolys - end_cap_npolys, end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys, vgroup_end_cap_remap, vgroup_end_cap_remap_len); /* Identify doubles with last chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, end_cap_start, end_cap_nverts, amd->merge_dist); } } /* done capping */ /* Handle merging */ tot_doubles = 0; if (use_merge) { for (i = 0; i < result_nverts; i++) { int new_i = full_doubles_map[i]; if (new_i != -1) { /* We have to follow chains of doubles (merge start/end especially is likely to create some), * those are not supported at all by CDDM_merge_verts! */ while (!ELEM(full_doubles_map[new_i], -1, new_i)) { new_i = full_doubles_map[new_i]; } if (i == new_i) { full_doubles_map[i] = -1; } else { full_doubles_map[i] = new_i; tot_doubles++; } } } if (tot_doubles > 0) { result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL); } MEM_freeN(full_doubles_map); } /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm! * TODO: we may need to set other dirty flags as well? */ if (use_recalc_normals) { result->dirty |= DM_DIRTY_NORMALS; } if (vgroup_start_cap_remap) { MEM_freeN(vgroup_start_cap_remap); } if (vgroup_end_cap_remap) { MEM_freeN(vgroup_end_cap_remap); } return result; }