Beispiel #1
0
void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey)
{
	wmJob *wm_job;
	IconPreview *ip, *old_ip;
	
	/* suspended start means it starts after 1 timer step, see WM_jobs_timer below */
	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview",
	                     WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, WM_JOB_TYPE_RENDER_PREVIEW);

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

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

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

	icon_preview_add_size(ip, rect, sizex, sizey);

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

	WM_jobs_start(CTX_wm_manager(C), wm_job);
}
Beispiel #2
0
void clip_start_prefetch_job(const bContext *C)
{
	wmJob *wm_job;
	PrefetchJob *pj;
	SpaceClip *sc = CTX_wm_space_clip(C);

	if (prefetch_check_early_out(C))
		return;

	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Prefetching",
	                     WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_PREFETCH);

	/* create new job */
	pj = MEM_callocN(sizeof(PrefetchJob), "prefetch job");
	pj->clip = ED_space_clip_get_clip(sc);
	pj->start_frame = prefetch_get_start_frame(C);
	pj->current_frame = sc->user.framenr;
	pj->end_frame = prefetch_get_final_frame(C);
	pj->render_size = sc->user.render_size;
	pj->render_flag = sc->user.render_flag;

	WM_jobs_customdata_set(wm_job, pj, prefetch_freejob);
	WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
	WM_jobs_callbacks(wm_job, prefetch_startjob, NULL, NULL, NULL);

	G.is_break = FALSE;

	/* and finally start the job */
	WM_jobs_start(CTX_wm_manager(C), wm_job);
}
Beispiel #3
0
static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
	bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");

	PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
	job->baker = ptcache_baker_create(C, op, all);
	job->baker->bake_job = job;
	job->baker->update_progress = ptcache_job_update;

	wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C),
	                            "Point Cache", WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE);

	WM_jobs_customdata_set(wm_job, job, ptcache_job_free);
	WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE);
	WM_jobs_callbacks(wm_job, ptcache_job_startjob, NULL, NULL, ptcache_job_endjob);

	WM_set_locked_interface(CTX_wm_manager(C), true);

	WM_jobs_start(CTX_wm_manager(C), wm_job);

	WM_event_add_modal_handler(C, op);

	/* we must run modal until the bake job is done, otherwise the undo push
	 * happens before the job ends, which can lead to race conditions between
	 * the baking and file writing code */
	return OPERATOR_RUNNING_MODAL;
}
Beispiel #4
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;
}
Beispiel #5
0
static void render_view3d_do(RenderEngine *engine, const bContext *C)
{
	wmJob *wm_job;
	RenderPreview *rp;
	Scene *scene = CTX_data_scene(C);
	ARegion *ar = CTX_wm_region(C);
	int width = ar->winx, height = ar->winy;
	int divider = 1;
	int resolution_threshold = scene->r.preview_start_resolution *
	                           scene->r.preview_start_resolution;

	if (CTX_wm_window(C) == NULL)
		return;
	if (!render_view3d_flag_changed(engine, C))
		return;

	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview",
	                     WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW);
	rp = MEM_callocN(sizeof(RenderPreview), "render preview");
	rp->job = wm_job;

	while (width * height > resolution_threshold) {
		width = max_ii(1, width / 2);
		height = max_ii(1, height / 2);
		divider *= 2;
	}

	/* customdata for preview thread */
	rp->scene = scene;
	rp->engine = engine;
	rp->sa = CTX_wm_area(C);
	rp->ar = CTX_wm_region(C);
	rp->v3d = rp->sa->spacedata.first;
	rp->rv3d = CTX_wm_region_view3d(C);
	rp->bmain = CTX_data_main(C);
	rp->resolution_divider = divider;
	rp->start_resolution_divider = divider;
	rp->has_freestyle = (scene->r.mode & R_EDGE_FRS) != 0;
	copy_m4_m4(rp->viewmat, rp->rv3d->viewmat);
	
	/* clear info text */
	engine->text[0] = '\0';
	
	/* setup job */
	WM_jobs_customdata_set(wm_job, rp, render_view3d_free);
	WM_jobs_timer(wm_job, 0.1, NC_SPACE | ND_SPACE_VIEW3D, NC_SPACE | ND_SPACE_VIEW3D);
	WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL);
	
	WM_jobs_start(CTX_wm_manager(C), wm_job);
	
	engine->flag &= ~RE_ENGINE_DO_UPDATE;
}
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 *wm_job;
	ShaderPreview *sp;
	Scene *scene = CTX_data_scene(C);
	short id_type = GS(id->name);
	bool use_new_shading = BKE_scene_use_new_shading_nodes(scene);

	/* Only texture node preview is supported with Cycles. */
	if (use_new_shading && method == PR_NODE_RENDER && id_type != ID_TE) {
		return;
	}

	ED_preview_ensure_dbase();

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

	/* customdata for preview thread */
	sp->scene = scene;
	sp->owner = owner;
	sp->sizex = sizex;
	sp->sizey = sizey;
	sp->pr_method = method;
	sp->id = id;
	sp->parent = parent;
	sp->slot = slot;
	sp->bmain = CTX_data_main(C);

	/* hardcoded preview .blend for cycles/internal, this should be solved
	 * once with custom preview .blend path for external engines */
	if ((method != PR_NODE_RENDER) && id_type != ID_TE && use_new_shading) {
		sp->pr_main = G_pr_main_cycles;
	}
	else {
		sp->pr_main = G_pr_main;
	}

	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_set(wm_job, sp, shader_preview_free);
	WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
	WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL);
	
	WM_jobs_start(CTX_wm_manager(C), wm_job);
}
Beispiel #7
0
void ED_preview_icon_job(
    const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey)
{
  wmJob *wm_job;
  IconPreview *ip, *old_ip;

  ED_preview_ensure_dbase();

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

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

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

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

  icon_preview_add_size(ip, rect, sizex, sizey);

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

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

  WM_jobs_start(CTX_wm_manager(C), wm_job);
}
Beispiel #8
0
static int screencast_exec(bContext *C, wmOperator *op)
{
    wmWindowManager *wm = CTX_wm_manager(C);
    wmWindow *win = CTX_wm_window(C);
    bScreen *screen = CTX_wm_screen(C);
    wmJob *wm_job;
    ScreenshotJob *sj;

    /* if called again, stop the running job */
    if (WM_jobs_test(wm, screen, WM_JOB_TYPE_SCREENCAST))
        WM_jobs_stop(wm, screen, screenshot_startjob);

    wm_job = WM_jobs_get(wm, win, screen, "Screencast", 0, WM_JOB_TYPE_SCREENCAST);
    sj = MEM_callocN(sizeof(ScreenshotJob), "screenshot job");

    /* setup sj */
    if (RNA_boolean_get(op->ptr, "full")) {
        sj->x = 0;
        sj->y = 0;
        sj->dumpsx = WM_window_pixels_x(win);
        sj->dumpsy = WM_window_pixels_y(win);
    }
    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);
    sj->wm = wm;

    BKE_reports_init(&sj->reports, RPT_PRINT);

    /* setup job */
    WM_jobs_customdata_set(wm_job, sj, screenshot_freejob);
    WM_jobs_timer(wm_job, 0.1, 0, NC_SCREEN | ND_SCREENCAST);
    WM_jobs_callbacks(wm_job, screenshot_startjob, NULL, screenshot_updatejob, screenshot_endjob);

    WM_jobs_start(sj->wm, wm_job);

    screencast_cursor_toggle(sj->wm, 1);

    WM_event_add_notifier(C, NC_SCREEN | ND_SCREENCAST, screen);

    return OPERATOR_FINISHED;
}
static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
	wmJob *wm_job;
	BakeAPIRender *bkr;
	Render *re;
	Scene *scene = CTX_data_scene(C);

	bake_set_props(op, scene);

	/* only one render job at a time */
	if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE))
		return OPERATOR_CANCELLED;

	bkr = MEM_mallocN(sizeof(BakeAPIRender), "render bake");

	/* init bake render */
	bake_init_api_data(op, C, bkr);
	re = bkr->render;

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

	/* setup job */
	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake",
	                     WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_BAKE);
	WM_jobs_customdata_set(wm_job, bkr, bake_freejob);
	WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */
	WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL);

	G.is_break = false;
	G.is_rendering = true;

	WM_jobs_start(CTX_wm_manager(C), wm_job);

	WM_cursor_wait(0);

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

	WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
	return OPERATOR_RUNNING_MODAL;
}
static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_data)
{
	wmJob *wm_job;
	RenderPreview *rp;
	Scene *scene = CTX_data_scene(C);
	
	if (CTX_wm_window(C) == NULL) {
		engine->flag |= RE_ENGINE_DO_UPDATE;
		return;
	}

	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview",
	                     WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW);
	rp = MEM_callocN(sizeof(RenderPreview), "render preview");
	
	/* customdata for preview thread */
	rp->scene = scene;
	rp->engine = engine;
	rp->sa = CTX_wm_area(C);
	rp->ar = CTX_wm_region(C);
	rp->v3d = rp->sa->spacedata.first;
	rp->rv3d = CTX_wm_region_view3d(C);
	rp->bmain = CTX_data_main(C);
	rp->keep_data = keep_data;
	copy_m4_m4(rp->viewmat, rp->rv3d->viewmat);
	
	/* dont alloc in threads */
	if (engine->text == NULL)
		engine->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
	
	/* setup job */
	WM_jobs_customdata_set(wm_job, rp, render_view3d_free);
	WM_jobs_timer(wm_job, 0.1, NC_SPACE | ND_SPACE_VIEW3D, NC_SPACE | ND_SPACE_VIEW3D);
	WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL);
	
	WM_jobs_start(CTX_wm_manager(C), wm_job);
	
	engine->flag &= ~RE_ENGINE_DO_UPDATE;

}
void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
{
	/* first, get the preview job, if it exists */
	wmJob *wm_job;
	PreviewJob *pj;
	ScrArea *sa = CTX_wm_area(C);
	PreviewJobAudio *audiojob = MEM_callocN(sizeof(PreviewJobAudio), "preview_audio");
	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Strip Previews",
	                     WM_JOB_PROGRESS, WM_JOB_TYPE_SEQ_BUILD_PREVIEW);

	pj = WM_jobs_customdata_get(wm_job);

	if (!pj) {
		pj = MEM_callocN(sizeof(PreviewJob), "preview rebuild job");

		pj->mutex = BLI_mutex_alloc();
		pj->scene = CTX_data_scene(C);

		WM_jobs_customdata_set(wm_job, pj, free_preview_job);
		WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
		WM_jobs_callbacks(wm_job, preview_startjob, NULL, NULL, preview_endjob);
	}

	/* attempt to lock mutex of job here */

	audiojob->sound = seq->sound;

	BLI_mutex_lock(pj->mutex);
	BLI_addtail(&pj->previews, audiojob);
	pj->total++;
	BLI_mutex_unlock(pj->mutex);

	if (!WM_jobs_is_running(wm_job)) {
		G.is_break = false;
		WM_jobs_start(CTX_wm_manager(C), wm_job);
	}

	ED_area_tag_redraw(sa);
}
Beispiel #12
0
static void render_view3d_do(RenderEngine *engine, const bContext *C)
{
	wmJob *wm_job;
	RenderPreview *rp;
	Scene *scene = CTX_data_scene(C);
	
	if (CTX_wm_window(C) == NULL)
		return;
	if (!render_view3d_flag_changed(engine, C))
		return;

	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview",
	                     WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW);
	rp = MEM_callocN(sizeof(RenderPreview), "render preview");
	rp->job = wm_job;

	/* customdata for preview thread */
	rp->scene = scene;
	rp->engine = engine;
	rp->sa = CTX_wm_area(C);
	rp->ar = CTX_wm_region(C);
	rp->v3d = rp->sa->spacedata.first;
	rp->rv3d = CTX_wm_region_view3d(C);
	rp->bmain = CTX_data_main(C);
	rp->resolution_divider = START_RESOLUTION_DIVIDER;
	copy_m4_m4(rp->viewmat, rp->rv3d->viewmat);
	
	/* clear info text */
	engine->text[0] = '\0';
	
	/* setup job */
	WM_jobs_customdata_set(wm_job, rp, render_view3d_free);
	WM_jobs_timer(wm_job, 0.1, NC_SPACE | ND_SPACE_VIEW3D, NC_SPACE | ND_SPACE_VIEW3D);
	WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL);
	
	WM_jobs_start(CTX_wm_manager(C), wm_job);
	
	engine->flag &= ~RE_ENGINE_DO_UPDATE;
}
Beispiel #13
0
static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
{
	wmJob *wm_job;
	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;

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

	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,
		                                                   true, NULL);
	}

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

	G.is_break = false;
	WM_jobs_start(CTX_wm_manager(C), wm_job);

	ED_area_tag_redraw(sa);

	return OPERATOR_FINISHED;
}
Beispiel #14
0
void thumbnails_start(FileList *filelist, const bContext *C)
{
	wmJob *wm_job;
	ThumbnailJob *tj;
	int idx;

	/* prepare job data */
	tj = MEM_callocN(sizeof(*tj), __func__);
	tj->filelist = filelist;
	for (idx = 0; idx < filelist->numfiles; idx++) {
		if (!filelist->filelist[idx].path) {
			continue;
		}
		if (!filelist->filelist[idx].image) {
			if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
			                                     FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))
			{
				FileImage *limg = MEM_callocN(sizeof(*limg), __func__);
				BLI_strncpy(limg->path, filelist->filelist[idx].path, sizeof(limg->path));
				limg->index = idx;
				limg->flags = filelist->filelist[idx].flags;
				BLI_addtail(&tj->loadimages, limg);
			}
		}
	}

	BKE_reports_init(&tj->reports, RPT_PRINT);

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

	/* start the job */
	WM_jobs_start(CTX_wm_manager(C), wm_job);
}
Beispiel #15
0
/* /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */
int get_material(Main *bmain, bContext *C, Scene *scene, bNodeTree *ntree, const char *address, int32_t mat_id)
{
    /* Setup job */
    wmJob           *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Get LDB Material", WM_JOB_PROGRESS, WM_JOB_TYPE_RENDER);
    GetMaterialJob  *mj     = MEM_callocN(sizeof(GetMaterialJob), "get LDB mat job");

    mj->C       = C;
    mj->bmain   = bmain;
    mj->ntree   = ntree;
    mj->mat_id  = mat_id;
    strcpy(mj->address, address);

    WM_jobs_customdata_set(wm_job, mj, get_material_data_free);
    WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_RENDER_RESULT, 0);
    WM_jobs_callbacks(wm_job, get_material_startjob, NULL, NULL, get_material_endjob);

    WM_jobs_start(CTX_wm_manager(C), wm_job);

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

    return 1;
} /* get_material() */
Beispiel #16
0
wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm,
                                  struct wmWindow *win,
                                  struct Main *bmain,
                                  struct ViewLayer *view_layer,
                                  struct Scene *scene,
                                  int delay,
                                  int frame)
{
  EEVEE_LightBake *lbake = NULL;

  /* only one render job at a time */
  if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
    return NULL;
  }

  wmJob *wm_job = WM_jobs_get(wm,
                              win,
                              scene,
                              "Bake Lighting",
                              WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS,
                              WM_JOB_TYPE_LIGHT_BAKE);

  /* If job exists do not recreate context and depsgraph. */
  EEVEE_LightBake *old_lbake = (EEVEE_LightBake *)WM_jobs_customdata_get(wm_job);

  if (old_lbake && (old_lbake->view_layer_input == view_layer) && (old_lbake->bmain == bmain)) {
    lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake");
    /* Cannot reuse depsgraph for now because we cannot get the update from the
     * main database directly. TODO reuse depsgraph and only update positions. */
    /* lbake->depsgraph = old_lbake->depsgraph; */
    lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);

    lbake->mutex = BLI_mutex_alloc();

    BLI_mutex_lock(old_lbake->mutex);
    old_lbake->own_resources = false;

    lbake->scene = scene;
    lbake->bmain = bmain;
    lbake->view_layer_input = view_layer;
    lbake->gl_context = old_lbake->gl_context;
    lbake->own_resources = true;
    lbake->delay = delay;
    lbake->frame = frame;

    if (lbake->gl_context == NULL) {
      lbake->gl_context = WM_opengl_context_create();
      wm_window_reset_drawable();
    }

    if (old_lbake->stop != NULL) {
      *old_lbake->stop = 1;
    }
    BLI_mutex_unlock(old_lbake->mutex);
  }
  else {
    lbake = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, true, frame);
    lbake->delay = delay;
  }

  WM_jobs_customdata_set(wm_job, lbake, EEVEE_lightbake_job_data_free);
  WM_jobs_timer(wm_job, 0.4, NC_SCENE | NA_EDITED, 0);
  WM_jobs_callbacks(
      wm_job, EEVEE_lightbake_job, NULL, EEVEE_lightbake_update, EEVEE_lightbake_update);

  G.is_break = false;

  return wm_job;
}
/* using context, starts job */
static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
	/* new render clears all callbacks */
	Main *mainp;
	Scene *scene = CTX_data_scene(C);
	SceneRenderLayer *srl = NULL;
	View3D *v3d = CTX_wm_view3d(C);
	Render *re;
	wmJob *wm_job;
	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;
	const char *name;
	Object *active_object = CTX_data_active_object(C);
	
	/* only one render job at a time */
	if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER))
		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.im_format.imtype)) {
		BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
		return OPERATOR_CANCELLED;
	}
	
	/* stop all running jobs, except screen one. currently previews frustrate Render */
	WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));

	/* get main */
	if (G.debug_value == 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 (ED_screen_animation_playing(CTX_wm_manager(C)))
		ED_screen_animation_play(C, 0, 0);
	
	/* handle UI stuff */
	WM_cursor_wait(1);

	/* flush multires changes (for sculpt) */
	multires_force_render_update(active_object);

	/* flush changes from dynamic topology sculpt */
	sculptsession_bm_to_me_for_render(active_object);

	/* 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) */
	BKE_sequencer_cache_cleanup();

	/* get editmode results */
	ED_object_editmode_load(CTX_data_edit_object(C));

	// 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;
	
	/* custom scene and single layer re-render */
	screen_render_scene_layer_set(op, mainp, &scene, &srl);

	if (RNA_struct_property_is_set(op->ptr, "layer"))
		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 = 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;

	if (v3d) {
		rj->lay = v3d->lay;

		if (v3d->localvd)
			rj->lay |= v3d->localvd->lay;
	}

	/* setup job */
	if (RE_seq_render_active(scene, &scene->r)) name = "Sequence Render";
	else name = "Render";

	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag, WM_JOB_TYPE_RENDER);
	WM_jobs_customdata_set(wm_job, rj, render_freejob);
	WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0);
	WM_jobs_callbacks(wm_job, 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.is_break = FALSE;

	/* store actual owner of job, so modal operator could check for it,
	 * the reason of this is that active scene could change when rendering
	 * several layers from compositor [#31800]
	 */
	op->customdata = scene;

	WM_jobs_start(CTX_wm_manager(C), wm_job);

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

	/* we set G.is_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.is_rendering = TRUE;

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

	return OPERATOR_RUNNING_MODAL;
}
Beispiel #18
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 *wm_job;
  ShaderPreview *sp;
  Scene *scene = CTX_data_scene(C);
  short id_type = GS(id->name);

  /* Use workspace render only for buttons Window,
   * since the other previews are related to the datablock. */

  if (!check_engine_supports_preview(scene)) {
    return;
  }

  /* Only texture node preview is supported with Cycles. */
  if (method == PR_NODE_RENDER && id_type != ID_TE) {
    return;
  }

  ED_preview_ensure_dbase();

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

  /* customdata for preview thread */
  sp->scene = scene;
  sp->depsgraph = CTX_data_depsgraph(C);
  sp->owner = owner;
  sp->sizex = sizex;
  sp->sizey = sizey;
  sp->pr_method = method;
  sp->id = id;
  sp->id_copy = duplicate_ids(id);
  sp->own_id_copy = true;
  sp->parent = parent;
  sp->slot = slot;
  sp->bmain = CTX_data_main(C);
  Material *ma = NULL;

  /* hardcoded preview .blend for Eevee + Cycles, this should be solved
   * once with custom preview .blend path for external engines */

  /* grease pencil use its own preview file */
  if (GS(id->name) == ID_MA) {
    ma = (Material *)id;
  }

  if ((ma == NULL) || (ma->gp_style == NULL)) {
    sp->pr_main = G_pr_main;
  }
  else {
    sp->pr_main = G_pr_main_grease_pencil;
  }

  if (ob && ob->totcol) {
    copy_v4_v4(sp->color, ob->color);
  }
  else {
    ARRAY_SET_ITEMS(sp->color, 0.0f, 0.0f, 0.0f, 1.0f);
  }

  /* setup job */
  WM_jobs_customdata_set(wm_job, sp, shader_preview_free);
  WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
  WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL);

  WM_jobs_start(CTX_wm_manager(C), wm_job);
}
Beispiel #19
0
/* using context, starts job */
static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
	/* new render clears all callbacks */
	Main *mainp;
	Scene *scene = CTX_data_scene(C);
	SceneRenderLayer *srl = NULL;
	Render *re;
	wmJob *wm_job;
	RenderJob *rj;
	Image *ima;
	int jobflag;
	const bool is_animation = RNA_boolean_get(op->ptr, "animation");
	const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
	const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport");
	View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL;
	struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
	const char *name;
	ScrArea *sa;
	
	/* only one render job at a time */
	if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER))
		return OPERATOR_CANCELLED;

	if (RE_force_single_renderlayer(scene))
		WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);

	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.im_format.imtype)) {
		BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
		return OPERATOR_CANCELLED;
	}
	
	/* stop all running jobs, except screen one. currently previews frustrate Render */
	WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));

	/* get main */
	if (G.debug_value == 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 (ED_screen_animation_playing(CTX_wm_manager(C)))
		ED_screen_animation_play(C, 0, 0);
	
	/* handle UI stuff */
	WM_cursor_wait(1);

	/* flush sculpt and editmode changes */
	ED_editors_flush_edits(C, true);

	/* 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) */
	BKE_sequencer_cache_cleanup();

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

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

	jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS;
	
	/* custom scene and single layer re-render */
	screen_render_scene_layer_set(op, mainp, &scene, &srl);

	if (RNA_struct_property_is_set(op->ptr, "layer"))
		jobflag |= WM_JOB_SUSPEND;

	/* job custom data */
	rj = MEM_callocN(sizeof(RenderJob), "render job");
	rj->main = mainp;
	rj->scene = scene;
	rj->current_scene = rj->scene;
	rj->srl = srl;
	rj->camera_override = camera_override;
	rj->lay_override = 0;
	rj->anim = is_animation;
	rj->write_still = is_write_still && !is_animation;
	rj->iuser.scene = scene;
	rj->iuser.ok = 1;
	rj->reports = op->reports;
	rj->orig_layer = 0;
	rj->last_layer = 0;
	rj->sa = sa;

	BKE_color_managed_display_settings_copy(&rj->display_settings, &scene->display_settings);
	BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);

	if (sa) {
		SpaceImage *sima = sa->spacedata.first;
		rj->orig_layer = sima->iuser.layer;
	}

	if (v3d) {
		if (scene->lay != v3d->lay) {
			rj->lay_override = v3d->lay;
			rj->v3d_override = true;
		}
		else if (camera_override && camera_override != scene->camera)
			rj->v3d_override = true;

		if (v3d->localvd)
			rj->lay_override |= v3d->localvd->lay;
	}

	/* Lock the user interface depending on render settings. */
	if (scene->r.use_lock_interface) {
		int renderlay = rj->lay_override ? rj->lay_override : scene->lay;

		WM_set_locked_interface(CTX_wm_manager(C), true);

		/* Set flag interface need to be unlocked.
		 *
		 * This is so because we don't have copy of render settings
		 * accessible from render job and copy is needed in case
		 * of non-locked rendering, so we wouldn't try to unlock
		 * anything if option was initially unset but then was
		 * enabled during rendering.
		 */
		rj->interface_locked = true;

		/* Clean memory used by viewport? */
		clean_viewport_memory(rj->main, scene, renderlay);
	}

	/* setup job */
	if (RE_seq_render_active(scene, &scene->r)) name = "Sequence Render";
	else name = "Render";

	wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag, WM_JOB_TYPE_RENDER);
	WM_jobs_customdata_set(wm_job, rj, render_freejob);
	WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0);
	WM_jobs_callbacks(wm_job, 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_update_cb(re, rj, image_rect_update);
	RE_current_scene_update_cb(re, rj, current_scene_update);
	RE_stats_draw_cb(re, rj, image_renderinfo_cb);
	RE_progress_cb(re, rj, render_progress_update);

	rj->re = re;
	G.is_break = false;

	/* store actual owner of job, so modal operator could check for it,
	 * the reason of this is that active scene could change when rendering
	 * several layers from compositor [#31800]
	 */
	op->customdata = scene;

	WM_jobs_start(CTX_wm_manager(C), wm_job);

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

	/* we set G.is_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.is_rendering = true;

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

	return OPERATOR_RUNNING_MODAL;
}
Beispiel #20
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;
}