Exemple #1
0
// TODO: should we have a separate file for things like this?
static void fmod_envelope_deletepoint_cb(bContext *UNUSED(C), void *fcm_dv, void *ind_v)
{
	FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
	FCM_EnvelopeData *fedn;
	int index = GET_INT_FROM_POINTER(ind_v);
	
	/* check that no data exists for the current frame... */
	if (env->totvert > 1) {
		/* allocate a new smaller array */
		fedn = MEM_callocN(sizeof(FCM_EnvelopeData) * (env->totvert - 1), "FCM_EnvelopeData");

		memcpy(fedn, env->data, sizeof(FCM_EnvelopeData) * (index));
		memcpy(fedn + index, env->data + (index + 1), sizeof(FCM_EnvelopeData) * ((env->totvert - index) - 1));
		
		/* free old array, and set the new */
		MEM_freeN(env->data);
		env->data = fedn;
		env->totvert--;
	}
	else {
		/* just free array, since the only vert was deleted */
		if (env->data) {
			MEM_freeN(env->data);
			env->data = NULL;
		}
		env->totvert = 0;
	}
}
static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type)
{
	float hsv[3];
	int i = GET_INT_FROM_POINTER(type);
	float f = PyFloat_AsDouble(value);

	if (f == -1 && PyErr_Occurred()) {
		PyErr_SetString(PyExc_TypeError,
		                "color.h/s/v = value: "
		                "assigned value not a number");
		return -1;
	}

	if (BaseMath_ReadCallback(self) == -1)
		return -1;

	rgb_to_hsv_v(self->col, hsv);
	CLAMP(f, 0.0f, 1.0f);
	hsv[i] = f;
	hsv_to_rgb_v(hsv, self->col);

	if (BaseMath_WriteCallback(self) == -1)
		return -1;

	return 0;
}
static PyObject *bpy_bmlayeraccess_collection_get(BPy_BMLayerAccess *self, void *flag)
{
	const int type = (int)GET_INT_FROM_POINTER(flag);

	BPY_BM_CHECK_OBJ(self);

	return BPy_BMLayerCollection_CreatePyObject(self->bm, self->htype, type);
}
bool BM_elem_cb_check_hflag_ex(BMElem *ele, void *user_data)
{
	const uint hflag_pair = GET_INT_FROM_POINTER(user_data);
	const char hflag_p = (hflag_pair & 0xff);
	const char hflag_n = (hflag_pair >> 8);

	return ((BM_elem_flag_test(ele, hflag_p) != 0) &&
	        (BM_elem_flag_test(ele, hflag_n) == 0));
}
static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	SpaceNode *snode = CTX_wm_space_node(C);
	bNodeTree *ntree;
	int nodeclass = GET_INT_FROM_POINTER(arg_nodeclass);
	int event, compatibility = 0;
	
	ntree = snode->nodetree;
	
	if (!ntree) {
		uiItemS(layout);
		return;
	}

	if (ntree->type == NTREE_SHADER) {
		if (BKE_scene_use_new_shading_nodes(scene))
			compatibility = NODE_NEW_SHADING;
		else
			compatibility = NODE_OLD_SHADING;
	}
	
	if (nodeclass == NODE_CLASS_GROUP) {
		bNodeTree *ngroup;
		
		uiLayoutSetFunc(layout, do_node_add_group, NULL);
		
		/* XXX hack: negative numbers used for empty group types */
		if (node_tree_has_type(ntree->type, NODE_GROUP))
			uiItemV(layout, IFACE_("New Group"), 0, -NODE_GROUP);
		uiItemS(layout);
		
		for (ngroup = bmain->nodetree.first, event = 0; ngroup; ngroup = ngroup->id.next, ++event) {
			/* only use group trees */
			if (ngroup->type == ntree->type && ngroup->nodetype == NODE_GROUP) {
				uiItemV(layout, ngroup->id.name + 2, 0, event);
			}
		}
	}
	else {
		bNodeType *ntype;
		
		uiLayoutSetFunc(layout, do_node_add_static, NULL);
		
		for (ntype = ntreeGetType(ntree->type)->node_types.first; ntype; ntype = ntype->next) {
			if (ntype->nclass == nodeclass && ntype->name) {
				if (!compatibility || (ntype->compatibility & compatibility)) {
					uiItemV(layout, IFACE_(ntype->name), 0, ntype->type);
				}
			}
		}
	}
}
Exemple #6
0
LinkNode *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierData *md, CustomDataMask dataMask, int required_mode)
{
	LinkNode *dataMasks = NULL;
	LinkNode *curr, *prev;

	/* build a list of modifier data requirements in reverse order */
	for(; md; md = md->next) {
		ModifierTypeInfo *mti = modifierType_getInfo(md->type);
		CustomDataMask mask = 0;

		if(modifier_isEnabled(scene, md, required_mode))
			if(mti->requiredDataMask)
				mask = mti->requiredDataMask(ob, md);

		BLI_linklist_prepend(&dataMasks, SET_INT_IN_POINTER(mask));
	}

	/* build the list of required data masks - each mask in the list must
	* include all elements of the masks that follow it
	*
	* note the list is currently in reverse order, so "masks that follow it"
	* actually means "masks that precede it" at the moment
	*/
	for(curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) {
		if(prev) {
			CustomDataMask prev_mask = (CustomDataMask)GET_INT_FROM_POINTER(prev->link);
			CustomDataMask curr_mask = (CustomDataMask)GET_INT_FROM_POINTER(curr->link);

			curr->link = SET_INT_IN_POINTER(curr_mask | prev_mask);
		} else {
			CustomDataMask curr_mask = (CustomDataMask)GET_INT_FROM_POINTER(curr->link);

			curr->link = SET_INT_IN_POINTER(curr_mask | dataMask);
		}
	}

	/* reverse the list so it's in the correct order */
	BLI_linklist_reverse(&dataMasks);

	return dataMasks;
}
static PyObject *Color_channel_hsv_get(ColorObject *self, void *type)
{
	float hsv[3];
	int i = GET_INT_FROM_POINTER(type);

	if (BaseMath_ReadCallback(self) == -1)
		return NULL;

	rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2]));

	return PyFloat_FromDouble(hsv[i]);
}
Exemple #8
0
/* assign only one texid per buffer to avoid sampling the same texture twice */
static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key)
{
	if (BLI_ghash_haskey(bindhash, key)) {
		/* Reuse existing texid */
		input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, key));
	}
	else {
		/* Allocate new texid */
		input->texid = *texid;
		(*texid)++;
		input->bindtex = true;
		BLI_ghash_insert(bindhash, key, SET_INT_IN_POINTER(input->texid));
	}
}
Exemple #9
0
static void node_add_menu(bContext *C, uiLayout *layout, void *arg_nodeclass)
{
	Main *bmain= CTX_data_main(C);
	SpaceNode *snode= CTX_wm_space_node(C);
	bNodeTree *ntree;
	int nodeclass= GET_INT_FROM_POINTER(arg_nodeclass);
	int event;
	
	ntree = snode->nodetree;
	
	if(!ntree) {
		uiItemS(layout);
		return;
	}
	
	if (nodeclass==NODE_CLASS_GROUP) {
		bNodeTree *ngroup;
		
		uiLayoutSetFunc(layout, do_node_add_group, NULL);
		
		/* XXX hack: negative numbers used for empty group types */
		if (node_tree_has_type(ntree->type, NODE_GROUP))
			uiItemV(layout, "New Group", 0, -NODE_GROUP);
		if (node_tree_has_type(ntree->type, NODE_FORLOOP))
			uiItemV(layout, "New For Loop", 0, -NODE_FORLOOP);
		if (node_tree_has_type(ntree->type, NODE_WHILELOOP))
			uiItemV(layout, "New While Loop", 0, -NODE_WHILELOOP);
		uiItemS(layout);
		
		for(ngroup=bmain->nodetree.first, event=0; ngroup; ngroup= ngroup->id.next, ++event) {
			/* only use group trees */
			if (ngroup->type==ntree->type && ELEM3(ngroup->nodetype, NODE_GROUP, NODE_FORLOOP, NODE_WHILELOOP)) {
				uiItemV(layout, ngroup->id.name+2, 0, event);
			}
		}
	}
	else if (nodeclass==NODE_DYNAMIC) {
		/* disabled */
	}
	else {
		bNodeType *ntype;
		
		uiLayoutSetFunc(layout, do_node_add_static, NULL);
		
		for (ntype=ntreeGetType(ntree->type)->node_types.first; ntype; ntype=ntype->next) {
			if(ntype->nclass==nodeclass && ntype->name)
				uiItemV(layout, ntype->name, 0, ntype->type);
		}
	}
}
Exemple #10
0
static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
{
	GHashIterator gh_iter;
	GHASH_ITER (gh_iter, verts) {
		void *key = BLI_ghashIterator_getKey(&gh_iter);
		BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
		unsigned int id = GET_INT_FROM_POINTER(key);
		BMVert *v = bm_log_vert_from_id(log, id);

		/* Ensure the log has the final values of the vertex before
		 * deleting it */
		bm_log_vert_bmvert_copy(bm, lv, v);

		BM_vert_kill(bm, v);
	}
static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void *flag_p)
{
	const int flag = GET_INT_FROM_POINTER(flag_p);

	switch (PyC_Long_AsBool(value)) {
		case true:
			self->data->flag |= flag;
			return 0;
		case false:
			self->data->flag &= ~flag;
			return 0;
		default:
			/* error is set */
			return -1;
	}
}
static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void *flag_p)
{
	const int flag = GET_INT_FROM_POINTER(flag_p);

	switch (PyLong_AsLong(value)) {
		case true:
			self->data->flag |= flag;
			return 0;
		case false:
			self->data->flag &= ~flag;
			return 0;
		default:
			PyErr_SetString(PyExc_TypeError,
			                "expected a boolean type 0/1");
			return -1;
	}
}
Exemple #13
0
/* the actual callback - not necessarily called from py */
void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *arg)
{
	PyObject *cb_list = py_cb_array[GET_INT_FROM_POINTER(arg)];
	if (PyList_GET_SIZE(cb_list) > 0) {
		PyGILState_STATE gilstate = PyGILState_Ensure();

		PyObject *args = PyTuple_New(1);  /* save python creating each call */
		PyObject *func;
		PyObject *ret;
		Py_ssize_t pos;

		/* setup arguments */
		if (id) {
			PointerRNA id_ptr;
			RNA_id_pointer_create(id, &id_ptr);
			PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&id_ptr));
		}
		else {
			PyTuple_SET_ITEM(args, 0, Py_INCREF_RET(Py_None));
		}

		/* Iterate the list and run the callbacks
		 * note: don't store the list size since the scripts may remove themselves */
		for (pos = 0; pos < PyList_GET_SIZE(cb_list); pos++) {
			func = PyList_GET_ITEM(cb_list, pos);
			ret = PyObject_Call(func, args, NULL);
			if (ret == NULL) {
				/* Don't set last system variables because they might cause some
				 * dangling pointers to external render engines (when exception
				 * happens during rendering) which will break logic of render pipeline
				 * which expects to be the only user of render engine when rendering
				 * is finished.
				 */
				PyErr_PrintEx(0);
				PyErr_Clear();
			}
			else {
				Py_DECREF(ret);
			}
		}

		Py_DECREF(args);

		PyGILState_Release(gilstate);
	}
}
static void setMPolyMaterial(ExportMeshData *export_data,
                             MPoly *mpoly,
                             int which_orig_mesh)
{
	Object *orig_object;
	GHash *material_hash;
	Material *orig_mat;

	if (which_orig_mesh == CARVE_MESH_LEFT) {
		/* No need to change materian index for faces from left operand */
		return;
	}

	material_hash = export_data->material_hash;
	orig_object = which_object(export_data, which_orig_mesh);

	/* Set material, based on lookup in hash table. */
	orig_mat = give_current_material(orig_object, mpoly->mat_nr + 1);

	if (orig_mat) {
		/* For faces from right operand check if there's requested material
		 * in the left operand. And if it is, use index of that material,
		 * otherwise fallback to first material (material with index=0).
		 */
		if (!BLI_ghash_haskey(material_hash, orig_mat)) {
			int a, mat_nr;

			mat_nr = 0;
			for (a = 0; a < export_data->ob_left->totcol; a++) {
				if (give_current_material(export_data->ob_left, a + 1) == orig_mat) {
					mat_nr = a;
					break;
				}
			}

			BLI_ghash_insert(material_hash, orig_mat, SET_INT_IN_POINTER(mat_nr));

			mpoly->mat_nr = mat_nr;
		}
		else
			mpoly->mat_nr = GET_INT_FROM_POINTER(BLI_ghash_lookup(material_hash, orig_mat));
	}
	else {
		mpoly->mat_nr = 0;
	}
}
static void ui_node_link(bContext *C, void *arg_p, void *event_p)
{
	NodeLinkArg *arg = (NodeLinkArg *)arg_p;
	Main *bmain = arg->bmain;
	bNode *node_to = arg->node;
	bNodeSocket *sock_to = arg->sock;
	bNodeTree *ntree = arg->ntree;
	int event = GET_INT_FROM_POINTER(event_p);

	if (event == UI_NODE_LINK_DISCONNECT)
		node_socket_disconnect(bmain, ntree, node_to, sock_to);
	else if (event == UI_NODE_LINK_REMOVE)
		node_socket_remove(bmain, ntree, node_to, sock_to);
	else
		node_socket_add_replace(C, ntree, node_to, sock_to, arg->node_type->type, &arg->item);

	ED_undo_push(C, "Node input modify");
}
Exemple #16
0
/**
 * Returns the index of the struct info for the struct with the specified name.
 */
int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
	const short *sp = NULL;

	if (*index_last < sdna->nr_structs) {
		sp = sdna->structs[*index_last];
		if (strcmp(sdna->types[sp[0]], str) == 0) {
			return *index_last;
		}
	}

#ifdef WITH_DNA_GHASH
	{
		void **index_p;
		int a;

		index_p = BLI_ghash_lookup_p(sdna->structs_map, str);

		if (index_p) {
			a = GET_INT_FROM_POINTER(*index_p);
			*index_last = a;
		}
		else {
			a = -1;
		}
		return a;
	}
#else
	{
		int a;

		for (a = 0; a < sdna->nr_structs; a++) {

			sp = sdna->structs[a];

			if (strcmp(sdna->types[sp[0]], str) == 0) {
				*index_last = a;
				return a;
			}
		}
	}
	return -1;
#endif
}
Exemple #17
0
/* the actual callback - not necessarily called from py */
void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *arg)
{
	PyObject *cb_list= py_cb_array[GET_INT_FROM_POINTER(arg)];
	Py_ssize_t cb_list_len;
	if((cb_list_len= PyList_GET_SIZE(cb_list)) > 0) {
		PyGILState_STATE gilstate= PyGILState_Ensure();

		PyObject* args= PyTuple_New(1); // save python creating each call
		PyObject* func;
		PyObject* ret;
		Py_ssize_t pos;

		/* setup arguments */
		if(id) {
			PointerRNA id_ptr;
			RNA_id_pointer_create(id, &id_ptr);
			PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&id_ptr));
		}
		else {
			PyTuple_SET_ITEM(args, 0, Py_None);
			Py_INCREF(Py_None);
		}

		// Iterate the list and run the callbacks
		for (pos=0; pos < cb_list_len; pos++) {
			func= PyList_GET_ITEM(cb_list, pos);
			ret= PyObject_Call(func, args, NULL);
			if (ret==NULL) {
				PyErr_Print();
				PyErr_Clear();
			}
			else {
				Py_DECREF(ret);
			}
		}

		Py_DECREF(args);

		PyGILState_Release(gilstate);
	}
}
Exemple #18
0
static void ui_node_link(bContext *C, void *arg_p, void *event_p)
{
	NodeLinkArg *arg = (NodeLinkArg*)arg_p;
	Main *bmain = arg->bmain;
	bNode *node_to = arg->node;
	bNodeSocket *sock_to = arg->sock;
	bNodeTree *ntree = arg->ntree;
	int event = GET_INT_FROM_POINTER(event_p);
	bNodeTemplate ntemp;

	ntemp.type = arg->type;
	ntemp.ngroup = arg->ngroup;
	ntemp.scene = CTX_data_scene(C);
	ntemp.main = CTX_data_main(C);

	if (event == UI_NODE_LINK_DISCONNECT)
		node_socket_disconnect(bmain, ntree, node_to, sock_to);
	else if (event == UI_NODE_LINK_REMOVE)
		node_socket_remove(bmain, ntree, node_to, sock_to);
	else
		node_socket_add_replace(bmain, ntree, node_to, sock_to, &ntemp, arg->output);
	
	ED_undo_push(C, "Node input modify");
}
static PyObject *bpy_bmloopuv_flag_get(BPy_BMLoopUV *self, void *flag_p)
{
	const int flag = GET_INT_FROM_POINTER(flag_p);
	return PyBool_FromLong(self->data->flag & flag);
}
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_ex(dm, totdup, 0, totface - delface, 0, 0, CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS);
	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_coords(&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;
}
static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
{
	DerivedMesh *splitdm;
	MFace *mf = NULL, *df1 = NULL;
	MFace *mface = dm->getTessFaceArray(dm);
	MVert *dupve, *mv;
	EdgeHash *edgehash;
	EdgeHashIterator *ehi;
	int totvert = dm->getNumVerts(dm);
	int totface = dm->getNumTessFaces(dm);

	int *facesplit = MEM_callocN(sizeof(int) * totface, "explode_facesplit");
	int *vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa2");
	int *facepa = emd->facepa;
	int *fs, totesplit = 0, totfsplit = 0, curdupface = 0;
	int i, v1, v2, v3, v4, esplit,
	    v[4]  = {0, 0, 0, 0}, /* To quite gcc barking... */
	    uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
	int numlayer;
	unsigned int ed_v1, ed_v2;

	edgehash = BLI_edgehash_new(__func__);

	/* recreate vertpa from facepa calculation */
	for (i = 0, mf = mface; i < totface; i++, mf++) {
		vertpa[mf->v1] = facepa[i];
		vertpa[mf->v2] = facepa[i];
		vertpa[mf->v3] = facepa[i];
		if (mf->v4)
			vertpa[mf->v4] = facepa[i];
	}

	/* mark edges for splitting and how to split faces */
	for (i = 0, mf = mface, fs = facesplit; i < totface; i++, mf++, fs++) {
		v1 = vertpa[mf->v1];
		v2 = vertpa[mf->v2];
		v3 = vertpa[mf->v3];

		if (v1 != v2) {
			BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL);
			(*fs) |= 1;
		}

		if (v2 != v3) {
			BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL);
			(*fs) |= 2;
		}

		if (mf->v4) {
			v4 = vertpa[mf->v4];

			if (v3 != v4) {
				BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL);
				(*fs) |= 4;
			}

			if (v1 != v4) {
				BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL);
				(*fs) |= 8;
			}

			/* mark center vertex as a fake edge split */
			if (*fs == 15)
				BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL);
		}
		else {
			(*fs) |= 16; /* mark face as tri */

			if (v1 != v3) {
				BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL);
				(*fs) |= 4;
			}
		}
	}

	/* count splits & create indexes for new verts */
	ehi = BLI_edgehashIterator_new(edgehash);
	totesplit = totvert;
	for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
		BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(totesplit));
		totesplit++;
	}
	BLI_edgehashIterator_free(ehi);

	/* count new faces due to splitting */
	for (i = 0, fs = facesplit; i < totface; i++, fs++)
		totfsplit += add_faces[*fs];
	
	splitdm = CDDM_from_template(dm, totesplit, 0, totface + totfsplit, 0, 0);
	numlayer = CustomData_number_of_layers(&splitdm->faceData, CD_MTFACE);

	/* copy new faces & verts (is it really this painful with custom data??) */
	for (i = 0; i < totvert; i++) {
		MVert source;
		MVert *dest;
		dm->getVert(dm, i, &source);
		dest = CDDM_get_vert(splitdm, i);

		DM_copy_vert_data(dm, splitdm, i, i, 1);
		*dest = source;
	}

	/* override original facepa (original pointer is saved in caller function) */

	/* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are
	 * later interpreted as tri's, for this to work right I think we probably
	 * have to stop using tessface - campbell */

	facepa = MEM_callocN(sizeof(int) * (totface + (totfsplit * 2)), "explode_facepa");
	//memcpy(facepa, emd->facepa, totface*sizeof(int));
	emd->facepa = facepa;

	/* create new verts */
	ehi = BLI_edgehashIterator_new(edgehash);
	for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
		BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2);
		esplit = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
		mv = CDDM_get_vert(splitdm, ed_v2);
		dupve = CDDM_get_vert(splitdm, esplit);

		DM_copy_vert_data(splitdm, splitdm, ed_v2, esplit, 1);

		*dupve = *mv;

		mv = CDDM_get_vert(splitdm, ed_v1);

		mid_v3_v3v3(dupve->co, dupve->co, mv->co);
	}
	BLI_edgehashIterator_free(ehi);

	/* create new faces */
	curdupface = 0; //=totface;
	//curdupin=totesplit;
	for (i = 0, fs = facesplit; i < totface; i++, fs++) {
		mf = dm->getTessFaceData(dm, i, CD_MFACE);

		switch (*fs) {
			case 3:
			case 10:
			case 11:
			case 15:
				SET_VERTS(1, 2, 3, 4);
				break;
			case 5:
			case 6:
			case 7:
				SET_VERTS(2, 3, 4, 1);
				break;
			case 9:
			case 13:
				SET_VERTS(4, 1, 2, 3);
				break;
			case 12:
			case 14:
				SET_VERTS(3, 4, 1, 2);
				break;
			case 21:
			case 23:
				SET_VERTS(1, 2, 3, 4);
				break;
			case 19:
				SET_VERTS(2, 3, 1, 4);
				break;
			case 22:
				SET_VERTS(3, 1, 2, 4);
				break;
		}

		switch (*fs) {
			case 3:
			case 6:
			case 9:
			case 12:
				remap_faces_3_6_9_12(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
				if (numlayer)
					remap_uvs_3_6_9_12(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
				break;
			case 5:
			case 10:
				remap_faces_5_10(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
				if (numlayer)
					remap_uvs_5_10(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
				break;
			case 15:
				remap_faces_15(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
				if (numlayer)
					remap_uvs_15(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
				break;
			case 7:
			case 11:
			case 13:
			case 14:
				remap_faces_7_11_13_14(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
				if (numlayer)
					remap_uvs_7_11_13_14(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
				break;
			case 19:
			case 21:
			case 22:
				remap_faces_19_21_22(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
				if (numlayer)
					remap_uvs_19_21_22(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
				break;
			case 23:
				remap_faces_23(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
				if (numlayer)
					remap_uvs_23(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
				break;
			case 0:
			case 16:
				df1 = get_dface(dm, splitdm, curdupface, i, mf);
				facepa[curdupface] = vertpa[mf->v1];

				if (df1->v4)
					df1->flag |= ME_FACE_SEL;
				else
					df1->flag &= ~ME_FACE_SEL;
				break;
		}

		curdupface += add_faces[*fs] + 1;
	}

	for (i = 0; i < curdupface; i++) {
		mf = CDDM_get_tessface(splitdm, i);
		test_index_face(mf, &splitdm->faceData, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
	}

	BLI_edgehash_free(edgehash, NULL);
	MEM_freeN(facesplit);
	MEM_freeN(vertpa);

	CDDM_calc_edges_tessface(splitdm);
	CDDM_tessfaces_to_faces(splitdm); /*builds ngon faces from tess (mface) faces*/

	return splitdm;
}
static int edgecut_get(EdgeHash *edgehash, unsigned int v1, unsigned int v2)
{
	return GET_INT_FROM_POINTER(BLI_edgehash_lookup(edgehash, v1, v2));
}
static void loop_sync(bNodeTree *ntree, int sync_in_out)
{
	bNodeSocket *sock, *sync, *nsync, *mirror;
	ListBase *sync_lb;
	
	if (sync_in_out==SOCK_IN) {
		sock = ntree->outputs.first;
		
		sync = ntree->inputs.first;
		sync_lb = &ntree->inputs;
	}
	else {
		sock = ntree->inputs.first;
		
		sync = ntree->outputs.first;
		sync_lb = &ntree->outputs;
	}
	
	/* NB: the sock->storage pointer is used here directly to store the own_index int
	 * out the mirrored socket counterpart!
	 */
	
	while (sock) {
		/* skip static and internal sockets on the sync side (preserves socket order!) */
		while (sync && ((sync->flag & SOCK_INTERNAL) || !(sync->flag & SOCK_DYNAMIC)))
			sync = sync->next;
		
		if (sync && !(sync->flag & SOCK_INTERNAL) && (sync->flag & SOCK_DYNAMIC)) {
			if (sock->storage==NULL) {
				/* if mirror index is 0, the sockets is newly added and a new mirror must be created. */
				mirror = node_group_expose_socket(ntree, sock, sync_in_out);
				/* store the mirror index */
				sock->storage = SET_INT_IN_POINTER(mirror->own_index);
				mirror->storage = SET_INT_IN_POINTER(sock->own_index);
				/* move mirror to the right place */
				BLI_remlink(sync_lb, mirror);
				if (sync)
					BLI_insertlinkbefore(sync_lb, sync, mirror);
				else
					BLI_addtail(sync_lb, mirror);
			}
			else {
				/* look up the mirror socket */
				for (mirror=sync; mirror; mirror=mirror->next)
					if (mirror->own_index == GET_INT_FROM_POINTER(sock->storage))
						break;
				/* make sure the name is the same (only for identification by user, no deeper meaning) */
				BLI_strncpy(mirror->name, sock->name, sizeof(mirror->name));
				/* fix the socket order if necessary */
				if (mirror != sync) {
					BLI_remlink(sync_lb, mirror);
					BLI_insertlinkbefore(sync_lb, sync, mirror);
				}
				else
					sync = sync->next;
			}
		}
		
		sock = sock->next;
	}
	
	/* remaining sockets in sync_lb are leftovers from deleted sockets, remove them */
	while (sync) {
		nsync = sync->next;
		if (!(sync->flag & SOCK_INTERNAL) && (sync->flag & SOCK_DYNAMIC))
			node_group_remove_socket(ntree, sync, sync_in_out);
		sync = nsync;
	}
}
Exemple #24
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	MaskModifierData *mmd = (MaskModifierData *)md;
	DerivedMesh *dm = derivedData, *result = NULL;
	GHash *vertHash = NULL, *edgeHash, *polyHash;
	GHashIterator *hashIter;
	MDeformVert *dvert = NULL, *dv;
	int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0;
	int maxVerts, maxEdges, maxPolys;
	int i;

	MPoly *mpoly;
	MLoop *mloop;

	MPoly *mpoly_new;
	MLoop *mloop_new;
	MEdge *medge_new;
	MVert *mvert_new;


	int *loop_mapping;

	/* Overview of Method:
	 *	1. Get the vertices that are in the vertexgroup of interest 
	 *	2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
	 *	3. Make a new mesh containing only the mapping data
	 */
	
	/* get original number of verts, edges, and faces */
	maxVerts = dm->getNumVerts(dm);
	maxEdges = dm->getNumEdges(dm);
	maxPolys = dm->getNumPolys(dm);
	
	/* check if we can just return the original mesh 
	 *	- must have verts and therefore verts assigned to vgroups to do anything useful
	 */
	if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
	    (maxVerts == 0) || (ob->defbase.first == NULL) )
	{
		return derivedData;
	}
	
	/* if mode is to use selected armature bones, aggregate the bone groups */
	if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */
		Object *oba = mmd->ob_arm;
		bPoseChannel *pchan;
		bDeformGroup *def;
		char *bone_select_array;
		int bone_select_tot = 0;
		const int defbase_tot = BLI_countlist(&ob->defbase);
		
		/* check that there is armature object with bones to use, otherwise return original mesh */
		if (ELEM3(NULL, oba, oba->pose, ob->defbase.first))
			return derivedData;
		
		/* determine whether each vertexgroup is associated with a selected bone or not 
		 * - each cell is a boolean saying whether bone corresponding to the ith group is selected
		 * - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts)
		 */
		bone_select_array = MEM_mallocN(defbase_tot * sizeof(char), "mask array");
		
		for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
			pchan = BKE_pose_channel_find_name(oba->pose, def->name);
			if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
				bone_select_array[i] = TRUE;
				bone_select_tot++;
			}
			else {
				bone_select_array[i] = FALSE;
			}
		}
		
		/* if no dverts (i.e. no data for vertex groups exists), we've got an
		 * inconsistent situation, so free hashes and return oirginal mesh
		 */
		dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
		if (dvert == NULL) {
			MEM_freeN(bone_select_array);
			return derivedData;
		}
		
		/* verthash gives mapping from original vertex indices to the new indices (including selected matches only)
		 * key = oldindex, value = newindex
		 */
		vertHash = BLI_ghash_int_new("mask vert gh");
		
		/* add vertices which exist in vertexgroups into vertHash for filtering 
		 * - dv = for each vertex, what vertexgroups does it belong to
		 * - dw = weight that vertex was assigned to a vertexgroup it belongs to
		 */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			MDeformWeight *dw = dv->dw;
			short found = 0;
			int j;
			
			/* check the groups that vertex is assigned to, and see if it was any use */
			for (j = 0; j < dv->totweight; j++, dw++) {
				if (dw->def_nr < defbase_tot) {
					if (bone_select_array[dw->def_nr]) {
						if (dw->weight != 0.0f) {
							found = TRUE;
							break;
						}
					}
				}
			}
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (found) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!found) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
		
		/* free temp hashes */
		MEM_freeN(bone_select_array);
	}
	else {  /* --- Using Nominated VertexGroup only --- */
		int defgrp_index = defgroup_name_index(ob, mmd->vgroup);
		
		/* get dverts */
		if (defgrp_index != -1)
			dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
			
		/* if no vgroup (i.e. dverts) found, return the initial mesh */
		if ((defgrp_index == -1) || (dvert == NULL))
			return dm;
			
		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash = BLI_ghash_int_new("mask vert2 bh");
		
		/* add vertices which exist in vertexgroup into ghash for filtering */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			const int weight_set = defvert_find_weight(dv, defgrp_index) != 0.0f;
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (weight_set) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!weight_set) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
	}

	/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
	edgeHash = BLI_ghash_int_new("mask ed2 gh");
	polyHash = BLI_ghash_int_new("mask fa2 gh");
	
	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);

	loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */

	/* loop over edges and faces, and do the same thing to 
	 * ensure that they only reference existing verts 
	 */
	for (i = 0; i < maxEdges; i++) {
		MEdge me;
		dm->getEdge(dm, i, &me);
		
		/* only add if both verts will be in new mesh */
		if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) &&
		    BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)))
		{
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges));
			numEdges++;
		}
	}
	for (i = 0; i < maxPolys; i++) {
		MPoly *mp = &mpoly[i];
		MLoop *ml = mloop + mp->loopstart;
		int ok = TRUE;
		int j;
		
		for (j = 0; j < mp->totloop; j++, ml++) {
			if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) {
				ok = FALSE;
				break;
			}
		}
		
		/* all verts must be available */
		if (ok) {
			BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys));
			loop_mapping[numPolys] = numLoops;
			numPolys++;
			numLoops += mp->totloop;
		}
	}
	
	
	/* now we know the number of verts, edges and faces, 
	 * we can create the new (reduced) mesh
	 */
	result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys);
	
	mpoly_new = CDDM_get_polys(result);
	mloop_new = CDDM_get_loops(result);
	medge_new = CDDM_get_edges(result);
	mvert_new = CDDM_get_verts(result);
	
	/* using ghash-iterators, map data into new mesh */
	/* vertices */
	for (hashIter = BLI_ghashIterator_new(vertHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter) )
	{
		MVert source;
		MVert *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getVert(dm, oldIndex, &source);
		dest = &mvert_new[newIndex];
		
		DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
		
	/* edges */
	for (hashIter = BLI_ghashIterator_new(edgeHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter))
	{
		MEdge source;
		MEdge *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getEdge(dm, oldIndex, &source);
		dest = &medge_new[newIndex];
		
		source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
		source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
		
		DM_copy_edge_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
	
	/* faces */
	for (hashIter = BLI_ghashIterator_new(polyHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter) )
	{
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		MPoly *source = &mpoly[oldIndex];
		MPoly *dest = &mpoly_new[newIndex];
		int oldLoopIndex = source->loopstart;
		int newLoopIndex = loop_mapping[newIndex];
		MLoop *source_loop = &mloop[oldLoopIndex];
		MLoop *dest_loop = &mloop_new[newLoopIndex];
		
		DM_copy_poly_data(dm, result, oldIndex, newIndex, 1);
		DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop);

		*dest = *source;
		dest->loopstart = newLoopIndex;
		for (i = 0; i < source->totloop; i++) {
			dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v)));
			dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e)));
		}
	}

	BLI_ghashIterator_free(hashIter);

	MEM_freeN(loop_mapping);

	/* why is this needed? - campbell */
	/* recalculate normals */
	CDDM_calc_normals(result);
	
	/* free hashes */
	BLI_ghash_free(vertHash, NULL, NULL);
	BLI_ghash_free(edgeHash, NULL, NULL);
	BLI_ghash_free(polyHash, NULL, NULL);

	/* return the new mesh */
	return result;
}
static int debug_mode_generic(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
	G.debug |= GET_INT_FROM_POINTER(data);
	return 0;
}
Exemple #26
0
/**
 * Calculate edges from polygons
 *
 * \param mesh  The mesh to add edges into
 * \param update  When true create new edges co-exist
 */
void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
{
	CustomData edata;
	EdgeHashIterator *ehi;
	MPoly *mp;
	MEdge *med, *med_orig;
	EdgeHash *eh = BLI_edgehash_new();
	int i, totedge, totpoly = mesh->totpoly;
	int med_index;
	/* select for newly created meshes which are selected [#25595] */
	const short ed_flag = (ME_EDGEDRAW | ME_EDGERENDER) | (select ? SELECT : 0);

	if (mesh->totedge == 0)
		update = false;

	if (update) {
		/* assume existing edges are valid
		 * useful when adding more faces and generating edges from them */
		med = mesh->medge;
		for (i = 0; i < mesh->totedge; i++, med++)
			BLI_edgehash_insert(eh, med->v1, med->v2, med);
	}

	/* mesh loops (bmesh only) */
	for (mp = mesh->mpoly, i = 0; i < totpoly; mp++, i++) {
		MLoop *l = &mesh->mloop[mp->loopstart];
		int j, l_prev = (l + (mp->totloop - 1))->v;
		for (j = 0; j < mp->totloop; j++, l++) {
			if (!BLI_edgehash_haskey(eh, l_prev, l->v)) {
				BLI_edgehash_insert(eh, l_prev, l->v, NULL);
			}
			l_prev = l->v;
		}
	}

	totedge = BLI_edgehash_size(eh);

	/* write new edges into a temporary CustomData */
	CustomData_reset(&edata);
	CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);

	med = CustomData_get_layer(&edata, CD_MEDGE);
	for (ehi = BLI_edgehashIterator_new(eh), i = 0;
	     BLI_edgehashIterator_isDone(ehi) == FALSE;
	     BLI_edgehashIterator_step(ehi), ++i, ++med)
	{
		if (update && (med_orig = BLI_edgehashIterator_getValue(ehi))) {
			*med = *med_orig; /* copy from the original */
		}
		else {
			BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
			med->flag = ed_flag;
		}

		/* store the new edge index in the hash value */
		BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(i));
	}
	BLI_edgehashIterator_free(ehi);

	if (mesh->totpoly) {
		/* second pass, iterate through all loops again and assign
		 * the newly created edges to them. */
		for (mp = mesh->mpoly, i = 0; i < mesh->totpoly; mp++, i++) {
			MLoop *l = &mesh->mloop[mp->loopstart];
			MLoop *l_prev = (l + (mp->totloop - 1));
			int j;
			for (j = 0; j < mp->totloop; j++, l++) {
				/* lookup hashed edge index */
				med_index = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, l_prev->v, l->v));
				l_prev->e = med_index;
				l_prev = l;
			}
		}
	}

	/* free old CustomData and assign new one */
	CustomData_free(&mesh->edata, mesh->totedge);
	mesh->edata = edata;
	mesh->totedge = totedge;

	mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);

	BLI_edgehash_free(eh, NULL);
}
Exemple #27
0
int BKE_mesh_validate_arrays(Mesh *mesh,
                             MVert *mverts, unsigned int totvert,
                             MEdge *medges, unsigned int totedge,
                             MFace *mfaces, unsigned int totface,
                             MLoop *mloops, unsigned int totloop,
                             MPoly *mpolys, unsigned int totpoly,
                             MDeformVert *dverts, /* assume totvert length */
                             const bool do_verbose, const bool do_fixes)
{
#   define REMOVE_EDGE_TAG(_me) { _me->v2 = _me->v1; do_edge_free = true; } (void)0
#   define IS_REMOVED_EDGE(_me) (_me->v2 == _me->v1)

#   define REMOVE_LOOP_TAG(_ml) { _ml->e = INVALID_LOOP_EDGE_MARKER; do_polyloop_free = true; } (void)0
#   define REMOVE_POLY_TAG(_mp) { _mp->totloop *= -1; do_polyloop_free = true; } (void)0

	MVert *mv = mverts;
	MEdge *me;
	MLoop *ml;
	MPoly *mp;
	unsigned int i, j;
	int *v;

	bool do_edge_free = false;
	bool do_face_free = false;
	bool do_polyloop_free = false; /* This regroups loops and polys! */

	bool verts_fixed = false;
	bool vert_weights_fixed = false;
	bool msel_fixed = false;

	bool do_edge_recalc = false;

	EdgeHash *edge_hash = BLI_edgehash_new();

	BLI_assert(!(do_fixes && mesh == NULL));

	PRINT("%s: verts(%u), edges(%u), loops(%u), polygons(%u)\n",
	      __func__, totvert, totedge, totloop, totpoly);

	if (totedge == 0 && totpoly != 0) {
		PRINT("\tLogical error, %u polygons and 0 edges\n", totpoly);
		do_edge_recalc = do_fixes;
	}

	for (i = 1; i < totvert; i++, mv++) {
		int fix_normal = TRUE;

		for (j = 0; j < 3; j++) {
			if (!finite(mv->co[j])) {
				PRINT("\tVertex %u: has invalid coordinate\n", i);

				if (do_fixes) {
					zero_v3(mv->co);

					verts_fixed = TRUE;
				}
			}

			if (mv->no[j] != 0)
				fix_normal = FALSE;
		}

		if (fix_normal) {
			PRINT("\tVertex %u: has zero normal, assuming Z-up normal\n", i);
			if (do_fixes) {
				mv->no[2] = SHRT_MAX;
				verts_fixed = TRUE;
			}
		}
	}

	for (i = 0, me = medges; i < totedge; i++, me++) {
		int remove = FALSE;
		if (me->v1 == me->v2) {
			PRINT("\tEdge %u: has matching verts, both %u\n", i, me->v1);
			remove = do_fixes;
		}
		if (me->v1 >= totvert) {
			PRINT("\tEdge %u: v1 index out of range, %u\n", i, me->v1);
			remove = do_fixes;
		}
		if (me->v2 >= totvert) {
			PRINT("\tEdge %u: v2 index out of range, %u\n", i, me->v2);
			remove = do_fixes;
		}

		if (BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) {
			PRINT("\tEdge %u: is a duplicate of %d\n", i,
			      GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, me->v1, me->v2)));
			remove = do_fixes;
		}

		if (remove == FALSE) {
			BLI_edgehash_insert(edge_hash, me->v1, me->v2, SET_INT_IN_POINTER(i));
		}
		else {
			REMOVE_EDGE_TAG(me);
		}
	}

	if (mfaces && !mpolys) {
#		define REMOVE_FACE_TAG(_mf) { _mf->v3 = 0; do_face_free = TRUE; } (void)0
#		define CHECK_FACE_VERT_INDEX(a, b) \
					if (mf->a == mf->b) { \
						PRINT("    face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u\n", i, mf->a); \
						remove = do_fixes; \
					} (void)0
#		define CHECK_FACE_EDGE(a, b) \
					if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \
						PRINT("    face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \
						      " (%u,%u) is missing egde data\n", i, mf->a, mf->b); \
						do_edge_recalc = TRUE; \
					} (void)0

		MFace *mf;
		MFace *mf_prev;

		SortFace *sort_faces = MEM_callocN(sizeof(SortFace) * totface, "search faces");
		SortFace *sf;
		SortFace *sf_prev;
		unsigned int totsortface = 0;

		PRINT("No Polys, only tesselated Faces\n");

		for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) {
			int remove = FALSE;
			int fidx;
			unsigned int fv[4];

			fidx = mf->v4 ? 3 : 2;
			do {
				fv[fidx] = *(&(mf->v1) + fidx);
				if (fv[fidx] >= totvert) {
					PRINT("\tFace %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]);
					remove = do_fixes;
				}
			} while (fidx--);

			if (remove == FALSE) {
				if (mf->v4) {
					CHECK_FACE_VERT_INDEX(v1, v2);
					CHECK_FACE_VERT_INDEX(v1, v3);
					CHECK_FACE_VERT_INDEX(v1, v4);

					CHECK_FACE_VERT_INDEX(v2, v3);
					CHECK_FACE_VERT_INDEX(v2, v4);

					CHECK_FACE_VERT_INDEX(v3, v4);
				}
				else {
					CHECK_FACE_VERT_INDEX(v1, v2);
					CHECK_FACE_VERT_INDEX(v1, v3);

					CHECK_FACE_VERT_INDEX(v2, v3);
				}

				if (remove == FALSE) {
					if (totedge) {
						if (mf->v4) {
							CHECK_FACE_EDGE(v1, v2);
							CHECK_FACE_EDGE(v2, v3);
							CHECK_FACE_EDGE(v3, v4);
							CHECK_FACE_EDGE(v4, v1);
						}
						else {
							CHECK_FACE_EDGE(v1, v2);
							CHECK_FACE_EDGE(v2, v3);
							CHECK_FACE_EDGE(v3, v1);
						}
					}

					sf->index = i;

					if (mf->v4) {
						edge_store_from_mface_quad(sf->es, mf);

						qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
					}
					else {
						edge_store_from_mface_tri(sf->es, mf);
						qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
					}

					totsortface++;
					sf++;
				}
			}

			if (remove) {
				REMOVE_FACE_TAG(mf);
			}
		}

		qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);

		sf = sort_faces;
		sf_prev = sf;
		sf++;

		for (i = 1; i < totsortface; i++, sf++) {
			int remove = FALSE;

			/* on a valid mesh, code below will never run */
			if (memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
				mf = mfaces + sf->index;

				if (do_verbose) {
					mf_prev = mfaces + sf_prev->index;

					if (mf->v4) {
						PRINT("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n",
						      sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4,
						      mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
					}
					else {
						PRINT("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n",
						      sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3,
						      mf_prev->v1, mf_prev->v2, mf_prev->v3);
					}
				}

				remove = do_fixes;
			}
			else {
				sf_prev = sf;
			}

			if (remove) {
				REMOVE_FACE_TAG(mf);
			}
		}

		MEM_freeN(sort_faces);

#		undef REMOVE_FACE_TAG
#		undef CHECK_FACE_VERT_INDEX
#		undef CHECK_FACE_EDGE
	}

	/* Checking loops and polys is a bit tricky, as they are quite intricated...
	 *
	 * Polys must have:
	 * - a valid loopstart value.
	 * - a valid totloop value (>= 3 and loopstart+totloop < me.totloop).
	 *
	 * Loops must have:
	 * - a valid v value.
	 * - a valid e value (corresponding to the edge it defines with the next loop in poly).
	 *
	 * Also, loops not used by polys can be discarded.
	 * And "intersecting" loops (i.e. loops used by more than one poly) are invalid,
	 * so be sure to leave at most one poly per loop!
	 */
	{
		SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys");
		SortPoly *prev_sp, *sp = sort_polys;
		int prev_end;
		for (i = 0, mp = mpolys; i < totpoly; i++, mp++, sp++) {
			sp->index = i;

			if (mp->loopstart < 0 || mp->totloop < 3) {
				/* Invalid loop data. */
				PRINT("\tPoly %u is invalid (loopstart: %u, totloop: %u)\n", sp->index, mp->loopstart, mp->totloop);
				sp->invalid = TRUE;
			}
			else if (mp->loopstart + mp->totloop > totloop) {
				/* Invalid loop data. */
				PRINT("\tPoly %u uses loops out of range (loopstart: %u, loopend: %u, max nbr of loops: %u)\n",
				      sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1);
				sp->invalid = TRUE;
			}
			else {
				/* Poly itself is valid, for now. */
				int v1, v2; /* v1 is prev loop vert idx, v2 is current loop one. */
				sp->invalid = FALSE;
				sp->verts = v = MEM_mallocN(sizeof(int) * mp->totloop, "Vert idx of SortPoly");
				sp->numverts = mp->totloop;
				sp->loopstart = mp->loopstart;

				/* Test all poly's loops' vert idx. */
				for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) {
					if (ml->v >= totvert) {
						/* Invalid vert idx. */
						PRINT("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v);
						sp->invalid = TRUE;
					}

					mverts[ml->v].flag |= ME_VERT_TMP_TAG;
					*v = ml->v;
				}

				/* is the same vertex used more than once */
				if (!sp->invalid) {
					v = sp->verts;
					for (j = 0; j < mp->totloop; j++, v++) {
						if ((mverts[*v].flag & ME_VERT_TMP_TAG) == 0) {
							PRINT("\tPoly %u has duplicate vert reference at corner (%u)\n", i, j);
							sp->invalid = TRUE;
						}
						mverts[*v].flag &= ~ME_VERT_TMP_TAG;
					}
				}

				if (sp->invalid)
					continue;

				/* Test all poly's loops. */
				for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
					v1 = ml->v;
					v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v;
					if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
						/* Edge not existing. */
						PRINT("\tPoly %u needs missing edge (%u, %u)\n", sp->index, v1, v2);
						if (do_fixes)
							do_edge_recalc = TRUE;
						else
							sp->invalid = TRUE;
					}
					else if (ml->e >= totedge) {
						/* Invalid edge idx.
						 * We already know from previous text that a valid edge exists, use it (if allowed)! */
						if (do_fixes) {
							int prev_e = ml->e;
							ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
							PRINT("\tLoop %u has invalid edge reference (%u), fixed using edge %u\n",
							      sp->loopstart + j, prev_e, ml->e);
						}
						else {
							PRINT("\tLoop %u has invalid edge reference (%u)\n", sp->loopstart + j, ml->e);
							sp->invalid = TRUE;
						}
					}
					else {
						me = &medges[ml->e];
						if (IS_REMOVED_EDGE(me) || !((me->v1 == v1 && me->v2 == v2) || (me->v1 == v2 && me->v2 == v1))) {
							/* The pointed edge is invalid (tagged as removed, or vert idx mismatch),
							 * and we already know from previous test that a valid one exists, use it (if allowed)! */
							if (do_fixes) {
								int prev_e = ml->e;
								ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
								PRINT("\tPoly %u has invalid edge reference (%u), fixed using edge %u\n",
								      sp->index, prev_e, ml->e);
							}
							else {
								PRINT("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e);
								sp->invalid = TRUE;
							}
						}
					}
				}

				/* Now check that that poly does not use a same vertex more than once! */
				if (!sp->invalid) {
					int *prev_v = v = sp->verts;
					j = sp->numverts;

					qsort(sp->verts, j, sizeof(int), int_cmp);

					for (j--, v++; j; j--, v++) {
						if (*v != *prev_v) {
							int dlt = v - prev_v;
							if (dlt > 1) {
								PRINT("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
								      sp->index, *prev_v, dlt);
								sp->invalid = TRUE;
							}
							prev_v = v;
						}
					}
					if (v - prev_v > 1) { /* Don't forget final verts! */
						PRINT("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n",
						      sp->index, *prev_v, (int)(v - prev_v));
						sp->invalid = TRUE;
					}
				}
			
			}
		}

		/* Second check pass, testing polys using the same verts. */
		qsort(sort_polys, totpoly, sizeof(SortPoly), search_poly_cmp);
		sp = prev_sp = sort_polys;
		sp++;

		for (i = 1; i < totpoly; i++, sp++) {
			int p1_nv = sp->numverts, p2_nv = prev_sp->numverts;
			int *p1_v = sp->verts, *p2_v = prev_sp->verts;
			short p1_sub = TRUE, p2_sub = TRUE;
			if (sp->invalid)
				break;
			/* Test same polys. */
#if 0
			/* NOTE: This performs a sub-set test. */
			/* XXX This (and the sort of verts list) is better than systematic
			 *     search of all verts of one list into the other if lists have
			 *     a fair amount of elements.
			 *     Not sure however it's worth it in this case?
			 *     But as we also need sorted vert list to check verts multi-used
			 *     (in first pass of checks)... */
			/* XXX If we consider only "equal" polys (i.e. using exactly same set of verts)
			 *     as invalid, better to replace this by a simple memory cmp... */
			while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) {
				if (*p1_v < *p2_v) {
					if (p1_sub)
						p1_sub = FALSE;
					p1_nv--;
					p1_v++;
				}
				else if (*p2_v < *p1_v) {
					if (p2_sub)
						p2_sub = FALSE;
					p2_nv--;
					p2_v++;
				}
				else {
					/* Equality, both next verts. */
					p1_nv--;
					p2_nv--;
					p1_v++;
					p2_v++;
				}
			}
			if (p1_nv && p1_sub)
				p1_sub = FALSE;
			else if (p2_nv && p2_sub)
				p2_sub = FALSE;

			if (p1_sub && p2_sub) {
				PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n",
				      prev_sp->index, sp->index, sp->index);
				sp->invalid = TRUE;
			}
			/* XXX In fact, these might be valid? :/ */
			else if (p1_sub) {
				PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index);
				sp->invalid = TRUE;
			}
			else if (p2_sub) {
				PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index);
				prev_sp->invalid = TRUE;
				prev_sp = sp; /* sp is new reference poly. */
			}
#else
			if (0) {
				p1_sub += 0;
				p2_sub += 0;
			}
			if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
				if (do_verbose) {
					PRINT("\tPolys %u and %u use same vertices (%u",
					      prev_sp->index, sp->index, *p1_v);
					for (j = 1; j < p1_nv; j++)
						PRINT(", %u", p1_v[j]);
					PRINT("), considering poly %u as invalid.\n", sp->index);
				}
				sp->invalid = TRUE;
			}
#endif
			else {
				prev_sp = sp;
			}
		}

		/* Third check pass, testing loops used by none or more than one poly. */
		qsort(sort_polys, totpoly, sizeof(SortPoly), search_polyloop_cmp);
		sp = sort_polys;
		prev_sp = NULL;
		prev_end = 0;
		for (i = 0; i < totpoly; i++, sp++) {
			/* Free this now, we don't need it anymore, and avoid us another loop! */
			if (sp->verts)
				MEM_freeN(sp->verts);

			/* Note above prev_sp: in following code, we make sure it is always valid poly (or NULL). */
			if (sp->invalid) {
				if (do_fixes) {
					REMOVE_POLY_TAG((&mpolys[sp->index]));
					/* DO NOT REMOVE ITS LOOPS!!!
					 * As already invalid polys are at the end of the SortPoly list, the loops they
					 * were the only users have already been tagged as "to remove" during previous
					 * iterations, and we don't want to remove some loops that may be used by
					 * another valid poly! */
				}
			}
			/* Test loops users. */
			else {
				/* Unused loops. */
				if (prev_end < sp->loopstart) {
					for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) {
						PRINT("\tLoop %u is unused.\n", j);
						if (do_fixes)
							REMOVE_LOOP_TAG(ml);
					}
					prev_end = sp->loopstart + sp->numverts;
					prev_sp = sp;
				}
				/* Multi-used loops. */
				else if (prev_end > sp->loopstart) {
					PRINT("\tPolys %u and %u share loops from %u to %u, considering poly %u as invalid.\n",
					      prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index);
					if (do_fixes) {
						REMOVE_POLY_TAG((&mpolys[sp->index]));
						/* DO NOT REMOVE ITS LOOPS!!!
						 * They might be used by some next, valid poly!
						 * Just not updating prev_end/prev_sp vars is enough to ensure the loops
						 * effectively no more needed will be marked as "to be removed"! */
					}
				}
				else {
					prev_end = sp->loopstart + sp->numverts;
					prev_sp = sp;
				}
			}
		}
		/* We may have some remaining unused loops to get rid of! */
		if (prev_end < totloop) {
			for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) {
				PRINT("\tLoop %u is unused.\n", j);
				if (do_fixes)
					REMOVE_LOOP_TAG(ml);
			}
		}

		MEM_freeN(sort_polys);
	}

	BLI_edgehash_free(edge_hash, NULL);

	/* fix deform verts */
	if (dverts) {
		MDeformVert *dv;
		for (i = 0, dv = dverts; i < totvert; i++, dv++) {
			MDeformWeight *dw;

			for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
				/* note, greater then max defgroups is accounted for in our code, but not < 0 */
				if (!finite(dw->weight)) {
					PRINT("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
					if (do_fixes) {
						dw->weight = 0.0f;
						vert_weights_fixed = TRUE;
					}
				}
				else if (dw->weight < 0.0f || dw->weight > 1.0f) {
					PRINT("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
					if (do_fixes) {
						CLAMP(dw->weight, 0.0f, 1.0f);
						vert_weights_fixed = TRUE;
					}
				}

				if (dw->def_nr < 0) {
					PRINT("\tVertex deform %u, has invalid group %d\n", i, dw->def_nr);
					if (do_fixes) {
						defvert_remove_group(dv, dw);
						if (dv->dw) {
							/* re-allocated, the new values compensate for stepping
							 * within the for loop and may not be valid */
							j--;
							dw = dv->dw + j;

							vert_weights_fixed = TRUE;
						}
						else { /* all freed */
							break;
						}
					}
				}
			}
		}
	}

#   undef REMOVE_EDGE_TAG
#   undef IS_REMOVED_EDGE
#   undef REMOVE_LOOP_TAG
#   undef REMOVE_POLY_TAG

	if (mesh) {
		if (do_face_free) {
			BKE_mesh_strip_loose_faces(mesh);
		}

		if (do_polyloop_free) {
			BKE_mesh_strip_loose_polysloops(mesh);
		}

		if (do_edge_free) {
			BKE_mesh_strip_loose_edges(mesh);
		}

		if (do_edge_recalc) {
			BKE_mesh_calc_edges(mesh, true, false);
		}
	}

	if (mesh && mesh->mselect) {
		MSelect *msel;
		int free_msel = FALSE;

		for (i = 0, msel = mesh->mselect; i < mesh->totselect; i++, msel++) {
			int tot_elem = 0;

			if (msel->index < 0) {
				PRINT("\tMesh select element %d type %d index is negative, "
				      "resetting selection stack.\n", i, msel->type);
				free_msel = TRUE;
				break;
			}

			switch (msel->type) {
				case ME_VSEL:
					tot_elem = mesh->totvert;
					break;
				case ME_ESEL:
					tot_elem = mesh->totedge;
					break;
				case ME_FSEL:
					tot_elem = mesh->totface;
					break;
			}

			if (msel->index > tot_elem) {
				PRINT("\tMesh select element %d type %d index %d is larger than data array size %d, "
				      "resetting selection stack.\n", i, msel->type, msel->index, tot_elem);

				free_msel = TRUE;
				break;
			}
		}

		if (free_msel) {
			MEM_freeN(mesh->mselect);
			mesh->mselect = NULL;
			mesh->totselect = 0;
		}
	}

	PRINT("%s: finished\n\n", __func__);

	return (verts_fixed || vert_weights_fixed || do_polyloop_free || do_edge_free || do_edge_recalc || msel_fixed);
}
Exemple #28
0
static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DerivedMesh *dm = derivedData;
	DerivedMesh *result;
	BuildModifierData *bmd = (BuildModifierData *) md;
	int i, j, k;
	int numFaces_dst, numEdges_dst, numLoops_dst = 0;
	int *vertMap, *edgeMap, *faceMap;
	float frac;
	MPoly *mpoly_dst;
	MLoop *ml_dst, *ml_src /*, *mloop_dst */;
	GHashIterator *hashIter;
	/* maps vert indices in old mesh to indices in new mesh */
	GHash *vertHash = BLI_ghash_int_new("build ve apply gh");
	/* maps edge indices in new mesh to indices in old mesh */
	GHash *edgeHash = BLI_ghash_int_new("build ed apply gh");
	GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh");

	const int numVert_src = dm->getNumVerts(dm);
	const int numEdge_src = dm->getNumEdges(dm);
	const int numPoly_src = dm->getNumPolys(dm);
	MPoly *mpoly_src = dm->getPolyArray(dm);
	MLoop *mloop_src = dm->getLoopArray(dm);
	MEdge *medge_src = dm->getEdgeArray(dm);
	MVert *mvert_src = dm->getVertArray(dm);


	vertMap = MEM_mallocN(sizeof(*vertMap) * numVert_src, "build modifier vertMap");
	edgeMap = MEM_mallocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap");
	faceMap = MEM_mallocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap");

#pragma omp parallel sections if (numVert_src + numEdge_src + numPoly_src >= DM_OMP_LIMIT)
	{
#pragma omp section
		{ range_vn_i(vertMap, numVert_src, 0); }
#pragma omp section
		{ range_vn_i(edgeMap, numEdge_src, 0); }
#pragma omp section
		{ range_vn_i(faceMap, numPoly_src, 0); }
	}

	frac = (BKE_scene_frame_get(md->scene) - bmd->start) / bmd->length;
	CLAMP(frac, 0.0f, 1.0f);

	numFaces_dst = numPoly_src * frac;
	numEdges_dst = numEdge_src * frac;

	/* if there's at least one face, build based on faces */
	if (numFaces_dst) {
		MPoly *mpoly, *mp;
		MLoop *ml, *mloop;
		MEdge *medge;
		
		if (bmd->randomize) {
			BLI_array_randomize(faceMap, sizeof(*faceMap),
			                    numPoly_src, bmd->seed);
		}

		/* get the set of all vert indices that will be in the final mesh,
		 * mapped to the new indices
		 */
		mpoly = mpoly_src;
		mloop = mloop_src;
		for (i = 0; i < numFaces_dst; i++) {
			mp = mpoly + faceMap[i];
			ml = mloop + mp->loopstart;

			for (j = 0; j < mp->totloop; j++, ml++) {
				if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v)))
					BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(ml->v),
					                 SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
			}
			
			numLoops_dst += mp->totloop;
		}

		/* get the set of edges that will be in the new mesh (i.e. all edges
		 * that have both verts in the new mesh)
		 */
		medge = medge_src;
		for (i = 0; i < numEdge_src; i++) {
			MEdge *me = medge + i;

			if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) &&
			    BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2)))
			{
				j = BLI_ghash_size(edgeHash);
				
				BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
				                 SET_INT_IN_POINTER(i));
				BLI_ghash_insert(edgeHash2, SET_INT_IN_POINTER(i),
				                 SET_INT_IN_POINTER(j));
			}
		}
	}
	else if (numEdges_dst) {
		MEdge *medge, *me;

		if (bmd->randomize)
			BLI_array_randomize(edgeMap, sizeof(*edgeMap),
			                    numEdge_src, bmd->seed);

		/* get the set of all vert indices that will be in the final mesh,
		 * mapped to the new indices
		 */
		medge = medge_src;
		for (i = 0; i < numEdges_dst; i++) {
			me = medge + edgeMap[i];

			if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1))) {
				BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v1),
				                 SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
			}
			if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2))) {
				BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me->v2), SET_INT_IN_POINTER(BLI_ghash_size(vertHash)));
			}
		}

		/* get the set of edges that will be in the new mesh */
		for (i = 0; i < numEdges_dst; i++) {
			j = BLI_ghash_size(edgeHash);
			
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(j),
			                 SET_INT_IN_POINTER(edgeMap[i]));
			BLI_ghash_insert(edgeHash2,  SET_INT_IN_POINTER(edgeMap[i]),
			                 SET_INT_IN_POINTER(j));
		}
	}
	else {
		int numVerts = numVert_src * frac;

		if (bmd->randomize) {
			BLI_array_randomize(vertMap, sizeof(*vertMap),
			                    numVert_src, bmd->seed);
		}

		/* get the set of all vert indices that will be in the final mesh,
		 * mapped to the new indices
		 */
		for (i = 0; i < numVerts; i++) {
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(vertMap[i]), SET_INT_IN_POINTER(i));
		}
	}

	/* now we know the number of verts, edges and faces, we can create
	 * the mesh
	 */
	result = CDDM_from_template(dm, BLI_ghash_size(vertHash),
	                            BLI_ghash_size(edgeHash), 0, numLoops_dst, numFaces_dst);

	/* copy the vertices across */
	for (hashIter = BLI_ghashIterator_new(vertHash);
	     BLI_ghashIterator_done(hashIter) == false;
	     BLI_ghashIterator_step(hashIter)
	     )
	{
		MVert source;
		MVert *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));

		source = mvert_src[oldIndex];
		dest = CDDM_get_vert(result, newIndex);

		DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
	
	/* copy the edges across, remapping indices */
	for (i = 0; i < BLI_ghash_size(edgeHash); i++) {
		MEdge source;
		MEdge *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(i)));
		
		source = medge_src[oldIndex];
		dest = CDDM_get_edge(result, i);
		
		source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
		source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
		
		DM_copy_edge_data(dm, result, oldIndex, i, 1);
		*dest = source;
	}

	mpoly_dst = CDDM_get_polys(result);
	/* mloop_dst = */ ml_dst = CDDM_get_loops(result);
	
	/* copy the faces across, remapping indices */
	k = 0;
	for (i = 0; i < numFaces_dst; i++) {
		MPoly *source;
		MPoly *dest;
		
		source = mpoly_src + faceMap[i];
		dest = mpoly_dst + i;
		DM_copy_poly_data(dm, result, faceMap[i], i, 1);
		
		*dest = *source;
		dest->loopstart = k;
		
		DM_copy_loop_data(dm, result, source->loopstart, dest->loopstart, dest->totloop);

		ml_src = mloop_src + source->loopstart;
		for (j = 0; j < source->totloop; j++, k++, ml_src++, ml_dst++) {
			ml_dst->v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(ml_src->v)));
			ml_dst->e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash2, SET_INT_IN_POINTER(ml_src->e)));
		}
	}

	BLI_ghash_free(vertHash, NULL, NULL);
	BLI_ghash_free(edgeHash, NULL, NULL);
	BLI_ghash_free(edgeHash2, NULL, NULL);
	
	MEM_freeN(vertMap);
	MEM_freeN(edgeMap);
	MEM_freeN(faceMap);

	if (dm->dirty & DM_DIRTY_NORMALS) {
		result->dirty |= DM_DIRTY_NORMALS;
	}

	return result;
}
static void codegen_set_unique_ids(ListBase *nodes)
{
	GHash *bindhash, *definehash;
	GPUNode *node;
	GPUInput *input;
	GPUOutput *output;
	int id = 1, texid = 0;

	bindhash= BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
	definehash= BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");

	for (node=nodes->first; node; node=node->next) {
		for (input=node->inputs.first; input; input=input->next) {
			/* set id for unique names of uniform variables */
			input->id = id++;
			input->bindtex = 0;
			input->definetex = 0;

			/* set texid used for settings texture slot with multitexture */
			if (codegen_input_has_texture(input) &&
			    ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)))
			{
				if (input->link) {
					/* input is texture from buffer, assign only one texid per
					 * buffer to avoid sampling the same texture twice */
					if (!BLI_ghash_haskey(bindhash, input->link)) {
						input->texid = texid++;
						input->bindtex = 1;
						BLI_ghash_insert(bindhash, input->link, SET_INT_IN_POINTER(input->texid));
					}
					else
						input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->link));
				}
				else if (input->ima) {
					/* input is texture from image, assign only one texid per
					 * buffer to avoid sampling the same texture twice */
					if (!BLI_ghash_haskey(bindhash, input->ima)) {
						input->texid = texid++;
						input->bindtex = 1;
						BLI_ghash_insert(bindhash, input->ima, SET_INT_IN_POINTER(input->texid));
					}
					else
						input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->ima));
				}
				else if (input->prv) {
					/* input is texture from preview render, assign only one texid per
					 * buffer to avoid sampling the same texture twice */
					if (!BLI_ghash_haskey(bindhash, input->prv)) {
						input->texid = texid++;
						input->bindtex = 1;
						BLI_ghash_insert(bindhash, input->prv, SET_INT_IN_POINTER(input->texid));
					}
					else
						input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->prv));
				}
				else {
					if (!BLI_ghash_haskey(bindhash, input->tex)) {
						/* input is user created texture, check tex pointer */
						input->texid = texid++;
						input->bindtex = 1;
						BLI_ghash_insert(bindhash, input->tex, SET_INT_IN_POINTER(input->texid));
					}
					else
						input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->tex));
				}

				/* make sure this pixel is defined exactly once */
				if (input->source == GPU_SOURCE_TEX_PIXEL) {
					if (input->ima) {
						if (!BLI_ghash_haskey(definehash, input->ima)) {
							input->definetex = 1;
							BLI_ghash_insert(definehash, input->ima, SET_INT_IN_POINTER(input->texid));
						}
					}
					else {
						if (!BLI_ghash_haskey(definehash, input->link)) {
							input->definetex = 1;
							BLI_ghash_insert(definehash, input->link, SET_INT_IN_POINTER(input->texid));
						}
					}
				}
			}
		}

		for (output=node->outputs.first; output; output=output->next)
			/* set id for unique names of tmp variables storing output */
			output->id = id++;
	}

	BLI_ghash_free(bindhash, NULL, NULL);
	BLI_ghash_free(definehash, NULL, NULL);
}
static PyObject *bpy_bmvertskin_flag_get(BPy_BMVertSkin *self, void *flag_p)
{
	const int flag = GET_INT_FROM_POINTER(flag_p);
	return PyBool_FromLong(self->data->flag & flag);
}