Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Thu, 12 Jan 2017 11:59:45 +0000 (12:59 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Thu, 12 Jan 2017 11:59:45 +0000 (12:59 +0100)
20 files changed:
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_mesh.cpp
intern/cycles/blender/blender_session.cpp
intern/cycles/blender/blender_util.h
release/scripts/startup/bl_ui/space_sequencer.py
source/blender/blenkernel/intern/collision.c
source/blender/blenkernel/intern/dynamicpaint.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/smoke.c
source/blender/blenlib/BLI_math_geom.h
source/blender/blenlib/intern/math_geom.c
source/blender/editors/interface/interface_utils.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_nla/nla_buttons.c
source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
source/blender/makesrna/RNA_types.h
source/blender/makesrna/intern/rna_mesh_api.c
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/occlusion.c
tests/python/cycles_render_tests.py

index acca64148525a2ccdcc3a910a024580af755191d..a573fa1ce22db0668f36fb9291852c4fd0b8508c 100644 (file)
@@ -226,6 +226,7 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel):
 
         scene = context.scene
         cscene = scene.cycles
+        ccscene = scene.cycles_curves
 
         if cscene.feature_set == 'EXPERIMENTAL':
             split = layout.split()
@@ -252,6 +253,25 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel):
             row.prop(cscene, "volume_step_size")
             row.prop(cscene, "volume_max_steps")
 
+        layout.prop(ccscene, "use_curves", text="Use Hair")
+        col = layout.column()
+        col.active = ccscene.use_curves
+
+        col.prop(ccscene, "primitive", text="Primitive")
+        col.prop(ccscene, "shape", text="Shape")
+
+        if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'):
+            col.prop(ccscene, "cull_backfacing", text="Cull back-faces")
+
+        if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK':
+            col.prop(ccscene, "resolution", text="Resolution")
+        elif ccscene.primitive == 'CURVE_SEGMENTS':
+            col.prop(ccscene, "subdivisions", text="Curve subdivisions")
+
+        row = col.row()
+        row.prop(ccscene, "minimum_width", text="Min Pixels")
+        row.prop(ccscene, "maximum_width", text="Max Ext.")
+
 
 class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):
     bl_label = "Light Paths"
@@ -1391,43 +1411,6 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
             layout.template_ID(slot, "texture", new="texture.new")
 
 
-class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
-    bl_label = "Cycles Hair Rendering"
-    bl_context = "particle"
-
-    @classmethod
-    def poll(cls, context):
-        psys = context.particle_system
-        return CyclesButtonsPanel.poll(context) and psys and psys.settings.type == 'HAIR'
-
-    def draw_header(self, context):
-        ccscene = context.scene.cycles_curves
-        self.layout.prop(ccscene, "use_curves", text="")
-
-    def draw(self, context):
-        layout = self.layout
-
-        scene = context.scene
-        ccscene = scene.cycles_curves
-
-        layout.active = ccscene.use_curves
-
-        layout.prop(ccscene, "primitive", text="Primitive")
-        layout.prop(ccscene, "shape", text="Shape")
-
-        if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'):
-            layout.prop(ccscene, "cull_backfacing", text="Cull back-faces")
-
-        if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK':
-            layout.prop(ccscene, "resolution", text="Resolution")
-        elif ccscene.primitive == 'CURVE_SEGMENTS':
-            layout.prop(ccscene, "subdivisions", text="Curve subdivisions")
-
-        row = layout.row()
-        row.prop(ccscene, "minimum_width", text="Min Pixels")
-        row.prop(ccscene, "maximum_width", text="Max Ext.")
-
-
 class CyclesRender_PT_bake(CyclesButtonsPanel, Panel):
     bl_label = "Bake"
     bl_context = "render"
index fab03c7659bdb8c75adca94d81857753e389cad1..66893d4d6680fdeec6139e29211a63b33b7312c7 100644 (file)
@@ -597,8 +597,8 @@ static void create_mesh(Scene *scene,
                         Mesh *mesh,
                         BL::Mesh& b_mesh,
                         const vector<Shader*>& used_shaders,
-                        bool subdivision=false,
-                        bool subdivide_uvs=true)
+                        bool subdivision = false,
+                        bool subdivide_uvs = true)
 {
        /* count vertices and faces */
        int numverts = b_mesh.vertices.length();
@@ -671,28 +671,10 @@ static void create_mesh(Scene *scene,
                        int shader = clamp(f->material_index(), 0, used_shaders.size()-1);
                        bool smooth = f->use_smooth() || use_loop_normals;
 
-                       /* split vertices if normal is different
+                       /* Create triangles.
                         *
-                        * note all vertex attributes must have been set here so we can split
-                        * and copy attributes in split_vertex without remapping later */
-                       if(use_loop_normals) {
-                               BL::Array<float, 12> loop_normals = f->split_normals();
-
-                               for(int i = 0; i < n; i++) {
-                                       float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
-
-                                       if(N[vi[i]] != loop_N) {
-                                               int new_vi = mesh->split_vertex(vi[i]);
-
-                                               /* set new normal and vertex index */
-                                               N = attr_N->data_float3();
-                                               N[new_vi] = loop_N;
-                                               vi[i] = new_vi;
-                                       }
-                               }
-                       }
-
-                       /* create triangles */
+                        * NOTE: Autosmooth is already taken care about.
+                        */
                        if(n == 4) {
                                if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
                                   is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
@@ -724,24 +706,8 @@ static void create_mesh(Scene *scene,
 
                        vi.reserve(n);
                        for(int i = 0; i < n; i++) {
+                               /* NOTE: Autosmooth is already taken care about. */
                                vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();
-
-                               /* split vertices if normal is different
-                                *
-                                * note all vertex attributes must have been set here so we can split
-                                * and copy attributes in split_vertex without remapping later */
-                               if(use_loop_normals) {
-                                       float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal());
-
-                                       if(N[vi[i]] != loop_N) {
-                                               int new_vi = mesh->split_vertex(vi[i]);
-
-                                               /* set new normal and vertex index */
-                                               N = attr_N->data_float3();
-                                               N[new_vi] = loop_N;
-                                               vi[i] = new_vi;
-                                       }
-                               }
                        }
 
                        /* create subd faces */
@@ -961,7 +927,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
 
                mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
 
-               BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type);
+               BL::Mesh b_mesh = object_to_mesh(b_data,
+                                                b_ob,
+                                                b_scene,
+                                                true,
+                                                !preview,
+                                                need_undeformed,
+                                                mesh->subdivision_type);
 
                if(b_mesh) {
                        if(render_layer.use_surfaces && !hide_tris) {
@@ -1086,7 +1058,13 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
 
        if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
                /* get derived mesh */
-               b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false);
+               b_mesh = object_to_mesh(b_data,
+                                       b_ob,
+                                       b_scene,
+                                       true,
+                                       !preview,
+                                       false,
+                                       Mesh::SUBDIVISION_NONE);
        }
 
        if(!b_mesh) {
@@ -1157,10 +1135,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
                        {
                                /* no motion, remove attributes again */
                                if(b_mesh.vertices.length() != numverts) {
-                                       VLOG(1) << "Topology differs, disabling motion blur.";
+                                       VLOG(1) << "Topology differs, disabling motion blur for object "
+                                               << b_ob.name();
                                }
                                else {
-                                       VLOG(1) << "No actual deformation motion for object " << b_ob.name();
+                                       VLOG(1) << "No actual deformation motion for object "
+                                               << b_ob.name();
                                }
                                mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
                                if(attr_mN)
index 71c1eefe65f6232a2da556362effd2b85f5ddb2b..21166b2f1555e2b3d56d8b214f4e11a44319bf07 100644 (file)
@@ -580,7 +580,7 @@ static void populate_bake_data(BakeData *data, const
        BL::BakePixel bp = pixel_array;
 
        int i;
-       for(i=0; i < num_pixels; i++) {
+       for(i = 0; i < num_pixels; i++) {
                if(bp.object_id() == object_id) {
                        data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy());
                } else {
index f17a61f0ac88c74f99d72d4f6643c22117734c22..b67834cdea3d41801821d52de0edace4edb75788 100644 (file)
@@ -48,12 +48,12 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data,
                                       bool apply_modifiers,
                                       bool render,
                                       bool calc_undeformed,
-                                      bool subdivision)
+                                      Mesh::SubdivisionType subdivision_type)
 {
        bool subsurf_mod_show_render;
        bool subsurf_mod_show_viewport;
 
-       if(subdivision) {
+       if(subdivision_type != Mesh::SUBDIVISION_NONE) {
                BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1];
 
                subsurf_mod_show_render = subsurf_mod.show_render();
@@ -65,7 +65,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data,
 
        BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
 
-       if(subdivision) {
+       if(subdivision_type != Mesh::SUBDIVISION_NONE) {
                BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1];
 
                subsurf_mod.show_render(subsurf_mod_show_render);
@@ -74,9 +74,14 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data,
 
        if((bool)me) {
                if(me.use_auto_smooth()) {
-                       me.calc_normals_split();
+                       if(subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK) {
+                               me.calc_normals_split();
+                       }
+                       else {
+                               me.split_faces();
+                       }
                }
-               if(!subdivision) {
+               if(subdivision_type == Mesh::SUBDIVISION_NONE) {
                        me.calc_tessface(true);
                }
        }
index 26136a8e024fcfc58f3e2f96fe1337a99f04e548..0648db3746d4df0f411181c601432f1669ad37ac 100644 (file)
@@ -497,6 +497,7 @@ class SequencerButtonsPanel_Output:
 
 class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
     bl_label = "Edit Strip"
+    bl_category = "Strip"
 
     def draw(self, context):
         layout = self.layout
@@ -563,6 +564,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
 
 class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
     bl_label = "Effect Strip"
+    bl_category = "Strip"
 
     @classmethod
     def poll(cls, context):
@@ -701,6 +703,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
 
 class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
     bl_label = "Strip Input"
+    bl_category = "Strip"
 
     @classmethod
     def poll(cls, context):
@@ -795,6 +798,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
 
 class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
     bl_label = "Sound"
+    bl_category = "Strip"
 
     @classmethod
     def poll(cls, context):
@@ -848,6 +852,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
 
 class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
     bl_label = "Scene"
+    bl_category = "Strip"
 
     @classmethod
     def poll(cls, context):
@@ -894,6 +899,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
 
 class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
     bl_label = "Mask"
+    bl_category = "Strip"
 
     @classmethod
     def poll(cls, context):
@@ -923,6 +929,7 @@ class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
 
 class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
     bl_label = "Filter"
+    bl_category = "Strip"
 
     @classmethod
     def poll(cls, context):
@@ -977,6 +984,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
 
 class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
     bl_label = "Proxy/Timecode"
+    bl_category = "Strip"
 
     @classmethod
     def poll(cls, context):
@@ -1109,6 +1117,7 @@ class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel):
 
 class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
     bl_label = "Modifiers"
+    bl_category = "Modifiers"
 
     def draw(self, context):
         layout = self.layout
@@ -1211,6 +1220,7 @@ class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel):
     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
     _context_path = "scene.sequence_editor.active_strip"
     _property_type = (bpy.types.Sequence,)
+    bl_category = "Strip"
 
 
 if __name__ == "__main__":  # only for live edit.
index 18ca1407ba06b7f6d5d8062866f964d0d0ddda1a..ee25be368555533097de01492c034b3a5dbb916b 100644 (file)
@@ -1014,7 +1014,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll
 }
 
 BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
-                                                  float r_nor[3], float *r_lambda, float r_w[4])
+                                                  float r_nor[3], float *r_lambda, float r_w[3])
 {
        float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
        float nor_v0p2, nor_p1p2;
@@ -1026,7 +1026,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float
        
        nor_v0p2 = dot_v3v3(v0p2, r_nor);
        madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
-       interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face);
+       interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
        
        sub_v3_v3v3(p1p2, p2, p1);
        sub_v3_v3v3(v0p2, p2, v0);
@@ -1085,7 +1085,7 @@ static CollPair *cloth_point_collpair(
        const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
        float lambda /*, distance1 */, distance2;
        float facenor[3], v1p1[3], v1p2[3];
-       float w[4];
+       float w[3];
 
        if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w))
                return collpair;
index fce4620294d09aca9bf55f9df501fe8bab2d525f..1e8d0f0d767a56b3b17aa1cec8047e68f77f436b 100644 (file)
@@ -3739,7 +3739,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
 
                /* velocity brush, only do on main sample */
                if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
-                       float weights[4];
+                       float weights[3];
                        float brushPointVelocity[3];
                        float velocity[3];
 
@@ -3748,7 +3748,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
                        const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
 
                        /* calculate barycentric weights for hit point */
-                       interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord);
+                       interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
 
                        /* simple check based on brush surface velocity,
                         *  todo: perhaps implement something that handles volume movement as well */
index d21f43ac484a5981138ab4e5598eae8cd0e2305c..af02e02b017ec0f44db27aed5a1e691fe1ddfd25 100644 (file)
@@ -2346,6 +2346,11 @@ Mesh *BKE_mesh_new_from_object(
 
                                tmpmesh = BKE_mesh_add(bmain, "Mesh");
                                DM_to_mesh(dm, tmpmesh, ob, mask, true);
+
+                               /* Copy autosmooth settings from original mesh. */
+                               Mesh *me = (Mesh *)ob->data;
+                               tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
+                               tmpmesh->smoothresh = me->smoothresh;
                        }
 
                        /* BKE_mesh_add/copy gives us a user count we don't need */
index e8970d416e94f641bf0254c690e04ae921ace225..d0ef5cfc0928ef3939fb5b2f071a82a0b4fd7542 100644 (file)
@@ -758,15 +758,14 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
                        /* find the nearest point on the mesh */
                        if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) {
                                const MLoopTri *lt = &data->looptri[nearest.index];
-                               float weights[4];
+                               float weights[3];
                                int v1, v2, v3;
 
                                /* calculate barycentric weights for nearest point */
                                v1 = data->mloop[lt->tri[0]].v;
                                v2 = data->mloop[lt->tri[1]].v;
                                v3 = data->mloop[lt->tri[2]].v;
-                               interp_weights_face_v3(
-                                           weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, NULL, nearest.co);
+                               interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
 
                                // DG TODO
                                if (data->has_velocity)
@@ -1454,7 +1453,7 @@ static void sample_derivedmesh(
 
        /* find the nearest point on the mesh */
        if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
-               float weights[4];
+               float weights[3];
                int v1, v2, v3, f_index = nearest.index;
                float n1[3], n2[3], n3[3], hit_normal[3];
 
@@ -1471,7 +1470,7 @@ static void sample_derivedmesh(
                v1 = mloop[mlooptri[f_index].tri[0]].v;
                v2 = mloop[mlooptri[f_index].tri[1]].v;
                v3 = mloop[mlooptri[f_index].tri[2]].v;
-               interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
+               interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
 
                if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
                        /* apply normal directional velocity */
index b5007b29f4c3e7ecc59dab5e6664755e603f76bf..d33c2cb3279e92f41e6d0fc35174aa5beda8b9a2 100644 (file)
@@ -323,10 +323,8 @@ bool clip_segment_v3_plane_n(
         float r_p1[3], float r_p2[3]);
 
 /****************************** Interpolation ********************************/
-
-/* tri or quad, d can be NULL */
-void interp_weights_face_v3(float w[4],
-                            const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
+void interp_weights_tri_v3(float w[3], const float a[3], const float b[3], const float c[3], const float p[3]);
+void interp_weights_quad_v3(float w[4], const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
 void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
 void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
 
index 76dac5487f279b7131563b87258d047c1d4957ed..74ede1e7559920b4f0be5130af4d1866da93ec9b 100644 (file)
@@ -2950,7 +2950,15 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa
        }
 }
 
-void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
+void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
+{
+       float n[3];
+
+       normal_tri_v3(n, v1, v2, v3);
+       barycentric_weights(v1, v2, v3, co, n, w);
+}
+
+void interp_weights_quad_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3])
 {
        float w2[3];
 
@@ -2963,7 +2971,7 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
                w[1] = 1.0f;
        else if (equals_v3v3(co, v3))
                w[2] = 1.0f;
-       else if (v4 && equals_v3v3(co, v4))
+       else if (equals_v3v3(co, v4))
                w[3] = 1.0f;
        else {
                /* otherwise compute barycentric interpolation weights */
@@ -2971,35 +2979,24 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
                bool degenerate;
 
                sub_v3_v3v3(n1, v1, v3);
-               if (v4) {
-                       sub_v3_v3v3(n2, v2, v4);
-               }
-               else {
-                       sub_v3_v3v3(n2, v2, v3);
-               }
+               sub_v3_v3v3(n2, v2, v4);
                cross_v3_v3v3(n, n1, n2);
 
-               /* OpenGL seems to split this way, so we do too */
-               if (v4) {
-                       degenerate = barycentric_weights(v1, v2, v4, co, n, w);
-                       SWAP(float, w[2], w[3]);
-
-                       if (degenerate || (w[0] < 0.0f)) {
-                               /* if w[1] is negative, co is on the other side of the v1-v3 edge,
-                                * so we interpolate using the other triangle */
-                               degenerate = barycentric_weights(v2, v3, v4, co, n, w2);
-
-                               if (!degenerate) {
-                                       w[0] = 0.0f;
-                                       w[1] = w2[0];
-                                       w[2] = w2[1];
-                                       w[3] = w2[2];
-                               }
+               degenerate = barycentric_weights(v1, v2, v4, co, n, w);
+               SWAP(float, w[2], w[3]);
+
+               if (degenerate || (w[0] < 0.0f)) {
+                       /* if w[1] is negative, co is on the other side of the v1-v3 edge,
+                        * so we interpolate using the other triangle */
+                       degenerate = barycentric_weights(v2, v3, v4, co, n, w2);
+
+                       if (!degenerate) {
+                               w[0] = 0.0f;
+                               w[1] = w2[0];
+                               w[2] = w2[1];
+                               w[3] = w2[2];
                        }
                }
-               else {
-                       barycentric_weights(v1, v2, v3, co, n, w);
-               }
        }
 }
 
index 8dfbbdd02eb4aaed2effd3f7f6d58662dcfb4eeb..df6f098ee813cf05084bd1bb81baa179b5728ebb 100644 (file)
@@ -119,12 +119,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
                        else
                                but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL);
 
-                       PropertySubType subtype = RNA_property_subtype(prop);
-                       if (!(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME) || (block->flag & UI_BLOCK_LIST_ITEM))) {
-                               UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR);
-                       }
                        if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) {
-                               UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE);
+                               /* TEXTEDIT_UPDATE is usally used for search buttons. For these we also want
+                                * the 'x' icon to clear search string, so setting VALUE_CLEAR flag, too. */
+                               UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE | UI_BUT_VALUE_CLEAR);
                        }
                        break;
                case PROP_POINTER:
index 47f0220726bd345427f3c8083affff9c3ccb2c4b..84e98181dfb4233e68a8997600aaaa530db74e1f 100644 (file)
@@ -5693,11 +5693,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
        WM_operator_properties_create_ptr(&props_ptr, ot);
 
        if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
-               set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
-               RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail");
+               set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
+               RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
        }
        else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
-               set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
+               set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
                RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
        }
        else {
index 3243579f7d043cba241734b46f182a2ad9a5ad08..5355b8012dbf9919a0bd6eb44035688afaa83a21 100644 (file)
@@ -502,51 +502,57 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
 void nla_buttons_register(ARegionType *art)
 {
        PanelType *pt;
-       
+
        pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata");
        strcpy(pt->idname, "NLA_PT_animdata");
        strcpy(pt->label, N_("Animation Data"));
+       strcpy(pt->category, "Animations");
        strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
        pt->draw = nla_panel_animdata;
        pt->poll = nla_animdata_panel_poll;
        pt->flag = PNL_DEFAULT_CLOSED;
        BLI_addtail(&art->paneltypes, pt);
-       
+
        pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
        strcpy(pt->idname, "NLA_PT_track");
        strcpy(pt->label, N_("Active Track"));
+       strcpy(pt->category, "Animations");
        strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
        pt->draw = nla_panel_track;
        pt->poll = nla_track_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
-       
+
        pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
        strcpy(pt->idname, "NLA_PT_properties");
        strcpy(pt->label, N_("Active Strip"));
+       strcpy(pt->category, "Animations");
        strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
        pt->draw = nla_panel_properties;
        pt->poll = nla_strip_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
-       
+
        pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
        strcpy(pt->idname, "NLA_PT_actionclip");
        strcpy(pt->label, N_("Action Clip"));
+       strcpy(pt->category, "Animations");
        strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
        pt->draw = nla_panel_actclip;
        pt->poll = nla_strip_actclip_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
-       
+
        pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
        strcpy(pt->idname, "NLA_PT_evaluation");
        strcpy(pt->label, N_("Evaluation"));
+       strcpy(pt->category, "Animations");
        strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
        pt->draw = nla_panel_evaluation;
        pt->poll = nla_strip_eval_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
-       
+
        pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
        strcpy(pt->idname, "NLA_PT_modifiers");
        strcpy(pt->label, N_("Modifiers"));
+  strcpy(pt->category, "Modifiers");
        strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
        pt->draw = nla_panel_modifiers;
        pt->poll = nla_strip_eval_panel_poll;
index 054a2f795eef261ff2c6eb4417f077575d8bf135..50c8e25516296dfdda9186300fb84af13b5396df 100644 (file)
@@ -27,8 +27,7 @@ vec3 calculate_view_space_normal(in vec3 viewposition)
 {
        vec3 normal = cross(normalize(dFdx(viewposition)),
                            ssao_params.w * normalize(dFdy(viewposition)));
-       normalize(normal);
-       return normal;
+       return normalize(normal);
 }
 
 float calculate_ssao_factor(float depth)
index 1a191a68668e8095c29ded644e1ec5348d4d36f0..dee8df7d9330d99760ebd5885288cab5d9ace18f 100644 (file)
@@ -174,8 +174,10 @@ typedef enum PropertyFlag {
         * and collections */
        PROP_ANIMATABLE              = (1 << 1),
 
-       /* This flag means when the property's widget is in 'textedit' mode, it will be updated after every typed char,
-        * instead of waiting final validation. Used e.g. for text searchbox. */
+       /* This flag means when the property's widget is in 'textedit' mode, it will be updated
+        * after every typed char, instead of waiting final validation. Used e.g. for text searchbox.
+        * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag
+        * for search/filter properties, but this works just fine for now. */
        PROP_TEXTEDIT_UPDATE         = (1 << 31),
 
        /* icon */
index 4a078ef9182ac979b83fc11986afc736c505f8ce..cd48bc1a3df293367a356449fab0230a5cd1a499 100644 (file)
@@ -240,6 +240,9 @@ void RNA_api_mesh(StructRNA *srna)
        func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
        RNA_def_function_ui_description(func, "Free split vertex normals");
 
+       func = RNA_def_function(srna, "split_faces", "BKE_mesh_split_faces");
+       RNA_def_function_ui_description(func, "Spli faces based on the edge angle");
+
        func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents");
        RNA_def_function_flag(func, FUNC_USE_REPORTS);
        RNA_def_function_ui_description(func,
index 86961cdd169867ed23dc542f324872fea219c1e6..263ea3d4ef26676886a88bb6f58c81d5820a9e9c 100644 (file)
@@ -5569,12 +5569,17 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve
                                        /* interpolate speed vectors from strand surface */
                                        face= mesh->face[*index];
 
-                                       co1= mesh->co[face[0]];
-                                       co2= mesh->co[face[1]];
-                                       co3= mesh->co[face[2]];
-                                       co4= (face[3])? mesh->co[face[3]]: NULL;
+                                       co1 = mesh->co[face[0]];
+                                       co2 = mesh->co[face[1]];
+                                       co3 = mesh->co[face[2]];
 
-                                       interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co);
+                                       if (face[3]) {
+                                               co4 = mesh->co[face[3]];
+                                               interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
+                                       }
+                                       else {
+                                               interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
+                                       }
 
                                        zero_v4(speed);
                                        madd_v4_v4fl(speed, winspeed[face[0]], w[0]);
index ddcd2e8452059cf73b9d0a2e20d3dc5a2ce78be6..cd93898d8465dcc1a502162e08c81344b275ccb7 100644 (file)
@@ -1190,9 +1190,14 @@ static void sample_occ_surface(ShadeInput *shi)
                co1 = mesh->co[face[0]];
                co2 = mesh->co[face[1]];
                co3 = mesh->co[face[2]];
-               co4 = (face[3]) ? mesh->co[face[3]] : NULL;
 
-               interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co);
+               if (face[3]) {
+                       co4 = mesh->co[face[3]];
+                       interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
+               }
+               else {
+                       interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
+               }
 
                zero_v3(shi->ao);
                zero_v3(shi->env);
index 78b4b346f2440025a30744ffae3b1888275ae251..ae8848570f07343d0f051b07dff4bf492a4610ea 100755 (executable)
@@ -6,9 +6,46 @@ import os
 import shutil
 import subprocess
 import sys
+import time
 import tempfile
 
 
+class COLORS_ANSI:
+    RED = '\033[00;31m'
+    GREEN = '\033[00;32m'
+    ENDC = '\033[0m'
+
+
+class COLORS_DUMMY:
+    RED = ''
+    GREEN = ''
+    ENDC = ''
+
+COLORS = COLORS_DUMMY
+
+
+def printMessage(type, status, message):
+    if type == 'SUCCESS':
+        print(COLORS.GREEN, end="")
+    elif type == 'FAILURE':
+        print(COLORS.RED, end="")
+    status_text = ...
+    if status == 'RUN':
+        status_text = " RUN      "
+    elif status == 'OK':
+        status_text = "       OK "
+    elif status == 'PASSED':
+        status_text = "  PASSED  "
+    elif status == 'FAILED':
+        status_text = "  FAILED  "
+    else:
+        status_text = status
+    print("[{}]" . format(status_text), end="")
+    print(COLORS.ENDC, end="")
+    print(" {}" . format(message))
+    sys.stdout.flush()
+
+
 def render_file(filepath):
     command = (
         BLENDER,
@@ -83,16 +120,32 @@ def verify_output(filepath):
 def run_test(filepath):
     testname = test_get_name(filepath)
     spacer = "." * (32 - len(testname))
-    print(testname, spacer, end="")
-    sys.stdout.flush()
+    printMessage('SUCCESS', 'RUN', testname)
+    time_start = time.time()
     error = render_file(filepath)
+    status = "FAIL"
     if not error:
-        if verify_output(filepath):
-            print("PASS")
-        else:
+        if not verify_output(filepath):
             error = "VERIFY"
-    if error:
-        print("FAIL", error)
+    time_end = time.time()
+    elapsed_ms = int((time_end - time_start) * 1000)
+    if not error:
+        printMessage('SUCCESS', 'OK', "{} ({} ms)" .
+                     format(testname, elapsed_ms))
+    else:
+        if error == "NO_CYCLES":
+            print("Can't perform tests because Cycles failed to load!")
+            return False
+        elif error == "NO_START":
+            print('Can not perform tests because blender fails to start.',
+                  'Make sure INSTALL target was run.')
+            return False
+        elif error == 'VERIFY':
+            print("Rendered result is different from reference image")
+        else:
+            print("Unknown error %r" % error)
+        printMessage('FAILURE', 'FAILED', "{} ({} ms)" .
+                     format(testname, elapsed_ms))
     return error
 
 
@@ -105,30 +158,38 @@ def blend_list(path):
 
 
 def run_all_tests(dirpath):
+    passed_tests = []
     failed_tests = []
     all_files = list(blend_list(dirpath))
     all_files.sort()
+    printMessage('SUCCESS', "==========",
+                 "Running {} tests from 1 test case." . format(len(all_files)))
+    time_start = time.time()
     for filepath in all_files:
         error = run_test(filepath)
+        testname = test_get_name(filepath)
         if error:
             if error == "NO_CYCLES":
-                print("Can't perform tests because Cycles failed to load!")
                 return False
             elif error == "NO_START":
-                print('Can not perform tests because blender fails to start.',
-                      'Make sure INSTALL target was run.')
                 return False
-            elif error == 'VERIFY':
-                pass
-            else:
-                print("Unknown error %r" % error)
-            testname = test_get_name(filepath)
             failed_tests.append(testname)
+        else:
+            passed_tests.append(testname)
+    time_end = time.time()
+    elapsed_ms = int((time_end - time_start) * 1000)
+    print("")
+    printMessage('SUCCESS', "==========",
+                 "{} tests from 1 test case ran. ({} ms total)" .
+                 format(len(all_files), elapsed_ms))
+    printMessage('SUCCESS', 'PASSED', "{} tests." .
+                 format(len(passed_tests)))
     if failed_tests:
+        printMessage('FAILURE', 'FAILED', "{} tests, listed below:" .
+                     format(len(failed_tests)))
         failed_tests.sort()
-        print("\n\nFAILED tests:")
         for test in failed_tests:
-            print("   ", test)
+            printMessage('FAILURE', "FAILED", "{}" . format(test))
         return False
     return True
 
@@ -145,10 +206,14 @@ def main():
     parser = create_argparse()
     args = parser.parse_args()
 
+    global COLORS
     global BLENDER, ROOT, IDIFF
     global TEMP_FILE, TEMP_FILE_MASK, TEST_SCRIPT
     global VERBOSE
 
+    if os.environ.get("CYCLESTEST_COLOR") is not None:
+        COLORS = COLORS_ANSI
+
     BLENDER = args.blender[0]
     ROOT = args.testdir[0]
     IDIFF = args.idiff[0]