diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index acca6414852..a573fa1ce22 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -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" diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index fab03c7659b..66893d4d668 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -597,8 +597,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector& 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 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) diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 71c1eefe65f..21166b2f155 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -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 { diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index f17a61f0ac8..b67834cdea3 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -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); } } diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 26136a8e024..0648db3746d 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -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. diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 18ca1407ba0..ee25be36855 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -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; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index fce4620294d..1e8d0f0d767 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -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 */ diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index d21f43ac484..af02e02b017 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -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 */ diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index e8970d416e9..d0ef5cfc092 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -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 */ diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index b5007b29f4c..d33c2cb3279 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -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]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 76dac5487f2..74ede1e7559 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -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]); + 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)) { + /* 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]; - } + 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); - } } } diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 8dfbbdd02eb..df6f098ee81 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -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: diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 47f0220726b..84e98181dfb 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -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 { diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 3243579f7d0..5355b8012db 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -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; diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index 054a2f795ee..50c8e255162 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -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) diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 1a191a68668..dee8df7d933 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 4a078ef9182..cd48bc1a3df 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -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, diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 86961cdd169..263ea3d4ef2 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -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]); diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index ddcd2e84520..cd93898d846 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -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); diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 78b4b346f24..ae8848570f0 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -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]