Blender V4.5
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] = image->runtime->backdrop_offset[0];
180 offset[1] = 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 - image->runtime->backdrop_offset[0] - info->sample_size / 2);
202 sample_rect.ymin = max_ii(0, y - image->runtime->backdrop_offset[1] - info->sample_size / 2);
203 /* image_sample_rect_color_*() expects a rect, but we only want to retrieve a single value, so
204 * create a sample rect with size 1. */
205 sample_rect.xmax = sample_rect.xmin;
206 sample_rect.ymax = sample_rect.ymin;
207
208 if (ibuf->byte_buffer.data) {
209 image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
210 rgba_uchar_to_float(info->colf, info->col);
211
212 info->colp = info->col;
213 info->colfp = info->colf;
214 info->color_manage = true;
215 }
216 if (ibuf->float_buffer.data) {
217 image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
218
219 if (ibuf->channels == 4) {
220 /* pass */
221 }
222 else if (ibuf->channels == 3) {
223 info->colf[3] = 1.0f;
224 }
225 else {
226 info->colf[1] = info->colf[0];
227 info->colf[2] = info->colf[0];
228 info->colf[3] = 1.0f;
229 }
230 info->colfp = info->colf;
231
232 copy_v4_v4(info->linearcol, info->colf);
233
234 info->color_manage = true;
235 }
236
237 if (curve_mapping && ibuf->channels == 4) {
238 /* we reuse this callback for set curves point operators */
239 if (RNA_struct_find_property(op->ptr, "point")) {
240 int point = RNA_enum_get(op->ptr, "point");
241
242 if (point == 1) {
243 BKE_curvemapping_set_black_white(curve_mapping, nullptr, info->linearcol);
244 }
245 else if (point == 0) {
246 BKE_curvemapping_set_black_white(curve_mapping, info->linearcol, nullptr);
247 }
249 }
250 }
251
252/* XXX node curve integration. */
253#if 0
254 {
255 ScrArea *area, *cur = curarea;
256
257 node_curvemap_sample(fp); /* sends global to node editor */
258 for (area = G.curscreen->areabase.first; area; area = area->next) {
259 if (area->spacetype == SPACE_NODE) {
260 areawinset(area->win);
261 scrarea_do_windraw(area);
262 }
263 }
264 node_curvemap_sample(nullptr); /* clears global in node editor */
265 curarea = cur;
266 }
267#endif
268 }
269 else {
270 info->draw = false;
271 }
272
275}
276
277static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
278{
279 Scene *scene = CTX_data_scene(C);
280 ARegion *region = CTX_wm_region(C);
281 ImBuf *ibuf = blender::ed::vse::sequencer_ibuf_get(C, scene->r.cfra, nullptr);
282 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(op->customdata);
283 float fx, fy;
284
285 if (ibuf == nullptr) {
286 info->draw = false;
287 return;
288 }
289
290 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fx, &fy);
291
292 fx /= scene->r.xasp / scene->r.yasp;
293
294 fx += float(scene->r.xsch) / 2.0f;
295 fy += float(scene->r.ysch) / 2.0f;
296 fx *= float(ibuf->x) / float(scene->r.xsch);
297 fy *= float(ibuf->y) / float(scene->r.ysch);
298
299 if (fx >= 0.0f && fy >= 0.0f && fx < ibuf->x && fy < ibuf->y) {
300 const float *fp;
301 const uchar *cp;
302 int x = int(fx), y = int(fy);
303
304 info->x = x;
305 info->y = y;
306 info->draw = true;
307 info->channels = ibuf->channels;
308
309 info->colp = nullptr;
310 info->colfp = nullptr;
311
312 if (ibuf->byte_buffer.data) {
313 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
314
315 info->col[0] = cp[0];
316 info->col[1] = cp[1];
317 info->col[2] = cp[2];
318 info->col[3] = cp[3];
319 info->colp = info->col;
320
321 info->colf[0] = float(cp[0]) / 255.0f;
322 info->colf[1] = float(cp[1]) / 255.0f;
323 info->colf[2] = float(cp[2]) / 255.0f;
324 info->colf[3] = float(cp[3]) / 255.0f;
325 info->colfp = info->colf;
326
327 copy_v4_v4(info->linearcol, info->colf);
329 info->linearcol, false, ibuf->byte_buffer.colorspace);
330
331 info->color_manage = true;
332 }
333 if (ibuf->float_buffer.data) {
334 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
335
336 info->colf[0] = fp[0];
337 info->colf[1] = fp[1];
338 info->colf[2] = fp[2];
339 info->colf[3] = fp[3];
340 info->colfp = info->colf;
341
342 /* sequencer's image buffers are in non-linear space, need to make them linear */
343 copy_v4_v4(info->linearcol, info->colf);
345
346 info->color_manage = true;
347 }
348 }
349 else {
350 info->draw = false;
351 }
352
353 IMB_freeImBuf(ibuf);
355}
356
357static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
358{
359 ScrArea *area = CTX_wm_area(C);
360 if (area == nullptr) {
361 return;
362 }
363
364 switch (area->spacetype) {
365 case SPACE_IMAGE: {
366 image_sample_apply(C, op, event);
367 break;
368 }
369 case SPACE_SEQ: {
370 sequencer_sample_apply(C, op, event);
371 break;
372 }
373 }
374}
375
377
378/* -------------------------------------------------------------------- */
383
384void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
385{
386 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(arg_info);
387 if (!info->draw) {
388 return;
389 }
390
391 Scene *scene = CTX_data_scene(C);
392 ED_image_draw_info(scene,
393 region,
394 info->color_manage,
395 info->use_default_view,
396 info->channels,
397 info->x,
398 info->y,
399 info->colp,
400 info->colfp,
401 info->linearcol);
402
403 if (info->sample_size > 1) {
404 ScrArea *area = CTX_wm_area(C);
405
406 if (area && area->spacetype == SPACE_IMAGE) {
407
408 const wmWindow *win = CTX_wm_window(C);
409 const wmEvent *event = win->eventstate;
410
414
415 const float color[3] = {1, 1, 1};
417 immUniformColor3fv(color);
418
419 /* TODO(@ideasman42): lock to pixels. */
420 rctf sample_rect_fl;
421 BLI_rctf_init_pt_radius(&sample_rect_fl,
422 blender::float2{float(event->xy[0] - region->winrct.xmin),
423 float(event->xy[1] - region->winrct.ymin)},
424 float(info->sample_size / 2.0f) * sima->zoom);
425
427
428 GPU_line_width(1.0f);
430 pos, sample_rect_fl.xmin, sample_rect_fl.ymin, sample_rect_fl.xmax, sample_rect_fl.ymax);
431
433
435 }
436 }
437}
438
440{
441 ImageSampleInfo *info = static_cast<ImageSampleInfo *>(op->customdata);
442
445 MEM_freeN(info);
446}
447
449{
450 ARegion *region = CTX_wm_region(C);
451 ScrArea *area = CTX_wm_area(C);
452 if (area) {
453 switch (area->spacetype) {
454 case SPACE_IMAGE: {
455 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
456 if (region->regiontype == RGN_TYPE_WINDOW) {
457 if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
459 }
460 }
461 if (!ED_space_image_has_buffer(sima)) {
462 return OPERATOR_CANCELLED;
463 }
464 break;
465 }
466 case SPACE_SEQ: {
467 /* Sequencer checks could be added. */
468 break;
469 }
470 }
471 }
472
473 ImageSampleInfo *info = MEM_callocN<ImageSampleInfo>("ImageSampleInfo");
474
475 info->art = region->runtime->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 default: {
502 break;
503 }
504 }
505
507}
508
513
515{
516 ScrArea *area = CTX_wm_area(C);
517 if (area == nullptr) {
518 return false;
519 }
520
521 switch (area->spacetype) {
522 case SPACE_IMAGE: {
523 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
524 Object *obedit = CTX_data_edit_object(C);
525 if (obedit) {
526 /* Disable when UV editing so it doesn't swallow all click events
527 * (use for setting cursor). */
528 if (ED_space_image_show_uvedit(sima, obedit)) {
529 return false;
530 }
531 }
532 else if (sima->mode != SI_MODE_VIEW) {
533 return false;
534 }
535 return true;
536 }
537 case SPACE_SEQ: {
538 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
539
540 if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
541 return false;
542 }
543 if (blender::seq::editing_get(CTX_data_scene(C)) == nullptr) {
544 return false;
545 }
546 ARegion *region = CTX_wm_region(C);
547 if (!(region && (region->regiontype == RGN_TYPE_PREVIEW))) {
548 return false;
549 }
550 return true;
551 }
552 }
553
554 return false;
555}
556
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.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:714
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:166
void GPU_logic_op_xor_set(bool enable)
Definition gpu_state.cc:88
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
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:1667
#define NC_WINDOW
Definition WM_types.hh:372
@ KM_RELEASE
Definition WM_types.hh:309
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)
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:272
void render_pixel_from_sequencer_space_v4(const Scene *scene, float pixel[4])
Definition render.cc:184
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:754
short val
Definition WM_types.hh:756
int mval[2]
Definition WM_types.hh:760
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