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
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) {
203 result &= ~(SI_USE_ALPHA | SI_SHOW_ALPHA);
204 }
205 if (!zbuf) {
206 result &= ~SI_SHOW_ZBUF;
207 }
208 if (!color) {
209 result &= ~(SI_SHOW_R | SI_SHOW_G | SI_SHOW_B);
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
339void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
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 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.
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
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
struct Scopes scopes
MaskSpaceInfo mask_info
struct ImageUser iuser
struct Image * image
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)