From 8530e48f8692f4b92c43489029f2d2ef67c7cb62 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 18 Mar 2022 21:28:04 +0100 Subject: Cleanup: move render image and multilayer EXR write code to image_save.cc These share a lot of logic with regular image saving and should be unified more in the future. --- source/blender/blenkernel/BKE_image.h | 6 +- source/blender/blenkernel/BKE_image_save.h | 20 ++ source/blender/blenkernel/BKE_scene.h | 2 +- source/blender/blenkernel/intern/image.cc | 12 +- source/blender/blenkernel/intern/image_save.cc | 336 ++++++++++++++++++++++++- source/blender/blenkernel/intern/scene.c | 4 +- source/blender/editors/render/render_opengl.cc | 11 +- source/blender/imbuf/IMB_colormanagement.h | 2 +- source/blender/imbuf/IMB_imbuf.h | 8 +- source/blender/imbuf/intern/colormanagement.c | 2 +- source/blender/imbuf/intern/stereoimbuf.c | 42 ++-- source/blender/render/RE_pipeline.h | 31 +-- source/blender/render/intern/pipeline.c | 171 +------------ source/blender/render/intern/render_result.c | 199 ++------------- source/blender/render/intern/render_result.h | 1 - 15 files changed, 433 insertions(+), 414 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 7b3124cca26..fba2512fa49 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -64,7 +64,7 @@ struct StampData *BKE_stamp_info_from_scene_static(const struct Scene *scene); * Check whether the given metadata field name translates to a known field of a stamp. */ bool BKE_stamp_is_known_field(const char *field_name); -void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf); +void BKE_imbuf_stamp_info(const struct RenderResult *rr, struct ImBuf *ibuf); void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf); void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, @@ -82,8 +82,8 @@ void BKE_image_stamp_buf(struct Scene *scene, int height, int channels); bool BKE_imbuf_alpha_test(struct ImBuf *ibuf); -int BKE_imbuf_write_stamp(struct Scene *scene, - struct RenderResult *rr, +int BKE_imbuf_write_stamp(const struct Scene *scene, + const struct RenderResult *rr, struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf); diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h index dea1c25cd5e..f9d07387463 100644 --- a/source/blender/blenkernel/BKE_image_save.h +++ b/source/blender/blenkernel/BKE_image_save.h @@ -16,6 +16,9 @@ struct Image; struct Main; struct ReportList; struct Scene; +struct RenderResult; + +/* Image datablock saving. */ typedef struct ImageSaveOptions { /* Context within which image is saved. */ @@ -44,6 +47,23 @@ bool BKE_image_save(struct ReportList *reports, struct ImageUser *iuser, struct ImageSaveOptions *opts); +/* Lower level image writing. */ + +/* Save single or multilayer OpenEXR files from the render result. + * Optionally saves only a specific view or layer. */ +bool BKE_image_render_write_exr(struct ReportList *reports, + const struct RenderResult *rr, + const char *filename, + const struct ImageFormatData *imf, + const char *view, + int layer); + +bool BKE_image_render_write(struct ReportList *reports, + struct RenderResult *rr, + const struct Scene *scene, + const bool stamp, + const char *name); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index d06b1d43b96..8c50a89ec90 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -282,7 +282,7 @@ struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct R int view_id); const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, int view_id); int BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname); -void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv, +void BKE_scene_multiview_filepath_get(const struct SceneRenderView *srv, const char *filepath, char *r_filepath); /** diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index 51ffd3338c4..f8fb2ec7e45 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -2343,9 +2343,9 @@ static void metadata_get_field(void *data, const char *propname, char *propvalue IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len); } -void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf) +void BKE_imbuf_stamp_info(const RenderResult *rr, ImBuf *ibuf) { - struct StampData *stamp_data = rr->stamp_data; + StampData *stamp_data = const_cast(rr->stamp_data); IMB_metadata_ensure(&ibuf->metadata); BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false); } @@ -2359,12 +2359,12 @@ static void metadata_copy_custom_fields(const char *field, const char *value, vo BKE_render_result_stamp_data(rr, field, value); } -void BKE_stamp_info_from_imbuf(RenderResult *rr, struct ImBuf *ibuf) +void BKE_stamp_info_from_imbuf(RenderResult *rr, ImBuf *ibuf) { if (rr->stamp_data == nullptr) { rr->stamp_data = MEM_cnew("RenderResult.stamp_data"); } - struct StampData *stamp_data = rr->stamp_data; + StampData *stamp_data = rr->stamp_data; IMB_metadata_ensure(&ibuf->metadata); BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true); /* Copy render engine specific settings. */ @@ -2428,8 +2428,8 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, cons return ok; } -int BKE_imbuf_write_stamp(Scene *scene, - struct RenderResult *rr, +int BKE_imbuf_write_stamp(const Scene *scene, + const struct RenderResult *rr, ImBuf *ibuf, const char *name, const struct ImageFormatData *imf) diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 180008e0f64..fdeb5eedcde 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -20,6 +20,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "intern/openexr/openexr_multi.h" + #include "BKE_colortools.h" #include "BKE_image.h" #include "BKE_image_format.h" @@ -219,14 +221,14 @@ static bool image_save_single(ReportList *reports, /* fancy multiview OpenEXR */ if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { /* save render result */ - ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, NULL, layer); image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); BKE_image_release_ibuf(ima, ibuf, lock); } /* regular mono pipeline */ else if (is_mono) { if (is_exr_rr) { - ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, NULL, layer); } else { colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( @@ -261,7 +263,7 @@ static bool image_save_single(ReportList *reports, if (is_exr_rr) { BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); - ok_view = RE_WriteRenderResult(reports, rr, filepath, imf, view, layer); + ok_view = BKE_image_render_write_exr(reports, rr, filepath, imf, view, layer); image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed); } else { @@ -308,7 +310,7 @@ static bool image_save_single(ReportList *reports, /* stereo (multiview) images */ else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) { if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) { - ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, NULL, layer); image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); BKE_image_release_ibuf(ima, ibuf, lock); } @@ -449,3 +451,329 @@ bool BKE_image_save( return ok; } + +/* OpenEXR saving, single and multilayer. */ + +bool BKE_image_render_write_exr(ReportList *reports, + const RenderResult *rr, + const char *filename, + const ImageFormatData *imf, + const char *view, + int layer) +{ + void *exrhandle = IMB_exr_get_handle(); + const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16); + const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR); + const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF)); + + /* Write first layer if not multilayer and no layer was specified. */ + if (!multi_layer && layer == -1) { + layer = 0; + } + + /* First add views since IMB_exr_add_channel checks number of views. */ + const RenderView *first_rview = (const RenderView *)rr->views.first; + if (first_rview && (first_rview->next || first_rview->name[0])) { + LISTBASE_FOREACH (RenderView *, rview, &rr->views) { + if (!view || STREQ(view, rview->name)) { + IMB_exr_add_view(exrhandle, rview->name); + } + } + } + + /* Compositing result. */ + if (rr->have_combined) { + LISTBASE_FOREACH (RenderView *, rview, &rr->views) { + if (!rview->rectf) { + continue; + } + + const char *viewname = rview->name; + if (view) { + if (!STREQ(view, viewname)) { + continue; + } + + viewname = ""; + } + + /* Skip compositing if only a single other layer is requested. */ + if (!multi_layer && layer != 0) { + continue; + } + + float *output_rect = rview->rectf; + + for (int a = 0; a < 4; a++) { + char passname[EXR_PASS_MAXNAME]; + char layname[EXR_PASS_MAXNAME]; + const char *chan_id = "RGBA"; + + if (multi_layer) { + IMB_exr_channel_name(passname, NULL, "Combined", NULL, chan_id, a); + BLI_strncpy(layname, "Composite", sizeof(layname)); + } + else { + passname[0] = chan_id[a]; + passname[1] = '\0'; + layname[0] = '\0'; + } + + IMB_exr_add_channel( + exrhandle, layname, passname, viewname, 4, 4 * rr->rectx, output_rect + a, half_float); + } + + if (write_z && rview->rectz) { + const char *layname = (multi_layer) ? "Composite" : ""; + IMB_exr_add_channel(exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->rectz, false); + } + } + } + + /* Other render layers. */ + int nr = (rr->have_combined) ? 1 : 0; + LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) { + /* Skip other render layers if requested. */ + if (!multi_layer && nr != layer) { + continue; + } + + LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) { + /* Skip non-RGBA and Z passes if not using multi layer. */ + if (!multi_layer && !(STREQ(rp->name, RE_PASSNAME_COMBINED) || STREQ(rp->name, "") || + (STREQ(rp->name, RE_PASSNAME_Z) && write_z))) { + continue; + } + + /* Skip pass if it does not match the requested view(s). */ + const char *viewname = rp->view; + if (view) { + if (!STREQ(view, viewname)) { + continue; + } + + viewname = ""; + } + + /* We only store RGBA passes as half float, for + * others precision loss can be problematic. */ + const bool pass_RGBA = (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A")); + const bool pass_half_float = half_float && pass_RGBA; + + float *output_rect = rp->rect; + + for (int a = 0; a < rp->channels; a++) { + /* Save Combined as RGBA if single layer save. */ + char passname[EXR_PASS_MAXNAME]; + char layname[EXR_PASS_MAXNAME]; + + if (multi_layer) { + IMB_exr_channel_name(passname, NULL, rp->name, NULL, rp->chan_id, a); + BLI_strncpy(layname, rl->name, sizeof(layname)); + } + else { + passname[0] = rp->chan_id[a]; + passname[1] = '\0'; + layname[0] = '\0'; + } + + IMB_exr_add_channel(exrhandle, + layname, + passname, + viewname, + rp->channels, + rp->channels * rr->rectx, + output_rect + a, + pass_half_float); + } + } + } + + errno = 0; + + BLI_make_existing_file(filename); + + int compress = (imf ? imf->exr_codec : 0); + bool success = IMB_exr_begin_write( + exrhandle, filename, rr->rectx, rr->recty, compress, rr->stamp_data); + if (success) { + IMB_exr_write_channels(exrhandle); + } + else { + /* TODO: get the error from openexr's exception. */ + BKE_reportf( + reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno)); + } + + IMB_exr_close(exrhandle); + return success; +} + +/* Render output. */ + +static void image_render_print_save_message(ReportList *reports, const char *name, int ok, int err) +{ + if (ok) { + /* no need to report, just some helpful console info */ + printf("Saved: '%s'\n", name); + } + else { + /* report on error since users will want to know what failed */ + BKE_reportf(reports, RPT_ERROR, "Render error (%s) cannot save: '%s'", strerror(err), name); + } +} + +static int image_render_write_stamp_test(ReportList *reports, + const Scene *scene, + const RenderResult *rr, + ImBuf *ibuf, + const char *name, + const ImageFormatData *imf, + const bool stamp) +{ + int ok; + + if (stamp) { + /* writes the name of the individual cameras */ + ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, imf); + } + else { + ok = BKE_imbuf_write(ibuf, name, imf); + } + + image_render_print_save_message(reports, name, ok, errno); + + return ok; +} + +bool BKE_image_render_write(ReportList *reports, + RenderResult *rr, + const Scene *scene, + const bool stamp, + const char *filename) +{ + bool ok = true; + const RenderData *rd = &scene->r; + + if (!rr) { + return false; + } + + const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; + const bool is_exr_rr = ELEM(rd->im_format.imtype, + R_IMF_IMTYPE_OPENEXR, + R_IMF_IMTYPE_MULTILAYER) && + RE_HasFloatPixels(rr); + const float dither = scene->r.dither_intensity; + + if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { + ok = BKE_image_render_write_exr(reports, rr, filename, &rd->im_format, NULL, -1); + image_render_print_save_message(reports, filename, ok, errno); + } + + /* mono, legacy code */ + else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { + int view_id = 0; + for (const RenderView *rv = (const RenderView *)rr->views.first; rv; + rv = rv->next, view_id++) { + char filepath[FILE_MAX]; + if (is_mono) { + STRNCPY(filepath, filename); + } + else { + BKE_scene_multiview_view_filepath_get(&scene->r, filename, rv->name, filepath); + } + + if (is_exr_rr) { + ok = BKE_image_render_write_exr(reports, rr, filepath, &rd->im_format, rv->name, -1); + image_render_print_save_message(reports, filepath, ok, errno); + + /* optional preview images for exr */ + if (ok && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + ImageFormatData imf = rd->im_format; + imf.imtype = R_IMF_IMTYPE_JPEG90; + + if (BLI_path_extension_check(filepath, ".exr")) { + filepath[strlen(filepath) - 4] = 0; + } + BKE_image_path_ensure_ext_from_imformat(filepath, &imf); + + ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &imf, dither, view_id); + ibuf->planes = 24; + IMB_colormanagement_imbuf_for_write( + ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf); + + ok = image_render_write_stamp_test(reports, scene, rr, ibuf, filepath, &imf, stamp); + + IMB_freeImBuf(ibuf); + } + } + else { + ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); + + IMB_colormanagement_imbuf_for_write( + ibuf, true, false, &scene->view_settings, &scene->display_settings, &rd->im_format); + + ok = image_render_write_stamp_test( + reports, scene, rr, ibuf, filepath, &rd->im_format, stamp); + + /* imbuf knows which rects are not part of ibuf */ + IMB_freeImBuf(ibuf); + } + } + } + else { /* R_IMF_VIEWS_STEREO_3D */ + BLI_assert(rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D); + + char filepath[FILE_MAX]; + STRNCPY(filepath, filename); + + if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { + printf("Stereo 3D not supported for MultiLayer image: %s\n", filepath); + } + else { + ImBuf *ibuf_arr[3] = {NULL}; + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + int i; + + for (i = 0; i < 2; i++) { + int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); + ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], + true, + false, + &scene->view_settings, + &scene->display_settings, + &rd->im_format); + IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]); + } + + ibuf_arr[2] = IMB_stereo3d_ImBuf(&rd->im_format, ibuf_arr[0], ibuf_arr[1]); + + ok = image_render_write_stamp_test( + reports, scene, rr, ibuf_arr[2], filepath, &rd->im_format, stamp); + + /* optional preview images for exr */ + if (ok && is_exr_rr && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + ImageFormatData imf = rd->im_format; + imf.imtype = R_IMF_IMTYPE_JPEG90; + + if (BLI_path_extension_check(filepath, ".exr")) { + filepath[strlen(filepath) - 4] = 0; + } + + BKE_image_path_ensure_ext_from_imformat(filepath, &imf); + ibuf_arr[2]->planes = 24; + + ok = image_render_write_stamp_test(reports, scene, rr, ibuf_arr[2], filepath, &imf, stamp); + } + + /* imbuf knows which rects are not part of ibuf */ + for (i = 0; i < 3; i++) { + IMB_freeImBuf(ibuf_arr[i]); + } + } + } + + return ok; +} diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 86d38064b2d..6797538d190 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -3123,7 +3123,9 @@ int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname) return 0; } -void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath, char *r_filepath) +void BKE_scene_multiview_filepath_get(const SceneRenderView *srv, + const char *filepath, + char *r_filepath) { BLI_strncpy(r_filepath, filepath, FILE_MAX); BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, ""); diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc index 872e2867696..fbdc1086874 100644 --- a/source/blender/editors/render/render_opengl.cc +++ b/source/blender/editors/render/render_opengl.cc @@ -35,6 +35,7 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_image_format.h" +#include "BKE_image_save.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_report.h" @@ -313,13 +314,13 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R imb_freerectfloatImBuf(out); } BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y)); - RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); + RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id); IMB_freeImBuf(out); } else if (gpd) { /* If there are no strips, Grease Pencil still needs a buffer to draw on */ ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect); - RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); + RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id); IMB_freeImBuf(out); } @@ -415,7 +416,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4); } - RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id); + RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id); IMB_freeImBuf(ibuf_result); } } @@ -440,7 +441,7 @@ static void screen_opengl_render_write(OGLRender *oglrender) /* write images as individual images or stereo */ BKE_render_result_stamp_info(scene, scene->camera, rr, false); - ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name); + ok = BKE_image_render_write(oglrender->reports, rr, scene, false, name); RE_ReleaseResultImage(oglrender->re); @@ -1071,7 +1072,7 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v) nullptr); BKE_render_result_stamp_info(scene, scene->camera, rr, false); - ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name); + ok = BKE_image_render_write(nullptr, rr, scene, true, name); if (!ok) { BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name); } diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 785fa2b198a..7434db732fd 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -244,7 +244,7 @@ struct ImBuf *IMB_colormanagement_imbuf_for_write( bool allocate_result, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, - struct ImageFormatData *image_format_data); + const struct ImageFormatData *image_format_data); void IMB_colormanagement_buffer_make_display_space( float *buffer, diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 8929a467670..0390df06052 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -965,13 +965,13 @@ 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, +int *IMB_stereo3d_from_rect(const struct ImageFormatData *im_format, size_t x, size_t y, size_t channels, int *rect_left, int *rect_right); -float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format, +float *IMB_stereo3d_from_rectf(const struct ImageFormatData *im_format, size_t x, size_t y, size_t channels, @@ -980,13 +980,13 @@ float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format, /** * Left/right are always float. */ -struct ImBuf *IMB_stereo3d_ImBuf(struct ImageFormatData *im_format, +struct ImBuf *IMB_stereo3d_ImBuf(const 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, +void IMB_ImBufFromStereo3d(const struct Stereo3dFormat *s3d, struct ImBuf *ibuf_stereo, struct ImBuf **r_ibuf_left, struct ImBuf **r_ibuf_right); diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index bf3e50b8870..e60df0ca1c9 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -2433,7 +2433,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool allocate_result, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, - ImageFormatData *image_format_data) + const ImageFormatData *image_format_data) { ImBuf *colormanaged_ibuf = ibuf; bool do_colormanagement; diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c index c081ffb981a..52756891f21 100644 --- a/source/blender/imbuf/intern/stereoimbuf.c +++ b/source/blender/imbuf/intern/stereoimbuf.c @@ -28,8 +28,10 @@ /* prototypes */ struct Stereo3DData; -static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d); -static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d); +static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data, + const struct Stereo3dFormat *s3d); +static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data, + const struct Stereo3dFormat *s3d); typedef struct Stereo3DData { struct { @@ -46,7 +48,7 @@ typedef struct Stereo3DData { /** \name Local Functions * \{ */ -static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode) +static void imb_stereo3d_write_anaglyph(const Stereo3DData *s3d, enum eStereo3dAnaglyphType mode) { int x, y; size_t width = s3d->x; @@ -144,7 +146,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp } } -static void imb_stereo3d_write_interlace(Stereo3DData *s3d, +static void imb_stereo3d_write_interlace(const Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap) { @@ -402,7 +404,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, } /* stereo3d output (s3d->rectf.stereo) is always unsqueezed */ -static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseyed) +static void imb_stereo3d_write_sidebyside(const Stereo3DData *s3d, const bool crosseyed) { int y; size_t width = s3d->x; @@ -450,7 +452,7 @@ static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseye } /* stereo3d output (s3d->rectf.stereo) is always unsqueezed */ -static void imb_stereo3d_write_topbottom(Stereo3DData *s3d) +static void imb_stereo3d_write_topbottom(const Stereo3DData *s3d) { int y; size_t width = s3d->x; @@ -565,7 +567,7 @@ void IMB_stereo3d_read_dimensions(const char mode, * \{ */ static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf, - Stereo3dFormat *s3d, + const Stereo3dFormat *s3d, const size_t x, const size_t y) { @@ -581,7 +583,7 @@ static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf, } static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf, - Stereo3dFormat *s3d, + const Stereo3dFormat *s3d, const size_t x, const size_t y) { @@ -597,7 +599,7 @@ static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf, } static void imb_stereo3d_squeeze_rectf( - float *rectf, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels) + float *rectf, const Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels) { ImBuf *ibuf; size_t width, height; @@ -631,7 +633,7 @@ static void imb_stereo3d_squeeze_rectf( } static void imb_stereo3d_squeeze_rect( - int *rect, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels) + int *rect, const Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels) { ImBuf *ibuf; size_t width, height; @@ -693,7 +695,7 @@ static void imb_stereo3d_data_init(Stereo3DData *s3d_data, s3d_data->rectf.stereo = rectf_stereo; } -int *IMB_stereo3d_from_rect(ImageFormatData *im_format, +int *IMB_stereo3d_from_rect(const ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels, @@ -717,7 +719,7 @@ int *IMB_stereo3d_from_rect(ImageFormatData *im_format, return r_rect; } -float *IMB_stereo3d_from_rectf(ImageFormatData *im_format, +float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format, const size_t x, const size_t y, const size_t channels, @@ -741,7 +743,7 @@ float *IMB_stereo3d_from_rectf(ImageFormatData *im_format, return r_rectf; } -ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right) +ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right) { ImBuf *ibuf_stereo = NULL; Stereo3DData s3d_data = {{NULL}}; @@ -776,7 +778,7 @@ ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *i return ibuf_stereo; } -static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d) +static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, const Stereo3dFormat *s3d) { switch (s3d->display_mode) { case S3D_DISPLAY_ANAGLYPH: @@ -803,7 +805,7 @@ static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d) /** \name Reading Stereo ImBuf's * \{ */ -static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode) +static void imb_stereo3d_read_anaglyph(const Stereo3DData *s3d, enum eStereo3dAnaglyphType mode) { int x, y; size_t width = s3d->x; @@ -901,7 +903,7 @@ static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyph } } -static void imb_stereo3d_read_interlace(Stereo3DData *s3d, +static void imb_stereo3d_read_interlace(const Stereo3DData *s3d, enum eStereo3dInterlaceType mode, const bool swap) { @@ -1159,7 +1161,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, } /* stereo input (s3d->rectf.stereo) is always unsqueezed */ -static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed) +static void imb_stereo3d_read_sidebyside(const Stereo3DData *s3d, const bool crosseyed) { int y; size_t width = s3d->x; @@ -1208,7 +1210,7 @@ static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed } /* stereo input (s3d->rectf.stereo) is always unsqueezed */ -static void imb_stereo3d_read_topbottom(Stereo3DData *s3d) +static void imb_stereo3d_read_topbottom(const Stereo3DData *s3d) { int y; size_t width = s3d->x; @@ -1258,7 +1260,7 @@ static void imb_stereo3d_read_topbottom(Stereo3DData *s3d) /** \name Preparing To Call The Read Functions * \{ */ -void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d, +void IMB_ImBufFromStereo3d(const Stereo3dFormat *s3d, ImBuf *ibuf_stereo3d, ImBuf **r_ibuf_left, ImBuf **r_ibuf_right) @@ -1337,7 +1339,7 @@ void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d, *r_ibuf_right = ibuf_right; } -static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d) +static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, const Stereo3dFormat *s3d) { switch (s3d->display_mode) { case S3D_DISPLAY_ANAGLYPH: diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index a8436772299..f093f1f6e15 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -242,10 +242,13 @@ void RE_AcquiredResultGet32(struct Render *re, unsigned int *rect, int view_id); +struct ImBuf *RE_render_result_rect_to_ibuf(struct RenderResult *rr, + const struct ImageFormatData *imf, + const float dither, + const int view_id); void RE_render_result_rect_from_ibuf(struct RenderResult *rr, - struct RenderData *rd, - struct ImBuf *ibuf, - int view_id); + const struct ImBuf *ibuf, + const int view_id); struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname); @@ -305,11 +308,6 @@ void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect); */ void RE_init_threadcount(Render *re); -bool RE_WriteRenderViewsImage(struct ReportList *reports, - struct RenderResult *rr, - struct Scene *scene, - bool stamp, - char *name); bool RE_WriteRenderViewsMovie(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, @@ -372,16 +370,7 @@ void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene * Only the temp file! */ bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode); -/** - * Called from the UI and render pipeline, to save multi-layer and multi-view - * images, optionally isolating a specific, view, layer or RGBA/Z pass. - */ -bool RE_WriteRenderResult(struct ReportList *reports, - RenderResult *rr, - const char *filename, - struct ImageFormatData *imf, - const char *view, - int layer); + struct RenderResult *RE_MultilayerConvert( void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); @@ -463,9 +452,9 @@ bool RE_allow_render_generic_object(struct Object *ob); /******* defined in render_result.c *********/ -bool RE_HasCombinedLayer(RenderResult *res); -bool RE_HasFloatPixels(RenderResult *res); -bool RE_RenderResult_is_stereo(RenderResult *res); +bool RE_HasCombinedLayer(const RenderResult *res); +bool RE_HasFloatPixels(const RenderResult *res); +bool RE_RenderResult_is_stereo(const RenderResult *res); struct RenderView *RE_RenderViewGetById(struct RenderResult *rr, int view_id); struct RenderView *RE_RenderViewGetByName(struct RenderResult *rr, const char *viewname); diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 614c03eba11..0ca2ca82cf7 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -45,6 +45,7 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_image_format.h" +#include "BKE_image_save.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_lib_remap.h" @@ -223,41 +224,6 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) fflush(stdout); } -static void render_print_save_message(ReportList *reports, const char *name, int ok, int err) -{ - if (ok) { - /* no need to report, just some helpful console info */ - printf("Saved: '%s'\n", name); - } - else { - /* report on error since users will want to know what failed */ - BKE_reportf(reports, RPT_ERROR, "Render error (%s) cannot save: '%s'", strerror(err), name); - } -} - -static int render_imbuf_write_stamp_test(ReportList *reports, - Scene *scene, - struct RenderResult *rr, - ImBuf *ibuf, - const char *name, - const ImageFormatData *imf, - bool stamp) -{ - int ok; - - if (stamp) { - /* writes the name of the individual cameras */ - ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, imf); - } - else { - ok = BKE_imbuf_write(ibuf, name, imf); - } - - render_print_save_message(reports, name, ok, errno); - - return ok; -} - void RE_FreeRenderResult(RenderResult *rr) { render_result_free(rr); @@ -1385,7 +1351,7 @@ static void do_render_sequencer(Render *re) if (ibuf_arr[view_id]) { /* copy ibuf into combined pixel rect */ - RE_render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id); + RE_render_result_rect_from_ibuf(rr, ibuf_arr[view_id], view_id); if (ibuf_arr[view_id]->metadata && (re->r.stamp & R_STAMP_STRIPMETA)) { /* ensure render stamp info first */ @@ -1979,129 +1945,6 @@ void RE_RenderFreestyleExternal(Render *re) /** \name Read/Write Render Result (Images & Movies) * \{ */ -bool RE_WriteRenderViewsImage( - ReportList *reports, RenderResult *rr, Scene *scene, const bool stamp, char *name) -{ - bool ok = true; - RenderData *rd = &scene->r; - - if (!rr) { - return false; - } - - bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; - bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && - RE_HasFloatPixels(rr); - - if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { - ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, NULL, -1); - render_print_save_message(reports, name, ok, errno); - } - - /* mono, legacy code */ - else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { - RenderView *rv; - int view_id; - char filepath[FILE_MAX]; - - BLI_strncpy(filepath, name, sizeof(filepath)); - - for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) { - if (!is_mono) { - BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name); - } - - if (is_exr_rr) { - ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, rv->name, -1); - render_print_save_message(reports, name, ok, errno); - - /* optional preview images for exr */ - if (ok && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { - ImageFormatData imf = rd->im_format; - imf.imtype = R_IMF_IMTYPE_JPEG90; - - if (BLI_path_extension_check(name, ".exr")) { - name[strlen(name) - 4] = 0; - } - BKE_image_path_ensure_ext_from_imformat(name, &imf); - - ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id); - ibuf->planes = 24; - IMB_colormanagement_imbuf_for_write( - ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf); - - ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &imf, stamp); - - IMB_freeImBuf(ibuf); - } - } - else { - ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id); - - IMB_colormanagement_imbuf_for_write( - ibuf, true, false, &scene->view_settings, &scene->display_settings, &rd->im_format); - - ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &rd->im_format, stamp); - - /* imbuf knows which rects are not part of ibuf */ - IMB_freeImBuf(ibuf); - } - } - } - else { /* R_IMF_VIEWS_STEREO_3D */ - BLI_assert(scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D); - - if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { - printf("Stereo 3D not supported for MultiLayer image: %s\n", name); - } - else { - ImBuf *ibuf_arr[3] = {NULL}; - const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - int i; - - for (i = 0; i < 2; i++) { - int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); - ibuf_arr[i] = render_result_rect_to_ibuf(rr, rd, view_id); - IMB_colormanagement_imbuf_for_write(ibuf_arr[i], - true, - false, - &scene->view_settings, - &scene->display_settings, - &scene->r.im_format); - IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]); - } - - ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); - - ok = render_imbuf_write_stamp_test( - reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp); - - /* optional preview images for exr */ - if (ok && is_exr_rr && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { - ImageFormatData imf = rd->im_format; - imf.imtype = R_IMF_IMTYPE_JPEG90; - - if (BLI_path_extension_check(name, ".exr")) { - name[strlen(name) - 4] = 0; - } - - BKE_image_path_ensure_ext_from_imformat(name, &imf); - ibuf_arr[2]->planes = 24; - - ok = render_imbuf_write_stamp_test( - reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp); - } - - /* imbuf knows which rects are not part of ibuf */ - for (i = 0; i < 3; i++) { - IMB_freeImBuf(ibuf_arr[i]); - } - } - } - - return ok; -} - bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, @@ -2111,20 +1954,20 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, const int totvideos, bool preview) { - bool is_mono; bool ok = true; if (!rr) { return false; } - is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; + const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; + const float dither = scene->r.dither_intensity; if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { int view_id; for (view_id = 0; view_id < totvideos; view_id++) { const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); - ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id); + ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); IMB_colormanagement_imbuf_for_write( ibuf, true, false, &scene->view_settings, &scene->display_settings, &scene->r.im_format); @@ -2153,7 +1996,7 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, for (i = 0; i < 2; i++) { int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); - ibuf_arr[i] = render_result_rect_to_ibuf(rr, &scene->r, view_id); + ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, @@ -2225,7 +2068,7 @@ static int do_write_image_or_movie(Render *re, } /* write images as individual images or stereo */ - ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name); + ok = BKE_image_render_write(re->reports, &rres, scene, true, name); } RE_ReleaseResultImageViews(re, &rres); diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index f4ae3caa77b..d938c15e35e 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -27,6 +27,7 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_image_format.h" +#include "BKE_image_save.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -749,12 +750,6 @@ void render_result_views_new(RenderResult *rr, const RenderData *rd) } } -bool render_result_has_views(const RenderResult *rr) -{ - const RenderView *rv = rr->views.first; - return (rv && (rv->next || rv->name[0])); -} - /*********************************** Merge ***********************************/ static void do_merge_tile( @@ -809,162 +804,6 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) } } -bool RE_WriteRenderResult(ReportList *reports, - RenderResult *rr, - const char *filename, - ImageFormatData *imf, - const char *view, - int layer) -{ - void *exrhandle = IMB_exr_get_handle(); - const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16); - const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR); - const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF)); - - /* Write first layer if not multilayer and no layer was specified. */ - if (!multi_layer && layer == -1) { - layer = 0; - } - - /* First add views since IMB_exr_add_channel checks number of views. */ - if (render_result_has_views(rr)) { - LISTBASE_FOREACH (RenderView *, rview, &rr->views) { - if (!view || STREQ(view, rview->name)) { - IMB_exr_add_view(exrhandle, rview->name); - } - } - } - - /* Compositing result. */ - if (rr->have_combined) { - LISTBASE_FOREACH (RenderView *, rview, &rr->views) { - if (!rview->rectf) { - continue; - } - - const char *viewname = rview->name; - if (view) { - if (!STREQ(view, viewname)) { - continue; - } - - viewname = ""; - } - - /* Skip compositing if only a single other layer is requested. */ - if (!multi_layer && layer != 0) { - continue; - } - - for (int a = 0; a < 4; a++) { - char passname[EXR_PASS_MAXNAME]; - char layname[EXR_PASS_MAXNAME]; - const char *chan_id = "RGBA"; - - if (multi_layer) { - IMB_exr_channel_name(passname, NULL, "Combined", NULL, chan_id, a); - BLI_strncpy(layname, "Composite", sizeof(layname)); - } - else { - passname[0] = chan_id[a]; - passname[1] = '\0'; - layname[0] = '\0'; - } - - IMB_exr_add_channel(exrhandle, - layname, - passname, - viewname, - 4, - 4 * rr->rectx, - rview->rectf + a, - half_float); - } - - if (write_z && rview->rectz) { - const char *layname = (multi_layer) ? "Composite" : ""; - IMB_exr_add_channel(exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->rectz, false); - } - } - } - - /* Other render layers. */ - int nr = (rr->have_combined) ? 1 : 0; - for (RenderLayer *rl = rr->layers.first; rl; rl = rl->next, nr++) { - /* Skip other render layers if requested. */ - if (!multi_layer && nr != layer) { - continue; - } - - LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) { - /* Skip non-RGBA and Z passes if not using multi layer. */ - if (!multi_layer && !(STREQ(rp->name, RE_PASSNAME_COMBINED) || STREQ(rp->name, "") || - (STREQ(rp->name, RE_PASSNAME_Z) && write_z))) { - continue; - } - - /* Skip pass if it does not match the requested view(s). */ - const char *viewname = rp->view; - if (view) { - if (!STREQ(view, viewname)) { - continue; - } - - viewname = ""; - } - - /* We only store RGBA passes as half float, for - * others precision loss can be problematic. */ - bool pass_half_float = half_float && - (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A")); - - for (int a = 0; a < rp->channels; a++) { - /* Save Combined as RGBA if single layer save. */ - char passname[EXR_PASS_MAXNAME]; - char layname[EXR_PASS_MAXNAME]; - - if (multi_layer) { - IMB_exr_channel_name(passname, NULL, rp->name, NULL, rp->chan_id, a); - BLI_strncpy(layname, rl->name, sizeof(layname)); - } - else { - passname[0] = rp->chan_id[a]; - passname[1] = '\0'; - layname[0] = '\0'; - } - - IMB_exr_add_channel(exrhandle, - layname, - passname, - viewname, - rp->channels, - rp->channels * rr->rectx, - rp->rect + a, - pass_half_float); - } - } - } - - errno = 0; - - BLI_make_existing_file(filename); - - int compress = (imf ? imf->exr_codec : 0); - bool success = IMB_exr_begin_write( - exrhandle, filename, rr->rectx, rr->recty, compress, rr->stamp_data); - if (success) { - IMB_exr_write_channels(exrhandle); - } - else { - /* TODO: get the error from openexr's exception. */ - BKE_reportf( - reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno)); - } - - IMB_exr_close(exrhandle); - return success; -} - /**************************** Single Layer Rendering *************************/ void render_result_single_layer_begin(Render *re) @@ -1117,7 +956,7 @@ void render_result_exr_file_cache_write(Render *re) render_result_exr_file_cache_path(re->scene, root, str); printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str); - RE_WriteRenderResult(NULL, rr, str, NULL, NULL, -1); + BKE_image_render_write_exr(NULL, rr, str, NULL, NULL, -1); } bool render_result_exr_file_cache_read(Render *re) @@ -1153,9 +992,12 @@ bool render_result_exr_file_cache_read(Render *re) /*************************** Combined Pixel Rect *****************************/ -ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const int view_id) +ImBuf *RE_render_result_rect_to_ibuf(RenderResult *rr, + const ImageFormatData *imf, + const float dither, + const int view_id) { - ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0); + ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, imf->planes, 0); RenderView *rv = RE_RenderViewGetById(rr, view_id); /* if not exists, BKE_imbuf_write makes one */ @@ -1164,15 +1006,15 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const ibuf->zbuf_float = rv->rectz; /* float factor for random dither, imbuf takes care of it */ - ibuf->dither = rd->dither_intensity; + ibuf->dither = dither; /* prepare to gamma correct to sRGB color space * note that sequence editor can generate 8bpc render buffers */ if (ibuf->rect) { - if (BKE_imtype_valid_depths(rd->im_format.imtype) & + if (BKE_imtype_valid_depths(imf->imtype) & (R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_24 | R_IMF_CHAN_DEPTH_32)) { - if (rd->im_format.depth == R_IMF_CHAN_DEPTH_8) { + if (imf->depth == R_IMF_CHAN_DEPTH_8) { /* Higher depth bits are supported but not needed for current file output. */ ibuf->rect_float = NULL; } @@ -1188,7 +1030,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const /* Color -> gray-scale. */ /* editing directly would alter the render view */ - if (rd->im_format.planes == R_IMF_PLANES_BW) { + if (imf->planes == R_IMF_PLANES_BW) { ImBuf *ibuf_bw = IMB_dupImBuf(ibuf); IMB_color_to_bw(ibuf_bw); IMB_freeImBuf(ibuf); @@ -1198,10 +1040,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const return ibuf; } -void RE_render_result_rect_from_ibuf(RenderResult *rr, - RenderData *UNUSED(rd), - ImBuf *ibuf, - const int view_id) +void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const int view_id) { RenderView *rv = RE_RenderViewGetById(rr, view_id); @@ -1278,15 +1117,13 @@ void render_result_rect_get_pixels(RenderResult *rr, /*************************** multiview functions *****************************/ -bool RE_HasCombinedLayer(RenderResult *rr) +bool RE_HasCombinedLayer(const RenderResult *rr) { - RenderView *rv; - if (rr == NULL) { return false; } - rv = rr->views.first; + const RenderView *rv = rr->views.first; if (rv == NULL) { return false; } @@ -1294,11 +1131,9 @@ bool RE_HasCombinedLayer(RenderResult *rr) return (rv->rect32 || rv->rectf); } -bool RE_HasFloatPixels(RenderResult *rr) +bool RE_HasFloatPixels(const RenderResult *rr) { - RenderView *rview; - - for (rview = rr->views.first; rview; rview = rview->next) { + for (const RenderView *rview = rr->views.first; rview; rview = rview->next) { if (rview->rect32 && !rview->rectf) { return false; } @@ -1307,7 +1142,7 @@ bool RE_HasFloatPixels(RenderResult *rr) return true; } -bool RE_RenderResult_is_stereo(RenderResult *rr) +bool RE_RenderResult_is_stereo(const RenderResult *rr) { if (!BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name))) { return false; diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h index 07929f4351f..30f49775562 100644 --- a/source/blender/render/intern/render_result.h +++ b/source/blender/render/intern/render_result.h @@ -131,7 +131,6 @@ void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResu * Free the views created temporarily. */ void render_result_views_shallowdelete(struct RenderResult *rr); -bool render_result_has_views(const struct RenderResult *rr); #define FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re_, iter_) \ { \ -- cgit v1.2.3