diff options
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 69 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.h | 4 | ||||
-rw-r--r-- | intern/cycles/blender/blender_shader.cpp | 32 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 151 | ||||
-rw-r--r-- | intern/cycles/render/image.h | 10 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 14 | ||||
-rw-r--r-- | intern/cycles/render/nodes.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/makesrna.c | 23 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_image.c | 46 |
9 files changed, 287 insertions, 64 deletions
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index d0c7c06cbb3..60dfe37c9f8 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -109,6 +109,11 @@ void BlenderSession::create_session() 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 @@ void BlenderSession::test_cancel() 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 diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 7f3973ae873..dfa487bd244 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -93,6 +93,10 @@ public: 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 diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index ddbd7f935e4..3bb02bbfe74 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -511,9 +511,24 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen 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 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen 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()]; diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 230a12f9ff2..e6f8ab4a5d9 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -85,11 +85,21 @@ bool ImageManager::set_animation_frame_update(int frame) 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 @@ bool ImageManager::is_float_image(const string& filename) 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 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa /* 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 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa /* 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 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa 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 @@ void ImageManager::remove_image(const string& filename) 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 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) 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)) { - in->close(); - delete in; + if(in) { + in->close(); + delete in; + } + return false; } @@ -270,14 +298,19 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img) 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 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_ 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; + } + + /* we only handle certain number of components */ + width = spec.width; + height = spec.height; + components = spec.nchannels; } + else { + /* load image using builtin images callbacks */ + if(!builtin_image_info_cb || !builtin_image_float_pixels_cb) + return false; - /* we only handle certain number of components */ - int width = spec.width; - int height = spec.height; - int components = spec.nchannels; + bool is_float; + builtin_image_info_cb(img->filename, is_float, width, height, components); + } if(!(components == 1 || components == 3 || components == 4)) { - in->close(); - delete in; + if(in) { + in->close(); + delete in; + } return false; } @@ -332,14 +380,19 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_ float *pixels = (float*)tex_img.resize(width, height); int scanlinesize = width*components*sizeof(float); - in->read_image(TypeDesc::FLOAT, - (uchar*)pixels + (height-1)*scanlinesize, - AutoStride, - -scanlinesize, - AutoStride); + if(in) { + in->read_image(TypeDesc::FLOAT, + (uchar*)pixels + (height-1)*scanlinesize, + AutoStride, + -scanlinesize, + AutoStride); - in->close(); - delete in; + in->close(); + delete in; + } + else { + builtin_image_float_pixels_cb(img->filename, pixels); + } if(components == 3) { for(int i = width*height-1; i >= 0; i--) { diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 4d177174971..e39ac14b60f 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -51,9 +51,9 @@ public: ImageManager(); ~ImageManager(); - int add_image(const string& filename, bool animated, bool& is_float); - void remove_image(const string& filename); - bool is_float_image(const string& filename); + int add_image(const string& filename, bool is_builtin, bool animated, bool& is_float); + void remove_image(const string& filename, bool is_builtin); + bool is_float_image(const string& filename, bool is_builtin); void device_update(Device *device, DeviceScene *dscene, Progress& progress); void device_free(Device *device, DeviceScene *dscene); @@ -65,6 +65,9 @@ public: bool need_update; + boost::function<void(const string &filename, bool &is_float, int &width, int &height, int &channels)> builtin_image_info_cb; + boost::function<bool(const string &filename, unsigned char *pixels)> builtin_image_pixels_cb; + boost::function<bool(const string &filename, float *pixels)> builtin_image_float_pixels_cb; private: int tex_num_images; int tex_num_float_images; @@ -74,6 +77,7 @@ private: struct Image { string filename; + bool is_builtin; bool need_load; bool animated; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 14ef3c68ad3..d1297c9dc94 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -142,6 +142,7 @@ ImageTextureNode::ImageTextureNode() slot = -1; is_float = -1; filename = ""; + is_builtin = false; color_space = ustring("Color"); projection = ustring("Flat");; projection_blend = 0.0f; @@ -155,7 +156,7 @@ ImageTextureNode::ImageTextureNode() ImageTextureNode::~ImageTextureNode() { if(image_manager) - image_manager->remove_image(filename); + image_manager->remove_image(filename, is_builtin); } ShaderNode *ImageTextureNode::clone() const @@ -176,7 +177,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(is_float == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, animated, is_float_bool); + slot = image_manager->add_image(filename, is_builtin, animated, is_float_bool); is_float = (int)is_float_bool; } @@ -237,7 +238,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) tex_mapping.compile(compiler); if(is_float == -1) - is_float = (int)image_manager->is_float_image(filename); + is_float = (int)image_manager->is_float_image(filename, false); compiler.parameter("filename", filename.c_str()); if(is_float || color_space != "Color") @@ -271,6 +272,7 @@ EnvironmentTextureNode::EnvironmentTextureNode() slot = -1; is_float = -1; filename = ""; + is_builtin = false; color_space = ustring("Color"); projection = ustring("Equirectangular"); animated = false; @@ -283,7 +285,7 @@ EnvironmentTextureNode::EnvironmentTextureNode() EnvironmentTextureNode::~EnvironmentTextureNode() { if(image_manager) - image_manager->remove_image(filename); + image_manager->remove_image(filename, is_builtin); } ShaderNode *EnvironmentTextureNode::clone() const @@ -304,7 +306,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(slot == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, animated, is_float_bool); + slot = image_manager->add_image(filename, is_builtin, animated, is_float_bool); is_float = (int)is_float_bool; } @@ -354,7 +356,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) tex_mapping.compile(compiler); if(is_float == -1) - is_float = (int)image_manager->is_float_image(filename); + is_float = (int)image_manager->is_float_image(filename, false); compiler.parameter("filename", filename.c_str()); compiler.parameter("projection", projection); diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 564ceee5a5b..8b2d6a0e5c8 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -70,6 +70,7 @@ public: int slot; int is_float; string filename; + bool is_builtin; ustring color_space; ustring projection; float projection_blend; @@ -89,6 +90,7 @@ public: int slot; int is_float; string filename; + bool is_builtin; ustring color_space; ustring projection; bool animated; diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 1ba50657751..2eacdfd4880 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3544,8 +3544,27 @@ static const char *cpp_classes = "" "#define COLLECTION_PROPERTY_LOOKUP_STRING_FALSE(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_string_wrap(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) \\\n" " { \\\n" -" memset(r_ptr, 0, sizeof(*r_ptr)); \\\n" -" return 0; \\\n" +" CollectionPropertyIterator iter; \\\n" +" int found = 0; \\\n" +" PropertyRNA *item_name_prop = RNA_struct_name_property(ptr->type); \\\n" +" sname##_##identifier##_begin(&iter, ptr); \\\n" +" while (iter.valid && !found) { \\\n" +" char name_fixed[32]; \\\n" +" const char *name; \\\n" +" int name_length; \\\n" +" name = RNA_property_string_get_alloc(&iter.ptr, item_name_prop, name_fixed, sizeof(name_fixed), &name_length); \\\n" +" if (!strncmp(name, key, name_length)) { \\\n" +" *r_ptr = iter.ptr; \\\n" +" found = 1; \\\n" +" } \\\n" +" if (name_fixed != name) \\\n" +" MEM_freeN((void *) name); \\\n" +" sname##_##identifier##_next(&iter); \\\n" +" } \\\n" +" sname##_##identifier##_end(&iter); \\\n" +" if (!found) \\\n" +" memset(r_ptr, 0, sizeof(*r_ptr)); \\\n" +" return found; \\\n" " } \n" "#define COLLECTION_PROPERTY_LOOKUP_STRING_TRUE(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_string_wrap(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) \\\n" diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 5d37f67fa93..11510b7e436 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -377,6 +377,38 @@ static void rna_Image_pixels_set(PointerRNA *ptr, const float *values) BKE_image_release_ibuf(ima, ibuf, lock); } +static int rna_Image_channels_get(PointerRNA *ptr) +{ + Image *im = (Image *)ptr->data; + ImBuf *ibuf; + void *lock; + int channels = 0; + + ibuf = BKE_image_acquire_ibuf(im, NULL, &lock); + if (ibuf) + channels = ibuf->channels; + + BKE_image_release_ibuf(im, ibuf, lock); + + return channels; +} + +static int rna_Image_is_float_get(PointerRNA *ptr) +{ + Image *im = (Image *)ptr->data; + ImBuf *ibuf; + void *lock; + int is_float = FALSE; + + ibuf = BKE_image_acquire_ibuf(im, NULL, &lock); + if (ibuf) + is_float = ibuf->rect_float != NULL; + + BKE_image_release_ibuf(im, ibuf, lock); + + return is_float; +} + #else static void rna_def_imageuser(BlenderRNA *brna) @@ -664,6 +696,10 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Duration", "Duration (in frames) of the image (1 when not a video/sequence)"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* NOTE about pixels/channels/is_floa: + * this properties describes how image is stored internally (inside of ImBuf), + * not how it was saved to disk or how it'll be saved on disk + */ prop = RNA_def_property(srna, "pixels", PROP_FLOAT, PROP_NONE); RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_multi_array(prop, 1, NULL); @@ -671,6 +707,16 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_dynamic_array_funcs(prop, "rna_Image_pixels_get_length"); RNA_def_property_float_funcs(prop, "rna_Image_pixels_get", "rna_Image_pixels_set", NULL); + prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, "rna_Image_channels_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Channels", "Number of channels in pixels nuffer"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop = RNA_def_property(srna, "is_float", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Image_is_float_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Is Float", "True if this image is stored in float buffer"); + prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings"); RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); |