diff options
Diffstat (limited to 'source/blender/render/intern/source/render_result.c')
-rw-r--r-- | source/blender/render/intern/source/render_result.c | 816 |
1 files changed, 557 insertions, 259 deletions
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 6486844bacf..19beec9a6fe 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -48,9 +48,8 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" -#ifdef WITH_CYCLES_DEBUG -# include "BKE_scene.h" -#endif +#include "BKE_camera.h" +#include "BKE_scene.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -63,14 +62,32 @@ /********************************** Free *************************************/ +static void render_result_views_free(RenderResult *res) +{ + while (res->views.first) { + RenderView *rv = res->views.first; + BLI_remlink(&res->views, rv); + + if (rv->rect32) + MEM_freeN(rv->rect32); + + if (rv->rectz) + MEM_freeN(rv->rectz); + + if (rv->rectf) + MEM_freeN(rv->rectf); + + MEM_freeN(rv); + } +} + void render_result_free(RenderResult *res) { if (res == NULL) return; while (res->layers.first) { RenderLayer *rl = res->layers.first; - - if (rl->rectf) MEM_freeN(rl->rectf); + /* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */ if (rl->acolrect) MEM_freeN(rl->acolrect); if (rl->scolrect) MEM_freeN(rl->scolrect); @@ -85,7 +102,9 @@ void render_result_free(RenderResult *res) BLI_remlink(&res->layers, rl); MEM_freeN(rl); } - + + render_result_views_free(res); + if (res->rect32) MEM_freeN(res->rect32); if (res->rectz) @@ -96,7 +115,9 @@ void render_result_free(RenderResult *res) MEM_freeN(res->text); if (res->error) MEM_freeN(res->error); - + if (res->stamp_data) + MEM_freeN(res->stamp_data); + MEM_freeN(res); } @@ -115,13 +136,44 @@ void render_result_free_list(ListBase *lb, RenderResult *rr) } } -/********************************* Names *************************************/ +/********************************* multiview *************************************/ -/* NOTE: OpenEXR only supports 32 chars for layer+pass names - * In blender we now use max 10 chars for pass, max 20 for layer */ -static const char *get_pass_name(int passtype, int channel) +/* create a new views Listbase in rr without duplicating the memory pointers */ +void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src) +{ + RenderView *rview; + + if (dst == NULL || src == NULL) + return; + + for (rview = src->views.first; rview; rview = rview->next) { + RenderView *rv; + + rv = MEM_mallocN(sizeof(RenderView), "new render view"); + BLI_addtail(&dst->views, rv); + + BLI_strncpy(rv->name, rview->name, sizeof(rv->name)); + rv->rectf = rview->rectf; + rv->rectz = rview->rectz; + rv->rect32 = rview->rect32; + } +} + +/* free the views created temporarily */ +void render_result_views_shallowdelete(RenderResult *rr) +{ + if (rr == NULL) + return; + + while (rr->views.first) { + RenderView *rv = rr->views.first; + BLI_remlink(&rr->views, rv); + MEM_freeN(rv); + } +} + +static const char *name_from_passtype(int passtype, int channel) { - if (passtype == SCE_PASS_COMBINED) { if (channel == -1) return "Combined"; if (channel == 0) return "Combined.R"; @@ -308,122 +360,151 @@ static const char *get_pass_name(int passtype, int channel) static int passtype_from_name(const char *str) { - - if (STREQ(str, "Combined")) + if (STRPREFIX(str, "Combined")) return SCE_PASS_COMBINED; - if (STREQ(str, "Depth")) + if (STRPREFIX(str, "Depth")) return SCE_PASS_Z; - if (STREQ(str, "Vector")) + if (STRPREFIX(str, "Vector")) return SCE_PASS_VECTOR; - if (STREQ(str, "Normal")) + if (STRPREFIX(str, "Normal")) return SCE_PASS_NORMAL; - if (STREQ(str, "UV")) + if (STRPREFIX(str, "UV")) return SCE_PASS_UV; - if (STREQ(str, "Color")) + if (STRPREFIX(str, "Color")) return SCE_PASS_RGBA; - if (STREQ(str, "Emit")) + if (STRPREFIX(str, "Emit")) return SCE_PASS_EMIT; - if (STREQ(str, "Diffuse")) + if (STRPREFIX(str, "Diffuse")) return SCE_PASS_DIFFUSE; - if (STREQ(str, "Spec")) + if (STRPREFIX(str, "Spec")) return SCE_PASS_SPEC; - if (STREQ(str, "Shadow")) + if (STRPREFIX(str, "Shadow")) return SCE_PASS_SHADOW; - if (STREQ(str, "AO")) + if (STRPREFIX(str, "AO")) return SCE_PASS_AO; - if (STREQ(str, "Env")) + if (STRPREFIX(str, "Env")) return SCE_PASS_ENVIRONMENT; - if (STREQ(str, "Indirect")) + if (STRPREFIX(str, "Indirect")) return SCE_PASS_INDIRECT; - if (STREQ(str, "Reflect")) + if (STRPREFIX(str, "Reflect")) return SCE_PASS_REFLECT; - if (STREQ(str, "Refract")) + if (STRPREFIX(str, "Refract")) return SCE_PASS_REFRACT; - if (STREQ(str, "IndexOB")) + if (STRPREFIX(str, "IndexOB")) return SCE_PASS_INDEXOB; - if (STREQ(str, "IndexMA")) + if (STRPREFIX(str, "IndexMA")) return SCE_PASS_INDEXMA; - if (STREQ(str, "Mist")) + if (STRPREFIX(str, "Mist")) return SCE_PASS_MIST; - if (STREQ(str, "RayHits")) + if (STRPREFIX(str, "RayHits")) return SCE_PASS_RAYHITS; - if (STREQ(str, "DiffDir")) + if (STRPREFIX(str, "DiffDir")) return SCE_PASS_DIFFUSE_DIRECT; - if (STREQ(str, "DiffInd")) + if (STRPREFIX(str, "DiffInd")) return SCE_PASS_DIFFUSE_INDIRECT; - if (STREQ(str, "DiffCol")) + if (STRPREFIX(str, "DiffCol")) return SCE_PASS_DIFFUSE_COLOR; - if (STREQ(str, "GlossDir")) + if (STRPREFIX(str, "GlossDir")) return SCE_PASS_GLOSSY_DIRECT; - if (STREQ(str, "GlossInd")) + if (STRPREFIX(str, "GlossInd")) return SCE_PASS_GLOSSY_INDIRECT; - if (STREQ(str, "GlossCol")) + if (STRPREFIX(str, "GlossCol")) return SCE_PASS_GLOSSY_COLOR; - if (STREQ(str, "TransDir")) + if (STRPREFIX(str, "TransDir")) return SCE_PASS_TRANSM_DIRECT; - if (STREQ(str, "TransInd")) + if (STRPREFIX(str, "TransInd")) return SCE_PASS_TRANSM_INDIRECT; - if (STREQ(str, "TransCol")) + if (STRPREFIX(str, "TransCol")) return SCE_PASS_TRANSM_COLOR; - if (STREQ(str, "SubsurfaceDir")) + if (STRPREFIX(str, "SubsurfaceDir")) return SCE_PASS_SUBSURFACE_DIRECT; - if (STREQ(str, "SubsurfaceInd")) + if (STRPREFIX(str, "SubsurfaceInd")) return SCE_PASS_SUBSURFACE_INDIRECT; - if (STREQ(str, "SubsurfaceCol")) + if (STRPREFIX(str, "SubsurfaceCol")) return SCE_PASS_SUBSURFACE_COLOR; return 0; } + +static void set_pass_name(char *passname, int passtype, int channel, const char *view) +{ + const char delims[] = {'.', '\0'}; + const char *sep; + const char *token; + size_t len; + + const char *passtype_name = name_from_passtype(passtype, channel); + + if (view == NULL || view[0] == '\0') { + BLI_strncpy(passname, passtype_name, EXR_PASS_MAXNAME); + return; + } + + len = BLI_str_rpartition(passtype_name, delims, &sep, &token); + + if (sep) { + BLI_snprintf(passname, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passtype_name, view, token); + } + else { + BLI_snprintf(passname, EXR_PASS_MAXNAME, "%s.%s", passtype_name, view); + } +} + /********************************** New **************************************/ -static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype) +static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname) { - const char *typestr = get_pass_name(passtype, 0); + const size_t view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name)); + const char *typestr = name_from_passtype(passtype, -1); RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr); - int rectsize = rr->rectx * rr->recty * channels; + size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels; BLI_addtail(&rl->passes, rpass); rpass->passtype = passtype; rpass->channels = channels; rpass->rectx = rl->rectx; rpass->recty = rl->recty; - BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); + rpass->view_id = view_id; + + set_pass_name(rpass->name, rpass->passtype, -1, viewname); + BLI_strncpy(rpass->internal_name, typestr, sizeof(rpass->internal_name)); + BLI_strncpy(rpass->view, viewname, sizeof(rpass->view)); if (rl->exrhandle) { int a; for (a = 0; a < channels; a++) - IMB_exr_add_channel(rl->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL); + IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(passtype, a), viewname, 0, 0, NULL, false); } else { float *rect; @@ -452,6 +533,10 @@ static const char *debug_pass_type_name_get(int debug_type) switch (debug_type) { case RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS: return "BVH Traversal Steps"; + case RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES: + return "BVH Traversed Instances"; + case RENDER_PASS_DEBUG_RAY_BOUNCES: + return "Ray Bounces"; } return "Unknown"; } @@ -460,13 +545,15 @@ static RenderPass *render_layer_add_debug_pass(RenderResult *rr, RenderLayer *rl, int channels, int pass_type, - int debug_type) + int debug_type, + const char *view) { - RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type); + RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view); rpass->debug_type = debug_type; BLI_strncpy(rpass->name, debug_pass_type_name_get(debug_type), sizeof(rpass->name)); + BLI_strncpy(rpass->internal_name, rpass->name, sizeof(rpass->internal_name)); return rpass; } #endif @@ -475,12 +562,14 @@ static RenderPass *render_layer_add_debug_pass(RenderResult *rr, /* will read info from Render *re to define layers */ /* called in threads */ /* re->winx,winy is coordinate space of entire image, partrct the part within */ -RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername) +RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname) { RenderResult *rr; RenderLayer *rl; + RenderView *rv; SceneRenderLayer *srl; - int rectx, recty, nr; + int rectx, recty; + int nr; rectx = BLI_rcti_size_x(partrct); recty = BLI_rcti_size_y(partrct); @@ -505,6 +594,8 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf rr->do_exr_tile = true; } + render_result_views_new(rr, &re->r); + /* check renderdata for amount of layers */ for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) { @@ -538,84 +629,90 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf if (rr->do_exr_tile) { rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba"); - rl->exrhandle = IMB_exr_get_handle(); - - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL); } - else - rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba"); - - if (srl->passflag & SCE_PASS_Z) - render_layer_add_pass(rr, rl, 1, SCE_PASS_Z); - if (srl->passflag & SCE_PASS_VECTOR) - render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR); - if (srl->passflag & SCE_PASS_NORMAL) - render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL); - if (srl->passflag & SCE_PASS_UV) - render_layer_add_pass(rr, rl, 3, SCE_PASS_UV); - if (srl->passflag & SCE_PASS_RGBA) - render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA); - if (srl->passflag & SCE_PASS_EMIT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT); - if (srl->passflag & SCE_PASS_DIFFUSE) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE); - if (srl->passflag & SCE_PASS_SPEC) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC); - if (srl->passflag & SCE_PASS_AO) - render_layer_add_pass(rr, rl, 3, SCE_PASS_AO); - if (srl->passflag & SCE_PASS_ENVIRONMENT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT); - if (srl->passflag & SCE_PASS_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT); - if (srl->passflag & SCE_PASS_SHADOW) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW); - if (srl->passflag & SCE_PASS_REFLECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT); - if (srl->passflag & SCE_PASS_REFRACT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT); - if (srl->passflag & SCE_PASS_INDEXOB) - render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB); - if (srl->passflag & SCE_PASS_INDEXMA) - render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA); - if (srl->passflag & SCE_PASS_MIST) - render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST); - if (rl->passflag & SCE_PASS_RAYHITS) - render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS); - if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT); - if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT); - if (srl->passflag & SCE_PASS_DIFFUSE_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR); - if (srl->passflag & SCE_PASS_GLOSSY_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT); - if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT); - if (srl->passflag & SCE_PASS_GLOSSY_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR); - if (srl->passflag & SCE_PASS_TRANSM_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT); - if (srl->passflag & SCE_PASS_TRANSM_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT); - if (srl->passflag & SCE_PASS_TRANSM_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR); - if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT); - if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT); - if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR); + + for (rv = rr->views.first; rv; rv = rv->next) { + const char *view = rv->name; + + if (viewname && viewname[0]) + if (!STREQ(view, viewname)) + continue; + + if (rr->do_exr_tile) + IMB_exr_add_view(rl->exrhandle, view); + + /* a renderlayer should always have a Combined pass*/ + render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view); + + if (srl->passflag & SCE_PASS_Z) + render_layer_add_pass(rr, rl, 1, SCE_PASS_Z, view); + if (srl->passflag & SCE_PASS_VECTOR) + render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR, view); + if (srl->passflag & SCE_PASS_NORMAL) + render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL, view); + if (srl->passflag & SCE_PASS_UV) + render_layer_add_pass(rr, rl, 3, SCE_PASS_UV, view); + if (srl->passflag & SCE_PASS_RGBA) + render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA, view); + if (srl->passflag & SCE_PASS_EMIT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT, view); + if (srl->passflag & SCE_PASS_DIFFUSE) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE, view); + if (srl->passflag & SCE_PASS_SPEC) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC, view); + if (srl->passflag & SCE_PASS_AO) + render_layer_add_pass(rr, rl, 3, SCE_PASS_AO, view); + if (srl->passflag & SCE_PASS_ENVIRONMENT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT, view); + if (srl->passflag & SCE_PASS_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT, view); + if (srl->passflag & SCE_PASS_SHADOW) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW, view); + if (srl->passflag & SCE_PASS_REFLECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT, view); + if (srl->passflag & SCE_PASS_REFRACT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT, view); + if (srl->passflag & SCE_PASS_INDEXOB) + render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB, view); + if (srl->passflag & SCE_PASS_INDEXMA) + render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA, view); + if (srl->passflag & SCE_PASS_MIST) + render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST, view); + if (rl->passflag & SCE_PASS_RAYHITS) + render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS, view); + if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view); + if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view); + if (srl->passflag & SCE_PASS_DIFFUSE_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view); + if (srl->passflag & SCE_PASS_GLOSSY_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view); + if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view); + if (srl->passflag & SCE_PASS_GLOSSY_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view); + if (srl->passflag & SCE_PASS_TRANSM_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view); + if (srl->passflag & SCE_PASS_TRANSM_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view); + if (srl->passflag & SCE_PASS_TRANSM_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view); + if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view); + if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view); + if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view); #ifdef WITH_CYCLES_DEBUG - if (BKE_scene_use_new_shading_nodes(re->scene)) { - render_layer_add_debug_pass(rr, rl, 1, SCE_PASS_DEBUG, - RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS); - } + if (BKE_scene_use_new_shading_nodes(re->scene)) { + render_layer_add_debug_pass(rr, rl, 1, SCE_PASS_DEBUG, + re->r.debug_pass_type, view); + } #endif + } } /* sss, previewrender and envmap don't do layers, so we make a default one */ if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) { @@ -628,18 +725,23 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf /* duplicate code... */ if (rr->do_exr_tile) { rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba"); - rl->exrhandle = IMB_exr_get_handle(); - - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL); } - else { - rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba"); + + for (rv = rr->views.first; rv; rv = rv->next) { + const char *view = rv->name; + + if (viewname && viewname[0]) + if (strcmp(view, viewname) != 0) + continue; + + if (rr->do_exr_tile) + IMB_exr_add_view(rl->exrhandle, view); + + /* a renderlayer should always have a Combined pass */ + render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view); } - + /* note, this has to be in sync with scene.c */ rl->lay = (1 << 20) - 1; rl->layflag = 0x7FFF; /* solid ztra halo strand */ @@ -657,15 +759,15 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf } /* allocate osa new results for samples */ -RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers) +RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname) { int a; if (re->osa == 0) - return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS); + return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname); for (a = 0; a < re->osa; a++) { - RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS); + RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname); BLI_addtail(lb, rr); rr->sample_nr = a; } @@ -686,28 +788,98 @@ static void *ml_addlayer_cb(void *base, const char *str) return rl; } -static void ml_addpass_cb(void *UNUSED(base), void *lay, const char *str, float *rect, int totchan, const char *chan_id) +static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view) { + RenderResult *rr = base; RenderLayer *rl = lay; RenderPass *rpass = MEM_callocN(sizeof(RenderPass), "loaded pass"); int a; BLI_addtail(&rl->passes, rpass); rpass->channels = totchan; - rpass->passtype = passtype_from_name(str); if (rpass->passtype == 0) printf("unknown pass %s\n", str); rl->passflag |= rpass->passtype; - BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME); /* channel id chars */ for (a = 0; a < totchan; a++) rpass->chan_id[a] = chan_id[a]; - + rpass->rect = rect; + if (view[0] != '\0') { + BLI_snprintf(rpass->name, sizeof(rpass->name), "%s.%s", str, view); + rpass->view_id = BLI_findstringindex(&rr->views, view, offsetof(RenderView, name)); + } + else { + BLI_strncpy(rpass->name, str, sizeof(rpass->name)); + rpass->view_id = 0; + } + + BLI_strncpy(rpass->view, view, sizeof(rpass->view)); + BLI_strncpy(rpass->internal_name, str, sizeof(rpass->internal_name)); +} + +static void *ml_addview_cb(void *base, const char *str) +{ + RenderResult *rr = base; + RenderView *rv; + + rv = MEM_callocN(sizeof(RenderView), "new render view"); + BLI_strncpy(rv->name, str, EXR_VIEW_MAXNAME); + + /* For stereo drawing we need to ensure: + * STEREO_LEFT_NAME == STEREO_LEFT_ID and + * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */ + + if (STREQ(str, STEREO_LEFT_NAME)) { + BLI_addhead(&rr->views, rv); + } + else if (STREQ(str, STEREO_RIGHT_NAME)) { + RenderView *left_rv = BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)); + + if (left_rv == NULL) { + BLI_addhead(&rr->views, rv); + } + else { + BLI_insertlinkafter(&rr->views, left_rv, rv); + } + } + else { + BLI_addtail(&rr->views, rv); + } + + return rv; +} + +static int order_render_passes(const void *a, const void *b) +{ + // 1 if a is after b + RenderPass *rpa = (RenderPass *) a; + RenderPass *rpb = (RenderPass *) b; + + if (rpa->passtype > rpb->passtype) + return 1; + else if (rpa->passtype < rpb->passtype) + return 0; + + /* they have the same type */ + /* left first */ + if (STREQ(rpa->view, STEREO_LEFT_NAME)) + return 0; + else if (STREQ(rpb->view, STEREO_LEFT_NAME)) + return 1; + + /* right second */ + if (STREQ(rpa->view, STEREO_RIGHT_NAME)) + return 0; + else if (STREQ(rpb->view, STEREO_RIGHT_NAME)) + return 1; + + /* remaining in ascending id order */ + return (rpa->view_id < rpb->view_id); } -/* from imbuf, if a handle was returned we convert this to render result */ +/* from imbuf, if a handle was returned and it's not a singlelayer multiview we convert this to render result */ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty) { RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__); @@ -718,13 +890,17 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace rr->rectx = rectx; rr->recty = recty; - IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb); + IMB_exr_multilayer_convert(exrhandle, rr, ml_addview_cb, ml_addlayer_cb, ml_addpass_cb); for (rl = rr->layers.first; rl; rl = rl->next) { + int c=0; rl->rectx = rectx; rl->recty = recty; + BLI_listbase_sort(&rl->passes, order_render_passes); + for (rpass = rl->passes.first; rpass; rpass = rpass->next) { + printf("%d: %s\n", c++, rpass->name); rpass->rectx = rectx; rpass->recty = recty; @@ -738,26 +914,56 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace return rr; } +void render_result_view_new(RenderResult *rr, const char *viewname) +{ + RenderView *rv = MEM_callocN(sizeof(RenderView), "new render view"); + BLI_addtail(&rr->views, rv); + BLI_strncpy(rv->name, viewname, sizeof(rv->name)); +} + +void render_result_views_new(RenderResult *rr, RenderData *rd) +{ + SceneRenderView *srv; + + /* clear previously existing views - for sequencer */ + render_result_views_free(rr); + + /* check renderdata for amount of views */ + if ((rd->scemode & R_MULTIVIEW)) { + for (srv = rd->views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) + continue; + render_result_view_new(rr, srv->name); + } + } + + /* we always need at least one view */ + if (BLI_listbase_count_ex(&rr->views, 1) == 0) { + render_result_view_new(rr, ""); + } +} + /*********************************** Merge ***********************************/ static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize) { - int y, ofs, copylen, tilex, tiley; + int y, tilex, tiley; + size_t ofs, copylen; copylen = tilex = rrpart->rectx; tiley = rrpart->recty; if (rrpart->crop) { /* filters add pixel extra */ - tile += pixsize * (rrpart->crop + rrpart->crop * tilex); + tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex); copylen = tilex - 2 * rrpart->crop; tiley -= 2 * rrpart->crop; - ofs = (rrpart->tilerect.ymin + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop); + ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop); target += pixsize * ofs; } else { - ofs = (rrpart->tilerect.ymin * rr->rectx + rrpart->tilerect.xmin); + ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin); target += pixsize * ofs; } @@ -783,16 +989,19 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) for (rl = rr->layers.first; rl; rl = rl->next) { rlp = RE_GetRenderLayer(rrpart, rl->name); if (rlp) { - /* combined */ - if (rl->rectf && rlp->rectf) - do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4); - /* passes are allocated in sync */ for (rpass = rl->passes.first, rpassp = rlp->passes.first; rpass && rpassp; - rpass = rpass->next, rpassp = rpassp->next) + rpass = rpass->next) { + /* renderresult have all passes, renderpart only the active view's passes */ + if (strcmp(rpassp->name, rpass->name) != 0) + continue; + do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels); + + /* manually get next render pass */ + rpassp = rpassp->next; } } } @@ -801,7 +1010,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) /* for passes read from files, these have names stored */ static char *make_pass_name(RenderPass *rpass, int chan) { - static char name[16]; + static char name[EXR_PASS_MAXNAME]; int len; BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME); @@ -813,55 +1022,111 @@ static char *make_pass_name(RenderPass *rpass, int chan) return name; } -/* filename already made absolute */ -/* called from within UI, saves both rendered result as a file-read result */ -bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress) +/* called from within UI and render pipeline, saves both rendered result as a file-read result + * if multiview is true saves all views in a multiview exr + * else if view is not NULL saves single view + * else saves stereo3d + */ +bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const bool multiview, const char *view) { RenderLayer *rl; RenderPass *rpass; + RenderView *rview; void *exrhandle = IMB_exr_get_handle(); bool success; - - BLI_make_existing_file(filename); - - /* composite result */ - if (rr->rectf) { - IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4 * rr->rectx, rr->rectf); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4 * rr->rectx, rr->rectf + 1); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4 * rr->rectx, rr->rectf + 2); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4 * rr->rectx, rr->rectf + 3); + int a, nr; + const char *chan_view = NULL; + int compress = (imf ? imf->exr_codec : 0); + size_t width, height; + + const bool is_mono = view && !multiview; + const bool use_half_float = (imf->depth == R_IMF_CHAN_DEPTH_16); + + width = rr->rectx; + height = rr->recty; + + if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) { + /* single layer OpenEXR */ + const char *RGBAZ[] = {"R", "G", "B", "A", "Z"}; + for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { + IMB_exr_add_view(exrhandle, rview->name); + + if (rview->rectf) { + for (a = 0; a < 4; a++) { + IMB_exr_add_channel(exrhandle, "", RGBAZ[a], + rview->name, 4, 4 * width, rview->rectf + a, + use_half_float); + } + if (rview->rectz) { + /* Z pass is always stored as float. */ + IMB_exr_add_channel(exrhandle, "", RGBAZ[4], + rview->name, 1, width, rview->rectz, + false); + } + } + } } - - /* add layers/passes and assign channels */ - for (rl = rr->layers.first; rl; rl = rl->next) { - - /* combined */ - if (rl->rectf) { - int a, xstride = 4; - for (a = 0; a < xstride; a++) { - IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride * rr->rectx, rl->rectf + a); + else { + for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { + if (is_mono) { + if (!STREQ(view, rview->name)) { + continue; + } + chan_view = ""; + } + else { + /* if rendered only one view, we treat as a a non-view render */ + chan_view = rview->name; + } + + IMB_exr_add_view(exrhandle, rview->name); + + if (rview->rectf) { + for (a = 0; a < 4; a++) { + IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a), + chan_view, 4, 4 * width, rview->rectf + a, + use_half_float); + } } } - - /* passes are allocated in sync */ - for (rpass = rl->passes.first; rpass; rpass = rpass->next) { - int a, xstride = rpass->channels; - for (a = 0; a < xstride; a++) { - if (rpass->passtype) { - IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), - xstride, xstride * rr->rectx, rpass->rect + a); + + /* add layers/passes and assign channels */ + for (rl = rr->layers.first; rl; rl = rl->next) { + + /* passes are allocated in sync */ + for (rpass = rl->passes.first; rpass; rpass = rpass->next) { + const int xstride = rpass->channels; + + if (is_mono) { + if (!STREQ(view, rpass->view)) { + continue; + } + chan_view = ""; } else { - IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), - xstride, xstride * rr->rectx, rpass->rect + a); + /* if rendered only one view, we treat as a a non-view render */ + chan_view = (nr > 1 ? rpass->view :""); + } + + for (a = 0; a < xstride; a++) { + if (rpass->passtype) { + IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view, + xstride, xstride * width, rpass->rect + a, + rpass->passtype == SCE_PASS_Z ? false : use_half_float); + } + else { + IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view, + xstride, xstride * width, rpass->rect + a, + use_half_float); + } } } } } - /* when the filename has no permissions, this can fail */ - if (IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress)) { + BLI_make_existing_file(filename); + + if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) { IMB_exr_write_channels(exrhandle); success = true; } @@ -870,8 +1135,8 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil BKE_report(reports, RPT_ERROR, "Error writing render result (see console)"); success = false; } - IMB_exr_close(exrhandle); + IMB_exr_close(exrhandle); return success; } @@ -932,7 +1197,7 @@ void render_result_single_layer_end(Render *re) /************************* EXR Tile File Rendering ***************************/ -static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) +static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, const char *viewname) { RenderLayer *rlp, *rl; RenderPass *rpassp; @@ -955,21 +1220,17 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) else { offs = 0; } - - /* combined */ - if (rlp->rectf) { - int a, xstride = 4; - for (a = 0; a < xstride; a++) { - IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride * rrpart->rectx, rlp->rectf + a + xstride * offs); - } - } - + /* passes are allocated in sync */ for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) { - int a, xstride = rpassp->channels; + const int xstride = rpassp->channels; + int a; + char passname[EXR_PASS_MAXNAME]; + for (a = 0; a < xstride; a++) { - IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a), + set_pass_name(passname, rpassp->passtype, a, rpassp->view); + + IMB_exr_set_channel(rl->exrhandle, rlp->name, passname, xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs); } } @@ -988,13 +1249,13 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) continue; } - IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0); + IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname); } BLI_unlock_thread(LOCK_IMAGE); } -static void save_empty_result_tiles(Render *re) +void render_result_save_empty_result_tiles(Render *re) { RenderPart *pa; RenderResult *rr; @@ -1002,13 +1263,13 @@ static void save_empty_result_tiles(Render *re) for (rr = re->result; rr; rr = rr->next) { for (rl = rr->layers.first; rl; rl = rl->next) { - IMB_exrtile_clear_channels(rl->exrhandle); + IMB_exr_clear_channels(rl->exrhandle); for (pa = re->parts.first; pa; pa = pa->next) { if (pa->status != PART_STATUS_READY) { int party = pa->disprect.ymin - re->disprect.ymin + pa->crop; int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop; - IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0); + IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname); } } } @@ -1037,8 +1298,6 @@ void render_result_exr_file_end(Render *re) RenderResult *rr; RenderLayer *rl; - save_empty_result_tiles(re); - for (rr = re->result; rr; rr = rr->next) { for (rl = rr->layers.first; rl; rl = rl->next) { IMB_exr_close(rl->exrhandle); @@ -1055,10 +1314,10 @@ void render_result_exr_file_end(Render *re) } /* save part into exr file */ -void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart) +void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart, const char *viewname) { for (; rr && rrpart; rr = rr->next, rrpart = rrpart->next) - save_render_result_tile(rr, rrpart); + save_render_result_tile(rr, rrpart, viewname); } /* path to temporary exr file */ @@ -1088,7 +1347,7 @@ int render_result_exr_file_read_sample(Render *re, int sample) bool success = true; RE_FreeRenderResult(re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); for (rl = re->result->layers.first; rl; rl = rl->next) { render_result_exr_file_path(re->scene, rl->name, sample, str); @@ -1129,23 +1388,20 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c for (rl = rr->layers.first; rl; rl = rl->next) { if (rl_single && rl_single != rl) continue; - - /* combined */ - if (rl->rectf) { - int a, xstride = 4; - for (a = 0; a < xstride; a++) - IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride * rectx, rl->rectf + a); - } /* passes are allocated in sync */ for (rpass = rl->passes.first; rpass; rpass = rpass->next) { - int a, xstride = rpass->channels; - for (a = 0; a < xstride; a++) - IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), + const int xstride = rpass->channels; + int a; + char passname[EXR_PASS_MAXNAME]; + + for (a = 0; a < xstride; a++) { + set_pass_name(passname, rpass->passtype, a, rpass->view); + IMB_exr_set_channel(exrhandle, rl->name, passname, xstride, xstride * rectx, rpass->rect + a); + } - BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); + set_pass_name(rpass->name, rpass->passtype, -1, rpass->view); } } @@ -1191,7 +1447,8 @@ 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, 0); + + RE_WriteRenderResult(NULL, rr, str, NULL, true, NULL); } /* For cache, makes exact copy of render result */ @@ -1201,7 +1458,7 @@ bool render_result_exr_file_cache_read(Render *re) char *root = U.render_cachedir; RE_FreeRenderResult(re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); /* First try cache. */ render_result_exr_file_cache_path(re->scene, root, str); @@ -1216,15 +1473,16 @@ bool render_result_exr_file_cache_read(Render *re) /*************************** Combined Pixel Rect *****************************/ -ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd) +ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int view_id) { ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0); - + RenderView *rv = RE_RenderViewGetById(rr, view_id); + /* if not exists, BKE_imbuf_write makes one */ - ibuf->rect = (unsigned int *)rr->rect32; - ibuf->rect_float = rr->rectf; - ibuf->zbuf_float = rr->rectz; - + ibuf->rect = (unsigned int *) rv->rect32; + ibuf->rect_float = rv->rectf; + ibuf->zbuf_float = rv->rectz; + /* float factor for random dither, imbuf takes care of it */ ibuf->dither = rd->dither_intensity; @@ -1259,57 +1517,97 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd) return ibuf; } -void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf) +void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf, const int view_id) { + RenderView *rv = RE_RenderViewGetById(rr, view_id); + if (ibuf->rect_float) { - if (!rr->rectf) - rr->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf"); + if (!rv->rectf) + rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf"); - memcpy(rr->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty); + memcpy(rv->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty); /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 * can hang around when sequence render has rendered a 32 bits one before */ - if (rr->rect32) { - MEM_freeN(rr->rect32); - rr->rect32 = NULL; - } + MEM_SAFE_FREE(rv->rect32); } else if (ibuf->rect) { - if (!rr->rect32) - rr->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); + if (!rv->rect32) + rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); - memcpy(rr->rect32, ibuf->rect, 4 * rr->rectx * rr->recty); + memcpy(rv->rect32, ibuf->rect, 4 * rr->rectx * rr->recty); /* Same things as above, old rectf can hang around from previous render. */ - if (rr->rectf) { - MEM_freeN(rr->rectf); - rr->rectf = NULL; - } + MEM_SAFE_FREE(rv->rectf); } } -void render_result_rect_fill_zero(RenderResult *rr) +void render_result_rect_fill_zero(RenderResult *rr, const int view_id) { - if (rr->rectf) - memset(rr->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty); - else if (rr->rect32) - memset(rr->rect32, 0, 4 * rr->rectx * rr->recty); + RenderView *rv = RE_RenderViewGetById(rr, view_id); + + if (rv->rectf) + memset(rv->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty); + else if (rv->rect32) + memset(rv->rect32, 0, 4 * rr->rectx * rr->recty); else - rr->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); + rv->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); } void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty, - const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) + const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, + const int view_id) { - if (rr->rect32) { - memcpy(rect, rr->rect32, sizeof(int) * rr->rectx * rr->recty); - } - else if (rr->rectf) { - IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4, + RenderView *rv = RE_RenderViewGetById(rr, view_id); + + if (rv->rect32) + memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty); + else if (rv->rectf) + IMB_display_buffer_transform_apply((unsigned char *) rect, rv->rectf, rr->rectx, rr->recty, 4, view_settings, display_settings, true); - } else /* else fill with black */ memset(rect, 0, sizeof(int) * rectx * recty); } + +/*************************** multiview functions *****************************/ + +bool RE_HasFakeLayer(RenderResult *res) +{ + RenderView *rv; + + if (res == NULL) + return false; + + rv = res->views.first; + if (rv == NULL) + return false; + + return (rv->rect32 || rv->rectf); +} + +bool RE_RenderResult_is_stereo(RenderResult *res) +{ + if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name))) + return false; + + if (! BLI_findstring(&res->views, STEREO_RIGHT_NAME, offsetof(RenderView, name))) + return false; + + return true; +} + +RenderView *RE_RenderViewGetById(RenderResult *res, const int view_id) +{ + RenderView *rv = BLI_findlink(&res->views, view_id); + BLI_assert(res->views.first); + return rv ? rv : res->views.first; +} + +RenderView *RE_RenderViewGetByName(RenderResult *res, const char *viewname) +{ + RenderView *rv = BLI_findstring(&res->views, viewname, offsetof(RenderView, name)); + BLI_assert(res->views.first); + return rv ? rv : res->views.first; +} |