diff options
20 files changed, 546 insertions, 502 deletions
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index c377223d14b..6bc83f8dd09 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -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) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 541ebe8f01d..393f8f87a90 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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) { diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 5a8a4d46ac9..8631a9f556b 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -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) diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 6d1227bb0a8..ae3bf8cead6 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -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) { diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl index 1fdfd05332e..87bf116ff89 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl @@ -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); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl index 7fed42aca0d..34777018a73 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl @@ -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); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl index bc703d2a078..73baacb35d4 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl @@ -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() { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 87366289bf7..7606fa914d1 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -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 */ diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index e8c600ee545..1c60fc09057 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -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); } diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index 5f833e4c6a1..82c11a278de 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -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 index 00000000000..45f711296f3 --- /dev/null +++ b/source/blender/draw/modes/shaders/common_colormanagement_lib.glsl @@ -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 index 00000000000..5d8ad3c79ea --- /dev/null +++ b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl @@ -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 index 00000000000..61b88c013aa --- /dev/null +++ b/source/blender/draw/modes/shaders/object_camera_image_vert.glsl @@ -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; +} diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl index 88220140aec..7dfbf469adc 100644 --- a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl +++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl @@ -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 diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl index af7ea99e6a1..e8722590802 100644 --- a/source/blender/draw/modes/shaders/paint_texture_frag.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl @@ -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; diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index 08ac0d91d42..386c3164843 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -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) diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 3fb7dfc6331..d5e763987cb 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -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, diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 7813ae68371..f5d599eb647 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -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]); diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h index c804a78eccb..efda24d6e0e 100644 --- a/source/blender/makesdna/DNA_movieclip_types.h +++ b/source/blender/makesdna/DNA_movieclip_types.h @@ -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 { diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 7cb1610fd31..bb236fc3ef4 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -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); |