예제 #1
0
/* executes blocking render */
static int screen_render_exec(bContext *C, wmOperator *op)
{
	Scene *scene = CTX_data_scene(C);
	SceneRenderLayer *srl = NULL;
	Render *re;
	Image *ima;
	View3D *v3d = CTX_wm_view3d(C);
	Main *mainp = CTX_data_main(C);
	unsigned int lay_override;
	const bool is_animation = RNA_boolean_get(op->ptr, "animation");
	const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
	struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;

	/* custom scene and single layer re-render */
	screen_render_scene_layer_set(op, mainp, &scene, &srl);

	if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
		BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
		return OPERATOR_CANCELLED;
	}

	re = RE_NewRender(scene->id.name);
	lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0;

	G.is_break = false;
	RE_test_break_cb(re, NULL, render_break);

	ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
	BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
	BKE_image_backup_render(scene, ima);

	/* cleanup sequencer caches before starting user triggered render.
	 * otherwise, invalidated cache entries can make their way into
	 * the output rendering. We can't put that into RE_BlenderFrame,
	 * since sequence rendering can call that recursively... (peter) */
	BKE_sequencer_cache_cleanup();

	RE_SetReports(re, op->reports);

	BLI_begin_threaded_malloc();
	if (is_animation)
		RE_BlenderAnim(re, mainp, scene, camera_override, lay_override, scene->r.sfra, scene->r.efra, scene->r.frame_step);
	else
		RE_BlenderFrame(re, mainp, scene, srl, camera_override, lay_override, scene->r.cfra, is_write_still);
	BLI_end_threaded_malloc();

	RE_SetReports(re, NULL);

	// no redraw needed, we leave state as we entered it
	ED_update_for_newframe(mainp, scene, 1);

	WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);

	return OPERATOR_FINISHED;
}
예제 #2
0
static int bake_exec(bContext *C, wmOperator *op)
{
	Render *re;
	int result = OPERATOR_CANCELLED;
	BakeAPIRender bkr = {NULL};

	bake_init_api_data(op, C, &bkr);
	re = bkr.render;

	/* setup new render */
	RE_test_break_cb(re, NULL, bake_break);

	if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
		goto finally;
	}

	if (bkr.is_clear) {
		const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && (bkr.normal_space == R_BAKE_SPACE_TANGENT));
		bake_images_clear(bkr.main, is_tangent);
	}

	RE_SetReports(re, bkr.reports);

	if (bkr.is_selected_to_active) {
		result = bake(
		        bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports,
		        bkr.pass_type, bkr.margin, bkr.save_mode,
		        bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage,
		        bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
		        bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
		        bkr.uv_layer);
	}
	else {
		CollectionPointerLink *link;
		const bool is_clear = bkr.is_clear && BLI_listbase_is_single(&bkr.selected_objects);
		for (link = bkr.selected_objects.first; link; link = link->next) {
			Object *ob_iter = link->ptr.data;
			result = bake(
			        bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports,
			        bkr.pass_type, bkr.margin, bkr.save_mode,
			        is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage,
			        bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
			        bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
			        bkr.uv_layer);
		}
	}

	RE_SetReports(re, NULL);


finally:
	BLI_freelistN(&bkr.selected_objects);
	return result;
}
예제 #3
0
static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, float *progress)
{
	BakeAPIRender *bkr = (BakeAPIRender *)bkv;

	/* setup new render */
	bkr->do_update = do_update;
	bkr->progress = progress;

	RE_SetReports(bkr->render, bkr->reports);

	if (!bake_pass_filter_check(bkr->pass_type, bkr->pass_filter, bkr->reports)) {
		bkr->result = OPERATOR_CANCELLED;
		return;
	}

	if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
		bkr->result = OPERATOR_CANCELLED;
		return;
	}

	if (bkr->is_clear) {
		const bool is_tangent = ((bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT));
		bake_images_clear(bkr->main, is_tangent);
	}

	if (bkr->is_selected_to_active) {
		bkr->result = bake(
		        bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports,
		        bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
		        bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage,
		        bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
		        bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
		        bkr->uv_layer);
	}
	else {
		CollectionPointerLink *link;
		const bool is_clear = bkr->is_clear && BLI_listbase_is_single(&bkr->selected_objects);
		for (link = bkr->selected_objects.first; link; link = link->next) {
			Object *ob_iter = link->ptr.data;
			bkr->result = bake(
			        bkr->render, bkr->main, bkr->scene, ob_iter, NULL, bkr->reports,
			        bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
			        is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage,
			        bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
			        bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
			        bkr->uv_layer);

			if (bkr->result == OPERATOR_CANCELLED)
				return;
		}
	}

	RE_SetReports(bkr->render, NULL);
}
static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
{
	RenderJob *rj = rjv;

	rj->stop = stop;
	rj->do_update = do_update;
	rj->progress = progress;

	RE_SetReports(rj->re, rj->reports);

	if (rj->anim)
		RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->camera_override, rj->lay, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step);
	else
		RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->srl, rj->camera_override, rj->lay, rj->scene->r.cfra, rj->write_still);

	RE_SetReports(rj->re, NULL);
}
예제 #5
0
static int render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
	bContext *C = data;
	if (CTX_data_scene(C)) {
		Main *bmain= CTX_data_main(C);
		Scene *scene= CTX_data_scene(C);
		Render *re= RE_NewRender(scene->id.name);
		ReportList reports;
		BKE_reports_init(&reports, RPT_PRINT);
		RE_SetReports(re, &reports);
		RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
		RE_SetReports(re, NULL);
	} else {
		printf("\nError: no blend loaded. cannot use '-a'.\n");
	}
	return 0;
}
예제 #6
0
/* executes blocking render */
static int screen_render_exec(bContext *C, wmOperator *op)
{
	Scene *scene= CTX_data_scene(C);
	Render *re= RE_NewRender(scene->id.name);
	Image *ima;
	View3D *v3d= CTX_wm_view3d(C);
	Main *mainp= CTX_data_main(C);
	unsigned int lay= (v3d)? v3d->lay: scene->lay;
	const short is_animation= RNA_boolean_get(op->ptr, "animation");
	const short is_write_still= RNA_boolean_get(op->ptr, "write_still");
	struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;

	if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) {
		BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected.");
		return OPERATOR_CANCELLED;
	}

	G.afbreek= 0;
	RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);

	ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
	BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
	BKE_image_backup_render(scene, ima);

	/* cleanup sequencer caches before starting user triggered render.
	   otherwise, invalidated cache entries can make their way into
	   the output rendering. We can't put that into RE_BlenderFrame,
	   since sequence rendering can call that recursively... (peter) */
	seq_stripelem_cache_cleanup();

	RE_SetReports(re, op->reports);

	if(is_animation)
		RE_BlenderAnim(re, mainp, scene, camera_override, lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
	else
		RE_BlenderFrame(re, mainp, scene, NULL, camera_override, lay, scene->r.cfra, is_write_still);

	RE_SetReports(re, NULL);

	// no redraw needed, we leave state as we entered it
	ED_update_for_newframe(mainp, scene, CTX_wm_screen(C), 1);

	WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);

	return OPERATOR_FINISHED;
}
예제 #7
0
static int render_frame(int argc, const char **argv, void *data)
{
	bContext *C = data;
	Scene *scene = CTX_data_scene(C);
	if (scene) {
		Main *bmain = CTX_data_main(C);

		if (argc > 1) {
			Render *re = RE_NewRender(scene->id.name);
			int frame;
			ReportList reports;

			switch (*argv[1]) {
				case '+':
					frame = scene->r.sfra + atoi(argv[1] + 1);
					break;
				case '-':
					frame = (scene->r.efra - atoi(argv[1] + 1)) + 1;
					break;
				default:
					frame = atoi(argv[1]);
					break;
			}

			BLI_begin_threaded_malloc();
			BKE_reports_init(&reports, RPT_PRINT);

			frame = CLAMPIS(frame, MINAFRAME, MAXFRAME);

			RE_SetReports(re, &reports);
			RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step);
			RE_SetReports(re, NULL);
			BLI_end_threaded_malloc();
			return 1;
		}
		else {
			printf("\nError: frame number must follow '-f / --render-frame'.\n");
			return 0;
		}
	}
	else {
		printf("\nError: no blend loaded. cannot use '-f / --render-frame'.\n");
		return 0;
	}
}
예제 #8
0
/* executes blocking blensor */
static int screen_blensor_exec(bContext *C, wmOperator *op)
{
	Scene *scene= CTX_data_scene(C);
	static Render *re=NULL;
	Image *ima;
	View3D *v3d= CTX_wm_view3d(C);
	Main *mainp= CTX_data_main(C);
	unsigned int lay= (v3d)? v3d->lay: scene->lay;
  float *rays;
  float *returns;
  char ray_ptr_str[17];
  char return_ptr_str[17];

    /* add modal handler for ESC */

	const int raycount= RNA_int_get(op->ptr, "raycount");
	const int elements_per_ray= RNA_int_get(op->ptr, "elements_per_ray");
	const int keep_render_setup = RNA_boolean_get(op->ptr, "keep_render_setup");
	const int shading = RNA_boolean_get(op->ptr, "shading");

	const float maximum_distance =RNA_float_get(op->ptr, "maximum_distance");
	struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;

  RNA_string_get(op->ptr, "vector_strptr", ray_ptr_str);
  RNA_string_get(op->ptr, "return_vector_strptr", return_ptr_str);
  rays = (float *)convert_str_to_ptr(ray_ptr_str);
  returns = (float *)convert_str_to_ptr(return_ptr_str);
      
  if (raycount > 0)
  {
        
      printf ("Raycount: %d\n",raycount);
      
	    if(re==NULL) {
		    re = RE_NewRender(scene->id.name);
	    }
	
  
      G.is_break = FALSE;
	    //RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);

	    ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
	    BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
	    BKE_image_backup_render(scene, ima);

      /* cleanup sequencer caches before starting user triggered render.
       * otherwise, invalidated cache entries can make their way into
       * the output rendering. We can't put that into RE_BlenderFrame,
       * since sequence rendering can call that recursively... (peter) */
      BKE_sequencer_cache_cleanup();

      RE_SetReports(re, op->reports);

	    RE_BlensorFrame(re, mainp, scene, NULL, camera_override, lay, scene->r.cfra, 0, rays, raycount, elements_per_ray, returns, maximum_distance, keep_render_setup, shading);

    	RE_SetReports(re, NULL);

	    // no redraw needed, we leave state as we entered it
	    ED_update_for_newframe(mainp, scene, 1);

	    WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
      if (keep_render_setup == 0)
      {
        re = NULL;
      }

  }
	return OPERATOR_FINISHED;
}
예제 #9
0
static int bake(
        Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
        const ScenePassType pass_type, const int margin,
        const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials,
        const bool is_automatic_name, const bool use_selected_to_active,
        const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[],
        const char *custom_cage, const char *filepath, const int width, const int height,
        const char *identifier)
{
	int op_result = OPERATOR_CANCELLED;
	bool ok = false;

	Object *ob_cage = NULL;

	BakeHighPolyData *highpoly;
	int tot_highpoly;

	char restrict_flag_low = ob_low->restrictflag;
	char restrict_flag_cage;

	Mesh *me_low = NULL;
	Render *re;

	float *result = NULL;

	BakePixel *pixel_array_low = NULL;

	const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL);
	const bool is_noncolor = is_noncolor_pass(pass_type);
	const int depth = RE_pass_depth(pass_type);

	bool is_highpoly = false;
	bool is_tangent;

	BakeImages bake_images = {NULL};

	int num_pixels;
	int tot_materials;
	int i;

	re = RE_NewRender(scene->id.name);

	is_tangent = pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT;
	tot_materials = ob_low->totcol;

	if (tot_materials == 0) {
		if (is_save_internal) {
			BKE_report(reports, RPT_ERROR,
			           "No active image found. Add a material or bake to an external file");

			goto cleanup;
		}
		else if (is_split_materials) {
			BKE_report(reports, RPT_ERROR,
			           "No active image found. Add a material or bake without the Split Materials option");

			goto cleanup;
		}
		else {
			/* baking externally without splitting materials */
			tot_materials = 1;
		}
	}

	/* we overallocate in case there is more materials than images */
	bake_images.data = MEM_callocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)");
	bake_images.lookup = MEM_callocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)");

	if (!build_image_lookup(bmain, ob_low, &bake_images, reports))
		goto cleanup;

	if (is_save_internal) {
		num_pixels = initialize_internal_images(&bake_images, reports);

		if (num_pixels == 0) {
			goto cleanup;
		}

		if (is_clear) {
			RE_bake_ibuf_clear(&bake_images, is_tangent);
		}
	}
	else {
		/* when saving extenally always use the size specified in the UI */

		num_pixels = width * height * bake_images.size;

		for (i = 0; i < bake_images.size; i++) {
			bake_images.data[i].width = width;
			bake_images.data[i].height = height;
			bake_images.data[i].offset = (is_split_materials ? num_pixels : 0);
			bake_images.data[i].image = NULL;
		}

		if (!is_split_materials) {
			/* saving a single image */
			for (i = 0; i < tot_materials; i++)
				bake_images.lookup[i] = 0;
		}
	}

	if (use_selected_to_active) {
		CollectionPointerLink *link;
		tot_highpoly = 0;

		for (link = selected_objects->first; link; link = link->next) {
			Object *ob_iter = link->ptr.data;

			if (ob_iter == ob_low)
				continue;

			tot_highpoly ++;
		}

		if (tot_highpoly == 0) {
			BKE_report(reports, RPT_ERROR, "No valid selected objects");
			op_result = OPERATOR_CANCELLED;

			goto cleanup;
		}
		else {
			is_highpoly = true;
		}
	}

	if (custom_cage[0] != '\0') {
		ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2);

		/* TODO check if cage object has the same topology (num of triangles and a valid UV) */
		if (ob_cage == NULL || ob_cage->type != OB_MESH) {
			BKE_report(reports, RPT_ERROR, "No valid cage object");
			op_result = OPERATOR_CANCELLED;

			goto cleanup;
		}
		else {
			restrict_flag_cage = ob_cage->restrictflag;
		}
	}

	RE_bake_engine_set_engine_parameters(re, bmain, scene);

	/* blender_test_break uses this global */
	G.is_break = false;

	RE_test_break_cb(re, NULL, bake_break);

	pixel_array_low = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
	result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");

	if (is_highpoly) {
		CollectionPointerLink *link;
		ModifierData *md, *nmd;
		ListBase modifiers_tmp, modifiers_original;
		float mat_low[4][4];
		int i = 0;
		highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects");

		/* prepare cage mesh */
		if (ob_cage) {
			me_low = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0);
			copy_m4_m4(mat_low, ob_cage->obmat);
		}
		else {
			modifiers_original = ob_low->modifiers;
			BLI_listbase_clear(&modifiers_tmp);

			for (md = ob_low->modifiers.first; md; md = md->next) {
				/* Edge Split cannot be applied in the cage,
				 * the cage is supposed to have interpolated normals
				 * between the faces unless the geometry is physically
				 * split. So we create a copy of the low poly mesh without
				 * the eventual edge split.*/

				if (md->type == eModifierType_EdgeSplit)
					continue;

				nmd = modifier_new(md->type);
				BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
				modifier_copyData(md, nmd);
				BLI_addtail(&modifiers_tmp, nmd);
			}

			/* temporarily replace the modifiers */
			ob_low->modifiers = modifiers_tmp;

			/* get the cage mesh as it arrives in the renderer */
			me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
			copy_m4_m4(mat_low, ob_low->obmat);
		}

		/* populate highpoly array */
		for (link = selected_objects->first; link; link = link->next) {
			TriangulateModifierData *tmd;
			Object *ob_iter = link->ptr.data;

			if (ob_iter == ob_low)
				continue;

			/* initialize highpoly_data */
			highpoly[i].ob = ob_iter;
			highpoly[i].me = NULL;
			highpoly[i].tri_mod = NULL;
			highpoly[i].restrict_flag = ob_iter->restrictflag;
			highpoly[i].pixel_array = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");


			/* triangulating so BVH returns the primitive_id that will be used for rendering */
			highpoly[i].tri_mod = ED_object_modifier_add(
			        reports, bmain, scene, highpoly[i].ob,
			        "TmpTriangulate", eModifierType_Triangulate);
			tmd = (TriangulateModifierData *)highpoly[i].tri_mod;
			tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
			tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;

			highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 1, 0);
			highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;

			/* lowpoly to highpoly transformation matrix */
			invert_m4_m4(highpoly[i].mat_lowtohigh, highpoly[i].ob->obmat);
			mul_m4_m4m4(highpoly[i].mat_lowtohigh, highpoly[i].mat_lowtohigh, mat_low);

			i++;
		}

		BLI_assert(i == tot_highpoly);

		/* populate the pixel array with the face data */
		RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images);

		ob_low->restrictflag |= OB_RESTRICT_RENDER;

		/* populate the pixel arrays with the corresponding face data for each high poly object */
		RE_bake_pixels_populate_from_objects(
		        me_low, pixel_array_low, highpoly, tot_highpoly,
		        num_pixels, cage_extrusion);

		/* the baking itself */
		for (i = 0; i < tot_highpoly; i++) {
			if (RE_bake_has_engine(re)) {
				ok = RE_bake_engine(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels,
				                    depth, pass_type, result);
			}
			else {
				ok = RE_bake_internal(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels,
				                      depth, pass_type, result);
			}

			if (!ok)
				break;
		}

		/* reverting data back */
		if (ob_cage) {
			ob_cage->restrictflag |= OB_RESTRICT_RENDER;
		}
		else {
			ob_low->modifiers = modifiers_original;

			while ((md = BLI_pophead(&modifiers_tmp))) {
				modifier_free(md);
			}
		}
	}
	else {
		/* get the mesh as it arrives in the renderer */
		me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);

		/* populate the pixel array with the face data */
		RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images);

		/* make sure low poly renders */
		ob_low->restrictflag &= ~OB_RESTRICT_RENDER;

		if (RE_bake_has_engine(re))
			ok = RE_bake_engine(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result);
		else
			ok = RE_bake_internal(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result);
	}

	/* normal space conversion
	 * the normals are expected to be in world space, +X +Y +Z */
	if (pass_type == SCE_PASS_NORMAL) {
		switch (normal_space) {
			case R_BAKE_SPACE_WORLD:
			{
				/* Cycles internal format */
				if ((normal_swizzle[0] == R_BAKE_POSX) &&
				    (normal_swizzle[1] == R_BAKE_POSY) &&
				    (normal_swizzle[2] == R_BAKE_POSZ))
				{
					break;
				}
				else {
					RE_bake_normal_world_to_world(pixel_array_low, num_pixels,  depth, result, normal_swizzle);
				}
				break;
			}
			case R_BAKE_SPACE_OBJECT:
			{
				RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle);
				break;
			}
			case R_BAKE_SPACE_TANGENT:
			{
				if (is_highpoly) {
					RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle);
				}
				else {
					/* from multiresolution */
					Mesh *me_nores = NULL;
					ModifierData *md = NULL;
					int mode;

					md = modifiers_findByType(ob_low, eModifierType_Multires);

					if (md) {
						mode = md->mode;
						md->mode &= ~eModifierMode_Render;
					}

					me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
					RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images);

					RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle);
					BKE_libblock_free(bmain, me_nores);

					if (md)
						md->mode = mode;
				}
				break;
			}
			default:
				break;
		}
	}

	if (!ok) {
		BKE_report(reports, RPT_ERROR, "Problem baking object map");
		op_result = OPERATOR_CANCELLED;
	}
	else {
		/* save the results */
		for (i = 0; i < bake_images.size; i++) {
			BakeImage *bk_image = &bake_images.data[i];

			if (is_save_internal) {
				ok = write_internal_bake_pixels(
				         bk_image->image,
				         pixel_array_low + bk_image->offset,
				         result + bk_image->offset * depth,
				         bk_image->width, bk_image->height,
				         margin, is_clear, is_noncolor);

				if (!ok) {
					BKE_report(reports, RPT_ERROR,
					           "Problem saving the bake map internally, "
					           "make sure there is a Texture Image node in the current object material");
					op_result = OPERATOR_CANCELLED;
				}
				else {
					BKE_report(reports, RPT_INFO,
					           "Baking map saved to internal image, save it externally or pack it");
					op_result = OPERATOR_FINISHED;
				}
			}
			/* save externally */
			else {
				BakeData *bake = &scene->r.bake;
				char name[FILE_MAX];

				BKE_makepicstring_from_type(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false);

				if (is_automatic_name) {
					BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
					BLI_path_suffix(name, FILE_MAX, identifier, "_");
				}

				if (is_split_materials) {
					if (bk_image->image) {
						BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_");
					}
					else {
						if (ob_low->mat[i]) {
							BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_");
						}
						else if (me_low->mat[i]) {
							BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_");
						}
						else {
							/* if everything else fails, use the material index */
							char tmp[4];
							sprintf(tmp, "%d", i % 1000);
							BLI_path_suffix(name, FILE_MAX, tmp, "_");
						}
					}
				}

				/* save it externally */
				ok = write_external_bake_pixels(
				        name,
				        pixel_array_low + bk_image->offset,
				        result + bk_image->offset * depth,
				        bk_image->width, bk_image->height,
				        margin, &bake->im_format, is_noncolor);

				if (!ok) {
					BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\".", name);
					op_result = OPERATOR_CANCELLED;
				}
				else {
					BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\".", name);
					op_result = OPERATOR_FINISHED;
				}

				if (!is_split_materials) {
					break;
				}
			}
		}
	}


cleanup:

	if (is_highpoly) {
		int i;
		for (i = 0; i < tot_highpoly; i++) {
			highpoly[i].ob->restrictflag = highpoly[i].restrict_flag;

			if (highpoly[i].pixel_array)
				MEM_freeN(highpoly[i].pixel_array);

			if (highpoly[i].tri_mod)
				ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod);

			if (highpoly[i].me)
				BKE_libblock_free(bmain, highpoly[i].me);
		}
		MEM_freeN(highpoly);
	}

	ob_low->restrictflag = restrict_flag_low;

	if (ob_cage)
		ob_cage->restrictflag = restrict_flag_cage;

	if (pixel_array_low)
		MEM_freeN(pixel_array_low);

	if (bake_images.data)
		MEM_freeN(bake_images.data);

	if (bake_images.lookup)
		MEM_freeN(bake_images.lookup);

	if (result)
		MEM_freeN(result);

	if (me_low)
		BKE_libblock_free(bmain, me_low);

	RE_SetReports(re, NULL);

	return op_result;
}