Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Mon, 11 Jun 2018 14:02:46 +0000 (16:02 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Mon, 11 Jun 2018 14:02:46 +0000 (16:02 +0200)
Conflicts:
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/intern/mesh_convert.c
source/blender/editors/interface/interface_eyedropper_color.c
source/blender/editors/object/object_add.c
source/blender/editors/space_image/image_ops.c
source/blender/makesrna/intern/rna_image.c
source/blender/windowmanager/intern/wm_draw.c

37 files changed:
1  2 
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/bpath.c
source/blender/blenkernel/intern/image.c
source/blender/blenkernel/intern/mesh_convert.c
source/blender/blenkernel/intern/node.c
source/blender/collada/DocumentImporter.cpp
source/blender/editors/include/ED_image.h
source/blender/editors/include/ED_node.h
source/blender/editors/interface/interface_eyedropper_color.c
source/blender/editors/object/object_add.c
source/blender/editors/render/render_internal.c
source/blender/editors/render/render_opengl.c
source/blender/editors/render/render_view.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/editors/space_image/image_edit.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_node/node_add.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_manipulators.c
source/blender/makesrna/intern/rna_color.c
source/blender/makesrna/intern/rna_image.c
source/blender/makesrna/intern/rna_image_api.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_material.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/makesrna/intern/rna_space.c
source/blender/nodes/composite/node_composite_tree.c
source/blender/nodes/shader/node_shader_tree.c
source/blender/nodes/texture/node_texture_tree.c
source/blender/render/intern/source/pipeline.c
source/blender/windowmanager/intern/wm_draw.c
source/blender/windowmanager/intern/wm_operators.c

@@@ -133,22 -100,6 +133,22 @@@ void   BKE_mesh_orco_verts_transform(st
  int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
  struct Mesh *BKE_mesh_from_object(struct Object *ob);
  void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me);
-         struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary);
- void BKE_mesh_from_nurbs(struct Object *ob);
 +void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
 +int  BKE_mesh_nurbs_to_mdata(
 +        struct Object *ob, struct MVert **r_allvert, int *r_totvert,
 +        struct MEdge **r_alledge, int *r_totedge, struct MLoop **r_allloop, struct MPoly **r_allpoly,
 +        int *r_totloop, int *r_totpoly);
 +int BKE_mesh_nurbs_displist_to_mdata(
 +        struct Object *ob, const struct ListBase *dispbase,
 +        struct MVert **r_allvert, int *r_totvert,
 +        struct MEdge **r_alledge, int *r_totedge,
 +        struct MLoop **r_allloop, struct MPoly **r_allpoly,
 +        struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly);
 +void BKE_mesh_from_nurbs_displist(
- void BKE_mesh_to_curve(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
++        struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary);
++void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob);
 +void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, const int edge_users_test);
++void BKE_mesh_to_curve(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
  void BKE_mesh_material_index_remove(struct Mesh *me, short index);
  void BKE_mesh_material_index_clear(struct Mesh *me);
  void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
Simple merge
@@@ -490,63 -479,11 +490,63 @@@ int BKE_mesh_nurbs_displist_to_mdata
        return 0;
  }
  
 +Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
 +{
 +      Curve *cu = ob->data;
 +      Mesh *mesh;
 +      MVert *allvert;
 +      MEdge *alledge;
 +      MLoop *allloop;
 +      MPoly *allpoly;
 +      MLoopUV *alluv = NULL;
 +      int totvert, totedge, totloop, totpoly;
 +      bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
 +
 +      if (BKE_mesh_nurbs_displist_to_mdata(
 +              ob, dispbase, &allvert, &totvert, &alledge,
 +              &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL,
 +              &totloop, &totpoly) != 0)
 +      {
 +              /* Error initializing mdata. This often happens when curve is empty */
 +              return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
 +      }
 +
 +      mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
 +      mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
 +
 +      memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
 +      memcpy(mesh->medge, alledge, totedge * sizeof(MEdge));
 +      memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop));
 +      memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
 +
 +      if (alluv) {
 +              const char *uvname = "Orco";
 +              CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
 +      }
 +
 +      MEM_freeN(allvert);
 +      MEM_freeN(alledge);
 +      MEM_freeN(allloop);
 +      MEM_freeN(allpoly);
 +
 +      return mesh;
 +}
 +
 +Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
 +{
 +      ListBase disp = {NULL, NULL};
 +
 +      if (ob->curve_cache) {
 +              disp = ob->curve_cache->disp;
 +      }
 +
 +      return BKE_mesh_new_nomain_from_curve_displist(ob, &disp);
 +}
  
  /* this may fail replacing ob->data, be sure to check ob->type */
- void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary)
+ void BKE_mesh_from_nurbs_displist(
 -        Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name)
++        Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary)
  {
-       Main *bmain = G.main;
        Object *ob1;
        DerivedMesh *dm = ob->derivedFinal;
        Mesh *me;
                ob1 = ob1->id.next;
        }
  
 -      BKE_libblock_free_us(bmain, cu);
 +      if (temporary) {
 +              /* For temporary objects in BKE_mesh_new_from_object don't remap
 +               * the entire scene with associated depsgraph updates, which are
 +               * problematic for renderers exporting data. */
 +              id_us_min(&cu->id);
 +              BKE_libblock_free(bmain, cu);
 +      }
 +      else {
 +              BKE_libblock_free_us(bmain, cu);
 +      }
  }
  
- void BKE_mesh_from_nurbs(Object *ob)
+ void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
  {
        Curve *cu = (Curve *) ob->data;
        bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
                disp = ob->curve_cache->disp;
        }
  
-       BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv, cu->id.name, false);
 -      BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name);
++      BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
  }
  
  typedef struct EdgeLink {
@@@ -812,18 -741,18 +812,18 @@@ void BKE_mesh_to_curve_nurblist(const M
        }
  }
  
- void BKE_mesh_to_curve(Depsgraph *depsgraph, Scene *scene, Object *ob)
 -void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob)
++void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
  {
        /* make new mesh data from the original copy */
 -      DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_MESH);
 +      Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_MESH);
        ListBase nurblist = {NULL, NULL};
        bool needsFree = false;
  
 -      BKE_mesh_to_curve_nurblist(dm, &nurblist, 0);
 -      BKE_mesh_to_curve_nurblist(dm, &nurblist, 1);
 +      BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
 +      BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1);
  
        if (nurblist.first) {
-               Curve *cu = BKE_curve_add(G.main, ob->id.name + 2, OB_CURVE);
+               Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVE);
                cu->flag |= CU_3D;
  
                cu->nurb = nurblist;
@@@ -929,7 -849,7 +929,7 @@@ Mesh *BKE_mesh_new_from_object
  
                        /* convert object type to mesh */
                        uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
-                       BKE_mesh_from_nurbs_displist(tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
 -                      BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2);
++                      BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
  
                        tmpmesh = tmpobj->data;
  
@@@ -43,7 -42,8 +43,7 @@@ struct ViewLayer
  
  /* image_edit.c, exported for transform */
  struct Image *ED_space_image(struct SpaceImage *sima);
- void          ED_space_image_set(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima);
 -void          ED_space_image_set(
 -        struct Main *bmain, struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima);
++void          ED_space_image_set(struct Main *bmain, struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima);
  struct Mask  *ED_space_image_get_mask(struct SpaceImage *sima);
  void          ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
  
@@@ -131,8 -132,9 +132,9 @@@ static void eyedropper_exit(bContext *C
  void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
  {
        /* we could use some clever */
 -      wmWindow *win = CTX_wm_window(C);
 -      ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
+       Main *bmain = CTX_data_main(C);
 +      bScreen *screen = CTX_wm_screen(C);
 +      ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
        const char *display_device = CTX_data_scene(C)->display_settings.display_device;
        struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
  
@@@ -1635,10 -1567,10 +1635,10 @@@ static void convert_ensure_curve_cache(
        }
  }
  
- static void curvetomesh(Depsgraph *depsgraph, Scene *scene, Object *ob)
 -static void curvetomesh(Main *bmain, Scene *scene, Object *ob)
++static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
  {
 -      convert_ensure_curve_cache(bmain, scene, ob);
 +      convert_ensure_curve_cache(depsgraph, scene, ob);
-       BKE_mesh_from_nurbs(ob); /* also does users */
+       BKE_mesh_from_nurbs(bmain, ob); /* also does users */
  
        if (ob->type == OB_MESH) {
                BKE_object_free_modifiers(ob, 0);
@@@ -1785,7 -1724,7 +1785,7 @@@ static int convert_exec(bContext *C, wm
                                newob = ob;
                        }
  
-                       BKE_mesh_to_curve(depsgraph, scene, newob);
 -                      BKE_mesh_to_curve(bmain, scene, newob);
++                      BKE_mesh_to_curve(bmain, depsgraph, scene, newob);
  
                        if (newob->type == OB_CURVE) {
                                BKE_object_free_modifiers(newob, 0);   /* after derivedmesh calls! */
                        BKE_curve_curve_dimension_update(cu);
  
                        if (target == OB_MESH) {
-                               curvetomesh(depsgraph, scene, newob);
 -                              curvetomesh(bmain, scene, newob);
++                              curvetomesh(bmain, depsgraph, scene, newob);
  
                                /* meshes doesn't use displist */
                                BKE_object_free_curve_cache(newob);
                                        newob = ob;
                                }
  
-                               curvetomesh(depsgraph, scene, newob);
 -                              curvetomesh(bmain, scene, newob);
++                              curvetomesh(bmain, depsgraph, scene, newob);
  
                                /* meshes doesn't use displist */
                                BKE_object_free_curve_cache(newob);
@@@ -1002,8 -974,8 +1002,8 @@@ static int screen_render_invoke(bContex
        WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob);
  
        /* get a render result image, and make sure it is empty */
-       ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
-       BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
 -      ima = BKE_image_verify_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result");
++      ima = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
+       BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE);
        BKE_image_backup_render(rj->scene, ima, true);
        rj->image = ima;
  
@@@ -1107,10 -1076,8 +1107,10 @@@ static int texture_paint_toggle_exec(bC
                                                if (sl->spacetype == SPACE_IMAGE) {
                                                        SpaceImage *sima = (SpaceImage *)sl;
  
 -                                                      if (!sima->pin)
 -                                                              ED_space_image_set(bmain, sima, scene, scene->obedit, ima);
 +                                                      if (!sima->pin) {
 +                                                              Object *obedit = CTX_data_edit_object(C);
-                                                               ED_space_image_set(sima, scene, obedit, ima);
++                                                              ED_space_image_set(bmain, sima, scene, obedit, ima);
 +                                                      }
                                                }
                                        }
                                }
@@@ -5437,11 -5447,9 +5437,12 @@@ static int texture_paint_image_from_vie
        ImBuf *ibuf;
        char filename[FILE_MAX];
  
+       Main *bmain = CTX_data_main(C);
 +      Depsgraph *depsgraph = CTX_data_depsgraph(C);
        Scene *scene = CTX_data_scene(C);
        ToolSettings *settings = scene->toolsettings;
 +      View3D *v3d = CTX_wm_view3d(C);
 +      RegionView3D *rv3d = CTX_wm_region_view3d(C);
        int w = settings->imapaint.screen_grab_size[0];
        int h = settings->imapaint.screen_grab_size[1];
        int maxsize;
@@@ -5698,9 -5744,9 +5699,9 @@@ static bool proj_paint_add_slot(bContex
  
                if (ima) {
                        BKE_texpaint_slot_refresh_cache(scene, ma);
-                       BKE_image_signal(ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
+                       BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
                        WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
 -                      DAG_id_tag_update(&ma->id, 0);
 +                      DEG_id_tag_update(&ma->id, 0);
                        ED_area_tag_redraw(CTX_wm_area(C));
  
                        BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
@@@ -64,8 -62,11 +64,8 @@@ Image *ED_space_image(SpaceImage *sima
  }
  
  /* called to assign images to UV faces */
- void ED_space_image_set(SpaceImage *sima, Scene *UNUSED(scene), Object *obedit, Image *ima)
 -void ED_space_image_set(Main *bmain, SpaceImage *sima, Scene *scene, Object *obedit, Image *ima)
++void ED_space_image_set(Main *bmain, SpaceImage *sima, Scene *UNUSED(scene), Object *obedit, Image *ima)
  {
 -      /* context may be NULL, so use global */
 -      ED_uvedit_assign_image(bmain, scene, obedit, ima, sima->image);
 -
        /* change the space ima after because uvedit_face_visible_test uses the space ima
         * to check if the face is displayed in UV-localview */
        sima->image = ima;
@@@ -1308,9 -1304,19 +1308,9 @@@ static int image_open_exec(bContext *C
        }
        else if (sa && sa->spacetype == SPACE_IMAGE) {
                SpaceImage *sima = sa->spacedata.first;
-               ED_space_image_set(sima, scene, obedit, ima);
+               ED_space_image_set(bmain, sima, scene, obedit, ima);
                iuser = &sima->iuser;
        }
 -      else if (sa && sa->spacetype == SPACE_VIEW3D) {
 -              View3D *v3d = sa->spacedata.first;
 -
 -              for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
 -                      if (bgpic->ima == ima) {
 -                              iuser = &bgpic->iuser;
 -                              break;
 -                      }
 -              }
 -      }
        else {
                Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
                if (tex && tex->type == TEX_IMAGE) {
@@@ -2349,8 -2346,8 +2352,8 @@@ static int image_reload_exec(bContext *
        ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
  
        // XXX other users?
-       BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
+       BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
 -      DAG_id_tag_update(&ima->id, 0);
 +      DEG_id_tag_update(&ima->id, 0);
  
        WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
  
@@@ -2460,7 -2458,7 +2463,7 @@@ static int image_new_exec(bContext *C, 
                                                SpaceImage *sima_other = (SpaceImage *)sl;
  
                                                if (!sima_other->pin) {
-                                                       ED_space_image_set(sima_other, scene, obedit, ima);
 -                                                      ED_space_image_set(bmain, sima_other, scene, scene->obedit, ima);
++                                                      ED_space_image_set(bmain, sima_other, scene, obedit, ima);
                                                }
                                        }
                                }
@@@ -3602,8 -3600,9 +3605,9 @@@ void IMAGE_OT_change_frame(wmOperatorTy
  
  /* Reload cached render results... */
  /* goes over all scenes, reads render layers */
 -static int image_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
 +static int image_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
  {
+       Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
        SpaceImage *sima = CTX_wm_space_image(C);
        Image *ima;
@@@ -3151,8 -3234,8 +3151,9 @@@ void ED_init_node_socket_type_virtual(b
  
  void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeInstanceKey parent_key)
  {
+       Main *bmain = CTX_data_main(C);
        bNodeInstanceKey active_viewer_key = (snode->nodetree ? snode->nodetree->active_viewer_key : NODE_INSTANCE_KEY_NONE);
 +      float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f};
        Image *ima;
        void *lock;
        ImBuf *ibuf;
@@@ -673,8 -690,24 +676,8 @@@ void ED_node_set_active(Main *bmain, bN
                                        ED_node_tag_update_nodetree(bmain, ntree, node);
  
                                /* addnode() doesnt link this yet... */
-                               node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+                               node->id = (ID *)BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
                        }
 -                      else if (node->type == CMP_NODE_R_LAYERS) {
 -                              Scene *scene;
 -
 -                              for (scene = bmain->scene.first; scene; scene = scene->id.next) {
 -                                      if (scene->nodetree && scene->use_nodes && ntreeHasTree(scene->nodetree, ntree)) {
 -                                              if (node->id == NULL || node->id == (ID *)scene) {
 -                                                      int num_layers = BLI_listbase_count(&scene->r.layers);
 -                                                      scene->r.actlay = node->custom1;
 -                                                      /* Clamp the value, because it might have come from a different
 -                                                       * scene which could have more render layers than new one.
 -                                                       */
 -                                                      scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
 -                                              }
 -                                      }
 -                              }
 -                      }
                        else if (node->type == CMP_NODE_COMPOSITE) {
                                if (was_output == 0) {
                                        bNode *tnode;
index 73b0f44,0000000..851e397
mode 100644,000000..100644
--- /dev/null
@@@ -1,616 -1,0 +1,621 @@@
-       Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/editors/space_node/node_manipulators.c
 + *  \ingroup spnode
 + */
 +
 +#include <math.h>
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_math_matrix.h"
 +#include "BLI_math_vector.h"
 +#include "BLI_rect.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_image.h"
++#include "BKE_main.h"
 +
 +#include "ED_screen.h"
 +#include "ED_manipulator_library.h"
 +
 +#include "IMB_imbuf_types.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "RNA_access.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "node_intern.h"
 +
 +
 +/* -------------------------------------------------------------------- */
 +
 +/** \name Local Utilities
 + * \{ */
 +
 +static void node_manipulator_calc_matrix_space(
 +        const SpaceNode *snode, const ARegion *ar, float matrix_space[4][4])
 +{
 +      unit_m4(matrix_space);
 +      mul_v3_fl(matrix_space[0], snode->zoom);
 +      mul_v3_fl(matrix_space[1], snode->zoom);
 +      matrix_space[3][0] = (ar->winx / 2) + snode->xof;
 +      matrix_space[3][1] = (ar->winy / 2) + snode->yof;
 +}
 +
 +static void node_manipulator_calc_matrix_space_with_image_dims(
 +        const SpaceNode *snode, const ARegion *ar, const float image_dims[2], float matrix_space[4][4])
 +{
 +      unit_m4(matrix_space);
 +      mul_v3_fl(matrix_space[0], snode->zoom * image_dims[0]);
 +      mul_v3_fl(matrix_space[1], snode->zoom * image_dims[1]);
 +      matrix_space[3][0] = ((ar->winx / 2) + snode->xof) - ((image_dims[0] / 2.0f) * snode->zoom);
 +      matrix_space[3][1] = ((ar->winy / 2) + snode->yof) - ((image_dims[1] / 2.0f) * snode->zoom);
 +}
 +
 +/** \} */
 +
 +
 +
 +/* -------------------------------------------------------------------- */
 +
 +/** \name Backdrop Manipulator
 + * \{ */
 +
 +static void manipulator_node_backdrop_prop_matrix_get(
 +        const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
 +        void *value_p)
 +{
 +      float (*matrix)[4] = value_p;
 +      BLI_assert(mpr_prop->type->array_length == 16);
 +      const SpaceNode *snode = mpr_prop->custom_func.user_data;
 +      matrix[0][0] = snode->zoom;
 +      matrix[1][1] = snode->zoom;
 +      matrix[3][0] = snode->xof;
 +      matrix[3][1] = snode->yof;
 +}
 +
 +static void manipulator_node_backdrop_prop_matrix_set(
 +        const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
 +        const void *value_p)
 +{
 +      const float (*matrix)[4] = value_p;
 +      BLI_assert(mpr_prop->type->array_length == 16);
 +      SpaceNode *snode = mpr_prop->custom_func.user_data;
 +      snode->zoom = matrix[0][0];
 +      snode->zoom = matrix[1][1];
 +      snode->xof  = matrix[3][0];
 +      snode->yof  = matrix[3][1];
 +}
 +
 +static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
 +{
 +      SpaceNode *snode = CTX_wm_space_node(C);
 +
 +      if ((snode->flag & SNODE_BACKDRAW) == 0) {
 +              return false;
 +      }
 +
 +      if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
 +              bNode *node = nodeGetActive(snode->edittree);
 +
 +              if (node && ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
 +                      return true;
 +              }
 +      }
 +
 +      return false;
 +}
 +
 +static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__);
 +
 +      wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL);
 +
 +      RNA_enum_set(wwrapper->manipulator->ptr, "transform",
 +                   ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM);
 +
 +      mgroup->customdata = wwrapper;
 +}
 +
 +static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
++      Main *bmain = CTX_data_main(C);
 +      wmManipulator *cage = ((wmManipulatorWrapper *)mgroup->customdata)->manipulator;
 +      const ARegion *ar = CTX_wm_region(C);
 +      /* center is always at the origin */
 +      const float origin[3] = {ar->winx / 2, ar->winy / 2};
 +
 +      void *lock;
-       Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
++      Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
 +      ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
 +
 +      if (ibuf) {
 +              const float dims[2] = {
 +                      (ibuf->x > 0) ? ibuf->x : 64.0f,
 +                      (ibuf->y > 0) ? ibuf->y : 64.0f,
 +              };
 +
 +              RNA_float_set_array(cage->ptr, "dimensions", dims);
 +              WM_manipulator_set_matrix_location(cage, origin);
 +              WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, false);
 +
 +              /* need to set property here for undo. TODO would prefer to do this in _init */
 +              SpaceNode *snode = CTX_wm_space_node(C);
 +#if 0
 +              PointerRNA nodeptr;
 +              RNA_pointer_create(snode->id, &RNA_SpaceNodeEditor, snode, &nodeptr);
 +              WM_manipulator_target_property_def_rna(cage, "offset", &nodeptr, "backdrop_offset", -1);
 +              WM_manipulator_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1);
 +#endif
 +
 +              WM_manipulator_target_property_def_func(
 +                      cage, "matrix",
 +                      &(const struct wmManipulatorPropertyFnParams) {
 +                          .value_get_fn = manipulator_node_backdrop_prop_matrix_get,
 +                          .value_set_fn = manipulator_node_backdrop_prop_matrix_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = snode,
 +                      });
 +      }
 +      else {
 +              WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, true);
 +      }
 +
 +      BKE_image_release_ibuf(ima, ibuf, lock);
 +}
 +
 +void NODE_WGT_backdrop_transform(wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Backdrop Transform Widget";
 +      wgt->idname = "NODE_WGT_backdrop_transform";
 +
 +      wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT;
 +
 +      wgt->poll = WIDGETGROUP_node_transform_poll;
 +      wgt->setup = WIDGETGROUP_node_transform_setup;
 +      wgt->refresh = WIDGETGROUP_node_transform_refresh;
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +
 +/** \name Crop Manipulator
 + * \{ */
 +
 +struct NodeCropWidgetGroup {
 +      wmManipulator *border;
 +
 +      struct {
 +              float dims[2];
 +      } state;
 +
 +      struct {
 +              PointerRNA ptr;
 +              PropertyRNA *prop;
 +              bContext *context;
 +      } update_data;
 +};
 +
 +static void manipulator_node_crop_update(struct NodeCropWidgetGroup *crop_group)
 +{
 +      RNA_property_update(crop_group->update_data.context, &crop_group->update_data.ptr, crop_group->update_data.prop);
 +}
 +
 +static void two_xy_to_rect(const NodeTwoXYs *nxy, rctf *rect, const float dims[2], bool is_relative)
 +{
 +      if (is_relative) {
 +              rect->xmin = nxy->fac_x1;
 +              rect->xmax = nxy->fac_x2;
 +              rect->ymin = nxy->fac_y1;
 +              rect->ymax = nxy->fac_y2;
 +      }
 +      else {
 +              rect->xmin = nxy->x1 / dims[0];
 +              rect->xmax = nxy->x2 / dims[0];
 +              rect->ymin = nxy->y1 / dims[1];
 +              rect->ymax = nxy->y2 / dims[1];
 +      }
 +}
 +
 +static void two_xy_from_rect(NodeTwoXYs *nxy, const rctf *rect, const float dims[2], bool is_relative)
 +{
 +      if (is_relative) {
 +              nxy->fac_x1 = rect->xmin;
 +              nxy->fac_x2 = rect->xmax;
 +              nxy->fac_y1 = rect->ymin;
 +              nxy->fac_y2 = rect->ymax;
 +      }
 +      else {
 +              nxy->x1 = rect->xmin * dims[0];
 +              nxy->x2 = rect->xmax * dims[0];
 +              nxy->y1 = rect->ymin * dims[1];
 +              nxy->y2 = rect->ymax * dims[1];
 +      }
 +}
 +
 +/* scale callbacks */
 +static void manipulator_node_crop_prop_matrix_get(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        void *value_p)
 +{
 +      float (*matrix)[4] = value_p;
 +      BLI_assert(mpr_prop->type->array_length == 16);
 +      struct NodeCropWidgetGroup *crop_group = mpr->parent_mgroup->customdata;
 +      const float *dims = crop_group->state.dims;
 +      const bNode *node = mpr_prop->custom_func.user_data;
 +      const NodeTwoXYs *nxy = node->storage;
 +      bool is_relative = (bool)node->custom2;
 +      rctf rct;
 +      two_xy_to_rect(nxy, &rct, dims, is_relative);
 +      matrix[0][0] = BLI_rctf_size_x(&rct);
 +      matrix[1][1] = BLI_rctf_size_y(&rct);
 +      matrix[3][0] = (BLI_rctf_cent_x(&rct) - 0.5f) * dims[0];
 +      matrix[3][1] = (BLI_rctf_cent_y(&rct) - 0.5f) * dims[1];
 +}
 +
 +static void manipulator_node_crop_prop_matrix_set(
 +        const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
 +        const void *value_p)
 +{
 +      const float (*matrix)[4] = value_p;
 +      BLI_assert(mpr_prop->type->array_length == 16);
 +      struct NodeCropWidgetGroup *crop_group = mpr->parent_mgroup->customdata;
 +      const float *dims = crop_group->state.dims;
 +      bNode *node = mpr_prop->custom_func.user_data;
 +      NodeTwoXYs *nxy = node->storage;
 +      bool is_relative = (bool)node->custom2;
 +      rctf rct;
 +      two_xy_to_rect(nxy, &rct, dims, is_relative);
 +      BLI_rctf_resize(&rct, matrix[0][0], matrix[1][1]);
 +      BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f);
 +      BLI_rctf_isect(&(rctf){.xmin = 0, .ymin = 0, .xmax = 1, .ymax = 1}, &rct, &rct);
 +      two_xy_from_rect(nxy, &rct, dims, is_relative);
 +      manipulator_node_crop_update(crop_group);
 +}
 +
 +static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
 +{
 +      SpaceNode *snode = CTX_wm_space_node(C);
 +
 +      if ((snode->flag & SNODE_BACKDRAW) == 0) {
 +              return false;
 +      }
 +
 +      if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
 +              bNode *node = nodeGetActive(snode->edittree);
 +
 +              if (node && ELEM(node->type, CMP_NODE_CROP)) {
 +                      /* ignore 'use_crop_size', we can't usefully edit the crop in this case. */
 +                      if ((node->custom1 & (0 << 1)) == 0) {
 +                              return true;
 +                      }
 +              }
 +      }
 +
 +      return false;
 +}
 +
 +static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup), __func__);
 +
 +      crop_group->border = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL);
 +
 +      RNA_enum_set(crop_group->border->ptr, "transform",
 +                   ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE);
 +
 +      mgroup->customdata = crop_group;
 +}
 +
 +static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ARegion *ar = CTX_wm_region(C);
 +      wmManipulator *mpr = mgroup->manipulators.first;
 +
 +      SpaceNode *snode = CTX_wm_space_node(C);
 +
 +      node_manipulator_calc_matrix_space(snode, ar, mpr->matrix_space);
 +}
 +
 +static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
++      Main *bmain = CTX_data_main(C);
 +      struct NodeCropWidgetGroup *crop_group = mgroup->customdata;
 +      wmManipulator *mpr = crop_group->border;
 +
 +      void *lock;
-       Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
++      Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
 +      ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
 +
 +      if (ibuf) {
 +              crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
 +              crop_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
 +
 +              RNA_float_set_array(mpr->ptr, "dimensions", crop_group->state.dims);
 +              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
 +
 +              SpaceNode *snode = CTX_wm_space_node(C);
 +              bNode *node = nodeGetActive(snode->edittree);
 +
 +              crop_group->update_data.context = (bContext *)C;
 +              RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeCrop, node, &crop_group->update_data.ptr);
 +              crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "relative");
 +
 +              WM_manipulator_target_property_def_func(
 +                      mpr, "matrix",
 +                      &(const struct wmManipulatorPropertyFnParams) {
 +                          .value_get_fn = manipulator_node_crop_prop_matrix_get,
 +                          .value_set_fn = manipulator_node_crop_prop_matrix_set,
 +                          .range_get_fn = NULL,
 +                          .user_data = node,
 +                      });
 +      }
 +      else {
 +              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true);
 +      }
 +
 +      BKE_image_release_ibuf(ima, ibuf, lock);
 +}
 +
 +void NODE_WGT_backdrop_crop(wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Backdrop Crop Widget";
 +      wgt->idname = "NODE_WGT_backdrop_crop";
 +
 +      wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT;
 +
 +      wgt->poll = WIDGETGROUP_node_crop_poll;
 +      wgt->setup = WIDGETGROUP_node_crop_setup;
 +      wgt->draw_prepare = WIDGETGROUP_node_crop_draw_prepare;
 +      wgt->refresh = WIDGETGROUP_node_crop_refresh;
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +
 +/** \name Sun Beams
 + * \{ */
 +
 +struct NodeSunBeamsWidgetGroup {
 +      wmManipulator *manipulator;
 +
 +      struct {
 +              float dims[2];
 +      } state;
 +};
 +
 +static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
 +{
 +      SpaceNode *snode = CTX_wm_space_node(C);
 +
 +      if ((snode->flag & SNODE_BACKDRAW) == 0) {
 +              return false;
 +      }
 +
 +      if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
 +              bNode *node = nodeGetActive(snode->edittree);
 +
 +              if (node && ELEM(node->type, CMP_NODE_SUNBEAMS)) {
 +                      return true;
 +              }
 +      }
 +
 +      return false;
 +}
 +
 +static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup), __func__);
 +
 +      sbeam_group->manipulator = WM_manipulator_new("MANIPULATOR_WT_grab_3d", mgroup, NULL);
 +      wmManipulator *mpr = sbeam_group->manipulator;
 +
 +      RNA_enum_set(mpr->ptr, "draw_style",  ED_MANIPULATOR_GRAB_STYLE_CROSS_2D);
 +
 +      mpr->scale_basis = 0.05f;
 +
 +      mgroup->customdata = sbeam_group;
 +}
 +
 +static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      struct NodeSunBeamsWidgetGroup *sbeam_group = mgroup->customdata;
 +      ARegion *ar = CTX_wm_region(C);
 +      wmManipulator *mpr = mgroup->manipulators.first;
 +
 +      SpaceNode *snode = CTX_wm_space_node(C);
 +
 +      node_manipulator_calc_matrix_space_with_image_dims(snode, ar, sbeam_group->state.dims, mpr->matrix_space);
 +}
 +
 +static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
++      Main *bmain = CTX_data_main(C);
 +      struct NodeSunBeamsWidgetGroup *sbeam_group = mgroup->customdata;
 +      wmManipulator *mpr = sbeam_group->manipulator;
 +
 +      void *lock;
-       Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
++      Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
 +      ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
 +
 +      if (ibuf) {
 +              sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
 +              sbeam_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
 +
 +              SpaceNode *snode = CTX_wm_space_node(C);
 +              bNode *node = nodeGetActive(snode->edittree);
 +
 +              /* need to set property here for undo. TODO would prefer to do this in _init */
 +              PointerRNA nodeptr;
 +              RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeSunBeams, node, &nodeptr);
 +              WM_manipulator_target_property_def_rna(mpr, "offset", &nodeptr, "source", -1);
 +
 +              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_MODAL, true);
 +      }
 +      else {
 +              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true);
 +      }
 +
 +      BKE_image_release_ibuf(ima, ibuf, lock);
 +}
 +
 +void NODE_WGT_backdrop_sun_beams(wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Sun Beams Widget";
 +      wgt->idname = "NODE_WGT_sbeam";
 +
 +      wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT;
 +
 +      wgt->poll = WIDGETGROUP_node_sbeam_poll;
 +      wgt->setup = WIDGETGROUP_node_sbeam_setup;
 +      wgt->draw_prepare = WIDGETGROUP_node_sbeam_draw_prepare;
 +      wgt->refresh = WIDGETGROUP_node_sbeam_refresh;
 +}
 +
 +/** \} */
 +
 +
 +
 +/* -------------------------------------------------------------------- */
 +
 +/** \name Corner Pin
 + * \{ */
 +
 +struct NodeCornerPinWidgetGroup {
 +      wmManipulator *manipulators[4];
 +
 +      struct {
 +              float dims[2];
 +      } state;
 +};
 +
 +static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
 +{
 +      SpaceNode *snode = CTX_wm_space_node(C);
 +
 +      if ((snode->flag & SNODE_BACKDRAW) == 0) {
 +              return false;
 +      }
 +
 +      if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
 +              bNode *node = nodeGetActive(snode->edittree);
 +
 +              if (node && ELEM(node->type, CMP_NODE_CORNERPIN)) {
 +                      return true;
 +              }
 +      }
 +
 +      return false;
 +}
 +
 +static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN(sizeof(struct NodeCornerPinWidgetGroup), __func__);
 +      const wmManipulatorType *wt_grab_3d = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", false);
 +
 +      for (int i = 0; i < 4; i++) {
 +              cpin_group->manipulators[i] = WM_manipulator_new_ptr(wt_grab_3d, mgroup, NULL);
 +              wmManipulator *mpr = cpin_group->manipulators[i];
 +
 +              RNA_enum_set(mpr->ptr, "draw_style",  ED_MANIPULATOR_GRAB_STYLE_CROSS_2D);
 +
 +              mpr->scale_basis = 0.01f;
 +      }
 +
 +      mgroup->customdata = cpin_group;
 +}
 +
 +static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      struct NodeCornerPinWidgetGroup *cpin_group = mgroup->customdata;
 +      ARegion *ar = CTX_wm_region(C);
 +
 +      SpaceNode *snode = CTX_wm_space_node(C);
 +
 +      float matrix_space[4][4];
 +      node_manipulator_calc_matrix_space_with_image_dims(snode, ar, cpin_group->state.dims, matrix_space);
 +
 +      for (int i = 0; i < 4; i++) {
 +              wmManipulator *mpr = cpin_group->manipulators[i];
 +              copy_m4_m4(mpr->matrix_space, matrix_space);
 +      }
 +}
 +
 +static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
++      Main *bmain = CTX_data_main(C);
 +      struct NodeCornerPinWidgetGroup *cpin_group = mgroup->customdata;
 +
 +      void *lock;
++      Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
 +      ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
 +
 +      if (ibuf) {
 +              cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
 +              cpin_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
 +
 +              SpaceNode *snode = CTX_wm_space_node(C);
 +              bNode *node = nodeGetActive(snode->edittree);
 +
 +              /* need to set property here for undo. TODO would prefer to do this in _init */
 +              int i = 0;
 +              for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) {
 +                      if (sock->type == SOCK_VECTOR) {
 +                              wmManipulator *mpr = cpin_group->manipulators[i++];
 +
 +                              PointerRNA sockptr;
 +                              RNA_pointer_create((ID *)snode->edittree, &RNA_NodeSocket, sock, &sockptr);
 +                              WM_manipulator_target_property_def_rna(mpr, "offset", &sockptr, "default_value", -1);
 +
 +                              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_MODAL, true);
 +                      }
 +              }
 +      }
 +      else {
 +              for (int i = 0; i < 4; i++) {
 +                      wmManipulator *mpr = cpin_group->manipulators[i];
 +                      WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true);
 +              }
 +      }
 +
 +      BKE_image_release_ibuf(ima, ibuf, lock);
 +}
 +
 +void NODE_WGT_backdrop_corner_pin(wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Corner Pin Widget";
 +      wgt->idname = "NODE_WGT_backdrop_corner_pin";
 +
 +      wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT;
 +
 +      wgt->poll = WIDGETGROUP_node_corner_pin_poll;
 +      wgt->setup = WIDGETGROUP_node_corner_pin_setup;
 +      wgt->draw_prepare = WIDGETGROUP_node_corner_pin_draw_prepare;
 +      wgt->refresh = WIDGETGROUP_node_corner_pin_refresh;
 +}
 +
 +/** \} */
@@@ -555,9 -581,9 +555,9 @@@ static void rna_ColorManagedColorspaceS
        if (GS(id->name) == ID_IM) {
                Image *ima = (Image *) id;
  
 -              DAG_id_tag_update(&ima->id, 0);
 +              DEG_id_tag_update(&ima->id, 0);
  
-               BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE);
+               BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
  
                WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
                WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
@@@ -92,8 -104,8 +92,8 @@@ static void rna_Image_source_set(Pointe
  
        if (value != ima->source) {
                ima->source = value;
-               BKE_image_signal(ima, NULL, IMA_SIGNAL_SRC_CHANGE);
+               BKE_image_signal(G.main, ima, NULL, IMA_SIGNAL_SRC_CHANGE);
 -              DAG_id_tag_update(&ima->id, 0);
 +              DEG_id_tag_update(&ima->id, 0);
        }
  }
  
@@@ -118,25 -130,25 +118,25 @@@ static void rna_Image_fields_update(Mai
        BKE_image_release_ibuf(ima, ibuf, lock);
  }
  
- static void rna_Image_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+ static void rna_Image_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
  {
        Image *ima = ptr->id.data;
-       BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+       BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
        WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
 -      DAG_id_tag_update(&ima->id, 0);
 +      DEG_id_tag_update(&ima->id, 0);
  }
  
- static void rna_Image_generated_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+ static void rna_Image_generated_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
  {
        Image *ima = ptr->id.data;
-       BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
+       BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_FREE);
  }
  
- static void rna_Image_colormanage_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+ static void rna_Image_colormanage_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
  {
        Image *ima = ptr->id.data;
-       BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE);
+       BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
 -      DAG_id_tag_update(&ima->id, 0);
 +      DEG_id_tag_update(&ima->id, 0);
        WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
        WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
  }
@@@ -159,9 -205,9 +159,9 @@@ static void rna_Material_active_paint_t
                                for (sl = sa->spacedata.first; sl; sl = sl->next) {
                                        if (sl->spacetype == SPACE_IMAGE) {
                                                SpaceImage *sima = (SpaceImage *)sl;
 -
 -                                              if (!sima->pin)
 -                                                      ED_space_image_set(bmain, sima, scene, scene->obedit, image);
 +                                              if (!sima->pin) {
-                                                       ED_space_image_set(sima, scene, obedit, image);
++                                                      ED_space_image_set(bmain, sima, scene, obedit, image);
 +                                              }
                                        }
                                }
                        }
@@@ -406,13 -382,13 +406,13 @@@ static void rna_ImaPaint_canvas_update(
        for (sc = bmain->screen.first; sc; sc = sc->id.next) {
                ScrArea *sa;
                for (sa = sc->areabase.first; sa; sa = sa->next) {
 -                      SpaceLink *sl;
 -                      for (sl = sa->spacedata.first; sl; sl = sl->next) {
 -                              if (sl->spacetype == SPACE_IMAGE) {
 -                                      SpaceImage *sima = (SpaceImage *)sl;
 +                      SpaceLink *slink;
 +                      for (slink = sa->spacedata.first; slink; slink = slink->next) {
 +                              if (slink->spacetype == SPACE_IMAGE) {
 +                                      SpaceImage *sima = (SpaceImage *)slink;
  
                                        if (!sima->pin)
-                                               ED_space_image_set(sima, scene, obedit, ima);
 -                                              ED_space_image_set(bmain, sima, scene, scene->obedit, ima);
++                                              ED_space_image_set(bmain, sima, scene, obedit, ima);
                                }
                        }
                }
@@@ -916,11 -835,8 +916,11 @@@ static void rna_SpaceImageEditor_image_
  {
        SpaceImage *sima = (SpaceImage *)(ptr->data);
        bScreen *sc = (bScreen *)ptr->id.data;
 -
 -      ED_space_image_set(G.main, sima, sc->scene, sc->scene->obedit, (Image *)value.data);
 +      wmWindow *win;
 +      Scene *scene = ED_screen_scene_find_with_window(sc, G.main->wm.first, &win);
 +      ViewLayer *view_layer = WM_window_get_active_view_layer(win);
 +      Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
-       ED_space_image_set(sima, scene, obedit, (Image *)value.data);
++      ED_space_image_set(G.main, sima, scene, obedit, (Image *)value.data);
  }
  
  static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, PointerRNA value)
  
  #include "BKE_context.h"
  #include "BKE_image.h"
+ #include "BKE_main.h"
 +#include "BKE_screen.h"
 +#include "BKE_scene.h"
 +#include "BKE_workspace.h"
  
  #include "GHOST_C-api.h"
  
@@@ -117,73 -116,31 +118,73 @@@ static void wm_paintcursor_draw(bContex
        }
  }
  
 -/* ********************* drawing, swap ****************** */
  
- static bool wm_draw_region_stereo_set(ScrArea *sa, ARegion *ar, eStereoViews sview)
 -static void wm_area_mark_invalid_backbuf(ScrArea *sa)
++static bool wm_draw_region_stereo_set(Main *bmain, ScrArea *sa, ARegion *ar, eStereoViews sview)
  {
 -      if (sa->spacetype == SPACE_VIEW3D)
 -              ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
 +      /* We could detect better when stereo is actually needed, by inspecting the
 +       * image in the image editor and sequencer. */
 +      if (ar->regiontype != RGN_TYPE_WINDOW) {
 +              return false;
 +      }
 +
 +      switch (sa->spacetype) {
 +              case SPACE_IMAGE:
 +              {
 +                      SpaceImage *sima = sa->spacedata.first;
 +                      sima->iuser.multiview_eye = sview;
 +                      return true;
 +              }
 +              case SPACE_VIEW3D:
 +              {
 +                      View3D *v3d = sa->spacedata.first;
 +                      if (v3d->camera && v3d->camera->type == OB_CAMERA) {
 +                              Camera *cam = v3d->camera->data;
 +                              CameraBGImage *bgpic = cam->bg_images.first;
 +                              v3d->multiview_eye = sview;
 +                              if (bgpic) bgpic->iuser.multiview_eye = sview;
 +                              return true;
 +                      }
 +                      return false;
 +              }
 +              case SPACE_NODE:
 +              {
 +                      SpaceNode *snode = sa->spacedata.first;
 +                      if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
-                               Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
++                              Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
 +                              ima->eye = sview;
 +                              return true;
 +                      }
 +                      return false;
 +              }
 +              case SPACE_SEQ:
 +              {
 +                      SpaceSeq *sseq = sa->spacedata.first;
 +                      sseq->multiview_eye = sview;
 +                      return true;
 +              }
 +      }
 +
 +      return false;
  }
  
 -static bool wm_area_test_invalid_backbuf(ScrArea *sa)
 +/* ********************* drawing ****************** */
 +
 +static void wm_area_mark_invalid_backbuf(ScrArea *sa)
  {
        if (sa->spacetype == SPACE_VIEW3D)
 -              return (((View3D *)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF) != 0;
 -      else
 -              return true;
 +              ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
  }
  
 -static void wm_region_test_render_do_draw(const bScreen *screen, ScrArea *sa, ARegion *ar)
 +static void wm_region_test_render_do_draw(const Scene *scene, struct Depsgraph *depsgraph,
 +                                          ScrArea *sa, ARegion *ar)
  {
        /* tag region for redraw from render engine preview running inside of it */
 -      if (sa->spacetype == SPACE_VIEW3D) {
 +      if (sa->spacetype == SPACE_VIEW3D && ar->regiontype == RGN_TYPE_WINDOW) {
                RegionView3D *rv3d = ar->regiondata;
 -              RenderEngine *engine = (rv3d) ? rv3d->render_engine : NULL;
 +              RenderEngine *engine = rv3d->render_engine;
 +              GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
  
                if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
 -                      Scene *scene = screen->scene;
                        View3D *v3d = sa->spacedata.first;
                        rcti border_rect;
  
@@@ -467,78 -555,108 +468,79 @@@ void wm_draw_region_blend(ARegion *ar, 
        }
  }
  
 -static void wm_method_draw_triple(bContext *C, wmWindow *win)
 +GPUViewport *WM_draw_region_get_viewport(ARegion *ar, int view)
  {
 -      wmWindowManager *wm = CTX_wm_manager(C);
 -      wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first;
 -      bScreen *screen = win->screen;
 -      ScrArea *sa;
 -      ARegion *ar;
 -      int copytex = false;
 -
 -      if (drawdata && drawdata->triple) {
 -              glClearColor(0, 0, 0, 0);
 -              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 -
 -              wmSubWindowSet(win, screen->mainwin);
 -
 -              wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
 +      if (!ar->draw_buffer) {
 +              return NULL;
        }
 -      else {
 -              /* we run it when we start OR when we turn stereo on */
 -              if (drawdata == NULL) {
 -                      drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
 -                      BLI_addhead(&win->drawdata, drawdata);
 -              }
  
 -              drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
 +      return ar->draw_buffer->viewport[view];
 +}
  
 -              if (!wm_triple_gen_textures(win, drawdata->triple)) {
 -                      wm_draw_triple_fail(C, win);
 -                      return;
 -              }
 +GPUViewport *WM_draw_region_get_bound_viewport(ARegion *ar)
 +{
 +      if (!ar->draw_buffer || ar->draw_buffer->bound_view == -1) {
 +              return NULL;
        }
  
 -      /* it means stereo was just turned off */
 -      /* note: we are removing all drawdatas that are not the first */
 -      for (dd = drawdata->next; dd; dd = dd_next) {
 -              dd_next = dd->next;
 -
 -              BLI_remlink(&win->drawdata, dd);
 -              wm_draw_triple_free(dd->triple);
 -              MEM_freeN(dd);
 -      }
 +      int view = ar->draw_buffer->bound_view;
 +      return ar->draw_buffer->viewport[view];
 +}
  
 -      wmDrawTriple *triple = drawdata->triple;
 +static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
 +{
++      Main *bmain = CTX_data_main(C);
 +      wmWindowManager *wm = CTX_wm_manager(C);
 +      bScreen *screen = WM_window_get_active_screen(win);
  
 -      /* draw marked area regions */
 -      for (sa = screen->areabase.first; sa; sa = sa->next) {
 +      /* Draw screen areas into own frame buffer. */
 +      ED_screen_areas_iter(win, screen, sa) {
                CTX_wm_area_set(C, sa);
  
 -              for (ar = sa->regionbase.first; ar; ar = ar->next) {
 -                      if (ar->swinid && ar->do_draw) {
 -                              if (ar->overlap == false) {
 -                                      CTX_wm_region_set(C, ar);
 -                                      ED_region_do_draw(C, ar);
 -                                      ar->do_draw = false;
 -                                      CTX_wm_region_set(C, NULL);
 -                                      copytex = true;
 -                              }
 +              /* Compute UI layouts for dynamically size regions. */
 +              for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
 +                      if (ar->visible && ar->do_draw && ar->type && ar->type->layout) {
 +                              CTX_wm_region_set(C, ar);
 +                              ED_region_do_layout(C, ar);
 +                              CTX_wm_region_set(C, NULL);
                        }
                }
  
 -              wm_area_mark_invalid_backbuf(sa);
 -              CTX_wm_area_set(C, NULL);
 -      }
 -
 -      if (copytex) {
 -              wmSubWindowSet(win, screen->mainwin);
 -
 -              wm_triple_copy_textures(win, triple);
 -      }
 -
 -      if (wm->paintcursors.first) {
 -              for (sa = screen->areabase.first; sa; sa = sa->next) {
 -                      for (ar = sa->regionbase.first; ar; ar = ar->next) {
 -                              if (ar->swinid && ar->swinid == screen->subwinactive) {
 -                                      CTX_wm_area_set(C, sa);
 -                                      CTX_wm_region_set(C, ar);
 +              ED_area_update_region_sizes(wm, win, sa);
  
 -                                      /* make region ready for draw, scissor, pixelspace */
 -                                      ED_region_set(C, ar);
 -                                      wm_paintcursor_draw(C, ar);
 -
 -                                      CTX_wm_region_set(C, NULL);
 -                                      CTX_wm_area_set(C, NULL);
 +              /* Then do actual drawing of regions. */
 +              for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
 +                      if (ar->visible && ar->do_draw) {
 +                              CTX_wm_region_set(C, ar);
 +                              bool use_viewport = wm_region_use_viewport(sa, ar);
 +
-                               if (stereo && wm_draw_region_stereo_set(sa, ar, STEREO_LEFT_ID)) {
++                              if (stereo && wm_draw_region_stereo_set(bmain, sa, ar, STEREO_LEFT_ID)) {
 +                                      wm_draw_region_buffer_create(ar, true, use_viewport);
 +
 +                                      for (int view = 0; view < 2; view++) {
 +                                              eStereoViews sview;
 +                                              if (view == 0) {
 +                                                      sview = STEREO_LEFT_ID;
 +                                              }
 +                                              else {
 +                                                      sview = STEREO_RIGHT_ID;
-                                                       wm_draw_region_stereo_set(sa, ar, sview);
++                                                      wm_draw_region_stereo_set(bmain, sa, ar, sview);
 +                                              }
 +
 +                                              wm_draw_region_bind(ar, view);
 +                                              ED_region_do_draw(C, ar);
 +                                              wm_draw_region_unbind(ar, view);
 +                                      }
 +                              }
 +                              else {
 +                                      wm_draw_region_buffer_create(ar, false, use_viewport);
 +                                      wm_draw_region_bind(ar, 0);
 +                                      ED_region_do_draw(C, ar);
 +                                      wm_draw_region_unbind(ar, 0);
                                }
 -                      }
 -              }
 -
 -              wmSubWindowSet(win, screen->mainwin);
 -      }
 -
 -      /* draw overlapping area regions (always like popups) */
 -      for (sa = screen->areabase.first; sa; sa = sa->next) {
 -              CTX_wm_area_set(C, sa);
  
 -              for (ar = sa->regionbase.first; ar; ar = ar->next) {
 -                      if (ar->swinid && ar->overlap) {
 -                              CTX_wm_region_set(C, ar);
 -                              ED_region_do_draw(C, ar);
                                ar->do_draw = false;
                                CTX_wm_region_set(C, NULL);
 -
 -                              wm_draw_region_blend(win, ar, triple);
                        }
                }