Fix T62876: Camera Background Images
authorJeroen Bakker <j.bakker@atmind.nl>
Tue, 2 Apr 2019 14:05:22 +0000 (16:05 +0200)
committerJeroen Bakker <j.bakker@atmind.nl>
Fri, 21 Jun 2019 07:53:51 +0000 (09:53 +0200)
Migrate old legacy code to the draw mamager/object mode. The old legacy
version did not work with wireframe. By migrating the code
to modern draw manager code we have mode control on the drawing process.

Still background images do not work with OIT, the cause seems to be that the transparent pixels are treated as background pixels.
Also There are some artifacts when working with Holdouts and DoF, this
is because the draw engines do not pass the correct alpha values.

Reviewers: fclem, brecht

Differential Revision: https://developer.blender.org/D4638

20 files changed:
source/blender/blenkernel/intern/movieclip.c
source/blender/blenloader/intern/readfile.c
source/blender/draw/CMakeLists.txt
source/blender/draw/engines/gpencil/gpencil_engine.c
source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
source/blender/draw/intern/draw_manager.c
source/blender/draw/modes/object_mode.c
source/blender/draw/modes/paint_texture_mode.c
source/blender/draw/modes/shaders/common_colormanagement_lib.glsl [new file with mode: 0644]
source/blender/draw/modes/shaders/object_camera_image_frag.glsl [new file with mode: 0644]
source/blender/draw/modes/shaders/object_camera_image_vert.glsl [new file with mode: 0644]
source/blender/draw/modes/shaders/object_empty_image_frag.glsl
source/blender/draw/modes/shaders/paint_texture_frag.glsl
source/blender/editors/space_view3d/view3d_draw_legacy.c
source/blender/gpu/GPU_texture.h
source/blender/gpu/intern/gpu_draw.c
source/blender/makesdna/DNA_movieclip_types.h
source/blender/makesrna/intern/rna_camera.c

index c377223d14b014c3a986db8331e0d6b976ae82c9..6bc83f8dd09199be0a810af4ac15abceec4b0345 100644 (file)
@@ -67,6 +67,8 @@
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_query.h"
 
+#include "GPU_texture.h"
+
 #ifdef WITH_OPENEXR
 #  include "intern/openexr/openexr_multi.h"
 #endif
@@ -1353,6 +1355,17 @@ static void free_buffers(MovieClip *clip)
     IMB_free_anim(clip->anim);
     clip->anim = NULL;
   }
+
+  MovieClip_RuntimeGPUTexture *tex;
+  for (tex = clip->runtime.gputextures.first; tex; tex = tex->next) {
+    for (int i = 0; i < TEXTARGET_COUNT; i++) {
+      if (tex->gputexture[i] != NULL) {
+        GPU_texture_free(tex->gputexture[i]);
+        tex->gputexture[i] = NULL;
+      }
+    }
+  }
+  BLI_freelistN(&clip->runtime.gputextures);
 }
 
 void BKE_movieclip_clear_cache(MovieClip *clip)
index 541ebe8f01d76e3a64efdf6497afd51f380bb80e..393f8f87a904731fdb2383d1bb29e09628679853 100644 (file)
@@ -2038,6 +2038,7 @@ void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain)
   for (; clip; clip = clip->id.next) {
     clip->cache = newmclipadr(fd, clip->cache);
     clip->tracking.camera.intrinsics = newmclipadr(fd, clip->tracking.camera.intrinsics);
+    BLI_freelistN(&clip->runtime.gputextures);
   }
 
   for (; sce; sce = sce->id.next) {
index 5a8a4d46ac9f3451d0012bc9ab09287a937294e0..8631a9f556bf395189698ea2e83ea05c1e831fe1 100644 (file)
@@ -249,6 +249,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
 
+data_to_c_simple(modes/shaders/common_colormanagement_lib.glsl SRC)
 data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC)
 data_to_c_simple(modes/shaders/common_hair_lib.glsl SRC)
 data_to_c_simple(modes/shaders/common_hair_refine_vert.glsl SRC)
@@ -295,6 +296,8 @@ data_to_c_simple(modes/shaders/overlay_face_orientation_vert.glsl SRC)
 data_to_c_simple(modes/shaders/overlay_face_wireframe_vert.glsl SRC)
 data_to_c_simple(modes/shaders/overlay_face_wireframe_geom.glsl SRC)
 data_to_c_simple(modes/shaders/overlay_face_wireframe_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_camera_image_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_camera_image_vert.glsl SRC)
 data_to_c_simple(modes/shaders/object_empty_axes_vert.glsl SRC)
 data_to_c_simple(modes/shaders/object_empty_image_frag.glsl SRC)
 data_to_c_simple(modes/shaders/object_empty_image_vert.glsl SRC)
index 6d1227bb0a8bef5f1945d649e2208224a1651ad6..ae3bf8cead6756ec91aa933555c06f1b9f499319 100644 (file)
@@ -61,6 +61,7 @@ extern char datatoc_gpencil_edit_point_geom_glsl[];
 extern char datatoc_gpencil_edit_point_frag_glsl[];
 extern char datatoc_gpencil_blend_frag_glsl[];
 
+extern char datatoc_common_colormanagement_lib_glsl[];
 extern char datatoc_common_view_lib_glsl[];
 
 /* *********** STATIC *********** */
@@ -169,29 +170,37 @@ static void GPENCIL_create_shaders(void)
 {
   /* normal fill shader */
   if (!e_data.gpencil_fill_sh) {
-    e_data.gpencil_fill_sh = DRW_shader_create_with_lib(datatoc_gpencil_fill_vert_glsl,
-                                                        NULL,
-                                                        datatoc_gpencil_fill_frag_glsl,
-                                                        datatoc_common_view_lib_glsl,
-                                                        NULL);
+    e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({
+        .vert =
+            (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_fill_vert_glsl, NULL},
+        .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+                                 datatoc_gpencil_fill_frag_glsl,
+                                 NULL},
+    });
   }
 
   /* normal stroke shader using geometry to display lines (line mode) */
   if (!e_data.gpencil_stroke_sh) {
-    e_data.gpencil_stroke_sh = DRW_shader_create_with_lib(datatoc_gpencil_stroke_vert_glsl,
-                                                          datatoc_gpencil_stroke_geom_glsl,
-                                                          datatoc_gpencil_stroke_frag_glsl,
-                                                          datatoc_common_view_lib_glsl,
-                                                          NULL);
+    e_data.gpencil_stroke_sh = GPU_shader_create_from_arrays({
+        .vert =
+            (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_stroke_vert_glsl, NULL},
+        .geom = (const char *[]){datatoc_gpencil_stroke_geom_glsl, NULL},
+        .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+                                 datatoc_gpencil_stroke_frag_glsl,
+                                 NULL},
+    });
   }
 
   /* dot/rectangle mode for normal strokes using geometry */
   if (!e_data.gpencil_point_sh) {
-    e_data.gpencil_point_sh = DRW_shader_create_with_lib(datatoc_gpencil_point_vert_glsl,
-                                                         datatoc_gpencil_point_geom_glsl,
-                                                         datatoc_gpencil_point_frag_glsl,
-                                                         datatoc_common_view_lib_glsl,
-                                                         NULL);
+    e_data.gpencil_point_sh = GPU_shader_create_from_arrays({
+        .vert =
+            (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_point_vert_glsl, NULL},
+        .geom = (const char *[]){datatoc_gpencil_point_geom_glsl, NULL},
+        .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+                                 datatoc_gpencil_point_frag_glsl,
+                                 NULL},
+    });
   }
   /* used for edit points or strokes with one point only */
   if (!e_data.gpencil_edit_point_sh) {
index 1fdfd05332e5974fc15cd574ef4a85c6d19b0591..87bf116ff89a35d87f0f3eda696dd9adac6c4332 100644 (file)
@@ -90,31 +90,6 @@ void set_color(in vec4 color,
   ocolor.a *= layer_opacity;
 }
 
-float linearrgb_to_srgb(float c)
-{
-  if (c < 0.0031308) {
-    return (c < 0.0) ? 0.0 : c * 12.92;
-  }
-  else {
-    return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
-  }
-}
-
-vec4 texture_read_as_srgb(sampler2D tex, bool premultiplied, vec2 co)
-{
-  /* By convention image textures return scene linear colors, but
-   * grease pencil still works in srgb. */
-  vec4 color = texture(tex, co);
-  /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
-  if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
-    color.rgb = color.rgb / color.a;
-  }
-  color.r = linearrgb_to_srgb(color.r);
-  color.g = linearrgb_to_srgb(color.g);
-  color.b = linearrgb_to_srgb(color.b);
-  return color;
-}
-
 void main()
 {
   vec2 t_center = vec2(0.5, 0.5);
index 7fed42aca0dd108423fd1e5cae9dda3a2f2b828d..34777018a73b4554bceeea51d3360524c0e57d2a 100644 (file)
@@ -48,31 +48,6 @@ vec2 check_box_point(vec2 pt, vec2 radius)
   return rtn;
 }
 
-float linearrgb_to_srgb(float c)
-{
-  if (c < 0.0031308) {
-    return (c < 0.0) ? 0.0 : c * 12.92;
-  }
-  else {
-    return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
-  }
-}
-
-vec4 texture_read_as_srgb(sampler2D tex, bool premultiplied, vec2 co)
-{
-  /* By convention image textures return scene linear colors, but
-   * grease pencil still works in srgb. */
-  vec4 color = texture(tex, co);
-  /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
-  if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
-    color.rgb = color.rgb / color.a;
-  }
-  color.r = linearrgb_to_srgb(color.r);
-  color.g = linearrgb_to_srgb(color.g);
-  color.b = linearrgb_to_srgb(color.b);
-  return color;
-}
-
 void main()
 {
   vec2 centered = mTexCoord - vec2(0.5);
index bc703d2a078c908b8a5c9f533cc44c119750dbf2..73baacb35d490e1f34717ce2a380c2a61527f737 100644 (file)
@@ -28,31 +28,6 @@ out vec4 fragColor;
 
 bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR);
 
-float linearrgb_to_srgb(float c)
-{
-  if (c < 0.0031308) {
-    return (c < 0.0) ? 0.0 : c * 12.92;
-  }
-  else {
-    return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
-  }
-}
-
-vec4 texture_read_as_srgb(sampler2D tex, bool premultiplied, vec2 co)
-{
-  /* By convention image textures return scene linear colors, but
-   * grease pencil still works in srgb. */
-  vec4 color = texture(tex, co);
-  /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
-  if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
-    color.rgb = color.rgb / color.a;
-  }
-  color.r = linearrgb_to_srgb(color.r);
-  color.g = linearrgb_to_srgb(color.g);
-  color.b = linearrgb_to_srgb(color.b);
-  return color;
-}
-
 void main()
 {
 
index 87366289bf7515b48a9b6b6c51f1908dde1cd84a..7606fa914d1650aae4e86a142cd9ec7db44e4071 100644 (file)
@@ -1558,7 +1558,6 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
   RegionView3D *rv3d = ar->regiondata;
   const bool do_annotations = (((v3d->flag2 & V3D_SHOW_ANNOTATION) != 0) &&
                                ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0));
-  const bool do_camera_frame = !DST.options.is_image_render;
 
   DST.draw_ctx.evil_C = evil_C;
   DST.viewport = viewport;
@@ -1650,24 +1649,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
 
   drw_engines_draw_background();
 
-  /* WIP, single image drawn over the camera view (replace) */
-  bool do_bg_image = false;
-  if (rv3d->persp == RV3D_CAMOB) {
-    Object *cam_ob = v3d->camera;
-    if (cam_ob && cam_ob->type == OB_CAMERA) {
-      Camera *cam = cam_ob->data;
-      if (!BLI_listbase_is_empty(&cam->bg_images)) {
-        do_bg_image = true;
-      }
-    }
-  }
-
   GPU_framebuffer_bind(DST.default_framebuffer);
 
-  if (do_bg_image) {
-    ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, do_camera_frame);
-  }
-
   DRW_draw_callbacks_pre_scene();
   if (DST.draw_ctx.evil_C) {
     ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_PRE_VIEW);
@@ -1734,10 +1717,6 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
 
   DRW_stats_reset();
 
-  if (do_bg_image) {
-    ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, do_camera_frame);
-  }
-
   if (G.debug_value > 20 && G.debug_value < 30) {
     GPU_depth_test(false);
     rcti rect; /* local coordinate visible rect inside region, to accommodate overlapping ui */
index e8c600ee545fc579dd9ac3b49aea4f72f6f06153..1c60fc09057a7cb06e1db0a4e163e2ad33ad33c3 100644 (file)
@@ -38,6 +38,7 @@
 #include "DNA_rigidbody_types.h"
 #include "DNA_smoke_types.h"
 #include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
 #include "DNA_world_types.h"
 
 #include "BKE_anim.h"
@@ -45,6 +46,7 @@
 #include "BKE_constraint.h"
 #include "BKE_curve.h"
 #include "BKE_editmesh.h"
+#include "BKE_image.h"
 #include "BKE_mball.h"
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
@@ -55,6 +57,8 @@
 
 #include "BLI_ghash.h"
 
+#include "IMB_imbuf_types.h"
+
 #include "ED_view3d.h"
 
 #include "GPU_batch.h"
@@ -80,6 +84,8 @@ extern char datatoc_object_outline_detect_frag_glsl[];
 extern char datatoc_object_outline_expand_frag_glsl[];
 extern char datatoc_object_grid_frag_glsl[];
 extern char datatoc_object_grid_vert_glsl[];
+extern char datatoc_object_camera_image_frag_glsl[];
+extern char datatoc_object_camera_image_vert_glsl[];
 extern char datatoc_object_empty_image_frag_glsl[];
 extern char datatoc_object_empty_image_vert_glsl[];
 extern char datatoc_object_lightprobe_grid_vert_glsl[];
@@ -87,6 +93,7 @@ extern char datatoc_object_loose_points_frag_glsl[];
 extern char datatoc_object_particle_prim_vert_glsl[];
 extern char datatoc_object_particle_dot_vert_glsl[];
 extern char datatoc_object_particle_dot_frag_glsl[];
+extern char datatoc_common_colormanagement_lib_glsl[];
 extern char datatoc_common_globals_lib_glsl[];
 extern char datatoc_common_view_lib_glsl[];
 extern char datatoc_common_fxaa_lib_glsl[];
@@ -115,6 +122,8 @@ typedef struct OBJECT_PassList {
   struct DRWPass *bone_axes[2];
   struct DRWPass *particle;
   struct DRWPass *lightprobes;
+  struct DRWPass *camera_images_back;
+  struct DRWPass *camera_images_front;
 } OBJECT_PassList;
 
 typedef struct OBJECT_FramebufferList {
@@ -148,6 +157,8 @@ typedef struct OBJECT_Shaders {
   GPUShader *outline_fade_large;
 
   /* regular shaders */
+  GPUShader *object_camera_image;
+  GPUShader *object_camera_image_cm;
   GPUShader *object_empty_image;
   GPUShader *object_empty_image_wire;
   GPUShader *grid;
@@ -336,6 +347,7 @@ static struct {
   struct GPUTexture *outlines_blur_tx;
 
   ListBase smoke_domains;
+  ListBase movie_clips;
 } e_data = {NULL}; /* Engine data */
 
 enum {
@@ -460,7 +472,9 @@ static void OBJECT_engine_init(void *vedata)
                                    datatoc_common_view_lib_glsl,
                                    datatoc_object_empty_image_vert_glsl,
                                    NULL},
-          .frag = (const char *[]){datatoc_object_empty_image_frag_glsl, NULL},
+          .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+                                   datatoc_object_empty_image_frag_glsl,
+                                   NULL},
           .defs = (const char *[]){sh_cfg_data->def, empty_image_defs, NULL},
       });
       sh_data->object_empty_image_wire = GPU_shader_create_from_arrays({
@@ -471,6 +485,21 @@ static void OBJECT_engine_init(void *vedata)
           .frag = (const char *[]){datatoc_object_empty_image_frag_glsl, NULL},
           .defs = (const char *[]){sh_cfg_data->def, "#define USE_WIRE\n", empty_image_defs, NULL},
       });
+
+      sh_data->object_camera_image_cm = GPU_shader_create_from_arrays({
+          .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_camera_image_vert_glsl, NULL},
+          .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+                                   datatoc_object_camera_image_frag_glsl,
+                                   NULL},
+          .defs =
+              (const char *[]){sh_cfg_data->def, "#define DRW_STATE_DO_COLOR_MANAGEMENT\n", NULL},
+      });
+      sh_data->object_camera_image = GPU_shader_create_from_arrays({
+          .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_camera_image_vert_glsl, NULL},
+          .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+                                   datatoc_object_camera_image_frag_glsl,
+                                   NULL},
+      });
     }
 
     /* Grid */
@@ -1035,6 +1064,291 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data,
   }
 }
 
+/* Draw Camera Background Images */
+typedef struct CameraEngineData {
+  DrawData dd;
+  ListBase bg_data;
+} CameraEngineData;
+typedef struct CameraEngineBGData {
+  float transform_mat[4][4];
+} CameraEngineBGData;
+
+static void camera_engine_data_free(DrawData *dd)
+{
+  CameraEngineData *data = (CameraEngineData *)dd;
+  for (LinkData *link = data->bg_data.first; link; link = link->next) {
+    CameraEngineBGData *bg_data = (CameraEngineBGData *)link->data;
+    MEM_freeN(bg_data);
+  }
+  BLI_freelistN(&data->bg_data);
+}
+
+static void camera_background_images_stereo_setup(Scene *scene,
+                                                  View3D *v3d,
+                                                  Image *ima,
+                                                  ImageUser *iuser)
+{
+  if (BKE_image_is_stereo(ima)) {
+    iuser->flag |= IMA_SHOW_STEREO;
+
+    if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+      iuser->multiview_eye = STEREO_LEFT_ID;
+    }
+    else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+      /* show only left or right camera */
+      iuser->multiview_eye = v3d->stereo3d_camera;
+    }
+
+    BKE_image_multiview_index(ima, iuser);
+  }
+  else {
+    iuser->flag &= ~IMA_SHOW_STEREO;
+  }
+}
+
+static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
+                                                 OBJECT_PassList *psl,
+                                                 Object *ob,
+                                                 RegionView3D *rv3d)
+{
+  if (!BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d)) {
+    return;
+  }
+
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  struct ARegion *ar = draw_ctx->ar;
+  View3D *v3d = draw_ctx->v3d;
+  Scene *scene = draw_ctx->scene;
+  Depsgraph *depsgraph = draw_ctx->depsgraph;
+  Camera *cam = ob->data;
+  const Object *camera_object = DEG_get_evaluated_object(depsgraph, v3d->camera);
+  const bool is_active = (ob == camera_object);
+  const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
+
+  if (look_through && (cam->flag & CAM_SHOW_BG_IMAGE)) {
+    GPUBatch *batch = DRW_cache_image_plane_get();
+
+    /* load camera engine data */
+    CameraEngineData *camera_engine_data = (CameraEngineData *)DRW_drawdata_ensure(
+        &ob->id,
+        &draw_engine_object_type,
+        sizeof(CameraEngineData),
+        NULL,
+        camera_engine_data_free);
+    LinkData *list_node = camera_engine_data->bg_data.first;
+
+    for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+      if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED)) {
+        continue;
+      }
+
+      /* retrieve the image we want to show, continue to next when no image could be found */
+      ImBuf *ibuf = NULL;
+      GPUTexture *tex = NULL;
+      float image_aspect_x, image_aspect_y;
+      float image_aspect = 1.0;
+      int image_width, image_height;
+      bool premultiplied = false;
+
+      if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+        Image *image = bgpic->ima;
+        if (image == NULL) {
+          continue;
+        }
+        premultiplied = (image->alpha_mode == IMA_ALPHA_PREMUL);
+        ImageUser *iuser = &bgpic->iuser;
+        BKE_image_user_frame_calc(image, iuser, (int)DEG_get_ctime(depsgraph));
+        if (image->source == IMA_SRC_SEQUENCE && !(iuser->flag & IMA_USER_FRAME_IN_RANGE)) {
+          /* frame is out of range, dont show */
+          continue;
+        }
+        else {
+          camera_background_images_stereo_setup(scene, v3d, image, iuser);
+        }
+        tex = GPU_texture_from_blender(image, iuser, GL_TEXTURE_2D);
+        if (tex == NULL) {
+          continue;
+        }
+        ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+        if (ibuf == NULL) {
+          continue;
+        }
+
+        image_aspect_x = bgpic->ima->aspx;
+        image_aspect_y = bgpic->ima->aspy;
+
+        image_width = ibuf->x;
+        image_height = ibuf->y;
+        BKE_image_release_ibuf(image, ibuf, NULL);
+        image_aspect = (image_width * image_aspect_x) / (image_height * image_aspect_y);
+      }
+      else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+        MovieClip *clip = NULL;
+        if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
+          if (scene->camera) {
+            clip = BKE_object_movieclip_get(scene, scene->camera, true);
+          }
+        }
+        else {
+          clip = bgpic->clip;
+        }
+
+        if (clip == NULL) {
+          continue;
+        }
+
+        image_aspect_x = clip->aspx;
+        image_aspect_y = clip->aspy;
+
+        BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph));
+        tex = GPU_texture_from_movieclip(clip, &bgpic->cuser, GL_TEXTURE_2D);
+        if (tex == NULL) {
+          continue;
+        }
+        BLI_addtail(&e_data.movie_clips, BLI_genericNodeN(clip));
+        BKE_movieclip_get_size(clip, &bgpic->cuser, &image_width, &image_height);
+        image_aspect = (image_width * image_aspect_x) / (image_height * image_aspect_y);
+      }
+
+      /* ensure link_data is allocated to store matrice */
+      CameraEngineBGData *bg_data;
+      if (list_node != NULL) {
+        bg_data = (CameraEngineBGData *)list_node->data;
+        list_node = list_node->next;
+      }
+      else {
+        bg_data = MEM_mallocN(sizeof(CameraEngineBGData), __func__);
+        BLI_addtail(&camera_engine_data->bg_data, BLI_genericNodeN(bg_data));
+      }
+
+      /* calculate the transformation matric for the current bg image */
+      float uv2img_space[4][4];
+      float img2cam_space[4][4];
+      float rot_m4[4][4];
+      float scale_m4[4][4];
+      float translate_m4[4][4];
+      float win_m4_scale[4][4];
+      float win_m4_translate[4][4];
+
+      unit_m4(uv2img_space);
+      unit_m4(img2cam_space);
+      unit_m4(win_m4_scale);
+      unit_m4(win_m4_translate);
+      unit_m4(scale_m4);
+      axis_angle_to_mat4_single(rot_m4, 'Z', bgpic->rotation);
+      unit_m4(translate_m4);
+
+      const float *size = DRW_viewport_size_get();
+      float camera_aspect_x = 1.0;
+      float camera_aspect_y = 1.0;
+      float camera_offset_x = 0.0;
+      float camera_offset_y = 0.0;
+      float camera_aspect = 1.0;
+      float camera_width = size[0];
+      float camera_height = size[1];
+
+      if (!DRW_state_is_image_render()) {
+        rctf render_border;
+        ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &render_border, true);
+        camera_width = render_border.xmax - render_border.xmin;
+        camera_height = render_border.ymax - render_border.ymin;
+        camera_aspect = camera_width / camera_height;
+        const float camera_aspect_center_x = (render_border.xmax + render_border.xmin) / 2.0;
+        const float camera_aspect_center_y = (render_border.ymax + render_border.ymin) / 2.0;
+
+        camera_aspect_x = camera_width / size[0];
+        camera_aspect_y = camera_height / size[1];
+        win_m4_scale[0][0] = camera_aspect_x;
+        win_m4_scale[1][1] = camera_aspect_y;
+
+        camera_offset_x = (camera_aspect_center_x - (ar->winx / 2.0)) /
+                          (0.5 * camera_width / camera_aspect_x);
+        camera_offset_y = (camera_aspect_center_y - (ar->winy / 2.0)) /
+                          (0.5 * camera_height / camera_aspect_y);
+        win_m4_translate[3][0] = camera_offset_x;
+        win_m4_translate[3][1] = camera_offset_y;
+      }
+
+      /* Convert from uv space to image space -0.5..-.5 */
+      uv2img_space[0][0] = image_width;
+      uv2img_space[1][1] = image_height;
+
+      img2cam_space[0][0] = (1.0 / image_width);
+      img2cam_space[1][1] = (1.0 / image_height);
+
+      /* Update scaling based on image and camera framing */
+      float scale_x = bgpic->scale;
+      float scale_y = bgpic->scale;
+
+      if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
+        float fit_scale = image_aspect / camera_aspect;
+        if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
+          if (image_aspect > camera_aspect) {
+            scale_x *= fit_scale;
+          }
+          else {
+            scale_y /= fit_scale;
+          }
+        }
+        else {
+          if (image_aspect > camera_aspect) {
+            scale_y /= fit_scale;
+          }
+          else {
+            scale_x *= fit_scale;
+          }
+        }
+      }
+
+      // scale image to match the desired aspect ratio
+      scale_m4[0][0] = scale_x;
+      scale_m4[1][1] = scale_y;
+
+      // translate
+      translate_m4[3][0] = bgpic->offset[0];
+      translate_m4[3][1] = bgpic->offset[1];
+
+      mul_m4_series(bg_data->transform_mat,
+                    win_m4_translate,
+                    win_m4_scale,
+                    translate_m4,
+                    img2cam_space,
+                    scale_m4,
+                    rot_m4,
+                    uv2img_space);
+
+      DRWPass *pass = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? psl->camera_images_front :
+                                                                  psl->camera_images_back;
+      GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm :
+                                                            sh_data->object_camera_image;
+      DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+
+      DRW_shgroup_uniform_float_copy(
+          grp, "depth", (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? 0.000001 : 0.999999);
+      DRW_shgroup_uniform_float_copy(grp, "alpha", bgpic->alpha);
+      DRW_shgroup_uniform_texture(grp, "image", tex);
+      DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", premultiplied);
+
+      DRW_shgroup_uniform_float_copy(
+          grp, "flipX", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
+      DRW_shgroup_uniform_float_copy(
+          grp, "flipY", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
+      DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat);
+
+      DRW_shgroup_call(grp, batch, NULL);
+    }
+  }
+}
+
+static void camera_background_images_free_textures(void)
+{
+  for (LinkData *link = e_data.movie_clips.first; link; link = link->next) {
+    MovieClip *clip = (MovieClip *)link->data;
+    GPU_free_texture_movieclip(clip);
+  }
+  BLI_freelistN(&e_data.movie_clips);
+}
+
 static void OBJECT_cache_init(void *vedata)
 {
   const GlobalsUboStorage *gb = &G_draw.block;
@@ -1206,6 +1520,13 @@ static void OBJECT_cache_init(void *vedata)
     DRW_shgroup_call(grp, geom, NULL);
   }
 
+  /* Camera background images */
+  {
+    DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+    psl->camera_images_back = DRW_pass_create("Camera Images Back", state);
+    psl->camera_images_front = DRW_pass_create("Camera Images Front", state);
+  }
+
   for (int i = 0; i < 2; ++i) {
     OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
 
@@ -3266,6 +3587,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
           break;
         }
         DRW_shgroup_camera(sgl, ob, view_layer);
+        DRW_shgroup_camera_background_images(sh_data, psl, ob, rv3d);
         break;
       case OB_EMPTY:
         if (hide_object_extra) {
@@ -3449,6 +3771,8 @@ static void OBJECT_draw_scene(void *vedata)
 
   float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
 
+  DRW_draw_pass(psl->camera_images_back);
+
   /* Don't draw Transparent passes in MSAA buffer. */
   //  DRW_draw_pass(psl->bone_envelope);  /* Never drawn in Object mode currently. */
   DRW_draw_pass(stl->g_data->sgl.transp_shapes);
@@ -3518,7 +3842,6 @@ static void OBJECT_draw_scene(void *vedata)
       DRW_draw_pass(psl->outlines_resolve);
     }
   }
-
   volumes_free_smoke_textures();
   batch_camera_path_free(&stl->g_data->sgl.camera_path);
 
@@ -3567,6 +3890,9 @@ static void OBJECT_draw_scene(void *vedata)
 
   batch_camera_path_free(&stl->g_data->sgl_ghost.camera_path);
 
+  DRW_draw_pass(psl->camera_images_front);
+  camera_background_images_free_textures();
+
   DRW_draw_pass(psl->ob_center);
 }
 
index 5f833e4c6a15725aba9d30266536763b8cd8703e..82c11a278deeb7c714a14ceb6e33000765012209 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "DEG_depsgraph_query.h"
 
+extern char datatoc_common_colormanagement_lib_glsl[];
 extern char datatoc_common_globals_lib_glsl[];
 extern char datatoc_common_view_lib_glsl[];
 extern char datatoc_paint_texture_vert_glsl[];
@@ -160,7 +161,9 @@ static void PAINT_TEXTURE_engine_init(void *vedata)
                                  datatoc_common_view_lib_glsl,
                                  datatoc_paint_texture_vert_glsl,
                                  NULL},
-        .frag = (const char *[]){datatoc_paint_texture_frag_glsl, NULL},
+        .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
+                                 datatoc_paint_texture_frag_glsl,
+                                 NULL},
         .defs = (const char *[]){sh_cfg_data->def, NULL},
     });
 
diff --git a/source/blender/draw/modes/shaders/common_colormanagement_lib.glsl b/source/blender/draw/modes/shaders/common_colormanagement_lib.glsl
new file mode 100644 (file)
index 0000000..45f7112
--- /dev/null
@@ -0,0 +1,30 @@
+float linearrgb_to_srgb(float c)
+{
+  if (c < 0.0031308) {
+    return (c < 0.0) ? 0.0 : c * 12.92;
+  }
+  else {
+    return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+  }
+}
+
+vec4 texture_read_as_linearrgb(sampler2D tex, bool premultiplied, vec2 co)
+{
+  /* By convention image textures return scene linear colors, but
+   * overlays still assume srgb. */
+  vec4 color = texture(tex, co);
+  /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
+  if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
+    color.rgb = color.rgb / color.a;
+  }
+  return color;
+}
+
+vec4 texture_read_as_srgb(sampler2D tex, bool premultiplied, vec2 co)
+{
+  vec4 color = texture_read_as_linearrgb(tex, premultiplied, co);
+  color.r = linearrgb_to_srgb(color.r);
+  color.g = linearrgb_to_srgb(color.g);
+  color.b = linearrgb_to_srgb(color.b);
+  return color;
+}
diff --git a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl
new file mode 100644 (file)
index 0000000..5d8ad3c
--- /dev/null
@@ -0,0 +1,23 @@
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+uniform float alpha;
+uniform bool imagePremultiplied;
+
+void main()
+{
+#ifdef DRW_STATE_DO_COLOR_MANAGEMENT
+  /* render engine has already applied the view transform. We sample the
+   * camera images as srgb*/
+  vec4 color = texture_read_as_srgb(image, imagePremultiplied, texCoord_interp);
+
+#else
+  /* Render engine renders in linearrgb. We sample the camera images as
+   * linearrgb */
+  vec4 color = texture_read_as_linearrgb(image, imagePremultiplied, texCoord_interp);
+#endif
+
+  color.a *= alpha;
+  fragColor = color;
+}
diff --git a/source/blender/draw/modes/shaders/object_camera_image_vert.glsl b/source/blender/draw/modes/shaders/object_camera_image_vert.glsl
new file mode 100644 (file)
index 0000000..61b88c0
--- /dev/null
@@ -0,0 +1,18 @@
+uniform mat4 TransformMat;
+uniform float flipX;
+uniform float flipY;
+uniform float depth;
+
+in vec2 texCoord;
+in vec2 pos;
+
+out vec2 texCoord_interp;
+
+void main()
+{
+  vec4 position = TransformMat * vec4((pos - 0.5) * 2.0, 1.0, 1.0);
+  gl_Position = vec4(position.xy, depth, 1.0);
+
+  vec2 uv_mul = vec2(flipX, flipY);
+  texCoord_interp = texCoord * uv_mul;
+}
index 88220140aec170d6a46818448a9155ff7c66abf0..7dfbf469adcc567f2964232f813dbda0be5edd89 100644 (file)
@@ -15,31 +15,6 @@ uniform bool imagePremultiplied;
 uniform int depthMode;
 uniform bool useAlphaTest;
 
-float linearrgb_to_srgb(float c)
-{
-  if (c < 0.0031308) {
-    return (c < 0.0) ? 0.0 : c * 12.92;
-  }
-  else {
-    return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
-  }
-}
-
-vec4 texture_read_as_srgb(sampler2D tex, bool premultiplied, vec2 co)
-{
-  /* By convention image textures return scene linear colors, but
-   * overlays still assume srgb. */
-  vec4 color = texture(tex, co);
-  /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
-  if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
-    color.rgb = color.rgb / color.a;
-  }
-  color.r = linearrgb_to_srgb(color.r);
-  color.g = linearrgb_to_srgb(color.g);
-  color.b = linearrgb_to_srgb(color.b);
-  return color;
-}
-
 void main()
 {
 #ifdef USE_WIRE
index af7ea99e6a1bb2e448fe6f2d40168662b2574388..e8722590802d45269783169b9310a58b5adeea29 100644 (file)
@@ -18,31 +18,6 @@ uniform vec3 maskingColor;
 uniform bool maskingInvertStencil;
 #endif
 
-float linearrgb_to_srgb(float c)
-{
-  if (c < 0.0031308) {
-    return (c < 0.0) ? 0.0 : c * 12.92;
-  }
-  else {
-    return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
-  }
-}
-
-vec4 texture_read_as_srgb(sampler2D tex, bool premultiplied, vec2 co)
-{
-  /* By convention image textures return scene linear colors, but
-   * overlays still assume srgb. */
-  vec4 color = texture(tex, co);
-  /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */
-  if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) {
-    color.rgb = color.rgb / color.a;
-  }
-  color.r = linearrgb_to_srgb(color.r);
-  color.g = linearrgb_to_srgb(color.g);
-  color.b = linearrgb_to_srgb(color.b);
-  return color;
-}
-
 void main()
 {
   vec2 uv = uv_interp;
index 08ac0d91d4278d42507e4c24f533807902265724..386c31648431df8198bf80d8750ea651290166b3 100644 (file)
@@ -301,341 +301,6 @@ uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_b
   return buf;
 }
 
-/* ************************************************************* */
-
-static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
-{
-  if (BKE_image_is_stereo(ima)) {
-    iuser->flag |= IMA_SHOW_STEREO;
-
-    if ((scene->r.scemode & R_MULTIVIEW) == 0) {
-      iuser->multiview_eye = STEREO_LEFT_ID;
-    }
-    else if (v3d->stereo3d_camera != STEREO_3D_ID) {
-      /* show only left or right camera */
-      iuser->multiview_eye = v3d->stereo3d_camera;
-    }
-
-    BKE_image_multiview_index(ima, iuser);
-  }
-  else {
-    iuser->flag &= ~IMA_SHOW_STEREO;
-  }
-}
-
-static void view3d_draw_bgpic(Scene *scene,
-                              Depsgraph *depsgraph,
-                              ARegion *ar,
-                              View3D *v3d,
-                              const bool do_foreground,
-                              const bool do_camera_frame)
-{
-  RegionView3D *rv3d = ar->regiondata;
-  int fg_flag = do_foreground ? CAM_BGIMG_FLAG_FOREGROUND : 0;
-  if (v3d->camera == NULL || v3d->camera->type != OB_CAMERA) {
-    return;
-  }
-  Camera *cam = v3d->camera->data;
-
-  for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
-    if ((bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != fg_flag) {
-      continue;
-    }
-
-    {
-      float image_aspect[2];
-      float x1, y1, x2, y2, centx, centy;
-
-      void *lock;
-
-      Image *ima = NULL;
-
-      /* disable individual images */
-      if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED)) {
-        continue;
-      }
-
-      ImBuf *ibuf = NULL;
-      ImBuf *freeibuf = NULL;
-      ImBuf *releaseibuf = NULL;
-      if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
-        ima = bgpic->ima;
-        if (ima == NULL) {
-          continue;
-        }
-
-        ImageUser iuser = bgpic->iuser;
-        iuser.scene = scene; /* Needed for render results. */
-        BKE_image_user_frame_calc(ima, &iuser, (int)DEG_get_ctime(depsgraph));
-        if (ima->source == IMA_SRC_SEQUENCE && !(iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
-          ibuf = NULL; /* frame is out of range, dont show */
-        }
-        else {
-          view3d_stereo_bgpic_setup(scene, v3d, ima, &iuser);
-          ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock);
-          releaseibuf = ibuf;
-        }
-
-        image_aspect[0] = ima->aspx;
-        image_aspect[1] = ima->aspy;
-      }
-      else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
-        /* TODO: skip drawing when out of frame range (as image sequences do above) */
-        MovieClip *clip = NULL;
-
-        if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
-          if (scene->camera) {
-            clip = BKE_object_movieclip_get(scene, scene->camera, true);
-          }
-        }
-        else {
-          clip = bgpic->clip;
-        }
-
-        if (clip == NULL) {
-          continue;
-        }
-
-        BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph));
-        ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
-
-        image_aspect[0] = clip->aspx;
-        image_aspect[1] = clip->aspy;
-
-        /* working with ibuf from image and clip has got different workflow now.
-         * ibuf acquired from clip is referenced by cache system and should
-         * be dereferenced after usage. */
-        freeibuf = ibuf;
-      }
-      else {
-        /* perhaps when loading future files... */
-        BLI_assert(0);
-        copy_v2_fl(image_aspect, 1.0f);
-      }
-
-      if (ibuf == NULL) {
-        continue;
-      }
-
-      if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) {
-        /* invalid image format */
-        if (freeibuf) {
-          IMB_freeImBuf(freeibuf);
-        }
-        if (releaseibuf) {
-          BKE_image_release_ibuf(ima, releaseibuf, lock);
-        }
-
-        continue;
-      }
-
-      if (ibuf->rect == NULL) {
-        IMB_rect_from_float(ibuf);
-      }
-
-      BLI_assert(rv3d->persp == RV3D_CAMOB);
-      {
-        if (do_camera_frame) {
-          rctf vb;
-          ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
-          x1 = vb.xmin;
-          y1 = vb.ymin;
-          x2 = vb.xmax;
-          y2 = vb.ymax;
-        }
-        else {
-          x1 = ar->winrct.xmin;
-          y1 = ar->winrct.ymin;
-          x2 = ar->winrct.xmax;
-          y2 = ar->winrct.ymax;
-        }
-
-        /* apply offset last - camera offset is different to offset in blender units */
-        /* so this has some sane way of working - this matches camera's shift _exactly_ */
-        {
-          const float max_dim = max_ff(x2 - x1, y2 - y1);
-          const float xof_scale = bgpic->offset[0] * max_dim;
-          const float yof_scale = bgpic->offset[1] * max_dim;
-
-          x1 += xof_scale;
-          y1 += yof_scale;
-          x2 += xof_scale;
-          y2 += yof_scale;
-        }
-
-        centx = (x1 + x2) * 0.5f;
-        centy = (y1 + y2) * 0.5f;
-
-        /* aspect correction */
-        if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
-          /* apply aspect from clip */
-          const float w_src = ibuf->x * image_aspect[0];
-          const float h_src = ibuf->y * image_aspect[1];
-
-          /* destination aspect is already applied from the camera frame */
-          const float w_dst = x1 - x2;
-          const float h_dst = y1 - y2;
-
-          const float asp_src = w_src / h_src;
-          const float asp_dst = w_dst / h_dst;
-
-          if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
-            if ((asp_src > asp_dst) == ((bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) != 0)) {
-              /* fit X */
-              const float div = asp_src / asp_dst;
-              x1 = ((x1 - centx) * div) + centx;
-              x2 = ((x2 - centx) * div) + centx;
-            }
-            else {
-              /* fit Y */
-              const float div = asp_dst / asp_src;
-              y1 = ((y1 - centy) * div) + centy;
-              y2 = ((y2 - centy) * div) + centy;
-            }
-          }
-        }
-      }
-
-      /* complete clip? */
-      rctf clip_rect;
-      BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
-      if (bgpic->rotation) {
-        BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
-      }
-
-      if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx ||
-          clip_rect.ymin > ar->winy) {
-        if (freeibuf) {
-          IMB_freeImBuf(freeibuf);
-        }
-        if (releaseibuf) {
-          BKE_image_release_ibuf(ima, releaseibuf, lock);
-        }
-
-        continue;
-      }
-
-      float zoomx = (x2 - x1) / ibuf->x;
-      float zoomy = (y2 - y1) / ibuf->y;
-
-      /* For some reason; zoom-levels down refuses to use GL_ALPHA_SCALE. */
-      if (zoomx < 1.0f || zoomy < 1.0f) {
-        float tzoom = min_ff(zoomx, zoomy);
-        int mip = 0;
-
-        if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
-          IMB_remakemipmap(ibuf, 0);
-          ibuf->userflags &= ~IB_MIPMAP_INVALID;
-        }
-        else if (ibuf->mipmap[0] == NULL) {
-          IMB_makemipmap(ibuf, 0);
-        }
-
-        while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
-          tzoom *= 2.0f;
-          zoomx *= 2.0f;
-          zoomy *= 2.0f;
-          mip++;
-        }
-        if (mip > 0) {
-          ibuf = ibuf->mipmap[mip - 1];
-        }
-      }
-
-      GPU_depth_test(!do_foreground);
-      glDepthMask(GL_FALSE);
-
-      GPU_blend(true);
-      GPU_blend_set_func_separate(
-          GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
-
-      GPU_matrix_push_projection();
-      GPU_matrix_push();
-      ED_region_pixelspace(ar);
-
-      GPU_matrix_translate_2f(centx, centy);
-      GPU_matrix_scale_1f(bgpic->scale);
-      GPU_matrix_rotate_2d(RAD2DEGF(-bgpic->rotation));
-
-      if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) {
-        zoomx *= -1.0f;
-        x1 = x2;
-      }
-      if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) {
-        zoomy *= -1.0f;
-        y1 = y2;
-      }
-
-      float col[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
-      IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
-      immDrawPixelsTex(&state,
-                       x1 - centx,
-                       y1 - centy,
-                       ibuf->x,
-                       ibuf->y,
-                       GL_RGBA,
-                       GL_UNSIGNED_BYTE,
-                       GL_LINEAR,
-                       ibuf->rect,
-                       zoomx,
-                       zoomy,
-                       col);
-
-      GPU_matrix_pop_projection();
-      GPU_matrix_pop();
-
-      GPU_blend(false);
-
-      glDepthMask(GL_TRUE);
-      GPU_depth_test(true);
-
-      if (freeibuf) {
-        IMB_freeImBuf(freeibuf);
-      }
-      if (releaseibuf) {
-        BKE_image_release_ibuf(ima, releaseibuf, lock);
-      }
-    }
-  }
-}
-
-void ED_view3d_draw_bgpic_test(Scene *scene,
-                               Depsgraph *depsgraph,
-                               ARegion *ar,
-                               View3D *v3d,
-                               const bool do_foreground,
-                               const bool do_camera_frame)
-{
-  RegionView3D *rv3d = ar->regiondata;
-
-  if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
-    Camera *cam = v3d->camera->data;
-    if ((cam->flag & CAM_SHOW_BG_IMAGE) == 0) {
-      return;
-    }
-  }
-  else {
-    return;
-  }
-
-  /* disabled - mango request, since footage /w only render is quite useful
-   * and this option is easy to disable all background images at once */
-#if 0
-  if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
-    return;
-  }
-#endif
-
-  if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
-    if (rv3d->persp == RV3D_CAMOB) {
-      view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
-    }
-  }
-  else {
-    view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
-  }
-}
-
 /* *********************** */
 
 void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
index 3fb7dfc6331ccee69c4604a5695ad677a147c908..d5e763987cbb7ebe8eb772988311aa99ba578fa9 100644 (file)
@@ -33,6 +33,8 @@ extern "C" {
 struct GPUVertBuf;
 struct Image;
 struct ImageUser;
+struct MovieClip;
+struct MovieClipUser;
 struct PreviewImage;
 struct rcti;
 
@@ -189,6 +191,12 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode);
 GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, int textarget);
 GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
 
+/* movie clip drawing */
+GPUTexture *GPU_texture_from_movieclip(struct MovieClip *clip,
+                                       struct MovieClipUser *cuser,
+                                       int textarget);
+void GPU_free_texture_movieclip(struct MovieClip *clip);
+
 void GPU_texture_add_mipmap(GPUTexture *tex,
                             eGPUDataFormat gpu_data_format,
                             int miplvl,
index 7813ae68371ff2b2655d2cb44b1989651961f5a1..f5d599eb647a483675894c4ac1d6007142947959 100644 (file)
@@ -59,6 +59,7 @@
 #include "BKE_image.h"
 #include "BKE_main.h"
 #include "BKE_material.h"
+#include "BKE_movieclip.h"
 #include "BKE_node.h"
 #include "BKE_scene.h"
 
@@ -247,7 +248,7 @@ static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, int textarget)
        * this allows us to use sRGB texture formats and preserves color values in
        * zero alpha areas, and appears generally closer to what game engines that we
        * want to be compatible with do. */
-      const bool store_premultiplied = (ima->alpha_mode == IMA_ALPHA_PREMUL);
+      const bool store_premultiplied = ima ? (ima->alpha_mode == IMA_ALPHA_PREMUL) : true;
       IMB_colormanagement_imbuf_to_byte_texture(
           rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
     }
@@ -256,14 +257,13 @@ static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, int textarget)
     /* Float image is already in scene linear colorspace or non-color data by
      * convention, no colorspace conversion needed. But we do require 4 channels
      * currently. */
-    const bool store_premultiplied = (ima->alpha_mode != IMA_ALPHA_STRAIGHT);
+    const bool store_premultiplied = ima ? (ima->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
 
     if (ibuf->channels != 4 || !store_premultiplied) {
       rect_float = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
       if (rect_float == NULL) {
         return bindcode;
       }
-
       IMB_colormanagement_imbuf_to_float_texture(
           rect_float, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
     }
@@ -291,6 +291,36 @@ static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, int textarget)
   return bindcode;
 }
 
+static GPUTexture **gpu_get_movieclip_gputexture(MovieClip *clip,
+                                                 MovieClipUser *cuser,
+                                                 GLenum textarget)
+{
+  MovieClip_RuntimeGPUTexture *tex;
+  for (tex = clip->runtime.gputextures.first; tex; tex = tex->next) {
+    if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) {
+      break;
+    }
+  }
+
+  if (tex == NULL) {
+    tex = MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture), __func__);
+
+    for (int i = 0; i < TEXTARGET_COUNT; i++) {
+      tex->gputexture[i] = NULL;
+    }
+
+    memcpy(&tex->user, cuser, sizeof(MovieClipUser));
+    BLI_addtail(&clip->runtime.gputextures, tex);
+  }
+
+  if (textarget == GL_TEXTURE_2D)
+    return &tex->gputexture[TEXTARGET_TEXTURE_2D];
+  else if (textarget == GL_TEXTURE_CUBE_MAP)
+    return &tex->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
+
+  return NULL;
+}
+
 static void gpu_texture_update_scaled(
     uchar *rect, float *rect_float, int full_w, int full_h, int x, int y, int w, int h)
 {
@@ -472,6 +502,52 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
   return *tex;
 }
 
+GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, int textarget)
+{
+  if (clip == NULL) {
+    return NULL;
+  }
+
+  GPUTexture **tex = gpu_get_movieclip_gputexture(clip, cuser, textarget);
+  if (*tex) {
+    return *tex;
+  }
+
+  /* check if we have a valid image buffer */
+  uint bindcode = 0;
+  ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser);
+  if (ibuf == NULL) {
+    *tex = GPU_texture_from_bindcode(textarget, bindcode);
+    return *tex;
+  }
+
+  bindcode = gpu_texture_create_from_ibuf(NULL, ibuf, textarget);
+  IMB_freeImBuf(ibuf);
+
+  *tex = GPU_texture_from_bindcode(textarget, bindcode);
+  return *tex;
+}
+
+void GPU_free_texture_movieclip(struct MovieClip *clip)
+{
+  /* number of gpu textures to keep around as cache
+   * We don't want to keep too many GPU textures for
+   * movie clips around, as they can be large.*/
+  const int MOVIECLIP_NUM_GPUTEXTURES = 1;
+
+  while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) {
+    MovieClip_RuntimeGPUTexture *tex = BLI_pophead(&clip->runtime.gputextures);
+    for (int i = 0; i < TEXTARGET_COUNT; i++) {
+      /* free glsl image binding */
+      if (tex->gputexture[i]) {
+        GPU_texture_free(tex->gputexture[i]);
+        tex->gputexture[i] = NULL;
+      }
+    }
+    MEM_freeN(tex);
+  }
+}
+
 static void **gpu_gen_cube_map(uint *rect, float *frect, int rectw, int recth)
 {
   size_t block_size = frect ? sizeof(float[4]) : sizeof(uchar[4]);
index c804a78eccb5375596e57272766e0123de8aa03a..efda24d6e0e99fdccd9fae26169387c200c98be1 100644 (file)
@@ -57,6 +57,17 @@ typedef struct MovieClipProxy {
   short build_tc_flag;
 } MovieClipProxy;
 
+typedef struct MovieClip_RuntimeGPUTexture {
+  void *next, *prev;
+  MovieClipUser user;
+  /** Not written in file 2 = TEXTARGET_COUNT. */
+  struct GPUTexture *gputexture[2];
+} MovieClip_RuntimeGPUTexture;
+
+typedef struct MovieClip_Runtime {
+  struct ListBase gputextures;
+} MovieClip_Runtime;
+
 typedef struct MovieClip {
   ID id;
   /** Animation data (must be immediately after id for utilities to use it). */
@@ -111,6 +122,8 @@ typedef struct MovieClip {
 
   /* color management */
   ColorManagedColorspaceSettings colorspace_settings;
+
+  struct MovieClip_Runtime runtime;
 } MovieClip;
 
 typedef struct MovieClipScopes {
index 7cb1610fd3138a09c025f580812e8de37feaaad5..bb236fc3ef453e03d595e27669f8d748ab1d3f27 100644 (file)
@@ -231,12 +231,14 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
   prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_XYZ);
   RNA_def_property_float_sdna(prop, NULL, "offset");
   RNA_def_property_ui_text(prop, "Offset", "");
+  RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 0.1, RNA_TRANSLATION_PREC_DEFAULT);
   RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 
   prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
   RNA_def_property_float_sdna(prop, NULL, "scale");
   RNA_def_property_ui_text(prop, "Scale", "Scale the background image");
   RNA_def_property_range(prop, 0.0, FLT_MAX);
+  RNA_def_property_ui_range(prop, 0.0, 10.0, 0.100, RNA_TRANSLATION_PREC_DEFAULT);
   RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 
   prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);