static bool eyedropper_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Eyedropper *eye; op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper"); UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index); if ((eye->ptr.data == NULL) || (eye->prop == NULL) || (RNA_property_editable(&eye->ptr, eye->prop) == false) || (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || (RNA_property_type(eye->prop) != PROP_FLOAT)) { return false; } if (RNA_property_subtype(eye->prop) == PROP_COLOR) { const char *display_device; display_device = scene->display_settings.display_device; eye->display = IMB_colormanagement_display_get_named(display_device); } return true; }
/* 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; }
static void whiteBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask) { WhiteBalanceThreadData data; WhiteBalanceModifierData *wbmd = (WhiteBalanceModifierData *) smd; copy_v3_v3(data.white, wbmd->white_value); IMB_colormanagement_display_to_scene_linear_v3(data.white, IMB_colormanagement_display_get_named(wbmd->modifier.scene->display_settings.display_device)); data.colorspace = ibuf->rect_colorspace; modifier_apply_threaded(ibuf, mask, whiteBalance_apply_threaded, &data); }
/* 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; }
/* update rectangular section of the brush image */ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, int origx, int origy, int w, int h, int xt, int yt) { Scene *scene = painter->scene; Brush *brush = painter->brush; const char *display_device = scene->display_settings.display_device; struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; struct ImagePool *pool = painter->pool; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; bool use_texture_old = (oldtexibuf != NULL); int x, y, thread = 0; float brush_rgb[3]; ImBuf *ibuf = painter->cache.ibuf; ImBuf *texibuf = painter->cache.texibuf; /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display); } else { brush_rgb[0] = 1.0f; brush_rgb[1] = 1.0f; brush_rgb[2] = 1.0f; } /* fill pixels */ for (y = origy; y < h; y++) { for (x = origx; x < w; x++) { /* sample texture and multiply with brush color */ float texco[3], rgba[4]; if (!use_texture_old) { if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); } mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } } if (use_float) { /* handle float pixel */ float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4; float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4; /* read from old texture buffer */ if (use_texture_old) { const float *otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4; copy_v4_v4(rgba, otf); } /* write to new texture buffer */ copy_v4_v4(tf, rgba); /* output premultiplied float image, mf was already premultiplied */ mul_v3_v3fl(bf, rgba, rgba[3]); bf[3] = rgba[3]; } else { unsigned char crgba[4]; /* handle byte pixel */ unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4; unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4; /* read from old texture buffer */ if (use_texture_old) { unsigned char *ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4; crgba[0] = ot[0]; crgba[1] = ot[1]; crgba[2] = ot[2]; crgba[3] = ot[3]; } else rgba_float_to_uchar(crgba, rgba); /* write to new texture buffer */ t[0] = crgba[0]; t[1] = crgba[1]; t[2] = crgba[2]; t[3] = crgba[3]; /* write to brush image buffer */ b[0] = crgba[0]; b[1] = crgba[1]; b[2] = crgba[2]; b[3] = crgba[3]; } } } }
/* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance) { Scene *scene = painter->scene; Brush *brush = painter->brush; const char *display_device = scene->display_settings.display_device; struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; struct ImagePool *pool = painter->pool; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; int x, y, thread = 0; float brush_rgb[3]; /* allocate image buffer */ ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect); /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display); } else { brush_rgb[0] = 1.0f; brush_rgb[1] = 1.0f; brush_rgb[2] = 1.0f; } /* fill image buffer */ for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { /* sample texture and multiply with brush color */ float texco[3], rgba[4]; if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); } mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } if (use_float) { /* write to float pixel */ float *dstf = ibuf->rect_float + (y * size + x) * 4; mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */ dstf[3] = rgba[3]; } else { /* write to byte pixel */ unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4; rgb_float_to_uchar(dst, rgba); dst[3] = FTOCHAR(rgba[3]); } } } return ibuf; }
/* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) { Scene *scene = painter->scene; Brush *brush = painter->brush; const char *display_device = scene->display_settings.display_device; struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; bool is_maskbrush = painter->cache.is_maskbrush; float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush); int radius = BKE_brush_size_get(scene, brush); int xoff = -size * 0.5f + 0.5f; int yoff = -size * 0.5f + 0.5f; int x, y, thread = 0; float brush_rgb[3]; /* allocate image buffer */ ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect); /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { copy_v3_v3(brush_rgb, brush->rgb); if (use_color_correction) { IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display); } } else { brush_rgb[0] = 1.0f; brush_rgb[1] = 1.0f; brush_rgb[2] = 1.0f; } /* fill image buffer */ for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { /* sample texture and multiply with brush color */ float texco[3], rgba[4]; if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_display_to_scene_linear_v3(rgba, display); } mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } if (is_maskbrush) { brush_imbuf_tex_co(&mask_mapping, x, y, texco); rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); } /* when not using masking, multiply in falloff and strength */ if (!use_masking) { float xy[2] = {x + xoff, y + yoff}; float len = len_v2(xy); rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius); } if (use_float) { /* write to float pixel */ float *dstf = ibuf->rect_float + (y * size + x) * 4; mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */ dstf[3] = rgba[3]; } else { /* write to byte pixel */ unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4; rgb_float_to_uchar(dst, rgba); dst[3] = FTOCHAR(rgba[3]); } } } return ibuf; }