Exemple #1
0
bool imb_addrectfloatImBuf(ImBuf *ibuf)
{
	size_t size;
	
	if (ibuf == NULL) return false;
	
	if (ibuf->rect_float)
		imb_freerectfloatImBuf(ibuf);  /* frees mipmap too, hrm */
	
	size = (size_t)(ibuf->x * ibuf->y) * sizeof(float[4]);

	ibuf->channels = 4;
	if ((ibuf->rect_float = MEM_mapallocN(size, __func__))) {
		ibuf->mall |= IB_rectfloat;
		ibuf->flags |= IB_rectfloat;
		return true;
	}
	
	return false;
}
Exemple #2
0
static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame)
{
	const size_t size = vd_resol_size(vd);
	size_t i;
	char *data_c;

	if (is_vd_res_ok(vd) == false)
		return 0;

	vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
	if (vd->dataset == NULL) return 0;
	data_c = (char *)MEM_mallocN(sizeof(char) * size, "temporary voxel file reading storage");
	if (data_c == NULL) {
		MEM_freeN(vd->dataset);
		vd->dataset = NULL;
		return 0;
	}

	if (fseek(fp, (frame - 1) * size * sizeof(char), 0) == -1) {
		MEM_freeN(data_c);
		MEM_freeN(vd->dataset);
		vd->dataset = NULL;
		return 0;
	}
	if (fread(data_c, sizeof(char), size, fp) != size) {
		MEM_freeN(data_c);
		MEM_freeN(vd->dataset);
		vd->dataset = NULL;
		return 0;
	}
	
	for (i = 0; i < size; i++) {
		vd->dataset[i] = (float)data_c[i] / 255.f;
	}
	MEM_freeN(data_c);
	
	vd->cachedframe = frame;
	vd->ok = 1;
	return 1;
}
Exemple #3
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;
		}
	}
}
Exemple #4
0
static void init_frame_smoke(VoxelData *vd, int cfra)
{
#ifdef WITH_SMOKE
	Object *ob;
	ModifierData *md;
	
	vd->dataset = NULL;
	if (vd->object == NULL) return;
	ob = vd->object;
	
	/* draw code for smoke */
	if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) {
		SmokeModifierData *smd = (SmokeModifierData *)md;
		SmokeDomainSettings *sds = smd->domain;
		
		if (sds && sds->fluid) {
			BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);

			if (!sds->fluid) {
				BLI_rw_mutex_unlock(sds->fluid_mutex);
				return;
			}

			if (cfra < sds->point_cache[0]->startframe)
				;  /* don't show smoke before simulation starts, this could be made an option in the future */
			else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
				size_t totRes;
				size_t i;
				float *heat;

				if (!smoke_has_heat(sds->fluid)) {
					BLI_rw_mutex_unlock(sds->fluid_mutex);
					return;
				}

				copy_v3_v3_int(vd->resol, sds->res);
				totRes = vd_resol_size(vd);
				vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
				/* get heat data */
				heat = smoke_get_heat(sds->fluid);

				/* scale heat values from -2.0-2.0 to 0.0-1.0 */
				for (i = 0; i < totRes; i++) {
					vd->dataset[i] = (heat[i] + 2.0f) / 4.0f;
				}
			}
			else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
				size_t totRes;
				size_t i;
				float *xvel, *yvel, *zvel;

				copy_v3_v3_int(vd->resol, sds->res);
				totRes = vd_resol_size(vd);
				vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
				/* get velocity data */
				xvel = smoke_get_velocity_x(sds->fluid);
				yvel = smoke_get_velocity_y(sds->fluid);
				zvel = smoke_get_velocity_z(sds->fluid);

				/* map velocities between 0 and 0.3f */
				for (i = 0; i < totRes; i++) {
					vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f;
				}

			}
			else if (vd->smoked_type == TEX_VD_SMOKEFLAME) {
				size_t totRes;
				float *flame;

				if (sds->flags & MOD_SMOKE_HIGHRES) {
					if (!smoke_turbulence_has_fuel(sds->wt)) {
						BLI_rw_mutex_unlock(sds->fluid_mutex);
						return;
					}
					smoke_turbulence_get_res(sds->wt, vd->resol);
					flame = smoke_turbulence_get_flame(sds->wt);
				}
				else {
					if (!smoke_has_fuel(sds->fluid)) {
						BLI_rw_mutex_unlock(sds->fluid_mutex);
						return;
					}
					copy_v3_v3_int(vd->resol, sds->res);
					flame = smoke_get_flame(sds->fluid);
				}

				/* always store copy, as smoke internal data can change */
				totRes = vd_resol_size(vd);
				vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
				memcpy(vd->dataset, flame, sizeof(float)*totRes);
			}
			else {
				size_t totCells;
				int depth = 4;
				vd->data_type = TEX_VD_RGBA_PREMUL;

				/* data resolution */
				if (sds->flags & MOD_SMOKE_HIGHRES) {
					smoke_turbulence_get_res(sds->wt, vd->resol);
				}
				else {
					copy_v3_v3_int(vd->resol, sds->res);
				}

				/* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
				totCells = vd_resol_size(vd) * depth;
				/* always store copy, as smoke internal data can change */
				vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data");

				if (sds->flags & MOD_SMOKE_HIGHRES) {
					if (smoke_turbulence_has_colors(sds->wt)) {
						smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1);
					}
					else {
						smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1);
					}
				}
				else {
					if (smoke_has_colors(sds->fluid)) {
						smoke_get_rgba(sds->fluid, vd->dataset, 1);
					}
					else {
						smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1);
					}
				}
			}  /* end of fluid condition */

			BLI_rw_mutex_unlock(sds->fluid_mutex);
		}
	}
	
	vd->ok = 1;

#else // WITH_SMOKE
	(void)vd;
	(void)cfra;

	vd->dataset = NULL;
#endif
}
/* 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, const char *viewname)
{
	RenderResult *rr;
	RenderLayer *rl;
	RenderView *rv;
	SceneRenderLayer *srl;
	int rectx, recty;
	int 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;
	}

	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++) {

		if (layername && layername[0])
			if (!STREQ(srl->name, layername))
				continue;

		if (re->r.scemode & R_SINGLE_LAYER) {
			if (nr != re->r.actlay)
				continue;
		}
		else {
			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->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
			rl->exrhandle = IMB_exr_get_handle();
		}

		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,
				        re->r.debug_pass_type, 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])) {
		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->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
			rl->exrhandle = IMB_exr_get_handle();
		}

		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);

			/* a renderlayer should always have a Combined pass */
			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 */
		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;
}
/* note: this function is used for multilayer too, to ensure uniform 
   handling with BKE_image_get_ibuf() */
static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *iuser)
{
	ImBuf *ibuf;
	CompBuf *stackbuf;
	int type;

	float *rect;
	int alloc= FALSE;

	ibuf= BKE_image_get_ibuf(ima, iuser);
	if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
		return NULL;
	}

	if (ibuf->rect_float == NULL) {
		IMB_float_from_rect(ibuf);
	}

	/* now we need a float buffer from the image with matching color management */
	/* XXX weak code, multilayer is excluded from this */
	if(ibuf->channels == 4 && ima->rr==NULL) {
		if(rd->color_mgt_flag & R_COLOR_MANAGEMENT) {
			if(ibuf->profile != IB_PROFILE_NONE) {
				rect= ibuf->rect_float;
			}
			else {
				rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
				srgb_to_linearrgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
				alloc= TRUE;
			}
		}
		else {
			if(ibuf->profile == IB_PROFILE_NONE) {
				rect= ibuf->rect_float;
			}
			else {
				rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
				linearrgb_to_srgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
				alloc= TRUE;
			}
		}
	}
	else {
		/* non-rgba passes can't use color profiles */
		rect= ibuf->rect_float;
	}
	/* done coercing into the correct color management */


	type= ibuf->channels;
	
	if(rd->scemode & R_COMP_CROP) {
		stackbuf= get_cropped_compbuf(&rd->disprect, rect, ibuf->x, ibuf->y, type);
		if(alloc)
			MEM_freeN(rect);
	}
	else {
		/* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
		stackbuf= alloc_compbuf(ibuf->x, ibuf->y, type, FALSE);
		stackbuf->rect= rect;
		stackbuf->malloc= alloc;
	}
	
	/*code to respect the premul flag of images; I'm
	  not sure if this is a good idea for multilayer images,
	  since it never worked before for them.
	if (type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
		//premul the image
		int i;
		float *pixel = stackbuf->rect;
		
		for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
			pixel[0] *= pixel[3];
			pixel[1] *= pixel[3];
			pixel[2] *= pixel[3];
		}
	}
	*/
	return stackbuf;
}
Exemple #7
0
static void init_frame_smoke(VoxelData *vd, float cfra)
{
#ifdef WITH_SMOKE
	Object *ob;
	ModifierData *md;
	
	vd->dataset = NULL;
	if (vd->object == NULL)	return;	
	ob= vd->object;
	
	/* draw code for smoke */
	if( (md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke)) )
	{
		SmokeModifierData *smd = (SmokeModifierData *)md;

		
		if(smd->domain && smd->domain->fluid) {
			if(cfra < smd->domain->point_cache[0]->startframe)
				; /* don't show smoke before simulation starts, this could be made an option in the future */
			else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
				size_t totRes;
				size_t i;
				float *heat;

				VECCOPY(vd->resol, smd->domain->res);
				totRes= vd_resol_size(vd);

				// scaling heat values from -2.0-2.0 to 0.0-1.0
				vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");


				heat = smoke_get_heat(smd->domain->fluid);

				for (i=0; i<totRes; i++)
				{
					vd->dataset[i] = (heat[i]+2.0f)/4.0f;
				}

				//vd->dataset = smoke_get_heat(smd->domain->fluid);
			}
			else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
				size_t totRes;
				size_t i;
				float *xvel, *yvel, *zvel;

				VECCOPY(vd->resol, smd->domain->res);
				totRes= vd_resol_size(vd);

				// scaling heat values from -2.0-2.0 to 0.0-1.0
				vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");

				xvel = smoke_get_velocity_x(smd->domain->fluid);
				yvel = smoke_get_velocity_y(smd->domain->fluid);
				zvel = smoke_get_velocity_z(smd->domain->fluid);

				for (i=0; i<totRes; i++)
				{
					vd->dataset[i] = sqrt(xvel[i]*xvel[i] + yvel[i]*yvel[i] + zvel[i]*zvel[i])*3.0f;
				}

			}
			else {
				size_t totRes;
				float *density;

				if (smd->domain->flags & MOD_SMOKE_HIGHRES) {
					smoke_turbulence_get_res(smd->domain->wt, vd->resol);
					density = smoke_turbulence_get_density(smd->domain->wt);
				} else {
					VECCOPY(vd->resol, smd->domain->res);
					density = smoke_get_density(smd->domain->fluid);
				}

				/* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
				totRes= vd_resol_size(vd);
				/* always store copy, as smoke internal data can change */
				vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
				memcpy(vd->dataset, density, sizeof(float)*totRes);
			} // end of fluid condition
		}
	}
	
	vd->ok = 1;

#else // WITH_SMOKE
	(void)vd;
	(void)cfra;

	vd->dataset= NULL;
#endif
}
Exemple #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;
}