Blender V4.3
image_edit.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 "DNA_brush_types.h"
10#include "DNA_mask_types.h"
11#include "DNA_object_types.h"
12#include "DNA_scene_types.h"
13
14#include "BLI_listbase.h"
15#include "BLI_rect.h"
16
17#include "BKE_colortools.hh"
18#include "BKE_context.hh"
19#include "BKE_editmesh.hh"
20#include "BKE_global.hh"
21#include "BKE_image.hh"
22#include "BKE_layer.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_main.hh"
25#include "BKE_paint.hh"
26#include "BKE_scene.hh"
27
28#include "IMB_imbuf_types.hh"
29
30#include "ED_image.hh" /* own include */
31#include "ED_mesh.hh"
32#include "ED_screen.hh"
33#include "ED_uvedit.hh"
34
35#include "UI_view2d.hh"
36
37#include "WM_api.hh"
38#include "WM_types.hh"
39
41{
42 /* NOTE: image_panel_properties() uses pointer to `sima->image` directly. */
43 return sima->image;
44}
45
46void ED_space_image_set(Main *bmain, SpaceImage *sima, Image *ima, bool automatic)
47{
48 /* Automatically pin image when manually assigned, otherwise it follows object. */
49 if (!automatic && sima->image != ima && sima->mode == SI_MODE_UV) {
50 sima->pin = true;
51 }
52
53 sima->image = ima;
54
55 if (ima == nullptr || ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE) {
56 if (sima->mode == SI_MODE_PAINT) {
57 sima->mode = SI_MODE_VIEW;
58 }
59 }
60
61 if (sima->image) {
63 }
64
65 id_us_ensure_real((ID *)sima->image);
66
68}
69
70void ED_space_image_sync(Main *bmain, Image *image, bool ignore_render_viewer)
71{
73 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
74 const bScreen *screen = WM_window_get_active_screen(win);
75 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
76 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
77 if (sl->spacetype != SPACE_IMAGE) {
78 continue;
79 }
80 SpaceImage *sima = (SpaceImage *)sl;
81 if (sima->pin) {
82 continue;
83 }
84 if (ignore_render_viewer && sima->image &&
86 {
87 continue;
88 }
89 ED_space_image_set(bmain, sima, image, true);
90 }
91 }
92 }
93}
94
96{
97 if (sima->mode != SI_MODE_UV || sima->pin) {
98 return;
99 }
100
101 /* Track image assigned to active face in edit mode. */
103 if (!(ob && (ob->mode & OB_MODE_EDIT) && ED_space_image_show_uvedit(sima, ob))) {
104 return;
105 }
106
108 BMesh *bm = em->bm;
109 BMFace *efa = BM_mesh_active_face_get(bm, true, false);
110 if (efa == nullptr) {
111 return;
112 }
113
114 Image *ima = nullptr;
115 ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, nullptr, nullptr, nullptr);
116
117 if (ima != sima->image) {
118 sima->image = ima;
119
120 if (sima->image) {
121 Main *bmain = CTX_data_main(C);
123 }
124 }
125}
126
128{
129 return sima->mask_info.mask;
130}
131
133{
134 sima->mask_info.mask = mask;
135
136 /* weak, but same as image/space */
138
139 if (C) {
141 }
142}
143
145{
146 ImBuf *ibuf;
147
148 if (sima && sima->image) {
149 const Image *image = sima->image;
150
151#if 0
152 if (image->type == IMA_TYPE_R_RESULT && BIF_show_render_spare()) {
153 return BIF_render_spare_imbuf();
154 }
155 else
156#endif
157 {
158 sima->iuser.tile = tile;
159 ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, r_lock);
160 sima->iuser.tile = 0;
161 }
162
163 if (ibuf) {
164 if (image->type == IMA_TYPE_R_RESULT && ibuf->x != 0 && ibuf->y != 0) {
165 /* Render result might be lazily allocated. Return ibuf without buffers to indicate that
166 * there is image buffer but it has no data yet. */
167 return ibuf;
168 }
169
170 if (ibuf->byte_buffer.data || ibuf->float_buffer.data) {
171 return ibuf;
172 }
173 BKE_image_release_ibuf(sima->image, ibuf, *r_lock);
174 *r_lock = nullptr;
175 }
176 }
177 else {
178 *r_lock = nullptr;
179 }
180
181 return nullptr;
182}
183
185{
186 if (sima && sima->image) {
187 BKE_image_release_ibuf(sima->image, ibuf, lock);
188 }
189}
190
192{
194 if (!ibuf) {
195 return result;
196 }
197
198 const bool color = ibuf->channels >= 3;
199 const bool alpha = ibuf->channels == 4;
200 const bool zbuf = ibuf->channels == 1;
201
202 if (!alpha) {
204 }
205 if (!zbuf) {
207 }
208 if (!color) {
210 }
211 return result;
212}
213
215{
216 ImBuf *ibuf;
217 void *lock;
218 bool has_buffer;
219
220 ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
221 has_buffer = (ibuf != nullptr);
223
224 return has_buffer;
225}
226
227void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
228{
229 Scene *scene = sima->iuser.scene;
230 ImBuf *ibuf;
231 void *lock;
232
233 /* TODO(lukas): Support tiled images with different sizes */
234 ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
235
236 if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
237 *r_width = ibuf->x;
238 *r_height = ibuf->y;
239 }
240 else if (sima->image && sima->image->type == IMA_TYPE_R_RESULT && scene) {
241 /* not very important, just nice */
242 BKE_render_resolution(&scene->r, true, r_width, r_height);
243 }
244 /* I know a bit weak... but preview uses not actual image size */
245 // XXX else if (image_preview_active(sima, r_width, r_height));
246 else {
247 *r_width = IMG_SIZE_FALLBACK;
248 *r_height = IMG_SIZE_FALLBACK;
249 }
250
252}
253
254void ED_space_image_get_size_fl(SpaceImage *sima, float r_size[2])
255{
256 int size_i[2];
257 ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
258 r_size[0] = size_i[0];
259 r_size[1] = size_i[1];
260}
261
262void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
263{
264 Image *ima = sima->image;
265 if ((ima == nullptr) || (ima->aspx == 0.0f || ima->aspy == 0.0f)) {
266 *r_aspx = *r_aspy = 1.0;
267 }
268 else {
269 BKE_image_get_aspect(ima, r_aspx, r_aspy);
270 }
271}
272
274 const ARegion *region,
275 float *r_zoomx,
276 float *r_zoomy)
277{
278 int width, height;
279
280 ED_space_image_get_size(sima, &width, &height);
281
282 *r_zoomx = float(BLI_rcti_size_x(&region->winrct) + 1) /
283 float(BLI_rctf_size_x(&region->v2d.cur) * width);
284 *r_zoomy = float(BLI_rcti_size_y(&region->winrct) + 1) /
285 float(BLI_rctf_size_y(&region->v2d.cur) * height);
286}
287
288void ED_space_image_get_uv_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
289{
290 int w, h;
291
292 ED_space_image_get_aspect(sima, r_aspx, r_aspy);
293 ED_space_image_get_size(sima, &w, &h);
294
295 *r_aspx *= float(w);
296 *r_aspy *= float(h);
297
298 if (*r_aspx < *r_aspy) {
299 *r_aspy = *r_aspy / *r_aspx;
300 *r_aspx = 1.0f;
301 }
302 else {
303 *r_aspx = *r_aspx / *r_aspy;
304 *r_aspy = 1.0f;
305 }
306}
307
308void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *r_aspy)
309{
310 if (ima) {
311 int w, h;
312
313 BKE_image_get_aspect(ima, r_aspx, r_aspy);
314 BKE_image_get_size(ima, iuser, &w, &h);
315
316 *r_aspx *= float(w);
317 *r_aspy *= float(h);
318 }
319 else {
320 *r_aspx = 1.0f;
321 *r_aspy = 1.0f;
322 }
323}
324
325void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
326{
327 int sx, sy, width, height;
328 float zoomx, zoomy;
329
330 ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
331 ED_space_image_get_size(sima, &width, &height);
332
333 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
334
335 co[0] = ((mval[0] - sx) / zoomx) / width;
336 co[1] = ((mval[1] - sy) / zoomy) / height;
337}
338
340{
341 int width, height;
342 float aspx, aspy;
343
344 ED_space_image_get_size(sima, &width, &height);
345 ED_space_image_get_aspect(sima, &aspx, &aspy);
346
347 sima->xof = (x - 0.5f) * width * aspx;
348 sima->yof = (y - 0.5f) * height * aspy;
349}
350
352 SpaceImage *sima, const ARegion *region, float x, float y, float *r_x, float *r_y)
353{
354 int sx, sy, width, height;
355 float zoomx, zoomy;
356
357 ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
358 ED_space_image_get_size(sima, &width, &height);
359
360 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
361
362 *r_x = ((x - sx) / zoomx) / width;
363 *r_y = ((y - sy) / zoomy) / height;
364}
365
367 const ARegion *region,
368 const float co[2],
369 float r_co[2])
370{
371 float zoomx, zoomy;
372 int width, height;
373 int sx, sy;
374
375 UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &sx, &sy);
376 ED_space_image_get_size(sima, &width, &height);
377 ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
378
379 r_co[0] = (co[0] * width * zoomx) + float(sx);
380 r_co[1] = (co[1] * height * zoomy) + float(sy);
381}
382
383bool ED_image_slot_cycle(Image *image, int direction)
384{
385 const int cur = image->render_slot;
386 int i, slot;
387
388 BLI_assert(ELEM(direction, -1, 1));
389
390 int num_slots = BLI_listbase_count(&image->renderslots);
391 for (i = 1; i < num_slots; i++) {
392 slot = (cur + ((direction == -1) ? -i : i)) % num_slots;
393 if (slot < 0) {
394 slot += num_slots;
395 }
396
397 RenderSlot *render_slot = BKE_image_get_renderslot(image, slot);
398 if ((render_slot && render_slot->render) || slot == image->last_render_slot) {
399 image->render_slot = slot;
400 break;
401 }
402 }
403
404 if (num_slots == 1) {
405 image->render_slot = 0;
406 }
407 else if (i == num_slots) {
408 image->render_slot = ((cur == 1) ? 0 : 1);
409 }
410
411 if (cur != image->render_slot) {
413 }
414 return (cur != image->render_slot);
415}
416
418 SpaceImage *sima,
419 ImBuf *ibuf,
420 bool use_view_settings)
421{
422 Scene *scene = CTX_data_scene(C);
424
425 /* scope update can be expensive, don't update during paint modes */
426 if (sima->mode == SI_MODE_PAINT) {
427 return;
428 }
429 if (ob && ((ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0)) {
430 return;
431 }
432
433 /* We also don't update scopes of render result during render. */
434 if (G.is_rendering) {
435 const Image *image = sima->image;
436 if (image != nullptr && ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
437 return;
438 }
439 }
440
442 ibuf,
443 use_view_settings ? &scene->view_settings : nullptr,
444 &scene->display_settings);
445}
446
448{
449 return (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE));
450}
451
453{
454 if (ED_space_image_show_render(sima)) {
455 return false;
456 }
457
458 return (sima->mode == SI_MODE_PAINT);
459}
460
462{
463 if (sima) {
464 if (ED_space_image_show_render(sima)) {
465 return false;
466 }
467 if (sima->mode != SI_MODE_UV) {
468 return false;
469 }
470 }
471
472 if (obedit && obedit->type == OB_MESH) {
474 bool ret;
475
476 ret = EDBM_uv_check(em);
477
478 return ret;
479 }
480
481 return false;
482}
483
485{
486 /* check editmode - this is reserved for UV editing */
487 if (obedit && ED_space_image_show_uvedit(sima, obedit)) {
488 return false;
489 }
490
491 return (sima->mode == SI_MODE_MASK);
492}
493
495{
497
498 if (sima) {
499 Scene *scene = CTX_data_scene(C);
500 ViewLayer *view_layer = CTX_data_view_layer(C);
501 BKE_view_layer_synced_ensure(scene, view_layer);
502 Object *obedit = BKE_view_layer_edit_object_get(view_layer);
503 return ED_space_image_check_show_maskedit(sima, obedit);
504 }
505
506 return false;
507}
508
510{
512 return false;
513 }
514
515 const SpaceImage *space_image = CTX_wm_space_image(C);
516 return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
517}
518
520{
522
523 if (sima && sima->mode == SI_MODE_PAINT) {
524 Brush *br = BKE_paint_brush(&CTX_data_tool_settings(C)->imapaint.paint);
525
526 if (br && (br->flag & BRUSH_CURVE)) {
527 return true;
528 }
529 }
530
531 return false;
532}
533
535{
538 return sima->mask_info.mask != nullptr;
539 }
540
541 return false;
542}
543
545{
547 return false;
548 }
549
550 const SpaceImage *space_image = CTX_wm_space_image(C);
551 return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
552}
553
void BKE_scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
SpaceImage * CTX_wm_space_image(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:63
RenderSlot * BKE_image_get_renderslot(Image *ima, int index)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_get_aspect(Image *image, float *r_aspx, float *r_aspy)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
#define IMA_SIGNAL_USER_NEW_IMAGE
Definition BKE_image.hh:142
void BKE_image_get_size(Image *image, ImageUser *iuser, int *r_width, int *r_height)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_edit_object_get(const ViewLayer *view_layer)
void id_us_ensure_real(ID *id)
Definition lib_id.cc:306
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2877
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
#define ELEM(...)
@ BRUSH_CURVE
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ MASK_DRAWFLAG_SPLINE
@ OB_MODE_EDIT
@ OB_MODE_TEXTURE_PAINT
Object is a sort of wrapper for general info.
@ OB_MESH
@ SI_SHOW_ZBUF
@ SI_SHOW_R
@ SI_USE_ALPHA
@ SI_SHOW_G
@ SI_SHOW_B
@ SI_SHOW_ALPHA
@ SPACE_IMAGE
@ SI_MODE_PAINT
@ SI_MODE_VIEW
@ SI_MODE_MASK
@ SI_MODE_UV
#define IMG_SIZE_FALLBACK
bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
bool EDBM_uv_check(BMEditMesh *em)
bool ED_operator_uvedit_space_image(bContext *C)
bool ED_object_get_active_image(Object *ob, int mat_nr, Image **r_ima, ImageUser **r_iuser, const bNode **r_node, const bNodeTree **r_ntree)
Contains defines and structs used throughout the imbuf module.
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
#define C
Definition RandGen.cpp:29
void UI_view2d_view_to_region(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1718
#define ND_SPACE_IMAGE
Definition WM_types.hh:488
#define NC_MASK
Definition WM_types.hh:365
#define NC_SPACE
Definition WM_types.hh:359
#define NA_SELECTED
Definition WM_types.hh:555
volatile int lock
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
draw_view in_light_buf[] float
void ED_space_image_release_buffer(SpaceImage *sima, ImBuf *ibuf, void *lock)
void ED_space_image_auto_set(const bContext *C, SpaceImage *sima)
Definition image_edit.cc:95
void ED_space_image_sync(Main *bmain, Image *image, bool ignore_render_viewer)
Definition image_edit.cc:70
void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
bool ED_space_image_maskedit_visible_splines_poll(bContext *C)
bool ED_space_image_maskedit_mask_visible_splines_poll(bContext *C)
int ED_space_image_get_display_channel_mask(ImBuf *ibuf)
ImBuf * ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
bool ED_space_image_maskedit_mask_poll(bContext *C)
bool ED_space_image_show_paint(const SpaceImage *sima)
void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
void ED_space_image_get_uv_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
bool ED_space_image_paint_curve(const bContext *C)
bool ED_space_image_check_show_maskedit(SpaceImage *sima, Object *obedit)
bool ED_space_image_show_render(const SpaceImage *sima)
void ED_image_point_pos(SpaceImage *sima, const ARegion *region, float x, float y, float *r_x, float *r_y)
void ED_space_image_set(Main *bmain, SpaceImage *sima, Image *ima, bool automatic)
Definition image_edit.cc:46
void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *r_aspy)
bool ED_space_image_has_buffer(SpaceImage *sima)
bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
bool ED_space_image_maskedit_poll(bContext *C)
bool ED_image_slot_cycle(Image *image, int direction)
void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
void ED_space_image_scopes_update(const bContext *C, SpaceImage *sima, ImBuf *ibuf, bool use_view_settings)
void ED_space_image_get_size_fl(SpaceImage *sima, float r_size[2])
void ED_space_image_get_zoom(SpaceImage *sima, const ARegion *region, float *r_zoomx, float *r_zoomy)
void ED_space_image_set_mask(bContext *C, SpaceImage *sima, Mask *mask)
void ED_image_point_pos__reverse(SpaceImage *sima, const ARegion *region, const float co[2], float r_co[2])
bool ED_space_image_cursor_poll(bContext *C)
Image * ED_space_image(const SpaceImage *sima)
Definition image_edit.cc:40
void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
Mask * ED_space_image_get_mask(const SpaceImage *sima)
ccl_global const KernelWorkTile * tile
ccl_device_inline float4 mask(const int4 mask, const float4 a)
#define G(x, y, z)
return ret
short mat_nr
Definition DNA_ID.h:413
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
struct Scene * scene
void * first
ListBase wm
Definition BKE_main.hh:239
struct Mask * mask
struct RenderResult * render
ColorManagedViewSettings view_settings
struct RenderData r
ColorManagedDisplaySettings display_settings
struct Scopes scopes
MaskSpaceInfo mask_info
struct ImageUser iuser
struct Image * image
ListBase areabase
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
bScreen * WM_window_get_active_screen(const wmWindow *win)