Merge branch 'master' into blender2.8
[blender.git] / intern / cycles / blender / blender_util.h
index 079320e909ca5be7513610c99243c8663e919f9f..89a53a1deca75f6b54962f843456710fc59401d7 100644 (file)
@@ -1,19 +1,17 @@
 /*
- * Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
  */
 
 #ifndef __BLENDER_UTIL_H__
  * todo: clean this up ... */
 
 extern "C" {
-void BLI_timestr(double _time, char *str);
+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);
+float *BKE_image_get_float_pixels_for_frame(void *image, int frame);
 }
 
 CCL_NAMESPACE_BEGIN
 
-static inline BL::Mesh object_to_mesh(BL::Object self, BL::Scene scene, bool apply_modifiers, bool render)
+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 self.to_mesh(NULL, scene, apply_modifiers, (render)? 2: 1);
+       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 object_remove_mesh(BL::BlendData data, BL::Mesh mesh)
+static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap& curve,
+                                         float *min_x,
+                                         float *max_x)
 {
-       /* TODO: BlendData.meshes ideally should be also a subclass of BlendDataMeshes */
-       BL::BlendDataMeshes mesh_data(data.ptr);
+       *min_x = min(*min_x, curve.points[0].location()[0]);
+       *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
+}
 
-       mesh_data.remove(NULL, mesh);
+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 object_create_duplilist(BL::Object self, BL::Scene scene)
+static inline void curvemapping_to_array(BL::CurveMapping& cumap,
+                                         array<float>& data,
+                                         int size)
 {
-       self.dupli_list_create(NULL, scene, 2);
+       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 object_free_duplilist(BL::Object self)
+static inline void curvemapping_color_to_array(BL::CurveMapping& cumap,
+                                               array<float3>& data,
+                                               int size,
+                                               bool rgb_curve)
 {
-       self.dupli_list_clear();
+       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 = 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));
+                       data[i][2] = mapB.evaluate(mapI.evaluate(t));
+               }
+       }
+       else {
+               for(int i = 0; i < size; i++) {
+                       float t = min_x + (float)i/(float)(size-1) * range_x;
+
+                       data[i][0] = mapR.evaluate(t);
+                       data[i][1] = mapG.evaluate(t);
+                       data[i][2] = mapB.evaluate(t);
+               }
+       }
 }
 
-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 string image_user_file_path(BL::ImageUser iuser, BL::Image ima, int cfra)
+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)
+{
+       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)
 {
        char filepath[1024];
        BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
@@ -88,14 +196,27 @@ static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, in
        return string(filepath);
 }
 
-static inline void scene_frame_set(BL::Scene scene, int frame)
+static inline int image_user_frame_number(BL::ImageUser& iuser, int cfra)
 {
-       scene.frame_set(frame, 0.0f);
+       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)
+static inline Transform get_transform(const BL::Array<float, 16>& array)
 {
        Transform tfm;
 
@@ -107,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;
 
@@ -148,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;
 
@@ -157,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++)
@@ -167,43 +300,81 @@ 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;
 }
 
-#if 0
 static inline float3 get_float3(PointerRNA& ptr, const char *name)
 {
        float3 f;
        RNA_float_get_array(&ptr, name, &f.x);
        return f;
 }
-#endif
+
+static inline void set_float3(PointerRNA& ptr, const char *name, float3 value)
+{
+       RNA_float_set_array(&ptr, name, &value.x);
+}
+
+static inline float4 get_float4(PointerRNA& ptr, const char *name)
+{
+       float4 f;
+       RNA_float_get_array(&ptr, name, &f.x);
+       return f;
+}
+
+static inline void set_float4(PointerRNA& ptr, const char *name, float4 value)
+{
+       RNA_float_set_array(&ptr, name, &value.x);
+}
 
 static inline bool get_boolean(PointerRNA& ptr, const char *name)
 {
        return RNA_boolean_get(&ptr, name)? true: false;
 }
 
+static inline void set_boolean(PointerRNA& ptr, const char *name, bool value)
+{
+       RNA_boolean_set(&ptr, name, (int)value);
+}
+
 static inline float get_float(PointerRNA& ptr, const char *name)
 {
        return RNA_float_get(&ptr, name);
 }
 
+static inline void set_float(PointerRNA& ptr, const char *name, float value)
+{
+       RNA_float_set(&ptr, name, value);
+}
+
 static inline int get_int(PointerRNA& ptr, const char *name)
 {
        return RNA_int_get(&ptr, name);
 }
 
-static inline int get_enum(PointerRNA& ptr, const char *name)
+static inline void set_int(PointerRNA& ptr, const char *name, int value)
+{
+       RNA_int_set(&ptr, name, value);
+}
+
+/* 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)
 {
-       return RNA_enum_get(&ptr, name);
+       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)
@@ -217,15 +388,47 @@ static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
        return string(identifier);
 }
 
+static inline void set_enum(PointerRNA& ptr, const char *name, int value)
+{
+       RNA_enum_set(&ptr, name, value);
+}
+
+static inline void set_enum(PointerRNA& ptr, const char *name, const string &identifier)
+{
+       RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str());
+}
+
+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)
+               MEM_freeN(cstr);
+       
+       return str;
+}
+
+static inline void set_string(PointerRNA& ptr, const char *name, const string &value)
+{
+       RNA_string_set(&ptr, name, value.c_str());
+}
+
 /* 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();
 
@@ -235,6 +438,87 @@ static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, co
        return path;
 }
 
+/* Texture Space */
+
+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());
+
+       if(size.x != 0.0f) size.x = 0.5f/size.x;
+       if(size.y != 0.0f) size.y = 0.5f/size.y;
+       if(size.z != 0.0f) size.z = 0.5f/size.z;
+
+       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.
@@ -248,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);
        }
@@ -263,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);
        }
@@ -278,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;
@@ -307,6 +591,12 @@ public:
                return recalc;
        }
 
+       bool is_used(const K& key)
+       {
+               T *data = find(key);
+               return (data) ? used_set.find(data) != used_set.end() : false;
+       }
+
        void used(T *data)
        {
                /* tag data as still in use */
@@ -366,27 +656,36 @@ protected:
 
 /* Object Key */
 
+enum { OBJECT_PERSISTENT_ID_SIZE = 8 };
+
 struct ObjectKey {
        void *parent;
-       int index;
+       int id[OBJECT_PERSISTENT_ID_SIZE];
        void *ob;
 
-       ObjectKey(void *parent_, int index_, void *ob_)
-       : parent(parent_), index(index_), ob(ob_) {}
+       ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_)
+       : parent(parent_), ob(ob_)
+       {
+               if(id_)
+                       memcpy(id, id_, sizeof(id));
+               else
+                       memset(id, 0, sizeof(id));
+       }
 
        bool operator<(const ObjectKey& k) const
-       { return (parent < k.parent || (parent == k.parent && (index < k.index || (index == k.index && ob < k.ob)))); }
-};
-
-struct ParticleSystemKey {
-       void *ob;
-       void *psys;
-
-       ParticleSystemKey(void *ob_, void *psys_)
-       : ob(ob_), psys(psys_) {}
+       {
+               if(ob < k.ob) {
+                       return true;
+               }
+               else if(ob == k.ob) {
+                       if(parent < k.parent)
+                               return true;
+                       else if(parent == k.parent)
+                               return memcmp(id, k.id, sizeof(id)) < 0;
+               }
 
-       bool operator<(const ParticleSystemKey& k) const
-       { return (ob < k.ob && psys < k.psys); }
+               return false;
+       }
 };
 
 CCL_NAMESPACE_END