Exemplo n.º 1
0
static void updateDepgraph(ModifierData *md, DagForest *forest,
                           struct Scene *scene, struct Object *ob,
                           DagNode *obNode)
{
	SmokeModifierData *smd = (SmokeModifierData *) md;
	Base *base;

	if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
		if (smd->domain->fluid_group || smd->domain->coll_group) {
			GroupObject *go = NULL;
			
			if (smd->domain->fluid_group)
				for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
					if (go->ob) {
						SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
						
						/* check for initialized smoke object */
						if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
							DagNode *curNode = dag_get_node(forest, go->ob);
							dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow");
						}
					}
				}

			if (smd->domain->coll_group)
				for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
					if (go->ob) {
						SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
						
						/* check for initialized smoke object */
						if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
							DagNode *curNode = dag_get_node(forest, go->ob);
							dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Coll");
						}
					}
				}
		}
		else {
			base = scene->base.first;
			for (; base; base = base->next) {
				SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke);

				if (smd2 && (((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) || ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll))) {
					DagNode *curNode = dag_get_node(forest, base->object);
					dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow/Coll");
				}
			}
		}
		/* add relation to all "smoke flow" force fields */
		base = scene->base.first;
		for (; base; base = base->next) {
			if (base->object->pd && base->object->pd->forcefield == PFIELD_SMOKEFLOW && base->object->pd->f_source == ob) {
				DagNode *node2 = dag_get_node(forest, base->object);
				dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
			}
		}
	}
}
Exemplo n.º 2
0
static char *view3d_modeselect_pup(Scene *scene)
{
	Object *ob= OBACT;
	static char string[256];
	const char *title= N_("Mode: %t");
	char *str = string;

	if(U.transopts&USER_TR_IFACE)
		title= BLF_gettext(title);

	BLI_strncpy(str, title, sizeof(string));

	str += modeselect_addmode(str, N_("Object Mode"), OB_MODE_OBJECT, ICON_OBJECT_DATA);
	
	if(ob==NULL || ob->data==NULL) return string;
	if(ob->id.lib) return string;
	
	if(!((ID *)ob->data)->lib) {
		/* if active object is editable */
		if ( ((ob->type == OB_MESH)
			|| (ob->type == OB_CURVE) || (ob->type == OB_SURF) || (ob->type == OB_FONT)
			|| (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) {
			
			str += modeselect_addmode(str, N_("Edit Mode"), OB_MODE_EDIT, ICON_EDITMODE_HLT);
		}
		else if (ob->type == OB_ARMATURE) {
			if (ob->mode & OB_MODE_POSE)
				str += modeselect_addmode(str, N_("Edit Mode"), OB_MODE_EDIT|OB_MODE_POSE, ICON_EDITMODE_HLT);
			else
				str += modeselect_addmode(str, N_("Edit Mode"), OB_MODE_EDIT, ICON_EDITMODE_HLT);
		}

		if (ob->type == OB_MESH) {

			str += modeselect_addmode(str, N_("Sculpt Mode"), OB_MODE_SCULPT, ICON_SCULPTMODE_HLT);
			str += modeselect_addmode(str, N_("Vertex Paint"), OB_MODE_VERTEX_PAINT, ICON_VPAINT_HLT);
			str += modeselect_addmode(str, N_("Texture Paint"), OB_MODE_TEXTURE_PAINT, ICON_TPAINT_HLT);
			str += modeselect_addmode(str, N_("Weight Paint"), OB_MODE_WEIGHT_PAINT, ICON_WPAINT_HLT);
		}
	}
		
	/* if active object is an armature */
	if (ob->type==OB_ARMATURE) {
		str += modeselect_addmode(str, N_("Pose Mode"), OB_MODE_POSE, ICON_POSE_HLT);
	}

	if (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)) {
		str += modeselect_addmode(str, N_("Particle Mode"), OB_MODE_PARTICLE_EDIT, ICON_PARTICLEMODE);
	}
	(void)str;
	return (string);
}
Exemplo n.º 3
0
static char *view3d_modeselect_pup(Scene *scene)
{
	Object *ob= OBACT;
	static char string[256];
	static char formatstr[] = "|%s %%x%d %%i%d";
	char *str = string;

	str += sprintf(str, "Mode: %%t");
	
	str += sprintf(str, formatstr, "Object Mode", OB_MODE_OBJECT, ICON_OBJECT_DATA);
	
	if(ob==NULL || ob->data==NULL) return string;
	if(ob->id.lib) return string;
	
	if(!((ID *)ob->data)->lib) {
		/* if active object is editable */
		if ( ((ob->type == OB_MESH)
			|| (ob->type == OB_CURVE) || (ob->type == OB_SURF) || (ob->type == OB_FONT)
			|| (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) {
			
			str += sprintf(str, formatstr, "Edit Mode", OB_MODE_EDIT, ICON_EDITMODE_HLT);
		}
		else if (ob->type == OB_ARMATURE) {
			if (ob->mode & OB_MODE_POSE)
				str += sprintf(str, formatstr, "Edit Mode", OB_MODE_EDIT|OB_MODE_POSE, ICON_EDITMODE_HLT);
			else
				str += sprintf(str, formatstr, "Edit Mode", OB_MODE_EDIT, ICON_EDITMODE_HLT);
		}

		if (ob->type == OB_MESH) {

			str += sprintf(str, formatstr, "Sculpt Mode", OB_MODE_SCULPT, ICON_SCULPTMODE_HLT);
			str += sprintf(str, formatstr, "Vertex Paint", OB_MODE_VERTEX_PAINT, ICON_VPAINT_HLT);
			str += sprintf(str, formatstr, "Texture Paint", OB_MODE_TEXTURE_PAINT, ICON_TPAINT_HLT);
			str += sprintf(str, formatstr, "Weight Paint", OB_MODE_WEIGHT_PAINT, ICON_WPAINT_HLT);
		}
	}
		
	/* if active object is an armature */
	if (ob->type==OB_ARMATURE) {
		str += sprintf(str, formatstr, "Pose Mode", OB_MODE_POSE, ICON_POSE_HLT);
	}

	if (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)) {
		str += sprintf(str, formatstr, "Particle Mode", OB_MODE_PARTICLE_EDIT, ICON_PARTICLEMODE);
	}
	(void)str;
	return (string);
}
Exemplo n.º 4
0
static void updateDepgraph(
					 ModifierData *md, DagForest *forest, Scene *scene, Object *ob,
	  DagNode *obNode)
{
	ClothModifierData *clmd = (ClothModifierData*) md;
	
	Base *base;
	
	if(clmd)
	{
		for(base = scene->base.first; base; base= base->next) 
		{
			Object *ob1= base->object;
			if(ob1 != ob)
			{
				CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
				if(coll_clmd)
				{
					DagNode *curNode = dag_get_node(forest, ob1);
					dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Cloth Collision");
				}
			}
		}
	}
}
Exemplo n.º 5
0
/*
 * Bake Dynamic Paint image sequence surface
 */
static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
{
	DynamicPaintModifierData *pmd = NULL;
	DynamicPaintCanvasSettings *canvas;
	Object *ob = ED_object_context(C);
	int status = 0;
	double timer = PIL_check_seconds_timer();
	DynamicPaintSurface *surface;

	/*
	 * Get modifier data
	 */
	pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
	if (!pmd) {
		BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
		return 0;
	}

	/* Make sure we're dealing with a canvas */
	canvas = pmd->canvas;
	if (!canvas) {
		BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas");
		return 0;
	}
	surface = get_activeSurface(canvas);

	/* Set state to baking and init surface */
	canvas->error[0] = '\0';
	canvas->flags |= MOD_DPAINT_BAKING;
	G.is_break = FALSE;  /* reset blender_test_break*/

	/*  Bake Dynamic Paint	*/
	status = dynamicPaint_bakeImageSequence(C, surface, ob);
	/* Clear bake */
	canvas->flags &= ~MOD_DPAINT_BAKING;
	WM_cursor_restore(CTX_wm_window(C));
	dynamicPaint_freeSurfaceData(surface);

	/* Bake was successful:
	 *  Report for ended bake and how long it took */
	if (status) {
		/* Format time string */
		char time_str[30];
		double time = PIL_check_seconds_timer() - timer;
		BLI_timestr(time, time_str);

		/* Show bake info */
		BKE_reportf(op->reports, RPT_INFO, "Bake complete! (%s)", time_str);
	}
	else {
		if (strlen(canvas->error)) { /* If an error occurred */
			BKE_reportf(op->reports, RPT_ERROR, "Bake failed: %s", canvas->error);
		}
		else { /* User canceled the bake */
			BKE_report(op->reports, RPT_WARNING, "Baking canceled!");
		}
	}

	return status;
}
Exemplo n.º 6
0
static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
	DynamicPaintModifierData *pmd = NULL;
	Object *obj_ctx = ED_object_context(C);
	DynamicPaintCanvasSettings *canvas;
	DynamicPaintSurface *surface;
	int id = 0;

	/* Make sure we're dealing with a canvas */
	pmd = (DynamicPaintModifierData *)modifiers_findByType(obj_ctx, eModifierType_DynamicPaint);
	if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;

	canvas = pmd->canvas;
	surface = canvas->surfaces.first;

	/* find active surface and remove it */
	for (; surface; surface = surface->next) {
		if (id == canvas->active_sur) {
				canvas->active_sur -= 1;
				dynamicPaint_freeSurface(surface);
				break;
			}
		id++;
	}

	dynamicPaint_resetPreview(canvas);
	DAG_id_tag_update(&obj_ctx->id, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obj_ctx);

	return OPERATOR_FINISHED;
}
Exemplo n.º 7
0
static void updateDepgraph(
        ModifierData *md, DagForest *forest, Scene *scene,
        Object *ob, DagNode *obNode)
{
	FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
	Base *base;

	if (fluidmd && fluidmd->fss) {
		if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
			for (base = scene->base.first; base; base = base->next) {
				Object *ob1 = base->object;
				if (ob1 != ob) {
					FluidsimModifierData *fluidmdtmp =
					        (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
					
					/* only put dependencies from NON-DOMAIN fluids in here */
					if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
						DagNode *curNode = dag_get_node(forest, ob1);
						dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Fluidsim Object");
					}
				}
			}
		}
	}
}
Exemplo n.º 8
0
static int type_toggle_exec(bContext *C, wmOperator *op)
{

	Object *cObject = ED_object_context(C);
	Scene *scene = CTX_data_scene(C);
	DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
	int type = RNA_enum_get(op->ptr, "type");

	if (!pmd) return OPERATOR_CANCELLED;

	/* if type is already enabled, toggle it off */
	if (type == MOD_DYNAMICPAINT_TYPE_CANVAS && pmd->canvas) {
			dynamicPaint_freeCanvas(pmd);
	}
	else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush) {
			dynamicPaint_freeBrush(pmd);
	}
	/* else create a new type */
	else {
		if (!dynamicPaint_createType(pmd, type, scene))
			return OPERATOR_CANCELLED;
	}
	
	/* update dependency */
	DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
	DAG_relations_tag_update(CTX_data_main(C));
	WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, cObject);

	return OPERATOR_FINISHED;
}
Exemplo n.º 9
0
static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
{
	DynamicPaintModifierData *pmd = NULL;
	Object *cObject = ED_object_context(C);
	DynamicPaintCanvasSettings *canvas;
	DynamicPaintSurface *surface;

	/* Make sure we're dealing with a canvas */
	pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
	if (!pmd || !pmd->canvas)
		return OPERATOR_CANCELLED;

	canvas = pmd->canvas;
	surface = dynamicPaint_createNewSurface(canvas, CTX_data_scene(C));

	if (!surface)
		return OPERATOR_CANCELLED;

	/* set preview for this surface only and set active */
	canvas->active_sur = 0;
	for (surface = surface->prev; surface; surface = surface->prev) {
		surface->flags &= ~MOD_DPAINT_PREVIEW;
		canvas->active_sur++;
	}

	return OPERATOR_FINISHED;
}
Exemplo n.º 10
0
static void set_vertex_channel(float *channel, float time, struct Scene *scene, struct FluidObject *fobj, int i)
{
	Object *ob = fobj->object;
	FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
	float *verts;
	int *tris=NULL, numVerts=0, numTris=0;
	int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
	int framesize = (3*fobj->numVerts) + 1;
	int j;
	
	if (channel == NULL)
		return;
	
	initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
	
	/* don't allow mesh to change number of verts in anim sequence */
	if (numVerts != fobj->numVerts) {
		MEM_freeN(channel);
		channel = NULL;
		return;
	}
	
	/* fill frame of channel with vertex locations */
	for (j=0; j < (3*numVerts); j++) {
		channel[i*framesize + j] = verts[j];
	}
	channel[i*framesize + framesize-1] = time;
	
	MEM_freeN(verts);
	MEM_freeN(tris);
}
Exemplo n.º 11
0
static char *rna_ClothCollisionSettings_path(PointerRNA *ptr)
{
	Object *ob= (Object*)ptr->id.data;
	ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth);

	return md ? BLI_sprintfN("modifiers[\"%s\"].collision_settings", md->name) : NULL;
}
Exemplo n.º 12
0
static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDomain)
{
	Base *base;
	Object *newdomain = NULL;
	int channelObjCount = 0;
	int fluidInputCount = 0;

	for(base=scene->base.first; base; base= base->next)
	{
		Object *ob = base->object;
		FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);			

		/* only find objects with fluid modifiers */
		if (!fluidmdtmp || ob->type != OB_MESH) continue;
			
		if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) {
			/* if no initial domain object given, find another potential domain */
			if (!fsDomain) {
				newdomain = ob;
			}
			/* if there's more than one domain, cancel */
			else if (fsDomain && ob != fsDomain) {
				BKE_report(reports, RPT_ERROR, "There should be only one domain object.");
				return 0;
			}
		}
		
		/* count number of objects needed for animation channels */
		if ( !ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE) )
			channelObjCount++;
		
		/* count number of fluid input objects */
		if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW))
			fluidInputCount++;
	}

	if (newdomain)
		fsDomain = newdomain;
	
	if (!fsDomain) {
		BKE_report(reports, RPT_ERROR, "No domain object found.");
		return 0;
	}
	
	if (channelObjCount>=255) {
		BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects.");
		return 0;
	}
	
	if (fluidInputCount == 0) {
		BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene.");
		return 0;
	}
	
	return 1;
}
Exemplo n.º 13
0
static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
	Object *ob = (Object*)ptr->id.data;
	FluidsimModifierData *fluidmd;
	ParticleSystemModifierData *psmd;
	ParticleSystem *psys;
	ParticleSettings *part;
	
	fluidmd = (FluidsimModifierData*)modifiers_findByType(ob, eModifierType_Fluidsim);
	fluidmd->fss->flag &= ~OB_FLUIDSIM_REVERSE; /* clear flag */

	/* remove fluidsim particle system */
	if (fluidmd->fss->type & OB_FLUIDSIM_PARTICLE) {
		for (psys = ob->particlesystem.first; psys; psys = psys->next)
			if (psys->part->type == PART_FLUID)
				break;

		if (ob->type == OB_MESH && !psys) {
			/* add particle system */
			part = psys_new_settings("ParticleSettings", bmain);
			psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");

			part->type = PART_FLUID;
			psys->part = part;
			psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
			psys->flag |= PSYS_ENABLED;
			BLI_strncpy(psys->name, "FluidParticles", sizeof(psys->name));
			BLI_addtail(&ob->particlesystem,psys);

			/* add modifier */
			psmd = (ParticleSystemModifierData*)modifier_new(eModifierType_ParticleSystem);
			BLI_strncpy(psmd->modifier.name, "FluidParticleSystem", sizeof(psmd->modifier.name));
			psmd->psys = psys;
			BLI_addtail(&ob->modifiers, psmd);
			modifier_unique_name(&ob->modifiers, (ModifierData *)psmd);
		}
	}
	else {
		for (psys = ob->particlesystem.first; psys; psys = psys->next) {
			if (psys->part->type == PART_FLUID) {
				/* clear modifier */
				psmd = psys_get_modifier(ob, psys);
				BLI_remlink(&ob->modifiers, psmd);
				modifier_free((ModifierData *)psmd);

				/* clear particle system */
				BLI_remlink(&ob->particlesystem, psys);
				psys_free(ob, psys);
			}
		}
	}

	rna_fluid_update(bmain, scene, ptr);
}
Exemplo n.º 14
0
static void rna_cloth_pinning_changed(Main *bmain, Scene *scene, PointerRNA *ptr)
{
	Object *ob= (Object*)ptr->id.data;
//	ClothSimSettings *settings = (ClothSimSettings*)ptr->data;
	ClothModifierData *clmd = (ClothModifierData*)modifiers_findByType(ob, eModifierType_Cloth);

	cloth_free_modifier(clmd);

	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	WM_main_add_notifier(NC_OBJECT|ND_MODIFIER, ob);
}
Exemplo n.º 15
0
/*
 * Bake Dynamic Paint image sequence surface
 */
static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op)
{
	DynamicPaintModifierData *pmd = NULL;
	DynamicPaintCanvasSettings *canvas;
	Object *ob = ED_object_context(C);
	Scene *scene = CTX_data_scene(C);

	DynamicPaintSurface *surface;

	/*
	 * Get modifier data
	 */
	pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
	if (!pmd) {
		BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
		return OPERATOR_CANCELLED;
	}

	/* Make sure we're dealing with a canvas */
	canvas = pmd->canvas;
	if (!canvas) {
		BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas");
		return OPERATOR_CANCELLED;
	}
	surface = get_activeSurface(canvas);

	/* Set state to baking and init surface */
	canvas->error[0] = '\0';
	canvas->flags |= MOD_DPAINT_BAKING;

	DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob");
	job->bmain = CTX_data_main(C);
	job->scene = scene;
	job->ob = ob;
	job->canvas = canvas;
	job->surface = surface;

	wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene,
	                            "Dynamic Paint Bake", WM_JOB_PROGRESS,
	                            WM_JOB_TYPE_DPAINT_BAKE);

	WM_jobs_customdata_set(wm_job, job, dpaint_bake_free);
	WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
	WM_jobs_callbacks(wm_job, dpaint_bake_startjob, NULL, NULL, dpaint_bake_endjob);

	WM_set_locked_interface(CTX_wm_manager(C), true);

	/* Bake Dynamic Paint */
	WM_jobs_start(CTX_wm_manager(C), wm_job);

	return OPERATOR_FINISHED;
}
Exemplo n.º 16
0
static void rna_fluid_find_enframe(Main *bmain, Scene *scene, PointerRNA *ptr)
{
	Object *ob = ptr->id.data;
	FluidsimModifierData *fluidmd = (FluidsimModifierData*)modifiers_findByType(ob, eModifierType_Fluidsim);

	if (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE) {
		fluidmd->fss->lastgoodframe = fluidsim_find_lastframe(ob, fluidmd->fss);
	}
	else {
		fluidmd->fss->lastgoodframe = -1;
	}
	rna_fluid_update(bmain, scene, ptr);
}
Exemplo n.º 17
0
static char *rna_ClothCollisionSettings_path(PointerRNA *ptr)
{
	Object *ob = (Object *)ptr->id.data;
	ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);

	if (md) {
		char name_esc[sizeof(md->name) * 2];
		BLI_strescape(name_esc, md->name, sizeof(name_esc));
		return BLI_sprintfN("modifiers[\"%s\"].collision_settings", name_esc);
	}
	else {
		return NULL;
	}
}
Exemplo n.º 18
0
static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel)
{
	CacheFile *cache_file;

	for (cache_file = bmain->cachefiles.first;
	     cache_file;
	     cache_file = cache_file->id.next)
	{
		cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
	}

	for (Base *base = scene->base.first; base; base = base->next) {
		Object *ob = base->object;

		ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);

		if (md) {
			MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;

			cache_file = mcmd->cache_file;

			if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
				continue;
			}

			cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;

			time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
		}

		for (bConstraint *con = ob->constraints.first; con; con = con->next) {
			if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
				continue;
			}

			bTransformCacheConstraint *data = con->data;

			cache_file = data->cache_file;

			if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
				continue;
			}

			cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;

			time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel);
		}
	}
}
Exemplo n.º 19
0
static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
{
	Object *ob;
	ModifierData *md;
	
	vd->dataset = NULL;
	if (vd->object == NULL) return;
	ob = vd->object;
	
	if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) {
		ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
		
		if (pmd->psys && pmd->psys->clmd) {
			vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
		}
	}
}
Exemplo n.º 20
0
static int output_toggle_exec(bContext *C, wmOperator *op)
{
	Object *ob = ED_object_context(C);
	Scene *scene = CTX_data_scene(C);
	DynamicPaintSurface *surface;
	DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
	int output= RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */

	if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED;
	surface = get_activeSurface(pmd->canvas);

	/* if type is already enabled, toggle it off */
	if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
		int exists = dynamicPaint_outputLayerExists(surface, ob, output);
		const char *name;
		
		if (output == 0)
			name = surface->output_name;
		else
			name = surface->output_name2;

		/* Vertex Color Layer */
		if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
			if (!exists)
				ED_mesh_color_add(C, scene, ob, ob->data, name, 1);
			else 
				ED_mesh_color_remove_named(C, ob, ob->data, name);
		}
		/* Vertex Weight Layer */
		else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
			if (!exists) {
				ED_vgroup_add_name(ob, name);
			}
			else {
				bDeformGroup *defgroup = defgroup_find_name(ob, name);
				if (defgroup) ED_vgroup_delete(ob, defgroup);
			}
		}
	}

	return OPERATOR_FINISHED;
}
Exemplo n.º 21
0
static void updateDepsgraph(ModifierData *md,
                            struct Main *UNUSED(bmain),
                            struct Scene *scene,
                            Object *ob,
                            struct DepsNodeHandle *node)
{
	ClothModifierData *clmd = (ClothModifierData *)md;
	if (clmd != NULL) {
		Base *base;
		for (base = scene->base.first; base; base = base->next) {
			Object *ob1 = base->object;
			if (ob1 != ob) {
				CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
				if (coll_clmd) {
					DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier");
				}
			}
		}
	}
}
Exemplo n.º 22
0
static void precalculate_effector(EffectorCache *eff)
{
	unsigned int cfra = (unsigned int)(eff->scene->r.cfra >= 0 ? eff->scene->r.cfra : -eff->scene->r.cfra);
	if (!eff->pd->rng)
		eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
	else
		BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);

	if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) {
		Curve *cu= eff->ob->data;
		if (cu->flag & CU_PATH) {
			if (eff->ob->curve_cache == NULL || eff->ob->curve_cache->path==NULL || eff->ob->curve_cache->path->data==NULL)
				BKE_displist_make_curveTypes(eff->scene, eff->ob, 0);

			if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) {
				where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
				mul_m4_v3(eff->ob->obmat, eff->guide_loc);
				mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
			}
		}
	}
	else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
		eff->surmd = (SurfaceModifierData *)modifiers_findByType( eff->ob, eModifierType_Surface );
		if (eff->ob->type == OB_CURVE)
			eff->flag |= PE_USE_NORMAL_DATA;
	}
	else if (eff->psys)
		psys_update_particle_tree(eff->psys, eff->scene->r.cfra);

	/* Store object velocity */
	if (eff->ob) {
		float old_vel[3];

		BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra - 1.0f);
		copy_v3_v3(old_vel, eff->ob->obmat[3]);
		BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra);
		sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel);
	}
}
Exemplo n.º 23
0
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
{
	for (Base *base = scene->base.first; base; base = base->next) {
		Object *ob = base->object;

		ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);

		if (md) {
			MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;

			if (cache_file == mcmd->cache_file) {
#ifdef WITH_ALEMBIC
				if (mcmd->reader != NULL) {
					CacheReader_free(mcmd->reader);
				}
#endif
				mcmd->reader = NULL;
			}
		}

		for (bConstraint *con = ob->constraints.first; con; con = con->next) {
			if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
				continue;
			}

			bTransformCacheConstraint *data = con->data;

			if (cache_file == data->cache_file) {
#ifdef WITH_ALEMBIC
				if (data->reader != NULL) {
					CacheReader_free(data->reader);
				}
#endif
				data->reader = NULL;
			}
		}
	}
}
Exemplo n.º 24
0
int modifiers_isParticleEnabled(Object *ob)
{
	ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);

	return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
Exemplo n.º 25
0
int modifiers_isClothEnabled(Object *ob)
{
	ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);

	return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
Exemplo n.º 26
0
ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
	ModifierData *md=NULL, *new_md=NULL;
	ModifierTypeInfo *mti = modifierType_getInfo(type);
	
	/* only geometry objects should be able to get modifiers [#25291] */
	if(!ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
		BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to Object '%s'", ob->id.name+2);
		return NULL;
	}
	
	if(mti->flags&eModifierTypeFlag_Single) {
		if(modifiers_findByType(ob, type)) {
			BKE_report(reports, RPT_WARNING, "Only one modifier of this type allowed");
			return NULL;
		}
	}
	
	if(type == eModifierType_ParticleSystem) {
		/* don't need to worry about the new modifier's name, since that is set to the number
		 * of particle systems which shouldn't have too many duplicates 
		 */
		new_md = object_add_particle_system(scene, ob, name);
	}
	else {
		/* get new modifier data to add */
		new_md= modifier_new(type);
		
		if(mti->flags&eModifierTypeFlag_RequiresOriginalData) {
			md = ob->modifiers.first;
			
			while(md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform)
				md = md->next;
			
			BLI_insertlinkbefore(&ob->modifiers, md, new_md);
		}
		else
			BLI_addtail(&ob->modifiers, new_md);

		if(name)
			BLI_strncpy(new_md->name, name, sizeof(new_md->name));

		/* make sure modifier data has unique name */

		modifier_unique_name(&ob->modifiers, new_md);
		
		/* special cases */
		if(type == eModifierType_Softbody) {
			if(!ob->soft) {
				ob->soft= sbNew(scene);
				ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
			}
		}
		else if(type == eModifierType_Collision) {
			if(!ob->pd)
				ob->pd= object_add_collision_fields(0);
			
			ob->pd->deflect= 1;
			DAG_scene_sort(bmain, scene);
		}
		else if(type == eModifierType_Surface)
			DAG_scene_sort(bmain, scene);
		else if(type == eModifierType_Multires)
			/* set totlvl from existing MDISPS layer if object already had it */
			multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob);
	}

	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);

	return new_md;
}
int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
{
	SpaceButs *sbuts = CTX_wm_space_buts(C);
	ButsContextPath *path = sbuts ? sbuts->path : NULL;

	if (!path)
		return 0;

	/* here we handle context, getting data from precomputed path */
	if (CTX_data_dir(member)) {
		/* in case of new shading system we skip texture_slot, complex python
		 * UI script logic depends on checking if this is available */
		if (sbuts->texuser)
			CTX_data_dir_set(result, buttons_context_dir + 1);
		else
			CTX_data_dir_set(result, buttons_context_dir);
		return 1;
	}
	else if (CTX_data_equals(member, "scene")) {
		/* Do not return one here if scene not found in path, in this case we want to get default context scene! */
		return set_pointer_type(path, result, &RNA_Scene);
	}
	else if (CTX_data_equals(member, "world")) {
		set_pointer_type(path, result, &RNA_World);
		return 1;
	}
	else if (CTX_data_equals(member, "object")) {
		set_pointer_type(path, result, &RNA_Object);
		return 1;
	}
	else if (CTX_data_equals(member, "mesh")) {
		set_pointer_type(path, result, &RNA_Mesh);
		return 1;
	}
	else if (CTX_data_equals(member, "armature")) {
		set_pointer_type(path, result, &RNA_Armature);
		return 1;
	}
	else if (CTX_data_equals(member, "lattice")) {
		set_pointer_type(path, result, &RNA_Lattice);
		return 1;
	}
	else if (CTX_data_equals(member, "curve")) {
		set_pointer_type(path, result, &RNA_Curve);
		return 1;
	}
	else if (CTX_data_equals(member, "meta_ball")) {
		set_pointer_type(path, result, &RNA_MetaBall);
		return 1;
	}
	else if (CTX_data_equals(member, "lamp")) {
		set_pointer_type(path, result, &RNA_Lamp);
		return 1;
	}
	else if (CTX_data_equals(member, "camera")) {
		set_pointer_type(path, result, &RNA_Camera);
		return 1;
	}
	else if (CTX_data_equals(member, "speaker")) {
		set_pointer_type(path, result, &RNA_Speaker);
		return 1;
	}
	else if (CTX_data_equals(member, "material")) {
		set_pointer_type(path, result, &RNA_Material);
		return 1;
	}
	else if (CTX_data_equals(member, "texture")) {
		ButsContextTexture *ct = sbuts->texuser;

		if (ct) {
			/* new shading system */
			CTX_data_pointer_set(result, &ct->texture->id, &RNA_Texture, ct->texture);
		}
		else {
			/* old shading system */
			set_pointer_type(path, result, &RNA_Texture);
		}

		return 1;
	}
	else if (CTX_data_equals(member, "material_slot")) {
		PointerRNA *ptr = get_pointer_type(path, &RNA_Object);

		if (ptr) {
			Object *ob = ptr->data;

			if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type) && ob->totcol) {
				/* a valid actcol isn't ensured [#27526] */
				int matnr = ob->actcol - 1;
				if (matnr < 0) matnr = 0;
				CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, &ob->mat[matnr]);
			}
		}

		return 1;
	}
	else if (CTX_data_equals(member, "texture_user")) {
		ButsContextTexture *ct = sbuts->texuser;

		if (!ct)
			return -1;  /* old shading system (found but not available) */

		if (ct->user && ct->user->ptr.data) {
			ButsTextureUser *user = ct->user;
			CTX_data_pointer_set(result, user->ptr.id.data, user->ptr.type, user->ptr.data);
		}

		return 1;
	}
	else if (CTX_data_equals(member, "texture_user_property")) {
		ButsContextTexture *ct = sbuts->texuser;

		if (!ct)
			return -1;  /* old shading system (found but not available) */

		if (ct->user && ct->user->ptr.data) {
			ButsTextureUser *user = ct->user;
			CTX_data_pointer_set(result, NULL, &RNA_Property, user->prop);
		}

		return 1;
	}
	else if (CTX_data_equals(member, "texture_node")) {
		ButsContextTexture *ct = sbuts->texuser;

		if (ct) {
			/* new shading system */
			if (ct->user && ct->user->node) {
				CTX_data_pointer_set(result, &ct->user->ntree->id, &RNA_Node, ct->user->node);
			}

			return 1;
		}
		else {
			/* old shading system */
			PointerRNA *ptr;

			if ((ptr = get_pointer_type(path, &RNA_Material))) {
				Material *ma = ptr->data;

				if (ma) {
					bNode *node = give_current_material_texture_node(ma);
					CTX_data_pointer_set(result, &ma->nodetree->id, &RNA_Node, node);
				}
			}

			return 1;
		}
	}
	else if (CTX_data_equals(member, "texture_slot")) {
		ButsContextTexture *ct = sbuts->texuser;
		PointerRNA *ptr;

		/* Particles slots are used in both old and new textures handling. */
		if ((ptr = get_pointer_type(path, &RNA_ParticleSystem))) {
			ParticleSettings *part = ((ParticleSystem *)ptr->data)->part;

			if (part)
				CTX_data_pointer_set(result, &part->id, &RNA_ParticleSettingsTextureSlot, part->mtex[(int)part->texact]);
		}
		else if (ct) {
			return 0;  /* new shading system */
		}
		else if ((ptr = get_pointer_type(path, &RNA_Material))) {
			Material *ma = ptr->data;

			/* if we have a node material, get slot from material in material node */
			if (ma && ma->use_nodes && ma->nodetree) {
				/* if there's an active texture node in the node tree,
				 * then that texture is in context directly, without a texture slot */
				if (give_current_material_texture_node(ma))
					return 0;

				ma = give_node_material(ma);
				if (ma)
					CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
				else
					return 0;
			}
			else if (ma) {
				CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
			}
		}
		else if ((ptr = get_pointer_type(path, &RNA_Lamp))) {
			Lamp *la = ptr->data;

			if (la)
				CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
		}
		else if ((ptr = get_pointer_type(path, &RNA_World))) {
			World *wo = ptr->data;

			if (wo)
				CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
		}
		else if ((ptr = get_pointer_type(path, &RNA_FreestyleLineStyle))) {
			FreestyleLineStyle *ls = ptr->data;

			if (ls)
				CTX_data_pointer_set(result, &ls->id, &RNA_LineStyleTextureSlot, ls->mtex[(int)ls->texact]);
		}

		return 1;
	}
	else if (CTX_data_equals(member, "bone")) {
		set_pointer_type(path, result, &RNA_Bone);
		return 1;
	}
	else if (CTX_data_equals(member, "edit_bone")) {
		set_pointer_type(path, result, &RNA_EditBone);
		return 1;
	}
	else if (CTX_data_equals(member, "pose_bone")) {
		set_pointer_type(path, result, &RNA_PoseBone);
		return 1;
	}
	else if (CTX_data_equals(member, "particle_system")) {
		set_pointer_type(path, result, &RNA_ParticleSystem);
		return 1;
	}
	else if (CTX_data_equals(member, "particle_system_editable")) {
		if (PE_poll((bContext *)C))
			set_pointer_type(path, result, &RNA_ParticleSystem);
		else
			CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL);
		return 1;
	}
	else if (CTX_data_equals(member, "particle_settings")) {
		/* only available when pinned */
		PointerRNA *ptr = get_pointer_type(path, &RNA_ParticleSettings);
		
		if (ptr && ptr->data) {
			CTX_data_pointer_set(result, ptr->id.data, &RNA_ParticleSettings, ptr->data);
			return 1;
		}
		else {
			/* get settings from active particle system instead */
			ptr = get_pointer_type(path, &RNA_ParticleSystem);
			
			if (ptr && ptr->data) {
				ParticleSettings *part = ((ParticleSystem *)ptr->data)->part;
				CTX_data_pointer_set(result, ptr->id.data, &RNA_ParticleSettings, part);
				return 1;
			}
		}
		set_pointer_type(path, result, &RNA_ParticleSettings);
		return 1;
	}
	else if (CTX_data_equals(member, "cloth")) {
		PointerRNA *ptr = get_pointer_type(path, &RNA_Object);

		if (ptr && ptr->data) {
			Object *ob = ptr->data;
			ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
			CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
			return 1;
		}
	}
	else if (CTX_data_equals(member, "soft_body")) {
		PointerRNA *ptr = get_pointer_type(path, &RNA_Object);

		if (ptr && ptr->data) {
			Object *ob = ptr->data;
			ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
			CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
			return 1;
		}
	}
	else if (CTX_data_equals(member, "fluid")) {
		PointerRNA *ptr = get_pointer_type(path, &RNA_Object);

		if (ptr && ptr->data) {
			Object *ob = ptr->data;
			ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
			CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md);
			return 1;
		}
	}
	
	else if (CTX_data_equals(member, "smoke")) {
		PointerRNA *ptr = get_pointer_type(path, &RNA_Object);

		if (ptr && ptr->data) {
			Object *ob = ptr->data;
			ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
			CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md);
			return 1;
		}
	}
	else if (CTX_data_equals(member, "collision")) {
		PointerRNA *ptr = get_pointer_type(path, &RNA_Object);

		if (ptr && ptr->data) {
			Object *ob = ptr->data;
			ModifierData *md = modifiers_findByType(ob, eModifierType_Collision);
			CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
			return 1;
		}
	}
	else if (CTX_data_equals(member, "brush")) {
		set_pointer_type(path, result, &RNA_Brush);
		return 1;
	}
	else if (CTX_data_equals(member, "dynamic_paint")) {
		PointerRNA *ptr = get_pointer_type(path, &RNA_Object);

		if (ptr && ptr->data) {
			Object *ob = ptr->data;
			ModifierData *md = modifiers_findByType(ob, eModifierType_DynamicPaint);
			CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md);
			return 1;
		}
	}
	else if (CTX_data_equals(member, "line_style")) {
		set_pointer_type(path, result, &RNA_FreestyleLineStyle);
		return 1;
	}
	else {
		return 0; /* not found */
	}

	return -1; /* found but not available */
}
static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par,
                                 int heat, const bool mirror)
{
	/* This functions implements the automatic computation of vertex group
	 * weights, either through envelopes or using a heat equilibrium.
	 *
	 * This function can be called both when parenting a mesh to an armature,
	 * or in weightpaint + posemode. In the latter case selection is taken
	 * into account and vertex weights can be mirrored.
	 *
	 * The mesh vertex positions used are either the final deformed coords
	 * from the derivedmesh in weightpaint mode, the final subsurf coords
	 * when parenting, or simply the original mesh coords.
	 */

	bArmature *arm = par->data;
	Bone **bonelist, *bone;
	bDeformGroup **dgrouplist, **dgroupflip;
	bDeformGroup *dgroup;
	bPoseChannel *pchan;
	Mesh *mesh;
	Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL;
	float (*root)[3], (*tip)[3], (*verts)[3];
	int *selected;
	int numbones, vertsfilled = 0, i, j, segments = 0;
	int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
	struct { Object *armob; void *list; int heat; } looper_data;

	looper_data.armob = par;
	looper_data.heat = heat;
	looper_data.list = NULL;

	/* count the number of skinnable bones */
	numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
	
	if (numbones == 0)
		return;
	
	if (BKE_object_defgroup_data_create(ob->data) == NULL)
		return;

	/* create an array of pointer to bones that are skinnable
	 * and fill it with all of the skinnable bones */
	bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
	looper_data.list = bonelist;
	bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);

	/* create an array of pointers to the deform groups that
	 * correspond to the skinnable bones (creating them
	 * as necessary. */
	dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
	dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip");

	looper_data.list = dgrouplist;
	bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);

	/* create an array of root and tip positions transformed into
	 * global coords */
	root = MEM_callocN(numbones * sizeof(float) * 3, "root");
	tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
	selected = MEM_callocN(numbones * sizeof(int), "selected");

	for (j = 0; j < numbones; ++j) {
		bone = bonelist[j];
		dgroup = dgrouplist[j];
		
		/* handle bbone */
		if (heat) {
			if (segments == 0) {
				segments = 1;
				bbone = NULL;
				
				if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
					if (bone->segments > 1) {
						segments = bone->segments;
						b_bone_spline_setup(pchan, 1, bbone_array);
						bbone = bbone_array;
					}
				}
			}
			
			segments--;
		}
		
		/* compute root and tip */
		if (bbone) {
			mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
			if ((segments + 1) < bone->segments) {
				mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
			}
			else {
				copy_v3_v3(tip[j], bone->arm_tail);
			}
		}
		else {
			copy_v3_v3(root[j], bone->arm_head);
			copy_v3_v3(tip[j], bone->arm_tail);
		}
		
		mul_m4_v3(par->obmat, root[j]);
		mul_m4_v3(par->obmat, tip[j]);
		
		/* set selected */
		if (wpmode) {
			if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
				selected[j] = 1;
		}
		else
			selected[j] = 1;
		
		/* find flipped group */
		if (dgroup && mirror) {
			char name_flip[MAXBONENAME];

			BKE_deform_flip_side_name(name_flip, dgroup->name, false);
			dgroupflip[j] = defgroup_find_name(ob, name_flip);
		}
	}

	/* create verts */
	mesh = (Mesh *)ob->data;
	verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");

	if (wpmode) {
		/* if in weight paint mode, use final verts from derivedmesh */
		DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
		
		if (dm->foreachMappedVert) {
			mesh_get_mapped_verts_coords(dm, verts, mesh->totvert);
			vertsfilled = 1;
		}
		
		dm->release(dm);
	}
	else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
		/* is subsurf on? Lets use the verts on the limit surface then.
		 * = same amount of vertices as mesh, but vertices  moved to the
		 * subsurfed position, like for 'optimal'. */
		subsurf_calculate_limit_positions(mesh, verts);
		vertsfilled = 1;
	}

	/* transform verts to global space */
	for (i = 0; i < mesh->totvert; i++) {
		if (!vertsfilled)
			copy_v3_v3(verts[i], mesh->mvert[i].co);
		mul_m4_v3(ob->obmat, verts[i]);
	}

	/* compute the weights based on gathered vertices and bones */
	if (heat) {
		const char *error = NULL;

		heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
		                    root, tip, selected, &error);
		if (error) {
			BKE_report(reports, RPT_WARNING, error);
		}
	}
	else {
		envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
		                        dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
	}

	/* only generated in some cases but can call anyway */
	ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');

	/* free the memory allocated */
	MEM_freeN(bonelist);
	MEM_freeN(dgrouplist);
	MEM_freeN(dgroupflip);
	MEM_freeN(root);
	MEM_freeN(tip);
	MEM_freeN(selected);
	MEM_freeN(verts);
}
Exemplo n.º 29
0
static int bake(
        Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
        const ScenePassType pass_type, const int margin,
        const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials,
        const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage,
        const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[],
        const char *custom_cage, const char *filepath, const int width, const int height,
        const char *identifier, ScrArea *sa, const char *uv_layer)
{
	int op_result = OPERATOR_CANCELLED;
	bool ok = false;

	Object *ob_cage = NULL;

	BakeHighPolyData *highpoly = NULL;
	int tot_highpoly = 0;

	char restrict_flag_low = ob_low->restrictflag;
	char restrict_flag_cage = 0;

	Mesh *me_low = NULL;
	Mesh *me_cage = NULL;

	float *result = NULL;

	BakePixel *pixel_array_low = NULL;
	BakePixel *pixel_array_high = NULL;

	const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL);
	const bool is_noncolor = is_noncolor_pass(pass_type);
	const int depth = RE_pass_depth(pass_type);

	BakeImages bake_images = {NULL};

	size_t num_pixels;
	int tot_materials;

	RE_bake_engine_set_engine_parameters(re, bmain, scene);

	if (!RE_bake_has_engine(re)) {
		BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
		goto cleanup;
	}

	tot_materials = ob_low->totcol;

	if (uv_layer && uv_layer[0] != '\0') {
		Mesh *me = (Mesh *)ob_low->data;
		if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) {
			BKE_reportf(reports, RPT_ERROR,
			            "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2);
			goto cleanup;
		}
	}

	if (tot_materials == 0) {
		if (is_save_internal) {
			BKE_report(reports, RPT_ERROR,
			           "No active image found, add a material or bake to an external file");

			goto cleanup;
		}
		else if (is_split_materials) {
			BKE_report(reports, RPT_ERROR,
			           "No active image found, add a material or bake without the Split Materials option");

			goto cleanup;
		}
		else {
			/* baking externally without splitting materials */
			tot_materials = 1;
		}
	}

	/* we overallocate in case there is more materials than images */
	bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)");
	bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)");

	build_image_lookup(bmain, ob_low, &bake_images);

	if (is_save_internal) {
		num_pixels = initialize_internal_images(&bake_images, reports);

		if (num_pixels == 0) {
			goto cleanup;
		}
	}
	else {
		/* when saving extenally always use the size specified in the UI */

		num_pixels = (size_t)width * (size_t)height * bake_images.size;

		for (int i = 0; i < bake_images.size; i++) {
			bake_images.data[i].width = width;
			bake_images.data[i].height = height;
			bake_images.data[i].offset = (is_split_materials ? num_pixels : 0);
			bake_images.data[i].image = NULL;
		}

		if (!is_split_materials) {
			/* saving a single image */
			for (int i = 0; i < tot_materials; i++) {
				bake_images.lookup[i] = 0;
			}
		}
	}

	if (is_selected_to_active) {
		CollectionPointerLink *link;
		tot_highpoly = 0;

		for (link = selected_objects->first; link; link = link->next) {
			Object *ob_iter = link->ptr.data;

			if (ob_iter == ob_low)
				continue;

			tot_highpoly ++;
		}

		if (is_cage && custom_cage[0] != '\0') {
			ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2);

			if (ob_cage == NULL || ob_cage->type != OB_MESH) {
				BKE_report(reports, RPT_ERROR, "No valid cage object");
				goto cleanup;
			}
			else {
				restrict_flag_cage = ob_cage->restrictflag;
				ob_cage->restrictflag |= OB_RESTRICT_RENDER;
			}
		}
	}

	pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
	pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
	result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");

	/* get the mesh as it arrives in the renderer */
	me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
	BKE_mesh_split_faces(me_low);

	/* populate the pixel array with the face data */
	if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
		RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer);
	/* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh)  */

	if (is_selected_to_active) {
		CollectionPointerLink *link;
		ModifierData *md, *nmd;
		ListBase modifiers_tmp, modifiers_original;
		int i = 0;

		/* prepare cage mesh */
		if (ob_cage) {
			me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0);
			BKE_mesh_split_faces(me_cage);
			if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) {
				BKE_report(reports, RPT_ERROR,
				           "Invalid cage object, the cage mesh must have the same number "
				           "of faces as the active object");
				goto cleanup;
			}
		}
		else if (is_cage) {
			modifiers_original = ob_low->modifiers;
			BLI_listbase_clear(&modifiers_tmp);

			for (md = ob_low->modifiers.first; md; md = md->next) {
				/* Edge Split cannot be applied in the cage,
				 * the cage is supposed to have interpolated normals
				 * between the faces unless the geometry is physically
				 * split. So we create a copy of the low poly mesh without
				 * the eventual edge split.*/

				if (md->type == eModifierType_EdgeSplit)
					continue;

				nmd = modifier_new(md->type);
				BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
				modifier_copyData(md, nmd);
				BLI_addtail(&modifiers_tmp, nmd);
			}

			/* temporarily replace the modifiers */
			ob_low->modifiers = modifiers_tmp;

			/* get the cage mesh as it arrives in the renderer */
			me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
			BKE_mesh_split_faces(me_cage);
			RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
		}

		highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects");

		/* populate highpoly array */
		for (link = selected_objects->first; link; link = link->next) {
			TriangulateModifierData *tmd;
			Object *ob_iter = link->ptr.data;

			if (ob_iter == ob_low)
				continue;

			/* initialize highpoly_data */
			highpoly[i].ob = ob_iter;
			highpoly[i].restrict_flag = ob_iter->restrictflag;

			/* triangulating so BVH returns the primitive_id that will be used for rendering */
			highpoly[i].tri_mod = ED_object_modifier_add(
			        reports, bmain, scene, highpoly[i].ob,
			        "TmpTriangulate", eModifierType_Triangulate);
			tmd = (TriangulateModifierData *)highpoly[i].tri_mod;
			tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
			tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;

			highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0);
			highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
			BKE_mesh_split_faces(highpoly[i].me);

			/* lowpoly to highpoly transformation matrix */
			copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat);
			invert_m4_m4(highpoly[i].imat, highpoly[i].obmat);

			highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat);

			i++;
		}

		BLI_assert(i == tot_highpoly);

		ob_low->restrictflag |= OB_RESTRICT_RENDER;

		/* populate the pixel arrays with the corresponding face data for each high poly object */
		if (!RE_bake_pixels_populate_from_objects(
		            me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL,
		            cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage))
		{
			BKE_report(reports, RPT_ERROR, "Error handling selected objects");
			goto cage_cleanup;
		}

		/* the baking itself */
		for (i = 0; i < tot_highpoly; i++) {
			ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high,
			                    num_pixels, depth, pass_type, result);
			if (!ok) {
				BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
				goto cage_cleanup;
			}
		}

cage_cleanup:
		/* reverting data back */
		if ((ob_cage == NULL) && is_cage) {
			ob_low->modifiers = modifiers_original;

			while ((md = BLI_pophead(&modifiers_tmp))) {
				modifier_free(md);
			}
		}

		if (!ok) {
			goto cleanup;
		}
	}
	else {
		/* make sure low poly renders */
		ob_low->restrictflag &= ~OB_RESTRICT_RENDER;

		if (RE_bake_has_engine(re)) {
			ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result);
		}
		else {
			BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
			goto cleanup;
		}
	}

	/* normal space conversion
	 * the normals are expected to be in world space, +X +Y +Z */
	if (ok && pass_type == SCE_PASS_NORMAL) {
		switch (normal_space) {
			case R_BAKE_SPACE_WORLD:
			{
				/* Cycles internal format */
				if ((normal_swizzle[0] == R_BAKE_POSX) &&
				    (normal_swizzle[1] == R_BAKE_POSY) &&
				    (normal_swizzle[2] == R_BAKE_POSZ))
				{
					break;
				}
				else {
					RE_bake_normal_world_to_world(pixel_array_low, num_pixels,  depth, result, normal_swizzle);
				}
				break;
			}
			case R_BAKE_SPACE_OBJECT:
			{
				RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle);
				break;
			}
			case R_BAKE_SPACE_TANGENT:
			{
				if (is_selected_to_active) {
					RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat);
				}
				else {
					/* from multiresolution */
					Mesh *me_nores = NULL;
					ModifierData *md = NULL;
					int mode;

					md = modifiers_findByType(ob_low, eModifierType_Multires);

					if (md) {
						mode = md->mode;
						md->mode &= ~eModifierMode_Render;
					}

					me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
					BKE_mesh_split_faces(me_nores);
					RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);

					RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
					BKE_libblock_free(bmain, me_nores);

					if (md)
						md->mode = mode;
				}
				break;
			}
			default:
				break;
		}
	}

	if (!ok) {
		BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2);
		op_result = OPERATOR_CANCELLED;
	}
	else {
		/* save the results */
		for (int i = 0; i < bake_images.size; i++) {
			BakeImage *bk_image = &bake_images.data[i];

			if (is_save_internal) {
				ok = write_internal_bake_pixels(
				         bk_image->image,
				         pixel_array_low + bk_image->offset,
				         result + bk_image->offset * depth,
				         bk_image->width, bk_image->height,
				         margin, is_clear, is_noncolor);

				/* might be read by UI to set active image for display */
				bake_update_image(sa, bk_image->image);

				if (!ok) {
					BKE_reportf(reports, RPT_ERROR,
					           "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2);
					op_result = OPERATOR_CANCELLED;
				}
				else {
					BKE_report(reports, RPT_INFO,
					           "Baking map saved to internal image, save it externally or pack it");
					op_result = OPERATOR_FINISHED;
				}
			}
			/* save externally */
			else {
				BakeData *bake = &scene->r.bake;
				char name[FILE_MAX];

				BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL);

				if (is_automatic_name) {
					BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
					BLI_path_suffix(name, FILE_MAX, identifier, "_");
				}

				if (is_split_materials) {
					if (bk_image->image) {
						BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_");
					}
					else {
						if (ob_low->mat[i]) {
							BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_");
						}
						else if (me_low->mat[i]) {
							BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_");
						}
						else {
							/* if everything else fails, use the material index */
							char tmp[4];
							sprintf(tmp, "%d", i % 1000);
							BLI_path_suffix(name, FILE_MAX, tmp, "_");
						}
					}
				}

				/* save it externally */
				ok = write_external_bake_pixels(
				        name,
				        pixel_array_low + bk_image->offset,
				        result + bk_image->offset * depth,
				        bk_image->width, bk_image->height,
				        margin, &bake->im_format, is_noncolor);

				if (!ok) {
					BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
					op_result = OPERATOR_CANCELLED;
				}
				else {
					BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name);
					op_result = OPERATOR_FINISHED;
				}

				if (!is_split_materials) {
					break;
				}
			}
		}
	}

	if (is_save_internal)
		refresh_images(&bake_images);

cleanup:

	if (highpoly) {
		int i;
		for (i = 0; i < tot_highpoly; i++) {
			highpoly[i].ob->restrictflag = highpoly[i].restrict_flag;

			if (highpoly[i].tri_mod)
				ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod);

			if (highpoly[i].me)
				BKE_libblock_free(bmain, highpoly[i].me);
		}
		MEM_freeN(highpoly);
	}

	ob_low->restrictflag = restrict_flag_low;

	if (ob_cage)
		ob_cage->restrictflag = restrict_flag_cage;

	if (pixel_array_low)
		MEM_freeN(pixel_array_low);

	if (pixel_array_high)
		MEM_freeN(pixel_array_high);

	if (bake_images.data)
		MEM_freeN(bake_images.data);

	if (bake_images.lookup)
		MEM_freeN(bake_images.lookup);

	if (result)
		MEM_freeN(result);

	if (me_low)
		BKE_libblock_free(bmain, me_low);

	if (me_cage)
		BKE_libblock_free(bmain, me_cage);

	return op_result;
}
Exemplo n.º 30
0
static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
{
	Scene *scene= CTX_data_scene(C);
	int i;
	FluidsimSettings *domainSettings;

	char debugStrBuffer[256];
	
	int gridlevels = 0;
	const char *relbase= modifier_path_relbase(fsDomain);
	const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
	const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
	const char *suffixSurface = FLUID_SUFFIX_SURFACE;

	char targetDir[FILE_MAX];  // store & modify output settings
	char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
	int  outStringsChanged = 0;             // modified? copy back before baking

	float domainMat[4][4];
	float invDomMat[4][4];

	int noFrames;
	int origFrame = scene->r.cfra;
	
	FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels");
	ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects");
	FluidsimModifierData *fluidmd = NULL;
	Mesh *mesh = NULL;

	FluidBakeJob *fb;
	elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings");

	fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
	
	if (getenv(strEnvName)) {
		int dlevel = atoi(getenv(strEnvName));
		elbeemSetDebugLevel(dlevel);
		BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", strEnvName);
		elbeemDebugOut(debugStrBuffer);
	}
	
	/* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */;
	noFrames = scene->r.efra - 0;
	if (noFrames<=0) {
		BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)");
		fluidbake_free_data(channels, fobjects, fsset, fb);
		return 0;
	}
	
	/* check scene for sane object/modifier settings */
	if (!fluid_validate_scene(reports, scene, fsDomain)) {
		fluidbake_free_data(channels, fobjects, fsset, fb);
		return 0;
	}
	
	/* these both have to be valid, otherwise we wouldn't be here */
	fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
	domainSettings = fluidmd->fss;
	mesh = fsDomain->data;
	
	domainSettings->bakeStart = 1;
	domainSettings->bakeEnd = scene->r.efra;
	
	// calculate bounding box
	fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize);
	
	// reset last valid frame
	domainSettings->lastgoodframe = -1;

	/* delete old baked files */
	fluidsim_delete_until_lastframe(domainSettings, relbase);
	
	/* rough check of settings... */
	if (domainSettings->previewresxyz > domainSettings->resolutionxyz) {
		BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz,  domainSettings->resolutionxyz);
		elbeemDebugOut(debugStrBuffer);
		domainSettings->previewresxyz = domainSettings->resolutionxyz;
	}
	// set adaptive coarsening according to resolutionxyz
	// this should do as an approximation, with in/outflow
	// doing this more accurate would be overkill
	// perhaps add manual setting?
	if (domainSettings->maxRefine <0) {
		if (domainSettings->resolutionxyz>128) {
			gridlevels = 2;
		}
		else if (domainSettings->resolutionxyz > 64) {
			gridlevels = 1;
		}
		else {
			gridlevels = 0;
		}
	}
	else {
		gridlevels = domainSettings->maxRefine;
	}
	BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name, gridlevels);
	elbeemDebugOut(debugStrBuffer);
	
	
	
	/* ******** prepare output file paths ******** */
	outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer);
	channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra)
	channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames;
	
	/* ******** initialize and allocate animation channels ******** */
	fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects);

	/* reset to original current frame */
	scene->r.cfra = origFrame;
	ED_update_for_newframe(CTX_data_main(C), scene, 1);
		
	/* ******** init domain object's matrix ******** */
	copy_m4_m4(domainMat, fsDomain->obmat);
	if (!invert_m4_m4(invDomMat, domainMat)) {
		BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n");
		elbeemDebugOut(debugStrBuffer);
		BKE_report(reports, RPT_ERROR, "Invalid object matrix"); 

		fluidbake_free_data(channels, fobjects, fsset, fb);
		return 0;
	}

	/* ********  start writing / exporting ******** */
	// use .tmp, don't overwrite/delete original file
	BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
	
	// make sure these directories exist as well
	if (outStringsChanged) {
		BLI_make_existing_file(targetFile);
	}

	/* ******** export domain to elbeem ******** */
	elbeemResetSettings(fsset);
	fsset->version = 1;
	fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : domainSettings->threads;
	// setup global settings
	copy_v3_v3(fsset->geoStart, domainSettings->bbStart);
	copy_v3_v3(fsset->geoSize, domainSettings->bbSize);
	
	// simulate with 50^3
	fsset->resolutionxyz = (int)domainSettings->resolutionxyz;
	fsset->previewresxyz = (int)domainSettings->previewresxyz;

	fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
	fsset->viscosity = get_fluid_viscosity(domainSettings);
	get_fluid_gravity(fsset->gravity, scene, domainSettings);

	// simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
	fsset->animStart = domainSettings->animStart;
	fsset->aniFrameTime = channels->aniFrameTime;
	fsset->noOfFrames = noFrames; // is otherwise subtracted in parser

	BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);

	// defaults for compressibility and adaptive grids
	fsset->gstar = domainSettings->gstar;
	fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
	fsset->generateParticles = domainSettings->generateParticles; 
	fsset->numTracerParticles = domainSettings->generateTracers; 
	fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; 
	fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; 
	fsset->farFieldSize = domainSettings->farFieldSize; 
	BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));

	// domain channels
	fsset->channelSizeFrameTime = 
	fsset->channelSizeViscosity = 
	fsset->channelSizeGravity = channels->length;
	fsset->channelFrameTime = channels->DomainTime;
	fsset->channelViscosity = channels->DomainViscosity;
	fsset->channelGravity = channels->DomainGravity;
	
	fsset->runsimCallback = &runSimulationCallback;
	fsset->runsimUserData = fb;

	if (domainSettings->typeFlags & OB_FSBND_NOSLIP)		fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
	else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP)	fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
	else if (domainSettings->typeFlags&OB_FSBND_FREESLIP)	fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
	fsset->domainobsPartslip = domainSettings->partSlipValue;

	/* use domainobsType also for surface generation flag (bit: >=64) */
	if (domainSettings->typeFlags & OB_FSSG_NOOBS)
		fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS;
	else
		fsset->mFsSurfGenSetting = 0; // "normal" mode

	fsset->generateVertexVectors = (domainSettings->domainNovecgen==0);

	// init blender domain transform matrix
	{ int j;
	for (i=0; i<4; i++) {
		for (j=0; j<4; j++) {
			fsset->surfaceTrafo[i*4+j] = invDomMat[j][i];
		}
	} }

	/* ******** init solver with settings ******** */
	elbeemInit();
	elbeemAddDomain(fsset);
	
	/* ******** export all fluid objects to elbeem ******** */
	export_fluid_objects(fobjects, scene, channels->length);
	
	/* custom data for fluid bake job */
	fb->settings = fsset;
	
	if (do_job) {
		wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation",
		                            WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_FLUID);

		/* setup job */
		WM_jobs_customdata_set(wm_job, fb, fluidbake_free);
		WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
		WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob);

		WM_jobs_start(CTX_wm_manager(C), wm_job);
	}
	else {
		short dummy_stop = 0, dummy_do_update = 0;
		float dummy_progress = 0.0f;

		/* blocking, use with exec() */
		fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress);
		fluidbake_endjob((void *)fb);
		fluidbake_free((void *)fb);
	}

	/* ******** free stored animation data ******** */
	fluidbake_free_data(channels, fobjects, NULL, NULL);

	// elbeemFree();
	return 1;
}