예제 #1
0
/* OB_DUPLIVERTS - FONT */
static Object *find_family_object(const char *family, size_t family_len, unsigned int ch, GHash *family_gh)
{
	Object **ob_pt;
	Object *ob;
	void *ch_key = SET_UINT_IN_POINTER(ch);

	if ((ob_pt = (Object **)BLI_ghash_lookup_p(family_gh, ch_key))) {
		ob = *ob_pt;
	}
	else {
		char ch_utf8[7];
		size_t ch_utf8_len;

		ch_utf8_len = BLI_str_utf8_from_unicode(ch, ch_utf8);
		ch_utf8[ch_utf8_len] = '\0';
		ch_utf8_len += 1;  /* compare with null terminator */

		for (ob = G.main->object.first; ob; ob = ob->id.next) {
			if (STREQLEN(ob->id.name + 2 + family_len, ch_utf8, ch_utf8_len)) {
				if (STREQLEN(ob->id.name + 2, family, family_len)) {
					break;
				}
			}
		}

		/* inserted value can be NULL, just to save searches in future */
		BLI_ghash_insert(family_gh, ch_key, ob);
	}

	return ob;
}
예제 #2
0
/* Set the face's unique ID in the log */
static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id)
{
	void *fid = SET_UINT_IN_POINTER(id);

	BLI_ghash_reinsert(log->id_to_elem, fid, f, NULL, NULL);
	BLI_ghash_reinsert(log->elem_to_id, f, fid, NULL, NULL);
}
예제 #3
0
/* Set the vertex's unique ID in the log */
static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id)
{
	void *vid = SET_UINT_IN_POINTER(id);
	
	BLI_ghash_reinsert(log->id_to_elem, vid, v, NULL, NULL);
	BLI_ghash_reinsert(log->elem_to_id, v, vid, NULL, NULL);
}
예제 #4
0
wmTimer *WM_event_add_timer_notifier(wmWindowManager *wm, wmWindow *win, unsigned int type, double timestep)
{
    wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");

    wt->event_type = TIMERNOTIFIER;
    wt->ltime = PIL_check_seconds_timer();
    wt->ntime = wt->ltime + timestep;
    wt->stime = wt->ltime;
    wt->timestep = timestep;
    wt->win = win;
    wt->customdata = SET_UINT_IN_POINTER(type);

    BLI_addtail(&wm->timers, wt);

    return wt;
}
예제 #5
0
static VChar *freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
{
	const float scale = vfd->scale;
	const float eps = 0.0001f;
	const float eps_sq = eps * eps;
	/* Blender */
	struct Nurb *nu;
	struct VChar *che;
	struct BezTriple *bezt;

	/* Freetype2 */
	FT_GlyphSlot glyph;
	FT_UInt glyph_index;
	FT_Outline ftoutline;
	float dx, dy;
	int j, k, l, m = 0;

	/*
	 * Generate the character 3D data
	 *
	 * Get the FT Glyph index and load the Glyph */
	glyph_index = FT_Get_Char_Index(face, charcode);
	err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);

	/* If loading succeeded, convert the FT glyph to the internal format */
	if (!err) {
		int *npoints;
		int *onpoints;

		/* First we create entry for the new character to the character list */
		che = (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");

		/* Take some data for modifying purposes */
		glyph = face->glyph;
		ftoutline = glyph->outline;

		/* Set the width and character code */
		che->index = charcode;
		che->width = glyph->advance.x * scale;

		BLI_ghash_insert(vfd->characters, SET_UINT_IN_POINTER(che->index), che);

		/* Start converting the FT data */
		npoints = (int *)MEM_mallocN((ftoutline.n_contours) * sizeof(int), "endpoints");
		onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints");

		/* calculate total points of each contour */
		for (j = 0; j < ftoutline.n_contours; j++) {
			if (j == 0)
				npoints[j] = ftoutline.contours[j] + 1;
			else
				npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
		}

		/* get number of on-curve points for beziertriples (including conic virtual on-points) */
		for (j = 0; j < ftoutline.n_contours; j++) {
			for (k = 0; k < npoints[j]; k++) {
				l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;

				if (ftoutline.tags[l] == FT_Curve_Tag_On)
					onpoints[j]++;

				if (k < npoints[j] - 1) {
					if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
					    ftoutline.tags[l + 1] == FT_Curve_Tag_Conic)
					{
						onpoints[j]++;
					}
				}
			}
		}

		/* contour loop, bezier & conic styles merged */
		for (j = 0; j < ftoutline.n_contours; j++) {
			/* add new curve */
			nu  =  (Nurb *)MEM_callocN(sizeof(struct Nurb), "objfnt_nurb");
			bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt");
			BLI_addtail(&che->nurbsbase, nu);

			nu->type = CU_BEZIER;
			nu->pntsu = onpoints[j];
			nu->resolu = 8;
			nu->flag = CU_2D;
			nu->flagu = CU_NURB_CYCLIC;
			nu->bezt = bezt;

			/* individual curve loop, start-end */
			for (k = 0; k < npoints[j]; k++) {
				if (j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
				if (k == 0) m = l;

				/* virtual conic on-curve points */
				if (k < npoints[j] - 1) {
					if (ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) {
						dx = (ftoutline.points[l].x + ftoutline.points[l + 1].x) * scale / 2.0f;
						dy = (ftoutline.points[l].y + ftoutline.points[l + 1].y) * scale / 2.0f;

						/* left handle */
						bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x) * scale) / 3.0f;
						bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y) * scale) / 3.0f;

						/* midpoint (virtual on-curve point) */
						bezt->vec[1][0] = dx;
						bezt->vec[1][1] = dy;

						/* right handle */
						bezt->vec[2][0] = (dx + (2 * ftoutline.points[l + 1].x) * scale) / 3.0f;
						bezt->vec[2][1] = (dy + (2 * ftoutline.points[l + 1].y) * scale) / 3.0f;

						bezt->h1 = bezt->h2 = HD_ALIGN;
						bezt->radius = 1.0f;
						bezt++;
					}
				}

				/* on-curve points */
				if (ftoutline.tags[l] == FT_Curve_Tag_On) {
					/* left handle */
					if (k > 0) {
						if (ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
							bezt->vec[0][0] = ftoutline.points[l - 1].x * scale;
							bezt->vec[0][1] = ftoutline.points[l - 1].y * scale;
							bezt->h1 = HD_FREE;
						}
						else if (ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
							bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x)) * scale / 3.0f;
							bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y)) * scale / 3.0f;
							bezt->h1 = HD_FREE;
						}
						else {
							bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l - 1].x) * scale / 3.0f;
							bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l - 1].y) * scale / 3.0f;
							bezt->h1 = HD_VECT;
						}
					}
					else { /* first point on curve */
						if (ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
							bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
							bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
							bezt->h1 = HD_FREE;
						}
						else if (ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
							bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x)) * scale / 3.0f;
							bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y)) * scale / 3.0f;
							bezt->h1 = HD_FREE;
						}
						else {
							bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x) * scale / 3.0f;
							bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y) * scale / 3.0f;
							bezt->h1 = HD_VECT;
						}
					}

					/* midpoint (on-curve point) */
					bezt->vec[1][0] = ftoutline.points[l].x * scale;
					bezt->vec[1][1] = ftoutline.points[l].y * scale;

					/* right handle */
					if (k < (npoints[j] - 1)) {
						if (ftoutline.tags[l + 1] == FT_Curve_Tag_Cubic) {
							bezt->vec[2][0] = ftoutline.points[l + 1].x * scale;
							bezt->vec[2][1] = ftoutline.points[l + 1].y * scale;
							bezt->h2 = HD_FREE;
						}
						else if (ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) {
							bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l + 1].x)) * scale / 3.0f;
							bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l + 1].y)) * scale / 3.0f;
							bezt->h2 = HD_FREE;
						}
						else {
							bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l + 1].x) * scale / 3.0f;
							bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l + 1].y) * scale / 3.0f;
							bezt->h2 = HD_VECT;
						}
					}
					else { /* last point on curve */
						if (ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
							bezt->vec[2][0] = ftoutline.points[m].x * scale;
							bezt->vec[2][1] = ftoutline.points[m].y * scale;
							bezt->h2 = HD_FREE;
						}
						else if (ftoutline.tags[m] == FT_Curve_Tag_Conic) {
							bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x)) * scale / 3.0f;
							bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y)) * scale / 3.0f;
							bezt->h2 = HD_FREE;
						}
						else {
							bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[m].x) * scale / 3.0f;
							bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[m].y) * scale / 3.0f;
							bezt->h2 = HD_VECT;
						}
					}

					/* get the handles that are aligned, tricky...
					 * - check if one of them is a vector handle.
					 * - dist_squared_to_line_v2, check if the three beztriple points are on one line
					 * - len_squared_v2v2, see if there's a distance between the three points
					 * - len_squared_v2v2 again, to check the angle between the handles
					 */
					if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) &&
					    (dist_squared_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) < (0.001f * 0.001f)) &&
					    (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > eps_sq) &&
					    (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > eps_sq) &&
					    (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > eps_sq) &&
					    (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) >
					     max_ff(len_squared_v2v2(bezt->vec[0], bezt->vec[1]),
					            len_squared_v2v2(bezt->vec[1], bezt->vec[2]))))
					{
						bezt->h1 = bezt->h2 = HD_ALIGN;
					}
					bezt->radius = 1.0f;
					bezt++;
				}
			}
		}
		if (npoints) MEM_freeN(npoints);
		if (onpoints) MEM_freeN(onpoints);

		return che;
	}

	return NULL;
}
예제 #6
0
static void layer_bucket_init(MaskRasterLayer *layer, const float pixel_size)
{
	MemArena *arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__);

	const float bucket_dim_x = BLI_rctf_size_x(&layer->bounds);
	const float bucket_dim_y = BLI_rctf_size_y(&layer->bounds);

	layer->buckets_x = (unsigned int)((bucket_dim_x / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);
	layer->buckets_y = (unsigned int)((bucket_dim_y / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);

//		printf("bucket size %ux%u\n", layer->buckets_x, layer->buckets_y);

	CLAMP(layer->buckets_x, 8, 512);
	CLAMP(layer->buckets_y, 8, 512);

	layer->buckets_xy_scalar[0] = (1.0f / (bucket_dim_x + FLT_EPSILON)) * (float)layer->buckets_x;
	layer->buckets_xy_scalar[1] = (1.0f / (bucket_dim_y + FLT_EPSILON)) * (float)layer->buckets_y;

	{
		/* width and height of each bucket */
		const float bucket_size_x = (bucket_dim_x + FLT_EPSILON) / (float)layer->buckets_x;
		const float bucket_size_y = (bucket_dim_y + FLT_EPSILON) / (float)layer->buckets_y;
		const float bucket_max_rad = (max_ff(bucket_size_x, bucket_size_y) * (float)M_SQRT2) + FLT_EPSILON;
		const float bucket_max_rad_squared = bucket_max_rad * bucket_max_rad;

		unsigned int *face = &layer->face_array[0][0];
		float (*cos)[3] = layer->face_coords;

		const unsigned int  bucket_tot = layer->buckets_x * layer->buckets_y;
		LinkNode     **bucketstore     = MEM_callocN(bucket_tot * sizeof(LinkNode *),  __func__);
		unsigned int  *bucketstore_tot = MEM_callocN(bucket_tot * sizeof(unsigned int), __func__);

		unsigned int face_index;

		for (face_index = 0; face_index < layer->face_tot; face_index++, face += 4) {
			float xmin;
			float xmax;
			float ymin;
			float ymax;

			if (face[3] == TRI_VERT) {
				const float *v1 = cos[face[0]];
				const float *v2 = cos[face[1]];
				const float *v3 = cos[face[2]];

				xmin = min_ff(v1[0], min_ff(v2[0], v3[0]));
				xmax = max_ff(v1[0], max_ff(v2[0], v3[0]));
				ymin = min_ff(v1[1], min_ff(v2[1], v3[1]));
				ymax = max_ff(v1[1], max_ff(v2[1], v3[1]));
			}
			else {
				const float *v1 = cos[face[0]];
				const float *v2 = cos[face[1]];
				const float *v3 = cos[face[2]];
				const float *v4 = cos[face[3]];

				xmin = min_ff(v1[0], min_ff(v2[0], min_ff(v3[0], v4[0])));
				xmax = max_ff(v1[0], max_ff(v2[0], max_ff(v3[0], v4[0])));
				ymin = min_ff(v1[1], min_ff(v2[1], min_ff(v3[1], v4[1])));
				ymax = max_ff(v1[1], max_ff(v2[1], max_ff(v3[1], v4[1])));
			}


			/* not essential but may as will skip any faces outside the view */
			if (!((xmax < 0.0f) || (ymax < 0.0f) || (xmin > 1.0f) || (ymin > 1.0f))) {

				CLAMP(xmin, 0.0f,  1.0f);
				CLAMP(ymin, 0.0f,  1.0f);
				CLAMP(xmax, 0.0f,  1.0f);
				CLAMP(ymax, 0.0f,  1.0f);

				{
					unsigned int xi_min = (unsigned int) ((xmin - layer->bounds.xmin) * layer->buckets_xy_scalar[0]);
					unsigned int xi_max = (unsigned int) ((xmax - layer->bounds.xmin) * layer->buckets_xy_scalar[0]);
					unsigned int yi_min = (unsigned int) ((ymin - layer->bounds.ymin) * layer->buckets_xy_scalar[1]);
					unsigned int yi_max = (unsigned int) ((ymax - layer->bounds.ymin) * layer->buckets_xy_scalar[1]);
					void *face_index_void = SET_UINT_IN_POINTER(face_index);

					unsigned int xi, yi;

					/* this should _almost_ never happen but since it can in extreme cases,
					 * we have to clamp the values or we overrun the buffer and crash */
					if (xi_min >= layer->buckets_x) xi_min = layer->buckets_x - 1;
					if (xi_max >= layer->buckets_x) xi_max = layer->buckets_x - 1;
					if (yi_min >= layer->buckets_y) yi_min = layer->buckets_y - 1;
					if (yi_max >= layer->buckets_y) yi_max = layer->buckets_y - 1;

					for (yi = yi_min; yi <= yi_max; yi++) {
						unsigned int bucket_index = (layer->buckets_x * yi) + xi_min;
						for (xi = xi_min; xi <= xi_max; xi++, bucket_index++) {
							// unsigned int bucket_index = (layer->buckets_x * yi) + xi; /* correct but do in outer loop */

							BLI_assert(xi < layer->buckets_x);
							BLI_assert(yi < layer->buckets_y);
							BLI_assert(bucket_index < bucket_tot);

							/* check if the bucket intersects with the face */
							/* note: there is a trade off here since checking box/tri intersections isn't
							 * as optimal as it could be, but checking pixels against faces they will never intersect
							 * with is likely the greater slowdown here - so check if the cell intersects the face */
							if (layer_bucket_isect_test(layer, face_index,
							                            xi, yi,
							                            bucket_size_x, bucket_size_y,
							                            bucket_max_rad_squared))
							{
								BLI_linklist_prepend_arena(&bucketstore[bucket_index], face_index_void, arena);
								bucketstore_tot[bucket_index]++;
							}
						}
					}
				}
			}
		}

		if (1) {
			/* now convert linknodes into arrays for faster per pixel access */
			unsigned int  **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__);
			unsigned int bucket_index;

			for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
				if (bucketstore_tot[bucket_index]) {
					unsigned int  *bucket = MEM_mallocN((bucketstore_tot[bucket_index] + 1) * sizeof(unsigned int),
					                                    __func__);
					LinkNode *bucket_node;

					buckets_face[bucket_index] = bucket;

					for (bucket_node = bucketstore[bucket_index]; bucket_node; bucket_node = bucket_node->next) {
						*bucket = GET_UINT_FROM_POINTER(bucket_node->link);
						bucket++;
					}
					*bucket = TRI_TERMINATOR_ID;
				}
				else {
					buckets_face[bucket_index] = NULL;
				}
			}

			layer->buckets_face = buckets_face;
		}

		MEM_freeN(bucketstore);
		MEM_freeN(bucketstore_tot);
	}

	BLI_memarena_free(arena);
}
예제 #7
0
static void initSnappingMode(TransInfo *t)
{
	ToolSettings *ts = t->settings;
	Object *obedit = t->obedit;
	Scene *scene = t->scene;
	Base *base_act = scene->basact;

	if (t->spacetype == SPACE_NODE) {
		/* force project off when not supported */
		t->tsnap.project = 0;
		
		t->tsnap.mode = ts->snap_node_mode;
	}
	else if (t->spacetype == SPACE_IMAGE) {
		/* force project off when not supported */
		t->tsnap.project = 0;
		
		t->tsnap.mode = ts->snap_uv_mode;
	}
	else {
		/* force project off when not supported */
		if (ts->snap_mode != SCE_SNAP_MODE_FACE)
			t->tsnap.project = 0;
		
		t->tsnap.mode = ts->snap_mode;
	}

	if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) &&  /* Only 3D view or UV */
	    (t->flag & T_CAMERA) == 0)  /* Not with camera selected in camera view */
	{
		setSnappingCallback(t);

		/* Edit mode */
		if (t->tsnap.applySnap != NULL && // A snapping function actually exist
		    (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
		{
			/* Exclude editmesh if using proportional edit */
			if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
				t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
			}
			else {
				t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE;
			}
		}
		/* Particles edit mode*/
		else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
		         (obedit == NULL && base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT))
		{
			t->tsnap.modeSelect = SNAP_ALL;
		}
		/* Object mode */
		else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
		         (obedit == NULL) ) // Object Mode
		{
			t->tsnap.modeSelect = SNAP_NOT_SELECTED;
		}
		else {
			/* Grid if snap is not possible */
			t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
		}
	}
	else if (t->spacetype == SPACE_NODE) {
		setSnappingCallback(t);
		
		if (t->tsnap.applySnap != NULL) {
			t->tsnap.modeSelect = SNAP_NOT_SELECTED;
		}
		else {
			/* Grid if snap is not possible */
			t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
		}
	}
	else if (t->spacetype == SPACE_SEQ) {
		/* We do our own snapping currently, so nothing here */
		t->tsnap.mode = SCE_SNAP_MODE_GRID;  /* Dummy, should we rather add a NOP mode? */
	}
	else {
		/* Always grid outside of 3D view */
		t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
	}

	if (t->spacetype == SPACE_VIEW3D) {
		if (t->tsnap.object_context == NULL) {
			t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
			        G.main, t->scene, SNAP_OBJECT_USE_CACHE,
			        t->ar, t->view);

			ED_transform_snap_object_context_set_editmesh_callbacks(
			        t->tsnap.object_context,
			        (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
			        bm_edge_is_snap_target,
			        bm_face_is_snap_target,
			        SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
		}
	}
}
예제 #8
0
/* Get a face from its unique ID */
static BMFace *bm_log_face_from_id(BMLog *log, unsigned int id)
{
	void *key = SET_UINT_IN_POINTER(id);
	BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
	return BLI_ghash_lookup(log->id_to_elem, key);
}
예제 #9
0
파일: MOD_mask.c 프로젝트: wchargin/blender
static DerivedMesh *applyModifier(
        ModifierData *md, Object *ob,
        DerivedMesh *dm,
        ModifierApplyFlag UNUSED(flag))
{
	MaskModifierData *mmd = (MaskModifierData *)md;
	const bool found_test = (mmd->flag & MOD_MASK_INV) == 0;
	DerivedMesh *result = NULL;
	GHash *vertHash = NULL, *edgeHash, *polyHash;
	GHashIterator gh_iter;
	MDeformVert *dvert, *dv;
	int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0;
	int maxVerts, maxEdges, maxPolys;
	int i;

	const MVert *mvert_src;
	const MEdge *medge_src;
	const MPoly *mpoly_src;
	const MLoop *mloop_src;

	MPoly *mpoly_dst;
	MLoop *mloop_dst;
	MEdge *medge_dst;
	MVert *mvert_dst;

	int *loop_mapping;

	dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
	if (dvert == NULL) {
		return found_test ? CDDM_from_template(dm, 0, 0, 0, 0, 0) : dm;
	}

	/* 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) || BLI_listbase_is_empty(&ob->defbase))
	{
		return dm;
	}

	/* 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;
		bool *bone_select_array;
		int bone_select_tot = 0;
		const int defbase_tot = BLI_listbase_count(&ob->defbase);

		/* check that there is armature object with bones to use, otherwise return original mesh */
		if (ELEM(NULL, oba, oba->pose, ob->defbase.first))
			return dm;

		/* 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_malloc_arrayN((size_t)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;
			}
		}

		/* verthash gives mapping from original vertex indices to the new indices (including selected matches only)
		 * key = oldindex, value = newindex
		 */
		vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts);

		/* 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;
			bool found = false;
			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;
						}
					}
				}
			}

			if (found_test != 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);

		/* if no vgroup (i.e. dverts) found, return the initial mesh */
		if (defgrp_index == -1)
			return dm;

		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts);

		/* add vertices which exist in vertexgroup into ghash for filtering */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			const bool found = defvert_find_weight(dv, defgrp_index) != 0.0f;
			if (found_test != 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++;
		}
	}

	/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
	edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges);
	polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys);

	mvert_src = dm->getVertArray(dm);
	medge_src = dm->getEdgeArray(dm);
	mpoly_src = dm->getPolyArray(dm);
	mloop_src = dm->getLoopArray(dm);

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

	/* loop over edges and faces, and do the same thing to
	 * ensure that they only reference existing verts
	 */
	for (i = 0; i < maxEdges; i++) {
		const MEdge *me = &medge_src[i];

		/* 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++) {
		const MPoly *mp_src = &mpoly_src[i];
		const MLoop *ml_src = &mloop_src[mp_src->loopstart];
		bool ok = true;
		int j;

		for (j = 0; j < mp_src->totloop; j++, ml_src++) {
			if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml_src->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_src->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_dst = CDDM_get_polys(result);
	mloop_dst = CDDM_get_loops(result);
	medge_dst = CDDM_get_edges(result);
	mvert_dst = CDDM_get_verts(result);

	/* using ghash-iterators, map data into new mesh */
	/* vertices */
	GHASH_ITER (gh_iter, vertHash) {
		const MVert *v_src;
		MVert *v_dst;
		const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
		const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));

		v_src = &mvert_src[i_src];
		v_dst = &mvert_dst[i_dst];

		*v_dst = *v_src;
		DM_copy_vert_data(dm, result, i_src, i_dst, 1);
	}

	/* edges */
	GHASH_ITER (gh_iter, edgeHash) {
		const MEdge *e_src;
		MEdge *e_dst;
		const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
		const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));

		e_src = &medge_src[i_src];
		e_dst = &medge_dst[i_dst];

		DM_copy_edge_data(dm, result, i_src, i_dst, 1);
		*e_dst = *e_src;
		e_dst->v1 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v1)));
		e_dst->v2 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v2)));
	}

	/* faces */
	GHASH_ITER (gh_iter, polyHash) {
		const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
		const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
		const MPoly *mp_src = &mpoly_src[i_src];
		MPoly *mp_dst = &mpoly_dst[i_dst];
		const int i_ml_src = mp_src->loopstart;
		const int i_ml_dst = loop_mapping[i_dst];
		const MLoop *ml_src = &mloop_src[i_ml_src];
		MLoop *ml_dst = &mloop_dst[i_ml_dst];

		DM_copy_poly_data(dm, result, i_src, i_dst, 1);
		DM_copy_loop_data(dm, result, i_ml_src, i_ml_dst, mp_src->totloop);

		*mp_dst = *mp_src;
		mp_dst->loopstart = i_ml_dst;
		for (i = 0; i < mp_src->totloop; i++) {
			ml_dst[i].v = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(ml_src[i].v)));
			ml_dst[i].e = GET_UINT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_UINT_IN_POINTER(ml_src[i].e)));
		}
	}

	MEM_freeN(loop_mapping);

	/* why is this needed? - campbell */
	/* recalculate normals */
	result->dirty |= DM_DIRTY_NORMALS;

	/* 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;
}
예제 #10
0
/* Get a vertex from its unique ID */
static BMVert *bm_log_vert_from_id(BMLog *log, uint id)
{
	void *key = SET_UINT_IN_POINTER(id);
	BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
	return BLI_ghash_lookup(log->id_to_elem, key);
}