Example #1
0
static void dpaint_bake_endjob(void *customdata)
{
	DynamicPaintBakeJob *job = customdata;
	DynamicPaintCanvasSettings *canvas = job->canvas;

	canvas->flags &= ~MOD_DPAINT_BAKING;

	dynamicPaint_freeSurfaceData(job->surface);

	G.is_rendering = false;
	BKE_spacedata_draw_locks(false);

	WM_set_locked_interface(G.main->wm.first, false);

	/* Bake was successful:
	 *  Report for ended bake and how long it took */
	if (job->success) {
		/* Show bake info */
		WM_reportf(RPT_INFO, "DynamicPaint: Bake complete! (%.2f)", PIL_check_seconds_timer() - job->start);
	}
	else {
		if (strlen(canvas->error)) { /* If an error occurred */
			WM_reportf(RPT_ERROR, "DynamicPaint: Bake failed: %s", canvas->error);
		}
		else { /* User canceled the bake */
			WM_report(RPT_WARNING, "Baking canceled!");
		}
	}
}
Example #2
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;
}
Example #3
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;
}
Example #4
0
static void ptcache_job_endjob(void *customdata)
{
	PointCacheJob *job = customdata;
	Scene *scene = job->baker->scene;

	G.is_rendering = false;
	BKE_spacedata_draw_locks(false);

	WM_set_locked_interface(G.main->wm.first, false);

	WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
	WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.ob);
}
Example #5
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;
}
Example #6
0
static void render_endjob(void *rjv)
{
	RenderJob *rj = rjv;

	/* this render may be used again by the sequencer without the active 'Render' where the callbacks
	 * would be re-assigned. assign dummy callbacks to avoid referencing freed renderjobs bug [#24508] */
	RE_InitRenderCB(rj->re);

	if (rj->main != G.main)
		BKE_main_free(rj->main);

	/* else the frame will not update for the original value */
	if (rj->anim && !(rj->scene->r.scemode & R_NO_FRAME_UPDATE)) {
		/* possible this fails of loading new file while rendering */
		if (G.main->wm.first) {
			ED_update_for_newframe(G.main, rj->scene, 1);
		}
	}
	
	/* XXX above function sets all tags in nodes */
	ntreeCompositClearTags(rj->scene->nodetree);
	
	/* potentially set by caller */
	rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
	
	if (rj->srl) {
		nodeUpdateID(rj->scene->nodetree, &rj->scene->id);
		WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
	}

	if (rj->sa) {
		render_image_restore_layer(rj);
	}

	/* XXX render stability hack */
	G.is_rendering = false;
	WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL);

	/* Partial render result will always update display buffer
	 * for first render layer only. This is nice because you'll
	 * see render progress during rendering, but it ends up in
	 * wrong display buffer shown after rendering.
	 *
	 * The code below will mark display buffer as invalid after
	 * rendering in case multiple layers were rendered, which
	 * ensures display buffer matches render layer after
	 * rendering.
	 *
	 * Perhaps proper way would be to toggle active render
	 * layer in image editor and job, so we always display
	 * layer being currently rendered. But this is not so much
	 * trivial at this moment, especially because of external
	 * engine API, so lets use simple and robust way for now
	 *                                          - sergey -
	 */
	if (rj->scene->r.layers.first != rj->scene->r.layers.last ||
	    rj->image_outdated)
	{
		void *lock;
		Image *ima = rj->image;
		ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock);

		if (ibuf)
			ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;

		BKE_image_release_ibuf(ima, ibuf, lock);
	}

	/* Finally unlock the user interface (if it was locked). */
	if (rj->interface_locked) {
		Scene *scene;

		/* Interface was locked, so window manager couldn't have been changed
		 * and using one from Global will unlock exactly the same manager as
		 * was locked before running the job.
		 */
		WM_set_locked_interface(G.main->wm.first, false);

		/* We've freed all the derived caches before rendering, which is
		 * effectively the same as if we re-loaded the file.
		 *
		 * So let's not try being smart here and just reset all updated
		 * scene layers and use generic DAG_on_visible_update.
		 */
		for (scene = G.main->scene.first; scene; scene = scene->id.next) {
			scene->lay_updated = 0;
		}

		DAG_on_visible_update(G.main, false);
	}
}