diff options
Diffstat (limited to 'source/blender/render/intern')
-rw-r--r-- | source/blender/render/intern/include/render_result.h | 21 | ||||
-rw-r--r-- | source/blender/render/intern/include/render_types.h | 3 | ||||
-rw-r--r-- | source/blender/render/intern/source/convertblender.c | 6 | ||||
-rw-r--r-- | source/blender/render/intern/source/envmap.c | 6 | ||||
-rw-r--r-- | source/blender/render/intern/source/external_engine.c | 27 | ||||
-rw-r--r-- | source/blender/render/intern/source/initrender.c | 20 | ||||
-rw-r--r-- | source/blender/render/intern/source/pipeline.c | 1099 | ||||
-rw-r--r-- | source/blender/render/intern/source/render_result.c | 815 | ||||
-rw-r--r-- | source/blender/render/intern/source/rendercore.c | 111 | ||||
-rw-r--r-- | source/blender/render/intern/source/zbuf.c | 14 |
10 files changed, 1521 insertions, 601 deletions
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h index 90ff69dbfbe..e7a2cbf99cd 100644 --- a/source/blender/render/intern/include/render_result.h +++ b/source/blender/render/intern/include/render_result.h @@ -38,6 +38,7 @@ #define RR_USE_EXR 1 #define RR_ALL_LAYERS NULL +#define RR_ALL_VIEWS NULL struct ImBuf; struct ListBase; @@ -53,12 +54,14 @@ struct ColorManagedViewSettings; /* New */ struct RenderResult *render_result_new(struct Render *re, - struct rcti *partrct, int crop, int savebuffers, const char *layername); + struct rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname); struct RenderResult *render_result_new_full_sample(struct Render *re, - struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers); + struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers, const char *viewname); struct RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); +void render_result_views_new(struct RenderResult *rr, struct RenderData *rd); + /* Merge */ void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart); @@ -78,7 +81,7 @@ void render_result_single_layer_end(struct Render *re); void render_result_exr_file_begin(struct Render *re); void render_result_exr_file_end(struct Render *re); -void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart); +void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname); void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath); int render_result_exr_file_read_sample(struct Render *re, int sample); @@ -91,15 +94,19 @@ bool render_result_exr_file_cache_read(struct Render *re); /* Combined Pixel Rect */ -struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd); +struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd, const int view_id); void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd, - struct ImBuf *ibuf); + struct ImBuf *ibuf, const int view_id); -void render_result_rect_fill_zero(struct RenderResult *rr); +void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id); void render_result_rect_get_pixels(struct RenderResult *rr, unsigned int *rect, int rectx, int recty, const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings); + const struct ColorManagedDisplaySettings *display_settings, + const int view_id); + +void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src); +void render_result_views_shallowdelete(struct RenderResult *rr); #endif /* __RENDER_RESULT_H__ */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 0d23c81afb0..8fe12015e87 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -275,6 +275,9 @@ struct Render struct ImagePool *pool; struct EvaluationContext *eval_ctx; + + void **movie_ctx_arr; + char viewname[MAX_NAME]; }; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index c0ba2f43c36..d36ab46d145 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -5171,8 +5171,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l * above call to BKE_scene_update_for_newframe, fixes bug. [#22702]. * following calls don't depend on 'RE_SetCamera' */ RE_SetCamera(re, camera); - - normalize_m4_m4(mat, camera->obmat); + RE_GetCameraModelMatrix(re, camera, mat); invert_m4(mat); RE_SetView(re, mat); @@ -5342,7 +5341,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la /* if no camera, viewmat should have been set! */ if (camera) { - normalize_m4_m4(mat, camera->obmat); + RE_GetCameraModelMatrix(re, camera, mat); + normalize_m4(mat); invert_m4(mat); RE_SetView(re, mat); } diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 0698f849073..ed3033d8393 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -495,9 +495,11 @@ static void render_envmap(Render *re, EnvMap *env) RenderLayer *rl = envre->result->layers.first; int y; float *alpha; - + float *rect; + + rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname); ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat); - memcpy(ibuf->rect_float, rl->rectf, ibuf->channels * ibuf->x * ibuf->y * sizeof(float)); + memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float)); /* envmap renders without alpha */ alpha = ibuf->rect_float + 3; diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index e56466bdf48..343c4a9387a 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -42,6 +42,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_camera.h" #include "BKE_global.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -181,7 +182,7 @@ static RenderPart *get_part_from_result(Render *re, RenderResult *result) return NULL; } -RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername) +RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname) { Render *re = engine->re; RenderResult *result; @@ -204,7 +205,7 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, disprect.ymin = y; disprect.ymax = y + h; - result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername); + result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname); /* todo: make this thread safe */ @@ -269,7 +270,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel if (!cancel || merge_results) { if (re->result->do_exr_tile) { if (!cancel) { - render_result_exr_file_merge(re->result, result); + render_result_exr_file_merge(re->result, result, re->viewname); } } else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW))) @@ -368,6 +369,24 @@ void RE_engine_set_error_message(RenderEngine *engine, const char *msg) } } +void RE_engine_active_view_set(RenderEngine *engine, const char *viewname) +{ + Render *re = engine->re; + RE_SetActiveRenderView(re, viewname); +} + +float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera) +{ + Render *re = engine->re; + return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname); +} + +void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, float *r_modelmat) +{ + Render *re = engine->re; + BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat); +} + rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free) { static rcti tiles_static[BLENDER_MAX_THREADS]; @@ -612,7 +631,7 @@ int RE_engine_render(Render *re, int do_all) if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE)) savebuffers = RR_USE_EXR; - re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS); } BLI_rw_mutex_unlock(&re->resultmutex); diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index a0fcc7cdcd2..970a3937657 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -426,10 +426,10 @@ void make_sample_tables(Render *re) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - struct Object *RE_GetCamera(Render *re) { - return re->camera_override ? re->camera_override : re->scene->camera; + Object *camera = re->camera_override ? re->camera_override : re->scene->camera; + return BKE_camera_multiview_render(re->scene, camera, re->viewname); } static void re_camera_params_get(Render *re, CameraParams *params, Object *cam_ob) @@ -470,6 +470,16 @@ void RE_SetEnvmapCamera(Render *re, Object *cam_ob, float viewscale, float clips re_camera_params_get(re, ¶ms, cam_ob); } +void RE_SetOverrideCamera(Render *re, Object *camera) +{ + re->camera_override = camera; +} + +static void re_camera_params_stereo3d(Render *re, CameraParams *params, Object *cam_ob) +{ + BKE_camera_multiview_params(&re->r, params, cam_ob, re->viewname); +} + /* call this after InitState() */ /* per render, there's one persistent viewplane. Parts will set their own viewplanes */ void RE_SetCamera(Render *re, Object *cam_ob) @@ -479,6 +489,7 @@ void RE_SetCamera(Render *re, Object *cam_ob) /* setup parameters */ BKE_camera_params_init(¶ms); BKE_camera_params_from_object(¶ms, cam_ob); + re_camera_params_stereo3d(re, ¶ms, cam_ob); params.use_fields = (re->r.mode & R_FIELDS); params.field_second = (re->flag & R_SEC_FIELD); @@ -505,6 +516,11 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, flo copy_m4_m4(mat, re->winmat); } +void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4]) +{ + BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_mat); +} + /* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 4bde3dddaff..25adb4db4f7 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -70,6 +70,7 @@ #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */ +#include "BKE_object.h" #include "PIL_time.h" #include "IMB_colormanagement.h" @@ -131,7 +132,7 @@ Render R; /* ********* alloc and free ******** */ -static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override); +static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override); static volatile int g_break = 0; static int thread_break(void *UNUSED(arg)) @@ -190,14 +191,23 @@ void RE_FreeRenderResult(RenderResult *res) render_result_free(res); } -float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) +float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname) { RenderPass *rpass; - - for (rpass = rl->passes.first; rpass; rpass = rpass->next) - if (rpass->passtype == passtype) - return rpass->rect; - return NULL; + float *rect = NULL; + + for (rpass = rl->passes.last; rpass; rpass = rpass->prev) { + if (rpass->passtype == passtype) { + rect = rpass->rect; + + if (viewname == NULL) + break; + else if (strcmp(rpass->view, viewname) == 0) + break; + } + } + + return rect; } RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) @@ -307,8 +317,69 @@ Scene *RE_GetScene(Render *re) return NULL; } +/** + * Same as #RE_AcquireResultImage but creating the necessary views to store the result + * fill provided result struct with a copy of thew views of what is done so far the + * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews +*/ +void RE_AcquireResultImageViews(Render *re, RenderResult *rr) +{ + memset(rr, 0, sizeof(RenderResult)); + + if (re) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ); + + if (re->result) { + RenderLayer *rl; + RenderView *rv, *rview; + + rr->rectx = re->result->rectx; + rr->recty = re->result->recty; + + /* creates a temporary duplication of views */ + render_result_views_shallowcopy(rr, re->result); + + rv = rr->views.first; + + rr->have_combined = (rv->rectf != NULL); + + /* active layer */ + rl = render_get_active_layer(re, re->result); + + if (rl) { + if (rv->rectf == NULL) { + for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) { + rview->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rview->name); + } + } + + if (rv->rectz == NULL) { + for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) { + rview->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rview->name); + } + } + } + + rr->layers = re->result->layers; + rr->xof = re->disprect.xmin; + rr->yof = re->disprect.ymin; + } + } +} + +/* clear temporary renderresult struct */ +void RE_ReleaseResultImageViews(Render *re, RenderResult *rr) +{ + if (re) { + if (rr) { + render_result_views_shallowdelete(rr); + } + BLI_rw_mutex_unlock(&re->resultmutex); + } +} + /* fill provided result struct with what's currently active or done */ -void RE_AcquireResultImage(Render *re, RenderResult *rr) +void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) { memset(rr, 0, sizeof(RenderResult)); @@ -317,27 +388,35 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr) if (re->result) { RenderLayer *rl; + RenderView *rv; rr->rectx = re->result->rectx; rr->recty = re->result->recty; - rr->rectf = re->result->rectf; - rr->rectz = re->result->rectz; - rr->rect32 = re->result->rect32; - + /* actview view */ + rv = BLI_findlink(&re->result->views, view_id); + if (rv == NULL) + rv = (RenderView *)re->result->views.first; + + rr->rectf = rv ? rv->rectf : NULL; + rr->rectz = rv ? rv->rectz : NULL; + rr->rect32 = rv ? rv->rect32 : NULL; + /* active layer */ rl = render_get_active_layer(re, re->result); - if (rl) { - if (rr->rectf == NULL) - rr->rectf = rl->rectf; - if (rr->rectz == NULL) - rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z); + if (rl && rv) { + if (rv->rectf == NULL) + rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name); + + if (rv->rectz == NULL) + rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name); } - rr->have_combined = (re->result->rectf != NULL); + rr->have_combined = rv ? (rv->rectf != NULL) : false; rr->layers = re->result->layers; - + rr->views = re->result->views; + rr->xof = re->disprect.xmin; rr->yof = re->disprect.ymin; } @@ -354,17 +433,18 @@ void RE_ReleaseResultImage(Render *re) void RE_ResultGet32(Render *re, unsigned int *rect) { RenderResult rres; - - RE_AcquireResultImage(re, &rres); - render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); + const size_t view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname); + + RE_AcquireResultImage(re, &rres, view_id); + render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, 0); RE_ReleaseResultImage(re); } /* caller is responsible for allocating rect in correct size! */ /* Only for acquired results, for lock */ -void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect) +void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect, const int view_id) { - render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); + render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id); } RenderStats *RE_GetStats(Render *re) @@ -683,6 +763,8 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, RE_init_threadcount(re); } +/* This function is only called by view3d rendering, which doesn't support + * multiview at the moment. so handle only one view here */ static void render_result_rescale(Render *re) { RenderResult *result = re->result; @@ -694,7 +776,7 @@ static void render_result_rescale(Render *re) if (src_rectf == NULL) { RenderLayer *rl = render_get_active_layer(re, re->result); if (rl != NULL) { - src_rectf = rl->rectf; + src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, ""); } } @@ -704,7 +786,8 @@ static void render_result_rescale(Render *re) &re->disprect, 0, RR_USE_MEM, - RR_ALL_LAYERS); + RR_ALL_LAYERS, + ""); if (re->result != NULL) { dst_rectf = re->result->rectf; @@ -712,7 +795,7 @@ static void render_result_rescale(Render *re) RenderLayer *rl; rl = render_get_active_layer(re, re->result); if (rl != NULL) { - dst_rectf = rl->rectf; + dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, ""); } } @@ -910,9 +993,9 @@ static void *do_part_thread(void *pa_v) if (R.test_break(R.tbh) == 0) { if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE)) - pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM); + pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM, R.viewname); else - pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS); + pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS, R.viewname); /* Copy EXR tile settings, so pipeline knows whether this is a result * for Save Buffers enabled rendering. @@ -935,7 +1018,7 @@ static void *do_part_thread(void *pa_v) /* merge too on break! */ if (R.result->do_exr_tile) { - render_result_exr_file_merge(R.result, pa->result); + render_result_exr_file_merge(R.result, pa->result, R.viewname); } else if (render_display_update_enabled(&R)) { /* on break, don't merge in result for preview renders, looks nicer */ @@ -1115,16 +1198,23 @@ static void *do_render_thread(void *thread_v) return NULL; } -static void threaded_tile_processor(Render *re) +static void main_render_result_end(Render *re) +{ + if (re->result->do_exr_tile) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_end(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } + + if (re->r.scemode & R_EXR_CACHE_FILE) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_cache_write(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } +} + +static void main_render_result_new(Render *re) { - RenderThread thread[BLENDER_MAX_THREADS]; - ThreadQueue *workqueue, *donequeue; - ListBase threads; - RenderPart *pa; - rctf viewplane = re->viewplane; - double lastdraw, elapsed, redrawtime = 1.0f; - int totpart = 0, minx = 0, slice = 0, a, wait; - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); /* first step; free the entire render result, make new, and/or prepare exr buffer saving */ @@ -1132,25 +1222,35 @@ static void threaded_tile_processor(Render *re) render_result_free(re->result); if (re->sss_points && render_display_update_enabled(re)) - 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); else if (re->r.scemode & R_FULL_SAMPLE) - re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR); + re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR, RR_ALL_VIEWS); else re->result = render_result_new(re, &re->disprect, 0, - (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS); + (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); } BLI_rw_mutex_unlock(&re->resultmutex); + + if (re->result->do_exr_tile) + render_result_exr_file_begin(re); +} + +static void threaded_tile_processor(Render *re) +{ + RenderThread thread[BLENDER_MAX_THREADS]; + ThreadQueue *workqueue, *donequeue; + ListBase threads; + RenderPart *pa; + rctf viewplane = re->viewplane; + double lastdraw, elapsed, redrawtime = 1.0f; + int totpart = 0, minx = 0, slice = 0, a, wait; if (re->result == NULL) return; /* warning; no return here without closing exr file */ - RE_parts_init(re, true); - - if (re->result->do_exr_tile) - render_result_exr_file_begin(re); /* assuming no new data gets added to dbase... */ R = *re; @@ -1256,18 +1356,6 @@ static void threaded_tile_processor(Render *re) BLI_thread_queue_free(donequeue); BLI_thread_queue_free(workqueue); - if (re->result->do_exr_tile) { - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - render_result_exr_file_end(re); - BLI_rw_mutex_unlock(&re->resultmutex); - } - - if (re->r.scemode & R_EXR_CACHE_FILE) { - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - render_result_exr_file_cache_write(re); - BLI_rw_mutex_unlock(&re->resultmutex); - } - /* unset threadsafety */ g_break = 0; BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); @@ -1284,6 +1372,7 @@ static void free_all_freestyle_renders(void); /* currently only called by preview renders and envmap */ void RE_TileProcessor(Render *re) { + main_render_result_new(re); threaded_tile_processor(re); re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; @@ -1309,6 +1398,7 @@ void RE_TileProcessor(Render *re) static void do_render_3d(Render *re) { + RenderView *rv; int cfra_backup; re->current_scene_update(re->suh, re->scene); @@ -1325,40 +1415,49 @@ static void do_render_3d(Render *re) BKE_scene_frame_set(re->scene, (double)re->scene->r.cfra + (double)re->mblur_offs + (double)re->field_offs); - /* lock drawing in UI during data phase */ - if (re->draw_lock) - re->draw_lock(re->dlh, 1); - - /* make render verts/faces/halos/lamps */ - if (render_scene_needs_vector(re)) { - RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay); - } - else { - RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); - RE_Database_Preprocess(re); - } + /* init main render result */ + main_render_result_new(re); + + /* we need a new database for each view */ + for (rv = re->result->views.first; rv; rv = rv->next) { + RE_SetActiveRenderView(re, rv->name); + + /* lock drawing in UI during data phase */ + if (re->draw_lock) + re->draw_lock(re->dlh, 1); + + /* make render verts/faces/halos/lamps */ + if (render_scene_needs_vector(re)) + RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay); + else { + RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); + RE_Database_Preprocess(re); + } - /* clear UI drawing locks */ - if (re->draw_lock) - re->draw_lock(re->dlh, 0); + /* clear UI drawing locks */ + if (re->draw_lock) + re->draw_lock(re->dlh, 0); - threaded_tile_processor(re); + threaded_tile_processor(re); #ifdef WITH_FREESTYLE - /* Freestyle */ - if (re->r.mode & R_EDGE_FRS) - if (!re->test_break(re->tbh)) - add_freestyle(re, 1); + /* Freestyle */ + if (re->r.mode & R_EDGE_FRS) + if (!re->test_break(re->tbh)) + add_freestyle(re, 1); #endif - /* do left-over 3d post effects (flares) */ - if (re->flag & R_HALO) - if (!re->test_break(re->tbh)) - add_halo_flare(re); - - /* free all render verts etc */ - RE_Database_Free(re); - + /* do left-over 3d post effects (flares) */ + if (re->flag & R_HALO) + if (!re->test_break(re->tbh)) + add_halo_flare(re); + + /* free all render verts etc */ + RE_Database_Free(re); + } + + main_render_result_end(re); + re->scene->r.cfra = cfra_backup; re->scene->r.subframe = 0.f; } @@ -1431,19 +1530,13 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b rl1 = brr->layers.first; for (rl = rr->layers.first; rl && rl1; rl = rl->next, rl1 = rl1->next) { - - /* combined */ - if (rl->rectf && rl1->rectf) { - if (key_alpha) - addblur_rect_key(rr, rl->rectf, rl1->rectf, blurfac); - else - addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4); - } - /* passes are allocated in sync */ rpass1 = rl1->passes.first; for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) { - addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels); + if ((rpass->passtype & SCE_PASS_COMBINED) && key_alpha) + addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac); + else + addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels); } } } @@ -1456,7 +1549,7 @@ static void do_render_blur_3d(Render *re) int blur = re->r.mblur_samples; /* create accumulation render result */ - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); /* do the blur steps */ while (blur--) { @@ -1518,10 +1611,6 @@ static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, Rende rl2 = rr2->layers.first; for (rl = rr->layers.first; rl && rl1 && rl2; rl = rl->next, rl1 = rl1->next, rl2 = rl2->next) { - /* combined */ - if (rl->rectf && rl1->rectf && rl2->rectf) - interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4); - /* passes are allocated in sync */ rpass1 = rl1->passes.first; rpass2 = rl2->passes.first; @@ -1589,7 +1678,7 @@ static void do_render_fields_3d(Render *re) re->disprect.ymax *= 2; BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - 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); if (rr2) { if (re->r.mode & R_ODDFIELD) @@ -1661,7 +1750,7 @@ static void do_render_fields_blur_3d(Render *re) /* weak is: it chances disprect from border */ render_result_disprect_to_full_resolution(re); - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); render_result_merge(rres, re->result); render_result_free(re->result); @@ -2068,11 +2157,14 @@ static void free_all_freestyle_renders(void) } #endif -/* reads all buffers, calls optional composite, merges in first result->rectf */ +/* reads all buffers, calls optional composite, merges in first result->views rectf */ static void do_merge_fullsample(Render *re, bNodeTree *ntree) { + ListBase *rectfs; + RenderView *rv; float *rectf, filt[3][3]; int x, y, sample; + int nr, numviews; /* interaction callbacks */ if (ntree) { @@ -2087,9 +2179,18 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* filtmask needs it */ R = *re; - /* we accumulate in here */ - rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); - + /* temporary storage of the acccumulation buffers */ + rectfs = MEM_callocN(sizeof(ListBase), "fullsample accumulation buffers"); + + numviews = BLI_listbase_count(&re->result->views); + for (nr = 0; nr < numviews; nr++) { + rv = MEM_callocN(sizeof(RenderView), "fullsample renderview"); + + /* we accumulate in here */ + rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); + BLI_addtail(rectfs, rv); + } + for (sample = 0; sample < re->r.osa; sample++) { Scene *sce; Render *re1; @@ -2126,54 +2227,70 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) if (ntree) { ntreeCompositTagRender(re->scene); ntreeCompositTagAnimated(ntree); - - ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings); + + for (rv = re->result->views.first; rv; rv = rv->next) { + ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name); + } } - - /* ensure we get either composited result or the active layer */ - RE_AcquireResultImage(re, &rres); - - /* accumulate with filter, and clip */ - mask = (1 << sample); - mask_array(mask, filt); - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; - float *col = rres.rectf + 4 * y * re->rectx; - - for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { - /* clamping to 1.0 is needed for correct AA */ - if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f; - if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f; - if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f; + for (nr = 0, rv = re->result->views.first; rv; rv = rv->next, nr++) { + rectf = rv->rectf; + + /* ensure we get either composited result or the active layer */ + RE_AcquireResultImage(re, &rres, nr); + + /* accumulate with filter, and clip */ + mask = (1 << sample); + mask_array(mask, filt); + + for (y = 0; y < re->recty; y++) { + float *rf = rectf + 4 * y * re->rectx; + float *col = rres.rectf + 4 * y * re->rectx; - add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); + for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { + /* clamping to 1.0 is needed for correct AA */ + if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f; + if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f; + if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f; + + add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); + } } - } - RE_ReleaseResultImage(re); + RE_ReleaseResultImage(re); - /* show stuff */ - if (sample != re->osa - 1) { - /* weak... the display callback wants an active renderlayer pointer... */ - re->result->renlay = render_get_active_layer(re, re->result); - re->display_update(re->duh, re->result, NULL); + /* show stuff */ + if (sample != re->osa - 1) { + /* weak... the display callback wants an active renderlayer pointer... */ + re->result->renlay = render_get_active_layer(re, re->result); + RE_SetActiveRenderView(re, rv->name); + re->display_update(re->duh, re->result, NULL); + } } - - if (re->test_break(re->tbh)) - break; } - /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; + for (nr = 0; nr < numviews; nr++) { + rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf; + + /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ + for (y = 0; y < re->recty; y++) { + float *rf = rectf + 4 * y * re->rectx; - for (x = 0; x < re->rectx; x++, rf += 4) { - rf[0] = MAX2(rf[0], 0.0f); - rf[1] = MAX2(rf[1], 0.0f); - rf[2] = MAX2(rf[2], 0.0f); - CLAMP(rf[3], 0.0f, 1.0f); + for (x = 0; x < re->rectx; x++, rf += 4) { + rf[0] = MAX2(rf[0], 0.0f); + rf[1] = MAX2(rf[1], 0.0f); + rf[2] = MAX2(rf[2], 0.0f); + CLAMP(rf[3], 0.0f, 1.0f); + } } + + /* store the final result */ + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + rv = BLI_findlink(&re->result->views, nr); + if (rv->rectf) + MEM_freeN(rv->rectf); + rv->rectf = rectf; + BLI_rw_mutex_unlock(&re->resultmutex); } /* clear interaction callbacks */ @@ -2186,12 +2303,14 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* disable full sample print */ R.i.curfsa = 0; - - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - if (re->result->rectf) - MEM_freeN(re->result->rectf); - re->result->rectf = rectf; - BLI_rw_mutex_unlock(&re->resultmutex); + + /* garbage collection */ + while (rectfs->first) { + RenderView *rv = rectfs->first; + BLI_remlink(rectfs, rv); + MEM_freeN(rv); + } + MEM_freeN(rectfs); } /* called externally, via compositor */ @@ -2267,7 +2386,11 @@ static void do_render_composite_fields_blur_3d(Render *re) if (composite_needs_render(re->scene, 1)) { /* save memory... free all cached images */ ntreeFreeCache(ntree); - + + /* render the frames + * it could be optimized to render only the needed view + * but what if a scene has a different number of views + * than the main scene? */ do_render_fields_blur_3d(re); } else { @@ -2280,7 +2403,7 @@ static void do_render_composite_fields_blur_3d(Render *re) if ((re->r.mode & R_CROP) == 0) { render_result_disprect_to_full_resolution(re); } - 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); BLI_rw_mutex_unlock(&re->resultmutex); @@ -2325,7 +2448,10 @@ static void do_render_composite_fields_blur_3d(Render *re) if (re->r.scemode & R_FULL_SAMPLE) do_merge_fullsample(re, ntree); else { - ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings); + RenderView *rv; + for (rv = re->result->views.first; rv; rv = rv->next) { + ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name); + } } ntree->stats_draw = NULL; @@ -2350,13 +2476,17 @@ static void do_render_composite_fields_blur_3d(Render *re) static void renderresult_stampinfo(Render *re) { RenderResult rres; + RenderView *rv; + int nr; /* this is the basic trick to get the displayed float or char rect from render result */ - RE_AcquireResultImage(re, &rres); - BKE_image_stamp_buf( - re->scene, RE_GetCamera(re), - (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4); - RE_ReleaseResultImage(re); + nr = 0; + for (rv = re->result->views.first;rv;rv = rv->next, nr++) { + RE_SetActiveRenderView(re, rv->name); + RE_AcquireResultImage(re, &rres, nr); + BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rv->rect32, rv->rectf, rres.rectx, rres.recty, 4); + RE_ReleaseResultImage(re); + } } int RE_seq_render_active(Scene *scene, RenderData *rd) @@ -2380,10 +2510,12 @@ int RE_seq_render_active(Scene *scene, RenderData *rd) static void do_render_seq(Render *re) { static int recurs_depth = 0; - struct ImBuf *ibuf, *out; + struct ImBuf *out; RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */ int cfra = re->r.cfra; SeqRenderData context; + size_t view_id, tot_views; + struct ImBuf **ibuf_arr; int re_x, re_y; re->i.cfra = cfra; @@ -2406,45 +2538,67 @@ static void do_render_seq(Render *re) re_y = re->result->recty; } + tot_views = BKE_scene_multiview_num_views_get(&re->r); + ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * tot_views, "Sequencer Views ImBufs"); + BKE_sequencer_new_render_data( re->eval_ctx, re->main, re->scene, re_x, re_y, 100, &context); - out = BKE_sequencer_give_ibuf(&context, cfra, 0); + /* the renderresult gets destroyed during the rendering, so we first collect all ibufs + * and then we populate the final renderesult */ - if (out) { - ibuf = IMB_dupImBuf(out); - IMB_freeImBuf(out); - BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf); - } - else { - ibuf = NULL; - } + for (view_id = 0; view_id < tot_views; view_id++) { + context.view_id = view_id; + out = BKE_sequencer_give_ibuf(&context, cfra, 0); - recurs_depth--; + if (out) { + ibuf_arr[view_id] = IMB_dupImBuf(out); + IMB_freeImBuf(out); + BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf_arr[view_id]); + } + else { + ibuf_arr[view_id] = NULL; + } + } rr = re->result; - + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_views_new(rr, &re->r); + BLI_rw_mutex_unlock(&re->resultmutex); - if (ibuf) { - /* copy ibuf into combined pixel rect */ - render_result_rect_from_ibuf(rr, &re->r, ibuf); - - if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */ - Editing *ed = re->scene->ed; - if (ed) - BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true); + for (view_id = 0; view_id < tot_views; view_id++) { + RenderView *rv = BLI_findlink(&rr->views, view_id); + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + + if (ibuf_arr[view_id]) { + /* copy ibuf into combined pixel rect */ + render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id); + + if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */ + Editing *ed = re->scene->ed; + if (ed) + BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true); + } + IMB_freeImBuf(ibuf_arr[view_id]); } - IMB_freeImBuf(ibuf); - } - else { - /* render result is delivered empty in most cases, nevertheless we handle all cases */ - render_result_rect_fill_zero(rr); + else { + /* render result is delivered empty in most cases, nevertheless we handle all cases */ + render_result_rect_fill_zero(rr, view_id); + } + + BLI_rw_mutex_unlock(&re->resultmutex); + + /* would mark display buffers as invalid */ + RE_SetActiveRenderView(re, rv->name); + re->display_update(re->duh, re->result, NULL); } - BLI_rw_mutex_unlock(&re->resultmutex); + MEM_freeN(ibuf_arr); + + recurs_depth--; /* just in case this flag went missing at some point */ re->r.scemode |= R_DOSEQ; @@ -2454,9 +2608,6 @@ static void do_render_seq(Render *re) re->progress(re->prh, (float)(cfra - re->r.sfra) / (re->r.efra - re->r.sfra)); else re->progress(re->prh, 1.0f); - - /* would mark display buffers as invalid */ - re->display_update(re->duh, re->result, NULL); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -2543,11 +2694,50 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override } } +static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportList *reports) +{ + SceneRenderView *srv; + bool active_view = false; + + if ((scene->r.scemode & R_MULTIVIEW) == 0) + return true; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { + active_view = true; + + if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW) { + Object *view_camera; + view_camera = BKE_camera_multiview_render(scene, camera, srv->name); + + if (view_camera == camera) { + /* if the suffix is not in the camera, means we are using the fallback camera */ + if (!BLI_str_endswith(view_camera->id.name + 2, srv->suffix)) { + BKE_reportf(reports, RPT_ERROR, "Camera \"%s\" is not a multi-view camera", + camera->id.name + 2); + return false; + } + } + } + } + } + + if (!active_view) { + BKE_reportf(reports, RPT_ERROR, "No active view found in scene \"%s\"", scene->id.name + 2); + return false; + } + + return true; +} + static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports) { if (camera_override == NULL && scene->camera == NULL) scene->camera = BKE_scene_camera_find(scene); + if (!check_valid_camera_multiview(scene, scene->camera, reports)) + return false; + if (RE_seq_render_active(scene, &scene->r)) { if (scene->ed) { Sequence *seq = scene->ed->seqbase.first; @@ -2565,6 +2755,8 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList } } } + else if (!check_valid_camera_multiview(seq->scene, seq->scene_camera, reports)) + return false; } seq = seq->next; @@ -2729,6 +2921,17 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init) BKE_ptcache_bake(&baker); } + +void RE_SetActiveRenderView(Render *re, const char *viewname) +{ + BLI_strncpy(re->viewname, viewname, sizeof(re->viewname)); +} + +const char *RE_GetActiveRenderView(Render *re) +{ + return re->viewname; +} + /* evaluating scene options for general Blender render */ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay_override, int anim, int anim_init) @@ -2764,7 +2967,8 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, re->lay = lay_override ? lay_override : scene->lay; re->layer_override = lay_override; re->i.localview = (re->lay & 0xFF000000) != 0; - + re->viewname[0] = '\0'; + /* not too nice, but it survives anim-border render */ if (anim) { render_update_anim_renderdata(re, &scene->r); @@ -2838,10 +3042,10 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr char name[FILE_MAX]; BKE_image_path_from_imformat( name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false); + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL); /* reports only used for Movie */ - do_write_image_or_movie(re, bmain, scene, NULL, name); + do_write_image_or_movie(re, bmain, scene, NULL, 0, name); } } @@ -2879,96 +3083,269 @@ void RE_RenderFreestyleExternal(Render *re) } #endif -static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override) +bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, struct Object *camera, const bool stamp, char *name) { - char name[FILE_MAX]; - RenderResult rres; - Object *camera = RE_GetCamera(re); - double render_time; - int ok = 1; - - RE_AcquireResultImage(re, &rres); + bool is_mono; + bool ok = true; + RenderData *rd = &scene->r; - /* write movie or image */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - bool do_free = false; - ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r); + if (!rr) + return false; - /* note; the way it gets 32 bits rects is weak... */ - if (ibuf->rect == NULL) { - ibuf->rect = MEM_mapallocN(sizeof(int) * rres.rectx * rres.recty, "temp 32 bits rect"); - ibuf->mall |= IB_rect; - RE_AcquiredResultGet32(re, &rres, ibuf->rect); - do_free = true; - } + is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + if (ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && + rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW) + { + RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL); + printf("Saved: %s\n", name); + } - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &scene->r.im_format); + /* mono, legacy code */ + else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) + { + RenderView *rv; + size_t view_id; + char filepath[FILE_MAX]; - ok = mh->append_movie(&re->r, scene->r.sfra, scene->r.cfra, (int *) ibuf->rect, - ibuf->x, ibuf->y, re->reports); - if (do_free) { - MEM_freeN(ibuf->rect); - ibuf->rect = NULL; - ibuf->mall &= ~IB_rect; - } + BLI_strncpy(filepath, name, sizeof(filepath)); - /* imbuf knows which rects are not part of ibuf */ - IMB_freeImBuf(ibuf); + for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) { + BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name); - printf("Append frame %d", scene->r.cfra); - } - else { - if (name_override) - BLI_strncpy(name, name_override, sizeof(name)); - else - BKE_image_path_from_imformat( - name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); - - if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { - if (re->result) { - RE_WriteRenderResult(re->reports, re->result, name, scene->r.im_format.exr_codec); - printf("Saved: %s", name); + if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { + + RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name); + printf("Saved: %s\n", name); } + 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); + + if (stamp) { + /* writes the name of the individual cameras */ + Object *view_camera = BKE_camera_multiview_render(scene, camera, rv->name); + ok = BKE_imbuf_write_stamp(scene, view_camera, ibuf, name, &rd->im_format); + } + else { + ok = BKE_imbuf_write(ibuf, name, &rd->im_format); + } + + if (ok == false) { + printf("Render error: cannot save %s\n", name); + } + else printf("Saved: %s\n", name); + + /* optional preview images for exr */ + if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + ImageFormatData imf = rd->im_format; + imf.imtype = R_IMF_IMTYPE_JPEG90; + + if (BLI_testextensie(name, ".exr")) + name[strlen(name) - 4] = 0; + BKE_image_path_ensure_ext_from_imformat(name, &imf); + ibuf->planes = 24; + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &rd->im_format); + + if (stamp) { + /* writes the name of the individual cameras */ + Object *view_camera = BKE_camera_multiview_render(scene, camera, rv->name); + ok = BKE_imbuf_write_stamp(scene, view_camera, ibuf, name, &rd->im_format); + } + else { + ok = BKE_imbuf_write(ibuf, name, &rd->im_format); + } + printf("Saved: %s\n", name); + } + + /* 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 support for MultiLayer image: %s\n", name); } else { - ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r); + 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]); + } - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &scene->r.im_format); + ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); - ok = BKE_imbuf_write_stamp(scene, camera, ibuf, name, &scene->r.im_format); - - if (ok == 0) { + if (stamp) + ok = BKE_imbuf_write_stamp(scene, camera, ibuf_arr[2], name, &rd->im_format); + else + ok = BKE_imbuf_write(ibuf_arr[2], name, &rd->im_format); + + if (ok == false) printf("Render error: cannot save %s\n", name); - } - else printf("Saved: %s", name); - + else + printf("Saved: %s\n", name); + /* optional preview images for exr */ - if (ok && scene->r.im_format.imtype == R_IMF_IMTYPE_OPENEXR && (scene->r.im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { - ImageFormatData imf = scene->r.im_format; + if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && + (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) + { + ImageFormatData imf = rd->im_format; imf.imtype = R_IMF_IMTYPE_JPEG90; if (BLI_testextensie(name, ".exr")) name[strlen(name) - 4] = 0; + BKE_image_path_ensure_ext_from_imformat(name, &imf); - ibuf->planes = 24; + ibuf_arr[2]->planes = 24; - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + IMB_colormanagement_imbuf_for_write(ibuf_arr[2], true, false, &scene->view_settings, &scene->display_settings, &imf); - BKE_imbuf_write_stamp(scene, camera, ibuf, name, &imf); - printf("\nSaved: %s", name); + if (stamp) + ok = BKE_imbuf_write_stamp(scene, camera, ibuf_arr[2], name, &rd->im_format); + else + ok = BKE_imbuf_write(ibuf_arr[2], name, &imf); + + printf("Saved: %s\n", name); } - + + /* 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, RenderData *rd, bMovieHandle *mh, + const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos) +{ + bool is_mono; + bool ok = true; + + if (!rr) + return false; + + is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + + if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { + size_t view_id; + for (view_id = 0; view_id < totvideos; view_id++) { + bool do_free = false; + 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); + + /* note; the way it gets 32 bits rects is weak... */ + if (ibuf->rect == NULL) { + ibuf->rect = MEM_mapallocN(sizeof(int) * rr->rectx * rr->recty, "temp 32 bits rect"); + ibuf->mall |= IB_rect; + render_result_rect_get_pixels(rr, ibuf->rect, width, height, &scene->view_settings, &scene->display_settings, view_id); + do_free = true; + } + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + + ok &= mh->append_movie(movie_ctx_arr[view_id], rd, scene->r.sfra, scene->r.cfra, + (int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports); + + if (do_free) { + MEM_freeN(ibuf->rect); + ibuf->rect = NULL; + ibuf->mall &= ~IB_rect; + } + /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); } + printf("Append frame %d\n", scene->r.cfra); + } + else { /* R_IMF_VIEWS_STEREO_3D */ + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + ImBuf *ibuf_arr[3] = {NULL}; + bool do_free[2] = {false, false}; + size_t i; + + BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D)); + + 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); + + /* note; the way it gets 32 bits rects is weak... */ + if (ibuf_arr[i]->rect == NULL) { + ibuf_arr[i]->rect = MEM_mapallocN(sizeof(int) * width * height, "temp 32 bits rect"); + ibuf_arr[i]->mall |= IB_rect; + render_result_rect_get_pixels(rr, ibuf_arr[i]->rect, width, height, &scene->view_settings, &scene->display_settings, view_id); + do_free[i] = true; + } + + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + } + + ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); + + ok = mh->append_movie(movie_ctx_arr[0], rd, scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect, + ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports); + + for (i = 0; i < 2; i++) { + if (do_free[i]) { + MEM_freeN(ibuf_arr[i]->rect); + ibuf_arr[i]->rect = NULL; + ibuf_arr[i]->mall &= ~IB_rect; + } + + /* imbuf knows which rects are not part of ibuf */ + IMB_freeImBuf(ibuf_arr[i]); + } + } + + return ok; +} + +static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override) +{ + char name[FILE_MAX]; + RenderResult rres; + double render_time; + bool ok = true; + Object *camera = RE_GetCamera(re); + + RE_AcquireResultImageViews(re, &rres); + + /* write movie or image */ + if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { + RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos); + } + else { + if (name_override) + BLI_strncpy(name, name_override, sizeof(name)); + else + BKE_image_path_from_imformat( + name, scene->r.pic, bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); + + /* write images as individual images or stereo */ + ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, camera, true, name); } - RE_ReleaseResultImage(re); + RE_ReleaseResultImageViews(re, &rres); render_time = re->i.lastframetime; re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; @@ -2987,20 +3364,51 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie return ok; } +static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, size_t *r_height) +{ + size_t width, height; + if (re->r.mode & R_BORDER) { + if ((re->r.mode & R_CROP) == 0) { + width = re->winx; + height = re->winy; + } + else { + width = re->rectx; + height = re->recty; + } + } + else { + width = re->rectx; + height = re->recty; + } + + BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height); +} + /* saves images to disk */ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override, unsigned int lay_override, int sfra, int efra, int tfra) { RenderData rd = scene->r; - bMovieHandle *mh = BKE_movie_handle_get(scene->r.im_format.imtype); + bMovieHandle *mh = NULL; int cfrao = scene->r.cfra; int nfra, totrendered = 0, totskipped = 0; - + const size_t totvideos = BKE_scene_multiview_num_videos_get(&rd); + const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); + const bool is_multiview_name = ((scene->r.scemode & R_MULTIVIEW) != 0 && + (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)); + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT); /* do not fully call for each frame, it initializes & pops output window */ if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1)) return; + + /* we don't support Frame Server and streaming of individual views */ + if ((rd.im_format.imtype == R_IMF_IMTYPE_FRAMESERVER) && (totvideos > 1)) { + BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering"); + return; + } /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */ /* is also set by caller renderwin.c */ @@ -3008,31 +3416,33 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri re->flag |= R_ANIMATION; - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - int width, height; - if (re->r.mode & R_BORDER) { - if ((re->r.mode & R_CROP) == 0) { - width = re->winx; - height = re->winy; - } - else { - width = re->rectx; - height = re->recty; - } - } - else { - width = re->rectx; - height = re->recty; - } + if (is_movie) { + size_t i, width, height; + + get_videos_dimensions(re, &rd, &width, &height); + + mh = BKE_movie_handle_get(scene->r.im_format.imtype); + re->movie_ctx_arr = MEM_mallocN(sizeof(void *) * totvideos, "Movies' Context"); + + for (i = 0; i < totvideos; i++) { + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&re->r, i); - /* last argument here depends on users really, but no users using preview have been found so far */ - if (!mh->start_movie(scene, &re->r, width, height, re->reports, false)) - G.is_break = true; + re->movie_ctx_arr[i] = mh->context_create(); + + if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix)) + G.is_break = true; + } } - if (mh->get_next_frame) { + if (mh && mh->get_next_frame) { + /* MULTIVIEW_TODO: + * in case a new video format is added that implements get_next_frame multiview has to be addressed + * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well + */ + BLI_assert(totvideos < 2); + while (!(G.is_break == 1)) { - int nf = mh->get_next_frame(&re->r, re->reports); + int nf = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports); if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) { scene->r.cfra = re->r.cfra = nf; @@ -3042,7 +3452,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri totrendered++; if (re->test_break(re->tbh) == 0) { - if (!do_write_image_or_movie(re, bmain, scene, mh, NULL)) + if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) G.is_break = true; } @@ -3085,20 +3495,67 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri nfra += tfra; /* Touch/NoOverwrite options are only valid for image's */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) { + if (is_movie == false) { if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH)) BKE_image_path_from_imformat( name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); + + if (scene->r.mode & R_NO_OVERWRITE) { + if (!is_multiview_name) { + if (BLI_exists(name)) { + printf("skipping existing frame \"%s\"\n", name); + totskipped++; + continue; + } + } + else { + SceneRenderView *srv; + bool is_skip = false; + char filepath[FILE_MAX]; - if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) { - printf("skipping existing frame \"%s\"\n", name); - totskipped++; - continue; + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if (BLI_exists(filepath)) { + is_skip = true; + printf("skipping existing frame \"%s\" for view \"%s\"\n", filepath, srv->name); + } + } + + if (is_skip) { + totskipped++; + continue; + } + } } - if (scene->r.mode & R_TOUCH && !BLI_exists(name)) { - BLI_make_existing_file(name); /* makes the dir if its not there */ - BLI_file_touch(name); + + if (scene->r.mode & R_TOUCH) { + if (!is_multiview_name) { + if (!BLI_exists(name)) { + BLI_make_existing_file(name); /* makes the dir if its not there */ + BLI_file_touch(name); + } + } + else { + SceneRenderView *srv; + char filepath[FILE_MAX]; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if (!BLI_exists(filepath)) { + BLI_make_existing_file(filepath); /* makes the dir if its not there */ + BLI_file_touch(filepath); + } + } + } } } @@ -3113,7 +3570,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (re->test_break(re->tbh) == 0) { if (!G.is_break) - if (!do_write_image_or_movie(re, bmain, scene, mh, NULL)) + if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) G.is_break = true; } else @@ -3121,10 +3578,30 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (G.is_break == true) { /* remove touched file */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) { - if ((scene->r.mode & R_TOUCH) && (BLI_file_size(name) == 0)) { - /* BLI_exists(name) is implicit */ - BLI_delete(name, false, false); + if (is_movie == false) { + if ((scene->r.mode & R_TOUCH)) { + if (!is_multiview_name) { + if ((BLI_file_size(name) == 0)) { + /* BLI_exists(name) is implicit */ + BLI_delete(name, false, false); + } + } + else { + SceneRenderView *srv; + char filepath[FILE_MAX]; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if ((BLI_file_size(filepath) == 0)) { + /* BLI_exists(filepath) is implicit */ + BLI_delete(filepath, false, false); + } + } + } } } @@ -3139,8 +3616,17 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri } /* end movie */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) - mh->end_movie(); + if (is_movie) { + size_t i; + for (i = 0; i < totvideos; i++) { + mh->end_movie(re->movie_ctx_arr[i]); + mh->context_free(re->movie_ctx_arr[i]); + } + + if (re->movie_ctx_arr) { + MEM_freeN(re->movie_ctx_arr); + } + } if (totskipped && totrendered == 0) BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite"); @@ -3238,13 +3724,22 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char { /* OCIO_TODO: assume layer was saved in defaule color space */ ImBuf *ibuf = IMB_loadiffname(filename, IB_rect, NULL); + RenderPass *rpass = NULL; + + /* multiview: since the API takes no 'view', we use the first combined pass found */ + for (rpass = layer->passes.first; rpass; rpass = rpass->next) + if (rpass->passtype == SCE_PASS_COMBINED) + break; + + if (rpass == NULL) + BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: no Combined pass found in the render layer '%s'", filename); if (ibuf && (ibuf->rect || ibuf->rect_float)) { if (ibuf->x == layer->rectx && ibuf->y == layer->recty) { if (ibuf->rect_float == NULL) IMB_float_from_rect(ibuf); - memcpy(layer->rectf, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); + memcpy(rpass->rect, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); } else { if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) { @@ -3257,7 +3752,7 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char if (ibuf_clip) { IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty); - memcpy(layer->rectf, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); + memcpy(rpass->rect, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); IMB_freeImBuf(ibuf_clip); } else { @@ -3345,3 +3840,21 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, } } +/* used in the interface to decide whether to show layers */ +bool RE_layers_have_name(struct RenderResult *rr) +{ + switch (BLI_listbase_count_ex(&rr->layers, 2)) { + case 0: + return false; + break; + case 1: + return (((RenderLayer *)rr->layers.first)->name[0] != '\0'); + break; + default: + return true; + break; + } + return false; +} + + diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 6486844bacf..90f6eab0cc1 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) @@ -115,13 +134,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,108 +358,131 @@ 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 *end; + const char *token; + int 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; + } + + end = passtype_name + strlen(passtype_name); + len = IMB_exr_split_token(passtype_name, end, &token); + + if (len == strlen(passtype_name)) + sprintf(passname, "%s.%s", passtype_name, view); + else + sprintf(passname, "%.*s%s.%s", (int)(end-passtype_name) - len, passtype_name, view, token); +} + /********************************** 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; @@ -418,12 +491,16 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int 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); } else { float *rect; @@ -460,9 +537,10 @@ 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), @@ -475,12 +553,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, i; rectx = BLI_rcti_size_x(partrct); recty = BLI_rcti_size_y(partrct); @@ -505,6 +585,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 +620,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, + RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS, 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 +716,27 @@ 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); + + for (i=0; i < 4; i++) + IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(SCE_PASS_COMBINED, i), view, 0, 0, NULL); + } + else { + 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 +754,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 +783,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)); } -/* from imbuf, if a handle was returned we convert this to render result */ +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 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 +885,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,6 +909,33 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace return rr; } +void render_result_views_new(RenderResult *rr, RenderData *rd) +{ + SceneRenderView *srv; + RenderView *rv; + + /* 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; + + rv = MEM_callocN(sizeof(RenderView), "new render view"); + BLI_addtail(&rr->views, rv); + + BLI_strncpy(rv->name, srv->name, sizeof(rv->name)); + } + } + + /* we always need at least one view */ + if (BLI_listbase_count_ex(&rr->views, 1) == 0) { + rv = MEM_callocN(sizeof(RenderView), "new render view"); + BLI_addtail(&rr->views, rv); + } +} + /*********************************** Merge ***********************************/ static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize) @@ -783,16 +981,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 +1002,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,65 +1014,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); + bool success = false; + 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; + + 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); + if (rview->rectz) + IMB_exr_add_channel(exrhandle, "", RGBAZ[4], + rview->name, 1, width, rview->rectz); + } + } } - - /* 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); } } - - /* 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); + } + else { + IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view, + xstride, xstride * width, rpass->rect + a); + } } } } } - /* 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)) { IMB_exr_write_channels(exrhandle); - success = true; } else { /* TODO, get the error from openexr's exception */ 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 +1179,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 +1202,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,7 +1231,7 @@ 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); @@ -1002,13 +1245,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); } } } @@ -1055,10 +1298,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 +1331,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 +1372,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 +1431,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 +1442,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,14 +1457,14 @@ 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); /* 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 *) RE_RenderViewGetRect32(rr, view_id); + ibuf->rect_float = RE_RenderViewGetRectf(rr, view_id); + ibuf->zbuf_float = RE_RenderViewGetRectz(rr, view_id); /* float factor for random dither, imbuf takes care of it */ ibuf->dither = rd->dither_intensity; @@ -1259,53 +1500,73 @@ 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 = BLI_findlink(&rr->views, 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; + if (rv->rect32) { + MEM_freeN(rv->rect32); + rv->rect32 = NULL; } } 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 (rv->rectf) { + MEM_freeN(rv->rectf); + rv->rectf = NULL; + } + } + + /* clean up non-view buffers */ + if (rr) { if (rr->rectf) { MEM_freeN(rr->rectf); rr->rectf = NULL; } + + if (rr->rect32) { + MEM_freeN(rr->rect32); + rr->rect32 = NULL; + } } } -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 = BLI_findlink(&rr->views, 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); + int *rect32 = RE_RenderViewGetRect32(rr, view_id); + memcpy(rect, (rect32 ? rect32 : 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, + float *rectf = RE_RenderViewGetRectf(rr, view_id); + IMB_display_buffer_transform_apply((unsigned char *) rect, (rectf ? rectf : rr->rectf), rr->rectx, rr->recty, 4, view_settings, display_settings, true); } else @@ -1313,3 +1574,75 @@ void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rec 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; +} + +void RE_RenderViewSetRectf(RenderResult *res, const int view_id, float *rect) +{ + RenderView *rv = BLI_findlink(&res->views, view_id); + if (rv) { + rv->rectf = rect; + } +} + +void RE_RenderViewSetRectz(RenderResult *res, const int view_id, float *rect) +{ + RenderView *rv = BLI_findlink(&res->views, view_id); + if (rv) { + rv->rectz = rect; + } +} + +float *RE_RenderViewGetRectz(RenderResult *res, const int view_id) +{ + RenderView *rv = BLI_findlink(&res->views, view_id); + if (rv) { + return rv->rectz; + } + return res->rectz; +} + +float *RE_RenderViewGetRectf(RenderResult *res, const int view_id) +{ + RenderView *rv = BLI_findlink(&res->views, view_id); + if (rv) { + return rv->rectf; + } + return res->rectf; +} + +int *RE_RenderViewGetRect32(RenderResult *res, const int view_id) +{ + RenderView *rv = BLI_findlink(&res->views, view_id); + if (rv) { + return rv->rect32; + } + return res->rect32; +} + + diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 5b054005bac..99611a9c5a8 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -181,8 +181,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in if (fullsample) { for (sample=0; sample<totsample; sample++) - if (ps->mask & (1 << sample)) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + if (ps->mask & (1 << sample)) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } } else { fac= ((float)amountm)/(float)R.osa; @@ -214,8 +216,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in if (fullsample) { for (sample=0; sample<totsample; sample++) - if (!(mask & (1 << sample))) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + if (!(mask & (1 << sample))) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } } else { col[0]= accol[0]; @@ -223,8 +227,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in col[2]= accol[2]; col[3]= accol[3]; - for (sample=0; sample<totsample; sample++) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + for (sample=0; sample<totsample; sample++) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } } } @@ -305,8 +311,10 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl) zz= calchalo_z(har, *rz); if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) { if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) { - for (sample=0; sample<totsample; sample++) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + for (sample=0; sample<totsample; sample++) { + float * rect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(rect + od*4, col, har->add); + } } } } @@ -359,7 +367,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) if (fullsample) { for (sample=0; sample<totsample; sample++) { if (ps->mask & (1 << sample)) { - pass= rlpp[sample]->rectf + od*4; + pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= col[0]; pass[1]+= col[1]; pass[2]+= col[2]; @@ -370,7 +379,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) } else { fac= ((float)count)/(float)R.osa; - pass= rl->rectf + od*4; + pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= fac*col[0]; pass[1]+= fac*col[1]; pass[2]+= fac*col[2]; @@ -390,7 +400,9 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) if (fullsample) { for (sample=0; sample<totsample; sample++) { if (!(mask & (1 << sample))) { - pass= rlpp[sample]->rectf + od*4; + + pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= col[0]; pass[1]+= col[1]; pass[2]+= col[2]; @@ -401,7 +413,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) } else { fac= ((float)R.osa-totsamp)/(float)R.osa; - pass= rl->rectf + od*4; + pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= fac*col[0]; pass[1]+= fac*col[1]; pass[2]+= fac*col[2]; @@ -420,7 +433,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) renderspothalo(&shi, col, 1.0f); for (sample=0; sample<totsample; sample++) { - pass= rlpp[sample]->rectf + od*4; + pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= col[0]; pass[1]+= col[1]; pass[2]+= col[2]; @@ -444,14 +458,14 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, { RenderPass *rpass; - /* combined rgb */ - add_filt_fmask(curmask, shr->combined, rl->rectf + 4*offset, rectx); - for (rpass= rl->passes.first; rpass; rpass= rpass->next) { float *fp, *col= NULL; int pixsize= 3; switch (rpass->passtype) { + case SCE_PASS_COMBINED: + add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx); + break; case SCE_PASS_Z: fp= rpass->rect + offset; *fp= shr->z; @@ -555,15 +569,16 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult { RenderPass *rpass; float *fp; - - fp= rl->rectf + 4*offset; - copy_v4_v4(fp, shr->combined); - + for (rpass= rl->passes.first; rpass; rpass= rpass->next) { float *col= NULL, uvcol[3]; int a, pixsize= 3; switch (rpass->passtype) { + case SCE_PASS_COMBINED: + /* copy combined to use for preview */ + copy_v4_v4(rpass->rect + 4*offset, shr->combined); + break; case SCE_PASS_Z: fp= rpass->rect + offset; *fp= shr->z; @@ -681,7 +696,8 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl) bool done = false; for (sample= 0; sample<totsample; sample++) { - float *pass= rlpp[sample]->rectf + od; + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od; if (pass[3]<1.0f) { @@ -742,8 +758,8 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl) int sample; for (sample=0; sample<totsample; sample++) { - const float *zrect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z) + od; - float *rgbrect = rlpp[sample]->rectf + 4*od; + const float *zrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z, R.viewname) + od; + float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname) + 4*od; float rgb[3] = {0}; bool done = false; @@ -978,8 +994,8 @@ static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl) return; for (sample= 0; sample<totsample; sample++) { - float *rectf= rlpp[sample]->rectf; - + float *rectf = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) { rectf[0] = MAX2(rectf[0], 0.0f); rectf[1] = MAX2(rectf[1], 0.0f); @@ -1060,7 +1076,7 @@ static void reset_sky_speed(RenderPart *pa, RenderLayer *rl) totsample= get_sample_layers(pa, rl, rlpp); for (sample= 0; sample<totsample; sample++) { - fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR); + fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR, R.viewname); if (fp==NULL) break; for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--) @@ -1171,6 +1187,8 @@ void zbufshadeDA_tile(RenderPart *pa) pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); for (rl= rr->layers.first; rl; rl= rl->next) { + float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK)) pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask"); @@ -1211,7 +1229,7 @@ void zbufshadeDA_tile(RenderPart *pa) if (R.flag & R_ZTRA || R.totstrand) { if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) { if (pa->fullresult.first) { - zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist); + zbuffer_transp_shade(pa, rl, rect, &psmlist); } else { unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */ @@ -1220,9 +1238,9 @@ void zbufshadeDA_tile(RenderPart *pa) rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); /* swap for live updates, and it is used in zbuf.c!!! */ - SWAP(float *, rl->acolrect, rl->rectf); - ztramask= zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist); - SWAP(float *, rl->acolrect, rl->rectf); + SWAP(float *, rl->acolrect, rect); + ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist); + SWAP(float *, rl->acolrect, rect); /* zbuffer transp only returns ztramask if there's solid rendered */ if (ztramask) @@ -1231,7 +1249,8 @@ void zbufshadeDA_tile(RenderPart *pa) if (ztramask && solidmask) { unsigned short *sps= solidmask, *spz= ztramask; unsigned short fullmask= (1<<R.osa)-1; - float *fcol= rl->rectf; float *acol= rl->acolrect; + float *fcol= rect; + float *acol= rl->acolrect; int x; for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) { @@ -1242,7 +1261,8 @@ void zbufshadeDA_tile(RenderPart *pa) } } else { - float *fcol= rl->rectf; float *acol= rl->acolrect; + float *fcol= rect; + float *acol= rl->acolrect; int x; for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { addAlphaOverFloat(fcol, acol); @@ -1265,7 +1285,7 @@ void zbufshadeDA_tile(RenderPart *pa) /* extra layers */ if (rl->layflag & SCE_LAY_EDGE) if (R.r.mode & R_EDGE) - edge_enhance_add(pa, rl->rectf, edgerect); + edge_enhance_add(pa, rect, edgerect); if (rl->passflag & SCE_PASS_VECTOR) reset_sky_speed(pa, rl); @@ -1319,6 +1339,7 @@ void zbufshade_tile(RenderPart *pa) pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); for (rl= rr->layers.first; rl; rl= rl->next) { + float *rect= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK)) pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask"); @@ -1342,7 +1363,7 @@ void zbufshade_tile(RenderPart *pa) rr->renlay= rl; if (rl->layflag & SCE_LAY_SOLID) { - const float *fcol= rl->rectf; + const float *fcol = rect; const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz; int x, y, offs=0, seed; @@ -1405,11 +1426,11 @@ void zbufshade_tile(RenderPart *pa) rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); /* swap for live updates */ - SWAP(float *, rl->acolrect, rl->rectf); - zbuffer_transp_shade(pa, rl, rl->rectf, NULL); - SWAP(float *, rl->acolrect, rl->rectf); + SWAP(float *, rl->acolrect, rect); + zbuffer_transp_shade(pa, rl, rect, NULL); + SWAP(float *, rl->acolrect, rect); - fcol= rl->rectf; acol= rl->acolrect; + fcol= rect; acol= rl->acolrect; for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { addAlphaOverFloat(fcol, acol); } @@ -1427,7 +1448,7 @@ void zbufshade_tile(RenderPart *pa) if (!R.test_break(R.tbh)) { if (rl->layflag & SCE_LAY_EDGE) if (R.r.mode & R_EDGE) - edge_enhance_add(pa, rl->rectf, edgerect); + edge_enhance_add(pa, rect, edgerect); } if (rl->passflag & SCE_PASS_VECTOR) @@ -1654,7 +1675,7 @@ void zbufshade_sss_tile(RenderPart *pa) return; } - fcol= rl->rectf; + fcol= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo"); color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor"); @@ -1938,6 +1959,7 @@ void add_halo_flare(Render *re) RenderLayer *rl; HaloRen *har; int a, mode; + float *rect; /* for now, we get the first renderlayer in list with halos set */ for (rl= rr->layers.first; rl; rl= rl->next) { @@ -1945,8 +1967,11 @@ void add_halo_flare(Render *re) if ((rl->layflag & SCE_LAY_HALO) == 0) continue; - if (rl->rectf==NULL) - continue; + + rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname); + + if (rl==NULL || rect) + return; mode= R.r.mode; R.r.mode &= ~R_PANORAMA; @@ -1958,7 +1983,7 @@ void add_halo_flare(Render *re) if (har->flarec && (har->lay & rl->lay)) { do_draw = true; - renderflare(rr, rl->rectf, har); + renderflare(rr, rect, har); } } diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index d5d8595bf3f..b6628796e0d 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -3959,7 +3959,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf float *fp, *col; int a; - fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR); + fp = RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR, R.viewname); if (fp==NULL) return; col= rectf+3; @@ -4052,9 +4052,10 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas /* zero alpha pixels get speed vector max again */ if (addpassflag & SCE_PASS_VECTOR) - if (rl->layflag & SCE_LAY_SOLID) - reset_sky_speedvectors(pa, rl, rl->acolrect?rl->acolrect:rl->rectf); /* if acolrect is set we use it */ - + if (rl->layflag & SCE_LAY_SOLID) { + float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + reset_sky_speedvectors(pa, rl, rl->acolrect ? rl->acolrect : rect); /* if acolrect is set we use it */ + } /* filtered render, for now we assume only 1 filter size */ if (pa->crop) { crop= 1; @@ -4239,8 +4240,9 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas alpha= samp_shr[a].combined[3]; if (alpha!=0.0f) { RenderLayer *rl= ssamp.rlpp[a]; - - addAlphaOverFloat(rl->rectf + 4*od, samp_shr[a].combined); + + float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined); add_transp_passes(rl, od, &samp_shr[a], alpha); if (addpassflag & SCE_PASS_VECTOR) |