Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2022-01-26 23:57:44 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-01-27 00:03:58 +0300
commit4226c484bdbe7336f1221094916fcdfb12850034 (patch)
tree33428e72be40105c222ca77935ee1554b702facc /source/blender/imbuf
parent55a6a8900aec81e94f4d82401d6051e3b5507c0e (diff)
parentaf87b6d8cb75d9d625378dee25d726a0d55f75c6 (diff)
Merge branch 'draw-viewport-data' into eevee-rewrite
# Conflicts: # release/scripts/startup/bl_ui/properties_data_camera.py # source/blender/blenkernel/BKE_camera.h # source/blender/blenkernel/BKE_node.h # source/blender/blenkernel/intern/camera.c # source/blender/blenlib/BLI_float2.hh # source/blender/blenlib/BLI_float3.hh # source/blender/blenlib/BLI_float4.hh # source/blender/blenlib/BLI_math_geom.h # source/blender/blenlib/intern/math_geom.c # source/blender/draw/CMakeLists.txt # source/blender/draw/engines/basic/basic_engine.c # source/blender/draw/engines/eevee/eevee_cryptomatte.c # source/blender/draw/engines/eevee/eevee_effects.c # source/blender/draw/engines/eevee/eevee_engine.c # source/blender/draw/engines/eevee/eevee_lightcache.c # source/blender/draw/engines/eevee/eevee_lightcache.h # source/blender/draw/engines/eevee/eevee_lightprobes.c # source/blender/draw/engines/eevee/eevee_lights.c # source/blender/draw/engines/eevee/eevee_materials.c # source/blender/draw/engines/eevee/eevee_motion_blur.c # source/blender/draw/engines/eevee/eevee_occlusion.c # source/blender/draw/engines/eevee/eevee_private.h # source/blender/draw/engines/eevee/eevee_render.c # source/blender/draw/engines/eevee/eevee_renderpasses.c # source/blender/draw/engines/eevee/eevee_sampling.c # source/blender/draw/engines/eevee/eevee_screen_raytrace.c # source/blender/draw/engines/eevee/eevee_shaders.c # source/blender/draw/engines/eevee/eevee_shadows.c # source/blender/draw/engines/eevee/eevee_shadows_cube.c # source/blender/draw/engines/eevee/eevee_temporal_sampling.c # source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl # source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl # source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl # source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl # source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl # source/blender/draw/engines/eevee/shaders/random_lib.glsl # source/blender/draw/engines/eevee/shaders/shadow_vert.glsl # source/blender/draw/engines/eevee/shaders/surface_lib.glsl # source/blender/draw/engines/eevee/shaders/surface_vert.glsl # source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl # source/blender/draw/engines/external/external_engine.c # source/blender/draw/engines/gpencil/gpencil_engine.c # source/blender/draw/engines/image/image_engine.c # source/blender/draw/engines/overlay/overlay_engine.c # source/blender/draw/engines/select/select_engine.c # source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl # source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl # source/blender/draw/engines/workbench/workbench_engine.c # source/blender/draw/engines/workbench/workbench_shader.c # source/blender/draw/intern/DRW_render.h # source/blender/draw/intern/draw_debug.h # source/blender/draw/intern/draw_manager_data.c # source/blender/draw/intern/draw_manager_exec.c # source/blender/draw/intern/draw_view_data.h # source/blender/gpu/CMakeLists.txt # source/blender/gpu/GPU_material.h # source/blender/gpu/GPU_shader.h # source/blender/gpu/GPU_state.h # source/blender/gpu/GPU_vertex_buffer.h # source/blender/gpu/intern/gpu_codegen.c # source/blender/gpu/intern/gpu_material.c # source/blender/gpu/intern/gpu_material_library.h # source/blender/gpu/intern/gpu_node_graph.c # source/blender/gpu/intern/gpu_texture_private.hh # source/blender/gpu/intern/gpu_vertex_buffer.cc # source/blender/gpu/opengl/gl_shader.cc # source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl # source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl # source/blender/nodes/shader/node_shader_tree.cc # source/blender/nodes/shader/nodes/node_shader_background.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c # source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c # source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc # source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc # source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc # source/blender/nodes/shader/nodes/node_shader_emission.cc # source/blender/nodes/shader/nodes/node_shader_holdout.cc # source/blender/nodes/shader/nodes/node_shader_output_material.cc # source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c # source/blender/nodes/shader/nodes/node_shader_tex_coord.cc # source/blender/nodes/shader/nodes/node_shader_vector_transform.cc # source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc # source/blender/nodes/shader/nodes/node_shader_volume_principled.cc # source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc # source/blender/render/RE_pipeline.h # source/blender/render/intern/initrender.c
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r--source/blender/imbuf/CMakeLists.txt1
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h222
-rw-r--r--source/blender/imbuf/IMB_imbuf.h277
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h29
-rw-r--r--source/blender/imbuf/IMB_metadata.h5
-rw-r--r--source/blender/imbuf/IMB_moviecache.h5
-rw-r--r--source/blender/imbuf/IMB_thumbs.h39
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h129
-rw-r--r--source/blender/imbuf/intern/IMB_filter.h3
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c15
-rw-r--r--source/blender/imbuf/intern/anim_movie.c254
-rw-r--r--source/blender/imbuf/intern/bmp.c4
-rw-r--r--source/blender/imbuf/intern/cache.c2
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c61
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c12
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.cpp18
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h18
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.cpp5
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h5
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp2
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h7
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp23
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.h15
-rw-r--r--source/blender/imbuf/intern/dds/Stream.cpp25
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp9
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.h2
-rw-r--r--source/blender/imbuf/intern/divers.c29
-rw-r--r--source/blender/imbuf/intern/filter.c8
-rw-r--r--source/blender/imbuf/intern/imageprocess.c188
-rw-r--r--source/blender/imbuf/intern/indexer.c140
-rw-r--r--source/blender/imbuf/intern/iris.c12
-rw-r--r--source/blender/imbuf/intern/jp2.c16
-rw-r--r--source/blender/imbuf/intern/jpeg.c5
-rw-r--r--source/blender/imbuf/intern/moviecache.c39
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.h2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp31
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h6
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h29
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp2
-rw-r--r--source/blender/imbuf/intern/png.c4
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c31
-rw-r--r--source/blender/imbuf/intern/readimage.c2
-rw-r--r--source/blender/imbuf/intern/rectop.c35
-rw-r--r--source/blender/imbuf/intern/rotate.c62
-rw-r--r--source/blender/imbuf/intern/scaling.c11
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c3
-rw-r--r--source/blender/imbuf/intern/tiff.c40
-rw-r--r--source/blender/imbuf/intern/transform.cc604
-rw-r--r--source/blender/imbuf/intern/util.c2
-rw-r--r--source/blender/imbuf/intern/util_gpu.c5
53 files changed, 1693 insertions, 808 deletions
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index be0e364c85f..479f4f7e82f 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/thumbs.c
intern/thumbs_blend.c
intern/thumbs_font.c
+ intern/transform.cc
intern/util.c
intern/util_gpu.c
intern/writeimage.c
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 53b0e295385..30f2f24447f 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -45,7 +45,9 @@ struct bContext;
struct ColorManagedDisplay;
struct ColorSpace;
-/* ** Generic functions ** */
+/* -------------------------------------------------------------------- */
+/** \name Generic Functions
+ * \{ */
void IMB_colormanagement_check_file_config(struct Main *bmain);
@@ -67,13 +69,35 @@ bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace);
bool IMB_colormanagement_space_name_is_data(const char *name);
+/**
+ * Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Gray-scale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
+/**
+ * Byte equivalent of #IMB_colormanagement_get_luminance().
+ */
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
BLI_INLINE void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3]);
BLI_INLINE void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3]);
const float *IMB_colormanagement_get_xyz_to_rgb(void);
-/* ** Color space transformation functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Transformation Functions
+ * \{ */
+
+/**
+ * Convert the whole buffer from specified by name color space to another.
+ */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -81,6 +105,10 @@ void IMB_colormanagement_transform(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Convert the whole buffer from specified by name color space to another
+ * will do threaded conversion.
+ */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -88,6 +116,9 @@ void IMB_colormanagement_transform_threaded(float *buffer,
const char *from_colorspace,
const char *to_colorspace,
bool predivide);
+/**
+ * Similar to #IMB_colormanagement_transform_threaded, but operates on byte buffer.
+ */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -100,6 +131,9 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
int channels,
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Similar to #IMB_colormanagement_transform_byte_threaded, but gets float buffer from display one.
+ */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -118,12 +152,20 @@ void IMB_colormanagement_transform_v4(float pixel[4],
const char *from_colorspace,
const char *to_colorspace);
+/**
+ * Convert pixel from specified by descriptor color space to scene linear
+ * used by performance-critical areas such as renderer and baker.
+ */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3],
struct ColorSpace *colorspace);
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4],
bool predivide,
struct ColorSpace *colorspace);
+/**
+ * Same as #IMB_colormanagement_colorspace_to_scene_linear_v4,
+ * but converts colors in opposite direction.
+ */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3],
struct ColorSpace *colorspace);
@@ -135,29 +177,51 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer,
bool predivide);
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
- const int x,
- const int y,
- const int width,
- const int height,
+ int x,
+ int y,
+ int width,
+ int height,
const struct ImBuf *ibuf,
- const bool compress_as_srgb,
- const bool store_premultiplied);
+ bool compress_as_srgb,
+ bool store_premultiplied);
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
- const int offset_x,
- const int offset_y,
- const int width,
- const int height,
+ int offset_x,
+ int offset_y,
+ int width,
+ int height,
const struct ImBuf *ibuf,
- const bool store_premultiplied);
-
+ bool store_premultiplied);
+
+/**
+ * Conversion between color picking role. Typically we would expect such a
+ * requirements:
+ * - It is approximately perceptually linear, so that the HSV numbers and
+ * the HSV cube/circle have an intuitive distribution.
+ * - It has the same gamut as the scene linear color space.
+ * - Color picking values 0..1 map to scene linear values in the 0..1 range,
+ * so that picked albedo values are energy conserving.
+ */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]);
void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]);
+/**
+ * Conversion between sRGB, for rare cases like hex color or copy/pasting
+ * between UI theme and scene linear colors.
+ */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3]);
void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3]);
+/**
+ * Convert pixel from scene linear to display space using default view
+ * used by performance-critical areas such as color-related widgets where we want to reduce
+ * amount of per-widget allocations.
+ */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3],
struct ColorManagedDisplay *display);
+/**
+ * Same as #IMB_colormanagement_scene_linear_to_display_v3,
+ * but converts color in opposite direction.
+ */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3],
struct ColorManagedDisplay *display);
@@ -178,6 +242,18 @@ void IMB_colormanagement_imbuf_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Prepare image buffer to be saved on disk, applying color management if needed
+ * color management would be applied if image is saving as render result and if
+ * file format is not expecting float buffer to be in linear space (currently
+ * JPEG2000 and TIFF are such formats -- they're storing image as float but
+ * file itself stores applied color space).
+ *
+ * Both byte and float buffers would contain applied color space, and result's
+ * float_colorspace would be set to display color space. This should be checked
+ * in image format write callback and if float_colorspace is not NULL, no color
+ * space transformation should be applied on this buffer.
+ */
struct ImBuf *IMB_colormanagement_imbuf_for_write(
struct ImBuf *ibuf,
bool save_as_render,
@@ -196,7 +272,11 @@ void IMB_colormanagement_buffer_make_display_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
-/* ** Public display buffers interfaces ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Display Buffers Interfaces
+ * \{ */
void IMB_colormanagement_display_settings_from_ctx(
const struct bContext *C,
@@ -207,11 +287,17 @@ const char *IMB_colormanagement_get_display_colorspace_name(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
+/**
+ * Acquire display buffer for given image buffer using specified view and display settings.
+ */
unsigned char *IMB_display_buffer_acquire(
struct ImBuf *ibuf,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
void **cache_handle);
+/**
+ * Same as #IMB_display_buffer_acquire but gets view and display settings from context.
+ */
unsigned char *IMB_display_buffer_acquire_ctx(const struct bContext *C,
struct ImBuf *ibuf,
void **cache_handle);
@@ -227,24 +313,47 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
void IMB_display_buffer_release(void *cache_handle);
-/* ** Display functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Display Functions
+ * \{ */
+
int IMB_colormanagement_display_get_named_index(const char *name);
const char *IMB_colormanagement_display_get_indexed_name(int index);
const char *IMB_colormanagement_display_get_default_name(void);
+/**
+ * Used by performance-critical pixel processing areas, such as color widgets.
+ */
struct ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name);
const char *IMB_colormanagement_display_get_none_name(void);
const char *IMB_colormanagement_display_get_default_view_transform_name(
struct ColorManagedDisplay *display);
-/* ** View functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Functions
+ * \{ */
+
int IMB_colormanagement_view_get_named_index(const char *name);
const char *IMB_colormanagement_view_get_indexed_name(int index);
-/* ** Look functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Look Functions
+ * \{ */
+
int IMB_colormanagement_look_get_named_index(const char *name);
const char *IMB_colormanagement_look_get_indexed_name(int index);
-/* ** Color space functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Space Functions
+ * \{ */
+
int IMB_colormanagement_colorspace_get_named_index(const char *name);
const char *IMB_colormanagement_colorspace_get_indexed_name(int index);
const char *IMB_colormanagement_view_get_default_name(const char *display_name);
@@ -252,7 +361,12 @@ const char *IMB_colormanagement_view_get_default_name(const char *display_name);
void IMB_colormanagement_colorspace_from_ibuf_ftype(
struct ColorManagedColorspaceSettings *colorspace_settings, struct ImBuf *ibuf);
-/* ** RNA helper functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name RNA Helper Functions
+ * \{ */
+
void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem);
void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items,
int *totitem,
@@ -262,7 +376,12 @@ void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items,
const char *view_name);
void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem);
-/* ** Tile-based buffer management ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tile-based Buffer Management
+ * \{ */
+
void IMB_partial_display_buffer_update(struct ImBuf *ibuf,
const float *linear_buffer,
const unsigned char *byte_buffer,
@@ -293,7 +412,12 @@ void IMB_partial_display_buffer_update_threaded(
void IMB_partial_display_buffer_update_delayed(
struct ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax);
-/* ** Pixel processor functions ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pixel Processor Functions
+ * \{ */
+
struct ColormanageProcessor *IMB_colormanagement_display_processor_new(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -321,17 +445,40 @@ void IMB_colormanagement_processor_apply_byte(struct ColormanageProcessor *cm_pr
int channels);
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor);
-/* ** OpenGL drawing routines using GLSL for color space transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name OpenGL Drawing Routines Using GLSL for Color Space Transform
+ * \{ */
-/* Test if GLSL drawing is supported for combination of graphics card and this configuration */
+/**
+ * Test if GLSL drawing is supported for combination of graphics card and this configuration.
+ */
bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings *view_settings);
-/* Configures GLSL shader for conversion from scene linear to display space */
+/**
+ * Configures GLSL shader for conversion from scene linear to display space.
+ */
bool IMB_colormanagement_setup_glsl_draw(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
float dither,
bool predivide);
-/* Same as above, but display space conversion happens from a specified space */
+/**
+ * \note Same as IMB_colormanagement_setup_glsl_draw,
+ * but display space conversion happens from a specified space.
+ *
+ * Configures GLSL shader for conversion from specified to
+ * display color space
+ *
+ * Will create appropriate OCIO processor and setup GLSL shader,
+ * so further 2D texture usage will use this conversion.
+ *
+ * When there's no need to apply transform on 2D textures, use
+ * IMB_colormanagement_finish_glsl_draw().
+ *
+ * This is low-level function, use ED_draw_imbuf_ctx if you
+ * only need to display given image buffer
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
@@ -339,20 +486,31 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
float dither,
bool predivide,
bool do_overlay_merge);
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
+/**
+ * Same as setup_glsl_draw, but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C,
float dither,
bool predivide);
-/* Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context. */
+/**
+ * Same as `setup_glsl_draw_from_space`,
+ * but color management settings are guessing from a given context.
+ */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C,
struct ColorSpace *colorspace,
float dither,
bool predivide);
-/* Finish GLSL-based display space conversion */
+/**
+ * Finish GLSL-based display space conversion.
+ */
void IMB_colormanagement_finish_glsl_draw(void);
-/* ** View transform ** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Transform
+ * \{ */
+
void IMB_colormanagement_init_default_view_settings(
struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings);
@@ -368,6 +526,8 @@ enum {
COLOR_ROLE_DATA,
};
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index dd8e6549e24..a557d7dc6d1 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -199,6 +199,17 @@ bool addzbuffloatImBuf(struct ImBuf *ibuf);
size_t IMB_get_size_in_memory(struct ImBuf *ibuf);
/**
+ * \brief Get the length of the rect of the given image buffer in terms of pixels.
+ *
+ * This is the width * the height of the image buffer.
+ * This function is preferred over `ibuf->x * ibuf->y` due to overflow issues when
+ * working with large resolution images (30kx30k).
+ *
+ * \attention Defined in allocimbuf.c
+ */
+size_t IMB_get_rect_len(const struct ImBuf *ibuf);
+
+/**
*
* \attention Defined in rectop.c
*/
@@ -244,8 +255,14 @@ void IMB_blend_color_float(float dst[4],
const float src2[4],
IMB_BlendMode mode);
+/**
+ * In-place image crop.
+ */
void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop);
+/**
+ * In-place size setting (caller must fill in buffer contents).
+ */
void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]);
void IMB_rectclip(struct ImBuf *dbuf,
@@ -342,7 +359,9 @@ typedef enum eIMBInterpolationFilterMode {
IMB_FILTER_BILINEAR,
} eIMBInterpolationFilterMode;
-/* Defaults to BL_proxy within the directory of the animation. */
+/**
+ * Defaults to BL_proxy within the directory of the animation.
+ */
void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
void IMB_anim_get_fname(struct anim *anim, char *file, int size);
@@ -352,21 +371,28 @@ IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim);
struct IndexBuildContext;
-/* Prepare context for proxies/time-codes builder. */
+/**
+ * Prepare context for proxies/time-codes builder
+ */
struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
const bool overwrite,
- struct GSet *file_list);
+ struct GSet *file_list,
+ bool build_only_on_bad_performance);
-/* Will rebuild all used indices and proxies at once. */
+/**
+ * Will rebuild all used indices and proxies at once.
+ */
void IMB_anim_index_rebuild(struct IndexBuildContext *context,
short *stop,
short *do_update,
float *progress);
-/* Finish rebuilding proxies/time-codes and free temporary contexts used. */
+/**
+ * Finish rebuilding proxies/time-codes and free temporary contexts used.
+ */
void IMB_anim_index_rebuild_finish(struct IndexBuildContext *context, short stop);
/**
@@ -406,6 +432,7 @@ bool IMB_anim_can_produce_frames(const struct anim *anim);
int ismovie(const char *filepath);
int IMB_anim_get_image_width(struct anim *anim);
int IMB_anim_get_image_height(struct anim *anim);
+bool IMB_get_gop_decode_time(struct anim *anim);
/**
*
@@ -442,8 +469,20 @@ void IMB_free_anim(struct anim *anim);
void IMB_filter(struct ImBuf *ibuf);
void IMB_mask_filter_extend(char *mask, int width, int height);
void IMB_mask_clear(struct ImBuf *ibuf, const char *mask, int val);
+/**
+ * If alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
+ * When a mask is given, the mask will be used instead of the alpha channel, where only
+ * pixels with a mask value of 0 will be written to, and only pixels with a mask value of 1
+ * will be used for the average. The mask will be set to one for the pixels which were written.
+ */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter);
+/**
+ * Frees too (if there) and recreates new data.
+ */
void IMB_makemipmap(struct ImBuf *ibuf, int use_filter);
+/**
+ * Thread-safe version, only recreates existing maps.
+ */
void IMB_remakemipmap(struct ImBuf *ibuf, int use_filter);
struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
@@ -452,6 +491,9 @@ struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level);
* \attention Defined in cache.c
*/
+/**
+ * Presumed to be called when no threads are running.
+ */
void IMB_tile_cache_params(int totthread, int maxmem);
unsigned int *IMB_gettile(struct ImBuf *ibuf, int tx, int ty, int thread);
void IMB_tiles_to_rect(struct ImBuf *ibuf);
@@ -471,6 +513,8 @@ struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1);
/**
*
* \attention Defined in scaling.c
+ *
+ * Return true if \a ibuf is modified.
*/
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
@@ -478,6 +522,9 @@ bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
*
* \attention Defined in scaling.c
*/
+/**
+ * Return true if \a ibuf is modified.
+ */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy);
/**
@@ -491,7 +538,7 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int
* \attention Defined in writeimage.c
*/
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags);
-bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
+bool IMB_prepare_write_ImBuf(bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -499,7 +546,7 @@ bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
*/
bool IMB_ispic(const char *filepath);
bool IMB_ispic_type_matches(const char *filepath, int filetype);
-int IMB_ispic_type_from_memory(const unsigned char *buf, const size_t buf_size);
+int IMB_ispic_type_from_memory(const unsigned char *buf, size_t buf_size);
int IMB_ispic_type(const char *filepath);
/**
@@ -520,16 +567,27 @@ int imb_get_anim_type(const char *filepath);
*/
bool IMB_isfloat(const struct ImBuf *ibuf);
-/* Do byte/float and colorspace conversions need to take alpha into account? */
+/**
+ * Test if color-space conversions of pixels in buffer need to take into account alpha.
+ */
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf);
-/* create char buffer, color corrected if necessary, for ImBufs that lack one */
+/**
+ * Create char buffer, color corrected if necessary, for ImBufs that lack one.
+ */
void IMB_rect_from_float(struct ImBuf *ibuf);
void IMB_float_from_rect(struct ImBuf *ibuf);
+/**
+ * No profile conversion.
+ */
void IMB_color_to_bw(struct ImBuf *ibuf);
void IMB_saturation(struct ImBuf *ibuf, float sat);
-/* converting pixel buffers */
+/* Converting pixel buffers. */
+
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -541,6 +599,9 @@ void IMB_buffer_byte_from_float(unsigned char *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to byte pixels, output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
const float *rect_from,
int channels_from,
@@ -551,6 +612,9 @@ void IMB_buffer_byte_from_float_mask(unsigned char *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to float pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_float_from_byte(float *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -560,6 +624,9 @@ void IMB_buffer_float_from_byte(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -580,6 +647,9 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
int height,
int stride_to,
int stride_from);
+/**
+ * Float to float pixels, output 4-channel RGBA.
+ */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -588,6 +658,9 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
int stride_to,
int stride_from,
char *mask);
+/**
+ * Byte to byte pixels, input and output 4-channel RGBA.
+ */
void IMB_buffer_byte_from_byte(unsigned char *rect_to,
const unsigned char *rect_from,
int profile_to,
@@ -605,6 +678,8 @@ void IMB_buffer_float_premultiply(float *buf, int width, int height);
* rgba to abgr. size * 4 color bytes are reordered.
*
* \attention Defined in imageprocess.c
+ *
+ * Only this one is used liberally here, and in imbuf.
*/
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
@@ -612,27 +687,50 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
*
* \attention defined in imageprocess.c
*/
+
void bicubic_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void nearest_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
void bilinear_interpolation(
- struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+ const struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+typedef void (*InterpolationColorFunction)(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+
+/* Functions assumes out to be zeroed, only does RGBA. */
+
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+/**
+ * Note about wrapping, the u/v still needs to be within the image bounds,
+ * just the interpolation is wrapped.
+ * This the same as bilinear_interpolation_color except it wraps
+ * rather than using empty and emptyI.
+ */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3]);
+/**
+ * Sample pixel of image using NEAREST method.
+ */
void IMB_sampleImageAtLocation(
struct ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
@@ -686,7 +784,7 @@ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1);
void IMB_flipx(struct ImBuf *ibuf);
void IMB_flipy(struct ImBuf *ibuf);
-/* Premultiply alpha */
+/* Pre-multiply alpha. */
void IMB_premultiply_alpha(struct ImBuf *ibuf);
void IMB_unpremultiply_alpha(struct ImBuf *ibuf);
@@ -702,7 +800,27 @@ void IMB_freezbuffloatImBuf(struct ImBuf *ibuf);
*
* \attention Defined in rectop.c
*/
+/**
+ * Replace pixels of entire image with solid color.
+ * \param drect: An image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ */
void IMB_rectfill(struct ImBuf *drect, const float col[4]);
+/**
+ * Blend pixels of image area with solid color.
+ *
+ * For images with `uchar` buffer use color matching image color-space.
+ * For images with float buffer use color display color-space.
+ * If display color-space can not be referenced, use color in SRGB color-space.
+ *
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ * \param display: color-space reference for display space.
+ */
void IMB_rectfill_area(struct ImBuf *ibuf,
const float col[4],
int x1,
@@ -710,12 +828,23 @@ void IMB_rectfill_area(struct ImBuf *ibuf,
int x2,
int y2,
struct ColorManagedDisplay *display);
+/**
+ * Replace pixels of image area with solid color.
+ * \param ibuf: an image to be filled with color. It must be 4 channel image.
+ * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ */
void IMB_rectfill_area_replace(
const struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2);
-void IMB_rectfill_alpha(struct ImBuf *ibuf, const float value);
+void IMB_rectfill_alpha(struct ImBuf *ibuf, float value);
-/* This should not be here, really,
- * we needed it for operating on render data, IMB_rectfill_area calls it. */
+/**
+ * This should not be here, really,
+ * we needed it for operating on render data, #IMB_rectfill_area calls it.
+ */
void buf_rectfill_area(unsigned char *rect,
float *rectf,
int width,
@@ -727,23 +856,34 @@ void buf_rectfill_area(unsigned char *rect,
int x2,
int y2);
-/* exported for image tools in blender, to quickly allocate 32 bits rect */
+/**
+ * Exported for image tools in blender, to quickly allocate 32 bits rect.
+ */
void *imb_alloc_pixels(
unsigned int x, unsigned int y, unsigned int channels, size_t typesize, const char *name);
bool imb_addrectImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectImBuf(struct ImBuf *ibuf);
bool imb_addrectfloatImBuf(struct ImBuf *ibuf);
+/**
+ * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request.
+ */
void imb_freerectfloatImBuf(struct ImBuf *ibuf);
void imb_freemipmapImBuf(struct ImBuf *ibuf);
bool imb_addtilesImBuf(struct ImBuf *ibuf);
void imb_freetilesImBuf(struct ImBuf *ibuf);
+/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(struct ImBuf *ibuf);
-/* threaded processors */
+/**
+ * Threaded processors.
+ */
void IMB_processor_apply_threaded(
int buffer_lines,
int handle_size,
@@ -756,13 +896,48 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines,
ScanlineThreadFunc do_thread,
void *custom_data);
-void IMB_transform(struct ImBuf *src,
+/**
+ * \brief Transform modes to use for IMB_transform function.
+ *
+ * These are not flags as the combination of cropping and repeat can lead to different expectation.
+ */
+typedef enum eIMBTransformMode {
+ /** \brief Do not crop or repeat. */
+ IMB_TRANSFORM_MODE_REGULAR = 0,
+ /** \brief Crop the source buffer. */
+ IMB_TRANSFORM_MODE_CROP_SRC = 1,
+ /** \brief Wrap repeat the source buffer. Only supported in with nearest filtering. */
+ IMB_TRANSFORM_MODE_WRAP_REPEAT = 2,
+} eIMBTransformMode;
+
+/**
+ * \brief Transform source image buffer onto destination image buffer using a transform matrix.
+ *
+ * \param src Image buffer to read from.
+ * \param dst Image buffer to write to. rect or rect_float must already be initialized.
+ * - dst buffer must be a 4 channel buffers.
+ * - Only one data type buffer will be used (rect_float has priority over rect)
+ * \param mode Cropping/Wrap repeat effect to apply during transformation.
+ * \param filter Interpolation to use during sampling.
+ * \param transform_matrix Transformation matrix to use.
+ * The given matrix should transform between dst pixel space to src pixel space.
+ * One unit is one pixel.
+ * \param src_crop cropping region how to crop the source buffer. Should only be passed when mode
+ * is set to #IMB_TRANSFORM_MODE_CROP_SRC. For any other mode this should be empty.
+ *
+ * During transformation no data/color conversion will happens.
+ * When transforming between float images the number of channels of the source buffer may be
+ * between 1 and 4. When source buffer has one channel the data will be read as a gray scale value.
+ */
+void IMB_transform(const struct ImBuf *src,
struct ImBuf *dst,
- float transform_matrix[3][3],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter);
+ eIMBTransformMode mode,
+ eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop);
+
+/* FFMPEG */
-/* ffmpeg */
void IMB_ffmpeg_init(void);
const char *IMB_ffmpeg_last_error(void);
@@ -775,8 +950,17 @@ struct GPUTexture *IMB_create_gpu_texture(const char *name,
bool use_high_bitdepth,
bool use_premult,
bool limit_gl_texture_size);
+/**
+ * The `ibuf` is only here to detect the storage type. The produced texture will have undefined
+ * content. It will need to be populated by using #IMB_update_gpu_texture_sub().
+ */
struct GPUTexture *IMB_touch_gpu_texture(
const char *name, struct ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth);
+/**
+ * Will update a #GPUTexture using the content of the #ImBuf. Only one layer will be updated.
+ * Will resize the ibuf if needed.
+ * Z is the layer to update. Unused if the texture is 2D.
+ */
void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
struct ImBuf *ibuf,
int x,
@@ -788,36 +972,33 @@ void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
bool use_premult);
/**
- *
* \attention defined in stereoimbuf.c
*/
-void IMB_stereo3d_write_dimensions(const char mode,
- const bool is_squeezed,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
-void IMB_stereo3d_read_dimensions(const char mode,
- const bool is_squeezed,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
+void IMB_stereo3d_write_dimensions(
+ char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
+void IMB_stereo3d_read_dimensions(
+ char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
int *IMB_stereo3d_from_rect(struct ImageFormatData *im_format,
- const size_t x,
- const size_t y,
- const size_t channels,
+ size_t x,
+ size_t y,
+ size_t channels,
int *rect_left,
int *rect_right);
float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format,
- const size_t x,
- const size_t y,
- const size_t channels,
+ size_t x,
+ size_t y,
+ size_t channels,
float *rectf_left,
float *rectf_right);
+/**
+ * Left/right are always float.
+ */
struct ImBuf *IMB_stereo3d_ImBuf(struct ImageFormatData *im_format,
struct ImBuf *ibuf_left,
struct ImBuf *ibuf_right);
+/**
+ * Reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right).
+ */
void IMB_ImBufFromStereo3d(struct Stereo3dFormat *s3d,
struct ImBuf *ibuf_stereo,
struct ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 9697064b445..58148743b7e 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -143,10 +143,9 @@ typedef struct ImbFormatOptions {
char quality;
} ImbFormatOptions;
-/**
- * \name Imbuf Component flags
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Component flags
* \brief These flags determine the components of an ImBuf struct.
- *
* \{ */
typedef enum eImBufFlags {
@@ -175,6 +174,11 @@ typedef enum eImBufFlags {
} eImBufFlags;
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Buffer
+ * \{ */
+
typedef struct ImBuf {
struct ImBuf *next, *prev; /** < allow lists of #ImBufs, for caches or flip-books. */
@@ -301,11 +305,14 @@ enum {
IB_PERSISTENT = (1 << 5),
};
-/**
- * \name Imbuf preset profile tags
- * \brief Some predefined color space profiles that 8 bit imbufs can represent
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Preset Profile Tags
*
+ * \brief Some predefined color space profiles that 8 bit imbufs can represent.
* \{ */
+
#define IB_PROFILE_NONE 0
#define IB_PROFILE_LINEAR_RGB 1
#define IB_PROFILE_SRGB 2
@@ -322,7 +329,7 @@ enum {
# endif /* DDS_MAKEFOURCC */
/*
- * FOURCC codes for DX compressed-texture pixel formats
+ * FOURCC codes for DX compressed-texture pixel formats.
*/
# define FOURCC_DDS (DDS_MAKEFOURCC('D', 'D', 'S', ' '))
@@ -337,13 +344,13 @@ extern const char *imb_ext_image[];
extern const char *imb_ext_movie[];
extern const char *imb_ext_audio[];
-/* image formats that can only be loaded via filepath */
+/** Image formats that can only be loaded via filepath. */
extern const char *imb_ext_image_filepath_only[];
-/**
- * \name Imbuf Color Management Flag
- * \brief Used with #ImBuf.colormanage_flag
+/* -------------------------------------------------------------------- */
+/** \name Imbuf Color Management Flag
*
+ * \brief Used with #ImBuf.colormanage_flag
* \{ */
enum {
diff --git a/source/blender/imbuf/IMB_metadata.h b/source/blender/imbuf/IMB_metadata.h
index 652ce913ee5..50982d08c3e 100644
--- a/source/blender/imbuf/IMB_metadata.h
+++ b/source/blender/imbuf/IMB_metadata.h
@@ -58,10 +58,7 @@ void IMB_metadata_free(struct IDProperty *metadata);
* \param len: length of value buffer allocated by user.
* \return 1 (true) if metadata is present and value for the key found, 0 (false) otherwise.
*/
-bool IMB_metadata_get_field(struct IDProperty *metadata,
- const char *key,
- char *value,
- const size_t len);
+bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *value, size_t len);
/**
* Set user data in the metadata.
diff --git a/source/blender/imbuf/IMB_moviecache.h b/source/blender/imbuf/IMB_moviecache.h
index 8e5f15a64a0..156a060c621 100644
--- a/source/blender/imbuf/IMB_moviecache.h
+++ b/source/blender/imbuf/IMB_moviecache.h
@@ -59,7 +59,7 @@ void IMB_moviecache_set_priority_callback(struct MovieCache *cache,
void IMB_moviecache_put(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
bool IMB_moviecache_put_if_possible(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
-struct ImBuf *IMB_moviecache_get(struct MovieCache *cache, void *userkey);
+struct ImBuf *IMB_moviecache_get(struct MovieCache *cache, void *userkey, bool *r_is_cached_empty);
void IMB_moviecache_remove(struct MovieCache *cache, void *userkey);
bool IMB_moviecache_has_frame(struct MovieCache *cache, void *userkey);
void IMB_moviecache_free(struct MovieCache *cache);
@@ -70,6 +70,9 @@ void IMB_moviecache_cleanup(struct MovieCache *cache,
void *userdata),
void *userdata);
+/**
+ * Get segments of cached frames. Useful for debugging cache policies.
+ */
void IMB_moviecache_get_cache_segments(
struct MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points);
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index e1a315a0bd2..6a739002fb3 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -48,47 +48,66 @@ typedef enum ThumbSource {
THB_SOURCE_FONT,
} ThumbSource;
-/* don't generate thumbs for images bigger than this (100mb) */
+/**
+ * Don't generate thumbs for images bigger than this (100mb).
+ */
#define THUMB_SIZE_MAX (100 * 1024 * 1024)
#define PREVIEW_RENDER_DEFAULT_HEIGHT 128
#define PREVIEW_RENDER_LARGE_HEIGHT 256
-/* Note this can also be used as versioning system,
+/**
+ * Note this can also be used as versioning system,
* to force refreshing all thumbnails if e.g. we change some thumb generating code or so.
- * Only used by fonts so far. */
+ * Only used by fonts so far.
+ */
#define THUMB_DEFAULT_HASH "00000000000000000000000000000000"
-/* create thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Create thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_create(const char *path,
ThumbSize size,
ThumbSource source,
struct ImBuf *img);
-/* read thumbnail for file and returns new imbuf for thumbnail */
+/**
+ * Read thumbnail for file and returns new imbuf for thumbnail.
+ */
struct ImBuf *IMB_thumb_read(const char *path, ThumbSize size);
-/* delete all thumbs for the file */
+/**
+ * Delete all thumbs for the file.
+ */
void IMB_thumb_delete(const char *path, ThumbSize size);
-/* return the state of the thumb, needed to determine how to manage the thumb */
+/**
+ * Create the thumb if necessary and manage failed and old thumbs.
+ */
struct ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source);
-/* create the necessary dirs to store the thumbnails */
+/**
+ * Create the necessary dirs to store the thumbnails.
+ */
void IMB_thumb_makedirs(void);
-/* special function for loading a thumbnail embedded into a blend file */
+/**
+ * Special function for loading a thumbnail embedded into a blend file.
+ */
struct ImBuf *IMB_thumb_load_blend(const char *blen_path,
const char *blen_group,
const char *blen_id);
-/* special function for previewing fonts */
+/**
+ * Special function for previewing fonts.
+ */
struct ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
bool IMB_thumb_load_font_get_hash(char *r_hash);
void IMB_thumb_clear_translations(void);
void IMB_thumb_ensure_translations(void);
/* Threading */
+
void IMB_thumb_locks_acquire(void);
void IMB_thumb_locks_release(void);
void IMB_thumb_path_lock(const char *path);
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index c8f6135f330..bf6aef3ecd3 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -22,7 +22,9 @@
#include "IMB_imbuf.h"
-/* Generic File Type */
+/* -------------------------------------------------------------------- */
+/** \name Generic File Type
+ * \{ */
struct ImBuf;
@@ -39,7 +41,7 @@ typedef struct ImFileType {
* \note that this may only read in a small part of the files header,
* see: #IMB_ispic_type for details.
*/
- bool (*is_a)(const unsigned char *buf, const size_t size);
+ bool (*is_a)(const unsigned char *buf, size_t size);
/** Load an image from memory. */
struct ImBuf *(*load)(const unsigned char *mem,
@@ -78,36 +80,62 @@ void imb_tile_cache_init(void);
void imb_tile_cache_exit(void);
void imb_loadtile(struct ImBuf *ibuf, int tx, int ty, unsigned int *rect);
+/**
+ * External free.
+ */
void imb_tile_cache_tile_free(struct ImBuf *ibuf, int tx, int ty);
+/** \} */
+
/* Type Specific Functions */
-/* png */
-bool imb_is_a_png(const unsigned char *mem, const size_t size);
+/* -------------------------------------------------------------------- */
+/** \name Format: PNG (#IMB_FTYPE_PNG)
+ * \{ */
+
+bool imb_is_a_png(const unsigned char *mem, size_t size);
struct ImBuf *imb_loadpng(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags);
-/* targa */
-bool imb_is_a_targa(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TARGA (#IMB_FTYPE_TGA)
+ * \{ */
+
+bool imb_is_a_targa(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadtarga(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int flags);
-/* iris */
-bool imb_is_a_iris(const unsigned char *mem, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: IRIS (#IMB_FTYPE_IMAGIC)
+ * \{ */
+
+bool imb_is_a_iris(const unsigned char *mem, size_t size);
+/**
+ * Read in a B/W RGB or RGBA iris image file and return an image buffer.
+ */
struct ImBuf *imb_loadiris(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jp2 */
-bool imb_is_a_jp2(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JP2 (#IMB_FTYPE_JP2)
+ * \{ */
+
+bool imb_is_a_jp2(const unsigned char *buf, size_t size);
struct ImBuf *imb_load_jp2(const unsigned char *mem,
size_t size,
int flags,
@@ -117,53 +145,110 @@ struct ImBuf *imb_load_jp2_filepath(const char *filepath,
char colorspace[IM_MAX_SPACE]);
bool imb_save_jp2(struct ImBuf *ibuf, const char *filepath, int flags);
-/* jpeg */
-bool imb_is_a_jpeg(const unsigned char *mem, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: JPEG (#IMB_FTYPE_JPG)
+ * \{ */
+
+bool imb_is_a_jpeg(const unsigned char *mem, size_t size);
bool imb_savejpeg(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* bmp */
-bool imb_is_a_bmp(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: BMP (#IMB_FTYPE_BMP)
+ * \{ */
+
+bool imb_is_a_bmp(const unsigned char *buf, size_t size);
struct ImBuf *imb_bmp_decode(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
+/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(struct ImBuf *ibuf, const char *filepath, int flags);
-/* cineon */
-bool imb_is_a_cineon(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: CINEON (#IMB_FTYPE_CINEON)
+ * \{ */
+
+bool imb_is_a_cineon(const unsigned char *buf, size_t size);
bool imb_save_cineon(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_cineon(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* dpx */
-bool imb_is_a_dpx(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: DPX (#IMB_FTYPE_DPX)
+ * \{ */
+
+bool imb_is_a_dpx(const unsigned char *buf, size_t size);
bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_dpx(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
-/* hdr */
-bool imb_is_a_hdr(const unsigned char *buf, const size_t size);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: HDR (#IMB_FTYPE_RADHDR)
+ * \{ */
+
+bool imb_is_a_hdr(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadhdr(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags);
-/* tiff */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TIFF (#IMB_FTYPE_TIF)
+ * \{ */
+
void imb_inittiff(void);
-bool imb_is_a_tiff(const unsigned char *buf, const size_t size);
+bool imb_is_a_tiff(const unsigned char *buf, size_t size);
+/**
+ * Loads a TIFF file.
+ * \param mem: Memory containing the TIFF file.
+ * \param size: Size of the mem buffer.
+ * \param flags: If flags has IB_test set then the file is not actually loaded,
+ * but all other operations take place.
+ *
+ * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
+ */
struct ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
void imb_loadtiletiff(
struct ImBuf *ibuf, const unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect);
+/**
+ * Saves a TIFF file.
+ *
+ * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
+ * respectively) are accepted, and interpreted correctly. Note that the TIFF
+ * convention is to use pre-multiplied alpha, which can be achieved within
+ * Blender by setting "Premul" alpha handling. Other alpha conventions are
+ * not strictly correct, but are permitted anyhow.
+ *
+ * \param ibuf: Image buffer.
+ * \param filepath: Name of the TIFF file to create.
+ * \param flags: Currently largely ignored.
+ *
+ * \return 1 if the function is successful, 0 on failure.
+ */
bool imb_savetiff(struct ImBuf *ibuf, const char *filepath, int flags);
+
+/** \} */
diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h
index 556362d78c1..434750e6736 100644
--- a/source/blender/imbuf/intern/IMB_filter.h
+++ b/source/blender/imbuf/intern/IMB_filter.h
@@ -34,4 +34,7 @@ void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h);
void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h);
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h);
+/**
+ * Result in ibuf2, scaling should be done correctly.
+ */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1);
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 1369f8cc0f8..197d7e6b1d5 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -93,7 +93,6 @@ void imb_freemipmapImBuf(ImBuf *ibuf)
ibuf->miptot = 0;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectfloatImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -111,7 +110,6 @@ void imb_freerectfloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_rectfloat;
}
-/* any free rect frees mipmaps to be sure, creation is in render on first request */
void imb_freerectImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) {
@@ -197,7 +195,6 @@ void IMB_freezbuffloatImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_zbuffloat;
}
-/** Free all pixel data (associated with image size). */
void imb_freerectImbuf_all(ImBuf *ibuf)
{
imb_freerectImBuf(ibuf);
@@ -403,9 +400,10 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf)
return false;
}
-/* question; why also add zbuf? */
bool imb_addrectImBuf(ImBuf *ibuf)
{
+ /* Question; why also add ZBUF (when `planes > 32`)? */
+
if (ibuf == NULL) {
return false;
}
@@ -430,9 +428,6 @@ bool imb_addrectImBuf(ImBuf *ibuf)
return false;
}
-/**
- * \param take_ownership: When true, the buffers become owned by the resulting image.
- */
struct ImBuf *IMB_allocFromBufferOwn(
unsigned int *rect, float *rectf, unsigned int w, unsigned int h, unsigned int channels)
{
@@ -580,7 +575,6 @@ bool IMB_initImBuf(
return true;
}
-/* does no zbuffers? */
ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
{
ImBuf *ibuf2, tbuf;
@@ -669,6 +663,11 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
return ibuf2;
}
+size_t IMB_get_rect_len(const ImBuf *ibuf)
+{
+ return (size_t)ibuf->x * (size_t)ibuf->y;
+}
+
size_t IMB_get_size_in_memory(ImBuf *ibuf)
{
int a;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 13f9356751e..17e82fc79c9 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -58,6 +58,8 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "DNA_scene_types.h"
+
#include "MEM_guardedalloc.h"
#ifdef WITH_AVI
@@ -502,11 +504,6 @@ static ImBuf *avi_fetchibuf(struct anim *anim, int position)
#ifdef WITH_FFMPEG
-BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
-{
- return (anim->x & 31) != 0;
-}
-
static int startffmpeg(struct anim *anim)
{
int i, video_stream_index;
@@ -705,23 +702,20 @@ static int startffmpeg(struct anim *anim)
anim->pFrameComplete = false;
anim->pFrameDeinterlaced = av_frame_alloc();
anim->pFrameRGB = av_frame_alloc();
+ anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
+ anim->pFrameRGB->width = anim->x;
+ anim->pFrameRGB->height = anim->y;
- if (need_aligned_ffmpeg_buffer(anim)) {
- anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
- anim->pFrameRGB->width = anim->x;
- anim->pFrameRGB->height = anim->y;
-
- if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) {
- fprintf(stderr, "Could not allocate frame data.\n");
- avcodec_free_context(&anim->pCodecCtx);
- avformat_close_input(&anim->pFormatCtx);
- av_packet_free(&anim->cur_packet);
- av_frame_free(&anim->pFrameRGB);
- av_frame_free(&anim->pFrameDeinterlaced);
- av_frame_free(&anim->pFrame);
- anim->pCodecCtx = NULL;
- return -1;
- }
+ if (av_frame_get_buffer(anim->pFrameRGB, 0) < 0) {
+ fprintf(stderr, "Could not allocate frame data.\n");
+ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
+ av_packet_free(&anim->cur_packet);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
+ anim->pCodecCtx = NULL;
+ return -1;
}
if (av_image_get_buffer_size(AV_PIX_FMT_RGBA, anim->x, anim->y, 1) != anim->x * anim->y * 4) {
@@ -849,104 +843,61 @@ static void ffmpeg_postprocess(struct anim *anim)
}
}
- if (!need_aligned_ffmpeg_buffer(anim)) {
- av_image_fill_arrays(anim->pFrameRGB->data,
- anim->pFrameRGB->linesize,
- (unsigned char *)ibuf->rect,
- AV_PIX_FMT_RGBA,
- anim->x,
- anim->y,
- 1);
- }
-
-# if defined(__x86_64__) || defined(_M_X64)
- /* Scale and flip image over Y axis in one go, using negative strides.
- * This doesn't work with ARM/PowerPC though and may be misusing the API.
- * Limit it x86_64 where it appears to work.
- * http://trac.ffmpeg.org/ticket/9060 */
- int *dstStride = anim->pFrameRGB->linesize;
- uint8_t **dst = anim->pFrameRGB->data;
- const int dstStride2[4] = {-dstStride[0], 0, 0, 0};
- uint8_t *dst2[4] = {dst[0] + (anim->y - 1) * dstStride[0], 0, 0, 0};
-
- sws_scale(anim->img_convert_ctx,
- (const uint8_t *const *)input->data,
- input->linesize,
- 0,
- anim->y,
- dst2,
- dstStride2);
-# else
- /* Scale with swscale then flip image over Y axis. */
- int *dstStride = anim->pFrameRGB->linesize;
- uint8_t **dst = anim->pFrameRGB->data;
- const int dstStride2[4] = {dstStride[0], 0, 0, 0};
- uint8_t *dst2[4] = {dst[0], 0, 0, 0};
- int x, y, h, w;
- unsigned char *bottom;
- unsigned char *top;
-
sws_scale(anim->img_convert_ctx,
(const uint8_t *const *)input->data,
input->linesize,
0,
anim->y,
- dst2,
- dstStride2);
-
- bottom = (unsigned char *)ibuf->rect;
- top = bottom + ibuf->x * (ibuf->y - 1) * 4;
-
- h = (ibuf->y + 1) / 2;
- w = ibuf->x;
-
- for (y = 0; y < h; y++) {
- unsigned char tmp[4];
- unsigned int *tmp_l = (unsigned int *)tmp;
-
- for (x = 0; x < w; x++) {
- tmp[0] = bottom[0];
- tmp[1] = bottom[1];
- tmp[2] = bottom[2];
- tmp[3] = bottom[3];
-
- bottom[0] = top[0];
- bottom[1] = top[1];
- bottom[2] = top[2];
- bottom[3] = top[3];
-
- *(unsigned int *)top = *tmp_l;
-
- bottom += 4;
- top += 4;
- }
- top -= 8 * w;
+ anim->pFrameRGB->data,
+ anim->pFrameRGB->linesize);
+
+ /* Copy the valid bytes from the aligned buffer vertically flipped into ImBuf */
+ int aligned_stride = anim->pFrameRGB->linesize[0];
+ const uint8_t *const src[4] = {
+ anim->pFrameRGB->data[0] + (anim->y - 1) * aligned_stride, 0, 0, 0};
+ /* NOTE: Negative linesize is used to copy and flip image at once with function
+ * `av_image_copy_to_buffer`. This could cause issues in future and image may need to be flipped
+ * explicitly. */
+ const int src_linesize[4] = {-anim->pFrameRGB->linesize[0], 0, 0, 0};
+ int dst_size = av_image_get_buffer_size(
+ anim->pFrameRGB->format, anim->pFrameRGB->width, anim->pFrameRGB->height, 1);
+ av_image_copy_to_buffer(
+ (uint8_t *)ibuf->rect, dst_size, src, src_linesize, AV_PIX_FMT_RGBA, anim->x, anim->y, 1);
+ if (filter_y) {
+ IMB_filtery(ibuf);
}
-# endif
+}
- if (need_aligned_ffmpeg_buffer(anim)) {
- uint8_t *buf_src = anim->pFrameRGB->data[0];
- uint8_t *buf_dst = (uint8_t *)ibuf->rect;
- for (int y = 0; y < anim->y; y++) {
- memcpy(buf_dst, buf_src, anim->x * 4);
- buf_dst += anim->x * 4;
- buf_src += anim->pFrameRGB->linesize[0];
- }
- }
+static void ffmpeg_decode_store_frame_pts(struct anim *anim)
+{
+ anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
- if (filter_y) {
- IMB_filtery(ibuf);
+ if (anim->pFrame->key_frame) {
+ anim->cur_key_frame_pts = anim->cur_pts;
}
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
+ (int64_t)anim->cur_pts);
}
/* decode one video frame also considering the packet read into cur_packet */
-
static int ffmpeg_decode_video_frame(struct anim *anim)
{
- int rval = 0;
-
av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
+ /* Sometimes, decoder returns more than one frame per sent packet. Check if frames are available.
+ * This frames must be read, otherwise decoding will fail. See T91405. */
+ anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
+ if (anim->pFrameComplete) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE FROM CODEC BUFFER\n");
+ ffmpeg_decode_store_frame_pts(anim);
+ return 1;
+ }
+
+ int rval = 0;
if (anim->cur_packet->stream_index == anim->videoStream) {
av_packet_unref(anim->cur_packet);
anim->cur_packet->stream_index = -1;
@@ -963,22 +914,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
(anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts,
(anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : "");
if (anim->cur_packet->stream_index == anim->videoStream) {
- anim->pFrameComplete = 0;
-
avcodec_send_packet(anim->pCodecCtx, anim->cur_packet);
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
-
- if (anim->pFrame->key_frame) {
- anim->cur_key_frame_pts = anim->cur_pts;
- }
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
- (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
- (int64_t)anim->cur_pts);
+ ffmpeg_decode_store_frame_pts(anim);
break;
}
}
@@ -988,22 +928,11 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
if (rval == AVERROR_EOF) {
/* Flush any remaining frames out of the decoder. */
- anim->pFrameComplete = 0;
-
avcodec_send_packet(anim->pCodecCtx, NULL);
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
-
- if (anim->pFrame->key_frame) {
- anim->cur_key_frame_pts = anim->cur_pts;
- }
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- " FRAME DONE (after EOF): cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
- (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
- (int64_t)anim->cur_pts);
+ ffmpeg_decode_store_frame_pts(anim);
rval = 0;
}
}
@@ -1443,7 +1372,15 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
*
* The issue was reported to FFmpeg under ticket #8747 in the FFmpeg tracker
* and is fixed in the newer versions than 4.3.1. */
- anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, 32, 0);
+
+ const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt);
+
+ int planes = R_IMF_PLANES_RGBA;
+ if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) {
+ planes = R_IMF_PLANES_RGB;
+ }
+
+ anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, planes, 0);
anim->cur_frame_final->rect = MEM_mallocN_aligned(
(size_t)4 * anim->x * anim->y, 32, "ffmpeg ibuf");
anim->cur_frame_final->mall |= IB_rect;
@@ -1471,20 +1408,6 @@ static void free_anim_ffmpeg(struct anim *anim)
av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrame);
-
- if (!need_aligned_ffmpeg_buffer(anim)) {
- /* If there's no need for own aligned buffer it means that FFmpeg's
- * frame shares the same buffer as temporary ImBuf. In this case we
- * should not free the buffer when freeing the FFmpeg buffer.
- */
- av_image_fill_arrays(anim->pFrameRGB->data,
- anim->pFrameRGB->linesize,
- NULL,
- AV_PIX_FMT_RGBA,
- anim->x,
- anim->y,
- 1);
- }
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
@@ -1496,16 +1419,16 @@ static void free_anim_ffmpeg(struct anim *anim)
#endif
-/* Try next picture to read */
-/* No picture, try to open next animation */
-/* Succeed, remove first image from animation */
-
-static ImBuf *anim_getnew(struct anim *anim)
+/**
+ * Try to initialize the #anim struct.
+ * Returns true on success.
+ */
+static bool anim_getnew(struct anim *anim)
{
- struct ImBuf *ibuf = NULL;
-
+ BLI_assert(anim->curtype == ANIM_NONE);
if (anim == NULL) {
- return NULL;
+ /* Nothing to initialize. */
+ return false;
}
free_anim_movie(anim);
@@ -1518,44 +1441,43 @@ static ImBuf *anim_getnew(struct anim *anim)
free_anim_ffmpeg(anim);
#endif
- if (anim->curtype != 0) {
- return NULL;
- }
anim->curtype = imb_get_anim_type(anim->name);
switch (anim->curtype) {
- case ANIM_SEQUENCE:
- ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
+ case ANIM_SEQUENCE: {
+ ImBuf *ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
if (ibuf) {
BLI_strncpy(anim->first, anim->name, sizeof(anim->first));
anim->duration_in_frames = 1;
+ IMB_freeImBuf(ibuf);
+ }
+ else {
+ return false;
}
break;
+ }
case ANIM_MOVIE:
if (startmovie(anim)) {
- return NULL;
+ return false;
}
- ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0); /* fake */
break;
#ifdef WITH_AVI
case ANIM_AVI:
if (startavi(anim)) {
printf("couldn't start avi\n");
- return NULL;
+ return false;
}
- ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
break;
#endif
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
if (startffmpeg(anim)) {
- return 0;
+ return false;
}
- ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
break;
#endif
}
- return ibuf;
+ return true;
}
struct ImBuf *IMB_anim_previewframe(struct anim *anim)
@@ -1589,14 +1511,10 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
filter_y = (anim->ib_flags & IB_animdeinterlace);
if (preview_size == IMB_PROXY_NONE) {
- if (anim->curtype == 0) {
- ibuf = anim_getnew(anim);
- if (ibuf == NULL) {
+ if (anim->curtype == ANIM_NONE) {
+ if (!anim_getnew(anim)) {
return NULL;
}
-
- IMB_freeImBuf(ibuf); /* ???? */
- ibuf = NULL;
}
if (position < 0) {
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index 70bb70ec4fa..b44b12999bf 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -151,8 +151,7 @@ ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[
}
/* Validate and cross-check offsets and sizes. */
- if (x < 1 ||
- !(depth == 1 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32)) {
+ if (x < 1 || !(ELEM(depth, 1, 4, 8, 16, 24, 32))) {
return NULL;
}
@@ -307,7 +306,6 @@ static int putShortLSB(ushort us, FILE *ofile)
return putc((us >> 8) & 0xFF, ofile);
}
-/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
{
BMPINFOHEADER infoheader;
diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c
index 02d1fe3710a..ce11e1c3f80 100644
--- a/source/blender/imbuf/intern/cache.c
+++ b/source/blender/imbuf/intern/cache.c
@@ -153,7 +153,6 @@ static void imb_global_cache_tile_unload(ImGlobalTile *gtile)
GLOBAL_CACHE.totmem -= sizeof(unsigned int) * ibuf->tilex * ibuf->tiley;
}
-/* external free */
void imb_tile_cache_tile_free(ImBuf *ibuf, int tx, int ty)
{
ImGlobalTile *gtile, lookuptile;
@@ -248,7 +247,6 @@ void imb_tile_cache_exit(void)
}
}
-/* presumed to be called when no threads are running */
void IMB_tile_cache_params(int totthread, int maxmem)
{
int a;
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index 1223033f535..758b21f8cda 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -239,13 +239,13 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
}
if (cineon->depth == 1) {
- /* Grayscale image */
+ /* Gray-scale image. */
cineon->element[0].descriptor = descriptor_Luminance;
cineon->element[0].transfer = transfer_Linear;
cineon->element[0].depth = 1;
}
else if (cineon->depth == 3) {
- /* RGB image */
+ /* RGB image. */
if (cineon->numElements == 1) {
cineon->element[0].descriptor = descriptor_RGB;
cineon->element[0].transfer = transfer_PrintingDensity;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 119ef3ff971..6e9e5dd3ddb 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -342,7 +342,7 @@ static ImBuf *colormanage_cache_get_ibuf(ImBuf *ibuf,
*cache_handle = NULL;
- cache_ibuf = IMB_moviecache_get(moviecache, key);
+ cache_ibuf = IMB_moviecache_get(moviecache, key, NULL);
*cache_handle = cache_ibuf;
@@ -1968,7 +1968,6 @@ static void colormanagement_transform_ex(unsigned char *byte_buffer,
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert the whole buffer from specified by name color space to another */
void IMB_colormanagement_transform(float *buffer,
int width,
int height,
@@ -1981,9 +1980,6 @@ void IMB_colormanagement_transform(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
}
-/* convert the whole buffer from specified by name color space to another
- * will do threaded conversion
- */
void IMB_colormanagement_transform_threaded(float *buffer,
int width,
int height,
@@ -1996,7 +1992,6 @@ void IMB_colormanagement_transform_threaded(float *buffer,
NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
}
-/* Similar to functions above, but operates on byte buffer. */
void IMB_colormanagement_transform_byte(unsigned char *buffer,
int width,
int height,
@@ -2018,7 +2013,6 @@ void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer,
buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
}
-/* Similar to above, but gets float buffer from display one. */
void IMB_colormanagement_transform_from_byte(float *float_buffer,
unsigned char *byte_buffer,
int width,
@@ -2098,9 +2092,6 @@ void IMB_colormanagement_transform_v4(float pixel[4],
IMB_colormanagement_processor_free(cm_processor);
}
-/* convert pixel from specified by descriptor color space to scene linear
- * used by performance-critical areas such as renderer and baker
- */
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2118,7 +2109,6 @@ void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpac
}
}
-/* same as above, but converts colors in opposite direction */
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
{
OCIO_ConstCPUProcessorRcPtr *processor;
@@ -2315,14 +2305,6 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
}
}
-/* Conversion between color picking role. Typically we would expect such a
- * requirements:
- * - It is approximately perceptually linear, so that the HSV numbers and
- * the HSV cube/circle have an intuitive distribution.
- * - It has the same gamut as the scene linear color space.
- * - Color picking values 0..1 map to scene linear values in the 0..1 range,
- * so that picked albedo values are energy conserving.
- */
void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3])
{
if (!global_color_picking_state.cpu_processor_to && !global_color_picking_state.failed) {
@@ -2377,8 +2359,6 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
}
}
-/* Conversion between sRGB, for rare cases like hex color or copy/pasting
- * between UI theme and scene linear colors. */
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
{
mul_m3_v3(imbuf_rgb_to_xyz, pixel);
@@ -2393,10 +2373,6 @@ void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
mul_m3_v3(imbuf_xyz_to_rgb, pixel);
}
-/* convert pixel from scene linear to display space using default view
- * used by performance-critical areas such as color-related widgets where we want to reduce
- * amount of per-widget allocations
- */
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
@@ -2406,7 +2382,6 @@ void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManaged
}
}
-/* same as above, but converts color in opposite direction */
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
{
OCIO_ConstCPUProcessorRcPtr *processor = display_to_scene_linear_processor(display);
@@ -2468,17 +2443,6 @@ void IMB_colormanagement_imbuf_make_display_space(
colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
}
-/* prepare image buffer to be saved on disk, applying color management if needed
- * color management would be applied if image is saving as render result and if
- * file format is not expecting float buffer to be in linear space (currently
- * JPEG2000 and TIFF are such formats -- they're storing image as float but
- * file itself stores applied color space).
- *
- * Both byte and float buffers would contain applied color space, and result's
- * float_colorspace would be set to display color space. This should be checked
- * in image format write callback and if float_colorspace is not NULL, no color
- * space transformation should be applied on this buffer.
- */
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
@@ -2640,7 +2604,6 @@ void IMB_colormanagement_buffer_make_display_space(
/** \name Public Display Buffers Interfaces
* \{ */
-/* acquire display buffer for given image buffer using specified view and display settings */
unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -2738,7 +2701,6 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
return display_buffer;
}
-/* same as IMB_display_buffer_acquire but gets view and display settings from context */
unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
{
ColorManagedViewSettings *view_settings;
@@ -2899,7 +2861,6 @@ const char *IMB_colormanagement_display_get_default_name(void)
return display->name;
}
-/* used by performance-critical pixel processing areas, such as color widgets */
ColorManagedDisplay *IMB_colormanagement_display_get_named(const char *name)
{
return colormanage_display_get_named(name);
@@ -4027,19 +3988,6 @@ bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSE
return OCIO_supportGPUShader();
}
-/**
- * Configures GLSL shader for conversion from specified to
- * display color space
- *
- * Will create appropriate OCIO processor and setup GLSL shader,
- * so further 2D texture usage will use this conversion.
- *
- * When there's no need to apply transform on 2D textures, use
- * IMB_colormanagement_finish_glsl_draw().
- *
- * This is low-level function, use ED_draw_imbuf_ctx if you
- * only need to display given image buffer
- */
bool IMB_colormanagement_setup_glsl_draw_from_space(
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
@@ -4097,7 +4045,6 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
return global_gpu_state.gpu_shader_bound;
}
-/* Configures GLSL shader for conversion from scene linear to display space */
bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
float dither,
@@ -4107,10 +4054,6 @@ bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_se
view_settings, display_settings, NULL, dither, predivide, false);
}
-/**
- * Same as setup_glsl_draw_from_space,
- * but color management settings are guessing from a given context.
- */
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
struct ColorSpace *from_colorspace,
float dither,
@@ -4125,13 +4068,11 @@ bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C,
view_settings, display_settings, from_colorspace, dither, predivide, false);
}
-/* Same as setup_glsl_draw, but color management settings are guessing from a given context */
bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
{
return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, dither, predivide);
}
-/* Finish GLSL-based display space conversion */
void IMB_colormanagement_finish_glsl_draw(void)
{
if (global_gpu_state.gpu_shader_bound) {
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index c304ad8d8e5..6e57a8cc1b2 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -27,23 +27,11 @@
#include "BLI_math_vector.h"
#include "IMB_colormanagement_intern.h"
-/* Convert a float RGB triplet to the correct luminance weighted average.
- *
- * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
- * based on the luminance positions of the red, green, and blue primaries.
- * Given that the internal reference space may be arbitrarily set, any
- * effort to glean the luminance coefficients must be aware of the reference
- * space primaries.
- *
- * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
- */
-
float IMB_colormanagement_get_luminance(const float rgb[3])
{
return dot_v3v3(imbuf_luma_coefficients, rgb);
}
-/* Byte equivalent of IMB_colormanagement_get_luminance(). */
unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
{
float rgbf[3];
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp
index 4e4fca864a0..e471b6834ae 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.cpp
+++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp
@@ -158,7 +158,6 @@ uint BlockDXT1::evaluatePaletteNV5x(Color32 color_array[4]) const
return 3;
}
-/* Evaluate palette assuming 3 color block. */
void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -184,7 +183,6 @@ void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
color_array[3].a = 0x00;
}
-/* Evaluate palette assuming 4 color block. */
void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
@@ -247,14 +245,12 @@ void BlockDXT1::setIndices(const int *idx)
}
}
-/** Flip DXT1 block vertically. */
inline void BlockDXT1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT1 block vertically. */
inline void BlockDXT1::flip2()
{
swap(row[0], row[1]);
@@ -299,27 +295,23 @@ void AlphaBlockDXT3::decodeBlock(ColorBlock *block) const
block->color(0xF).a = (alphaF << 4) | alphaF;
}
-/** Flip DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half DXT3 alpha block vertically. */
void AlphaBlockDXT3::flip2()
{
swap(row[0], row[1]);
}
-/** Flip DXT3 block vertically. */
void BlockDXT3::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT3 block vertically. */
void BlockDXT3::flip2()
{
alpha.flip2();
@@ -458,21 +450,18 @@ void BlockDXT5::decodeBlockNV5x(ColorBlock *block) const
alpha.decodeBlock(block);
}
-/** Flip DXT5 block vertically. */
void BlockDXT5::flip4()
{
alpha.flip4();
color.flip4();
}
-/** Flip half DXT5 block vertically. */
void BlockDXT5::flip2()
{
alpha.flip2();
color.flip2();
}
-/** Decode ATI1 block. */
void BlockATI1::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -488,19 +477,16 @@ void BlockATI1::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI1 block vertically. */
void BlockATI1::flip4()
{
alpha.flip4();
}
-/** Flip half ATI1 block vertically. */
void BlockATI1::flip2()
{
alpha.flip2();
}
-/** Decode ATI2 block. */
void BlockATI2::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
@@ -525,14 +511,12 @@ void BlockATI2::decodeBlock(ColorBlock *block) const
}
}
-/** Flip ATI2 block vertically. */
void BlockATI2::flip4()
{
x.flip4();
y.flip4();
}
-/** Flip half ATI2 block vertically. */
void BlockATI2::flip2()
{
x.flip2();
@@ -586,14 +570,12 @@ void BlockCTX1::setIndices(const int *idx)
}
}
-/** Flip CTX1 block vertically. */
inline void BlockCTX1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
-/** Flip half CTX1 block vertically. */
inline void BlockCTX1::flip2()
{
swap(row[0], row[1]);
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
index 1fefa7c739d..eb2d5f8726c 100644
--- a/source/blender/imbuf/intern/dds/BlockDXT.h
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -69,7 +69,9 @@ struct BlockDXT1 {
uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePaletteNV5x(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 3 color block. */
void evaluatePalette3(Color32 color_array[4]) const;
+ /** Evaluate palette assuming 4 color block. */
void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock *block) const;
@@ -77,7 +79,9 @@ struct BlockDXT1 {
void setIndices(const int *idx);
+ /** Flip DXT1 block vertically. */
void flip4();
+ /** Flip half DXT1 block vertically. */
void flip2();
};
@@ -113,7 +117,9 @@ struct AlphaBlockDXT3 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip DXT3 alpha block vertically. */
void flip4();
+ /** Flip half DXT3 alpha block vertically. */
void flip2();
};
@@ -125,7 +131,9 @@ struct BlockDXT3 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT3 block vertically. */
void flip4();
+ /** Flip half DXT3 block vertically. */
void flip2();
};
@@ -253,7 +261,9 @@ struct BlockDXT5 {
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
+ /** Flip DXT5 block vertically. */
void flip4();
+ /** Flip half DXT5 block vertically. */
void flip2();
};
@@ -261,9 +271,12 @@ struct BlockDXT5 {
struct BlockATI1 {
AlphaBlockDXT5 alpha;
+ /** Decode ATI1 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI1 block vertically. */
void flip4();
+ /** Flip half ATI1 block vertically. */
void flip2();
};
@@ -272,9 +285,12 @@ struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
+ /** Decode ATI2 block. */
void decodeBlock(ColorBlock *block) const;
+ /** Flip ATI2 block vertically. */
void flip4();
+ /** Flip half ATI2 block vertically. */
void flip2();
};
@@ -292,7 +308,9 @@ struct BlockCTX1 {
void decodeBlock(ColorBlock *block) const;
+ /** Flip CTX1 block vertically. */
void flip4();
+ /** Flip half CTX1 block vertically. */
void flip2();
};
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp
index 6974e0bf99d..0ab98c01f6f 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.cpp
+++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp
@@ -46,7 +46,6 @@ inline static uint colorDistance(Color32 c0, Color32 c1)
}
#endif
-/** Init the color block from an array of colors. */
ColorBlock::ColorBlock(const uint *linearImage)
{
for (uint i = 0; i < 16; i++) {
@@ -54,7 +53,6 @@ ColorBlock::ColorBlock(const uint *linearImage)
}
}
-/** Init the color block with the contents of the given block. */
ColorBlock::ColorBlock(const ColorBlock &block)
{
for (uint i = 0; i < 16; i++) {
@@ -62,7 +60,6 @@ ColorBlock::ColorBlock(const ColorBlock &block)
}
}
-/** Initialize this color block. */
ColorBlock::ColorBlock(const Image *img, uint x, uint y)
{
init(img, x, y);
@@ -153,7 +150,6 @@ void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
}
}
-/** Returns true if the block has a single color. */
bool ColorBlock::isSingleColor(Color32 mask /*= Color32(0xFF, 0xFF, 0xFF, 0x00) */) const
{
uint u = m_color[0].u & mask.u;
@@ -234,7 +230,6 @@ Color32 ColorBlock::averageColor() const
}
#endif
-/** Return true if the block is not fully opaque. */
bool ColorBlock::hasAlpha() const
{
for (const auto &i : m_color) {
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
index 934837bb129..1dee5c76c9e 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.h
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -35,8 +35,11 @@
/** Uncompressed 4x4 color block. */
struct ColorBlock {
ColorBlock() = default;
+ /** Init the color block from an array of colors. */
ColorBlock(const uint *linearImage);
+ /** Init the color block with the contents of the given block. */
ColorBlock(const ColorBlock &block);
+ /** Initialize this color block. */
ColorBlock(const Image *img, uint x, uint y);
void init(const Image *img, uint x, uint y);
@@ -45,7 +48,9 @@ struct ColorBlock {
void swizzle(uint x, uint y, uint z, uint w); /* 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0 */
+ /** Returns true if the block has a single color. */
bool isSingleColor(Color32 mask = Color32(0xFF, 0xFF, 0xFF, 0x00)) const;
+ /** Return true if the block is not fully opaque. */
bool hasAlpha() const;
/* Accessors */
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index b665996b18f..efa438c2af5 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -1107,8 +1107,6 @@ void DirectDrawSurface::mipmap(Image *img, uint face, uint mipmap)
}
}
-/* It was easier to copy this function from upstream than to resync.
- * This should be removed if a resync ever occurs. */
void *DirectDrawSurface::readData(uint &rsize)
{
uint header_size = 128; // sizeof(DDSHeader);
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
index 381fa51f75c..343a7367f91 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.h
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -157,6 +157,10 @@ class DirectDrawSurface {
void setUserVersion(int version);
void mipmap(Image *img, uint f, uint m);
+ /**
+ * It was easier to copy this function from upstream than to resync.
+ * This should be removed if a resync ever occurs.
+ */
void *readData(uint &size);
// void mipmap(FloatImage *img, uint f, uint m);
@@ -174,7 +178,8 @@ class DirectDrawSurface {
void readBlock(ColorBlock *rgba);
private:
- Stream stream; /* Memory where DDS file resides. */
+ /** Memory where DDS file resides. */
+ Stream stream;
DDSHeader header;
};
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index 2acf072556a..6686d56e9d1 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -168,10 +168,16 @@ static void FlipDXT5BlockHalf(uint8_t *block)
FlipDXT1BlockHalf(block + 8);
}
-/* Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate. */
-int FlipDXTCImage(
- unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data)
+int FlipDXTCImage(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ int fourcc,
+ uint8_t *data,
+ int data_size,
+ unsigned int *r_num_valid_levels)
{
+ *r_num_valid_levels = 0;
+
/* Must have valid dimensions. */
if (width == 0 || height == 0) {
return 0;
@@ -205,14 +211,25 @@ int FlipDXTCImage(
return 0;
}
+ *r_num_valid_levels = levels;
+
unsigned int mip_width = width;
unsigned int mip_height = height;
+ const uint8_t *data_end = data + data_size;
+
for (unsigned int i = 0; i < levels; i++) {
unsigned int blocks_per_row = (mip_width + 3) / 4;
unsigned int blocks_per_col = (mip_height + 3) / 4;
unsigned int blocks = blocks_per_row * blocks_per_col;
+ if (data + block_bytes * blocks > data_end) {
+ /* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
+ * on a malformed files. */
+ *r_num_valid_levels = i;
+ break;
+ }
+
if (mip_height == 1) {
/* no flip to do, and we're done. */
break;
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.h b/source/blender/imbuf/intern/dds/FlipDXT.h
index d35157251bd..f9d3ce6112e 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.h
+++ b/source/blender/imbuf/intern/dds/FlipDXT.h
@@ -18,6 +18,15 @@
#include "BLI_sys_types.h"
-/* flip compressed DXT image vertically to fit OpenGL convention */
-int FlipDXTCImage(
- unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data);
+/**
+ * Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
+ *
+ * Use to flip vertically to fit OpenGL convention.
+ */
+int FlipDXTCImage(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ int fourcc,
+ uint8_t *data,
+ int data_size,
+ unsigned int *r_num_valid_levels);
diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp
index 3dab3c35675..31bf2076ed1 100644
--- a/source/blender/imbuf/intern/dds/Stream.cpp
+++ b/source/blender/imbuf/intern/dds/Stream.cpp
@@ -26,6 +26,21 @@
static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)";
static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)";
+inline bool is_read_within_bounds(const Stream &mem, unsigned int cnt)
+{
+ if (mem.pos >= mem.size) {
+ /* No more data remained in the memory buffer. */
+ return false;
+ }
+
+ if (cnt > mem.size - mem.pos) {
+ /* Reading past the memory bounds. */
+ return false;
+ }
+
+ return true;
+}
+
unsigned int Stream::seek(unsigned int p)
{
if (p > size) {
@@ -40,7 +55,7 @@ unsigned int Stream::seek(unsigned int p)
unsigned int mem_read(Stream &mem, unsigned long long &i)
{
- if (mem.pos + 8 > mem.size) {
+ if (!is_read_within_bounds(mem, 8)) {
mem.set_failed(msg_error_seek);
return 0;
}
@@ -51,7 +66,7 @@ unsigned int mem_read(Stream &mem, unsigned long long &i)
unsigned int mem_read(Stream &mem, unsigned int &i)
{
- if (mem.pos + 4 > mem.size) {
+ if (!is_read_within_bounds(mem, 4)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -62,7 +77,7 @@ unsigned int mem_read(Stream &mem, unsigned int &i)
unsigned int mem_read(Stream &mem, unsigned short &i)
{
- if (mem.pos + 2 > mem.size) {
+ if (!is_read_within_bounds(mem, 2)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -73,7 +88,7 @@ unsigned int mem_read(Stream &mem, unsigned short &i)
unsigned int mem_read(Stream &mem, unsigned char &i)
{
- if (mem.pos + 1 > mem.size) {
+ if (!is_read_within_bounds(mem, 1)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -84,7 +99,7 @@ unsigned int mem_read(Stream &mem, unsigned char &i)
unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int cnt)
{
- if (mem.pos + cnt > mem.size) {
+ if (!is_read_within_bounds(mem, cnt)) {
mem.set_failed(msg_error_read);
return 0;
}
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 1729a9a64f8..f576209ff62 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -186,8 +186,13 @@ struct ImBuf *imb_load_dds(const unsigned char *mem,
/* flip compressed texture */
if (ibuf->dds_data.data) {
- FlipDXTCImage(
- dds.width(), dds.height(), dds.mipmapCount(), dds.fourCC(), ibuf->dds_data.data);
+ FlipDXTCImage(dds.width(),
+ dds.height(),
+ ibuf->dds_data.nummipmaps,
+ dds.fourCC(),
+ ibuf->dds_data.data,
+ ibuf->dds_data.size,
+ &ibuf->dds_data.nummipmaps);
}
}
else {
diff --git a/source/blender/imbuf/intern/dds/dds_api.h b/source/blender/imbuf/intern/dds/dds_api.h
index 931c4f267f9..2d540f13a52 100644
--- a/source/blender/imbuf/intern/dds/dds_api.h
+++ b/source/blender/imbuf/intern/dds/dds_api.h
@@ -26,7 +26,7 @@
extern "C" {
#endif
-bool imb_is_a_dds(const unsigned char *mem, const size_t size);
+bool imb_is_a_dds(const unsigned char *mem, size_t size);
bool imb_save_dds(struct ImBuf *ibuf, const char *name, int flags);
struct ImBuf *imb_load_dds(const unsigned char *mem,
size_t size,
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index e6f42da1597..ff86fbfdd38 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -102,13 +102,11 @@ MINLINE void float_to_byte_dither_v4(
b[3] = unit_float_to_uchar_clamp(f[3]);
}
-/* Test if colorspace conversions of pixels in buffer need to take into account alpha. */
bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
{
return (ibuf->flags & IB_alphamode_channel_packed) == 0;
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -275,7 +273,6 @@ void IMB_buffer_byte_from_float(uchar *rect_to,
}
}
-/* float to byte pixels, output 4-channel RGBA */
void IMB_buffer_byte_from_float_mask(uchar *rect_to,
const float *rect_from,
int channels_from,
@@ -366,7 +363,6 @@ void IMB_buffer_byte_from_float_mask(uchar *rect_to,
}
}
-/* Byte to float pixels, input and output 4-channel RGBA. */
void IMB_buffer_float_from_byte(float *rect_to,
const uchar *rect_from,
int profile_to,
@@ -386,7 +382,7 @@ void IMB_buffer_float_from_byte(float *rect_to,
/* RGBA input */
for (y = 0; y < height; y++) {
- const uchar *from = rect_from + stride_from * y * 4;
+ const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
float *to = rect_to + ((size_t)stride_to) * y * 4;
if (profile_to == profile_from) {
@@ -426,7 +422,6 @@ void IMB_buffer_float_from_byte(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float(float *rect_to,
const float *rect_from,
int channels_from,
@@ -592,7 +587,6 @@ void IMB_buffer_float_from_float_threaded(float *rect_to,
}
}
-/* float to float pixels, output 4-channel RGBA */
void IMB_buffer_float_from_float_mask(float *rect_to,
const float *rect_from,
int channels_from,
@@ -646,7 +640,6 @@ void IMB_buffer_float_from_float_mask(float *rect_to,
}
}
-/* byte to byte pixels, input and output 4-channel RGBA */
void IMB_buffer_byte_from_byte(uchar *rect_to,
const uchar *rect_from,
int profile_to,
@@ -791,17 +784,14 @@ void IMB_float_from_rect(ImBuf *ibuf)
*/
rect_float = ibuf->rect_float;
if (rect_float == NULL) {
- size_t size;
-
- size = ((size_t)ibuf->x) * ibuf->y;
- size = sizeof(float[4]) * size;
- ibuf->channels = 4;
-
+ const size_t size = IMB_get_rect_len(ibuf) * sizeof(float[4]);
rect_float = MEM_callocN(size, "IMB_float_from_rect");
if (rect_float == NULL) {
return;
}
+
+ ibuf->channels = 4;
}
/* first, create float buffer in non-linear space */
@@ -834,10 +824,9 @@ void IMB_float_from_rect(ImBuf *ibuf)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Color to Grayscale
+/** \name Color to Gray-Scale
* \{ */
-/* no profile conversion */
void IMB_color_to_bw(ImBuf *ibuf)
{
float *rct_fl = ibuf->rect_float;
@@ -845,13 +834,13 @@ void IMB_color_to_bw(ImBuf *ibuf)
size_t i;
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
}
}
if (rct) {
- for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
}
}
@@ -892,7 +881,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
if (rct) {
float rgb[3];
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
rgb_uchar_to_float(rgb, rct);
rgb_to_hsv_v(rgb, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
@@ -901,7 +890,7 @@ void IMB_saturation(ImBuf *ibuf, float sat)
}
if (rct_fl) {
- for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
+ for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += 4) {
rgb_to_hsv_v(rct_fl, hsv);
hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
}
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 343c8cd8f64..324bc9806c1 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -420,12 +420,6 @@ static int check_pixel_assigned(
return res;
}
-/**
- * if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0
- *
- * When a mask is given, only effect pixels with a mask value of 1,
- * defined as #BAKE_MASK_MARGIN in rendercore.c
- */
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
{
const int width = ibuf->x;
@@ -557,7 +551,6 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter)
}
}
-/* threadsafe version, only recreates existing maps */
void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
@@ -594,7 +587,6 @@ void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
}
}
-/* frees too (if there) and recreates new data */
void IMB_makemipmap(ImBuf *ibuf, int use_filter)
{
ImBuf *hbuf = ibuf;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 804c9c3eb89..23c4c53d602 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -20,11 +20,10 @@
/** \file
* \ingroup imbuf
*
- * This file was moved here from the src/ directory. It is meant to
- * deal with endianness. It resided in a general blending lib. The
- * other functions were only used during rendering. This single
- * function remained. It should probably move to imbuf/intern/util.c,
- * but we'll keep it here for the time being. (nzc)
+ * This file was moved here from the `src/` directory.
+ * It is meant to deal with endianness. It resided in a general blending lib.
+ * The other functions were only used during rendering. This single function remained.
+ * It should probably move to `imbuf/intern/util.c`, but we'll keep it here for the time being.
*/
#include <math.h>
@@ -41,7 +40,6 @@
#include "IMB_imbuf_types.h"
#include <math.h>
-/* Only this one is used liberally here, and in imbuf */
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
size_t size;
@@ -77,7 +75,8 @@ void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
}
}
-static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
+static void pixel_from_buffer(
+ const struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
{
size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
@@ -96,7 +95,7 @@ static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **
* \{ */
void bicubic_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bicubic_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -106,7 +105,7 @@ void bicubic_interpolation_color(
}
}
-void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bicubic_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -127,16 +126,16 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
/** \name Bi-Linear Interpolation
* \{ */
-BLI_INLINE void bilinear_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void bilinear_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
}
-BLI_INLINE void bilinear_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void bilinear_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -144,7 +143,7 @@ BLI_INLINE void bilinear_interpolation_color_char(
}
void bilinear_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
@@ -157,12 +156,8 @@ void bilinear_interpolation_color(
/* function assumes out to be zero'ed, only does RGBA */
/* BILINEAR INTERPOLATION */
-/* Note about wrapping, the u/v still needs to be within the image bounds,
- * just the interpolation is wrapped.
- * This the same as bilinear_interpolation_color except it wraps
- * rather than using empty and emptyI. */
void bilinear_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
float *row1, *row2, *row3, *row4, a, b;
unsigned char *row1I, *row2I, *row3I, *row4I;
@@ -233,7 +228,7 @@ void bilinear_interpolation_color_wrap(
}
}
-void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void bilinear_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -254,9 +249,8 @@ void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, i
/** \name Nearest Interpolation
* \{ */
-/* functions assumes out to be zero'ed, only does RGBA */
-BLI_INLINE void nearest_interpolation_color_char(
- struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
+void nearest_interpolation_color_char(
+ const struct ImBuf *in, unsigned char outI[4], float UNUSED(outF[4]), float u, float v)
{
BLI_assert(outI);
BLI_assert(in->rect);
@@ -270,7 +264,7 @@ BLI_INLINE void nearest_interpolation_color_char(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const unsigned char *dataI = (unsigned char *)in->rect + offset;
outI[0] = dataI[0];
outI[1] = dataI[1];
@@ -278,8 +272,8 @@ BLI_INLINE void nearest_interpolation_color_char(
outI[3] = dataI[3];
}
-BLI_INLINE void nearest_interpolation_color_fl(
- struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
+void nearest_interpolation_color_fl(
+ const struct ImBuf *in, unsigned char UNUSED(outI[4]), float outF[4], float u, float v)
{
BLI_assert(outF);
BLI_assert(in->rect_float);
@@ -293,13 +287,13 @@ BLI_INLINE void nearest_interpolation_color_fl(
return;
}
- const size_t offset = (in->x * y1 + x1) * 4;
+ const size_t offset = ((size_t)in->x * y1 + x1) * 4;
const float *dataF = in->rect_float + offset;
copy_v4_v4(outF, dataF);
}
void nearest_interpolation_color(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
if (outF) {
nearest_interpolation_color_fl(in, outI, outF, u, v);
@@ -310,7 +304,7 @@ void nearest_interpolation_color(
}
void nearest_interpolation_color_wrap(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
+ const struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v)
{
const float *dataF;
unsigned char *dataI;
@@ -348,7 +342,7 @@ void nearest_interpolation_color_wrap(
}
}
-void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+void nearest_interpolation(const ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
{
unsigned char *outI = NULL;
float *outF = NULL;
@@ -363,139 +357,6 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in
nearest_interpolation_color(in, outI, outF, u, v);
}
-/* -------------------------------------------------------------------- */
-/** \name Image transform
- * \{ */
-typedef struct TransformUserData {
- ImBuf *src;
- ImBuf *dst;
- float start_uv[2];
- float add_x[2];
- float add_y[2];
- rctf src_crop;
-} TransformUserData;
-
-static void imb_transform_calc_start_uv(const float transform_matrix[3][3], float r_start_uv[2])
-{
- float orig[2];
- orig[0] = 0.0f;
- orig[1] = 0.0f;
- mul_v2_m3v2(r_start_uv, transform_matrix, orig);
-}
-
-static void imb_transform_calc_add_x(const float transform_matrix[3][3],
- const float start_uv[2],
- const int width,
- float r_add_x[2])
-{
- float uv_max_x[2];
- uv_max_x[0] = width;
- uv_max_x[1] = 0.0f;
- mul_v2_m3v2(r_add_x, transform_matrix, uv_max_x);
- sub_v2_v2(r_add_x, start_uv);
- mul_v2_fl(r_add_x, 1.0f / width);
-}
-
-static void imb_transform_calc_add_y(const float transform_matrix[3][3],
- const float start_uv[2],
- const int height,
- float r_add_y[2])
-{
- float uv_max_y[2];
- uv_max_y[0] = 0.0f;
- uv_max_y[1] = height;
- mul_v2_m3v2(r_add_y, transform_matrix, uv_max_y);
- sub_v2_v2(r_add_y, start_uv);
- mul_v2_fl(r_add_y, 1.0f / height);
-}
-
-typedef void (*InterpolationColorFunction)(
- struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v);
-BLI_INLINE void imb_transform_scanlines(const TransformUserData *user_data,
- int scanline,
- InterpolationColorFunction interpolation)
-{
- const int width = user_data->dst->x;
-
- float uv[2];
- madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
-
- unsigned char *outI = NULL;
- float *outF = NULL;
- pixel_from_buffer(user_data->dst, &outI, &outF, 0, scanline);
-
- for (int xi = 0; xi < width; xi++) {
- if (uv[0] >= user_data->src_crop.xmin && uv[0] < user_data->src_crop.xmax &&
- uv[1] >= user_data->src_crop.ymin && uv[1] < user_data->src_crop.ymax) {
- interpolation(user_data->src, outI, outF, uv[0], uv[1]);
- }
- add_v2_v2(uv, user_data->add_x);
- if (outI) {
- outI += 4;
- }
- if (outF) {
- outF += 4;
- }
- }
-}
-
-static void imb_transform_nearest_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = nearest_interpolation_color_fl;
- }
- else {
- interpolation = nearest_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static void imb_transform_bilinear_scanlines(void *custom_data, int scanline)
-{
- const TransformUserData *user_data = custom_data;
- InterpolationColorFunction interpolation = NULL;
- if (user_data->dst->rect_float) {
- interpolation = bilinear_interpolation_color_fl;
- }
- else if (user_data->dst->rect) {
- interpolation = bilinear_interpolation_color_char;
- }
- imb_transform_scanlines(user_data, scanline, interpolation);
-}
-
-static ScanlineThreadFunc imb_transform_scanline_func(const eIMBInterpolationFilterMode filter)
-{
- ScanlineThreadFunc scanline_func = NULL;
- switch (filter) {
- case IMB_FILTER_NEAREST:
- scanline_func = imb_transform_nearest_scanlines;
- break;
- case IMB_FILTER_BILINEAR:
- scanline_func = imb_transform_bilinear_scanlines;
- break;
- }
- return scanline_func;
-}
-
-void IMB_transform(struct ImBuf *src,
- struct ImBuf *dst,
- float transform_matrix[3][3],
- struct rctf *src_crop,
- const eIMBInterpolationFilterMode filter)
-{
- TransformUserData user_data;
- user_data.src = src;
- user_data.dst = dst;
- user_data.src_crop = *src_crop;
- imb_transform_calc_start_uv(transform_matrix, user_data.start_uv);
- imb_transform_calc_add_x(transform_matrix, user_data.start_uv, src->x, user_data.add_x);
- imb_transform_calc_add_y(transform_matrix, user_data.start_uv, src->y, user_data.add_y);
- ScanlineThreadFunc scanline_func = imb_transform_scanline_func(filter);
- IMB_processor_apply_threaded_scanlines(dst->y, scanline_func, &user_data);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -637,7 +498,6 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float b
/** \name Sample Pixel
* \{ */
-/* Sample pixel of image using NEAREST method. */
void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
{
if (ibuf->rect_float) {
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index bbb0f3b5b22..a85ba65d014 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -37,6 +37,8 @@
# include "BLI_winstuff.h"
#endif
+#include "PIL_time.h"
+
#include "IMB_anim.h"
#include "IMB_indexer.h"
#include "imbuf.h"
@@ -170,7 +172,6 @@ struct anim_index *IMB_indexer_open(const char *name)
int i;
if (!fp) {
- fprintf(stderr, "Couldn't open indexer file: %s\n", name);
return NULL;
}
@@ -183,13 +184,13 @@ struct anim_index *IMB_indexer_open(const char *name)
header[12] = 0;
if (memcmp(header, binary_header_str, 8) != 0) {
- fprintf(stderr, "Error reading %s: Binary file type string missmatch\n", name);
+ fprintf(stderr, "Error reading %s: Binary file type string mismatch\n", name);
fclose(fp);
return NULL;
}
if (atoi(header + 9) != INDEX_FILE_VERSION) {
- fprintf(stderr, "Error reading %s: File version missmatch\n", name);
+ fprintf(stderr, "Error reading %s: File version mismatch\n", name);
fclose(fp);
return NULL;
}
@@ -222,7 +223,7 @@ struct anim_index *IMB_indexer_open(const char *name)
}
if (UNLIKELY(items_read != idx->num_entries * 5)) {
- fprintf(stderr, "Error: Element data size missmatch in: %s\n", name);
+ fprintf(stderr, "Error: Element data size mismatch in: %s\n", name);
MEM_freeN(idx->entries);
MEM_freeN(idx);
fclose(fp);
@@ -815,12 +816,16 @@ typedef struct FFmpegIndexBuilderContext {
double pts_time_base;
int frameno, frameno_gapless;
int start_pts_set;
+
+ bool build_only_on_bad_performance;
+ bool building_cancelled;
} FFmpegIndexBuilderContext;
static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
- int quality)
+ int quality,
+ bool build_only_on_bad_performance)
{
FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext),
"FFmpeg index builder context");
@@ -832,6 +837,7 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
context->proxy_sizes_in_use = proxy_sizes_in_use;
context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
context->num_indexers = IMB_TC_MAX_SLOT;
+ context->build_only_on_bad_performance = build_only_on_bad_performance;
memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
memset(context->indexer, 0, sizeof(context->indexer));
@@ -937,15 +943,17 @@ static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int
{
int i;
+ const bool do_rollback = stop || context->building_cancelled;
+
for (i = 0; i < context->num_indexers; i++) {
if (context->tcs_in_use & tc_types[i]) {
- IMB_index_builder_finish(context->indexer[i], stop);
+ IMB_index_builder_finish(context->indexer[i], do_rollback);
}
}
for (i = 0; i < context->num_proxy_sizes; i++) {
if (context->proxy_sizes_in_use & proxy_sizes[i]) {
- free_proxy_output_ffmpeg(context->proxy_ctx[i], stop);
+ free_proxy_output_ffmpeg(context->proxy_ctx[i], do_rollback);
}
}
@@ -1096,6 +1104,111 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
return 1;
}
+/* Get number of frames, that can be decoded in specified time period. */
+static int indexer_performance_get_decode_rate(FFmpegIndexBuilderContext *context,
+ const double time_period)
+{
+ AVFrame *in_frame = av_frame_alloc();
+ AVPacket *packet = av_packet_alloc();
+
+ const double start = PIL_check_seconds_timer();
+ int frames_decoded = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+
+ int ret = avcodec_send_packet(context->iCodecCtx, packet);
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+ break;
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "Error decoding proxy frame: %s\n", av_err2str(ret));
+ break;
+ }
+ frames_decoded++;
+ }
+
+ const double end = PIL_check_seconds_timer();
+
+ if (end > start + time_period) {
+ break;
+ }
+ }
+
+ avcodec_flush_buffers(context->iCodecCtx);
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return frames_decoded;
+}
+
+/* Read up to 10k movie packets and return max GOP size detected.
+ * Number of packets is arbitrary. It should be as large as possible, but processed within
+ * reasonable time period, so detected GOP size is as close to real as possible. */
+static int indexer_performance_get_max_gop_size(FFmpegIndexBuilderContext *context)
+{
+ AVPacket *packet = av_packet_alloc();
+
+ const int packets_max = 10000;
+ int packet_index = 0;
+ int max_gop = 0;
+ int cur_gop = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+ packet_index++;
+ cur_gop++;
+
+ if (packet->flags & AV_PKT_FLAG_KEY) {
+ max_gop = max_ii(max_gop, cur_gop);
+ cur_gop = 0;
+ }
+
+ if (packet_index > packets_max) {
+ break;
+ }
+ }
+
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return max_gop;
+}
+
+/* Assess scrubbing performance of provided file. This function is not meant to be very exact.
+ * It compares number number of frames decoded in reasonable time with largest detected GOP size.
+ * Because seeking happens in single GOP, it means, that maximum seek time can be detected this
+ * way.
+ * Since proxies use GOP size of 10 frames, skip building if detected GOP size is less or
+ * equal.
+ */
+static bool indexer_need_to_build_proxy(FFmpegIndexBuilderContext *context)
+{
+ if (!context->build_only_on_bad_performance) {
+ return true;
+ }
+
+ /* Make sure, that file is not cold read. */
+ indexer_performance_get_decode_rate(context, 0.1);
+ /* Get decode rate per 100ms. This is arbitrary, but seems to be good baseline cadence of
+ * seeking. */
+ const int decode_rate = indexer_performance_get_decode_rate(context, 0.1);
+ const int max_gop_size = indexer_performance_get_max_gop_size(context);
+
+ if (max_gop_size <= 10 || max_gop_size < decode_rate) {
+ printf("Skipping proxy building for %s: Decoding performance is already good.\n",
+ context->iFormatCtx->url);
+ context->building_cancelled = true;
+ return false;
+ }
+
+ return true;
+}
+
#endif
/* ----------------------------------------------------------------------
@@ -1275,7 +1388,8 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
const bool overwrite,
- GSet *file_list)
+ GSet *file_list,
+ bool build_only_on_bad_performance)
{
IndexBuildContext *context = NULL;
IMB_Proxy_Size proxy_sizes_to_build = proxy_sizes_in_use;
@@ -1329,9 +1443,13 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
switch (anim->curtype) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
+ context = index_ffmpeg_create_context(
+ anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
break;
+#else
+ UNUSED_VARS(build_only_on_bad_performance);
#endif
+
#ifdef WITH_AVI
default:
context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
@@ -1359,7 +1477,9 @@ void IMB_anim_index_rebuild(struct IndexBuildContext *context,
switch (context->anim_type) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ if (indexer_need_to_build_proxy((FFmpegIndexBuilderContext *)context)) {
+ index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ }
break;
#endif
#ifdef WITH_AVI
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index df516d2a5c4..1c8548009e8 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -251,12 +251,6 @@ bool imb_is_a_iris(const uchar *mem, size_t size)
return ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC));
}
-/*
- * longimagedata -
- * read in a B/W RGB or RGBA iris image file and return a
- * pointer to an array of ints.
- */
-
struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
uint *base, *lptr = NULL;
@@ -274,7 +268,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
return NULL;
}
- /* Could pe part of the magic check above,
+ /* Could be part of the magic check above,
* by convention this check only requests the size needed to read it's magic though. */
if (size < HEADER_SIZE) {
return NULL;
@@ -542,7 +536,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
}
}
else if (image.zsize == 2) {
- /* grayscale with alpha */
+ /* Gray-scale with alpha. */
rect = (uchar *)ibuf->rect;
for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
rect[0] = rect[2];
@@ -570,7 +564,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
}
}
else if (image.zsize == 2) {
- /* grayscale with alpha */
+ /* Gray-scale with alpha. */
fbase = ibuf->rect_float;
for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
fbase[0] = fbase[2];
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 117e0d97b2e..3af7367ef6e 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -424,13 +424,13 @@ static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
h = image->comps[0].h;
switch (image->numcomps) {
- case 1: /* Grayscale */
- case 3: /* Color */
+ case 1: /* Gray-scale. */
+ case 3: /* Color. */
planes = 24;
use_alpha = false;
break;
- default: /* 2 or 4 - Grayscale or Color + alpha */
- planes = 32; /* grayscale + alpha */
+ default: /* 2 or 4 - Gray-scale or Color + alpha. */
+ planes = 32; /* Gray-scale + alpha. */
use_alpha = true;
break;
}
@@ -529,7 +529,7 @@ static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
r = image->comps[0].data;
a = (use_alpha) ? image->comps[1].data : NULL;
- /* grayscale */
+ /* Gray-scale. */
if (use_alpha) {
a = image->comps[3].data;
PIXEL_LOOPER_BEGIN (rect_uchar) {
@@ -848,7 +848,7 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
chanel_colormanage_cb = channel_colormanage_noop;
}
else {
- /* standard linear-to-srgb conversion if float buffer wasn't managed */
+ /* standard linear-to-SRGB conversion if float buffer wasn't managed */
chanel_colormanage_cb = linearrgb_to_srgb;
}
@@ -891,8 +891,8 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
prec = 8;
}
- /* 32bit images == alpha channel */
- /* grayscale not supported yet */
+ /* 32bit images == alpha channel. */
+ /* Gray-scale not supported yet. */
numcomps = (ibuf->planes == 32) ? 4 : 3;
}
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 48b5b0c34db..c3a07d7face 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -40,8 +40,9 @@
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
#include "imbuf.h"
-#include "jerror.h"
-#include "jpeglib.h"
+
+#include <jerror.h>
+#include <jpeglib.h>
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 6cc1932eff6..f290ab1a060 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -87,6 +87,8 @@ typedef struct MovieCacheItem {
ImBuf *ibuf;
MEM_CacheLimiterHandleC *c_handle;
void *priority_data;
+ /* Indicates that #ibuf is null, because there was an error during load. */
+ bool added_empty;
} MovieCacheItem;
static unsigned int moviecache_hashhash(const void *keyv)
@@ -120,8 +122,13 @@ static void moviecache_valfree(void *val)
PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
- if (item->ibuf) {
+ if (item->c_handle) {
+ BLI_mutex_lock(&limitor_lock);
MEM_CacheLimiter_unmanage(item->c_handle);
+ BLI_mutex_unlock(&limitor_lock);
+ }
+
+ if (item->ibuf) {
IMB_freeImBuf(item->ibuf);
}
@@ -141,11 +148,16 @@ static void check_unused_keys(MovieCache *cache)
while (!BLI_ghashIterator_done(&gh_iter)) {
const MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
const MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
- bool remove;
BLI_ghashIterator_step(&gh_iter);
- remove = !item->ibuf;
+ if (item->added_empty) {
+ /* Don't remove entries that have been added empty. Those indicate that the image couldn't be
+ * loaded correctly. */
+ continue;
+ }
+
+ bool remove = !item->ibuf;
if (remove) {
PRINT("%s: cache '%s' remove item %p without buffer\n", __func__, cache->name, item);
@@ -230,6 +242,9 @@ static int get_item_priority(void *item_v, int default_priority)
static bool get_item_destroyable(void *item_v)
{
MovieCacheItem *item = (MovieCacheItem *)item_v;
+ if (item->ibuf == NULL) {
+ return true;
+ }
/* IB_BITMAPDIRTY means image was modified from inside blender and
* changes are not saved to disk.
*
@@ -253,6 +268,7 @@ void IMB_moviecache_destruct(void)
{
if (limitor) {
delete_MEM_CacheLimiter(limitor);
+ limitor = NULL;
}
}
@@ -309,7 +325,9 @@ static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, boo
IMB_moviecache_init();
}
- IMB_refImBuf(ibuf);
+ if (ibuf != NULL) {
+ IMB_refImBuf(ibuf);
+ }
key = BLI_mempool_alloc(cache->keys_pool);
key->cache_owner = cache;
@@ -324,6 +342,7 @@ static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, boo
item->cache_owner = cache;
item->c_handle = NULL;
item->priority_data = NULL;
+ item->added_empty = ibuf == NULL;
if (cache->getprioritydatafp) {
item->priority_data = cache->getprioritydatafp(userkey);
@@ -365,7 +384,7 @@ bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibu
size_t mem_in_use, mem_limit, elem_size;
bool result = false;
- elem_size = get_size_in_memory(ibuf);
+ elem_size = (ibuf == NULL) ? 0 : get_size_in_memory(ibuf);
mem_limit = MEM_CacheLimiter_get_maximum();
BLI_mutex_lock(&limitor_lock);
@@ -389,7 +408,7 @@ void IMB_moviecache_remove(MovieCache *cache, void *userkey)
BLI_ghash_remove(cache->hash, &key, moviecache_keyfree, moviecache_valfree);
}
-ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
+ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey, bool *r_is_cached_empty)
{
MovieCacheKey key;
MovieCacheItem *item;
@@ -398,6 +417,10 @@ ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
key.userkey = userkey;
item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
+ if (r_is_cached_empty) {
+ *r_is_cached_empty = false;
+ }
+
if (item) {
if (item->ibuf) {
BLI_mutex_lock(&limitor_lock);
@@ -408,6 +431,9 @@ ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
return item->ibuf;
}
+ if (r_is_cached_empty) {
+ *r_is_cached_empty = true;
+ }
}
return NULL;
@@ -470,7 +496,6 @@ void IMB_moviecache_cleanup(MovieCache *cache,
}
}
-/* get segments of cached frames. useful for debugging cache policies */
void IMB_moviecache_get_cache_segments(
MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points)
{
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 3ad902a241d..22533b04b58 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -221,7 +221,7 @@ struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspac
string ics = spec.get_string_attribute("oiio:ColorSpace");
BLI_strncpy(file_colorspace, ics.c_str(), IM_MAX_SPACE);
- /* only use colorspaces exis */
+ /* Only use color-spaces exist. */
if (colormanage_colorspace_get_named(file_colorspace)) {
strcpy(colorspace, file_colorspace);
}
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.h b/source/blender/imbuf/intern/oiio/openimageio_api.h
index 659050cdb00..1201bd1b5e0 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.h
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.h
@@ -31,7 +31,7 @@ extern "C" {
struct ImBuf;
-bool imb_is_a_photoshop(const unsigned char *mem, const size_t size);
+bool imb_is_a_photoshop(const unsigned char *mem, size_t size);
int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index adf09f8dda8..ec8cf36dd49 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -327,10 +327,6 @@ static half float_to_half_safe(const float value)
extern "C" {
-/**
- * Test presence of OpenEXR file.
- * \param mem: pointer to loaded OpenEXR bitstream
- */
bool imb_is_a_openexr(const unsigned char *mem, const size_t size)
{
/* No define is exposed for this size. */
@@ -687,7 +683,7 @@ static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data);
void *IMB_exr_get_handle(void)
{
- ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ ExrHandle *data = MEM_cnew<ExrHandle>("exr handle");
data->multiView = new StringVector();
BLI_addtail(&exrhandles, data);
@@ -781,9 +777,6 @@ static void imb_exr_insert_view_name(char *name_full, const char *passname, cons
}
}
-/* adds flattened ExrChannels */
-/* xstride, ystride and rect can be done in set_channel too, for tile writing */
-/* passname does not include view */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -796,7 +789,7 @@ void IMB_exr_add_channel(void *handle,
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan = MEM_cnew<ExrChannel>("exr channel");
echan->m = new MultiViewChannelName();
if (layname && layname[0] != '\0') {
@@ -840,7 +833,6 @@ void IMB_exr_add_channel(void *handle,
BLI_addtail(&data->channels, echan);
}
-/* used for output files (from RenderResult) (single and multilayer, single and multiview) */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
@@ -896,8 +888,6 @@ bool IMB_exr_begin_write(void *handle,
return (data->ofile != nullptr);
}
-/* only used for writing temp. render results (not image files)
- * (FSA and Save Buffers) */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
{
@@ -963,7 +953,6 @@ void IMB_exrtile_begin_write(
}
}
-/* read from file */
bool IMB_exr_begin_read(
void *handle, const char *filename, int *width, int *height, const bool parse_channels)
{
@@ -1024,8 +1013,6 @@ bool IMB_exr_begin_read(
return true;
}
-/* still clumsy name handling, layers/channels can be ordered as list in list later */
-/* passname here is the raw channel name without the layer */
void IMB_exr_set_channel(
void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{
@@ -1167,8 +1154,6 @@ void IMB_exr_write_channels(void *handle)
}
}
-/* temporary function, used for FSA and Save Buffers */
-/* called once per tile * view */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty)
{
@@ -1511,7 +1496,7 @@ static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
if (lay == nullptr) {
- lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
+ lay = MEM_cnew<ExrLayer>("exr layer");
BLI_addtail(lb, lay);
BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
}
@@ -1524,7 +1509,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
if (pass == nullptr) {
- pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
+ pass = MEM_cnew<ExrPass>("exr pass");
if (STREQ(passname, "Combined")) {
BLI_addhead(lb, pass);
@@ -1937,8 +1922,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
file = new MultiPartInputFile(*membuf);
Box2i dw = file->header(0).dataWindow();
- const int width = dw.max.x - dw.min.x + 1;
- const int height = dw.max.y - dw.min.y + 1;
+ const size_t width = dw.max.x - dw.min.x + 1;
+ const size_t height = dw.max.y - dw.min.y + 1;
// printf("OpenEXR-load: image data window %d %d %d %d\n",
// dw.min.x, dw.min.y, dw.max.x, dw.max.y);
@@ -2001,8 +1986,8 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
const bool has_luma = exr_has_luma(*file);
FrameBuffer frameBuffer;
float *first;
- int xstride = sizeof(float[4]);
- int ystride = -xstride * width;
+ size_t xstride = sizeof(float[4]);
+ size_t ystride = -xstride * width;
imb_addrectfloatImBuf(ibuf);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index 940715690a7..4321c95db30 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -32,7 +32,11 @@ extern "C" {
void imb_initopenexr(void);
void imb_exitopenexr(void);
-bool imb_is_a_openexr(const unsigned char *mem, const size_t size);
+/**
+ * Test presence of OpenEXR file.
+ * \param mem: pointer to loaded OpenEXR bit-stream.
+ */
+bool imb_is_a_openexr(const unsigned char *mem, size_t size);
bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags);
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 82a5d161ded..0c3c4a4400f 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -23,7 +23,7 @@
#pragma once
-/* experiment with more advanced exr api */
+/* Experiment with more advanced EXR API. */
/* XXX layer+pass name max 64? */
/* This api also supports max 8 channels per pass now. easy to fix! */
@@ -41,6 +41,12 @@ struct StampData;
void *IMB_exr_get_handle(void);
void *IMB_exr_get_handle_name(const char *name);
+
+/**
+ * Adds flattened #ExrChannel's
+ * `xstride`, `ystride` and `rect` can be done in set_channel too, for tile writing.
+ * \param passname: Does not include view.
+ */
void IMB_exr_add_channel(void *handle,
const char *layname,
const char *passname,
@@ -50,17 +56,32 @@ void IMB_exr_add_channel(void *handle,
float *rect,
bool use_half_float);
+/**
+ * Read from file.
+ */
bool IMB_exr_begin_read(
- void *handle, const char *filename, int *width, int *height, const bool parse_channels);
+ void *handle, const char *filename, int *width, int *height, bool parse_channels);
+/**
+ * Used for output files (from #RenderResult) (single and multi-layer, single and multi-view).
+ */
bool IMB_exr_begin_write(void *handle,
const char *filename,
int width,
int height,
int compress,
const struct StampData *stamp);
+/**
+ * Only used for writing temp. render results (not image files)
+ * (FSA and Save Buffers).
+ */
void IMB_exrtile_begin_write(
void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
+/**
+ * Still clumsy name handling, layers/channels can be ordered as list in list later.
+ *
+ * \param passname: Here is the raw channel name without the layer.
+ */
void IMB_exr_set_channel(void *handle,
const char *layname,
const char *passname,
@@ -74,6 +95,10 @@ float *IMB_exr_channel_rect(void *handle,
void IMB_exr_read_channels(void *handle);
void IMB_exr_write_channels(void *handle);
+/**
+ * Temporary function, used for FSA and Save Buffers.
+ * called once per `tile * view`.
+ */
void IMB_exrtile_write_channels(
void *handle, int partx, int party, int level, const char *viewname, bool empty);
void IMB_exr_clear_channels(void *handle);
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 639100ac6fe..9b4d6178613 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -49,7 +49,7 @@ bool IMB_exr_begin_read(void * /*handle*/,
int * /*height*/,
const bool /*add_channels*/)
{
- return 0;
+ return false;
}
bool IMB_exr_begin_write(void * /*handle*/,
const char * /*filename*/,
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 399fd487065..aaf56b1daa0 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -23,7 +23,7 @@
* \todo Save floats as 16 bits per channel, currently readonly.
*/
-#include "png.h"
+#include <png.h>
#include "BLI_fileops.h"
#include "BLI_math.h"
@@ -153,7 +153,7 @@ bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags)
chanel_colormanage_cb = channel_colormanage_noop;
}
else {
- /* standard linear-to-srgb conversion if float buffer wasn't managed */
+ /* Standard linear-to-SRGB conversion if float buffer wasn't managed. */
chanel_colormanage_cb = linearrgb_to_srgb;
}
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 7f4e4dd31df..925ef0a8502 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -77,7 +77,7 @@ static const unsigned char *oldreadcolrs(RGBE *scan,
scan[0][BLU] = *mem++;
scan[0][EXP] = *mem++;
if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) {
- for (i = scan[0][EXP] << rshift; i > 0; i--) {
+ for (i = scan[0][EXP] << rshift; i > 0 && len > 0; i--) {
COPY_RGBE(scan[-1], scan[0]);
scan++;
len--;
@@ -227,7 +227,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
int found = 0;
int width = 0, height = 0;
const unsigned char *ptr, *mem_eof = mem + size;
- char oriY[80], oriX[80];
+ char oriY[3], oriX[3];
if (!imb_is_a_hdr(mem, size)) {
return NULL;
@@ -244,22 +244,33 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
}
}
- if ((found && (x < (size + 2))) == 0) {
+ if ((found && (x < (size - 1))) == 0) {
/* Data not found! */
return NULL;
}
- if (sscanf((const char *)&mem[x + 1],
- "%79s %d %79s %d",
- (char *)&oriY,
- &height,
- (char *)&oriX,
- &width) != 4) {
+ x++;
+
+ /* sscanf requires a null-terminated buffer argument */
+ char buf[32] = {0};
+ memcpy(buf, &mem[x], MIN2(sizeof(buf) - 1, size - x));
+
+ if (sscanf(buf, "%2s %d %2s %d", (char *)&oriY, &height, (char *)&oriX, &width) != 4) {
+ return NULL;
+ }
+
+ if (width < 1 || height < 1) {
return NULL;
}
+ /* Checking that width x height does not extend past mem_eof is not easily possible
+ * since the format uses RLE compression. Can cause excessive memory allocation to occur. */
+
/* find end of this line, data right behind it */
- ptr = (const unsigned char *)strchr((const char *)&mem[x + 1], '\n');
+ ptr = (const unsigned char *)strchr((const char *)&mem[x], '\n');
+ if (ptr == NULL || ptr >= mem_eof) {
+ return NULL;
+ }
ptr++;
if (flags & IB_test) {
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index 50210650f05..c75bdfa375c 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -126,7 +126,7 @@ ImBuf *IMB_ibImageFromMemory(const unsigned char *mem,
}
if ((flags & IB_test) == 0) {
- fprintf(stderr, "%s: unknown fileformat (%s)\n", __func__, descr);
+ fprintf(stderr, "%s: unknown file-format (%s)\n", __func__, descr);
}
return NULL;
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 4b5d68b9c13..1d81ee768e9 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -251,9 +251,6 @@ static void rect_crop_16bytes(void **buf_p, const int size_src[2], const rcti *c
*buf_p = (void *)MEM_reallocN(*buf_p, sizeof(uint[4]) * size_dst[0] * size_dst[1]);
}
-/**
- * In-place image crop.
- */
void IMB_rect_crop(ImBuf *ibuf, const rcti *crop)
{
const int size_src[2] = {
@@ -302,9 +299,6 @@ static void rect_realloc_16bytes(void **buf_p, const uint size[2])
*buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__);
}
-/**
- * In-place size setting (caller must fill in buffer contents).
- */
void IMB_rect_size_set(ImBuf *ibuf, const uint size[2])
{
BLI_assert(size[0] > 0 && size[1] > 0);
@@ -1070,11 +1064,6 @@ void IMB_rectblend_threaded(ImBuf *dbuf,
}
}
-/**
- * Replace pixels of entire image with solid color.
- * \param ibuf: An image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- */
void IMB_rectfill(ImBuf *drect, const float col[4])
{
int num;
@@ -1107,15 +1096,6 @@ void IMB_rectfill(ImBuf *drect, const float col[4])
}
}
-/**
- * Replace pixels of image area with solid color.
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- */
void IMB_rectfill_area_replace(
const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
{
@@ -1273,21 +1253,6 @@ void buf_rectfill_area(unsigned char *rect,
}
}
-/**
- * Blend pixels of image area with solid color.
- *
- * For images with `uchar` buffer use color matching image color-space.
- * For images with float buffer use color display color-space.
- * If display color-space can not be referenced, use color in SRGB color-space.
- *
- * \param ibuf: an image to be filled with color. It must be 4 channel image.
- * \param col: RGBA color.
- * \param x1, y1, x2, y2: (x1, y1) defines starting point of the rectangular area to be filled,
- * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
- * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
- * order the area between x1 and x2, and y1 and y2 is filled.
- * \param display: color-space reference for display space.
- */
void IMB_rectfill_area(ImBuf *ibuf,
const float col[4],
int x1,
diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c
index c2fc2190ce5..f02f3e37d6a 100644
--- a/source/blender/imbuf/intern/rotate.c
+++ b/source/blender/imbuf/intern/rotate.c
@@ -32,7 +32,7 @@
void IMB_flipy(struct ImBuf *ibuf)
{
- int x, y;
+ size_t x_size, y_size;
if (ibuf == NULL) {
return;
@@ -41,21 +41,23 @@ void IMB_flipy(struct ImBuf *ibuf)
if (ibuf->rect) {
unsigned int *top, *bottom, *line;
- x = ibuf->x;
- y = ibuf->y;
+ x_size = ibuf->x;
+ y_size = ibuf->y;
+
+ const size_t stride = x_size * sizeof(int);
top = ibuf->rect;
- bottom = top + ((y - 1) * x);
- line = MEM_mallocN(x * sizeof(int), "linebuf");
+ bottom = top + ((y_size - 1) * x_size);
+ line = MEM_mallocN(stride, "linebuf");
- y >>= 1;
+ y_size >>= 1;
- for (; y > 0; y--) {
- memcpy(line, top, x * sizeof(int));
- memcpy(top, bottom, x * sizeof(int));
- memcpy(bottom, line, x * sizeof(int));
- bottom -= x;
- top += x;
+ for (; y_size > 0; y_size--) {
+ memcpy(line, top, stride);
+ memcpy(top, bottom, stride);
+ memcpy(bottom, line, stride);
+ bottom -= x_size;
+ top += x_size;
}
MEM_freeN(line);
@@ -64,21 +66,23 @@ void IMB_flipy(struct ImBuf *ibuf)
if (ibuf->rect_float) {
float *topf = NULL, *bottomf = NULL, *linef = NULL;
- x = ibuf->x;
- y = ibuf->y;
+ x_size = ibuf->x;
+ y_size = ibuf->y;
+
+ const size_t stride = x_size * 4 * sizeof(float);
topf = ibuf->rect_float;
- bottomf = topf + 4 * ((y - 1) * x);
- linef = MEM_mallocN(4 * x * sizeof(float), "linebuff");
+ bottomf = topf + 4 * ((y_size - 1) * x_size);
+ linef = MEM_mallocN(stride, "linebuf");
- y >>= 1;
+ y_size >>= 1;
- for (; y > 0; y--) {
- memcpy(linef, topf, 4 * x * sizeof(float));
- memcpy(topf, bottomf, 4 * x * sizeof(float));
- memcpy(bottomf, linef, 4 * x * sizeof(float));
- bottomf -= 4 * x;
- topf += 4 * x;
+ for (; y_size > 0; y_size--) {
+ memcpy(linef, topf, stride);
+ memcpy(topf, bottomf, stride);
+ memcpy(bottomf, linef, stride);
+ bottomf -= 4 * x_size;
+ topf += 4 * x_size;
}
MEM_freeN(linef);
@@ -99,20 +103,22 @@ void IMB_flipx(struct ImBuf *ibuf)
if (ibuf->rect) {
for (yi = y - 1; yi >= 0; yi--) {
+ const size_t x_offset = (size_t)x * yi;
for (xr = x - 1, xl = 0; xr >= xl; xr--, xl++) {
- SWAP(unsigned int, ibuf->rect[(x * yi) + xr], ibuf->rect[(x * yi) + xl]);
+ SWAP(unsigned int, ibuf->rect[x_offset + xr], ibuf->rect[x_offset + xl]);
}
}
}
if (ibuf->rect_float) {
for (yi = y - 1; yi >= 0; yi--) {
+ const size_t x_offset = (size_t)x * yi;
for (xr = x - 1, xl = 0; xr >= xl; xr--, xl++) {
- memcpy(&px_f, &ibuf->rect_float[((x * yi) + xr) * 4], sizeof(float[4]));
- memcpy(&ibuf->rect_float[((x * yi) + xr) * 4],
- &ibuf->rect_float[((x * yi) + xl) * 4],
+ memcpy(&px_f, &ibuf->rect_float[(x_offset + xr) * 4], sizeof(float[4]));
+ memcpy(&ibuf->rect_float[(x_offset + xr) * 4],
+ &ibuf->rect_float[(x_offset + xl) * 4],
sizeof(float[4]));
- memcpy(&ibuf->rect_float[((x * yi) + xl) * 4], &px_f, sizeof(float[4]));
+ memcpy(&ibuf->rect_float[(x_offset + xl) * 4], &px_f, sizeof(float[4]));
}
}
}
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 1c4b7af6ef1..a18ba6748de 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -372,7 +372,6 @@ MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsign
}
}
-/* result in ibuf2, scaling should be done correctly */
void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
{
int x, y;
@@ -912,7 +911,7 @@ static ImBuf *scaledownx(struct ImBuf *ibuf, int newx)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1053,7 +1052,7 @@ static ImBuf *scaledowny(struct ImBuf *ibuf, int newy)
{
const int do_rect = (ibuf->rect != NULL);
const int do_float = (ibuf->rect_float != NULL);
- const size_t rect_size = ibuf->x * ibuf->y * 4;
+ const size_t rect_size = IMB_get_rect_len(ibuf) * 4;
uchar *rect, *_newrect, *newrect;
float *rectf, *_newrectf, *newrectf;
@@ -1661,9 +1660,6 @@ static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy)
}
}
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
@@ -1709,9 +1705,6 @@ struct imbufRGBA {
float r, g, b, a;
};
-/**
- * Return true if \a ibuf is modified.
- */
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
{
BLI_assert_msg(newx > 0 && newy > 0, "Images must be at least 1 on both dimensions!");
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index d3c91b55f22..dae2604802f 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -757,7 +757,6 @@ float *IMB_stereo3d_from_rectf(ImageFormatData *im_format,
return r_rectf;
}
-/* left/right are always float */
ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
{
ImBuf *ibuf_stereo = NULL;
@@ -1275,7 +1274,6 @@ static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
/** \name Preparing To Call The Read Functions
* \{ */
-/* reading a stereo encoded ibuf (*left) and generating two ibufs from it (*left and *right) */
void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d,
ImBuf *ibuf_stereo3d,
ImBuf **r_ibuf_left,
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index aa1da65253d..c39ce2e9a2a 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -523,7 +523,6 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
}
-/* read thumbnail for file and returns new imbuf for thumbnail */
ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -540,7 +539,6 @@ ImBuf *IMB_thumb_read(const char *path, ThumbSize size)
return img;
}
-/* delete all thumbs for the file */
void IMB_thumb_delete(const char *path, ThumbSize size)
{
char thumb[FILE_MAX];
@@ -559,7 +557,6 @@ void IMB_thumb_delete(const char *path, ThumbSize size)
}
}
-/* create the thumb if necessary and manage failed and old thumbs */
ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index d9e1db27ef0..1d3589f00a6 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -29,7 +29,7 @@
* high-level routine that loads all images as 32-bit RGBA, handling all the
* required conversions between many different TIFF types internally.
*
- * Saving supports RGB, RGBA and BW (grayscale) images correctly, with
+ * Saving supports RGB, RGBA and BW (gray-scale) images correctly, with
* 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
@@ -52,7 +52,7 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-#include "tiffio.h"
+#include <tiffio.h>
#ifdef WIN32
# include "utfconv.h"
@@ -457,7 +457,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
}
/* simple RGBA image */
- if (!(bitspersample == 32 || bitspersample == 16)) {
+ if (!(ELEM(bitspersample, 32, 16))) {
success |= TIFFReadRGBAImage(image, ibuf->x, ibuf->y, tmpibuf->rect, 0);
}
/* contiguous channels: RGBRGBRGB */
@@ -488,7 +488,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_fl(fbuf, ibuf->x, 1.0f);
}
- else if (chan >= spp) { /* for grayscale, duplicate first channel into G and B */
+ else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
@@ -500,7 +500,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_ushort(sbuf, ibuf->x, 65535);
}
- else if (chan >= spp) { /* for grayscale, duplicate first channel into G and B */
+ else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
@@ -553,15 +553,6 @@ void imb_inittiff(void)
}
}
-/**
- * Loads a TIFF file.
- * \param mem: Memory containing the TIFF file.
- * \param size: Size of the mem buffer.
- * \param flags: If flags has IB_test set then the file is not actually loaded,
- * but all other operations take place.
- *
- * \return A newly allocated #ImBuf structure if successful, otherwise NULL.
- */
ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
@@ -744,21 +735,6 @@ void imb_loadtiletiff(
/** \name Save TIFF
* \{ */
-/**
- * Saves a TIFF file.
- *
- * #ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
- * respectively) are accepted, and interpreted correctly. Note that the TIFF
- * convention is to use pre-multiplied alpha, which can be achieved within
- * Blender by setting "Premul" alpha handling. Other alpha conventions are
- * not strictly correct, but are permitted anyhow.
- *
- * \param ibuf: Image buffer.
- * \param name: Name of the TIFF file to create.
- * \param flags: Currently largely ignored.
- *
- * \return 1 if the function is successful, 0 on failure.
- */
bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
{
TIFF *image = NULL;
@@ -872,7 +848,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
}
else if (samplesperpixel == 1) {
- /* grayscale images, 1 channel */
+ /* Gray-scale images, 1 channel */
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
@@ -895,9 +871,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
copy_v3_v3(rgb, &fromf[from_i]);
}
else {
- /* Standard linear-to-srgb conversion if float buffer
- * wasn't managed.
- */
+ /* Standard linear-to-SRGB conversion if float buffer wasn't managed. */
linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]);
}
if (channels_in_float == 4) {
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
new file mode 100644
index 00000000000..e1c451a8412
--- /dev/null
+++ b/source/blender/imbuf/intern/transform.cc
@@ -0,0 +1,604 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup imbuf
+ */
+
+#include <array>
+#include <type_traits>
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+namespace blender::imbuf::transform {
+
+struct TransformUserData {
+ /** \brief Source image buffer to read from. */
+ const ImBuf *src;
+ /** \brief Destination image buffer to write to. */
+ ImBuf *dst;
+ /** \brief UV coordinates at the origin (0,0) in source image space. */
+ float start_uv[2];
+
+ /**
+ * \brief delta UV coordinates along the source image buffer, when moving a single pixel in the X
+ * axis of the dst image buffer.
+ */
+ float add_x[2];
+
+ /**
+ * \brief delta UV coordinate along the source image buffer, when moving a single pixel in the Y
+ * axes of the dst image buffer.
+ */
+ float add_y[2];
+
+ /**
+ * \brief Cropping region in source image pixel space.
+ */
+ rctf src_crop;
+
+ /**
+ * \brief Initialize the start_uv, add_x and add_y fields based on the given transform matrix.
+ */
+ void init(const float transform_matrix[4][4])
+ {
+ init_start_uv(transform_matrix);
+ init_add_x(transform_matrix);
+ init_add_y(transform_matrix);
+ }
+
+ private:
+ void init_start_uv(const float transform_matrix[4][4])
+ {
+ float start_uv_v3[3];
+ float orig[3];
+ zero_v3(orig);
+ mul_v3_m4v3(start_uv_v3, transform_matrix, orig);
+ copy_v2_v2(start_uv, start_uv_v3);
+ }
+
+ void init_add_x(const float transform_matrix[4][4])
+ {
+ const int width = src->x;
+ float add_x_v3[3];
+ float uv_max_x[3];
+ zero_v3(uv_max_x);
+ uv_max_x[0] = width;
+ uv_max_x[1] = 0.0f;
+ mul_v3_m4v3(add_x_v3, transform_matrix, uv_max_x);
+ sub_v2_v2(add_x_v3, start_uv);
+ mul_v2_fl(add_x_v3, 1.0f / width);
+ copy_v2_v2(add_x, add_x_v3);
+ }
+
+ void init_add_y(const float transform_matrix[4][4])
+ {
+ const int height = src->y;
+ float add_y_v3[3];
+ float uv_max_y[3];
+ zero_v3(uv_max_y);
+ uv_max_y[0] = 0.0f;
+ uv_max_y[1] = height;
+ mul_v3_m4v3(add_y_v3, transform_matrix, uv_max_y);
+ sub_v2_v2(add_y_v3, start_uv);
+ mul_v2_fl(add_y_v3, 1.0f / height);
+ copy_v2_v2(add_y, add_y_v3);
+ }
+};
+
+/**
+ * \brief Base class for source discarding.
+ *
+ * The class decides if a specific uv coordinate from the source buffer should be ignored.
+ * This is used to mix multiple images over a single output buffer. Discarded pixels will
+ * not change the output buffer.
+ */
+class BaseDiscard {
+ public:
+ virtual ~BaseDiscard() = default;
+
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ */
+ virtual bool should_discard(const TransformUserData &user_data, const float uv[2]) = 0;
+};
+
+/**
+ * \brief Crop uv-coordinates that are outside the user data src_crop rect.
+ */
+class CropSource : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Uses user_data.src_crop to determine if the uv coordinate should be skipped.
+ */
+ bool should_discard(const TransformUserData &user_data, const float uv[2]) override
+ {
+ return uv[0] < user_data.src_crop.xmin || uv[0] >= user_data.src_crop.xmax ||
+ uv[1] < user_data.src_crop.ymin || uv[1] >= user_data.src_crop.ymax;
+ }
+};
+
+/**
+ * \brief Discard that does not discard anything.
+ */
+class NoDiscard : public BaseDiscard {
+ public:
+ /**
+ * \brief Should the source pixel at the given uv coordinate be discarded.
+ *
+ * Will never discard any pixels.
+ */
+ bool should_discard(const TransformUserData &UNUSED(user_data),
+ const float UNUSED(uv[2])) override
+ {
+ return false;
+ }
+};
+
+/**
+ * \brief Pointer to a pixel to write to in serial.
+ */
+template<
+ /**
+ * \brief Kind of buffer.
+ * Possible options: float, unsigned char.
+ */
+ typename StorageType = float,
+
+ /**
+ * \brief Number of channels of a single pixel.
+ */
+ int NumChannels = 4>
+class PixelPointer {
+ public:
+ static const int ChannelLen = NumChannels;
+
+ private:
+ StorageType *pointer;
+
+ public:
+ void init_pixel_pointer(const ImBuf *image_buffer, int x, int y)
+ {
+ const size_t offset = (y * (size_t)image_buffer->x + x) * NumChannels;
+
+ if constexpr (std::is_same_v<StorageType, float>) {
+ pointer = image_buffer->rect_float + offset;
+ }
+ else if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ pointer = const_cast<unsigned char *>(
+ static_cast<const unsigned char *>(static_cast<const void *>(image_buffer->rect)) +
+ offset);
+ }
+ else {
+ pointer = nullptr;
+ }
+ }
+
+ /**
+ * \brief Get pointer to the current pixel to write to.
+ */
+ StorageType *get_pointer()
+ {
+ return pointer;
+ }
+
+ void increase_pixel_pointer()
+ {
+ pointer += NumChannels;
+ }
+};
+
+/**
+ * \brief Wrapping mode for the uv coordinates.
+ *
+ * Subclasses have the ability to change the UV coordinates when sampling the source buffer.
+ */
+class BaseUVWrapping {
+ public:
+ /**
+ * \brief modify the given u coordinate.
+ */
+ virtual float modify_u(const ImBuf *source_buffer, float u) = 0;
+
+ /**
+ * \brief modify the given v coordinate.
+ */
+ virtual float modify_v(const ImBuf *source_buffer, float v) = 0;
+};
+
+/**
+ * \brief UVWrapping method that does not modify the UV coordinates.
+ */
+class PassThroughUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *UNUSED(source_buffer), float u) override
+ {
+ return u;
+ }
+
+ float modify_v(const ImBuf *UNUSED(source_buffer), float v) override
+ {
+ return v;
+ }
+};
+
+/**
+ * \brief UVWrapping method that wrap repeats the UV coordinates.
+ */
+class WrapRepeatUV : public BaseUVWrapping {
+ public:
+ float modify_u(const ImBuf *source_buffer, float u) override
+
+ {
+ int x = (int)floor(u);
+ x = x % source_buffer->x;
+ if (x < 0) {
+ x += source_buffer->x;
+ }
+ return x;
+ }
+
+ float modify_v(const ImBuf *source_buffer, float v) override
+ {
+ int y = (int)floor(v);
+ y = y % source_buffer->y;
+ if (y < 0) {
+ y += source_buffer->y;
+ }
+ return y;
+ }
+};
+
+/**
+ * \brief Read a sample from an image buffer.
+ *
+ * A sampler can read from an image buffer.
+ *
+ */
+template<
+ /** \brief Interpolation mode to use when sampling. */
+ eIMBInterpolationFilterMode Filter,
+
+ /** \brief storage type of a single pixel channel (unsigned char or float). */
+ typename StorageType,
+ /**
+ * \brief number of channels if the image to read.
+ *
+ * Must match the actual channels of the image buffer that is sampled.
+ */
+ int NumChannels,
+ /**
+ * \brief Wrapping method to perform
+ *
+ * Should be a subclass of BaseUVWrapper
+ */
+ typename UVWrapping>
+class Sampler {
+ UVWrapping uv_wrapper;
+
+ public:
+ using ChannelType = StorageType;
+ static const int ChannelLen = NumChannels;
+ using SampleType = std::array<StorageType, NumChannels>;
+
+ void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
+ {
+ if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
+ NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR &&
+ std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
+ }
+ else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
+ if constexpr (std::is_same_v<UVWrapping, WrapRepeatUV>) {
+ BLI_bilinear_interpolation_wrap_fl(
+ source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
+ }
+ else {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ BLI_bilinear_interpolation_fl(source->rect_float,
+ &r_sample[0],
+ source->x,
+ source->y,
+ NumChannels,
+ wrapped_u,
+ wrapped_v);
+ }
+ }
+ else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
+ sample_nearest_float(source, wrapped_u, wrapped_v, r_sample);
+ }
+ else {
+ /* Unsupported sampler. */
+ BLI_assert_unreachable();
+ }
+ }
+
+ private:
+ void sample_nearest_float(const ImBuf *source,
+ const float u,
+ const float v,
+ SampleType &r_sample)
+ {
+ BLI_STATIC_ASSERT(std::is_same_v<StorageType, float>);
+
+ /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
+ int x1 = (int)(u);
+ int y1 = (int)(v);
+
+ /* Break when sample outside image is requested. */
+ if (x1 < 0 || x1 >= source->x || y1 < 0 || y1 >= source->y) {
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = 0.0f;
+ }
+ return;
+ }
+
+ const size_t offset = ((size_t)source->x * y1 + x1) * NumChannels;
+ const float *dataF = source->rect_float + offset;
+ for (int i = 0; i < NumChannels; i++) {
+ r_sample[i] = dataF[i];
+ }
+ }
+};
+
+/**
+ * \brief Change the number of channels and store it.
+ *
+ * Template class to convert and store a sample in a PixelPointer.
+ * It supports:
+ * - 4 channel unsigned char -> 4 channel unsigned char.
+ * - 4 channel float -> 4 channel float.
+ * - 3 channel float -> 4 channel float.
+ * - 2 channel float -> 4 channel float.
+ * - 1 channel float -> 4 channel float.
+ */
+template<typename StorageType, int SourceNumChannels, int DestinationNumChannels>
+class ChannelConverter {
+ public:
+ using SampleType = std::array<StorageType, SourceNumChannels>;
+ using PixelType = PixelPointer<StorageType, DestinationNumChannels>;
+
+ /**
+ * \brief Convert the number of channels of the given sample to match the pixel pointer and store
+ * it at the location the pixel_pointer points at.
+ */
+ void convert_and_store(const SampleType &sample, PixelType &pixel_pointer)
+ {
+ if constexpr (std::is_same_v<StorageType, unsigned char>) {
+ BLI_STATIC_ASSERT(SourceNumChannels == 4, "Unsigned chars always have 4 channels.");
+ BLI_STATIC_ASSERT(DestinationNumChannels == 4, "Unsigned chars always have 4 channels.");
+
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
+ DestinationNumChannels == 4) {
+ copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], sample[2], 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 2 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[1], 0.0f, 1.0f);
+ }
+ else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 1 &&
+ DestinationNumChannels == 4) {
+ copy_v4_fl4(pixel_pointer.get_pointer(), sample[0], sample[0], sample[0], 1.0f);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ }
+};
+
+/**
+ * \brief Processor for a scanline.
+ */
+template<
+ /**
+ * \brief Discard function to use.
+ *
+ * \attention Should be a subclass of BaseDiscard.
+ */
+ typename Discard,
+
+ /**
+ * \brief Color interpolation function to read from the source buffer.
+ */
+ typename Sampler,
+
+ /**
+ * \brief Kernel to store to the destination buffer.
+ * Should be an PixelPointer
+ */
+ typename OutputPixelPointer>
+class ScanlineProcessor {
+ Discard discarder;
+ OutputPixelPointer output;
+ Sampler sampler;
+
+ /**
+ * \brief Channels sizzling logic to convert between the input image buffer and the output image
+ * buffer.
+ */
+ ChannelConverter<typename Sampler::ChannelType,
+ Sampler::ChannelLen,
+ OutputPixelPointer::ChannelLen>
+ channel_converter;
+
+ public:
+ /**
+ * \brief Inner loop of the transformations, processing a full scanline.
+ */
+ void process(const TransformUserData *user_data, int scanline)
+ {
+ const int width = user_data->dst->x;
+
+ float uv[2];
+ madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
+
+ output.init_pixel_pointer(user_data->dst, 0, scanline);
+ for (int xi = 0; xi < width; xi++) {
+ if (!discarder.should_discard(*user_data, uv)) {
+ typename Sampler::SampleType sample;
+ sampler.sample(user_data->src, uv[0], uv[1], sample);
+ channel_converter.convert_and_store(sample, output);
+ }
+
+ add_v2_v2(uv, user_data->add_x);
+ output.increase_pixel_pointer();
+ }
+ }
+};
+
+/**
+ * \brief callback function for threaded transformation.
+ */
+template<typename Processor> void transform_scanline_function(void *custom_data, int scanline)
+{
+ const TransformUserData *user_data = static_cast<const TransformUserData *>(custom_data);
+ Processor processor;
+ processor.process(user_data, scanline);
+}
+
+template<eIMBInterpolationFilterMode Filter,
+ typename StorageType,
+ int SourceNumChannels,
+ int DestinationNumChannels>
+ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
+
+{
+ switch (mode) {
+ case IMB_TRANSFORM_MODE_REGULAR:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_CROP_SRC:
+ return transform_scanline_function<
+ ScanlineProcessor<CropSource,
+ Sampler<Filter, StorageType, SourceNumChannels, PassThroughUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ case IMB_TRANSFORM_MODE_WRAP_REPEAT:
+ return transform_scanline_function<
+ ScanlineProcessor<NoDiscard,
+ Sampler<Filter, StorageType, SourceNumChannels, WrapRepeatUV>,
+ PixelPointer<StorageType, DestinationNumChannels>>>;
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+ScanlineThreadFunc get_scanline_function(const TransformUserData *user_data,
+ const eIMBTransformMode mode)
+{
+ const ImBuf *src = user_data->src;
+ const ImBuf *dst = user_data->dst;
+
+ if (src->channels == 4 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 4, 4>(mode);
+ }
+ if (src->channels == 3 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 3, 4>(mode);
+ }
+ if (src->channels == 2 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 2, 4>(mode);
+ }
+ if (src->channels == 1 && dst->channels == 4) {
+ return get_scanline_function<Filter, float, 1, 4>(mode);
+ }
+ return nullptr;
+}
+
+template<eIMBInterpolationFilterMode Filter>
+static void transform_threaded(TransformUserData *user_data, const eIMBTransformMode mode)
+{
+ ScanlineThreadFunc scanline_func = nullptr;
+
+ if (user_data->dst->rect_float && user_data->src->rect_float) {
+ scanline_func = get_scanline_function<Filter>(user_data, mode);
+ }
+ else if (user_data->dst->rect && user_data->src->rect) {
+ /* Number of channels is always 4 when using unsigned char buffers (sRGB + straight alpha). */
+ scanline_func = get_scanline_function<Filter, unsigned char, 4, 4>(mode);
+ }
+
+ if (scanline_func != nullptr) {
+ IMB_processor_apply_threaded_scanlines(user_data->dst->y, scanline_func, user_data);
+ }
+}
+
+} // namespace blender::imbuf::transform
+
+extern "C" {
+
+using namespace blender::imbuf::transform;
+
+void IMB_transform(const struct ImBuf *src,
+ struct ImBuf *dst,
+ const eIMBTransformMode mode,
+ const eIMBInterpolationFilterMode filter,
+ const float transform_matrix[4][4],
+ const struct rctf *src_crop)
+{
+ BLI_assert_msg(mode != IMB_TRANSFORM_MODE_CROP_SRC || src_crop != nullptr,
+ "No source crop rect given, but crop source is requested. Or source crop rect "
+ "was given, but crop source was not requested.");
+
+ TransformUserData user_data;
+ user_data.src = src;
+ user_data.dst = dst;
+ if (mode == IMB_TRANSFORM_MODE_CROP_SRC) {
+ user_data.src_crop = *src_crop;
+ }
+ user_data.init(transform_matrix);
+
+ if (filter == IMB_FILTER_NEAREST) {
+ transform_threaded<IMB_FILTER_NEAREST>(&user_data, mode);
+ }
+ else {
+ transform_threaded<IMB_FILTER_BILINEAR>(&user_data, mode);
+ }
+}
+}
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 1bb047f1317..18ed4710e78 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -98,7 +98,7 @@ const char *imb_ext_movie[] = {
".mpg2", ".vob", ".mkv", ".flv", ".divx", ".xvid", ".mxf", ".webm", NULL,
};
-/* sort of wrong being here... */
+/** Sort of wrong having audio extensions in imbuf. */
const char *imb_ext_audio[] = {
".wav",
".ogg",
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 2b99a0aa81d..cc6fef634d5 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -162,8 +162,6 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
return data_rect;
}
-/* The ibuf is only here to detect the storage type. The produced texture will have undefined
- * content. It will need to be populated by using IMB_update_gpu_texture_sub(). */
GPUTexture *IMB_touch_gpu_texture(
const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
{
@@ -183,9 +181,6 @@ GPUTexture *IMB_touch_gpu_texture(
return tex;
}
-/* Will update a GPUTexture using the content of the ImBuf. Only one layer will be updated.
- * Will resize the ibuf if needed.
- * z is the layer to update. Unused if the texture is 2D. */
void IMB_update_gpu_texture_sub(GPUTexture *tex,
ImBuf *ibuf,
int x,