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);
		}
	}
}
Ejemplo n.º 2
0
/* 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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
		}
	}
}
Ejemplo n.º 6
0
/* 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);
}
Ejemplo n.º 8
0
/* 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;
}