/* called from within UI, saves both rendered result as a file-read result */ int RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress) { RenderLayer *rl; RenderPass *rpass; void *exrhandle = IMB_exr_get_handle(); int 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); } /* 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); } } /* 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); } else { IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), xstride, xstride * rr->rectx, rpass->rect + a); } } } } /* when the filename has no permissions, this can fail */ if (IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, 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); return success; }
void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename) { unsigned int width = this->getWidth(); unsigned int height = this->getHeight(); if (width != 0 && height != 0) { void *exrhandle; SceneRenderView *srv; /* get a new global handle */ exrhandle = IMB_exr_get_handle_name(filename); if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) return exrhandle; IMB_exr_clear_channels(exrhandle); /* check renderdata for amount of views */ for (srv = (SceneRenderView *) this->m_rd->views.first; srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false) continue; IMB_exr_add_view(exrhandle, srv->name); for (unsigned int i = 0; i < this->m_layers.size(); ++i) add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, srv->name, width, NULL); } BLI_make_existing_file(filename); /* prepare the file with all the channels for the header */ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec) == 0) { printf("Error Writing Multilayer Multiview Openexr\n"); IMB_exr_close(exrhandle); } else { IMB_exr_clear_channels(exrhandle); return exrhandle; } } return NULL; }
void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filename) { size_t width = this->getWidth(); size_t height = this->getHeight(); SceneRenderView *srv; if (width != 0 && height != 0) { void *exrhandle; exrhandle = IMB_exr_get_handle_name(filename); if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) return exrhandle; IMB_exr_clear_channels(exrhandle); for (srv = (SceneRenderView *)this->m_rd->views.first; srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false) continue; IMB_exr_add_view(exrhandle, srv->name); add_exr_channels(exrhandle, NULL, this->m_datatype, srv->name, width, NULL); } BLI_make_existing_file(filename); /* prepare the file with all the channels */ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_format->exr_codec) == 0) { printf("Error Writing Singlelayer Multiview Openexr\n"); IMB_exr_close(exrhandle); } else { IMB_exr_clear_channels(exrhandle); return exrhandle; } } return NULL; }
void OutputOpenExrMultiLayerOperation::deinitExecution() { unsigned int width = this->getWidth(); unsigned int height = this->getHeight(); if (width != 0 && height != 0) { Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; void *exrhandle = IMB_exr_get_handle(); BKE_makepicstring_from_type(filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER, (this->m_rd->scemode & R_EXTENSION), true); BLI_make_existing_file(filename); for (unsigned int i = 0; i < this->m_layers.size(); ++i) { OutputOpenExrLayer &layer = this->m_layers[i]; if (!layer.imageInput) continue; /* skip unconnected sockets */ char channelname[EXR_TOT_MAXNAME]; BLI_strncpy(channelname, this->m_layers[i].name, sizeof(channelname) - 2); char *channelname_ext = channelname + strlen(channelname); float *buf = this->m_layers[i].outputBuffer; /* create channels */ switch (this->m_layers[i].datatype) { case COM_DT_VALUE: strcpy(channelname_ext, ".V"); IMB_exr_add_channel(exrhandle, 0, channelname, 1, width, buf); break; case COM_DT_VECTOR: strcpy(channelname_ext, ".X"); IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf); strcpy(channelname_ext, ".Y"); IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 1); strcpy(channelname_ext, ".Z"); IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 2); break; case COM_DT_COLOR: strcpy(channelname_ext, ".R"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf); strcpy(channelname_ext, ".G"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 1); strcpy(channelname_ext, ".B"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 2); strcpy(channelname_ext, ".A"); IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 3); break; default: break; } } /* when the filename has no permissions, this can fail */ if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec)) { IMB_exr_write_channels(exrhandle); } else { /* TODO, get the error from openexr's exception */ /* XXX nice way to do report? */ printf("Error Writing Render Result, see console\n"); } IMB_exr_close(exrhandle); for (unsigned int i = 0; i < this->m_layers.size(); ++i) { if (this->m_layers[i].outputBuffer) { MEM_freeN(this->m_layers[i].outputBuffer); this->m_layers[i].outputBuffer = NULL; } this->m_layers[i].imageInput = NULL; } } }
/* 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; int a, nr; const char *chan_view = NULL; int compress = (imf ? imf->exr_codec : 0); size_t width, height; const bool is_mono = view && !multiview; const bool use_half_float = (imf != NULL) ? (imf->depth == R_IMF_CHAN_DEPTH_16) : false; width = rr->rectx; height = rr->recty; if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) { /* single layer OpenEXR */ const char *RGBAZ[] = {"R", "G", "B", "A", "Z"}; for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { IMB_exr_add_view(exrhandle, rview->name); if (rview->rectf) { for (a = 0; a < 4; a++) { IMB_exr_add_channel(exrhandle, "", RGBAZ[a], rview->name, 4, 4 * width, rview->rectf + a, use_half_float); } if (rview->rectz) { /* Z pass is always stored as float. */ IMB_exr_add_channel(exrhandle, "", RGBAZ[4], rview->name, 1, width, rview->rectz, false); } } } } else { for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { if (is_mono) { if (!STREQ(view, rview->name)) { continue; } chan_view = ""; } else { /* if rendered only one view, we treat as a a non-view render */ chan_view = rview->name; } IMB_exr_add_view(exrhandle, rview->name); if (rview->rectf) { for (a = 0; a < 4; a++) { IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a), chan_view, 4, 4 * width, rview->rectf + a, use_half_float); } } } /* 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 { /* if rendered only one view, we treat as a a non-view render */ chan_view = (nr > 1 ? rpass->view :""); } for (a = 0; a < xstride; a++) { if (rpass->passtype) { IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view, xstride, xstride * width, rpass->rect + a, rpass->passtype == SCE_PASS_Z ? false : use_half_float); } else { IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view, xstride, xstride * width, rpass->rect + a, use_half_float); } } } } } BLI_make_existing_file(filename); if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) { IMB_exr_write_channels(exrhandle); success = true; } 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); return success; }
/* write input data into layers */ static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack **in) { Main *bmain= G.main; /* TODO, have this passed along */ NodeImageMultiFile *nimf= node->storage; void *exrhandle= IMB_exr_get_handle(); char filename[FILE_MAX]; bNodeSocket *sock; int i; /* Must have consistent pixel size for exr file, simply take the first valid input size. */ int rectx = -1; int recty = -1; int has_preview = 0; BKE_makepicstring(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE); BLI_make_existing_file(filename); for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) { if (in[i]->data) { NodeImageMultiFileSocket *sockdata = sock->storage; CompBuf *cbuf = in[i]->data; char channelname[EXR_TOT_MAXNAME]; /* '.' and single character channel name is appended */ char *channelname_ext; if (cbuf->rect_procedural) { printf("Error writing multilayer EXR: Procedural buffer not supported\n"); continue; } if (rectx < 0) { rectx = cbuf->x; recty = cbuf->y; } else if (cbuf->x != rectx || cbuf->y != recty) { printf("Error: Multilayer EXR output node %s expects same resolution for all input buffers. Layer %s skipped.\n", node->name, sock->name); continue; } BLI_strncpy(channelname, sockdata->layer, sizeof(channelname)-2); channelname_ext = channelname + strlen(channelname); /* create channels */ switch (cbuf->type) { case CB_VAL: strcpy(channelname_ext, ".V"); IMB_exr_add_channel(exrhandle, NULL, channelname, 1, rectx, cbuf->rect); break; case CB_VEC2: strcpy(channelname_ext, ".X"); IMB_exr_add_channel(exrhandle, NULL, channelname, 2, 2*rectx, cbuf->rect); strcpy(channelname_ext, ".Y"); IMB_exr_add_channel(exrhandle, NULL, channelname, 2, 2*rectx, cbuf->rect+1); break; case CB_VEC3: strcpy(channelname_ext, ".X"); IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect); strcpy(channelname_ext, ".Y"); IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect+1); strcpy(channelname_ext, ".Z"); IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect+2); break; case CB_RGBA: strcpy(channelname_ext, ".R"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect); strcpy(channelname_ext, ".G"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+1); strcpy(channelname_ext, ".B"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+2); strcpy(channelname_ext, ".A"); IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+3); break; } /* simply pick the first valid input for preview */ if (!has_preview) { generate_preview(rd, node, cbuf); has_preview = 1; } } } /* when the filename has no permissions, this can fail */ if (IMB_exr_begin_write(exrhandle, filename, rectx, recty, nimf->format.exr_codec)) { IMB_exr_write_channels(exrhandle); } else { /* TODO, get the error from openexr's exception */ /* XXX nice way to do report? */ printf("Error Writing Render Result, see console\n"); } IMB_exr_close(exrhandle); }