예제 #1
0
파일: scanfill.c 프로젝트: sftd/blender
static void splitlist(ScanFillContext *sf_ctx, ListBase *tempve, ListBase *temped, unsigned short nr)
{
	/* everything is in templist, write only poly nr to fillist */
	ScanFillVert *eve, *eve_next;
	ScanFillEdge *eed, *eed_next;

	BLI_movelisttolist(tempve, &sf_ctx->fillvertbase);
	BLI_movelisttolist(temped, &sf_ctx->filledgebase);


	for (eve = tempve->first; eve; eve = eve_next) {
		eve_next = eve->next;
		if (eve->poly_nr == nr) {
			BLI_remlink(tempve, eve);
			BLI_addtail(&sf_ctx->fillvertbase, eve);
		}

	}
	
	for (eed = temped->first; eed; eed = eed_next) {
		eed_next = eed->next;
		if (eed->poly_nr == nr) {
			BLI_remlink(temped, eed);
			BLI_addtail(&sf_ctx->filledgebase, eed);
		}
	}
}
예제 #2
0
static void splitlist(ListBase *tempve, ListBase *temped, short nr)
{
	/* everything is in templist, write only poly nr to fillist */
	EditVert *eve,*nextve;
	EditEdge *eed,*nexted;

	BLI_movelisttolist(tempve,&fillvertbase);
	BLI_movelisttolist(temped,&filledgebase);

	eve= tempve->first;
	while(eve) {
		nextve= eve->next;
		if(eve->xs==nr) {
			BLI_remlink(tempve,eve);
			BLI_addtail(&fillvertbase,eve);
		}
		eve= nextve;
	}
	eed= temped->first;
	while(eed) {
		nexted= eed->next;
		if(eed->f1==nr) {
			BLI_remlink(temped,eed);
			BLI_addtail(&filledgebase,eed);
		}
		eed= nexted;
	}
}
예제 #3
0
파일: scanfill.c 프로젝트: 244xiao/blender
static void splitlist(ScanFillContext *sf_ctx, ListBase *tempve, ListBase *temped, short nr)
{
	/* everything is in templist, write only poly nr to fillist */
	ScanFillVert *eve, *nextve;
	ScanFillEdge *eed, *nexted;

	BLI_movelisttolist(tempve, &sf_ctx->fillvertbase);
	BLI_movelisttolist(temped, &sf_ctx->filledgebase);

	eve = tempve->first;
	while (eve) {
		nextve = eve->next;
		if (eve->poly_nr == nr) {
			BLI_remlink(tempve, eve);
			BLI_addtail(&sf_ctx->fillvertbase, eve);
		}
		eve = nextve;
	}
	eed = temped->first;
	while (eed) {
		nexted = eed->next;
		if (eed->poly_nr == nr) {
			BLI_remlink(temped, eed);
			BLI_addtail(&sf_ctx->filledgebase, eed);
		}
		eed = nexted;
	}
}
예제 #4
0
void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey)
{
	wmJob *wm_job;
	IconPreview *ip, *old_ip;
	
	/* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview",
	                     WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, WM_JOB_TYPE_RENDER_PREVIEW);

	ip = MEM_callocN(sizeof(IconPreview), "icon preview");

	/* render all resolutions from suspended job too */
	old_ip = WM_jobs_customdata_get(wm_job);
	if (old_ip)
		BLI_movelisttolist(&ip->sizes, &old_ip->sizes);

	/* customdata for preview thread */
	ip->scene = CTX_data_scene(C);
	ip->owner = id;
	ip->id = id;

	icon_preview_add_size(ip, rect, sizex, sizey);

	/* setup job */
	WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
	WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
	WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);

	WM_jobs_start(CTX_wm_manager(C), wm_job);
}
예제 #5
0
void ED_preview_icon_job(
    const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey)
{
  wmJob *wm_job;
  IconPreview *ip, *old_ip;

  ED_preview_ensure_dbase();

  /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
  wm_job = WM_jobs_get(CTX_wm_manager(C),
                       CTX_wm_window(C),
                       owner,
                       "Icon Preview",
                       WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND,
                       WM_JOB_TYPE_RENDER_PREVIEW);

  ip = MEM_callocN(sizeof(IconPreview), "icon preview");

  /* render all resolutions from suspended job too */
  old_ip = WM_jobs_customdata_get(wm_job);
  if (old_ip) {
    BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
  }

  /* customdata for preview thread */
  ip->bmain = CTX_data_main(C);
  ip->scene = CTX_data_scene(C);
  ip->depsgraph = CTX_data_depsgraph(C);
  ip->owner = owner;
  ip->id = id;
  ip->id_copy = duplicate_ids(id);

  icon_preview_add_size(ip, rect, sizex, sizey);

  /* Special threading hack:
   * warn main code that this preview is being rendered and cannot be freed... */
  {
    PreviewImage *prv_img = owner;
    if (prv_img->tag & PRV_TAG_DEFFERED) {
      prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
    }
  }

  /* setup job */
  WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
  WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
  WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);

  WM_jobs_start(CTX_wm_manager(C), wm_job);
}
예제 #6
0
void BLI_voronoi_compute(
    const VoronoiSite *sites, int sites_total, int width, int height, ListBase *edges)
{
  VoronoiProcess process;
  VoronoiEdge *edge;
  int i;

  memset(&process, 0, sizeof(VoronoiProcess));

  process.width = width;
  process.height = height;

  for (i = 0; i < sites_total; i++) {
    VoronoiEvent *event = MEM_callocN(sizeof(VoronoiEvent), "voronoi site event");

    event->type = voronoiEventType_Site;
    copy_v2_v2(event->site, sites[i].co);

    voronoi_insertEvent(&process, event);
  }

  while (process.queue.first) {
    VoronoiEvent *event = process.queue.first;

    process.current_y = event->site[1];

    if (event->type == voronoiEventType_Site) {
      voronoi_addParabola(&process, event->site);
    }
    else {
      voronoi_removeParabola(&process, event);
    }

    BLI_freelinkN(&process.queue, event);
  }

  voronoi_finishEdge(&process, process.root);

  edge = process.edges.first;
  while (edge) {
    if (edge->neighbor) {
      copy_v2_v2(edge->start, edge->neighbor->end);
      MEM_freeN(edge->neighbor);
    }

    edge = edge->next;
  }

  BLI_movelisttolist(edges, &process.edges);
}
예제 #7
0
/* This function adds data to the copy/paste buffer, freeing existing data first
 * Only the selected GP-layers get their selected keyframes copied.
 *
 * Returns whether the copy operation was successful or not
 */
bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
{
	ListBase anim_data = {NULL, NULL};
	bAnimListElem *ale;
	int filter;
	
	Scene *scene = ac->scene;
	
	
	/* clear buffer first */
	ED_gpencil_anim_copybuf_free();
	
	/* filter data */
	filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
	ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
	
	/* assume that each of these is a GP layer */
	for (ale = anim_data.first; ale; ale = ale->next) {
		ListBase copied_frames = {NULL, NULL};
		bGPDlayer *gpl = (bGPDlayer *)ale->data;
		bGPDframe *gpf;
		
		/* loop over frames, and copy only selected frames */
		for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
			/* if frame is selected, make duplicate it and its strokes */
			if (gpf->flag & GP_FRAME_SELECT) {
				/* make a copy of this frame */
				bGPDframe *new_frame = gpencil_frame_duplicate(gpf);
				BLI_addtail(&copied_frames, new_frame);
				
				/* extend extents for keyframes encountered */
				if (gpf->framenum  < gp_anim_copy_firstframe)
					gp_anim_copy_firstframe = gpf->framenum; 
				if (gpf->framenum > gp_anim_copy_lastframe)
					gp_anim_copy_lastframe = gpf->framenum;
			}
		}
		
		/* create a new layer in buffer if there were keyframes here */
		if (BLI_listbase_is_empty(&copied_frames) == false) {
			bGPDlayer *new_layer = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
			BLI_addtail(&gp_anim_copybuf, new_layer);
			
			/* move over copied frames */
			BLI_movelisttolist(&new_layer->frames, &copied_frames);
			BLI_assert(copied_frames.first == NULL);
			
			/* make a copy of the layer's name - for name-based matching later... */
			BLI_strncpy(new_layer->info, gpl->info, sizeof(new_layer->info));
		}
	}
	
	/* in case 'relative' paste method is used */
	gp_anim_copy_cfra = CFRA;
	
	/* clean up */
	ANIM_animdata_freelist(&anim_data);
	
	/* check if anything ended up in the buffer */
	if (ELEM(NULL, gp_anim_copybuf.first, gp_anim_copybuf.last)) {
		BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
		return false;
	}
	
	/* report success */
	return true;
}
예제 #8
0
파일: scanfill.c 프로젝트: sftd/blender
unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float nor_proj[3])
{
	/*
	 * - fill works with its own lists, so create that first (no faces!)
	 * - for vertices, put in ->tmp.v the old pointer
	 * - struct elements xs en ys are not used here: don't hide stuff in it
	 * - edge flag ->f becomes 2 when it's a new edge
	 * - mode: & 1 is check for crossings, then create edges (TO DO )
	 * - returns number of triangle faces added.
	 */
	ListBase tempve, temped;
	ScanFillVert *eve;
	ScanFillEdge *eed, *eed_next;
	PolyFill *pflist, *pf;
	float *min_xy_p, *max_xy_p;
	unsigned int totfaces = 0;  /* total faces added */
	unsigned short a, c, poly = 0;
	bool ok;
	float mat_2d[3][3];

	BLI_assert(!nor_proj || len_squared_v3(nor_proj) > FLT_EPSILON);

#ifdef DEBUG
	for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
		/* these values used to be set,
		 * however they should always be zero'd so check instead */
		BLI_assert(eve->f == 0);
		BLI_assert(sf_ctx->poly_nr || eve->poly_nr == 0);
		BLI_assert(eve->edge_tot == 0);
	}
#endif

#if 0
	if (flag & BLI_SCANFILL_CALC_QUADTRI_FASTPATH) {
		const int totverts = BLI_countlist(&sf_ctx->fillvertbase);

		if (totverts == 3) {
			eve = sf_ctx->fillvertbase.first;

			addfillface(sf_ctx, eve, eve->next, eve->next->next);
			return 1;
		}
		else if (totverts == 4) {
			float vec1[3], vec2[3];

			eve = sf_ctx->fillvertbase.first;
			/* no need to check 'eve->next->next->next' is valid, already counted */
			/* use shortest diagonal for quad */
			sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
			sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);

			if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) {
				addfillface(sf_ctx, eve, eve->next, eve->next->next);
				addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve);
			}
			else {
				addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next);
				addfillface(sf_ctx, eve->next->next->next, eve, eve->next);
			}
			return 2;
		}
	}
#endif

	/* first test vertices if they are in edges */
	/* including resetting of flags */
	for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
		BLI_assert(sf_ctx->poly_nr != SF_POLY_UNSET || eed->poly_nr == SF_POLY_UNSET);
		eed->v1->f = SF_VERT_AVAILABLE;
		eed->v2->f = SF_VERT_AVAILABLE;
	}

	for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
		if (eve->f == SF_VERT_AVAILABLE) {
			break;
		}
	}

	if (UNLIKELY(eve == NULL)) {
		return 0;
	}
	else {
		float n[3];

		if (nor_proj) {
			copy_v3_v3(n, nor_proj);
		}
		else {
			/* define projection: with 'best' normal */
			/* Newell's Method */
			/* Similar code used elsewhere, but this checks for double ups
			 * which historically this function supports so better not change */

			/* warning: this only gives stable direction with single polygons,
			 * ideally we'd calcualte connectivity and calculate each polys normal, see T41047 */
			const float *v_prev;

			zero_v3(n);
			eve = sf_ctx->fillvertbase.last;
			v_prev = eve->co;

			for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
				if (LIKELY(!compare_v3v3(v_prev, eve->co, SF_EPSILON))) {
					add_newell_cross_v3_v3v3(n, v_prev, eve->co);
					v_prev = eve->co;
				}
			}
		}

		if (UNLIKELY(normalize_v3(n) == 0.0f)) {
			return 0;
		}

		axis_dominant_v3_to_m3(mat_2d, n);
	}


	/* STEP 1: COUNT POLYS */
	if (sf_ctx->poly_nr != SF_POLY_UNSET) {
		poly = (unsigned short)(sf_ctx->poly_nr + 1);
		sf_ctx->poly_nr = SF_POLY_UNSET;
	}

	if (flag & BLI_SCANFILL_CALC_POLYS && (poly == 0)) {
		for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
			mul_v2_m3v3(eve->xy, mat_2d, eve->co);

			/* get first vertex with no poly number */
			if (eve->poly_nr == SF_POLY_UNSET) {
				unsigned int toggle = 0;
				/* now a sort of select connected */
				ok = true;
				eve->poly_nr = poly;

				while (ok) {

					ok = false;

					toggle++;
					for (eed = (toggle & 1) ? sf_ctx->filledgebase.first : sf_ctx->filledgebase.last;
					     eed;
					     eed = (toggle & 1) ? eed->next : eed->prev)
					{
						if (eed->v1->poly_nr == SF_POLY_UNSET && eed->v2->poly_nr == poly) {
							eed->v1->poly_nr = poly;
							eed->poly_nr = poly;
							ok = true;
						}
						else if (eed->v2->poly_nr == SF_POLY_UNSET && eed->v1->poly_nr == poly) {
							eed->v2->poly_nr = poly;
							eed->poly_nr = poly;
							ok = true;
						}
						else if (eed->poly_nr == SF_POLY_UNSET) {
							if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) {
								eed->poly_nr = poly;
								ok = true;
							}
						}
					}
				}

				poly++;
			}
		}
		/* printf("amount of poly's: %d\n", poly); */
	}
	else if (poly) {
		/* we pre-calculated poly_nr */
		for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
			mul_v2_m3v3(eve->xy, mat_2d, eve->co);
		}
	}
	else {
		poly = 1;

		for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
			mul_v2_m3v3(eve->xy, mat_2d, eve->co);
			eve->poly_nr = 0;
		}

		for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
			eed->poly_nr = 0;
		}
	}

	/* STEP 2: remove loose edges and strings of edges */
	if (flag & BLI_SCANFILL_CALC_LOOSE) {
		unsigned int toggle = 0;
		for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
			if (eed->v1->edge_tot++ > 250) break;
			if (eed->v2->edge_tot++ > 250) break;
		}
		if (eed) {
			/* otherwise it's impossible to be sure you can clear vertices */
#ifdef DEBUG
			printf("No vertices with 250 edges allowed!\n");
#endif
			return 0;
		}

		/* does it only for vertices with (->edge_tot == 1) */
		testvertexnearedge(sf_ctx);

		ok = true;
		while (ok) {
			ok = false;

			toggle++;
			for (eed = (toggle & 1) ? sf_ctx->filledgebase.first : sf_ctx->filledgebase.last;
			     eed;
			     eed = eed_next)
			{
				eed_next = (toggle & 1) ? eed->next : eed->prev;
				if (eed->v1->edge_tot == 1) {
					eed->v2->edge_tot--;
					BLI_remlink(&sf_ctx->fillvertbase, eed->v1);
					BLI_remlink(&sf_ctx->filledgebase, eed);
					ok = true;
				}
				else if (eed->v2->edge_tot == 1) {
					eed->v1->edge_tot--;
					BLI_remlink(&sf_ctx->fillvertbase, eed->v2);
					BLI_remlink(&sf_ctx->filledgebase, eed);
					ok = true;
				}
			}
		}
		if (BLI_listbase_is_empty(&sf_ctx->filledgebase)) {
			/* printf("All edges removed\n"); */
			return 0;
		}
	}
	else {
		/* skip checks for loose edges */
		for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
			eed->v1->edge_tot++;
			eed->v2->edge_tot++;
		}
#ifdef DEBUG
		/* ensure we're right! */
		for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
			BLI_assert(eed->v1->edge_tot != 1);
			BLI_assert(eed->v2->edge_tot != 1);
		}
#endif
	}


	/* CURRENT STATUS:
	 * - eve->f        :1 = available in edges
	 * - eve->poly_nr  :polynumber
	 * - eve->edge_tot :amount of edges connected to vertex
	 * - eve->tmp.v    :store! original vertex number
	 * 
	 * - eed->f        :1 = boundary edge (optionally set by caller)
	 * - eed->poly_nr  :poly number
	 */


	/* STEP 3: MAKE POLYFILL STRUCT */
	pflist = MEM_mallocN(sizeof(*pflist) * (size_t)poly, "edgefill");
	pf = pflist;
	for (a = 0; a < poly; a++) {
		pf->edges = pf->verts = 0;
		pf->min_xy[0] = pf->min_xy[1] =  1.0e20f;
		pf->max_xy[0] = pf->max_xy[1] = -1.0e20f;
		pf->f = SF_POLY_NEW;
		pf->nr = a;
		pf++;
	}
	for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
		pflist[eed->poly_nr].edges++;
	}

	for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
		pflist[eve->poly_nr].verts++;
		min_xy_p = pflist[eve->poly_nr].min_xy;
		max_xy_p = pflist[eve->poly_nr].max_xy;

		min_xy_p[0] = (min_xy_p[0]) < (eve->xy[0]) ? (min_xy_p[0]) : (eve->xy[0]);
		min_xy_p[1] = (min_xy_p[1]) < (eve->xy[1]) ? (min_xy_p[1]) : (eve->xy[1]);
		max_xy_p[0] = (max_xy_p[0]) > (eve->xy[0]) ? (max_xy_p[0]) : (eve->xy[0]);
		max_xy_p[1] = (max_xy_p[1]) > (eve->xy[1]) ? (max_xy_p[1]) : (eve->xy[1]);
		if (eve->edge_tot > 2) {
			pflist[eve->poly_nr].f = SF_POLY_VALID;
		}
	}

	/* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM
	 *  ( bounds just to divide it in pieces for optimization, 
	 *    the edgefill itself has good auto-hole detection)
	 * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */
	
	if ((flag & BLI_SCANFILL_CALC_HOLES) && (poly > 1)) {
		unsigned short *polycache, *pc;

		/* so, sort first */
		qsort(pflist, (size_t)poly, sizeof(PolyFill), vergpoly);

#if 0
		pf = pflist;
		for (a = 0; a < poly; a++) {
			printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f);
			PRINT2(f, f, pf->min[0], pf->min[1]);
			pf++;
		}
#endif

		polycache = pc = MEM_callocN(sizeof(*polycache) * (size_t)poly, "polycache");
		pf = pflist;
		for (a = 0; a < poly; a++, pf++) {
			for (c = (unsigned short)(a + 1); c < poly; c++) {
				
				/* if 'a' inside 'c': join (bbox too)
				 * Careful: 'a' can also be inside another poly.
				 */
				if (boundisect(pf, pflist + c)) {
					*pc = c;
					pc++;
				}
				/* only for optimize! */
				/* else if (pf->max_xy[0] < (pflist+c)->min[cox]) break; */
				
			}
			while (pc != polycache) {
				pc--;
				mergepolysSimp(sf_ctx, pf, pflist + *pc);
			}
		}
		MEM_freeN(polycache);
	}

#if 0
	printf("after merge\n");
	pf = pflist;
	for (a = 0; a < poly; a++) {
		printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f);
		pf++;
	}
#endif

	/* STEP 5: MAKE TRIANGLES */

	tempve.first = sf_ctx->fillvertbase.first;
	tempve.last = sf_ctx->fillvertbase.last;
	temped.first = sf_ctx->filledgebase.first;
	temped.last = sf_ctx->filledgebase.last;
	BLI_listbase_clear(&sf_ctx->fillvertbase);
	BLI_listbase_clear(&sf_ctx->filledgebase);

	pf = pflist;
	for (a = 0; a < poly; a++) {
		if (pf->edges > 1) {
			splitlist(sf_ctx, &tempve, &temped, pf->nr);
			totfaces += scanfill(sf_ctx, pf, flag);
		}
		pf++;
	}
	BLI_movelisttolist(&sf_ctx->fillvertbase, &tempve);
	BLI_movelisttolist(&sf_ctx->filledgebase, &temped);

	/* FREE */

	MEM_freeN(pflist);

	return totfaces;
}
예제 #9
0
int BLI_edgefill(int mat_nr)
{
	/*
	  - fill works with its own lists, so create that first (no faces!)
	  - for vertices, put in ->tmp.v the old pointer
	  - struct elements xs en ys are not used here: don't hide stuff in it
	  - edge flag ->f becomes 2 when it's a new edge
	  - mode: & 1 is check for crossings, then create edges (TO DO )
	*/
	ListBase tempve, temped;
	EditVert *eve;
	EditEdge *eed,*nexted;
	PolyFill *pflist,*pf;
	float *minp, *maxp, *v1, *v2, norm[3], len;
	short a,c,poly=0,ok=0,toggle=0;

	/* reset variables */
	eve= fillvertbase.first;
	while(eve) {
		eve->f= 0;
		eve->xs= 0;
		eve->h= 0;
		eve= eve->next;
	}

	/* first test vertices if they are in edges */
	/* including resetting of flags */
	eed= filledgebase.first;
	while(eed) {
		eed->f= eed->f1= eed->h= 0;
		eed->v1->f= 1;
		eed->v2->f= 1;

		eed= eed->next;
	}

	eve= fillvertbase.first;
	while(eve) {
		if(eve->f & 1) {
			ok=1; 
			break;
		}
		eve= eve->next;
	}

	if(ok==0) return 0;

	/* NEW NEW! define projection: with 'best' normal */
	/* just use the first three different vertices */
	
	/* THIS PART STILL IS PRETTY WEAK! (ton) */
	
	eve= fillvertbase.last;
	len= 0.0;
	v1= eve->co;
	v2= 0;
	eve= fillvertbase.first;
	while(eve) {
		if(v2) {
			if( compare_v3v3(v2, eve->co, COMPLIMIT)==0) {
				len= normal_tri_v3( norm,v1, v2, eve->co);
				if(len != 0.0) break;
			}
		}
		else if(compare_v3v3(v1, eve->co, COMPLIMIT)==0) {
			v2= eve->co;
		}
		eve= eve->next;
	}

	if(len==0.0) return 0;	/* no fill possible */

	norm[0]= fabs(norm[0]);
	norm[1]= fabs(norm[1]);
	norm[2]= fabs(norm[2]);
	
	if(norm[2]>=norm[0] && norm[2]>=norm[1]) {
		cox= 0; coy= 1;
	}
	else if(norm[1]>=norm[0] && norm[1]>=norm[2]) {
		cox= 0; coy= 2;
	}
	else {
		cox= 1; coy= 2;
	}

	/* STEP 1: COUNT POLYS */
	eve= fillvertbase.first;
	while(eve) {
		/* get first vertex with no poly number */
		if(eve->xs==0) {
			poly++;
			/* now a sortof select connected */
			ok= 1;
			eve->xs= poly;
			
			while(ok) {
				
				ok= 0;
				toggle++;
				if(toggle & 1) eed= filledgebase.first;
				else eed= filledgebase.last;

				while(eed) {
					if(eed->v1->xs==0 && eed->v2->xs==poly) {
						eed->v1->xs= poly;
						eed->f1= poly;
						ok= 1;
					}
					else if(eed->v2->xs==0 && eed->v1->xs==poly) {
						eed->v2->xs= poly;
						eed->f1= poly;
						ok= 1;
					}
					else if(eed->f1==0) {
						if(eed->v1->xs==poly && eed->v2->xs==poly) {
							eed->f1= poly;
							ok= 1;
						}
					}
					if(toggle & 1) eed= eed->next;
					else eed= eed->prev;
				}
			}
		}
		eve= eve->next;
	}
	/* printf("amount of poly's: %d\n",poly); */

	/* STEP 2: remove loose edges and strings of edges */
	eed= filledgebase.first;
	while(eed) {
		if(eed->v1->h++ >250) break;
		if(eed->v2->h++ >250) break;
		eed= eed->next;
	}
	if(eed) {
		/* otherwise it's impossible to be sure you can clear vertices */
		callLocalErrorCallBack("No vertices with 250 edges allowed!");
		return 0;
	}
	
	/* does it only for vertices with ->h==1 */
	testvertexnearedge();

	ok= 1;
	while(ok) {
		ok= 0;
		toggle++;
		if(toggle & 1) eed= filledgebase.first;
		else eed= filledgebase.last;
		while(eed) {
			if(toggle & 1) nexted= eed->next;
			else nexted= eed->prev;
			if(eed->v1->h==1) {
				eed->v2->h--;
				BLI_remlink(&fillvertbase,eed->v1); 
				BLI_remlink(&filledgebase,eed); 
				ok= 1;
			}
			else if(eed->v2->h==1) {
				eed->v1->h--;
				BLI_remlink(&fillvertbase,eed->v2); 
				BLI_remlink(&filledgebase,eed); 
				ok= 1;
			}
			eed= nexted;
		}
	}
	if(filledgebase.first==0) {
		/* printf("All edges removed\n"); */
		return 0;
	}


	/* CURRENT STATUS:
	- eve->f      :1= availalble in edges
	- eve->xs     :polynumber
	- eve->h      :amount of edges connected to vertex
	- eve->tmp.v  :store! original vertex number

	- eed->f  :
	- eed->f1 :poly number
	*/


	/* STEP 3: MAKE POLYFILL STRUCT */
	pflist= (PolyFill *)MEM_callocN(poly*sizeof(PolyFill),"edgefill");
	pf= pflist;
	for(a=1;a<=poly;a++) {
		pf->nr= a;
		pf->min[0]=pf->min[1]=pf->min[2]= 1.0e20;
		pf->max[0]=pf->max[1]=pf->max[2]= -1.0e20;
		pf++;
	}
	eed= filledgebase.first;
	while(eed) {
		pflist[eed->f1-1].edges++;
		eed= eed->next;
	}

	eve= fillvertbase.first;
	while(eve) {
		pflist[eve->xs-1].verts++;
		minp= pflist[eve->xs-1].min;
		maxp= pflist[eve->xs-1].max;

		minp[cox]= (minp[cox])<(eve->co[cox]) ? (minp[cox]) : (eve->co[cox]);
		minp[coy]= (minp[coy])<(eve->co[coy]) ? (minp[coy]) : (eve->co[coy]);
		maxp[cox]= (maxp[cox])>(eve->co[cox]) ? (maxp[cox]) : (eve->co[cox]);
		maxp[coy]= (maxp[coy])>(eve->co[coy]) ? (maxp[coy]) : (eve->co[coy]);
		if(eve->h>2) pflist[eve->xs-1].f= 1;

		eve= eve->next;
	}

	/* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM
	 *  ( bounds just to divide it in pieces for optimization, 
	 *    the edgefill itself has good auto-hole detection)
	 * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */
	
	if(poly>1) {
		short *polycache, *pc;

		/* so, sort first */
		qsort(pflist, poly, sizeof(PolyFill), vergpoly);
		
		/*pf= pflist;
		for(a=1;a<=poly;a++) {
			printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f);
			PRINT2(f, f, pf->min[0], pf->min[1]);
			pf++;
		}*/
	
		polycache= pc= MEM_callocN(sizeof(short)*poly, "polycache");
		pf= pflist;
		for(a=0; a<poly; a++, pf++) {
			for(c=a+1;c<poly;c++) {
				
				/* if 'a' inside 'c': join (bbox too)
				 * Careful: 'a' can also be inside another poly.
				 */
				if(boundisect(pf, pflist+c)) {
					*pc= c;
					pc++;
				}
				/* only for optimize! */
				/* else if(pf->max[cox] < (pflist+c)->min[cox]) break; */
				
			}
			while(pc!=polycache) {
				pc--;
				mergepolysSimp(pf, pflist+ *pc);
			}
		}
		MEM_freeN(polycache);
	}
	
	/* printf("after merge\n");
	pf= pflist;
	for(a=1;a<=poly;a++) {
		printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f);
		pf++;
	} */

	/* STEP 5: MAKE TRIANGLES */

	tempve.first= fillvertbase.first;
	tempve.last= fillvertbase.last;
	temped.first= filledgebase.first;
	temped.last= filledgebase.last;
	fillvertbase.first=fillvertbase.last= 0;
	filledgebase.first=filledgebase.last= 0;

	pf= pflist;
	for(a=0;a<poly;a++) {
		if(pf->edges>1) {
			splitlist(&tempve,&temped,pf->nr);
			scanfill(pf, mat_nr);
		}
		pf++;
	}
	BLI_movelisttolist(&fillvertbase,&tempve);
	BLI_movelisttolist(&filledgebase,&temped);

	/* FREE */

	MEM_freeN(pflist);
	return 1;

}
예제 #10
0
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask,
                                   const int width, const int height,
                                   const bool do_aspect_correct, const bool do_mask_aa,
                                   const bool do_feather)
{
	const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f};
	const float pixel_size = 1.0f / (float)min_ii(width, height);
	const float asp_xy[2] = {(do_aspect_correct && width > height) ? (float)height / (float)width  : 1.0f,
	                         (do_aspect_correct && width < height) ? (float)width  / (float)height : 1.0f};

	const float zvec[3] = {0.0f, 0.0f, 1.0f};
	MaskLayer *masklay;
	unsigned int masklay_index;
	MemArena *sf_arena;

	mr_handle->layers_tot = (unsigned int)BLI_countlist(&mask->masklayers);
	mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, "MaskRasterLayer");
	BLI_rctf_init_minmax(&mr_handle->bounds);

	sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);

	for (masklay = mask->masklayers.first, masklay_index = 0; masklay; masklay = masklay->next, masklay_index++) {

		/* we need to store vertex ranges for open splines for filling */
		unsigned int tot_splines;
		MaskRasterSplineInfo *open_spline_ranges;
		unsigned int   open_spline_index = 0;

		MaskSpline *spline;

		/* scanfill */
		ScanFillContext sf_ctx;
		ScanFillVert *sf_vert = NULL;
		ScanFillVert *sf_vert_next = NULL;
		ScanFillFace *sf_tri;

		unsigned int sf_vert_tot = 0;
		unsigned int tot_feather_quads = 0;

#ifdef USE_SCANFILL_EDGE_WORKAROUND
		unsigned int tot_boundary_used = 0;
		unsigned int tot_boundary_found = 0;
#endif

		if (masklay->restrictflag & MASK_RESTRICT_RENDER) {
			/* skip the layer */
			mr_handle->layers_tot--;
			masklay_index--;
			continue;
		}

		tot_splines = (unsigned int)BLI_countlist(&masklay->splines);
		open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__);

		BLI_scanfill_begin_arena(&sf_ctx, sf_arena);

		for (spline = masklay->splines.first; spline; spline = spline->next) {
			const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
			const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;

			float (*diff_points)[2];
			unsigned int tot_diff_point;

			float (*diff_feather_points)[2];
			float (*diff_feather_points_flip)[2];
			unsigned int tot_diff_feather_points;

			const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4;
			const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4;
			const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512);

			diff_points = BKE_mask_spline_differentiate_with_resolution(
			                  spline, &tot_diff_point, resol);

			if (do_feather) {
				diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
				                          spline, &tot_diff_feather_points, resol, FALSE);
				BLI_assert(diff_feather_points);
			}
			else {
				tot_diff_feather_points = 0;
				diff_feather_points = NULL;
			}

			if (tot_diff_point > 3) {
				ScanFillVert *sf_vert_prev;
				unsigned int j;

				float co[3];
				co[2] = 0.0f;

				sf_ctx.poly_nr++;

				if (do_aspect_correct) {
					if (width != height) {
						float *fp;
						float *ffp;
						unsigned int i;
						float asp;

						if (width < height) {
							fp = &diff_points[0][0];
							ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL;
							asp = (float)width / (float)height;
						}
						else {
							fp = &diff_points[0][1];
							ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL;
							asp = (float)height / (float)width;
						}

						for (i = 0; i < tot_diff_point; i++, fp += 2) {
							(*fp) = (((*fp) - 0.5f) / asp) + 0.5f;
						}

						if (tot_diff_feather_points) {
							for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) {
								(*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f;
							}
						}
					}
				}

				/* fake aa, using small feather */
				if (do_mask_aa == TRUE) {
					if (do_feather == FALSE) {
						tot_diff_feather_points = tot_diff_point;
						diff_feather_points = MEM_mallocN(sizeof(*diff_feather_points) *
						                                  (size_t)tot_diff_feather_points,
						                                  __func__);
						/* add single pixel feather */
						maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
						                                               tot_diff_point, pixel_size, FALSE);
					}
					else {
						/* ensure single pixel feather, on any zero feather areas */
						maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
						                                               tot_diff_point, pixel_size, TRUE);
					}
				}

				if (is_fill) {
					/* applt intersections depending on fill settings */
					if (spline->flag & MASK_SPLINE_NOINTERSECT) {
						BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points);
					}

					copy_v2_v2(co, diff_points[0]);
					sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co);
					sf_vert_prev->tmp.u = sf_vert_tot;
					sf_vert_prev->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
					sf_vert_tot++;

					/* TODO, an alternate functions so we can avoid double vector copy! */
					for (j = 1; j < tot_diff_point; j++) {
						copy_v2_v2(co, diff_points[j]);
						sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
						sf_vert->tmp.u = sf_vert_tot;
						sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
						sf_vert_tot++;
					}

					sf_vert = sf_vert_prev;
					sf_vert_prev = sf_ctx.fillvertbase.last;

					for (j = 0; j < tot_diff_point; j++) {
						ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert);

#ifdef USE_SCANFILL_EDGE_WORKAROUND
						if (diff_feather_points) {
							sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY;
							tot_boundary_used++;
						}
#else
						(void)sf_edge;
#endif
						sf_vert_prev = sf_vert;
						sf_vert = sf_vert->next;
					}

					if (diff_feather_points) {
						float co_feather[3];
						co_feather[2] = 1.0f;

						BLI_assert(tot_diff_feather_points == tot_diff_point);

						/* note: only added for convenience, we don't infact use these to scanfill,
						 * only to create feather faces after scanfill */
						for (j = 0; j < tot_diff_feather_points; j++) {
							copy_v2_v2(co_feather, diff_feather_points[j]);
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);

							/* no need for these attrs */
#if 0
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
#endif
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;
						}

						tot_feather_quads += tot_diff_point;
					}
				}
				else {
					/* unfilled spline */
					if (diff_feather_points) {

						float co_diff[2];

						float co_feather[3];
						co_feather[2] = 1.0f;

						if (spline->flag & MASK_SPLINE_NOINTERSECT) {
							diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points, "diff_feather_points_flip");

							for (j = 0; j < tot_diff_point; j++) {
								sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
								add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff);
							}

							BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points,      tot_diff_feather_points);
							BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points_flip, tot_diff_feather_points);
						}
						else {
							diff_feather_points_flip = NULL;
						}


						open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot;
						open_spline_ranges[open_spline_index].vertex_total = tot_diff_point;

						/* TODO, an alternate functions so we can avoid double vector copy! */
						for (j = 0; j < tot_diff_point; j++) {

							/* center vert */
							copy_v2_v2(co, diff_points[j]);
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;


							/* feather vert A */
							copy_v2_v2(co_feather, diff_feather_points[j]);
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;


							/* feather vert B */
							if (diff_feather_points_flip) {
								copy_v2_v2(co_feather, diff_feather_points_flip[j]);
							}
							else {
								sub_v2_v2v2(co_diff, co, co_feather);
								add_v2_v2v2(co_feather, co, co_diff);
							}

							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
							sf_vert->tmp.u = sf_vert_tot;
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
							sf_vert_tot++;

							tot_feather_quads += 2;
						}

						if (!is_cyclic) {
							tot_feather_quads -= 2;
						}

						if (diff_feather_points_flip) {
							MEM_freeN(diff_feather_points_flip);
							diff_feather_points_flip = NULL;
						}

						/* cap ends */

						/* dummy init value */
						open_spline_ranges[open_spline_index].vertex_total_cap_head = 0;
						open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0;

						if (!is_cyclic) {
							float *fp_cent;
							float *fp_turn;

							unsigned int k;

							fp_cent = diff_points[0];
							fp_turn = diff_feather_points[0];

#define CALC_CAP_RESOL                                                                      \
	clampis_uint((unsigned int )(len_v2v2(fp_cent, fp_turn) /                               \
	                             (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)),                \
	             SPLINE_RESOL_CAP_MIN, SPLINE_RESOL_CAP_MAX)

							{
								const unsigned int vertex_total_cap = CALC_CAP_RESOL;

								for (k = 1; k < vertex_total_cap; k++) {
									const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
									rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy);

									sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
									sf_vert->tmp.u = sf_vert_tot;
									sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
									sf_vert_tot++;
								}
								tot_feather_quads += vertex_total_cap;

								open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap;
							}

							fp_cent = diff_points[tot_diff_point - 1];
							fp_turn = diff_feather_points[tot_diff_point - 1];

							{
								const unsigned int vertex_total_cap = CALC_CAP_RESOL;

								for (k = 1; k < vertex_total_cap; k++) {
									const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
									rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy);

									sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
									sf_vert->tmp.u = sf_vert_tot;
									sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
									sf_vert_tot++;
								}
								tot_feather_quads += vertex_total_cap;

								open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap;
							}
						}

						open_spline_ranges[open_spline_index].is_cyclic = is_cyclic;
						open_spline_index++;

#undef CALC_CAP_RESOL
						/* end capping */

					}
				}
			}

			if (diff_points) {
				MEM_freeN(diff_points);
			}

			if (diff_feather_points) {
				MEM_freeN(diff_feather_points);
			}
		}

		{
			unsigned int (*face_array)[4], *face;  /* access coords */
			float        (*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */
			unsigned int sf_tri_tot;
			rctf bounds;
			unsigned int face_index;
			int scanfill_flag = 0;

			bool is_isect = false;
			ListBase isect_remvertbase = {NULL, NULL};
			ListBase isect_remedgebase = {NULL, NULL};

			/* now we have all the splines */
			face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords");

			/* init bounds */
			BLI_rctf_init_minmax(&bounds);

			/* coords */
			cos = (float *)face_coords;
			for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) {
				sf_vert_next = sf_vert->next;
				copy_v3_v3(cos, sf_vert->co);

				/* remove so as not to interfere with fill (called after) */
				if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) {
					BLI_remlink(&sf_ctx.fillvertbase, sf_vert);
				}

				/* bounds */
				BLI_rctf_do_minmax_v(&bounds, cos);

				cos += 3;
			}


			/* --- inefficient self-intersect case --- */
			/* if self intersections are found, its too trickty to attempt to map vertices
			 * so just realloc and add entirely new vertices - the result of the self-intersect check
			 */
			if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) &&
			    (is_isect = BLI_scanfill_calc_self_isect(&sf_ctx,
			                                             &isect_remvertbase,
			                                             &isect_remedgebase)))
			{
				unsigned int sf_vert_tot_isect = (unsigned int)BLI_countlist(&sf_ctx.fillvertbase);
				unsigned int i = sf_vert_tot;

				face_coords = MEM_reallocN(face_coords, sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect));

				cos = (float *)&face_coords[sf_vert_tot][0];

				for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) {
					copy_v3_v3(cos, sf_vert->co);
					sf_vert->tmp.u = i++;
					cos += 3;
				}

				sf_vert_tot += sf_vert_tot_isect;

				/* we need to calc polys after self intersect */
				scanfill_flag |= BLI_SCANFILL_CALC_POLYS;
			}
			/* --- end inefficient code --- */


			/* main scan-fill */
			if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0)
				scanfill_flag |= BLI_SCANFILL_CALC_HOLES;

			sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec);

			if (is_isect) {
				/* add removed data back, we only need edges for feather,
				 * but add verts back so they get freed along with others */
				BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase);
				BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase);
			}

			face_array = MEM_mallocN(sizeof(*face_array) * ((size_t)sf_tri_tot + (size_t)tot_feather_quads), "maskrast_face_index");
			face_index = 0;

			/* faces */
			face = (unsigned int *)face_array;
			for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
				*(face++) = sf_tri->v3->tmp.u;
				*(face++) = sf_tri->v2->tmp.u;
				*(face++) = sf_tri->v1->tmp.u;
				*(face++) = TRI_VERT;
				face_index++;
				FACE_ASSERT(face - 4, sf_vert_tot);
			}

			/* start of feather faces... if we have this set,
			 * 'face_index' is kept from loop above */

			BLI_assert(face_index == sf_tri_tot);

			if (tot_feather_quads) {
				ScanFillEdge *sf_edge;

				for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) {
					if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) {
						*(face++) = sf_edge->v1->tmp.u;
						*(face++) = sf_edge->v2->tmp.u;
						*(face++) = sf_edge->v2->keyindex;
						*(face++) = sf_edge->v1->keyindex;
						face_index++;
						FACE_ASSERT(face - 4, sf_vert_tot);

#ifdef USE_SCANFILL_EDGE_WORKAROUND
						tot_boundary_found++;
#endif
					}
				}
			}

#ifdef USE_SCANFILL_EDGE_WORKAROUND
			if (tot_boundary_found != tot_boundary_used) {
				BLI_assert(tot_boundary_found < tot_boundary_used);
			}
#endif

			/* feather only splines */
			while (open_spline_index > 0) {
				const unsigned int vertex_offset         = open_spline_ranges[--open_spline_index].vertex_offset;
				unsigned int       vertex_total          = open_spline_ranges[  open_spline_index].vertex_total;
				unsigned int       vertex_total_cap_head = open_spline_ranges[  open_spline_index].vertex_total_cap_head;
				unsigned int       vertex_total_cap_tail = open_spline_ranges[  open_spline_index].vertex_total_cap_tail;
				unsigned int k, j;

				j = vertex_offset;

				/* subtract one since we reference next vertex triple */
				for (k = 0; k < vertex_total - 1; k++, j += 3) {

					BLI_assert(j == vertex_offset + (k * 3));

					*(face++) = j + 3; /* next span */ /* z 1 */
					*(face++) = j + 0;                 /* z 1 */
					*(face++) = j + 1;                 /* z 0 */
					*(face++) = j + 4; /* next span */ /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = j + 0;                 /* z 1 */
					*(face++) = j + 3; /* next span */ /* z 1 */
					*(face++) = j + 5; /* next span */ /* z 0 */
					*(face++) = j + 2;                 /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);
				}

				if (open_spline_ranges[open_spline_index].is_cyclic) {
					*(face++) = vertex_offset + 0; /* next span */ /* z 1 */
					*(face++) = j             + 0;                 /* z 1 */
					*(face++) = j             + 1;                 /* z 0 */
					*(face++) = vertex_offset + 1; /* next span */ /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = j          + 0;                    /* z 1 */
					*(face++) = vertex_offset + 0; /* next span */ /* z 1 */
					*(face++) = vertex_offset + 2; /* next span */ /* z 0 */
					*(face++) = j          + 2;                    /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);
				}
				else {
					unsigned int midvidx = vertex_offset;

					/***************
					 * cap end 'a' */
					j = midvidx + (vertex_total * 3);

					for (k = 0; k < vertex_total_cap_head - 2; k++, j++) {
						*(face++) = midvidx + 0;  /* z 1 */
						*(face++) = midvidx + 0;  /* z 1 */
						*(face++) = j + 0;        /* z 0 */
						*(face++) = j + 1;        /* z 0 */
						face_index++;
						FACE_ASSERT(face - 4, sf_vert_tot);
					}

					j = vertex_offset + (vertex_total * 3);

					/* 2 tris that join the original */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = midvidx + 1;  /* z 0 */
					*(face++) = j + 0;        /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = j + vertex_total_cap_head - 2;  /* z 0 */
					*(face++) = midvidx + 2;                    /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);


					/***************
					 * cap end 'b' */
					/* ... same as previous but v 2-3 flipped, and different initial offsets */

					j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);

					midvidx = vertex_offset + (vertex_total * 3) - 3;

					for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) {
						*(face++) = midvidx;  /* z 1 */
						*(face++) = midvidx;  /* z 1 */
						*(face++) = j + 1;    /* z 0 */
						*(face++) = j + 0;    /* z 0 */
						face_index++;
						FACE_ASSERT(face - 4, sf_vert_tot);
					}

					j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);

					/* 2 tris that join the original */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = midvidx + 0;  /* z 1 */
					*(face++) = j + 0;        /* z 0 */
					*(face++) = midvidx + 1;  /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = midvidx + 0;                    /* z 1 */
					*(face++) = midvidx + 2;                    /* z 0 */
					*(face++) = j + vertex_total_cap_tail - 2;  /* z 0 */
					face_index++;
					FACE_ASSERT(face - 4, sf_vert_tot);

				}
			}

			MEM_freeN(open_spline_ranges);

//			fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found);

#ifdef USE_SCANFILL_EDGE_WORKAROUND
			BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) == sf_tri_tot + tot_feather_quads);
#else
			BLI_assert(face_index == sf_tri_tot + tot_feather_quads);
#endif
			{
				MaskRasterLayer *layer = &mr_handle->layers[masklay_index];

				if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) {
#ifdef USE_SCANFILL_EDGE_WORKAROUND
					layer->face_tot = (sf_tri_tot + tot_feather_quads) - (tot_boundary_used - tot_boundary_found);
#else
					layer->face_tot = (sf_tri_tot + tot_feather_quads);
#endif
					layer->face_coords = face_coords;
					layer->face_array  = face_array;
					layer->bounds = bounds;

					layer_bucket_init(layer, pixel_size);

					BLI_rctf_union(&mr_handle->bounds, &bounds);
				}
				else {
					MEM_freeN(face_coords);
					MEM_freeN(face_array);

					layer_bucket_init_dummy(layer);
				}

				/* copy as-is */
				layer->alpha = masklay->alpha;
				layer->blend = masklay->blend;
				layer->blend_flag = masklay->blend_flag;
				layer->falloff = masklay->falloff;
			}

			/* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */
		}

		/* add trianges */
		BLI_scanfill_end_arena(&sf_ctx, sf_arena);
	}

	BLI_memarena_free(sf_arena);
}
예제 #11
0
int BLI_edgefill_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedup, const float nor_proj[3])
{
	/*
	 * - fill works with its own lists, so create that first (no faces!)
	 * - for vertices, put in ->tmp.v the old pointer
	 * - struct elements xs en ys are not used here: don't hide stuff in it
	 * - edge flag ->f becomes 2 when it's a new edge
	 * - mode: & 1 is check for crossings, then create edges (TO DO )
	 * - returns number of triangle faces added.
	 */
	ListBase tempve, temped;
	ScanFillVert *eve;
	ScanFillEdge *eed, *nexted;
	PolyFill *pflist, *pf;
	float *min_xy_p, *max_xy_p;
	short a, c, poly = 0, ok = 0, toggle = 0;
	int totfaces = 0; /* total faces added */
	int co_x, co_y;

	/* reset variables */
	eve = sf_ctx->fillvertbase.first;
	a = 0;
	while (eve) {
		eve->f = 0;
		eve->poly_nr = 0;
		eve->h = 0;
		eve = eve->next;
		a += 1;
	}

	if (do_quad_tri_speedup && (a == 3)) {
		eve = sf_ctx->fillvertbase.first;

		addfillface(sf_ctx, eve, eve->next, eve->next->next);
		return 1;
	}
	else if (do_quad_tri_speedup && (a == 4)) {
		float vec1[3], vec2[3];

		eve = sf_ctx->fillvertbase.first;
		/* no need to check 'eve->next->next->next' is valid, already counted */
		/* use shortest diagonal for quad */
		sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
		sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);

		if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) {
			addfillface(sf_ctx, eve, eve->next, eve->next->next);
			addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve);
		}
		else {
			addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next);
			addfillface(sf_ctx, eve->next->next->next, eve, eve->next);
		}
		return 2;
	}

	/* first test vertices if they are in edges */
	/* including resetting of flags */
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		eed->poly_nr = 0;
		eed->v1->f = SF_VERT_UNKNOWN;
		eed->v2->f = SF_VERT_UNKNOWN;

		eed = eed->next;
	}

	eve = sf_ctx->fillvertbase.first;
	while (eve) {
		if (eve->f & SF_VERT_UNKNOWN) {
			ok = 1;
			break;
		}
		eve = eve->next;
	}

	if (ok == 0) {
		return 0;
	}
	else {
		float n[3];

		if (nor_proj) {
			copy_v3_v3(n, nor_proj);
		}
		else {
			/* define projection: with 'best' normal */
			/* Newell's Method */
			/* Similar code used elsewhere, but this checks for double ups
			 * which historically this function supports so better not change */
			float *v_prev;

			zero_v3(n);
			eve = sf_ctx->fillvertbase.last;
			v_prev = eve->co;

			for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
				if (LIKELY(!compare_v3v3(v_prev, eve->co, SF_EPSILON))) {
					add_newell_cross_v3_v3v3(n, v_prev, eve->co);
					v_prev = eve->co;
				}
			}
		}

		if (UNLIKELY(normalize_v3(n) == 0.0f)) {
			return 0;
		}

		axis_dominant_v3(&co_x, &co_y, n);
	}


	/* STEP 1: COUNT POLYS */
	eve = sf_ctx->fillvertbase.first;
	while (eve) {
		eve->xy[0] = eve->co[co_x];
		eve->xy[1] = eve->co[co_y];

		/* get first vertex with no poly number */
		if (eve->poly_nr == 0) {
			poly++;
			/* now a sort of select connected */
			ok = 1;
			eve->poly_nr = poly;
			
			while (ok) {
				
				ok = 0;
				toggle++;
				if (toggle & 1) eed = sf_ctx->filledgebase.first;
				else eed = sf_ctx->filledgebase.last;

				while (eed) {
					if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) {
						eed->v1->poly_nr = poly;
						eed->poly_nr = poly;
						ok = 1;
					}
					else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) {
						eed->v2->poly_nr = poly;
						eed->poly_nr = poly;
						ok = 1;
					}
					else if (eed->poly_nr == 0) {
						if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) {
							eed->poly_nr = poly;
							ok = 1;
						}
					}
					if (toggle & 1) eed = eed->next;
					else eed = eed->prev;
				}
			}
		}
		eve = eve->next;
	}
	/* printf("amount of poly's: %d\n",poly); */

	/* STEP 2: remove loose edges and strings of edges */
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		if (eed->v1->h++ > 250) break;
		if (eed->v2->h++ > 250) break;
		eed = eed->next;
	}
	if (eed) {
		/* otherwise it's impossible to be sure you can clear vertices */
		callLocalErrorCallBack("No vertices with 250 edges allowed!");
		return 0;
	}
	
	/* does it only for vertices with ->h==1 */
	testvertexnearedge(sf_ctx);

	ok = 1;
	while (ok) {
		ok = 0;
		toggle++;
		if (toggle & 1) eed = sf_ctx->filledgebase.first;
		else eed = sf_ctx->filledgebase.last;
		while (eed) {
			if (toggle & 1) nexted = eed->next;
			else nexted = eed->prev;
			if (eed->v1->h == 1) {
				eed->v2->h--;
				BLI_remlink(&sf_ctx->fillvertbase, eed->v1);
				BLI_remlink(&sf_ctx->filledgebase, eed);
				ok = 1;
			}
			else if (eed->v2->h == 1) {
				eed->v1->h--;
				BLI_remlink(&sf_ctx->fillvertbase, eed->v2);
				BLI_remlink(&sf_ctx->filledgebase, eed);
				ok = 1;
			}
			eed = nexted;
		}
	}
	if (sf_ctx->filledgebase.first == 0) {
		/* printf("All edges removed\n"); */
		return 0;
	}


	/* CURRENT STATUS:
	 * - eve->f       :1= availalble in edges
	 * - eve->xs      :polynumber
	 * - eve->h       :amount of edges connected to vertex
	 * - eve->tmp.v   :store! original vertex number
	 * 
	 * - eed->f       :1= boundary edge (optionally set by caller)
	 * - eed->poly_nr :poly number
	 */


	/* STEP 3: MAKE POLYFILL STRUCT */
	pflist = (PolyFill *)MEM_callocN(poly * sizeof(PolyFill), "edgefill");
	pf = pflist;
	for (a = 1; a <= poly; a++) {
		pf->nr = a;
		pf->min_xy[0] = pf->min_xy[1] =  1.0e20;
		pf->max_xy[0] = pf->max_xy[1] = -1.0e20;
		pf++;
	}
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		pflist[eed->poly_nr - 1].edges++;
		eed = eed->next;
	}

	eve = sf_ctx->fillvertbase.first;
	while (eve) {
		pflist[eve->poly_nr - 1].verts++;
		min_xy_p = pflist[eve->poly_nr - 1].min_xy;
		max_xy_p = pflist[eve->poly_nr - 1].max_xy;

		min_xy_p[0] = (min_xy_p[0]) < (eve->xy[0]) ? (min_xy_p[0]) : (eve->xy[0]);
		min_xy_p[1] = (min_xy_p[1]) < (eve->xy[1]) ? (min_xy_p[1]) : (eve->xy[1]);
		max_xy_p[0] = (max_xy_p[0]) > (eve->xy[0]) ? (max_xy_p[0]) : (eve->xy[0]);
		max_xy_p[1] = (max_xy_p[1]) > (eve->xy[1]) ? (max_xy_p[1]) : (eve->xy[1]);
		if (eve->h > 2) pflist[eve->poly_nr - 1].f = 1;

		eve = eve->next;
	}

	/* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM
	 *  ( bounds just to divide it in pieces for optimization, 
	 *    the edgefill itself has good auto-hole detection)
	 * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */
	
	if (poly > 1) {
		short *polycache, *pc;

		/* so, sort first */
		qsort(pflist, poly, sizeof(PolyFill), vergpoly);

#if 0
		pf = pflist;
		for (a = 1; a <= poly; a++) {
			printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f);
			PRINT2(f, f, pf->min[0], pf->min[1]);
			pf++;
		}
#endif
	
		polycache = pc = MEM_callocN(sizeof(short) * poly, "polycache");
		pf = pflist;
		for (a = 0; a < poly; a++, pf++) {
			for (c = a + 1; c < poly; c++) {
				
				/* if 'a' inside 'c': join (bbox too)
				 * Careful: 'a' can also be inside another poly.
				 */
				if (boundisect(pf, pflist + c)) {
					*pc = c;
					pc++;
				}
				/* only for optimize! */
				/* else if (pf->max_xy[0] < (pflist+c)->min[cox]) break; */
				
			}
			while (pc != polycache) {
				pc--;
				mergepolysSimp(sf_ctx, pf, pflist + *pc);
			}
		}
		MEM_freeN(polycache);
	}

#if 0
	printf("after merge\n");
	pf = pflist;
	for (a = 1; a <= poly; a++) {
		printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f);
		pf++;
	}
#endif

	/* STEP 5: MAKE TRIANGLES */

	tempve.first = sf_ctx->fillvertbase.first;
	tempve.last = sf_ctx->fillvertbase.last;
	temped.first = sf_ctx->filledgebase.first;
	temped.last = sf_ctx->filledgebase.last;
	sf_ctx->fillvertbase.first = sf_ctx->fillvertbase.last = NULL;
	sf_ctx->filledgebase.first = sf_ctx->filledgebase.last = NULL;

	pf = pflist;
	for (a = 0; a < poly; a++) {
		if (pf->edges > 1) {
			splitlist(sf_ctx, &tempve, &temped, pf->nr);
			totfaces += scanfill(sf_ctx, pf);
		}
		pf++;
	}
	BLI_movelisttolist(&sf_ctx->fillvertbase, &tempve);
	BLI_movelisttolist(&sf_ctx->filledgebase, &temped);

	/* FREE */

	MEM_freeN(pflist);

	return totfaces;
}
예제 #12
0
static int gp_duplicate_exec(bContext *C, wmOperator *op)
{
	bGPdata *gpd = ED_gpencil_data_get_active(C);
	
	if (gpd == NULL) {
		BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
		return OPERATOR_CANCELLED;
	}
	
	/* for each visible (and editable) layer's selected strokes,
	 * copy the strokes into a temporary buffer, then append
	 * once all done
	 */
	CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
	{
		ListBase new_strokes = {NULL, NULL};
		bGPDframe *gpf = gpl->actframe;
		bGPDstroke *gps;
		
		if (gpf == NULL)
			continue;
		
		/* make copies of selected strokes, and deselect these once we're done */
		for (gps = gpf->strokes.first; gps; gps = gps->next) {
			/* skip strokes that are invalid for current view */
			if (ED_gpencil_stroke_can_use(C, gps) == false)
				continue;
			
			if (gps->flag & GP_STROKE_SELECT) {
				if (gps->totpoints == 1) {
					/* Special Case: If there's just a single point in this stroke... */
					bGPDstroke *gpsd;
					
					/* make direct copies of the stroke and its points */
					gpsd = MEM_dupallocN(gps);
					gpsd->points = MEM_dupallocN(gps->points);
					
					/* triangle information - will be calculated on next redraw */
					gpsd->flag |= GP_STROKE_RECALC_CACHES;
					gpsd->triangles = NULL;
					
					/* add to temp buffer */
					gpsd->next = gpsd->prev = NULL;
					BLI_addtail(&new_strokes, gpsd);
				}
				else {
					/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
					gp_duplicate_points(gps, &new_strokes);
				}
				
				/* deselect original stroke, or else the originals get moved too
				 * (when using the copy + move macro)
				 */
				gps->flag &= ~GP_STROKE_SELECT;
			}
		}
		
		/* add all new strokes in temp buffer to the frame (preventing double-copies) */
		BLI_movelisttolist(&gpf->strokes, &new_strokes);
		BLI_assert(new_strokes.first == NULL);
	}