Example #1
0
void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert_to_linear, struct ColorSpace *colorspace)
{
	float co[3] = {u, v, 0.0f};
	int hasrgb;
	float intensity;

	hasrgb = externtex(mtex, co, &intensity,
	                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
	if (!hasrgb) {
		rgba[0] = intensity;
		rgba[1] = intensity;
		rgba[2] = intensity;
		rgba[3] = 1.0f;
	}

	if (convert_to_linear)
		IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, colorspace);

	linearrgb_to_srgb_v3_v3(rgba, rgba);

	CLAMP(rgba[0], 0.0f, 1.0f);
	CLAMP(rgba[1], 0.0f, 1.0f);
	CLAMP(rgba[2], 0.0f, 1.0f);
	CLAMP(rgba[3], 0.0f, 1.0f);
}
Example #2
0
/* Returns color in the display space, matching ED_space_image_color_sample().
 * And here we've got recursion in the comments tips...
 */
bool ED_space_node_color_sample(Scene *scene, SpaceNode *snode, ARegion *ar, int mval[2], float r_col[3])
{
	const char *display_device = scene->display_settings.display_device;
	struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
	void *lock;
	Image *ima;
	ImBuf *ibuf;
	float fx, fy, bufx, bufy;
	bool ret = false;

	if (STREQ(snode->tree_idname, ntreeType_Composite->idname) || (snode->flag & SNODE_BACKDRAW) == 0) {
		/* use viewer image for color sampling only if we're in compositor tree
		 * with backdrop enabled
		 */
		return false;
	}

	ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
	ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
	if (!ibuf) {
		return false;
	}

	/* map the mouse coords to the backdrop image space */
	bufx = ibuf->x * snode->zoom;
	bufy = ibuf->y * snode->zoom;
	fx = (bufx > 0.0f ? ((float)mval[0] - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
	fy = (bufy > 0.0f ? ((float)mval[1] - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);

	if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
		const float *fp;
		unsigned char *cp;
		int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);

		CLAMP(x, 0, ibuf->x - 1);
		CLAMP(y, 0, ibuf->y - 1);

		if (ibuf->rect_float) {
			fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
			/* IB_PROFILE_NONE is default but infact its linear */
			copy_v3_v3(r_col, fp);
			ret = true;
		}
		else if (ibuf->rect) {
			cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
			rgb_uchar_to_float(r_col, cp);
			IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
			ret = true;
		}
	}

	if (ret) {
		IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
	}

	BKE_image_release_ibuf(ima, ibuf, lock);

	return ret;
}
Example #3
0
static void tonemapmodifier_apply_threaded_simple(int width,
                                                  int height,
                                                  unsigned char *rect,
                                                  float *rect_float,
                                                  unsigned char *mask_rect,
                                                  float *mask_rect_float,
                                                  void *data_v)
{
	AvgLogLum *avg = (AvgLogLum *)data_v;
	for (int y = 0; y < height; y++) {
		for (int x = 0; x < width; x++) {
			int pixel_index = (y * width + x) * 4;
			float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
			/* Get input value. */
			if (rect_float) {
				copy_v4_v4(input, &rect_float[pixel_index]);
			}
			else {
				straight_uchar_to_premul_float(input, &rect[pixel_index]);
			}
			IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
			copy_v4_v4(output, input);
			/* Get mask value. */
			if (mask_rect_float) {
				copy_v3_v3(mask, mask_rect_float + pixel_index);
			}
			else if (mask_rect) {
				rgb_uchar_to_float(mask, mask_rect + pixel_index);
			}
			/* Apply correction. */
			mul_v3_fl(output, avg->al);
			float dr = output[0] + avg->tmmd->offset;
			float dg = output[1] + avg->tmmd->offset;
			float db = output[2] + avg->tmmd->offset;
			output[0] /= ((dr == 0.0f) ? 1.0f : dr);
			output[1] /= ((dg == 0.0f) ? 1.0f : dg);
			output[2] /= ((db == 0.0f) ? 1.0f : db);
			const float igm = avg->igm;
			if (igm != 0.0f) {
				output[0] = powf(max_ff(output[0], 0.0f), igm);
				output[1] = powf(max_ff(output[1], 0.0f), igm);
				output[2] = powf(max_ff(output[2], 0.0f), igm);
			}
			/* Apply mask. */
			output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
			output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
			output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
			/* Copy result back. */
			IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
			if (rect_float) {
				copy_v4_v4(&rect_float[pixel_index], output);
			}
			else {
				premul_float_to_straight_uchar(&rect[pixel_index], output);
			}
		}
	}
}
Example #4
0
/* Returns color in the display space, matching ED_space_image_color_sample(). */
bool ED_space_clip_color_sample(Scene *scene, SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3])
{
	const char *display_device = scene->display_settings.display_device;
	struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
	ImBuf *ibuf;
	float fx, fy, co[2];
	bool ret = false;

	ibuf = ED_space_clip_get_buffer(sc);
	if (!ibuf) {
		return false;
	}

	/* map the mouse coords to the backdrop image space */
	ED_clip_mouse_pos(sc, ar, mval, co);

	fx = co[0];
	fy = co[1];

	if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
		const float *fp;
		unsigned char *cp;
		int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);

		CLAMP(x, 0, ibuf->x - 1);
		CLAMP(y, 0, ibuf->y - 1);

		if (ibuf->rect_float) {
			fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
			copy_v3_v3(r_col, fp);
			ret = true;
		}
		else if (ibuf->rect) {
			cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
			rgb_uchar_to_float(r_col, cp);
			IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
			ret = true;
		}
	}

	if (ret) {
		IMB_colormanagement_scene_linear_to_display_v3(r_col, display);
	}

	IMB_freeImBuf(ibuf);

	return ret;
}
Example #5
0
static void whiteBalance_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
                                        unsigned char *mask_rect, float *mask_rect_float, void *data_v)
{
	int x, y;
	float multiplier[3];

	WhiteBalanceThreadData *data = (WhiteBalanceThreadData *) data_v;

	multiplier[0] = 1.0f / data->white[0];
	multiplier[1] = 1.0f / data->white[1];
	multiplier[2] = 1.0f / data->white[2];

	for (y = 0; y < height; y++) {
		for (x = 0; x < width; x++) {
			int pixel_index = (y * width + x) * 4;
			float result[3], mask[3] = {1.0f, 1.0f, 1.0f};

			if (rect_float) {
				copy_v3_v3(result, rect_float + pixel_index);
			}
			else {
				straight_uchar_to_premul_float(result, rect + pixel_index);
				IMB_colormanagement_colorspace_to_scene_linear_v3(result, data->colorspace);
			}

			mul_v3_v3(result, multiplier);

			if (mask_rect_float)
				copy_v3_v3(mask, mask_rect_float + pixel_index);
			else if (mask_rect)
				rgb_uchar_to_float(mask, mask_rect + pixel_index);

			result[0] = result[0] * (1.0f - mask[0]) + result[0] * mask[0];
			result[1] = result[1] * (1.0f - mask[1]) + result[1] * mask[1];
			result[2] = result[2] * (1.0f - mask[2]) + result[2] * mask[2];

			if (rect_float)
				copy_v3_v3(rect_float + pixel_index, result);
			else
				IMB_colormanagement_scene_linear_to_colorspace_v3(result, data->colorspace);
			premul_float_to_straight_uchar(rect + pixel_index, result);
		}
	}
}
Example #6
0
/* Generic texture sampler for 3D painting systems. point has to be either in
 * region space mouse coordinates, or 3d world coordinates for 3D mapping.
 *
 * rgba outputs straight alpha. */
float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
                              const float point[3],
                              float rgba[4], const int thread,
                              struct ImagePool *pool)
{
	UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
	MTex *mtex = &br->mtex;
	float intensity = 1.0;
	bool hasrgb = false;

	if (!mtex->tex) {
		intensity = 1;
	}
	else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
		/* Get strength by feeding the vertex
		 * location directly into a texture */
		hasrgb = externtex(mtex, point, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}
	else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x, y;
		float co[3];

		x = point_2d[0] - br->stencil_pos[0];
		y = point_2d[1] - br->stencil_pos[1];

		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		if (fabsf(x) > br->stencil_dimension[0] || fabsf(y) > br->stencil_dimension[1]) {
			zero_v4(rgba);
			return 0.0f;
		}
		x /= (br->stencil_dimension[0]);
		y /= (br->stencil_dimension[1]);

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		hasrgb = externtex(mtex, co, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}
	else {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x = 0.0f, y = 0.0f; /* Quite warnings */
		float invradius = 1.0f; /* Quite warnings */
		float co[3];

		if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
			/* keep coordinates relative to mouse */

			rotation += ups->brush_rotation;

			x = point_2d[0] - ups->tex_mouse[0];
			y = point_2d[1] - ups->tex_mouse[1];

			/* use pressure adjusted size for fixed mode */
			invradius = 1.0f / ups->pixel_radius;
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
			/* leave the coordinates relative to the screen */

			/* use unadjusted size for tiled mode */
			invradius = 1.0f / BKE_brush_size_get(scene, br);

			x = point_2d[0];
			y = point_2d[1];
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
			rotation += ups->brush_rotation;
			/* these contain a random coordinate */
			x = point_2d[0] - ups->tex_mouse[0];
			y = point_2d[1] - ups->tex_mouse[1];

			invradius = 1.0f / ups->pixel_radius;
		}

		x *= invradius;
		y *= invradius;

		/* it is probably worth optimizing for those cases where
		 * the texture is not rotated by skipping the calls to
		 * atan2, sqrtf, sin, and cos. */
		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		hasrgb = externtex(mtex, co, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
	}

	intensity += br->texture_sample_bias;

	if (!hasrgb) {
		rgba[0] = intensity;
		rgba[1] = intensity;
		rgba[2] = intensity;
		rgba[3] = 1.0f;
	}
	/* For consistency, sampling always returns color in linear space */
	else if (ups->do_linear_conversion) {
		IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, ups->colorspace);
	}

	return intensity;
}
Example #7
0
static void tonemapmodifier_apply(struct SequenceModifierData *smd,
                                  ImBuf *ibuf,
                                  ImBuf *mask)
{
	SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *) smd;
	AvgLogLum data;
	data.tmmd = tmmd;
	data.colorspace = (ibuf->rect_float != NULL)
	                      ? ibuf->float_colorspace
	                      : ibuf->rect_colorspace;
	float lsum = 0.0f;
	int p = ibuf->x * ibuf->y;
	float *fp = ibuf->rect_float;
	unsigned char *cp = (unsigned char *)ibuf->rect;
	float avl, maxl = -FLT_MAX, minl = FLT_MAX;
	const float sc = 1.0f / p;
	float Lav = 0.f;
	float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
	while (p--) {
		float pixel[4];
		if (fp != NULL) {
			copy_v4_v4(pixel, fp);
		}
		else {
			straight_uchar_to_premul_float(pixel, cp);
		}
		IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, data.colorspace);
		float L = IMB_colormanagement_get_luminance(pixel);
		Lav += L;
		add_v3_v3(cav, pixel);
		lsum += logf(max_ff(L, 0.0f) + 1e-5f);
		maxl = (L > maxl) ? L : maxl;
		minl = (L < minl) ? L : minl;
		if (fp != NULL) {
			fp += 4;
		}
		else {
			cp += 4;
		}
	}
	data.lav = Lav * sc;
	mul_v3_v3fl(data.cav, cav, sc);
	maxl = logf(maxl + 1e-5f);
	minl = logf(minl + 1e-5f);
	avl = lsum * sc;
	data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
	float al = expf(avl);
	data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
	data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);

	if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
		modifier_apply_threaded(ibuf,
		                        mask,
		                        tonemapmodifier_apply_threaded_photoreceptor,
		                        &data);
	}
	else /* if (tmmd->type == SEQ_TONEMAP_RD_SIMPLE) */ {
		modifier_apply_threaded(ibuf,
		                        mask,
		                        tonemapmodifier_apply_threaded_simple,
		                        &data);
	}
}
Example #8
0
static void tonemapmodifier_apply_threaded_photoreceptor(int width,
                                                         int height,
                                                         unsigned char *rect,
                                                         float *rect_float,
                                                         unsigned char *mask_rect,
                                                         float *mask_rect_float,
                                                         void *data_v)
{
	AvgLogLum *avg = (AvgLogLum *)data_v;
	const float f = expf(-avg->tmmd->intensity);
	const float m = (avg->tmmd->contrast > 0.0f) ? avg->tmmd->contrast : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
	const float ic = 1.0f - avg->tmmd->correction, ia = 1.0f - avg->tmmd->adaptation;
	for (int y = 0; y < height; y++) {
		for (int x = 0; x < width; x++) {
			int pixel_index = (y * width + x) * 4;
			float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
			/* Get input value. */
			if (rect_float) {
				copy_v4_v4(input, &rect_float[pixel_index]);
			}
			else {
				straight_uchar_to_premul_float(input, &rect[pixel_index]);
			}
			IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
			copy_v4_v4(output, input);
			/* Get mask value. */
			if (mask_rect_float) {
				copy_v3_v3(mask, mask_rect_float + pixel_index);
			}
			else if (mask_rect) {
				rgb_uchar_to_float(mask, mask_rect + pixel_index);
			}
			/* Apply correction. */
			const float L = IMB_colormanagement_get_luminance(output);
			float I_l = output[0] + ic * (L - output[0]);
			float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
			float I_a = I_l + ia * (I_g - I_l);
			output[0] /= (output[0] + powf(f * I_a, m));
			I_l = output[1] + ic * (L - output[1]);
			I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
			I_a = I_l + ia * (I_g - I_l);
			output[1] /= (output[1] + powf(f * I_a, m));
			I_l = output[2] + ic * (L - output[2]);
			I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
			I_a = I_l + ia * (I_g - I_l);
			output[2] /= (output[2] + powf(f * I_a, m));
			/* Apply mask. */
			output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
			output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
			output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
			/* Copy result back. */
			IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
			if (rect_float) {
				copy_v4_v4(&rect_float[pixel_index], output);
			}
			else {
				premul_float_to_straight_uchar(&rect[pixel_index], output);
			}
		}
	}
}