[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [53737] trunk/blender: Packed and generated images support for Cycles

Sergey Sharybin sergey.vfx at gmail.com
Sat Jan 12 11:59:18 CET 2013


Revision: 53737
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53737
Author:   nazgul
Date:     2013-01-12 10:59:13 +0000 (Sat, 12 Jan 2013)
Log Message:
-----------
Packed and generated images support for Cycles

This commit adds support of packed and generated images
for Cycles when using SVM backend. Movies are still not
supported. This changes also doesn't touch OSL which is
much less trivial to adopt for any images which are not
saved to disk.

Implementation details:

- When adding images to Image Manager is now possible
  to mark image as builtin. Builtin images will bypass
  OIIO loader and will use special loading callbacks.

- Callbacks are set by Blender Session and they're
  using C++ RNA interface to obtain needed data (pixels,
  dimensions, is_float flag).

- Image Manager assumes file path is used as reference
  to a builtin images, but in fact currently image
  datablock name is used for reference. This makes it
  easy to find an image in BlendData database.

- Added some extra properties to Image RNA:
  * channels, which denotes actual number of channels
    in ImBuf. This is needed to treat image's pixels
    correct (before it wasn't possible because API
    used internal number of channels for pixels which
    is in fact doesn't correlate with image depth)
  * is_float, which is truth if image is stored in
    float buffer of ImBuf.

- Implemented string lookup for C++ RNA collections
  for cases there's no manual lookup function.

OSL is not supported because it used own image loading
and filtering routines and there's seems to be no API
to feed pre-loaded pixels directly to the library.

Think we'll either need to add some API to support
such kind of feeding or consider OSL does not have
support of packed images at all.

Movies are not supported at this moment because of lack
of RNA API to load specified frame. It's not difficult
to solve, just need to consider what to best here:
* Either write some general python interface for ImBuf
  and use it via C++ API, or
* Write a PY API function which will return pixels for
  given frame, or
* Use bad-level BKE_* call

Anyway, small steps, further improvements later.

Reviewed by Brecht, thanks!

Modified Paths:
--------------
    trunk/blender/intern/cycles/blender/blender_session.cpp
    trunk/blender/intern/cycles/blender/blender_session.h
    trunk/blender/intern/cycles/blender/blender_shader.cpp
    trunk/blender/intern/cycles/render/image.cpp
    trunk/blender/intern/cycles/render/image.h
    trunk/blender/intern/cycles/render/nodes.cpp
    trunk/blender/intern/cycles/render/nodes.h
    trunk/blender/source/blender/makesrna/intern/makesrna.c
    trunk/blender/source/blender/makesrna/intern/rna_image.c

Modified: trunk/blender/intern/cycles/blender/blender_session.cpp
===================================================================
--- trunk/blender/intern/cycles/blender/blender_session.cpp	2013-01-12 10:48:10 UTC (rev 53736)
+++ trunk/blender/intern/cycles/blender/blender_session.cpp	2013-01-12 10:59:13 UTC (rev 53737)
@@ -109,6 +109,11 @@
 	session->reset(buffer_params, session_params.samples);
 
 	b_engine.use_highlight_tiles(session_params.progressive_refine == false);
+
+	/* setup callbacks for builtin image support */
+	scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5);
+	scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2);
+	scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2);
 }
 
 void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
@@ -607,5 +612,69 @@
 			session->progress.set_cancel("Cancelled");
 }
 
+void BlenderSession::builtin_image_info(const string &name, bool &is_float, int &width, int &height, int &channels)
+{
+	BL::Image b_image = b_data.images[name];
+
+	if(b_image) {
+		is_float = b_image.is_float();
+		width = b_image.size()[0];
+		height = b_image.size()[1];
+		channels = b_image.channels();
+	}
+	else {
+		is_float = false;
+		width = 0;
+		height = 0;
+		channels = 0;
+	}
+}
+
+bool BlenderSession::builtin_image_pixels(const string &name, unsigned char *pixels)
+{
+	BL::Image b_image = b_data.images[name];
+
+	if(b_image) {
+		int width = b_image.size()[0];
+		int height = b_image.size()[1];
+		int channels = b_image.channels();
+
+		BL::DynamicArray<float> pixels_array = b_image.pixels();
+		float *float_pixels = pixels_array.data;
+
+		/* a bit of shame, but Py API currently only returns float array,
+		 * which need to be converted back to char buffer
+		 */
+		unsigned char *cp = pixels;
+		float *fp = float_pixels;
+		for(int i = 0; i < channels * width * height; i++, cp++, fp++) {
+			*cp = *fp * 255;
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
+bool BlenderSession::builtin_image_float_pixels(const string &name, float *pixels)
+{
+	BL::Image b_image = b_data.images[name];
+
+	if(b_image) {
+		int width = b_image.size()[0];
+		int height = b_image.size()[1];
+		int channels = b_image.channels();
+
+		BL::DynamicArray<float> pixels_array = b_image.pixels();
+
+		memcpy(pixels, pixels_array.data, width * height * channels * sizeof(float));
+
+		return true;
+	}
+
+	return false;
+}
+
 CCL_NAMESPACE_END
 

Modified: trunk/blender/intern/cycles/blender/blender_session.h
===================================================================
--- trunk/blender/intern/cycles/blender/blender_session.h	2013-01-12 10:48:10 UTC (rev 53736)
+++ trunk/blender/intern/cycles/blender/blender_session.h	2013-01-12 10:59:13 UTC (rev 53737)
@@ -93,6 +93,10 @@
 protected:
 	void do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only);
 	void do_write_update_render_tile(RenderTile& rtile, bool do_update_only);
+
+	void builtin_image_info(const string &name, bool &is_float, int &width, int &height, int &channels);
+	bool builtin_image_pixels(const string &name, unsigned char *pixels);
+	bool builtin_image_float_pixels(const string &name, float *pixels);
 };
 
 CCL_NAMESPACE_END

Modified: trunk/blender/intern/cycles/blender/blender_shader.cpp
===================================================================
--- trunk/blender/intern/cycles/blender/blender_shader.cpp	2013-01-12 10:48:10 UTC (rev 53736)
+++ trunk/blender/intern/cycles/blender/blender_shader.cpp	2013-01-12 10:59:13 UTC (rev 53737)
@@ -511,9 +511,24 @@
 			BL::ShaderNodeTexImage b_image_node(b_node);
 			BL::Image b_image(b_image_node.image());
 			ImageTextureNode *image = new ImageTextureNode();
-			/* todo: handle generated/builtin images */
+			/* todo: handle movie images */
 			if(b_image && b_image.source() != BL::Image::source_MOVIE) {
-				image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
+				/* builtin images will use callback-based reading because
+				 * they could only be loaded correct from blender side
+				 */
+				bool is_builtin = b_image.packed_file() ||
+				                  b_image.source() == BL::Image::source_GENERATED;
+
+				if(is_builtin) {
+					/* for builtin images we're using image datablock name to find an image to read pixels from later */
+					image->filename = b_image.name();
+					image->is_builtin = true;
+				}
+				else {
+					image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
+					image->is_builtin = false;
+				}
+
 				image->animated = b_image_node.image_user().use_auto_refresh();
 			}
 			image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
@@ -528,8 +543,17 @@
 			BL::Image b_image(b_env_node.image());
 			EnvironmentTextureNode *env = new EnvironmentTextureNode();
 			if(b_image && b_image.source() != BL::Image::source_MOVIE) {
-				env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
-				env->animated = b_env_node.image_user().use_auto_refresh();
+				bool is_builtin = b_image.packed_file() ||
+				                  b_image.source() == BL::Image::source_GENERATED;
+
+				if(is_builtin) {
+					env->filename = b_image.name();
+					env->is_builtin = true;
+				}
+				else {
+					env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
+					env->animated = b_env_node.image_user().use_auto_refresh();
+				}
 			}
 			env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
 			env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];

Modified: trunk/blender/intern/cycles/render/image.cpp
===================================================================
--- trunk/blender/intern/cycles/render/image.cpp	2013-01-12 10:48:10 UTC (rev 53736)
+++ trunk/blender/intern/cycles/render/image.cpp	2013-01-12 10:59:13 UTC (rev 53737)
@@ -85,11 +85,21 @@
 	return false;
 }
 
-bool ImageManager::is_float_image(const string& filename)
+bool ImageManager::is_float_image(const string& filename, bool is_builtin)
 {
-	ImageInput *in = ImageInput::create(filename);
 	bool is_float = false;
 
+	if(is_builtin) {
+		if(builtin_image_info_cb) {
+			int width, height, channels;
+			builtin_image_info_cb(filename, is_float, width, height, channels);
+		}
+
+		return is_float;
+	}
+
+	ImageInput *in = ImageInput::create(filename);
+
 	if(in) {
 		ImageSpec spec;
 
@@ -113,13 +123,13 @@
 	return is_float;
 }
 
-int ImageManager::add_image(const string& filename, bool animated, bool& is_float)
+int ImageManager::add_image(const string& filename, bool is_builtin, bool animated, bool& is_float)
 {
 	Image *img;
 	size_t slot;
 
 	/* load image info and find out if we need a float texture */
-	is_float = (pack_images)? false: is_float_image(filename);
+	is_float = (pack_images)? false: is_float_image(filename, is_builtin);
 
 	if(is_float) {
 		/* find existing image */
@@ -150,6 +160,7 @@
 		/* add new image */
 		img = new Image();
 		img->filename = filename;
+		img->is_builtin = is_builtin;
 		img->need_load = true;
 		img->animated = animated;
 		img->users = 1;
@@ -184,6 +195,7 @@
 		/* add new image */
 		img = new Image();
 		img->filename = filename;
+		img->is_builtin = is_builtin;
 		img->need_load = true;
 		img->animated = animated;
 		img->users = 1;
@@ -197,12 +209,12 @@
 	return slot;
 }
 
-void ImageManager::remove_image(const string& filename)
+void ImageManager::remove_image(const string& filename, bool is_builtin)
 {
 	size_t slot;
 
 	for(slot = 0; slot < images.size(); slot++) {
-		if(images[slot] && images[slot]->filename == filename) {
+		if(images[slot] && images[slot]->filename == filename && images[slot]->is_builtin == is_builtin) {
 			/* decrement user count */
 			images[slot]->users--;
 			assert(images[slot]->users >= 0);
@@ -220,7 +232,7 @@
 	if(slot == images.size()) {
 		/* see if it's in a float texture slot */
 		for(slot = 0; slot < float_images.size(); slot++) {
-			if(float_images[slot] && float_images[slot]->filename == filename) {
+			if(float_images[slot] && float_images[slot]->filename == filename && float_images[slot]->is_builtin == is_builtin) {
 				/* decrement user count */
 				float_images[slot]->users--;
 				assert(float_images[slot]->users >= 0);
@@ -242,27 +254,43 @@
 	if(img->filename == "")
 		return false;
 
-	/* load image from file through OIIO */
-	ImageInput *in = ImageInput::create(img->filename);
+	ImageInput *in = NULL;
+	int width, height, components;
 
-	if(!in)
-		return false;
+	if(!img->is_builtin) {
+		/* load image from file through OIIO */
+		in = ImageInput::create(img->filename);
 
-	ImageSpec spec;
+		if(!in)
+			return false;
 
-	if(!in->open(img->filename, spec)) {
-		delete in;
-		return false;
+		ImageSpec spec;
+
+		if(!in->open(img->filename, spec)) {
+			delete in;
+			return false;
+		}
+
+		width = spec.width;
+		height = spec.height;
+		components = spec.nchannels;
 	}
+	else {
+		/* load image using builtin images callbacks */
+		if(!builtin_image_info_cb || !builtin_image_pixels_cb)
+			return false;
 
+		bool is_float;
+		builtin_image_info_cb(img->filename, is_float, width, height, components);
+	}
+
 	/* we only handle certain number of components */
-	int width = spec.width;
-	int height = spec.height;
-	int components = spec.nchannels;
+	if(!(components == 1 || components == 3 || components == 4)) {
+		if(in) {
+			in->close();
+			delete in;
+		}
 
-	if(!(components == 1 || components == 3 || components == 4)) {
-		in->close();
-		delete in;
 		return false;
 	}
 
@@ -270,14 +298,19 @@
 	uchar *pixels = (uchar*)tex_img.resize(width, height);
 	int scanlinesize = width*components*sizeof(uchar);
 
-	in->read_image(TypeDesc::UINT8,
-		(uchar*)pixels + (height-1)*scanlinesize,
-		AutoStride,
-		-scanlinesize,
-		AutoStride);
+	if(in) {
+		in->read_image(TypeDesc::UINT8,
+			(uchar*)pixels + (height-1)*scanlinesize,
+			AutoStride,
+			-scanlinesize,
+			AutoStride);
 
-	in->close();
-	delete in;
+		in->close();
+		delete in;
+	}
+	else {
+		builtin_image_pixels_cb(img->filename, pixels);
+	}
 
 	if(components == 3) {
 		for(int i = width*height-1; i >= 0; i--) {
@@ -304,27 +337,42 @@

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list