示例#1
0
/**
 * \return if succeeded.
 */
bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm)
{
  if (BLI_listbase_is_single(&bmain->workspaces)) {
    return false;
  }

  ListBase ordered;
  BKE_id_ordered_list(&ordered, &bmain->workspaces);
  WorkSpace *prev = NULL, *next = NULL;
  for (LinkData *link = ordered.first; link; link = link->next) {
    if (link->data == workspace) {
      prev = link->prev ? link->prev->data : NULL;
      next = link->next ? link->next->data : NULL;
      break;
    }
  }
  BLI_freelistN(&ordered);
  BLI_assert((prev != NULL) || (next != NULL));

  for (wmWindow *win = wm->windows.first; win; win = win->next) {
    WorkSpace *workspace_active = WM_window_get_active_workspace(win);
    if (workspace_active == workspace) {
      ED_workspace_change((prev != NULL) ? prev : next, C, wm, win);
    }
  }

  BKE_id_free(bmain, &workspace->id);
  return true;
}
示例#2
0
static int bake_exec(bContext *C, wmOperator *op)
{
	Render *re;
	int result = OPERATOR_CANCELLED;
	BakeAPIRender bkr = {NULL};

	bake_init_api_data(op, C, &bkr);
	re = bkr.render;

	/* setup new render */
	RE_test_break_cb(re, NULL, bake_break);

	if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
		goto finally;
	}

	if (bkr.is_clear) {
		const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && (bkr.normal_space == R_BAKE_SPACE_TANGENT));
		bake_images_clear(bkr.main, is_tangent);
	}

	RE_SetReports(re, bkr.reports);

	if (bkr.is_selected_to_active) {
		result = bake(
		        bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports,
		        bkr.pass_type, bkr.margin, bkr.save_mode,
		        bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage,
		        bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
		        bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
		        bkr.uv_layer);
	}
	else {
		CollectionPointerLink *link;
		const bool is_clear = bkr.is_clear && BLI_listbase_is_single(&bkr.selected_objects);
		for (link = bkr.selected_objects.first; link; link = link->next) {
			Object *ob_iter = link->ptr.data;
			result = bake(
			        bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports,
			        bkr.pass_type, bkr.margin, bkr.save_mode,
			        is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage,
			        bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
			        bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
			        bkr.uv_layer);
		}
	}

	RE_SetReports(re, NULL);


finally:
	BLI_freelistN(&bkr.selected_objects);
	return result;
}
示例#3
0
static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, float *progress)
{
	BakeAPIRender *bkr = (BakeAPIRender *)bkv;

	/* setup new render */
	bkr->do_update = do_update;
	bkr->progress = progress;

	RE_SetReports(bkr->render, bkr->reports);

	if (!bake_pass_filter_check(bkr->pass_type, bkr->pass_filter, bkr->reports)) {
		bkr->result = OPERATOR_CANCELLED;
		return;
	}

	if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
		bkr->result = OPERATOR_CANCELLED;
		return;
	}

	if (bkr->is_clear) {
		const bool is_tangent = ((bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT));
		bake_images_clear(bkr->main, is_tangent);
	}

	if (bkr->is_selected_to_active) {
		bkr->result = bake(
		        bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports,
		        bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
		        bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage,
		        bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
		        bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
		        bkr->uv_layer);
	}
	else {
		CollectionPointerLink *link;
		const bool is_clear = bkr->is_clear && BLI_listbase_is_single(&bkr->selected_objects);
		for (link = bkr->selected_objects.first; link; link = link->next) {
			Object *ob_iter = link->ptr.data;
			bkr->result = bake(
			        bkr->render, bkr->main, bkr->scene, ob_iter, NULL, bkr->reports,
			        bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
			        is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage,
			        bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
			        bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
			        bkr->uv_layer);

			if (bkr->result == OPERATOR_CANCELLED)
				return;
		}
	}

	RE_SetReports(bkr->render, NULL);
}
示例#4
0
/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
{
  const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
  FModifier *fcm;

  /* sanity checks */
  if (ELEM(NULL, modifiers, fmi)) {
    return NULL;
  }

  /* special checks for whether modifier can be added */
  if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
    /* cycles modifier must be first in stack, so for now, don't add if it can't be */
    /* TODO: perhaps there is some better way, but for now, */
    CLOG_STR_ERROR(&LOG,
                   "Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be "
                   "first in stack.");
    return NULL;
  }

  /* add modifier itself */
  fcm = MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
  fcm->type = type;
  fcm->flag = FMODIFIER_FLAG_EXPANDED;
  fcm->curve = owner_fcu;
  fcm->influence = 1.0f;
  BLI_addtail(modifiers, fcm);

  /* tag modifier as "active" if no other modifiers exist in the stack yet */
  if (BLI_listbase_is_single(modifiers)) {
    fcm->flag |= FMODIFIER_FLAG_ACTIVE;
  }

  /* add modifier's data */
  fcm->data = MEM_callocN(fmi->size, fmi->structName);

  /* init custom settings if necessary */
  if (fmi->new_data) {
    fmi->new_data(fcm->data);
  }

  /* update the fcurve if the Cycles modifier is added */
  if ((owner_fcu) && (type == FMODIFIER_TYPE_CYCLES)) {
    calchandles_fcurve(owner_fcu);
  }

  /* return modifier for further editing */
  return fcm;
}
示例#5
0
/* helper for find_nearest_fcurve_vert() - get the best match to use */
static tNearestVertInfo *get_best_nearest_fcurve_vert(ListBase *matches)
{
	tNearestVertInfo *nvi = NULL;
	short found = 0;
	
	/* abort if list is empty */
	if (BLI_listbase_is_empty(matches))
		return NULL;
		
	/* if list only has 1 item, remove it from the list and return */
	if (BLI_listbase_is_single(matches)) {
		/* need to remove from the list, otherwise it gets freed and then we can't return it */
		return BLI_pophead(matches);
	}
	
	/* try to find the first selected F-Curve vert, then take the one after it */
	for (nvi = matches->first; nvi; nvi = nvi->next) {
		/* which mode of search are we in: find first selected, or find vert? */
		if (found) {
			/* just take this vert now that we've found the selected one 
			 *	- we'll need to remove this from the list so that it can be returned to the original caller
			 */
			BLI_remlink(matches, nvi);
			return nvi;
		}
		else {
			/* if vert is selected, we've got what we want... */
			if (nvi->sel)
				found = 1;
		}
	}
	
	/* if we're still here, this means that we failed to find anything appropriate in the first pass,
	 * so just take the first item now...
	 */
	return BLI_pophead(matches);
}
示例#6
0
/**
 * This function pastes data from the keyframes copy/paste buffer
 *
 * \return Status code is whether the method FAILED to do anything
 */
short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
                          const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
{
	bAnimListElem *ale;
	
	const Scene *scene = (ac->scene);
	
	const bool from_single = BLI_listbase_is_single(&animcopybuf);
	const bool to_simple = BLI_listbase_is_single(anim_data);
	
	float offset = 0.0f;
	int pass;

	/* check if buffer is empty */
	if (BLI_listbase_is_empty(&animcopybuf)) {
		BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
		return -1;
	}

	if (BLI_listbase_is_empty(anim_data)) {
		BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
		return -1;
	}
	
	/* methods of offset */
	switch (offset_mode) {
		case KEYFRAME_PASTE_OFFSET_CFRA_START:
			offset = (float)(CFRA - animcopy_firstframe);
			break;
		case KEYFRAME_PASTE_OFFSET_CFRA_END:
			offset = (float)(CFRA - animcopy_lastframe);
			break;
		case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
			offset = (float)(CFRA - animcopy_cfra);
			break;
		case KEYFRAME_PASTE_OFFSET_NONE:
			offset = 0.0f;
			break;
	}

	if (from_single && to_simple) {
		/* 1:1 match, no tricky checking, just paste */
		FCurve *fcu;
		tAnimCopybufItem *aci;
		
		ale = anim_data->first;
		fcu = (FCurve *)ale->data;  /* destination F-Curve */
		aci = animcopybuf.first;
		
		paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
		ale->update |= ANIM_UPDATE_DEFAULT;
	}
	else {
		/* from selected channels 
		 *  This "passes" system aims to try to find "matching" channels to paste keyframes
		 *  into with increasingly loose matching heuristics. The process finishes when at least
		 *  one F-Curve has been pasted into.
		 */
		for (pass = 0; pass < 3; pass++) {
			unsigned int totmatch = 0;
			
			for (ale = anim_data->first; ale; ale = ale->next) {
				/* find buffer item to paste from 
				 *	- if names don't matter (i.e. only 1 channel in buffer), don't check id/group
				 *	- if names do matter, only check if id-type is ok for now (group check is not that important)
				 *	- most importantly, rna-paths should match (array indices are unimportant for now)
				 */
				AnimData *adt = ANIM_nla_mapping_get(ac, ale);
				FCurve *fcu = (FCurve *)ale->data;  /* destination F-Curve */
				tAnimCopybufItem *aci = NULL;
				
				switch (pass) {
					case 0:
						/* most strict, must be exact path match data_path & index */
						aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip);
						break;
					
					case 1:
						/* less strict, just compare property names */
						aci = pastebuf_match_path_property(fcu, from_single, to_simple);
						break;
					
					case 2:
						/* Comparing properties gave no results, so just do index comparisons */
						aci = pastebuf_match_index_only(fcu, from_single, to_simple);
						break;
				}
				
				/* copy the relevant data from the matching buffer curve */
				if (aci) {
					totmatch++;
					
					if (adt) {
						ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
						paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
						ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
					}
					else {
						paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
					}
				}
				
				ale->update |= ANIM_UPDATE_DEFAULT;
			}
			
			/* don't continue if some fcurves were pasted */
			if (totmatch)
				break;
		}
	}
	
	ANIM_animdata_update(ac, anim_data);

	return 0;
}
示例#7
0
/* Does not fix anything, but checks that all linked data-blocks are still valid (i.e. pointing to the right library). */
bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports)
{
	ListBase mainlist;
	bool is_valid = true;

	BKE_main_lock(bmain);

	blo_split_main(&mainlist, bmain);

	ListBase *lbarray[MAX_LIBARRAY];
	int i = set_listbasepointers(bmain, lbarray);
	while (i--) {
		for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
			if (id->lib != NULL) {
				is_valid = false;
				BKE_reportf(reports, RPT_ERROR,
				            "ID %s is in local database while being linked from library %s!\n", id->name, id->lib->name);
			}
		}
	}

	for (Main *curmain = bmain->next; curmain != NULL; curmain = curmain->next) {
		Library *curlib = curmain->curlib;
		if (curlib == NULL) {
			BKE_reportf(reports, RPT_ERROR,
			            "Library database with NULL library datablock!\n");
			continue;
		}

		BKE_library_filepath_set(bmain, curlib, curlib->name);
		BlendHandle *bh = BLO_blendhandle_from_file(curlib->filepath, reports);

		if (bh == NULL) {
			BKE_reportf(reports, RPT_ERROR,
			            "Library ID %s not found at expected path %s!\n", curlib->id.name, curlib->filepath);
			continue;
		}

		i = set_listbasepointers(curmain, lbarray);
		while (i--) {
			ID *id = lbarray[i]->first;
			if (id == NULL) {
				continue;
			}

			if (GS(id->name) == ID_LI) {
				is_valid = false;
				BKE_reportf(reports, RPT_ERROR,
				            "Library ID %s in library %s, this should not happen!\n", id->name, curlib->name);
				continue;
			}

			int totnames = 0;
			LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), &totnames);
			for (; id != NULL; id = id->next) {
				if (id->lib == NULL) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s has NULL lib pointer while being in library %s!\n", id->name, curlib->name);
					continue;
				}
				if (id->lib != curlib) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s has mismatched lib pointer!\n", id->name);
					continue;
				}

				LinkNode *name = names;
				for (; name; name = name->next) {
					char *str_name = (char *)name->link;
					if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
						break;
					}
				}

				if (name == NULL) {
					is_valid = false;
					BKE_reportf(reports, RPT_ERROR,
					            "ID %s not found in library %s anymore!\n", id->name, id->lib->name);
					continue;
				}
			}

			BLI_linklist_free(names, free);
		}

		BLO_blendhandle_close(bh);
	}

	blo_join_main(&mainlist);

	BLI_assert(BLI_listbase_is_single(&mainlist));
	BLI_assert(mainlist.first == (void *)bmain);

	BKE_main_unlock(bmain);

	return is_valid;
}
示例#8
0
static bool scanfill_preprocess_self_isect(
        ScanFillContext *sf_ctx,
        PolyInfo *poly_info,
        const unsigned short poly_nr,
        ListBase *filledgebase)
{
	PolyInfo *pi = &poly_info[poly_nr];
	GHash *isect_hash = NULL;
	ListBase isect_lb = {NULL};

	/* warning, O(n2) check here, should use spatial lookup */
	{
		ScanFillEdge *eed;

		for (eed = pi->edge_first;
		     eed;
		     eed = (eed == pi->edge_last) ? NULL : eed->next)
		{
			ScanFillEdge *eed_other;

			for (eed_other = eed->next;
			     eed_other;
			     eed_other = (eed_other == pi->edge_last) ? NULL : eed_other->next)
			{
				if (!ELEM(eed->v1, eed_other->v1, eed_other->v2) &&
				    !ELEM(eed->v2, eed_other->v1, eed_other->v2) &&
				    (eed != eed_other))
				{
					/* check isect */
					float pt[2];
					BLI_assert(eed != eed_other);

					if (isect_seg_seg_v2_point(eed->v1->co, eed->v2->co,
					                           eed_other->v1->co, eed_other->v2->co,
					                           pt) == 1)
					{
						ScanFillIsect *isect;

						if (UNLIKELY(isect_hash == NULL)) {
							isect_hash = BLI_ghash_ptr_new(__func__);
						}

						isect = MEM_mallocN(sizeof(ScanFillIsect), __func__);

						BLI_addtail(&isect_lb, isect);

						copy_v2_v2(isect->co, pt);
						isect->co[2] = eed->v1->co[2];
						isect->v = BLI_scanfill_vert_add(sf_ctx, isect->co);
						isect->v->poly_nr = eed->v1->poly_nr;  /* NOTE: vert may belong to 2 polys now */
						VFLAG_SET(isect->v, V_ISISECT);
						edge_isect_ls_add(isect_hash, eed, isect);
						edge_isect_ls_add(isect_hash, eed_other, isect);
					}
				}
			}
		}
	}

	if (isect_hash == NULL) {
		return false;
	}

	/* now subdiv the edges */
	{
		ScanFillEdge *eed;

		for (eed = pi->edge_first;
		     eed;
		     eed = (eed == pi->edge_last) ? NULL : eed->next)
		{
			if (eed->user_flag & E_ISISECT) {
				ListBase *e_ls = BLI_ghash_lookup(isect_hash, eed);

				LinkData *isect_link;

				/* maintain coorect terminating edge */
				if (pi->edge_last == eed) {
					pi->edge_last = NULL;
				}

				if (BLI_listbase_is_single(e_ls) == false) {
					BLI_sortlist_r(e_ls, eed->v2->co, edge_isect_ls_sort_cb);
				}

				/* move original edge to filledgebase and add replacement
				 * (which gets subdivided next) */
				{
					ScanFillEdge *eed_tmp;
					eed_tmp = BLI_scanfill_edge_add(sf_ctx, eed->v1, eed->v2);
					BLI_remlink(&sf_ctx->filledgebase, eed_tmp);
					BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_tmp);
					BLI_remlink(&sf_ctx->filledgebase, eed);
					BLI_addtail(filledgebase, eed);
					if (pi->edge_first == eed) {
						pi->edge_first = eed_tmp;
					}
					eed = eed_tmp;
				}

				for (isect_link = e_ls->first; isect_link; isect_link = isect_link->next) {
					ScanFillIsect *isect = isect_link->data;
					ScanFillEdge *eed_subd;

					eed_subd = BLI_scanfill_edge_add(sf_ctx, isect->v, eed->v2);
					eed_subd->poly_nr = poly_nr;
					eed->v2 = isect->v;

					BLI_remlink(&sf_ctx->filledgebase, eed_subd);
					BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_subd);

					/* step to the next edge and continue dividing */
					eed = eed_subd;
				}

				BLI_freelistN(e_ls);
				MEM_freeN(e_ls);

				if (pi->edge_last == NULL) {
					pi->edge_last = eed;
				}
			}
		}
	}

	BLI_freelistN(&isect_lb);
	BLI_ghash_free(isect_hash, NULL, NULL);

	{
		ScanFillEdge *e_init;
		ScanFillEdge *e_curr;
		ScanFillEdge *e_next;

		ScanFillVert *v_prev;
		ScanFillVert *v_curr;

		int inside = false;

		/* first vert */
#if 0
		e_init = pi->edge_last;
		e_curr = e_init;
		e_next = pi->edge_first;

		v_prev = e_curr->v1;
		v_curr = e_curr->v2;
#else

		/* find outside vertex */
		{
			ScanFillEdge *eed;
			ScanFillEdge *eed_prev;
			float min_x = FLT_MAX;

			e_curr = pi->edge_last;
			e_next = pi->edge_first;

			eed_prev = pi->edge_last;
			for (eed = pi->edge_first;
			     eed;
			     eed = (eed == pi->edge_last) ? NULL : eed->next)
			{
				if (eed->v2->co[0] < min_x) {
					min_x = eed->v2->co[0];
					e_curr = eed_prev;
					e_next = eed;

				}
				eed_prev = eed;
			}

			e_init = e_curr;
			v_prev = e_curr->v1;
			v_curr = e_curr->v2;
		}
#endif

		BLI_assert(e_curr->poly_nr == poly_nr);
		BLI_assert(pi->edge_last->poly_nr == poly_nr);

		do {
			ScanFillVert *v_next;

			v_next = (e_next->v1 == v_curr) ? e_next->v2 : e_next->v1;
			BLI_assert(ELEM(v_curr, e_next->v1, e_next->v2));

			/* track intersections */
			if (inside) {
				EFLAG_SET(e_next, E_ISDELETE);
			}
			if (v_next->user_flag & V_ISISECT) {
				inside = !inside;
			}
			/* now step... */

			v_prev = v_curr;
			v_curr = v_next;
			e_curr = e_next;

			e_next = edge_step(poly_info, poly_nr, v_prev, v_curr, e_curr);

		} while (e_curr != e_init);
	}

	return true;
}