Merge branch 'master' into blender2.8
[blender.git] / intern / cycles / blender / blender_util.h
index cb0f7b76d56bf69b774c8accedb32dd83f445f84..89a53a1deca75f6b54962f843456710fc59401d7 100644 (file)
@@ -11,7 +11,7 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 #ifndef __BLENDER_UTIL_H__
@@ -28,7 +28,7 @@
  * todo: clean this up ... */
 
 extern "C" {
-void BLI_timestr(double _time, char *str, size_t maxlen);
+size_t BLI_timecode_string_from_time_simple(char *str, size_t maxlen, double time_seconds);
 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);
@@ -37,34 +37,114 @@ float *BKE_image_get_float_pixels_for_frame(void *image, int frame);
 
 CCL_NAMESPACE_BEGIN
 
-static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL::Scene scene, bool apply_modifiers, bool render, bool calc_undeformed)
+void python_thread_state_save(void **python_thread_state);
+void python_thread_state_restore(void **python_thread_state);
+
+static inline BL::Mesh object_to_mesh(BL::BlendData& data,
+                                      BL::Object& object,
+                                      BL::Scene& scene,
+                                      bool apply_modifiers,
+                                      bool render,
+                                      bool calc_undeformed)
 {
-       return data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, true, calc_undeformed);
+       BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
+       if((bool)me) {
+               if(me.use_auto_smooth()) {
+                       me.calc_normals_split();
+               }
+               me.calc_tessface(true);
+       }
+       return me;
 }
 
-static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size)
+static inline void colorramp_to_array(BL::ColorRamp& ramp,
+                                      array<float3>& ramp_color,
+                                      array<float>& ramp_alpha,
+                                      int size)
 {
+       ramp_color.resize(size);
+       ramp_alpha.resize(size);
+
        for(int i = 0; i < size; i++) {
                float color[4];
 
-               ramp.evaluate(i/(float)(size-1), color);
-               data[i] = make_float4(color[0], color[1], color[2], color[3]);
+               ramp.evaluate((float)i/(float)(size-1), color);
+               ramp_color[i] = make_float3(color[0], color[1], color[2]);
+               ramp_alpha[i] = color[3];
+       }
+}
+
+static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap& curve,
+                                         float *min_x,
+                                         float *max_x)
+{
+       *min_x = min(*min_x, curve.points[0].location()[0]);
+       *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
+}
+
+static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap,
+                                       bool rgb_curve,
+                                       float *min_x,
+                                       float *max_x)
+{
+       /* const int num_curves = cumap.curves.length(); */  /* Gives linking error so far. */
+       const int num_curves = rgb_curve? 4: 3;
+       *min_x = FLT_MAX;
+       *max_x = -FLT_MAX;
+       for(int i = 0; i < num_curves; ++i) {
+               BL::CurveMap map(cumap.curves[i]);
+               curvemap_minmax_curve(map, min_x, max_x);
        }
 }
 
-static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *data, int size, bool rgb_curve)
+static inline void curvemapping_to_array(BL::CurveMapping& cumap,
+                                         array<float>& data,
+                                         int size)
 {
+       cumap.update();
+       BL::CurveMap curve = cumap.curves[0];
+       data.resize(size);
+       for(int i = 0; i < size; i++) {
+               float t = (float)i/(float)(size-1);
+               data[i] = curve.evaluate(t);
+       }
+}
+
+static inline void curvemapping_color_to_array(BL::CurveMapping& cumap,
+                                               array<float3>& data,
+                                               int size,
+                                               bool rgb_curve)
+{
+       float min_x = 0.0f, max_x = 1.0f;
+
+       /* TODO(sergey): There is no easy way to automatically guess what is
+        * the range to be used here for the case when mapping is applied on
+        * top of another mapping (i.e. R curve applied on top of common
+        * one).
+        *
+        * Using largest possible range form all curves works correct for the
+        * cases like vector curves and should be good enough heuristic for
+        * the color curves as well.
+        *
+        * There might be some better estimations here tho.
+        */
+       curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x);
+
+       const float range_x = max_x - min_x;
+
        cumap.update();
 
        BL::CurveMap mapR = cumap.curves[0];
        BL::CurveMap mapG = cumap.curves[1];
        BL::CurveMap mapB = cumap.curves[2];
 
+       data.resize(size);
+
        if(rgb_curve) {
                BL::CurveMap mapI = cumap.curves[3];
 
                for(int i = 0; i < size; i++) {
-                       float t = i/(float)(size-1);
+                       float t = min_x + (float)i/(float)(size-1) * range_x;
 
                        data[i][0] = mapR.evaluate(mapI.evaluate(t));
                        data[i][1] = mapG.evaluate(mapI.evaluate(t));
@@ -73,7 +153,7 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *d
        }
        else {
                for(int i = 0; i < size; i++) {
-                       float t = i/(float)(size-1);
+                       float t = min_x + (float)i/(float)(size-1) * range_x;
 
                        data[i][0] = mapR.evaluate(t);
                        data[i][1] = mapG.evaluate(t);
@@ -82,27 +162,33 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *d
        }
 }
 
-static inline bool BKE_object_is_modified(BL::Object self, BL::Scene scene, bool preview)
+static inline bool BKE_object_is_modified(BL::Object& self,
+                                          BL::Scene& scene,
+                                          bool preview)
 {
        return self.is_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
 }
 
-static inline bool BKE_object_is_deform_modified(BL::Object self, BL::Scene scene, bool preview)
+static inline bool BKE_object_is_deform_modified(BL::Object& self,
+                                                 BL::Scene& scene,
+                                                 bool preview)
 {
        return self.is_deform_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
 }
 
-static inline int render_resolution_x(BL::RenderSettings b_render)
+static inline int render_resolution_x(BL::RenderSettings& b_render)
 {
        return b_render.resolution_x()*b_render.resolution_percentage()/100;
 }
 
-static inline int render_resolution_y(BL::RenderSettings b_render)
+static inline int render_resolution_y(BL::RenderSettings& b_render)
 {
        return b_render.resolution_y()*b_render.resolution_percentage()/100;
 }
 
-static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, int cfra)
+static inline string image_user_file_path(BL::ImageUser& iuser,
+                                          BL::Image& ima,
+                                          int cfra)
 {
        char filepath[1024];
        BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
@@ -110,25 +196,27 @@ 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)
+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)
+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)
+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)
+static inline Transform get_transform(const BL::Array<float, 16>& array)
 {
        Transform tfm;
 
@@ -140,37 +228,42 @@ static inline Transform get_transform(BL::Array<float, 16> array)
        return tfm;
 }
 
-static inline float2 get_float2(BL::Array<float, 2> array)
+static inline float2 get_float2(const BL::Array<float, 2>& array)
 {
        return make_float2(array[0], array[1]);
 }
 
-static inline float3 get_float3(BL::Array<float, 2> array)
+static inline float3 get_float3(const BL::Array<float, 2>& array)
 {
        return make_float3(array[0], array[1], 0.0f);
 }
 
-static inline float3 get_float3(BL::Array<float, 3> array)
+static inline float3 get_float3(const BL::Array<float, 3>& array)
 {
        return make_float3(array[0], array[1], array[2]);
 }
 
-static inline float3 get_float3(BL::Array<float, 4> array)
+static inline float3 get_float3(const BL::Array<float, 4>& array)
 {
        return make_float3(array[0], array[1], array[2]);
 }
 
-static inline float4 get_float4(BL::Array<float, 4> array)
+static inline float4 get_float4(const BL::Array<float, 4>& array)
 {
        return make_float4(array[0], array[1], array[2], array[3]);
 }
 
-static inline int4 get_int4(BL::Array<int, 4> array)
+static inline int3 get_int3(const BL::Array<int, 3>& array)
+{
+       return make_int3(array[0], array[1], array[2]);
+}
+
+static inline int4 get_int4(const BL::Array<int, 4>& array)
 {
        return make_int4(array[0], array[1], array[2], array[3]);
 }
 
-static inline uint get_layer(BL::Array<int, 20> array)
+static inline uint get_layer(const BL::Array<int, 20>& array)
 {
        uint layer = 0;
 
@@ -181,7 +274,10 @@ static inline uint get_layer(BL::Array<int, 20> array)
        return layer;
 }
 
-static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_array, bool use_local, bool is_light = false)
+static inline uint get_layer(const BL::Array<int, 20>& array,
+                             const BL::Array<int, 8>& local_array,
+                             bool is_light = false,
+                             uint scene_layers = (1 << 20) - 1)
 {
        uint layer = 0;
 
@@ -190,9 +286,13 @@ static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_a
                        layer |= (1 << i);
 
        if(is_light) {
-               /* consider lamps on all local view layers */
-               for(uint i = 0; i < 8; i++)
-                       layer |= (1 << (20+i));
+               /* Consider light is visible if it was visible without layer
+                * override, which matches behavior of Blender Internal.
+                */
+               if(layer & scene_layers) {
+                       for(uint i = 0; i < 8; i++)
+                               layer |= (1 << (20+i));
+               }
        }
        else {
                for(uint i = 0; i < 8; i++)
@@ -200,13 +300,6 @@ static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_a
                                layer |= (1 << (20+i));
        }
 
-       /* we don't have spare bits for localview (normally 20-28) because
-        * PATH_RAY_LAYER_SHIFT uses 20-32. So - check if we have localview and if
-        * so, shift local view bits down to 1-8, since this is done for the view
-        * port only - it should be OK and not conflict with render layers. */
-       if(use_local)
-               layer >>= 20;
-
        return layer;
 }
 
@@ -264,9 +357,24 @@ static inline void set_int(PointerRNA& ptr, const char *name, int value)
        RNA_int_set(&ptr, name, value);
 }
 
-static inline int get_enum(PointerRNA& ptr, const char *name)
-{
-       return RNA_enum_get(&ptr, name);
+/* Get a RNA enum value with sanity check: if the RNA value is above num_values
+ * the function will return a fallback default value.
+ *
+ * NOTE: This function assumes that RNA enum values are a continuous sequence
+ * from 0 to num_values-1. Be careful to use it with enums where some values are
+ * deprecated!
+ */
+static inline int get_enum(PointerRNA& ptr,
+                           const char *name,
+                           int num_values = -1,
+                           int default_value = -1)
+{
+       int value = RNA_enum_get(&ptr, name);
+       if(num_values != -1 && value >= num_values) {
+               assert(default_value != -1);
+               value = default_value;
+       }
+       return value;
 }
 
 static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
@@ -287,7 +395,7 @@ static inline void set_enum(PointerRNA& ptr, const char *name, int value)
 
 static inline void set_enum(PointerRNA& ptr, const char *name, const string &identifier)
 {
-       RNA_enum_set_identifier(&ptr, name, identifier.c_str());
+       RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str());
 }
 
 static inline string get_string(PointerRNA& ptr, const char *name)
@@ -295,7 +403,7 @@ static inline string get_string(PointerRNA& ptr, const char *name)
        char cstrbuf[1024];
        char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf));
        string str(cstr);
-       if (cstr != cstrbuf)
+       if(cstr != cstrbuf)
                MEM_freeN(cstr);
        
        return str;
@@ -308,13 +416,19 @@ static inline void set_string(PointerRNA& ptr, const char *name, const string &v
 
 /* Relative Paths */
 
-static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
+static inline string blender_absolute_path(BL::BlendData& b_data,
+                                           BL::ID& b_id,
+                                           const string& path)
 {
        if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
                string dirname;
                
-               if(b_id.library())
-                       dirname = blender_absolute_path(b_data, b_id.library(), b_id.library().filepath());
+               if(b_id.library()) {
+                       BL::ID b_library_id(b_id.library());
+                       dirname = blender_absolute_path(b_data,
+                                                       b_library_id,
+                                                       b_id.library().filepath());
+               }
                else
                        dirname = b_data.filepath();
 
@@ -326,7 +440,9 @@ static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, co
 
 /* Texture Space */
 
-static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size)
+static inline void mesh_texture_space(BL::Mesh& b_mesh,
+                                      float3& loc,
+                                      float3& size)
 {
        loc = get_float3(b_mesh.texspace_location());
        size = get_float3(b_mesh.texspace_size());
@@ -338,6 +454,71 @@ static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size
        loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
 }
 
+/* object used for motion blur */
+static inline bool object_use_motion(BL::Object& b_parent, BL::Object& b_ob)
+{
+       PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+       bool use_motion = get_boolean(cobject, "use_motion_blur");
+       /* If motion blur is enabled for the object we also check
+        * whether it's enabled for the parent object as well.
+        *
+        * This way we can control motion blur from the dupligroup
+        * duplicator much easier.
+        */
+       if(use_motion && b_parent.ptr.data != b_ob.ptr.data) {
+               PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
+               use_motion &= get_boolean(parent_cobject, "use_motion_blur");
+       }
+       return use_motion;
+}
+
+/* object motion steps */
+static inline uint object_motion_steps(BL::Object& b_ob)
+{
+       PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+       uint steps = get_int(cobject, "motion_steps");
+
+       /* use uneven number of steps so we get one keyframe at the current frame,
+        * and ue 2^(steps - 1) so objects with more/fewer steps still have samples
+        * at the same times, to avoid sampling at many different times */
+       return (2 << (steps - 1)) + 1;
+}
+
+/* object uses deformation motion blur */
+static inline bool object_use_deform_motion(BL::Object& b_parent,
+                                            BL::Object& b_ob)
+{
+       PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
+       bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
+       /* If motion blur is enabled for the object we also check
+        * whether it's enabled for the parent object as well.
+        *
+        * This way we can control motion blur from the dupligroup
+        * duplicator much easier.
+        */
+       if(use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
+               PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
+               use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
+       }
+       return use_deform_motion;
+}
+
+static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob)
+{
+       BL::Object::modifiers_iterator b_mod;
+
+       for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
+               if(b_mod->is_a(&RNA_SmokeModifier)) {
+                       BL::SmokeModifier b_smd(*b_mod);
+
+                       if(b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN)
+                               return b_smd.domain_settings();
+               }
+       }
+       
+       return BL::SmokeDomainSettings(PointerRNA_NULL);
+}
+
 /* ID Map
  *
  * Utility class to keep in sync with blender data.
@@ -351,7 +532,7 @@ public:
                scene_data = scene_data_;
        }
 
-       T *find(BL::ID id)
+       T *find(const BL::ID& id)
        {
                return find(id.ptr.id.data);
        }
@@ -366,7 +547,7 @@ public:
                return NULL;
        }
 
-       void set_recalc(BL::ID id)
+       void set_recalc(const BL::ID& id)
        {
                b_recalc.insert(id.ptr.data);
        }
@@ -381,12 +562,12 @@ public:
                used_set.clear();
        }
 
-       bool sync(T **r_data, BL::ID id)
+       bool sync(T **r_data, const BL::ID& id)
        {
                return sync(r_data, id, id, id.ptr.id.data);
        }
 
-       bool sync(T **r_data, BL::ID id, BL::ID parent, const K& key)
+       bool sync(T **r_data, const BL::ID& id, const BL::ID& parent, const K& key)
        {
                T *data = find(key);
                bool recalc;
@@ -507,33 +688,6 @@ struct ObjectKey {
        }
 };
 
-/* Particle System Key */
-
-struct ParticleSystemKey {
-       void *ob;
-       int id[OBJECT_PERSISTENT_ID_SIZE];
-
-       ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE])
-       : ob(ob_)
-       {
-               if(id_)
-                       memcpy(id, id_, sizeof(id));
-               else
-                       memset(id, 0, sizeof(id));
-       }
-
-       bool operator<(const ParticleSystemKey& k) const
-       {
-               /* first id is particle index, we don't compare that */
-               if(ob < k.ob)
-                       return true;
-               else if(ob == k.ob)
-                       return memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0;
-
-               return false;
-       }
-};
-
 CCL_NAMESPACE_END
 
 #endif /* __BLENDER_UTIL_H__ */