Blender V4.3
ed_util_imbuf.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "MEM_guardedalloc.h"
12
14#include "BLI_rect.h"
15
16#include "BKE_colortools.hh"
17#include "BKE_context.hh"
18#include "BKE_image.hh"
19
20#include "ED_image.hh"
21#include "ED_screen.hh"
22#include "ED_space_api.hh"
23
24#include "GPU_immediate.hh"
25#include "GPU_state.hh"
26
28#include "IMB_imbuf.hh"
29#include "IMB_imbuf_types.hh"
30
31#include "SEQ_render.hh"
32#include "SEQ_sequencer.hh"
33
34#include "UI_view2d.hh"
35
36#include "WM_api.hh"
37#include "WM_types.hh"
38
39#include "sequencer_intern.hh"
40
41/* Own define. */
42#include "ED_util_imbuf.hh"
43
44/* -------------------------------------------------------------------- */
47
51 int x, y;
53
56
58 float colf[4];
59 float linearcol[4];
60 int z;
61 float zf;
62
64 const float *colfp;
65 int *zp;
66 float *zfp;
67
68 bool draw;
71};
72
74
75/* -------------------------------------------------------------------- */
78
79static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
80 const int coord[2],
81 uchar r_col[4],
82 float r_col_linear[4])
83{
84 const uchar *cp = ibuf->byte_buffer.data + 4 * (coord[1] * ibuf->x + coord[0]);
85 copy_v4_v4_uchar(r_col, cp);
86 rgba_uchar_to_float(r_col_linear, r_col);
88 r_col_linear, false, ibuf->byte_buffer.colorspace);
89}
90
91static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
92{
93 const float *cp = ibuf->float_buffer.data + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
94 copy_v4_v4(r_col, cp);
95}
96
98
99/* -------------------------------------------------------------------- */
102
103static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
104 const rcti *rect,
105 uchar r_col[4],
106 float r_col_linear[4])
107{
108 uint col_accum_ub[4] = {0, 0, 0, 0};
109 zero_v4(r_col_linear);
110 int col_tot = 0;
111 int coord[2];
112 for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
113 for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
114 float col_temp_fl[4];
115 uchar col_temp_ub[4];
116 image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
117 add_v4_v4(r_col_linear, col_temp_fl);
118 col_accum_ub[0] += uint(col_temp_ub[0]);
119 col_accum_ub[1] += uint(col_temp_ub[1]);
120 col_accum_ub[2] += uint(col_temp_ub[2]);
121 col_accum_ub[3] += uint(col_temp_ub[3]);
122 col_tot += 1;
123 }
124 }
125 mul_v4_fl(r_col_linear, 1.0 / float(col_tot));
126
127 r_col[0] = std::min<uchar>(col_accum_ub[0] / col_tot, 255);
128 r_col[1] = std::min<uchar>(col_accum_ub[1] / col_tot, 255);
129 r_col[2] = std::min<uchar>(col_accum_ub[2] / col_tot, 255);
130 r_col[3] = std::min<uchar>(col_accum_ub[3] / col_tot, 255);
131}
132
133static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
134{
135 zero_v4(r_col);
136 int col_tot = 0;
137 int coord[2];
138 for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
139 for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
140 float col_temp_fl[4];
141 image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
142 add_v4_v4(r_col, col_temp_fl);
143 col_tot += 1;
144 }
145 }
146 mul_v4_fl(r_col, 1.0 / float(col_tot));
147}
148
150
151/* -------------------------------------------------------------------- */
154
155static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
156{
158 ARegion *region = CTX_wm_region(C);
159 Image *image = ED_space_image(sima);
160
161 float uv[2];
162 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
163 int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, nullptr);
164
165 void *lock;
167 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(op->customdata);
168 Scene *scene = CTX_data_scene(C);
169 CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
170
171 if (ibuf == nullptr) {
173 info->draw = false;
174 return;
175 }
176
177 int offset[2];
178 offset[0] = image->runtime.backdrop_offset[0];
179 offset[1] = image->runtime.backdrop_offset[1];
180
181 int x = int(uv[0] * ibuf->x), y = int(uv[1] * ibuf->y);
182
183 if (x >= offset[0] && y >= offset[1] && x < (ibuf->x + offset[0]) && y < (ibuf->y + offset[1])) {
184 info->width = ibuf->x;
185 info->height = ibuf->y;
186 info->x = x;
187 info->y = y;
188
189 info->draw = true;
190 info->channels = ibuf->channels;
191
192 info->colp = nullptr;
193 info->colfp = nullptr;
194 info->zp = nullptr;
195 info->zfp = nullptr;
196
197 info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
198
199 rcti sample_rect;
200 sample_rect.xmin = max_ii(0, x - image->runtime.backdrop_offset[0] - info->sample_size / 2);
201 sample_rect.ymin = max_ii(0, y - image->runtime.backdrop_offset[1] - info->sample_size / 2);
202 /* image_sample_rect_color_*() expects a rect, but we only want to retrieve a single value, so
203 * create a sample rect with size 1. */
204 sample_rect.xmax = sample_rect.xmin;
205 sample_rect.ymax = sample_rect.ymin;
206
207 if (ibuf->byte_buffer.data) {
208 image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
209 rgba_uchar_to_float(info->colf, info->col);
210
211 info->colp = info->col;
212 info->colfp = info->colf;
213 info->color_manage = true;
214 }
215 if (ibuf->float_buffer.data) {
216 image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
217
218 if (ibuf->channels == 4) {
219 /* pass */
220 }
221 else if (ibuf->channels == 3) {
222 info->colf[3] = 1.0f;
223 }
224 else {
225 info->colf[1] = info->colf[0];
226 info->colf[2] = info->colf[0];
227 info->colf[3] = 1.0f;
228 }
229 info->colfp = info->colf;
230
231 copy_v4_v4(info->linearcol, info->colf);
232
233 info->color_manage = true;
234 }
235
236 if (curve_mapping && ibuf->channels == 4) {
237 /* we reuse this callback for set curves point operators */
238 if (RNA_struct_find_property(op->ptr, "point")) {
239 int point = RNA_enum_get(op->ptr, "point");
240
241 if (point == 1) {
242 BKE_curvemapping_set_black_white(curve_mapping, nullptr, info->linearcol);
243 }
244 else if (point == 0) {
245 BKE_curvemapping_set_black_white(curve_mapping, info->linearcol, nullptr);
246 }
248 }
249 }
250
251/* XXX node curve integration. */
252#if 0
253 {
254 ScrArea *area, *cur = curarea;
255
256 node_curvemap_sample(fp); /* sends global to node editor */
257 for (area = G.curscreen->areabase.first; area; area = area->next) {
258 if (area->spacetype == SPACE_NODE) {
259 areawinset(area->win);
260 scrarea_do_windraw(area);
261 }
262 }
263 node_curvemap_sample(nullptr); /* clears global in node editor */
264 curarea = cur;
265 }
266#endif
267 }
268 else {
269 info->draw = false;
270 }
271
274}
275
276static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
277{
278 Scene *scene = CTX_data_scene(C);
279 ARegion *region = CTX_wm_region(C);
280 ImBuf *ibuf = sequencer_ibuf_get(C, scene->r.cfra, 0, nullptr);
281 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(op->customdata);
282 float fx, fy;
283
284 if (ibuf == nullptr) {
285 info->draw = false;
286 return;
287 }
288
289 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fx, &fy);
290
291 fx /= scene->r.xasp / scene->r.yasp;
292
293 fx += float(scene->r.xsch) / 2.0f;
294 fy += float(scene->r.ysch) / 2.0f;
295 fx *= float(ibuf->x) / float(scene->r.xsch);
296 fy *= float(ibuf->y) / float(scene->r.ysch);
297
298 if (fx >= 0.0f && fy >= 0.0f && fx < ibuf->x && fy < ibuf->y) {
299 const float *fp;
300 const uchar *cp;
301 int x = int(fx), y = int(fy);
302
303 info->x = x;
304 info->y = y;
305 info->draw = true;
306 info->channels = ibuf->channels;
307
308 info->colp = nullptr;
309 info->colfp = nullptr;
310
311 if (ibuf->byte_buffer.data) {
312 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
313
314 info->col[0] = cp[0];
315 info->col[1] = cp[1];
316 info->col[2] = cp[2];
317 info->col[3] = cp[3];
318 info->colp = info->col;
319
320 info->colf[0] = float(cp[0]) / 255.0f;
321 info->colf[1] = float(cp[1]) / 255.0f;
322 info->colf[2] = float(cp[2]) / 255.0f;
323 info->colf[3] = float(cp[3]) / 255.0f;
324 info->colfp = info->colf;
325
326 copy_v4_v4(info->linearcol, info->colf);
328 info->linearcol, false, ibuf->byte_buffer.colorspace);
329
330 info->color_manage = true;
331 }
332 if (ibuf->float_buffer.data) {
333 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
334
335 info->colf[0] = fp[0];
336 info->colf[1] = fp[1];
337 info->colf[2] = fp[2];
338 info->colf[3] = fp[3];
339 info->colfp = info->colf;
340
341 /* sequencer's image buffers are in non-linear space, need to make them linear */
342 copy_v4_v4(info->linearcol, info->colf);
344
345 info->color_manage = true;
346 }
347 }
348 else {
349 info->draw = false;
350 }
351
352 IMB_freeImBuf(ibuf);
354}
355
356static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
357{
358 ScrArea *area = CTX_wm_area(C);
359 if (area == nullptr) {
360 return;
361 }
362
363 switch (area->spacetype) {
364 case SPACE_IMAGE: {
365 image_sample_apply(C, op, event);
366 break;
367 }
368 case SPACE_SEQ: {
369 sequencer_sample_apply(C, op, event);
370 break;
371 }
372 }
373}
374
376
377/* -------------------------------------------------------------------- */
382
383void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
384{
385 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(arg_info);
386 if (!info->draw) {
387 return;
388 }
389
390 Scene *scene = CTX_data_scene(C);
391 ED_image_draw_info(scene,
392 region,
393 info->color_manage,
394 info->use_default_view,
395 info->channels,
396 info->x,
397 info->y,
398 info->colp,
399 info->colfp,
400 info->linearcol);
401
402 if (info->sample_size > 1) {
403 ScrArea *area = CTX_wm_area(C);
404
405 if (area && area->spacetype == SPACE_IMAGE) {
406
407 const wmWindow *win = CTX_wm_window(C);
408 const wmEvent *event = win->eventstate;
409
413
414 const float color[3] = {1, 1, 1};
417
418 /* TODO(@ideasman42): lock to pixels. */
419 rctf sample_rect_fl;
420 BLI_rctf_init_pt_radius(&sample_rect_fl,
421 blender::float2{float(event->xy[0] - region->winrct.xmin),
422 float(event->xy[1] - region->winrct.ymin)},
423 float(info->sample_size / 2.0f) * sima->zoom);
424
426
427 GPU_line_width(1.0f);
429 pos, sample_rect_fl.xmin, sample_rect_fl.ymin, sample_rect_fl.xmax, sample_rect_fl.ymax);
430
432
434 }
435 }
436}
437
439{
440 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(op->customdata);
441
444 MEM_freeN(info);
445}
446
448{
449 ARegion *region = CTX_wm_region(C);
450 ScrArea *area = CTX_wm_area(C);
451 if (area) {
452 switch (area->spacetype) {
453 case SPACE_IMAGE: {
454 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
455 if (region->regiontype == RGN_TYPE_WINDOW) {
456 if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
458 }
459 }
460 if (!ED_space_image_has_buffer(sima)) {
461 return OPERATOR_CANCELLED;
462 }
463 break;
464 }
465 case SPACE_SEQ: {
466 /* Sequencer checks could be added. */
467 break;
468 }
469 }
470 }
471
472 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(
473 MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo"));
474
475 info->art = region->type;
478 info->sample_size = RNA_int_get(op->ptr, "size");
479 op->customdata = info;
480
481 ed_imbuf_sample_apply(C, op, event);
482
484
486}
487
489{
490 switch (event->type) {
491 case LEFTMOUSE:
492 case RIGHTMOUSE: /* XXX hardcoded */
493 if (event->val == KM_RELEASE) {
495 return OPERATOR_CANCELLED;
496 }
497 break;
498 case MOUSEMOVE:
499 ed_imbuf_sample_apply(C, op, event);
500 break;
501 }
502
504}
505
510
512{
513 ScrArea *area = CTX_wm_area(C);
514 if (area == nullptr) {
515 return false;
516 }
517
518 switch (area->spacetype) {
519 case SPACE_IMAGE: {
520 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
521 Object *obedit = CTX_data_edit_object(C);
522 if (obedit) {
523 /* Disable when UV editing so it doesn't swallow all click events
524 * (use for setting cursor). */
525 if (ED_space_image_show_uvedit(sima, obedit)) {
526 return false;
527 }
528 }
529 else if (sima->mode != SI_MODE_VIEW) {
530 return false;
531 }
532 return true;
533 }
534 case SPACE_SEQ: {
535 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
536
537 if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
538 return false;
539 }
540 if (SEQ_editing_get(CTX_data_scene(C)) == nullptr) {
541 return false;
542 }
543 ARegion *region = CTX_wm_region(C);
544 if (!(region && (region->regiontype == RGN_TYPE_PREVIEW))) {
545 return false;
546 }
547 return true;
548 }
549 }
550
551 return false;
552}
553
void BKE_curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3])
SpaceImage * CTX_wm_space_image(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
MINLINE int max_ii(int a, int b)
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void zero_v4(float r[4])
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size)
Definition rct.c:462
unsigned char uchar
unsigned int uint
@ IMA_VIEW_AS_RENDER
@ RGN_TYPE_WINDOW
@ RGN_TYPE_PREVIEW
@ SPACE_NODE
@ SPACE_SEQ
@ SPACE_IMAGE
@ SEQ_DRAW_IMG_IMBUF
@ SI_MODE_VIEW
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_space_image_release_buffer(SpaceImage *sima, ImBuf *ibuf, void *lock)
ImBuf * ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
bool ED_space_image_has_buffer(SpaceImage *sima)
bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
void ED_image_draw_info(Scene *scene, ARegion *region, bool color_manage, bool use_default_view, int channels, int x, int y, const unsigned char cp[4], const float fp[4], const float linearcol[4])
Image * ED_space_image(const SpaceImage *sima)
Definition image_edit.cc:40
bool ED_space_image_show_cache_and_mval_over(const SpaceImage *sima, ARegion *region, const int mval[2])
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
#define REGION_DRAW_POST_PIXEL
void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
void immUnbindProgram()
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat()
void immUniformColor3fv(const float rgb[3])
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_line_width(float width)
Definition gpu_state.cc:161
void GPU_logic_op_xor_set(bool enable)
Definition gpu_state.cc:88
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, ColorSpace *colorspace)
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
#define C
Definition RandGen.cpp:29
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1663
#define NC_WINDOW
Definition WM_types.hh:342
@ KM_RELEASE
Definition WM_types.hh:285
volatile int lock
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
static void image_sample_rect_color_ubyte(const ImBuf *ibuf, const rcti *rect, uchar r_col[4], float r_col_linear[4])
static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
static void image_sample_pixel_color_ubyte(const ImBuf *ibuf, const int coord[2], uchar r_col[4], float r_col_linear[4])
static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
bool ED_imbuf_sample_poll(bContext *C)
static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
int ED_imbuf_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void IMB_freeImBuf(ImBuf *)
ccl_global const KernelWorkTile * tile
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
VecBase< float, 2 > float2
void SEQ_render_pixel_from_sequencer_space_v4(Scene *scene, float pixel[4])
Definition render.cc:199
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
int RNA_int_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
ImBuf * sequencer_ibuf_get(const bContext *C, int timeline_frame, int frame_ofs, const char *viewname)
struct ARegionType * type
struct CurveMapping * curve_mapping
ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
const float * colfp
ARegionType * art
void * first
ColorManagedViewSettings view_settings
struct RenderData r
ListBase spacedata
struct ScrArea * next
struct Image * image
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
struct PointerRNA * ptr
struct wmEvent * eventstate
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ MOUSEMOVE
@ LEFTMOUSE