diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-01-16 21:07:25 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2013-01-16 21:07:25 +0400 |
commit | b01233b07fbf06ba5139d4565c6148f65ab921e9 (patch) | |
tree | b7ffc32198307c1364f41b8f0368026a16af88ed | |
parent | f55a9eb3d4e12e5667e16b9f4dd2c2ec88a792f6 (diff) |
Movies support for Cycles
This adds support of movie textures for Cycles rendering.
Uses the same builtin images routines as packed/generated images,
but with some extra non-rna hookups from blender_session side.
Basically, it's not so clear how to give access to video frames
via C++ RNA -- it'll require exposing ImBuf to API, doing some
threading locks and so. Ended up adding two more functions which
are actually bad level call, but don't consider it's so much bad
-- we have few bad calls already, which are actually related.
Changed a bit how builtin images names are passing to image
manager. Now it's not just an ID datablock name, but also a frame
number concatenated via '@' character, which makes itpossible to
easily know frame number to be used for movie images, without
adding extra descriptors to image manager.
Decoding of builtin name is a bit slower now, but it should be
still nothing in comparison with rendering complexity.
Also exposed image user's frame_current to python API, which
is needed to get absolute frame number of movie from node's
image user.
P.S. Generated/packed images are also using bad level call but
only does it to make things more clear here. Either all images
are using C++ RNA here or no images does. That's the most clear
for now.
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 83 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.h | 7 | ||||
-rw-r--r-- | intern/cycles/blender/blender_shader.cpp | 26 | ||||
-rw-r--r-- | intern/cycles/blender/blender_util.h | 18 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_image.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image.c | 54 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_image.c | 5 |
7 files changed, 172 insertions, 25 deletions
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 60dfe37c9f8..3913323c21c 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -612,8 +612,25 @@ 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) +/* builtin image file name is actually an image datablock name with + * absolute sequence frame number concatenated via '@' character + * + * this function splits image id name and frame number from a + * builtin image name + */ +void BlenderSession::builtin_name_split(const string &builtin_name, string &name, int &frame) +{ + int last = builtin_name.find_last_of('@'); + name = builtin_name.substr(0, last); + frame = atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); +} + +void BlenderSession::builtin_image_info(const string &builtin_name, bool &is_float, int &width, int &height, int &channels) { + string name; + int frame; + builtin_name_split(builtin_name, name, frame); + BL::Image b_image = b_data.images[name]; if(b_image) { @@ -630,8 +647,12 @@ void BlenderSession::builtin_image_info(const string &name, bool &is_float, int } } -bool BlenderSession::builtin_image_pixels(const string &name, unsigned char *pixels) +bool BlenderSession::builtin_image_pixels(const string &builtin_name, unsigned char *pixels) { + string name; + int frame; + builtin_name_split(builtin_name, name, frame); + BL::Image b_image = b_data.images[name]; if(b_image) { @@ -639,16 +660,27 @@ bool BlenderSession::builtin_image_pixels(const string &name, unsigned char *pix 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; + unsigned char *image_pixels; + image_pixels = image_get_pixels_for_frame(b_image, frame); - /* 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; + if(image_pixels) { + memcpy(pixels, image_pixels, width * height * channels * sizeof(unsigned char)); + MEM_freeN(image_pixels); + } + else { + if(channels == 1) { + memset(pixels, 0, width * height * sizeof(unsigned char)); + } + else { + unsigned char *cp = pixels; + for(int i = 0; i < width * height; i++, cp += channels) { + cp[0] = 255; + cp[1] = 0; + cp[2] = 255; + if(channels == 4) + cp[3] = 255; + } + } } return true; @@ -657,8 +689,12 @@ bool BlenderSession::builtin_image_pixels(const string &name, unsigned char *pix return false; } -bool BlenderSession::builtin_image_float_pixels(const string &name, float *pixels) +bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, float *pixels) { + string name; + int frame; + builtin_name_split(builtin_name, name, frame); + BL::Image b_image = b_data.images[name]; if(b_image) { @@ -666,9 +702,28 @@ bool BlenderSession::builtin_image_float_pixels(const string &name, float *pixel int height = b_image.size()[1]; int channels = b_image.channels(); - BL::DynamicArray<float> pixels_array = b_image.pixels(); + float *image_pixels; + image_pixels = image_get_float_pixels_for_frame(b_image, frame); - memcpy(pixels, pixels_array.data, width * height * channels * sizeof(float)); + if(image_pixels) { + memcpy(pixels, image_pixels, width * height * channels * sizeof(float)); + MEM_freeN(image_pixels); + } + else { + if(channels == 1) { + memset(pixels, 0, width * height * sizeof(float)); + } + else { + float *fp = pixels; + for(int i = 0; i < width * height; i++, fp += channels) { + fp[0] = 1.0f; + fp[1] = 0.0f; + fp[2] = 1.0f; + if(channels == 4) + fp[3] = 1.0f; + } + } + } return true; } diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index dfa487bd244..686ff3d1be9 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -94,9 +94,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); + void builtin_name_split(const string &builtin_name, string &name, int &frame); + void builtin_image_info(const string &builtin_name, bool &is_float, int &width, int &height, int &channels); + bool builtin_image_pixels(const string &builtin_name, unsigned char *pixels); + bool builtin_image_float_pixels(const string &builtin_name, float *pixels); }; CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 3bb02bbfe74..b1eaedba47a 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -511,17 +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 movie images */ - if(b_image && b_image.source() != BL::Image::source_MOVIE) { + if(b_image) { /* 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; + b_image.source() == BL::Image::source_GENERATED || + b_image.source() == BL::Image::source_MOVIE; 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(); + /* for builtin images we're using image datablock name to find an image to + * read pixels from later + * + * also store frame number as well, so there's no differences in handling + * builtin names for packed images and movies + */ + int scene_frame = b_scene.frame_current(); + int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame); + image->filename = b_image.name() + "@" + string_printf("%d", image_frame); image->is_builtin = true; } else { @@ -542,12 +549,15 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen BL::ShaderNodeTexEnvironment b_env_node(b_node); BL::Image b_image(b_env_node.image()); EnvironmentTextureNode *env = new EnvironmentTextureNode(); - if(b_image && b_image.source() != BL::Image::source_MOVIE) { + if(b_image) { bool is_builtin = b_image.packed_file() || - b_image.source() == BL::Image::source_GENERATED; + b_image.source() == BL::Image::source_GENERATED || + b_image.source() == BL::Image::source_MOVIE; if(is_builtin) { - env->filename = b_image.name(); + int scene_frame = b_scene.frame_current(); + int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame); + env->filename = b_image.name() + "@" + string_printf("%d", image_frame); env->is_builtin = true; } else { diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 88c98860794..f134416f2d0 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -33,6 +33,8 @@ extern "C" { void BLI_timestr(double _time, char *str); void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr); void BKE_image_user_file_path(void *iuser, void *ima, char *path); +unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame); +float *BKE_image_get_float_pixels_for_frame(void *image, int frame); } CCL_NAMESPACE_BEGIN @@ -100,6 +102,22 @@ static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, in return string(filepath); } +static inline int image_user_frame_number(BL::ImageUser iuser, int cfra) +{ + BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0); + return iuser.frame_current(); +} + +static inline unsigned char *image_get_pixels_for_frame(BL::Image image, int frame) +{ + return BKE_image_get_pixels_for_frame(image.ptr.data, frame); +} + +static inline float *image_get_float_pixels_for_frame(BL::Image image, int frame) +{ + return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame); +} + /* Utilities */ static inline Transform get_transform(BL::Array<float, 16> array) diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 499609932d1..597f2f25575 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -219,6 +219,10 @@ void BKE_image_buf_fill_color(unsigned char *rect, float *rect_float, int width, void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int height, int width); void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int height, int width); +/* Cycles hookup */ +unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame); +float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 21417386d65..5124406b641 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -3199,3 +3199,57 @@ void BKE_image_get_aspect(Image *image, float *aspx, float *aspy) else *aspy = 1.0f; } + +unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame) +{ + ImageUser iuser = {0}; + void *lock; + ImBuf *ibuf; + unsigned char *pixels = NULL; + + iuser.framenr = frame; + iuser.ok = TRUE; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf) { + pixels = (unsigned char *) ibuf->rect; + + if (pixels) + pixels = MEM_dupallocN(pixels); + + BKE_image_release_ibuf(image, ibuf, lock); + } + + if (!pixels) + return NULL; + + return pixels; +} + +float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame) +{ + ImageUser iuser = {0}; + void *lock; + ImBuf *ibuf; + float *pixels = NULL; + + iuser.framenr = frame; + iuser.ok = TRUE; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf) { + pixels = ibuf->rect_float; + + if (pixels) + pixels = MEM_dupallocN(pixels); + + BKE_image_release_ibuf(image, ibuf, lock); + } + + if (!pixels) + return NULL; + + return pixels; +} diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 81dbfff13b2..180a5a180fd 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -427,6 +427,11 @@ static void rna_def_imageuser(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_ImageUser_update"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + prop = RNA_def_property(srna, "frame_current", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "framenr"); + RNA_def_property_range(prop, MINAFRAME, MAXFRAME); + RNA_def_property_ui_text(prop, "Current Frame", "Current frame number in image sequence or movie"); + /* animation */ prop = RNA_def_property(srna, "use_cyclic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "cycl", 0); |