コード例 #1
0
/* called for reading temp files, and for external engines */
int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, const char *filepath)
{
	RenderLayer *rl;
	RenderPass *rpass;
	void *exrhandle = IMB_exr_get_handle();
	int rectx, recty;

	if (IMB_exr_begin_read(exrhandle, filepath, &rectx, &recty) == 0) {
		printf("failed being read %s\n", filepath);
		IMB_exr_close(exrhandle);
		return 0;
	}

	if (rr == NULL || rectx != rr->rectx || recty != rr->recty) {
		if (rr)
			printf("error in reading render result: dimensions don't match\n");
		else
			printf("error in reading render result: NULL result pointer\n");
		IMB_exr_close(exrhandle);
		return 0;
	}

	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), 
				                    xstride, xstride * rectx, rpass->rect + a);

			BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name));
		}
	}

	IMB_exr_read_channels(exrhandle);
	IMB_exr_close(exrhandle);

	return 1;
}
コード例 #2
0
void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution()
{
	unsigned int width = this->getWidth();
	unsigned int height = this->getHeight();

	if (width != 0 && height != 0) {
		void *exrhandle;
		Main *bmain = G.main; /* TODO, have this passed along */
		char filename[FILE_MAX];

		BKE_image_path_from_imtype(
		        filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR,
		        (this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);

		exrhandle = this->get_handle(filename);
		add_exr_channels(exrhandle, NULL, this->m_datatype, this->m_viewName, width, this->m_outputBuffer);

		/* memory can only be freed after we write all views to the file */
		this->m_outputBuffer = NULL;
		this->m_imageInput = NULL;

		/* ready to close the file */
		if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
			IMB_exr_write_channels(exrhandle);

			/* free buffer memory for all the views */
			free_exr_channels(exrhandle, this->m_rd, NULL, this->m_datatype);

			/* remove exr handle and data */
			IMB_exr_close(exrhandle);
		}
	}
}
コード例 #3
0
/* called for reading temp files, and for external engines */
int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, const char *filepath)
{
	RenderLayer *rl;
	RenderPass *rpass;
	void *exrhandle = IMB_exr_get_handle();
	int rectx, recty;

	if (IMB_exr_begin_read(exrhandle, filepath, &rectx, &recty) == 0) {
		printf("failed being read %s\n", filepath);
		IMB_exr_close(exrhandle);
		return 0;
	}

	if (rr == NULL || rectx != rr->rectx || recty != rr->recty) {
		if (rr)
			printf("error in reading render result: dimensions don't match\n");
		else
			printf("error in reading render result: NULL result pointer\n");
		IMB_exr_close(exrhandle);
		return 0;
	}

	for (rl = rr->layers.first; rl; rl = rl->next) {
		if (rl_single && rl_single != rl)
			continue;
		
		/* passes are allocated in sync */
		for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
			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);
			}

			set_pass_name(rpass->name, rpass->passtype, -1, rpass->view);
		}
	}

	IMB_exr_read_channels(exrhandle);
	IMB_exr_close(exrhandle);

	return 1;
}
コード例 #4
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;
}
コード例 #5
0
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);
		}
	}
}
コード例 #6
0
ファイル: movieclip.c プロジェクト: Walid-Shouman/Blender
static ImBuf *movieclip_load_sequence_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
{
	struct ImBuf *ibuf;
	char name[FILE_MAX];
	int loadflag;
	bool use_proxy = false;
	char *colorspace;

	use_proxy = (flag & MCLIP_USE_PROXY) && user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL;
	if (use_proxy) {
		int undistort = user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
		get_proxy_fname(clip, user->render_size, undistort, framenr, name);

		/* Well, this is a bit weird, but proxies for movie sources
		 * are built in the same exact color space as the input,
		 *
		 * But image sequences are built in the display space.
		 */
		if (clip->source == MCLIP_SRC_MOVIE) {
			colorspace = clip->colorspace_settings.name;
		}
		else {
			colorspace = NULL;
		}
	}
	else {
		get_sequence_fname(clip, framenr, name);
		colorspace = clip->colorspace_settings.name;
	}

	loadflag = IB_rect | IB_multilayer | IB_alphamode_detect;

	/* read ibuf */
	ibuf = IMB_loadiffname(name, loadflag, colorspace);

#ifdef WITH_OPENEXR
	if (ibuf) {
		if (ibuf->ftype == OPENEXR && ibuf->userdata) {
			IMB_exr_close(ibuf->userdata);
			ibuf->userdata = NULL;
		}
	}
#endif

	return ibuf;
}
コード例 #7
0
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;
}
コード例 #8
0
/* end write of exr tile file, read back first sample */
void render_result_exr_file_end(Render *re)
{
	RenderResult *rr;
	RenderLayer *rl;

	for (rr = re->result; rr; rr = rr->next) {
		for (rl = rr->layers.first; rl; rl = rl->next) {
			IMB_exr_close(rl->exrhandle);
			rl->exrhandle = NULL;
		}

		rr->do_exr_tile = false;
	}
	
	render_result_free_list(&re->fullresult, re->result);
	re->result = NULL;

	render_result_exr_file_read_sample(re, 0);
}
コード例 #9
0
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;
}
コード例 #10
0
ファイル: movieclip.c プロジェクト: silkentrance/blender
static ImBuf *movieclip_load_sequence_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
{
	struct ImBuf *ibuf;
	char name[FILE_MAX];
	int loadflag, use_proxy = FALSE;
	char *colorspace;

	use_proxy = (flag & MCLIP_USE_PROXY) && user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL;
	if (use_proxy) {
		int undistort = user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
		get_proxy_fname(clip, user->render_size, undistort, framenr, name);

		/* proxies were built using default color space settings */
		colorspace = NULL;
	}
	else {
		get_sequence_fname(clip, framenr, name);
		colorspace = clip->colorspace_settings.name;
	}

	loadflag = IB_rect | IB_multilayer | IB_alphamode_detect;

	/* read ibuf */
	ibuf = IMB_loadiffname(name, loadflag, colorspace);

#ifdef WITH_OPENEXR
	if (ibuf) {
		if (ibuf->ftype == OPENEXR && ibuf->userdata) {
			IMB_exr_close(ibuf->userdata);
			ibuf->userdata = NULL;
		}
	}
#endif

	return ibuf;
}
コード例 #11
0
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;
		}
	}
}
コード例 #12
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;
}
コード例 #13
0
/* 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);
}