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;
	}
}
Esempio n. 2
0
/* 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);
}
Esempio n. 3
0
/* 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);
	}
}
Esempio n. 4
0
/* 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 */
	}
}
Esempio n. 5
0
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);
				}
			}
		}
	}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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(&params);
				BKE_camera_params_from_object(&params, projectors[i].ob);

				/* compute matrix, viewplane, .. */
				BKE_camera_params_compute_viewplane(&params, 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(&params);
				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 &param = 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;
}
Esempio n. 9
0
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);
}
Esempio n. 10
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);
				}
			}
		}
	}
}
Esempio n. 11
0
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;
		}
	}
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
/* 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;
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
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);
}
Esempio n. 18
0
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);
}
Esempio n. 19
0
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;
		}
	}
}
Esempio n. 20
0
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);
}
Esempio n. 21
0
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 &param = 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;
}
Esempio n. 23
0
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;
	}
}
Esempio n. 24
0
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;
}
Esempio n. 25
0
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;
}
Esempio n. 26
0
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 &param = 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;
}
Esempio n. 27
0
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;
}
Esempio n. 28
0
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);
}
Esempio n. 29
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;
}
Esempio n. 30
0
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;
}