Beispiel #1
0
void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, int method)
{
	Object *ob= CTX_data_active_object(C);
	wmJob *steve;
	ShaderPreview *sp;

	steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview", WM_JOB_EXCL_RENDER);
	sp= MEM_callocN(sizeof(ShaderPreview), "shader preview");

	/* customdata for preview thread */
	sp->scene= CTX_data_scene(C);
	sp->owner= owner;
	sp->sizex= sizex;
	sp->sizey= sizey;
	sp->pr_method= method;
	sp->id = id;
	sp->parent= parent;
	sp->slot= slot;
	if(ob && ob->totcol) copy_v4_v4(sp->col, ob->col);
	else sp->col[0]= sp->col[1]= sp->col[2]= sp->col[3]= 1.0f;
	
	/* setup job */
	WM_jobs_customdata(steve, sp, shader_preview_free);
	WM_jobs_timer(steve, 0.1, NC_MATERIAL, NC_MATERIAL);
	WM_jobs_callbacks(steve, common_preview_startjob, NULL, shader_preview_updatejob, NULL);
	
	WM_jobs_start(CTX_wm_manager(C), steve);
}
Beispiel #2
0
void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey)
{
	wmJob *steve;
	IconPreview *ip, *old_ip;
	
	/* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
	steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview", WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND);

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

	/* render all resolutions from suspended job too */
	old_ip = WM_jobs_get_customdata(steve);
	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(steve, ip, icon_preview_free);
	WM_jobs_timer(steve, 0.25, NC_MATERIAL, NC_MATERIAL);
	WM_jobs_callbacks(steve, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);

	WM_jobs_start(CTX_wm_manager(C), steve);
}
Beispiel #3
0
void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey)
{
	wmJob *steve;
	ShaderPreview *sp;
	
	/* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
	steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview", WM_JOB_EXCL_RENDER|WM_JOB_SUSPEND);
	sp= MEM_callocN(sizeof(ShaderPreview), "shader preview");

	/* customdata for preview thread */
	sp->scene= CTX_data_scene(C);
	sp->owner= id;
	sp->sizex= sizex;
	sp->sizey= sizey;
	sp->pr_method= PR_ICON_RENDER;
	sp->pr_rect= rect;
	sp->id = id;

	/* setup job */
	WM_jobs_customdata(steve, sp, shader_preview_free);
	WM_jobs_timer(steve, 0.25, NC_MATERIAL, NC_MATERIAL);
	WM_jobs_callbacks(steve, common_preview_startjob, NULL, NULL, common_preview_endjob);

	WM_jobs_start(CTX_wm_manager(C), steve);
}
Beispiel #4
0
void thumbnails_start(struct FileList* filelist, const struct bContext* C)
{
	wmJob *steve;
	ThumbnailJob *tj;
	int idx;
	
	/* prepare job data */
	tj= MEM_callocN(sizeof(ThumbnailJob), "thumbnails\n");
	tj->filelist = filelist;
	for (idx = 0; idx < filelist->numfiles;idx++) {
		if (!filelist->filelist[idx].image) {
			if ( (filelist->filelist[idx].flags & (IMAGEFILE|MOVIEFILE|BLENDERFILE)) ) {
				FileImage* limg = MEM_callocN(sizeof(struct FileImage), "loadimage");
				BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX);
				limg->index= idx;
				limg->flags= filelist->filelist[idx].flags;
				BLI_addtail(&tj->loadimages, limg);
			}
		}
	}

	BKE_reports_init(&tj->reports, RPT_PRINT);

	/* setup job */
	steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, "Thumbnails", 0);
	WM_jobs_customdata(steve, tj, thumbnails_free);
	WM_jobs_timer(steve, 0.5, NC_WINDOW, NC_WINDOW);
	WM_jobs_callbacks(steve, thumbnails_startjob, NULL, thumbnails_update, NULL);

	/* start the job */
	WM_jobs_start(CTX_wm_manager(C), steve);
}
Beispiel #5
0
void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, rcti *rect)
{
  if (idp) {
    wmWindowManager *wm = CTX_wm_manager(C);
    ScrArea *sa = CTX_wm_area(C);
    ID *id = (ID *)idp;
    ID *parent = (ID *)parentp;
    MTex *slot = (MTex *)slotp;
    SpaceProperties *sbuts = CTX_wm_space_properties(C);
    ShaderPreview *sp = WM_jobs_customdata(wm, sa);
    rcti newrect;
    int ok;
    int newx = BLI_rcti_size_x(rect);
    int newy = BLI_rcti_size_y(rect);

    newrect.xmin = rect->xmin;
    newrect.xmax = rect->xmin;
    newrect.ymin = rect->ymin;
    newrect.ymax = rect->ymin;

    if (parent) {
      ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect);
      ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect);
    }
    else {
      ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect);
    }

    if (ok) {
      *rect = newrect;
    }

    /* start a new preview render job if signaled through sbuts->preview,
     * if no render result was found and no preview render job is running,
     * or if the job is running and the size of preview changed */
    if ((sbuts != NULL && sbuts->preview) ||
        (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW)) ||
        (sp && (ABS(sp->sizex - newx) >= 2 || ABS(sp->sizey - newy) > 2))) {
      if (sbuts != NULL) {
        sbuts->preview = 0;
      }
      ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER);
    }
  }
}
Beispiel #6
0
static int screencast_exec(bContext *C, wmOperator *op)
{
	bScreen *screen = CTX_wm_screen(C);
	wmJob *steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, "Screencast", 0);
	ScreenshotJob *sj = MEM_callocN(sizeof(ScreenshotJob), "screenshot job");

	/* setup sj */
	if (RNA_boolean_get(op->ptr, "full")) {
		wmWindow *win = CTX_wm_window(C);
		sj->x = 0;
		sj->y = 0;
		sj->dumpsx = win->sizex;
		sj->dumpsy = win->sizey;
	} 
	else {
		ScrArea *curarea = CTX_wm_area(C);
		sj->x = curarea->totrct.xmin;
		sj->y = curarea->totrct.ymin;
		sj->dumpsx = curarea->totrct.xmax - sj->x;
		sj->dumpsy = curarea->totrct.ymax - sj->y;
	}
	sj->bmain = CTX_data_main(C);
	sj->scene = CTX_data_scene(C);

	BKE_reports_init(&sj->reports, RPT_PRINT);

	/* setup job */
	WM_jobs_customdata(steve, sj, screenshot_freejob);
	WM_jobs_timer(steve, 0.1, 0, NC_SCREEN | ND_SCREENCAST);
	WM_jobs_callbacks(steve, screenshot_startjob, NULL, screenshot_updatejob, NULL);
	
	WM_jobs_start(CTX_wm_manager(C), steve);
	
	WM_event_add_notifier(C, NC_SCREEN | ND_SCREENCAST, screen);
	
	return OPERATOR_FINISHED;
}
Beispiel #7
0
static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
{
    wmJob * steve;
    ProxyJob *pj;
    Scene *scene = CTX_data_scene(C);
    ScrArea *sa = CTX_wm_area(C);
    SpaceClip *sc = CTX_wm_space_clip(C);
    MovieClip *clip = ED_space_clip_get_clip(sc);

    if ((clip->flag & MCLIP_USE_PROXY) == 0)
        return OPERATOR_CANCELLED;

    steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies", WM_JOB_PROGRESS);

    pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
    pj->scene = scene;
    pj->main = CTX_data_main(C);
    pj->clip = clip;
    pj->clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;

    if (clip->anim) {
        pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag,
                            clip->proxy.build_size_flag, clip->proxy.quality);
    }

    WM_jobs_customdata(steve, pj, proxy_freejob);
    WM_jobs_timer(steve, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
    WM_jobs_callbacks(steve, proxy_startjob, NULL, NULL, proxy_endjob);

    G.afbreek = 0;
    WM_jobs_start(CTX_wm_manager(C), steve);

    ED_area_tag_redraw(CTX_wm_area(C));

    return OPERATOR_FINISHED;
}
Beispiel #8
0
static int ocean_bake_exec(bContext *C, wmOperator *op)
{
	Object *ob = ED_object_active_context(C);
	OceanModifierData *omd = (OceanModifierData *)edit_modifier_property_get(op, ob, eModifierType_Ocean);
	Scene *scene = CTX_data_scene(C);
	OceanCache *och;
	struct Ocean *ocean;
	int f, cfra, i=0;
	int free= RNA_boolean_get(op->ptr, "free");
	
	wmJob *steve;
	OceanBakeJob *oj;
	
	if (!omd)
		return OPERATOR_CANCELLED;
	
	if (free) {
		omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE;
		DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
		WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
		return OPERATOR_FINISHED;
	}

	och = BKE_init_ocean_cache(omd->cachepath, modifier_path_relbase(ob),
	                           omd->bakestart, omd->bakeend, omd->wave_scale,
	                           omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
	
	och->time = MEM_mallocN(och->duration*sizeof(float), "foam bake time");
	
	cfra = scene->r.cfra;
	
	/* precalculate time variable before baking */
	for (f=omd->bakestart; f<=omd->bakeend; f++) {
		/* from physics_fluid.c:
		 
		 * XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation,
		 * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ )
		 * --> BKE_animsys_evaluate_all_animation(G.main, eval_time);
		 * This doesn't work with drivers:
		 * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL);
		 */
		
		/* Modifying the global scene isn't nice, but we can do it in 
		 * this part of the process before a threaded job is created */
		
		//scene->r.cfra = f;
		//ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1);
		
		/* ok, this doesn't work with drivers, but is way faster. 
		 * let's use this for now and hope nobody wants to drive the time value... */
		BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM);
		
		och->time[i] = omd->time;
		i++;
	}
	
	/* make a copy of ocean to use for baking - threadsafety */
	ocean = BKE_add_ocean();
	init_ocean_modifier_bake(ocean, omd);
	
	/*
	 BKE_bake_ocean(ocean, och);
	
	omd->oceancache = och;
	omd->cached = TRUE;
	
	scene->r.cfra = cfra;
	
	DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
	*/
	
	/* job stuff */
	
	scene->r.cfra = cfra;
	
	/* setup job */
	steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation", WM_JOB_PROGRESS);
	oj= MEM_callocN(sizeof(OceanBakeJob), "ocean bake job");
	oj->ocean = ocean;
	oj->och = och;
	oj->omd = omd;
	
	WM_jobs_customdata(steve, oj, oceanbake_free);
	WM_jobs_timer(steve, 0.1, NC_OBJECT|ND_MODIFIER, NC_OBJECT|ND_MODIFIER);
	WM_jobs_callbacks(steve, oceanbake_startjob, NULL, NULL, oceanbake_endjob);
	
	WM_jobs_start(CTX_wm_manager(C), steve);
	
	
	
	return OPERATOR_FINISHED;
}
Beispiel #9
0
/* using context, starts job */
static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
	/* new render clears all callbacks */
	Main *mainp;
	Scene *scene= CTX_data_scene(C);
	SceneRenderLayer *srl=NULL;
	bScreen *screen= CTX_wm_screen(C);
	View3D *v3d= CTX_wm_view3d(C);
	Render *re;
	wmJob *steve;
	RenderJob *rj;
	Image *ima;
	int jobflag;
	const short is_animation= RNA_boolean_get(op->ptr, "animation");
	const short is_write_still= RNA_boolean_get(op->ptr, "write_still");
	struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
	
	/* only one render job at a time */
	if(WM_jobs_test(CTX_wm_manager(C), scene))
		return OPERATOR_CANCELLED;

	if(!RE_is_rendering_allowed(scene, camera_override, op->reports)) {
		return OPERATOR_CANCELLED;
	}

	if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) {
		BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected.");
		return OPERATOR_CANCELLED;
	}	
	
	/* stop all running jobs, currently previews frustrate Render */
	WM_jobs_stop_all(CTX_wm_manager(C));

	/* get main */
	if(G.rt == 101) {
		/* thread-safety experiment, copy main from the undo buffer */
		mainp= BKE_undo_get_main(&scene);
	}
	else
		mainp= CTX_data_main(C);

	/* cancel animation playback */
	if (screen->animtimer)
		ED_screen_animation_play(C, 0, 0);
	
	/* handle UI stuff */
	WM_cursor_wait(1);

	/* flush multires changes (for sculpt) */
	multires_force_render_update(CTX_data_active_object(C));

	/* cleanup sequencer caches before starting user triggered render.
	   otherwise, invalidated cache entries can make their way into
	   the output rendering. We can't put that into RE_BlenderFrame,
	   since sequence rendering can call that recursively... (peter) */
	seq_stripelem_cache_cleanup();

	/* get editmode results */
	ED_object_exit_editmode(C, 0);	/* 0 = does not exit editmode */

	// store spare
	// get view3d layer, local layer, make this nice api call to render
	// store spare

	/* ensure at least 1 area shows result */
	render_view_open(C, event->x, event->y);

	jobflag= WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS;
	
	/* single layer re-render */
	if(RNA_property_is_set(op->ptr, "layer")) {
		SceneRenderLayer *rl;
		Scene *scn;
		char scene_name[MAX_ID_NAME-2], rl_name[RE_MAXNAME];

		RNA_string_get(op->ptr, "layer", rl_name);
		RNA_string_get(op->ptr, "scene", scene_name);

		scn = (Scene *)BLI_findstring(&mainp->scene, scene_name, offsetof(ID, name) + 2);
		rl = (SceneRenderLayer *)BLI_findstring(&scene->r.layers, rl_name, offsetof(SceneRenderLayer, name));
		
		if (scn && rl) {
			/* camera switch wont have updated */
			scn->r.cfra= scene->r.cfra;
			scene_camera_switch_update(scn);

			scene = scn;
			srl = rl;
		}
		jobflag |= WM_JOB_SUSPEND;
	}

	/* job custom data */
	rj= MEM_callocN(sizeof(RenderJob), "render job");
	rj->main= mainp;
	rj->scene= scene;
	rj->win= CTX_wm_window(C);
	rj->srl = srl;
	rj->camera_override = camera_override;
	rj->lay = (v3d)? v3d->lay: scene->lay;
	rj->anim= is_animation;
	rj->write_still= is_write_still && !is_animation;
	rj->iuser.scene= scene;
	rj->iuser.ok= 1;
	rj->reports= op->reports;

	/* setup job */
	steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Render", jobflag);
	WM_jobs_customdata(steve, rj, render_freejob);
	WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
	WM_jobs_callbacks(steve, render_startjob, NULL, NULL, render_endjob);

	/* get a render result image, and make sure it is empty */
	ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
	BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
	BKE_image_backup_render(rj->scene, ima);
	rj->image= ima;

	/* setup new render */
	re= RE_NewRender(scene->id.name);
	RE_test_break_cb(re, rj, render_breakjob);
	RE_draw_lock_cb(re, rj, render_drawlock);
	RE_display_draw_cb(re, rj, image_rect_update);
	RE_stats_draw_cb(re, rj, image_renderinfo_cb);
	RE_progress_cb(re, rj, render_progress_update);

	rj->re= re;
	G.afbreek= 0;

	WM_jobs_start(CTX_wm_manager(C), steve);

	WM_cursor_wait(0);
	WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);

	/* we set G.rendering here already instead of only in the job, this ensure
	   main loop or other scene updates are disabled in time, since they may
	   have started before the job thread */
	G.rendering = 1;

	/* add modal handler for ESC */
	WM_event_add_modal_handler(C, op);

	return OPERATOR_RUNNING_MODAL;
}
Beispiel #10
0
int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
{
	Scene *scene= CTX_data_scene(C);
	int i;
	FluidsimSettings *domainSettings;

	char debugStrBuffer[256];
	
	int gridlevels = 0;
	const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
	const char *suffixConfig = FLUID_SUFFIX_CONFIG;
	const char *suffixSurface = FLUID_SUFFIX_SURFACE;

	char targetDir[FILE_MAXDIR+FILE_MAXFILE];  // store & modify output settings
	char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // 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;
	
	wmJob *steve;
	FluidBakeJob *fb;
	elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings");
	
	steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS);
	fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
	
	if(getenv(strEnvName)) {
		int dlevel = atoi(getenv(strEnvName));
		elbeemSetDebugLevel(dlevel);
		snprintf(debugStrBuffer,256,"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 wouldnt 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;
	
	/* rough check of settings... */
	if(domainSettings->previewresxyz > domainSettings->resolutionxyz) {
		snprintf(debugStrBuffer,256,"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;
	}
	snprintf(debugStrBuffer,256,"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;
	channels->aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames;
	
	/* ******** initialise 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, CTX_wm_screen(C), 1);
	
	
	/* ---- XXX: No Time animation curve for now, leaving this code here for reference 
	 
	{ int timeIcu[1] = { FLUIDSIM_TIME };
		float timeDef[1] = { 1. };

		// time channel is a bit special, init by hand...
		timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex");
		for(i=0; i<=scene->r.efra; i++) {
			timeAtIndex[i] = (float)(i-startFrame);
		}
		fluidsimInitChannel(scene, &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
		// time channel is a multiplicator for 
		if(channelDomainTime) {
			for(i=0; i<allchannelSize; i++) { 
				channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0]; 
				if(channelDomainTime[i*2+0]<0.) channelDomainTime[i*2+0] = 0.;
			}
		}
		timeAtFrame = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatframe");
		timeAtFrame[0] = timeAtFrame[1] = domainSettings->animStart; // start at index 1
		if(channelDomainTime) {
			for(i=2; i<=allchannelSize; i++) {
				timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0];
			}
		fsset->} else {
			for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; }
		}

	} // domain channel init
	*/
		
	/* ******** init domain object's matrix ******** */
	copy_m4_m4(domainMat, fsDomain->obmat);
	if(!invert_m4_m4(invDomMat, domainMat)) {
		snprintf(debugStrBuffer,256,"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, dont overwrite/delete original file
	BLI_snprintf(targetFile, sizeof(targetFile), "%s%s.tmp", targetDir, suffixConfig);
	
	// make sure these directories exist as well
	if(outStringsChanged) {
		BLI_make_existing_file(targetFile);
	}

	/* ******** export domain to elbeem ******** */
	elbeemResetSettings(fsset);
	fsset->version = 1;

	// 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_snprintf(targetFile, sizeof(targetFile), "%s%s", 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;
	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;
	
	/* setup job */
	WM_jobs_customdata(steve, fb, fluidbake_free);
	WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
	WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
	
	WM_jobs_start(CTX_wm_manager(C), steve);

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

	// elbeemFree();
	return 1;
}