Blender V5.0
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#include "BKE_screen.hh"
20
21#include "ED_image.hh"
22#include "ED_screen.hh"
23#include "ED_space_api.hh"
24
25#include "GPU_immediate.hh"
26#include "GPU_state.hh"
27
29#include "IMB_imbuf.hh"
30#include "IMB_imbuf_types.hh"
31
32#include "SEQ_render.hh"
33#include "SEQ_sequencer.hh"
34
35#include "UI_view2d.hh"
36
37#include "WM_api.hh"
38#include "WM_types.hh"
39
40#include "sequencer_intern.hh"
41
42/* Own define. */
43#include "ED_util_imbuf.hh"
44
45/* -------------------------------------------------------------------- */
48
52 int x, y;
54
57
59 float colf[4];
60 float linearcol[4];
61 int z;
62 float zf;
63
65 const float *colfp;
66 int *zp;
67 float *zfp;
68
69 bool draw;
72};
73
75
76/* -------------------------------------------------------------------- */
79
80static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
81 const int coord[2],
82 uchar r_col[4],
83 float r_col_linear[4])
84{
85 const uchar *cp = ibuf->byte_buffer.data + 4 * (coord[1] * ibuf->x + coord[0]);
86 copy_v4_v4_uchar(r_col, cp);
87 rgba_uchar_to_float(r_col_linear, r_col);
89 r_col_linear, false, ibuf->byte_buffer.colorspace);
90}
91
92static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
93{
94 const float *cp = ibuf->float_buffer.data + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
95 copy_v4_v4(r_col, cp);
96}
97
99
100/* -------------------------------------------------------------------- */
103
104static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
105 const rcti *rect,
106 uchar r_col[4],
107 float r_col_linear[4])
108{
109 uint col_accum_ub[4] = {0, 0, 0, 0};
110 zero_v4(r_col_linear);
111 int col_tot = 0;
112 int coord[2];
113 for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
114 for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
115 float col_temp_fl[4];
116 uchar col_temp_ub[4];
117 image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
118 add_v4_v4(r_col_linear, col_temp_fl);
119 col_accum_ub[0] += uint(col_temp_ub[0]);
120 col_accum_ub[1] += uint(col_temp_ub[1]);
121 col_accum_ub[2] += uint(col_temp_ub[2]);
122 col_accum_ub[3] += uint(col_temp_ub[3]);
123 col_tot += 1;
124 }
125 }
126 mul_v4_fl(r_col_linear, 1.0 / float(col_tot));
127
128 r_col[0] = std::min<uchar>(col_accum_ub[0] / col_tot, 255);
129 r_col[1] = std::min<uchar>(col_accum_ub[1] / col_tot, 255);
130 r_col[2] = std::min<uchar>(col_accum_ub[2] / col_tot, 255);
131 r_col[3] = std::min<uchar>(col_accum_ub[3] / col_tot, 255);
132}
133
134static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
135{
136 zero_v4(r_col);
137 int col_tot = 0;
138 int coord[2];
139 for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
140 for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
141 float col_temp_fl[4];
142 image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
143 add_v4_v4(r_col, col_temp_fl);
144 col_tot += 1;
145 }
146 }
147 mul_v4_fl(r_col, 1.0 / float(col_tot));
148}
149
151
152/* -------------------------------------------------------------------- */
155
156static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
157{
159 ARegion *region = CTX_wm_region(C);
160 Image *image = ED_space_image(sima);
161
162 float uv[2];
163 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
164 int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, nullptr);
165
166 void *lock;
168 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(op->customdata);
169 Scene *scene = CTX_data_scene(C);
170 CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
171
172 if (ibuf == nullptr) {
174 info->draw = false;
175 return;
176 }
177
178 int offset[2];
179 offset[0] = int(image->runtime->backdrop_offset[0]);
180 offset[1] = int(image->runtime->backdrop_offset[1]);
181
182 int x = int(uv[0] * ibuf->x), y = int(uv[1] * ibuf->y);
183
184 if (x >= offset[0] && y >= offset[1] && x < (ibuf->x + offset[0]) && y < (ibuf->y + offset[1])) {
185 info->width = ibuf->x;
186 info->height = ibuf->y;
187 info->x = x;
188 info->y = y;
189
190 info->draw = true;
191 info->channels = ibuf->channels;
192
193 info->colp = nullptr;
194 info->colfp = nullptr;
195 info->zp = nullptr;
196 info->zfp = nullptr;
197
198 info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
199
200 rcti sample_rect;
201 sample_rect.xmin = max_ii(0, x - offset[0] - info->sample_size / 2);
202 sample_rect.ymin = max_ii(0, y - offset[1] - info->sample_size / 2);
203
204 sample_rect.xmax = min_ii(ibuf->x - 1, x - offset[0] + info->sample_size / 2);
205 sample_rect.ymax = min_ii(ibuf->y - 1, y - offset[1] + info->sample_size / 2);
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{
279 ARegion *region = CTX_wm_region(C);
280 ImBuf *ibuf = blender::ed::vse::sequencer_ibuf_get(C, scene->r.cfra, 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
412 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
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 = MEM_callocN<ImageSampleInfo>("ImageSampleInfo");
473
474 info->art = region->runtime->type;
477 info->sample_size = RNA_int_get(op->ptr, "size");
478 op->customdata = info;
479
480 ed_imbuf_sample_apply(C, op, event);
481
483
485}
486
488{
489 switch (event->type) {
490 case LEFTMOUSE:
491 case RIGHTMOUSE: /* XXX hardcoded */
492 if (event->val == KM_RELEASE) {
494 return OPERATOR_CANCELLED;
495 }
496 break;
497 case MOUSEMOVE:
498 ed_imbuf_sample_apply(C, op, event);
499 break;
500 default: {
501 break;
502 }
503 }
504
506}
507
512
514{
515 ScrArea *area = CTX_wm_area(C);
516 if (area == nullptr) {
517 return false;
518 }
519
520 switch (area->spacetype) {
521 case SPACE_IMAGE: {
522 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
523 Object *obedit = CTX_data_edit_object(C);
524 if (obedit) {
525 /* Disable when UV editing so it doesn't swallow all click events
526 * (use for setting cursor). */
527 if (ED_space_image_show_uvedit(sima, obedit)) {
528 return false;
529 }
530 }
531 else if (sima->mode != SI_MODE_VIEW) {
532 return false;
533 }
534 return true;
535 }
536 case SPACE_SEQ: {
537 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
538
539 if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
540 return false;
541 }
543 return false;
544 }
545 ARegion *region = CTX_wm_region(C);
546 if (!(region && (region->regiontype == RGN_TYPE_PREVIEW))) {
547 return false;
548 }
549 return true;
550 }
551 }
552
553 return false;
554}
555
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)
Scene * CTX_data_sequencer_scene(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 min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE 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.cc:458
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_CANCELLED
@ 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:693
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(GPUBuiltinShader 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:166
void GPU_logic_op_xor_set(bool enable)
Definition gpu_state.cc:88
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, const ColorSpace *colorspace)
void IMB_freeImBuf(ImBuf *ibuf)
Read Guarded memory(de)allocation.
#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:1668
#define NC_WINDOW
Definition WM_types.hh:375
@ KM_RELEASE
Definition WM_types.hh:312
volatile int lock
nullptr float
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)
wmOperatorStatus ED_imbuf_sample_modal(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])
void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
bool ED_imbuf_sample_poll(bContext *C)
wmOperatorStatus ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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)
uint pos
const ccl_global KernelWorkTile * tile
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
ImBuf * sequencer_ibuf_get(const bContext *C, int timeline_frame, const char *viewname)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:286
void render_pixel_from_sequencer_space_v4(const Scene *scene, float pixel[4])
Definition render.cc:189
VecBase< float, 2 > float2
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)
ARegionRuntimeHandle * runtime
struct CurveMapping * curve_mapping
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
const float * colfp
ARegionType * art
ImageRuntimeHandle * runtime
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
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
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