void OutputStereoOperation::deinitExecution() { unsigned int width = this->getWidth(); unsigned int height = this->getHeight(); if (width != 0 && height != 0) { void *exrhandle; exrhandle = this->get_handle(this->m_path); float *buf = this->m_outputBuffer; /* populate single EXR channel with view data */ IMB_exr_add_channel(exrhandle, NULL, this->m_name, this->m_viewName, 1, this->m_channels * width * height, buf); this->m_imageInput = NULL; this->m_outputBuffer = NULL; /* create stereo ibuf */ if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) { ImBuf *ibuf[3] = {NULL}; const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; Main *bmain = G.main; /* TODO, have this passed along */ char filename[FILE_MAX]; int i; /* get rectf from EXR */ for (i = 0; i < 2; i++) { float *rectf = IMB_exr_channel_rect(exrhandle, NULL, this->m_name, names[i]); ibuf[i] = IMB_allocImBuf(width, height, this->m_format->planes, 0); ibuf[i]->channels = this->m_channels; ibuf[i]->rect_float = rectf; ibuf[i]->mall |= IB_rectfloat; ibuf[i]->dither = this->m_rd->dither_intensity; /* do colormanagement in the individual views, so it doesn't need to do in the stereo */ IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, this->m_viewSettings, this->m_displaySettings, this->m_format); IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]); } /* create stereo buffer */ ibuf[2] = IMB_stereo3d_ImBuf(this->m_format, ibuf[0], ibuf[1]); BKE_image_path_from_imformat( filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL); BKE_imbuf_write(ibuf[2], filename, this->m_format); /* imbuf knows which rects are not part of ibuf */ for (i = 0; i < 3; i++) IMB_freeImBuf(ibuf[i]); IMB_exr_close(exrhandle); } } }
/* 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; }
static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname) { 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); size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels; BLI_addtail(&rl->passes, rpass); rpass->passtype = passtype; rpass->channels = channels; rpass->rectx = rl->rectx; rpass->recty = rl->recty; 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, name_from_passtype(passtype, a), viewname, 0, 0, NULL, false); } else { float *rect; int x; rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, typestr); if (passtype == SCE_PASS_VECTOR) { /* initialize to max speed */ rect = rpass->rect; for (x = rectsize - 1; x >= 0; x--) rect[x] = PASS_VECTOR_MAX; } else if (passtype == SCE_PASS_Z) { rect = rpass->rect; for (x = rectsize - 1; x >= 0; x--) rect[x] = 10e10; } } return rpass; }
static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype) { const char *typestr = get_pass_name(passtype, 0); RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr); int rectsize = rr->rectx * rr->recty * channels; BLI_addtail(&rl->passes, rpass); rpass->passtype = passtype; rpass->channels = channels; rpass->rectx = rl->rectx; rpass->recty = rl->recty; BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); 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); } else { float *rect; int x; rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, typestr); if (passtype == SCE_PASS_VECTOR) { /* initialize to max speed */ rect = rpass->rect; for (x = rectsize - 1; x >= 0; x--) rect[x] = PASS_VECTOR_MAX; } else if (passtype == SCE_PASS_Z) { rect = rpass->rect; for (x = rectsize - 1; x >= 0; x--) rect[x] = 10e10; } } }
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); }
/* 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 *rr; RenderLayer *rl; SceneRenderLayer *srl; int rectx, recty, nr; rectx = BLI_rcti_size_x(partrct); recty = BLI_rcti_size_y(partrct); if (rectx <= 0 || recty <= 0) return NULL; rr = MEM_callocN(sizeof(RenderResult), "new render result"); rr->rectx = rectx; rr->recty = recty; rr->renrect.xmin = 0; rr->renrect.xmax = rectx - 2 * crop; /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */ rr->crop = crop; /* tilerect is relative coordinates within render disprect. do not subtract crop yet */ rr->tilerect.xmin = partrct->xmin - re->disprect.xmin; rr->tilerect.xmax = partrct->xmax - re->disprect.xmin; rr->tilerect.ymin = partrct->ymin - re->disprect.ymin; rr->tilerect.ymax = partrct->ymax - re->disprect.ymin; if (savebuffers) { rr->do_exr_tile = TRUE; } /* check renderdata for amount of layers */ for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) { if (layername && layername[0]) if (strcmp(srl->name, layername) != 0) continue; if ((re->r.scemode & R_SINGLE_LAYER) && nr != re->r.actlay) continue; if (srl->layflag & SCE_LAY_DISABLE) continue; rl = MEM_callocN(sizeof(RenderLayer), "new render layer"); BLI_addtail(&rr->layers, rl); BLI_strncpy(rl->name, srl->name, sizeof(rl->name)); rl->lay = srl->lay; rl->lay_zmask = srl->lay_zmask; rl->lay_exclude = srl->lay_exclude; rl->layflag = srl->layflag; rl->passflag = srl->passflag; /* for debugging: srl->passflag | SCE_PASS_RAYHITS; */ rl->pass_xor = srl->pass_xor; rl->light_override = srl->light_override; rl->mat_override = srl->mat_override; rl->rectx = rectx; rl->recty = recty; if (rr->do_exr_tile) { 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); } /* sss, previewrender and envmap don't do layers, so we make a default one */ if (rr->layers.first == NULL && !(layername && layername[0])) { rl = MEM_callocN(sizeof(RenderLayer), "new render layer"); BLI_addtail(&rr->layers, rl); rl->rectx = rectx; rl->recty = recty; /* duplicate code... */ if (rr->do_exr_tile) { 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"); } /* note, this has to be in sync with scene.c */ rl->lay = (1 << 20) - 1; rl->layflag = 0x7FFF; /* solid ztra halo strand */ rl->passflag = SCE_PASS_COMBINED; re->r.actlay = 0; } /* border render; calculate offset for use in compositor. compo is centralized coords */ /* XXX obsolete? I now use it for drawing border render offset (ton) */ rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2); rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2); return rr; }