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
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/* -------------------------------------------------------------------- */
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
75/* -------------------------------------------------------------------- */
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
99/* -------------------------------------------------------------------- */
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
151/* -------------------------------------------------------------------- */
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 }
247 WM_event_add_notifier(C, NC_WINDOW, nullptr);
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
377/* -------------------------------------------------------------------- */
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};
416 immUniformColor3fv(color);
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;
477 region->type, ED_imbuf_sample_draw, info, REGION_DRAW_POST_PIXEL);
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 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.
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
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)
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)
ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
const float * colfp
ARegionType * art
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