示例#1
0
static void screen_opengl_render_apply(OGLRender *oglrender)
{
	Scene *scene = oglrender->scene;
	ARegion *ar = oglrender->ar;
	View3D *v3d = oglrender->v3d;
	RegionView3D *rv3d = oglrender->rv3d;
	RenderResult *rr;
	Object *camera = NULL;
	ImBuf *ibuf;
	void *lock;
	float winmat[4][4];
	int sizex = oglrender->sizex;
	int sizey = oglrender->sizey;
	const short view_context = (v3d != NULL);
	bool draw_bgpic = true;
	bool draw_sky = (scene->r.alphamode == R_ADDSKY);
	unsigned char *rect = NULL;

	rr = RE_AcquireResultRead(oglrender->re);

	if (oglrender->is_sequencer) {
		SeqRenderData context;
		int chanshown = oglrender->sseq ? oglrender->sseq->chanshown : 0;

		context = BKE_sequencer_new_render_data(oglrender->bmain, scene, oglrender->sizex, oglrender->sizey, 100.0f);

		ibuf = BKE_sequencer_give_ibuf(context, CFRA, chanshown);

		if (ibuf) {
			ImBuf *linear_ibuf;

			BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));

			linear_ibuf = IMB_dupImBuf(ibuf);
			IMB_freeImBuf(ibuf);

			if (linear_ibuf->rect_float == NULL) {
				/* internally sequencer working in display space and stores both bytes and float buffers in that space.
				 * It is possible that byte->float onversion didn't happen in sequencer (e.g. when adding image sequence/movie
				 * into sequencer) there'll be only byte buffer. Create float buffer from existing byte buffer, making it linear
				 */

				IMB_float_from_rect(linear_ibuf);
			}
			else {
				/* ensure float buffer is in linear space, not in display space */
				BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
			}

			memcpy(rr->rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);

			IMB_freeImBuf(linear_ibuf);
		}
	}
	else if (view_context) {
		ED_view3d_draw_offscreen_init(scene, v3d);

		GPU_offscreen_bind(oglrender->ofs); /* bind */

		/* render 3d view */
		if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
			/*int is_ortho = scene->r.mode & R_ORTHO;*/
			camera = v3d->camera;
			RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
			
		}
		else {
			rctf viewplane;
			float clipsta, clipend;

			int is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
			if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
			else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
		}

		rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");

		if ((scene->r.mode & R_OSA) == 0) {
			ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky);
			GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
		}
		else {
			/* simple accumulation, less hassle then FSAA FBO's */
			static float jit_ofs[32][2];
			float winmat_jitter[4][4];
			int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int) * 4, "accum1");
			int i, j;

			BLI_jitter_init(jit_ofs[0], scene->r.osa);

			/* first sample buffer, also initializes 'rv3d->persmat' */
			ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky);
			GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);

			for (i = 0; i < sizex * sizey * 4; i++)
				accum_buffer[i] = rect[i];

			/* skip the first sample */
			for (j = 1; j < scene->r.osa; j++) {
				copy_m4_m4(winmat_jitter, winmat);
				window_translate_m4(winmat_jitter, rv3d->persmat,
				                    (jit_ofs[j][0] * 2.0f) / sizex,
				                    (jit_ofs[j][1] * 2.0f) / sizey);

				ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_bgpic, draw_sky);
				GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);

				for (i = 0; i < sizex * sizey * 4; i++)
					accum_buffer[i] += rect[i];
			}

			for (i = 0; i < sizex * sizey * 4; i++)
				rect[i] = accum_buffer[i] / scene->r.osa;

			MEM_freeN(accum_buffer);
		}

		GPU_offscreen_unbind(oglrender->ofs); /* unbind */
	}
	else {
		/* shouldnt suddenly give errors mid-render but possible */
		char err_out[256] = "unknown";
		ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
		                                                         IB_rect, OB_SOLID, FALSE, TRUE,
		                                                         (draw_sky) ? R_ADDSKY: R_ALPHAPREMUL, err_out);
		camera = scene->camera;

		if (ibuf_view) {
			/* steal rect reference from ibuf */
			rect = (unsigned char *)ibuf_view->rect;
			ibuf_view->mall &= ~IB_rect;

			IMB_freeImBuf(ibuf_view);
		}
		else {
			fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
		}
	}

	/* note on color management:
	 *
	 * OpenGL renders into sRGB colors, but render buffers are expected to be
	 * linear So we convert to linear here, so the conversion back to bytes can make it
	 * sRGB (or other display space) again, and so that e.g. openexr saving also saves the
	 * correct linear float buffer.
	 */

	if (rect) {
		int profile_to;
		
		if (BKE_scene_check_color_management_enabled(scene))
			profile_to = IB_PROFILE_LINEAR_RGB;
		else
			profile_to = IB_PROFILE_SRGB;

		/* sequencer has got trickier conversion happened above
		 * also assume opengl's space matches byte buffer color space */
		IMB_buffer_float_from_byte(rr->rectf, rect,
		                           profile_to, IB_PROFILE_SRGB, true,
		                           oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
	}

	/* rr->rectf is now filled with image data */

	if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
		BKE_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);

	RE_ReleaseResult(oglrender->re);

	/* update byte from float buffer */
	ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);

	if (ibuf) {
		/* update display buffer */
		if (ibuf->rect == NULL)
			imb_addrectImBuf(ibuf);

		IMB_partial_display_buffer_update(ibuf, rr->rectf, rect, rr->rectx, 0, 0,
		                                  &scene->view_settings, &scene->display_settings,
		                                  0, 0, rr->rectx, rr->recty, true);

		/* write file for animation */
		if (oglrender->write_still) {
			char name[FILE_MAX];
			int ok;

			if (scene->r.im_format.planes == R_IMF_CHAN_DEPTH_8) {
				IMB_color_to_bw(ibuf);
			}

			BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, FALSE);
			ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, TRUE); /* no need to stamp here */
			if (ok) printf("OpenGL Render written to '%s'\n", name);
			else printf("OpenGL Render failed to write '%s'\n", name);
		}
	}
	
	BKE_image_release_ibuf(oglrender->ima, ibuf, lock);

	if (rect)
		MEM_freeN(rect);
}
示例#2
0
static void draw_plane_marker_image(Scene *scene,
                                    MovieTrackingPlaneTrack *plane_track,
                                    MovieTrackingPlaneMarker *plane_marker)
{
	Image *image = plane_track->image;
	ImBuf *ibuf;
	void *lock;

	if (image == NULL) {
		return;
	}

	ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);

	if (ibuf) {
		unsigned char *display_buffer;
		void *cache_handle;

		if (image->flag & IMA_VIEW_AS_RENDER) {
			display_buffer = IMB_display_buffer_acquire(ibuf,
			                                            &scene->view_settings,
			                                            &scene->display_settings,
			                                            &cache_handle);
		}
		else {
			display_buffer = IMB_display_buffer_acquire(ibuf, NULL,
			                                            &scene->display_settings,
			                                            &cache_handle);
		}

		if (display_buffer) {
			GLuint texid;
			float frame_corners[4][2] = {{0.0f, 0.0f},
			                             {1.0f, 0.0f},
			                             {1.0f, 1.0f},
			                             {0.0f, 1.0f}};
			float perspective_matrix[3][3];
			float gl_matrix[4][4];
			bool transparent = false;
			BKE_tracking_homography_between_two_quads(frame_corners,
			                                          plane_marker->corners,
			                                          perspective_matrix);

			homogeneous_2d_to_gl_matrix(perspective_matrix, gl_matrix);

			if (plane_track->image_opacity != 1.0f || ibuf->planes == 32) {
				transparent = true;
				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA);
			}

			glColor4f(1.0, 1.0, 1.0, plane_track->image_opacity);

			GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
			glGenTextures(1, (GLuint *)&texid);

			glBindTexture(GL_TEXTURE_2D, texid);

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, GL_RGBA,
			             GL_UNSIGNED_BYTE, display_buffer);

			glPushMatrix();
			glMultMatrixf(gl_matrix);

			glBegin(GL_QUADS);
			glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
			glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, 0.0f);
			glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
			glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 1.0f);
			glEnd();

			glPopMatrix();

			glBindTexture(GL_TEXTURE_2D, 0);
			GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);

			if (transparent) {
				glDisable(GL_BLEND);
			}
		}

		IMB_display_buffer_release(cache_handle);
	}

	BKE_image_release_ibuf(image, ibuf, lock);
}
示例#3
0
// refresh texture
static PyObject *Texture_refresh(Texture *self, PyObject *args)
{
	// get parameter - refresh source
	PyObject *param;
	double ts = -1.0;

	if (!PyArg_ParseTuple(args, "O|d:refresh", &param, &ts) || !PyBool_Check(param))
	{
		// report error
		PyErr_SetString(PyExc_TypeError, "The value must be a bool");
		return NULL;
	}
	// some trick here: we are in the business of loading a texture,
	// no use to do it if we are still in the same rendering frame.
	// We find this out by looking at the engine current clock time
	KX_KetsjiEngine* engine = KX_GetActiveEngine();
	if (engine->GetClockTime() != self->m_lastClock)
	{
		self->m_lastClock = engine->GetClockTime();
		// set source refresh
		bool refreshSource = (param == Py_True);
		// try to proces texture from source
		try
		{
			// if source is available
			if (self->m_source != NULL)
			{
				// check texture code
				if (!self->m_orgSaved)
				{
					self->m_orgSaved = true;
					// save original image code
					if (self->m_useMatTexture)
						self->m_orgTex = self->m_matTexture->swapTexture(self->m_actTex);
					else
					{
						// Swapping will work only if the GPU has already loaded the image.
						// If not, it will delete and overwrite our texture on next render.
						// To avoid that, we acquire the image buffer now.
						// WARNING: GPU has a ImageUser to pass, we don't. Using NULL
						// works on image file, not necessarily on other type of image.
						self->m_imgBuf = BKE_image_acquire_ibuf(self->m_imgTexture, NULL, NULL);
						self->m_orgTex = self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D];
						self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D] = self->m_actTex;
					}
				}

				// get texture
				unsigned int * texture = self->m_source->m_image->getImage(self->m_actTex, ts);
				// if texture is available
				if (texture != NULL)
				{
					// get texture size
					short * orgSize = self->m_source->m_image->getSize();
					// calc scaled sizes
					short size[2];
					if (GLEW_ARB_texture_non_power_of_two)
					{
						size[0] = orgSize[0];
						size[1] = orgSize[1];
					}
					else
					{
						size[0] = ImageBase::calcSize(orgSize[0]);
						size[1] = ImageBase::calcSize(orgSize[1]);
					}
					// scale texture if needed
					if (size[0] != orgSize[0] || size[1] != orgSize[1])
					{
						IMB_freeImBuf(self->m_scaledImBuf);
						self->m_scaledImBuf = IMB_allocFromBuffer(texture, NULL, orgSize[0], orgSize[1]);
						IMB_scaleImBuf(self->m_scaledImBuf, size[0], size[1]);

						// use scaled image instead original
						texture = self->m_scaledImBuf->rect;
					}
					// load texture for rendering
					loadTexture(self->m_actTex, texture, size, self->m_mipmap);
				}
				// refresh texture source, if required
				if (refreshSource) {
					self->m_source->m_image->refresh();
				}
			}
		}
		CATCH_EXCP;
	}
示例#4
0
/* already have tested for tface and ima and zspan */
static void shade_tface(BakeShade *bs)
{
	VlakRen *vlr = bs->vlr;
	ObjectInstanceRen *obi = bs->obi;
	ObjectRen *obr = obi->obr;
	MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
	Image *ima = tface->tpage;
	float vec[4][2];
	int a, i1, i2, i3;
	
	/* check valid zspan */
	if (ima != bs->ima) {
		BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL);

		bs->ima = ima;
		bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
		/* note, these calls only free/fill contents of zspan struct, not zspan itself */
		zbuf_free_span(bs->zspan);
		zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop);
	}

	bs->rectx = bs->ibuf->x;
	bs->recty = bs->ibuf->y;
	bs->rect = bs->ibuf->rect;
	bs->rect_colorspace = bs->ibuf->rect_colorspace;
	bs->rect_float = bs->ibuf->rect_float;
	bs->vcol = NULL;
	bs->quad = 0;
	bs->rect_mask = NULL;
	bs->displacement_buffer = NULL;

	if (bs->use_mask || bs->use_displacement_buffer) {
		BakeImBufuserData *userdata = bs->ibuf->userdata;
		if (userdata == NULL) {
			BLI_lock_thread(LOCK_CUSTOM1);
			userdata = bs->ibuf->userdata;
			if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */
				userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeImBufuserData");

			if (bs->use_mask) {
				if (userdata->mask_buffer == NULL) {
					userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask");
				}
			}

			if (bs->use_displacement_buffer) {
				if (userdata->displacement_buffer == NULL) {
					userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp");
				}
			}

			bs->ibuf->userdata = userdata;

			BLI_unlock_thread(LOCK_CUSTOM1);
		}

		bs->rect_mask = userdata->mask_buffer;
		bs->displacement_buffer = userdata->displacement_buffer;
	}
	
	/* get pixel level vertex coordinates */
	for (a = 0; a < 4; a++) {
		/* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests
		 * where a pixel gets in between 2 faces or the middle of a quad,
		 * camera aligned quads also have this problem but they are less common.
		 * Add a small offset to the UVs, fixes bug #18685 - Campbell */
		vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f);
		vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f);
	}

	/* UV indices have to be corrected for possible quad->tria splits */
	i1 = 0; i2 = 1; i3 = 2;
	vlr_set_uv_indices(vlr, &i1, &i2, &i3);
	bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]);
	zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
	
	if (vlr->v4) {
		bs->quad = 1;
		bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]);
		zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
	}
}
示例#5
0
/* returns 0 if nothing was handled */
int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress)
{
	BakeShade *handles;
	ListBase threads;
	Image *ima;
	int a, vdone = false, result = BAKE_RESULT_OK;
	bool use_mask = false;
	bool use_displacement_buffer = false;
	bool do_manage = BKE_scene_check_color_management_enabled(re->scene);
	
	re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene);
	
	/* initialize render global */
	R = *re;
	R.bakebuf = NULL;

	/* initialize static vars */
	get_next_bake_face(NULL);
	
	/* do we need a mask? */
	if (re->r.bake_filter)
		use_mask = true;

	/* do we need buffer to store displacements  */
	if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
		if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) ||
		    (type == RE_BAKE_DERIVATIVE))
		{
			use_displacement_buffer = true;
			use_mask = true;
		}
	}

	/* baker uses this flag to detect if image was initialized */
	if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
		for (ima = G.main->image.first; ima; ima = ima->id.next) {
			ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
			ima->id.flag |= LIB_DOIT;
			ima->flag &= ~IMA_USED_FOR_RENDER;
			if (ibuf) {
				ibuf->userdata = NULL; /* use for masking if needed */
			}
			BKE_image_release_ibuf(ima, ibuf, NULL);
		}
	}

	if (R.r.bake_flag & R_BAKE_VCOL) {
		/* untag all meshes */
		BKE_main_id_tag_listbase(&G.main->mesh, false);
	}

	BLI_init_threads(&threads, do_bake_thread, re->r.threads);

	handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade");

	/* get the threads running */
	for (a = 0; a < re->r.threads; a++) {
		/* set defaults in handles */
		handles[a].ssamp.shi[0].lay = re->lay;

		if (type == RE_BAKE_SHADOW) {
			handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW;
		}
		else {
			handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED;
		}
		handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
		handles[a].ssamp.shi[0].thread = a;
		handles[a].ssamp.shi[0].do_manage = do_manage;
		handles[a].ssamp.tot = 1;

		handles[a].type = type;
		handles[a].actob = actob;
		if (R.r.bake_flag & R_BAKE_VCOL)
			handles[a].zspan = NULL;
		else
			handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake");
		
		handles[a].use_mask = use_mask;
		handles[a].use_displacement_buffer = use_displacement_buffer;

		handles[a].do_update = do_update; /* use to tell the view to update */
		
		handles[a].displacement_min = FLT_MAX;
		handles[a].displacement_max = -FLT_MAX;

		BLI_insert_thread(&threads, &handles[a]);
	}
	
	/* wait for everything to be done */
	a = 0;
	while (a != re->r.threads) {
		PIL_sleep_ms(50);

		/* calculate progress */
		for (vdone = false, a = 0; a < re->r.threads; a++)
			vdone += handles[a].vdone;
		if (progress)
			*progress = (float)(vdone / (float)re->totvlak);

		for (a = 0; a < re->r.threads; a++) {
			if (handles[a].ready == false) {
				break;
			}
		}
	}

	/* filter and refresh images */
	if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
		float displacement_min = FLT_MAX, displacement_max = -FLT_MAX;

		if (use_displacement_buffer) {
			for (a = 0; a < re->r.threads; a++) {
				displacement_min = min_ff(displacement_min, handles[a].displacement_min);
				displacement_max = max_ff(displacement_max, handles[a].displacement_max);
			}
		}

		for (ima = G.main->image.first; ima; ima = ima->id.next) {
			if ((ima->id.flag & LIB_DOIT) == 0) {
				ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
				BakeImBufuserData *userdata;

				if (ima->flag & IMA_USED_FOR_RENDER)
					result = BAKE_RESULT_FEEDBACK_LOOP;

				if (!ibuf)
					continue;

				userdata = (BakeImBufuserData *)ibuf->userdata;
				if (userdata) {
					if (use_displacement_buffer) {
						if (type == RE_BAKE_DERIVATIVE) {
							float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f;
							RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
							                        displacement_min, displacement_max, user_scale);
						}
						else {
							RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
							                                    displacement_min, displacement_max);
						}
					}

					RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter);
				}

				ibuf->userflags |= IB_BITMAPDIRTY;
				BKE_image_release_ibuf(ima, ibuf, NULL);
			}
		}

		/* calculate return value */
		for (a = 0; a < re->r.threads; a++) {
			zbuf_free_span(handles[a].zspan);
			MEM_freeN(handles[a].zspan);
		}
	}

	MEM_freeN(handles);
	
	BLI_end_threads(&threads);

	if (vdone == 0) {
		result = BAKE_RESULT_NO_OBJECTS;
	}

	return result;
}
示例#6
0
/* if all is good tag image and return true */
static bool bake_object_check(Scene *scene, Object *ob, ReportList *reports)
{
	Image *image;
	void *lock;
	int i;

	if ((ob->lay & scene->lay) == 0) {
		BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not on a scene layer", ob->id.name + 2);
		return false;
	}

	if (ob->type != OB_MESH) {
		BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2);
		return false;
	}
	else {
		Mesh *me = (Mesh *)ob->data;

		if (CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV) == -1) {
			BKE_reportf(reports, RPT_ERROR,
			            "No active UV layer found in the object \"%s\"", ob->id.name + 2);
			return false;
		}
	}

	for (i = 0; i < ob->totcol; i++) {
		bNodeTree *ntree = NULL;
		bNode *node = NULL;
		ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree);

		if (image) {
			ImBuf *ibuf;

			if (node) {
				if (BKE_node_is_connected_to_output(ntree, node)) {
					/* we don't return false since this may be a false positive
					 * this can't be RPT_ERROR though, otherwise it prevents
					 * multiple highpoly objects to be baked at once */
					BKE_reportf(reports, RPT_INFO,
					            "Circular dependency for image \"%s\" from object \"%s\"",
					            image->id.name + 2, ob->id.name + 2);
				}
			}

			ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);

			if (ibuf) {
				BKE_image_release_ibuf(image, ibuf, lock);
			}
			else {
				BKE_reportf(reports, RPT_ERROR,
				            "Uninitialized image \"%s\" from object \"%s\"",
				            image->id.name + 2, ob->id.name + 2);

				BKE_image_release_ibuf(image, ibuf, lock);
				return false;
			}
		}
		else {
			Material *mat = give_current_material(ob, i);
			if (mat != NULL) {
				BKE_reportf(reports, RPT_INFO,
				            "No active image found in material \"%s\" (%d) for object \"%s\"",
				            mat->id.name + 2, i, ob->id.name + 2);
			}
			else {
				BKE_reportf(reports, RPT_INFO,
				            "No active image found in material slot (%d) for object \"%s\"",
				            i, ob->id.name + 2);
			}
			continue;
		}

		image->id.tag |= LIB_TAG_DOIT;
	}
	return true;
}
示例#7
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)
		free_main(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);
	}

	/* 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);
	}
}
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
	ShaderPreview *sp = customdata;

	if (sp->pr_method == PR_ICON_DEFERRED) {
		PreviewImage *prv = sp->owner;
		ImBuf *thumb;
		char *deferred_data = PRV_DEFERRED_DATA(prv);
		int source =  deferred_data[0];
		char *path = &deferred_data[1];

//		printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);

		thumb = IMB_thumb_manage(path, THB_LARGE, source);

		if (thumb) {
			/* PreviewImage assumes premultiplied alhpa... */
			IMB_premultiply_alpha(thumb);

			icon_copy_rect(thumb, sp->sizex, sp->sizey, sp->pr_rect);
			IMB_freeImBuf(thumb);
		}
	}
	else {
		ID *id = sp->id;
		short idtype = GS(id->name);

		if (idtype == ID_IM) {
			Image *ima = (Image *)id;
			ImBuf *ibuf = NULL;
			ImageUser iuser = {NULL};

			/* ima->ok is zero when Image cannot load */
			if (ima == NULL || ima->ok == 0)
				return;

			/* setup dummy image user */
			iuser.ok = iuser.framenr = 1;
			iuser.scene = sp->scene;

			/* elubie: this needs to be changed: here image is always loaded if not
			 * already there. Very expensive for large images. Need to find a way to
			 * only get existing ibuf */
			ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
			if (ibuf == NULL || ibuf->rect == NULL) {
				BKE_image_release_ibuf(ima, ibuf, NULL);
				return;
			}

			icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);

			*do_update = true;

			BKE_image_release_ibuf(ima, ibuf, NULL);
		}
		else if (idtype == ID_BR) {
			Brush *br = (Brush *)id;

			br->icon_imbuf = get_brush_icon(br);

			memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));

			if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
				return;

			icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);

			*do_update = true;
		}
		else {
			/* re-use shader job */
			shader_preview_startjob(customdata, stop, do_update);

			/* world is rendered with alpha=0, so it wasn't displayed
			 * this could be render option for sky to, for later */
			if (idtype == ID_WO) {
				set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
			}
			else if (idtype == ID_MA) {
				Material *ma = (Material *)id;

				if (ma->material_type == MA_TYPE_HALO)
					set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
			}
		}
	}
}
示例#9
0
bool BL_Texture::InitFromImage(int unit,  Image *img, bool mipmap)
{

	ImBuf *ibuf;
	if (!img || img->ok==0) 
	{
		mOk = false;
		return mOk;
	}

	ibuf= BKE_image_acquire_ibuf(img, NULL, NULL);
	if (ibuf==NULL)
	{
		img->ok = 0;
		mOk = false;
		return mOk;
	}

	mipmap = mipmap && GPU_get_mipmap();

	mTexture = img->bindcode[TEXTARGET_TEXTURE_2D];
	mType = GL_TEXTURE_2D;
	mUnit = unit;

	ActivateUnit(mUnit);

	if (mTexture != 0) {
		glBindTexture(GL_TEXTURE_2D, mTexture );
		Validate();
		BKE_image_release_ibuf(img, ibuf, NULL);
		return mOk;
	}

	// look for an existing gl image
	BL_TextureMap::iterator mapLook = g_textureManager.find(img->id.name);
	if (mapLook != g_textureManager.end())
	{
		if (mapLook->second.gl_texture != 0)
		{
			mTexture = mapLook->second.gl_texture;
			glBindTexture(GL_TEXTURE_2D, mTexture);
			mOk = IsValid();
			BKE_image_release_ibuf(img, ibuf, NULL);
			return mOk;
		}
	}

	mNeedsDeleted = 1;
	glGenTextures(1, (GLuint*)&mTexture);

#ifdef WITH_DDS
	if (ibuf->ftype == IMB_FTYPE_DDS)
		InitGLCompressedTex(ibuf, mipmap);
	else
		InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap);
#else
	InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap);
#endif

	// track created units
	BL_TextureObject obj;
	obj.gl_texture = mTexture;
	obj.ref_buffer = img;
	g_textureManager.insert(std::pair<char*, BL_TextureObject>((char*)img->id.name, obj));


	glDisable(GL_TEXTURE_2D);
	ActivateUnit(0);
	Validate();

	BKE_image_release_ibuf(img, ibuf, NULL);

	return mOk;
}
示例#10
0
void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
{
	/// Image output
	OutputSocket *outputImage = this->getOutputSocket(0);
	bNode *editorNode = this->getbNode();
	Image *image = (Image *)editorNode->id;
	ImageUser *imageuser = (ImageUser *)editorNode->storage;
	int framenumber = context->getFramenumber();
	int numberOfOutputs = this->getNumberOfOutputSockets();
	bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
	BKE_image_user_frame_calc(imageuser, context->getFramenumber(), 0);

	/* force a load, we assume iuser index will be set OK anyway */
	if (image && image->type == IMA_TYPE_MULTILAYER) {
		bool is_multilayer_ok = false;
		ImBuf *ibuf = BKE_image_acquire_ibuf(image, imageuser, NULL);
		if (image->rr) {
			RenderLayer *rl = (RenderLayer *)BLI_findlink(&image->rr->layers, imageuser->layer);
			if (rl) {
				OutputSocket *socket;
				int index;

				is_multilayer_ok = true;

				for (index = 0; index < numberOfOutputs; index++) {
					NodeOperation *operation = NULL;
					socket = this->getOutputSocket(index);
					if (socket->isConnected() || index == 0) {
						bNodeSocket *bnodeSocket = socket->getbNodeSocket();
						/* Passes in the file can differ from passes stored in sockets (#36755).
						 * Look up the correct file pass using the socket identifier instead.
						 */
						#if 0
						NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;*/
						int passindex = storage->pass_index;*/
						RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex);
						#endif
						int passindex;
						RenderPass *rpass;
						for (rpass = (RenderPass *)rl->passes.first, passindex = 0; rpass; rpass = rpass->next, ++passindex)
							if (STREQ(rpass->name, bnodeSocket->identifier))
								break;
						if (rpass) {
							imageuser->pass = passindex;
							switch (rpass->channels) {
								case 1:
									operation = doMultilayerCheck(graph, rl, image, imageuser, framenumber, index, passindex, COM_DT_VALUE);
									break;
								/* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
								/* XXX any way to detect actual vector images? */
								case 3:
									operation = doMultilayerCheck(graph, rl, image, imageuser, framenumber, index, passindex, COM_DT_VECTOR);
									break;
								case 4:
									operation = doMultilayerCheck(graph, rl, image, imageuser, framenumber, index, passindex, COM_DT_COLOR);
									break;
								default:
									/* dummy operation is added below */
									break;
							}

							if (index == 0 && operation) {
								addPreviewOperation(graph, context, operation->getOutputSocket());
							}
						}
					}

					/* incase we can't load the layer */
					if (operation == NULL) {
						convertToOperations_invalid_index(graph, index);
					}
				}
			}
示例#11
0
void ImagesExporter::export_UV_Image(Image *image, bool use_copies) 
{
	std::string name(id_name(image));
	std::string translated_name(translate_id(name));
	bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_name) == mImages.end();

	if (not_yet_exported) {

		ImBuf *imbuf       = BKE_image_acquire_ibuf(image, NULL, NULL);
		if (!imbuf) {
			fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name);
			return;
		}

		bool  is_dirty     = (imbuf->userflags & IB_BITMAPDIRTY) != 0;

		ImageFormatData imageFormat;
		BKE_imbuf_to_image_format(&imageFormat, imbuf);

		short image_source = image->source;
		bool  is_generated = image_source == IMA_SRC_GENERATED;
		bool  is_packed    = image->packedfile != NULL;

		char export_path[FILE_MAX];
		char source_path[FILE_MAX];
		char export_dir[FILE_MAX];
		char export_file[FILE_MAX];

		// Destination folder for exported assets
		BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir));

		if (is_generated || is_dirty || use_copies || is_packed) {

			// make absolute destination path

			BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
			BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);

			BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);

			// make dest directory if it doesn't exist
			BLI_make_existing_file(export_path);
		}

		if (is_generated || is_dirty || is_packed) {

			// This image in its current state only exists in Blender memory.
			// So we have to export it. The export will keep the image state intact,
			// so the exported file will not be associated with the image.

			if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
				fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
				return;
			}
			BLI_strncpy(export_path, export_file, sizeof(export_path));
		}
		else {

			// make absolute source path
			BLI_strncpy(source_path, image->name, sizeof(source_path));
			BLI_path_abs(source_path, G.main->name);
			BLI_cleanup_path(NULL, source_path);

			if (use_copies) {
			
				// This image is already located on the file system.
				// But we want to create copies here.
				// To move images into the same export directory.
				// Note: If an image is already located in the export folder,
				// then skip the copy (as it would result in a file copy error).

				if (BLI_path_cmp(source_path, export_path) != 0) {
					if (BLI_copy(source_path, export_path) != 0) {
						fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path);
						return;
					}
				}

				BLI_strncpy(export_path, export_file, sizeof(export_path));

			}
			else {

				// Do not make any copies, but use the source path directly as reference
				// to the original image

				BLI_strncpy(export_path, source_path, sizeof(export_path));
			}
		}

		COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
		img.add(mSW);
		fprintf(stdout, "Collada export: Added image: %s\n", export_file);
		mImages.push_back(translated_name);

		BKE_image_release_ibuf(image, imbuf, NULL);
	}
}
示例#12
0
void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact)
{
	PropertyRNA *prop;
	PointerRNA imaptr;
	RNAUpdateCb *cb;
	Image *ima;
	ImageUser *iuser;
	ImBuf *ibuf;
	Scene *scene= CTX_data_scene(C);
	uiLayout *row, *split, *col;
	uiBlock *block;
	uiBut *but;
	char str[128];
	void *lock;

	if(!ptr->data)
		return;

	prop= RNA_struct_find_property(ptr, propname);
	if(!prop) {
		printf("%s: property not found: %s.%s\n",
		       __func__, RNA_struct_identifier(ptr->type), propname);
		return;
	}

	if(RNA_property_type(prop) != PROP_POINTER) {
		printf("%s: expected pointer property for %s.%s\n",
		       __func__, RNA_struct_identifier(ptr->type), propname);
		return;
	}

	block= uiLayoutGetBlock(layout);

	imaptr= RNA_property_pointer_get(ptr, prop);
	ima= imaptr.data;
	iuser= userptr->data;

	cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
	cb->ptr= *ptr;
	cb->prop= prop;
	cb->iuser= iuser;

	uiLayoutSetContextPointer(layout, "edit_image", &imaptr);

	if(!compact)
		uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL);

	if(ima) {
		uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);

		if(ima->source == IMA_SRC_VIEWER) {
			ibuf= BKE_image_acquire_ibuf(ima, iuser, &lock);
			image_info(scene, iuser, ima, ibuf, str);
			BKE_image_release_ibuf(ima, lock);

			uiItemL(layout, ima->id.name+2, ICON_NONE);
			uiItemL(layout, str, ICON_NONE);

			if(ima->type==IMA_TYPE_COMPOSITE) {
				// XXX not working yet
#if 0
				iuser= ntree_get_active_iuser(scene->nodetree);
				if(iuser) {
					uiBlockBeginAlign(block);
					uiDefIconTextBut(block, BUT, B_SIMA_RECORD, ICON_REC, "Record",	10,120,100,20, 0, 0, 0, 0, 0, "");
					uiDefIconTextBut(block, BUT, B_SIMA_PLAY, ICON_PLAY, "Play",	110,120,100,20, 0, 0, 0, 0, 0, "");
					but= uiDefBut(block, BUT, B_NOP, "Free Cache",	210,120,100,20, 0, 0, 0, 0, 0, "");
					uiButSetFunc(but, image_freecache_cb, ima, NULL);
					
					if(iuser->frames)
						sprintf(str, "(%d) Frames:", iuser->framenr);
					else strcpy(str, "Frames:");
					uiBlockBeginAlign(block);
					uiDefButI(block, NUM, imagechanged, str,		10, 90,150, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Number of images of a movie to use");
					uiDefButI(block, NUM, imagechanged, "StartFr:",	160,90,150,20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Global starting frame of the movie");
				}
#endif
			}
			else if(ima->type==IMA_TYPE_R_RESULT) {
				/* browse layer/passes */
				Render *re= RE_GetRender(scene->id.name);
				RenderResult *rr= RE_AcquireResultRead(re);
				uiblock_layer_pass_arrow_buttons(layout, rr, iuser, &ima->render_slot);
				RE_ReleaseResult(re);
			}
		}
		else {
			uiItemR(layout, &imaptr, "source", 0, NULL, ICON_NONE);

			if(ima->source != IMA_SRC_GENERATED) {
				row= uiLayoutRow(layout, 1);
				if (ima->packedfile)
					uiItemO(row, "", ICON_PACKAGE, "image.unpack");
				else
					uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
				
				row= uiLayoutRow(row, 0);
				uiLayoutSetEnabled(row, ima->packedfile==NULL);
				uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
				uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
			}

			// XXX what was this for?
#if 0
			 /* check for re-render, only buttons */
			if(imagechanged==B_IMAGECHANGED) {
				if(iuser->flag & IMA_ANIM_REFRESHED) {
					iuser->flag &= ~IMA_ANIM_REFRESHED;
					WM_event_add_notifier(C, NC_IMAGE, ima);
				}
			}
#endif

			/* multilayer? */
			if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
				uiblock_layer_pass_arrow_buttons(layout, ima->rr, iuser, NULL);
			}
			else if(ima->source != IMA_SRC_GENERATED) {
				if(compact == 0) {
					ibuf= BKE_image_acquire_ibuf(ima, iuser, &lock);
					image_info(scene, iuser, ima, ibuf, str);
					BKE_image_release_ibuf(ima, lock);
					uiItemL(layout, str, ICON_NONE);
				}
			}
			
			if(ima->source != IMA_SRC_GENERATED) {
				if(compact == 0) { /* background image view doesnt need these */
					uiItemS(layout);

					split= uiLayoutSplit(layout, 0, 0);

					col= uiLayoutColumn(split, 0);
					uiItemR(col, &imaptr, "use_fields", 0, NULL, ICON_NONE);
					row= uiLayoutRow(col, 0);
					uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields"));
					uiItemR(row, &imaptr, "field_order", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
					
					uiItemR(split, &imaptr, "use_premultiply", 0, NULL, ICON_NONE);
				}
			}

			if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
				uiItemS(layout);
				
				split= uiLayoutSplit(layout, 0, 0);

				col= uiLayoutColumn(split, 0);
				 
				sprintf(str, "(%d) Frames", iuser->framenr);
				uiItemR(col, userptr, "frame_duration", 0, str, ICON_NONE);
				if(ima->anim) {
					block= uiLayoutGetBlock(col);
					but= uiDefBut(block, BUT, 0, "Match Movie Length", 0, 0, UI_UNIT_X*2, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Set the number of frames to match the movie or sequence");
					uiButSetFunc(but, set_frames_cb, ima, iuser);
				}

				uiItemR(col, userptr, "frame_start", 0, "Start", ICON_NONE);
				uiItemR(col, userptr, "frame_offset", 0, NULL, ICON_NONE);

				col= uiLayoutColumn(split, 0);
				row= uiLayoutRow(col, 0);
				uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields"));
				uiItemR(row, userptr, "fields_per_frame", 0, "Fields", ICON_NONE);
				uiItemR(col, userptr, "use_auto_refresh", 0, NULL, ICON_NONE);
				uiItemR(col, userptr, "use_cyclic", 0, NULL, ICON_NONE);
			}
			else if(ima->source==IMA_SRC_GENERATED) {
				split= uiLayoutSplit(layout, 0, 0);

				col= uiLayoutColumn(split, 1);
				uiItemR(col, &imaptr, "generated_width", 0, "X", ICON_NONE);
				uiItemR(col, &imaptr, "generated_height", 0, "Y", ICON_NONE);
				uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE);

				uiItemR(split, &imaptr, "generated_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
			}

					}

		uiBlockSetNFunc(block, NULL, NULL, NULL);
	}

	MEM_freeN(cb);
}
示例#13
0
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
	ShaderPreview *sp = customdata;
	ID *id = sp->id;
	short idtype = GS(id->name);
	
	if (idtype == ID_IM) {
		Image *ima = (Image *)id;
		ImBuf *ibuf = NULL;
		ImageUser iuser = {NULL};

		/* ima->ok is zero when Image cannot load */
		if (ima == NULL || ima->ok == 0)
			return;

		/* setup dummy image user */
		iuser.ok = iuser.framenr = 1;
		iuser.scene = sp->scene;
		
		/* elubie: this needs to be changed: here image is always loaded if not
		 * already there. Very expensive for large images. Need to find a way to 
		 * only get existing ibuf */
		ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
		if (ibuf == NULL || ibuf->rect == NULL) {
			BKE_image_release_ibuf(ima, ibuf, NULL);
			return;
		}
		
		icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect);

		*do_update = true;

		BKE_image_release_ibuf(ima, ibuf, NULL);
	}
	else if (idtype == ID_BR) {
		Brush *br = (Brush *)id;

		br->icon_imbuf = get_brush_icon(br);

		memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));

		if (!(br->icon_imbuf) || !(br->icon_imbuf->rect))
			return;

		icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect);

		*do_update = true;
	}
	else {
		/* re-use shader job */
		shader_preview_startjob(customdata, stop, do_update);

		/* world is rendered with alpha=0, so it wasn't displayed 
		 * this could be render option for sky to, for later */
		if (idtype == ID_WO) {
			set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
		}
		else if (idtype == ID_MA) {
			Material *ma = (Material *)id;

			if (ma->material_type == MA_TYPE_HALO)
				set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
		}
	}
}
示例#14
0
void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
{
	/// Image output
	OutputSocket *outputImage = this->getOutputSocket(0);
	bNode *editorNode = this->getbNode();
	Image *image = (Image *)editorNode->id;
	ImageUser *imageuser = (ImageUser *)editorNode->storage;
	int framenumber = context->getFramenumber();
	int numberOfOutputs = this->getNumberOfOutputSockets();
	bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
	BKE_image_user_frame_calc(imageuser, context->getFramenumber(), 0);

	/* force a load, we assume iuser index will be set OK anyway */
	if (image && image->type == IMA_TYPE_MULTILAYER) {
		bool is_multilayer_ok = false;
		ImBuf *ibuf = BKE_image_acquire_ibuf(image, imageuser, NULL);
		if (image->rr) {
			RenderLayer *rl = (RenderLayer *)BLI_findlink(&image->rr->layers, imageuser->layer);
			if (rl) {
				OutputSocket *socket;
				int index;

				is_multilayer_ok = true;

				for (index = 0; index < numberOfOutputs; index++) {
					NodeOperation *operation = NULL;
					socket = this->getOutputSocket(index);
					if (socket->isConnected() || index == 0) {
						bNodeSocket *bnodeSocket = socket->getbNodeSocket();
						NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;
						int passindex = storage->pass_index;
						
						RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex);
						if (rpass) {
							imageuser->pass = passindex;
							switch (rpass->channels) {
								case 1:
									operation = doMultilayerCheck(graph, rl, image, imageuser, framenumber, index, passindex, COM_DT_VALUE);
									break;
								/* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
								/* XXX any way to detect actual vector images? */
								case 3:
									operation = doMultilayerCheck(graph, rl, image, imageuser, framenumber, index, passindex, COM_DT_VECTOR);
									break;
								case 4:
									operation = doMultilayerCheck(graph, rl, image, imageuser, framenumber, index, passindex, COM_DT_COLOR);
									break;
								default:
									/* dummy operation is added below */
									break;
							}

							if (index == 0 && operation) {
								addPreviewOperation(graph, context, operation->getOutputSocket());
							}
						}
					}

					/* incase we can't load the layer */
					if (operation == NULL) {
						convertToOperations_invalid_index(graph, index);
					}
				}
			}
		}
		BKE_image_release_ibuf(image, ibuf, NULL);

		/* without this, multilayer that fail to load will crash blender [#32490] */
		if (is_multilayer_ok == false) {
			convertToOperations_invalid(graph, context);
		}
	}
	else {
		if (numberOfOutputs >  0) {
			ImageOperation *operation = new ImageOperation();
			if (outputImage->isConnected()) {
				if (outputStraightAlpha) {
					NodeOperation *alphaConvertOperation = new ConvertPremulToStraightOperation();
					addLink(graph, operation->getOutputSocket(0), alphaConvertOperation->getInputSocket(0));
					outputImage->relinkConnections(alphaConvertOperation->getOutputSocket());
					graph->addOperation(alphaConvertOperation);
				}
				else {
					outputImage->relinkConnections(operation->getOutputSocket());
				}
			}
			operation->setImage(image);
			operation->setImageUser(imageuser);
			operation->setFramenumber(framenumber);
			graph->addOperation(operation);
			addPreviewOperation(graph, context, operation->getOutputSocket());
		}
		
		if (numberOfOutputs > 1) {
			OutputSocket *alphaImage = this->getOutputSocket(1);
			if (alphaImage->isConnected()) {
				ImageAlphaOperation *alphaOperation = new ImageAlphaOperation();
				alphaOperation->setImage(image);
				alphaOperation->setImageUser(imageuser);
				alphaOperation->setFramenumber(framenumber);
				alphaImage->relinkConnections(alphaOperation->getOutputSocket());
				graph->addOperation(alphaOperation);
			}
		}
		if (numberOfOutputs > 2) {
			OutputSocket *depthImage = this->getOutputSocket(2);
			if (depthImage->isConnected()) {
				ImageDepthOperation *depthOperation = new ImageDepthOperation();
				depthOperation->setImage(image);
				depthOperation->setImageUser(imageuser);
				depthOperation->setFramenumber(framenumber);
				depthImage->relinkConnections(depthOperation->getOutputSocket());
				graph->addOperation(depthOperation);
			}
		}
		if (numberOfOutputs > 3) {
			/* happens when unlinking image datablock from multilayer node */
			for (int i = 3; i < numberOfOutputs; i++) {
				OutputSocket *output = this->getOutputSocket(i);
				NodeOperation *operation = NULL;
				switch (output->getDataType()) {
					case COM_DT_VALUE:
					{
						SetValueOperation *valueoperation = new SetValueOperation();
						valueoperation->setValue(0.0f);
						operation = valueoperation;
						break;
					}
					case COM_DT_VECTOR:
					{
						SetVectorOperation *vectoroperation = new SetVectorOperation();
						vectoroperation->setX(0.0f);
						vectoroperation->setY(0.0f);
						vectoroperation->setW(0.0f);
						operation = vectoroperation;
						break;
					}
					case COM_DT_COLOR:
					{
						SetColorOperation *coloroperation = new SetColorOperation();
						coloroperation->setChannel1(0.0f);
						coloroperation->setChannel2(0.0f);
						coloroperation->setChannel3(0.0f);
						coloroperation->setChannel4(0.0f);
						operation = coloroperation;
						break;
					}
				}

				if (operation) {
					output->relinkConnections(operation->getOutputSocket());
					graph->addOperation(operation);
				}
			}
		}
	}
}
示例#15
0
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
	Main *bmain = CTX_data_main(C);
	OGLRender *oglrender = op->customdata;
	Scene *scene = oglrender->scene;
	ImBuf *ibuf, *ibuf_save = NULL;
	void *lock;
	char name[FILE_MAX];
	int ok = 0;
	const short view_context = (oglrender->v3d != NULL);
	Object *camera = NULL;
	int is_movie;

	/* go to next frame */
	if (CFRA < oglrender->nfra)
		CFRA++;
	while (CFRA < oglrender->nfra) {
		unsigned int lay = screen_opengl_layers(oglrender);

		if (lay & 0xFF000000)
			lay &= 0xFF000000;

		BKE_scene_update_for_newframe(bmain, scene, lay);
		CFRA++;
	}

	is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);

	if (!is_movie) {
		BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE);

		if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
			BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
			ok = true;
			goto finally;
		}
	}

	WM_cursor_time(oglrender->win, scene->r.cfra);

	BKE_scene_update_for_newframe(bmain, scene, screen_opengl_layers(oglrender));

	if (view_context) {
		if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) {
			/* since BKE_scene_update_for_newframe() is used rather
			 * then ED_update_for_newframe() the camera needs to be set */
			if (BKE_scene_camera_switch_update(scene)) {
				oglrender->v3d->camera = scene->camera;
			}

			camera = oglrender->v3d->camera;
		}
	}
	else {
		BKE_scene_camera_switch_update(scene);

		camera = scene->camera;
	}

	/* render into offscreen buffer */
	screen_opengl_render_apply(oglrender);

	/* save to disk */
	ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);

	if (ibuf) {
		int needs_free = FALSE;

		ibuf_save = ibuf;

		if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) {
			ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings,
			                                                &scene->display_settings, &scene->r.im_format);

			needs_free = TRUE;
		}

		/* color -> grayscale */
		/* editing directly would alter the render view */
		if (scene->r.im_format.planes == R_IMF_PLANES_BW) {
			ImBuf *ibuf_bw = IMB_dupImBuf(ibuf_save);
			IMB_color_to_bw(ibuf_bw);

			if (needs_free)
				IMB_freeImBuf(ibuf_save);

			ibuf_save = ibuf_bw;
		}
		else {
			/* this is lightweight & doesnt re-alloc the buffers, only do this
			 * to save the correct bit depth since the image is always RGBA */
			ImBuf *ibuf_cpy = IMB_allocImBuf(ibuf_save->x, ibuf_save->y, scene->r.im_format.planes, 0);

			ibuf_cpy->rect = ibuf_save->rect;
			ibuf_cpy->rect_float = ibuf_save->rect_float;
			ibuf_cpy->zbuf_float = ibuf_save->zbuf_float;

			if (needs_free) {
				ibuf_cpy->mall = ibuf_save->mall;
				ibuf_save->mall = 0;
				IMB_freeImBuf(ibuf_save);
			}

			ibuf_save = ibuf_cpy;
		}

		if (is_movie) {
			ok = oglrender->mh->append_movie(&scene->r, PSFRA, CFRA, (int *)ibuf_save->rect,
			                                 oglrender->sizex, oglrender->sizey, oglrender->reports);
			if (ok) {
				printf("Append frame %d", scene->r.cfra);
				BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
			}
		}
		else {
			ok = BKE_imbuf_write_stamp(scene, camera, ibuf_save, name, &scene->r.im_format);

			if (ok == 0) {
				printf("Write error: cannot save %s\n", name);
				BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
			}
			else {
				printf("Saved: %s", name);
				BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
			}
		}

		if (needs_free)
			IMB_freeImBuf(ibuf_save);
	}

	BKE_image_release_ibuf(oglrender->ima, ibuf, lock);

	/* movie stats prints have no line break */
	printf("\n");


finally:  /* Step the frame and bail early if needed */

	/* go to next frame */
	oglrender->nfra += scene->r.frame_step;

	/* stop at the end or on error */
	if (CFRA >= PEFRA || !ok) {
		screen_opengl_render_end(C, op->customdata);
		return 0;
	}

	return 1;
}
示例#16
0
bool BL_Texture::InitCubeMap(int unit,  EnvMap *cubemap)
{
	if (!GLEW_ARB_texture_cube_map)
	{
		spit("cubemaps not supported");
		mOk = false;
		return mOk;
	}
	else if (!cubemap || cubemap->ima->ok==0) 
	{
		mOk = false;
		return mOk;
	}

	ImBuf *ibuf= BKE_image_acquire_ibuf(cubemap->ima, NULL, NULL);
	if (ibuf==0)
	{
		cubemap->ima->ok = 0;
		mOk = false;
		return mOk;
	}

	mNeedsDeleted =	1;
	mType = GL_TEXTURE_CUBE_MAP_ARB;
	mTexture = 0;
	mUnit = unit;

	ActivateUnit(mUnit);

	BL_TextureMap::iterator mapLook = g_textureManager.find(cubemap->ima->id.name);
	if (mapLook != g_textureManager.end())
	{
		if (mapLook->second.gl_texture != 0 && mapLook->second.ref_buffer == cubemap->ima)
		{
			mTexture = mapLook->second.gl_texture;
			glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture);
			mOk = IsValid();
			BKE_image_release_ibuf(cubemap->ima, ibuf, NULL);
			return mOk;
		}
	}


	glGenTextures(1, (GLuint*)&mTexture);
	glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture);


	// track created units
	BL_TextureObject obj;
	obj.gl_texture = mTexture;
	obj.ref_buffer = cubemap->ima;
	g_textureManager.insert(std::pair<char*, BL_TextureObject>((char*)cubemap->ima->id.name, obj));


	bool needs_split = false;
	if (!cubemap->cube[0]) 
	{
		needs_split = true;
		spit ("Re-Generating texture buffer");
	}

	if (needs_split)
		my_envmap_split_ima(cubemap, ibuf);


	if (!is_power_of_2_i(cubemap->cube[0]->x) || !is_power_of_2_i(cubemap->cube[0]->y))
	{
		spit("invalid envmap size please render with CubeRes @ power of two");

		my_free_envmapdata(cubemap);
		mOk = false;
		BKE_image_release_ibuf(cubemap->ima, ibuf, NULL);
		return mOk;
	}


#define SetCubeMapFace(face, num)   \
	glTexImage2D(face, 0,GL_RGBA,	\
	cubemap->cube[num]->x,          \
	cubemap->cube[num]->y,          \
	0, GL_RGBA, GL_UNSIGNED_BYTE,   \
	cubemap->cube[num]->rect)

	SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 5);
	SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 3);
	SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0);
	SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 1);
	SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 2);
	SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 4);

	glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S,	 GL_CLAMP_TO_EDGE );
	glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T,	 GL_CLAMP_TO_EDGE );
	if (GLEW_VERSION_1_2)
		glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R,	 GL_CLAMP_TO_EDGE );

	if (needs_split)
		my_free_envmapdata(cubemap);



	glDisable(GL_TEXTURE_CUBE_MAP_ARB);
	ActivateUnit(0);

	mOk = IsValid();

	BKE_image_release_ibuf(cubemap->ima, ibuf, NULL);

	return mOk;
}
示例#17
0
static int get_next_bake_face(BakeShade *bs)
{
	ObjectRen *obr;
	VlakRen *vlr;
	MTFace *tface;
	static int v = 0, vdone = false;
	static ObjectInstanceRen *obi = NULL;

	if (bs == NULL) {
		vlr = NULL;
		v = vdone = false;
		obi = R.instancetable.first;
		return 0;
	}
	
	BLI_lock_thread(LOCK_CUSTOM1);

	for (; obi; obi = obi->next, v = 0) {
		obr = obi->obr;

		/* only allow non instances here */
		if (obr->flag & R_INSTANCEABLE)
			continue;

		for (; v < obr->totvlak; v++) {
			vlr = RE_findOrAddVlak(obr, v);

			if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) {
				if (R.r.bake_flag & R_BAKE_VCOL) {
					/* Gather face data for vertex color bake */
					Mesh *me;
					int *origindex, vcollayer;
					CustomDataLayer *cdl;

					if (obr->ob->type != OB_MESH)
						continue;
					me = obr->ob->data;

					origindex = RE_vlakren_get_origindex(obr, vlr, 0);
					if (origindex == NULL)
						continue;
					if (*origindex >= me->totpoly) {
						/* Small hack for Array modifier, which gives false
						 * original indices - z0r */
						continue;
					}
#if 0
					/* Only shade selected faces. */
					if ((me->mface[*origindex].flag & ME_FACE_SEL) == 0)
						continue;
#endif

					vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL);
					if (vcollayer == -1)
						continue;

					cdl = &me->ldata.layers[vcollayer];
					bs->mpoly = me->mpoly + *origindex;
					bs->vcol = ((MLoopCol *)cdl->data) + bs->mpoly->loopstart;
					bs->mloop = me->mloop + bs->mpoly->loopstart;

					/* Tag mesh for reevaluation. */
					me->id.flag |= LIB_DOIT;
				}
				else {
					Image *ima = NULL;
					ImBuf *ibuf = NULL;
					const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
					const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
					const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
					const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
					const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f};
					const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};

					tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);

					if (!tface || !tface->tpage)
						continue;

					ima = tface->tpage;
					ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);

					if (ibuf == NULL)
						continue;

					if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
						BKE_image_release_ibuf(ima, ibuf, NULL);
						continue;
					}

					if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) {
						BKE_image_release_ibuf(ima, ibuf, NULL);
						continue;
					}
					
					if (ima->flag & IMA_USED_FOR_RENDER) {
						ima->id.flag &= ~LIB_DOIT;
						BKE_image_release_ibuf(ima, ibuf, NULL);
						continue;
					}
					
					/* find the image for the first time? */
					if (ima->id.flag & LIB_DOIT) {
						ima->id.flag &= ~LIB_DOIT;
						
						/* we either fill in float or char, this ensures things go fine */
						if (ibuf->rect_float)
							imb_freerectImBuf(ibuf);
						/* clear image */
						if (R.r.bake_flag & R_BAKE_CLEAR) {
							if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
								IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
							else if (ELEM(R.r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE))
								IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid);
							else
								IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
						}
						/* might be read by UI to set active image for display */
						R.bakebuf = ima;
					}

					/* Tag image for redraw. */
					ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
					BKE_image_release_ibuf(ima, ibuf, NULL);
				}

				bs->obi = obi;
				bs->vlr = vlr;
				bs->vdone++;  /* only for error message if nothing was rendered */
				v++;
				BLI_unlock_thread(LOCK_CUSTOM1);
				return 1;
			}
		}
	}
	
	BLI_unlock_thread(LOCK_CUSTOM1);
	return 0;
}
示例#18
0
static bool write_internal_bake_pixels(
        Image *image, BakePixel pixel_array[], float *buffer,
        const int width, const int height, const int margin,
        const bool is_clear, const bool is_noncolor)
{
	ImBuf *ibuf;
	void *lock;
	bool is_float;
	char *mask_buffer = NULL;
	const size_t num_pixels = (size_t)width * (size_t)height;

	ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);

	if (!ibuf)
		return false;

	if (margin > 0 || !is_clear) {
		mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask");
		RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer);
	}

	is_float = (ibuf->flags & IB_rectfloat);

	/* colormanagement conversions */
	if (!is_noncolor) {
		const char *from_colorspace;
		const char *to_colorspace;

		from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);

		if (is_float)
			to_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
		else
			to_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);

		if (from_colorspace != to_colorspace)
			IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false);
	}

	/* populates the ImBuf */
	if (is_clear) {
		if (is_float) {
			IMB_buffer_float_from_float(
			        ibuf->rect_float, buffer, ibuf->channels,
			        IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
			        ibuf->x, ibuf->y, ibuf->x, ibuf->x);
		}
		else {
			IMB_buffer_byte_from_float(
			        (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither,
			        IB_PROFILE_SRGB, IB_PROFILE_SRGB,
			        false, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
		}
	}
	else {
		if (is_float) {
			IMB_buffer_float_from_float_mask(
			        ibuf->rect_float, buffer, ibuf->channels,
			        ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer);
		}
		else {
			IMB_buffer_byte_from_float_mask(
			        (unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither,
			        false, ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer);
		}
	}

	/* margins */
	if (margin > 0)
		RE_bake_margin(ibuf, mask_buffer, margin);

	ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_BITMAPDIRTY;

	if (ibuf->rect_float)
		ibuf->userflags |= IB_RECT_INVALID;

	/* force mipmap recalc */
	if (ibuf->mipmap[0]) {
		ibuf->userflags |= IB_MIPMAP_INVALID;
		imb_freemipmapImBuf(ibuf);
	}

	BKE_image_release_ibuf(image, ibuf, NULL);

	if (mask_buffer)
		MEM_freeN(mask_buffer);

	return true;
}