diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2017-02-17 15:54:04 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2017-02-17 16:18:25 +0300 |
commit | a908e63590cf8579894642df095c64dbe3abed01 (patch) | |
tree | 3bbd3fbf583d49f094b193c7b4755de8a3fc510e | |
parent | a644f2b46c54259809bf2c88ee26465aa33e7b37 (diff) | |
parent | d41451a0ca5053885deffce2bf603fc6c488ddf4 (diff) |
Merge branch 'master' into cycles_split_kernel
119 files changed, 3148 insertions, 2162 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 092de982b9d..1cc3e02e03a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -445,6 +445,7 @@ option(WITH_BOOST "Enable features depending on boost" ON) # Unit testsing option(WITH_GTESTS "Enable GTest unit testing" OFF) +option(WITH_OPENGL_TESTS "Enable OpenGL related unit testing (Experimental)" OFF) # Documentation diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index 76d538ad578..860dd1174cf 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -72,10 +72,8 @@ if 'cmake' in builder: # Set up OSX architecture if builder.endswith('x86_64_10_6_cmake'): cmake_extra_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64') - cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda8-hack/bin/nvcc') cmake_extra_options.append('-DWITH_CODEC_QUICKTIME=OFF') cmake_extra_options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.6') - build_cubins = False elif builder.startswith('win'): diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index 9a5476772ab..dd9889c81ba 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -62,7 +62,7 @@ if(WITH_IK_ITASC) add_subdirectory(itasc) endif() -if(WITH_IK_SOLVER OR WITH_GAMEENGINE OR WITH_MOD_BOOLEAN) +if(WITH_GAMEENGINE) add_subdirectory(moto) endif() diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 79c1c3e3e82..31fa15a2042 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -74,6 +74,7 @@ elseif(CMAKE_COMPILER_IS_GNUCC) if(CXX_HAS_AVX2) set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c -mfpmath=sse") endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -fno-finite-math-only") elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") check_cxx_compiler_flag(-msse CXX_HAS_SSE) check_cxx_compiler_flag(-mavx CXX_HAS_AVX) @@ -89,6 +90,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CXX_HAS_AVX2) set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c") endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -fno-finite-math-only") endif() if(CXX_HAS_SSE) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 85117cfff7b..a1ff81e750a 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -27,6 +27,7 @@ #include "subd_patch.h" #include "subd_split.h" +#include "util_algorithm.h" #include "util_foreach.h" #include "util_logging.h" #include "util_math.h" @@ -525,69 +526,177 @@ static void attr_create_uv_map(Scene *scene, } /* Create vertex pointiness attributes. */ + +/* Compare vertices by sum of their coordinates. */ +class VertexAverageComparator { +public: + VertexAverageComparator(const array<float3>& verts) + : verts_(verts) { + } + + bool operator()(const int& vert_idx_a, const int& vert_idx_b) + { + const float3 &vert_a = verts_[vert_idx_a]; + const float3 &vert_b = verts_[vert_idx_b]; + if(vert_a == vert_b) { + /* Special case for doubles, so we ensure ordering. */ + return vert_idx_a > vert_idx_b; + } + const float x1 = vert_a.x + vert_a.y + vert_a.z; + const float x2 = vert_b.x + vert_b.y + vert_b.z; + return x1 < x2; + } + +protected: + const array<float3>& verts_; +}; + static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, bool subdivision) { - if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { - const int numverts = b_mesh.vertices.length(); - AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; - Attribute *attr = attributes.add(ATTR_STD_POINTINESS); - float *data = attr->data_float(); - int *counter = new int[numverts]; - float *raw_data = new float[numverts]; - float3 *edge_accum = new float3[numverts]; - - /* Calculate pointiness using single ring neighborhood. */ - memset(counter, 0, sizeof(int) * numverts); - memset(raw_data, 0, sizeof(float) * numverts); - memset(edge_accum, 0, sizeof(float3) * numverts); - BL::Mesh::edges_iterator e; - int i = 0; - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++i) { - int v0 = b_mesh.edges[i].vertices()[0], - v1 = b_mesh.edges[i].vertices()[1]; - float3 co0 = get_float3(b_mesh.vertices[v0].co()), - co1 = get_float3(b_mesh.vertices[v1].co()); - float3 edge = normalize(co1 - co0); - edge_accum[v0] += edge; - edge_accum[v1] += -edge; - ++counter[v0]; - ++counter[v1]; - } - i = 0; - BL::Mesh::vertices_iterator v; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i) { - if(counter[i] > 0) { - float3 normal = get_float3(b_mesh.vertices[i].normal()); - float angle = safe_acosf(dot(normal, edge_accum[i] / counter[i])); - raw_data[i] = angle * M_1_PI_F; + if(!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { + return; + } + const int num_verts = b_mesh.vertices.length(); + /* STEP 1: Find out duplicated vertices and point duplicates to a single + * original vertex. + */ + vector<int> sorted_vert_indeices(num_verts); + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + sorted_vert_indeices[vert_index] = vert_index; + } + VertexAverageComparator compare(mesh->verts); + sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare); + /* This array stores index of the original vertex for the given vertex + * index. + */ + vector<int> vert_orig_index(num_verts); + for(int sorted_vert_index = 0; + sorted_vert_index < num_verts; + ++sorted_vert_index) + { + const int vert_index = sorted_vert_indeices[sorted_vert_index]; + const float3 &vert_co = mesh->verts[vert_index]; + bool found = false; + for(int other_sorted_vert_index = sorted_vert_index + 1; + other_sorted_vert_index < num_verts; + ++other_sorted_vert_index) + { + const int other_vert_index = + sorted_vert_indeices[other_sorted_vert_index]; + const float3 &other_vert_co = mesh->verts[other_vert_index]; + /* We are too far away now, we wouldn't have duplicate. */ + if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) - + (vert_co.x + vert_co.y + vert_co.z) > 3 * FLT_EPSILON) + { + break; } - else { - raw_data[i] = 0.0f; + /* Found duplicate. */ + if(len_squared(other_vert_co - vert_co) < FLT_EPSILON) { + found = true; + vert_orig_index[vert_index] = other_vert_index; + break; } } - - /* Blur vertices to approximate 2 ring neighborhood. */ - memset(counter, 0, sizeof(int) * numverts); - memcpy(data, raw_data, sizeof(float) * numverts); - i = 0; - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++i) { - int v0 = b_mesh.edges[i].vertices()[0], - v1 = b_mesh.edges[i].vertices()[1]; - data[v0] += raw_data[v1]; - data[v1] += raw_data[v0]; - ++counter[v0]; - ++counter[v1]; + if(!found) { + vert_orig_index[vert_index] = vert_index; } - for(i = 0; i < numverts; ++i) { - data[i] /= counter[i] + 1; + } + /* Make sure we always points to the very first orig vertex. */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + int orig_index = vert_orig_index[vert_index]; + while(orig_index != vert_orig_index[orig_index]) { + orig_index = vert_orig_index[orig_index]; } - - delete [] counter; - delete [] raw_data; - delete [] edge_accum; + vert_orig_index[vert_index] = orig_index; + } + sorted_vert_indeices.free_memory(); + /* STEP 2: Calculate vertex normals taking into account their possible + * duplicates which gets "welded" together. + */ + vector<float3> vert_normal(num_verts, make_float3(0.0f, 0.0f, 0.0f)); + /* First we accumulate all vertex normals in the original index. */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const float3 normal = get_float3(b_mesh.vertices[vert_index].normal()); + const int orig_index = vert_orig_index[vert_index]; + vert_normal[orig_index] += normal; + } + /* Then we normalize the accumulated result and flush it to all duplicates + * as well. + */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + vert_normal[vert_index] = normalize(vert_normal[orig_index]); + } + /* STEP 3: Calculate pointiness using single ring neighborhood. */ + vector<int> counter(num_verts, 0); + vector<float> raw_data(num_verts, 0.0f); + vector<float3> edge_accum(num_verts, make_float3(0.0f, 0.0f, 0.0f)); + BL::Mesh::edges_iterator e; + EdgeMap visited_edges; + int edge_index = 0; + memset(&counter[0], 0, sizeof(int) * counter.size()); + for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { + const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], + v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; + if(visited_edges.exists(v0, v1)) { + continue; + } + visited_edges.insert(v0, v1); + float3 co0 = get_float3(b_mesh.vertices[v0].co()), + co1 = get_float3(b_mesh.vertices[v1].co()); + float3 edge = normalize(co1 - co0); + edge_accum[v0] += edge; + edge_accum[v1] += -edge; + ++counter[v0]; + ++counter[v1]; + } + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + if(orig_index != vert_index) { + /* Skip duplicates, they'll be overwritten later on. */ + continue; + } + if(counter[vert_index] > 0) { + const float3 normal = vert_normal[vert_index]; + const float angle = + safe_acosf(dot(normal, + edge_accum[vert_index] / counter[vert_index])); + raw_data[vert_index] = angle * M_1_PI_F; + } + else { + raw_data[vert_index] = 0.0f; + } + } + /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */ + AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; + Attribute *attr = attributes.add(ATTR_STD_POINTINESS); + float *data = attr->data_float(); + memcpy(data, &raw_data[0], sizeof(float) * raw_data.size()); + memset(&counter[0], 0, sizeof(int) * counter.size()); + edge_index = 0; + visited_edges.clear(); + for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { + const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], + v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; + if(visited_edges.exists(v0, v1)) { + continue; + } + visited_edges.insert(v0, v1); + data[v0] += raw_data[v1]; + data[v1] += raw_data[v0]; + ++counter[v0]; + ++counter[v1]; + } + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + data[vert_index] /= counter[vert_index] + 1; + } + /* STEP 4: Copy attribute to the duplicated vertices. */ + for(int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + data[vert_index] = data[orig_index]; } } @@ -656,9 +765,6 @@ static void create_mesh(Scene *scene, generated[i++] = get_float3(v->undeformed_co())*size - loc; } - /* Create needed vertex attributes. */ - attr_create_pointiness(scene, mesh, b_mesh, subdivision); - /* create faces */ vector<int> nverts(numfaces); vector<int> face_flags(numfaces, FACE_FLAG_NONE); @@ -718,6 +824,7 @@ static void create_mesh(Scene *scene, /* Create all needed attributes. * The calculate functions will check whether they're needed or not. */ + attr_create_pointiness(scene, mesh, b_mesh, subdivision); attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision); attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs); @@ -1178,4 +1285,3 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, } CCL_NAMESPACE_END - diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index f6ec015e1b8..8baa53fc2ec 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -609,7 +609,8 @@ static ShaderNode *add_node(Scene *scene, bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED || b_image.source() == BL::Image::source_MOVIE || - b_engine.is_preview(); + (b_engine.is_preview() && + b_image.source() != BL::Image::source_SEQUENCE); if(is_builtin) { /* for builtin images we're using image datablock name to find an image to @@ -662,7 +663,8 @@ static ShaderNode *add_node(Scene *scene, bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED || b_image.source() == BL::Image::source_MOVIE || - b_engine.is_preview(); + (b_engine.is_preview() && + b_image.source() != BL::Image::source_SEQUENCE); if(is_builtin) { int scene_frame = b_scene.frame_current(); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index b67834cdea3..4411181dbcc 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -19,6 +19,7 @@ #include "mesh.h" +#include "util_algorithm.h" #include "util_map.h" #include "util_path.h" #include "util_set.h" @@ -79,6 +80,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, } else { me.split_faces(); + me.calc_normals_split(); } } if(subdivision_type == Mesh::SUBDIVISION_NONE) { @@ -786,6 +788,35 @@ struct ParticleSystemKey { } }; +class EdgeMap { +public: + EdgeMap() { + } + + void clear() { + edges_.clear(); + } + + void insert(int v0, int v1) { + get_sorted_verts(v0, v1); + edges_.insert(std::pair<int, int>(v0, v1)); + } + + bool exists(int v0, int v1) { + get_sorted_verts(v0, v1); + return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end(); + } + +protected: + void get_sorted_verts(int& v0, int& v1) { + if(v0 > v1) { + swap(v0, v1); + } + } + + set< std::pair<int, int> > edges_; +}; + CCL_NAMESPACE_END #endif /* __BLENDER_UTIL_H__ */ diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 874a4246d1d..1fb2f371a0f 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -81,6 +81,7 @@ void BVH::build(Progress& progress) pack.prim_type, pack.prim_index, pack.prim_object, + pack.prim_time, params, progress); BVHNode *root = bvh_build.run(); @@ -256,6 +257,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) pack.leaf_nodes.resize(leaf_nodes_size); pack.object_node.resize(objects.size()); + if(params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) { + pack.prim_time.resize(prim_index_size); + } + int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL; int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL; int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL; @@ -264,6 +269,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL; int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL; int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL; + float2 *pack_prim_time = (pack.prim_time.size())? &pack.prim_time[0]: NULL; /* merge */ foreach(Object *ob, objects) { @@ -309,6 +315,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) int *bvh_prim_type = &bvh->pack.prim_type[0]; uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0]; uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0]; + float2 *bvh_prim_time = bvh->pack.prim_time.size()? &bvh->pack.prim_time[0]: NULL; for(size_t i = 0; i < bvh_prim_index_size; i++) { if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { @@ -324,6 +331,9 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i]; pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i]; pack_prim_object[pack_prim_index_offset] = 0; // unused for instances + if(bvh_prim_time != NULL) { + pack_prim_time[pack_prim_index_offset] = bvh_prim_time[i]; + } pack_prim_index_offset++; } } diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index 35f4d305883..08f41fc736f 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -68,6 +68,8 @@ struct PackedBVH { array<int> prim_index; /* mapping from BVH primitive index, to the object id of that primitive. */ array<int> prim_object; + /* Time range of BVH primitive. */ + array<float2> prim_time; /* index of the root node. */ int root_index; diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index a2f8b33cb0b..fcbc50f4f6f 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -93,12 +93,14 @@ BVHBuild::BVHBuild(const vector<Object*>& objects_, array<int>& prim_type_, array<int>& prim_index_, array<int>& prim_object_, + array<float2>& prim_time_, const BVHParams& params_, Progress& progress_) : objects(objects_), prim_type(prim_type_), prim_index(prim_index_), prim_object(prim_object_), + prim_time(prim_time_), params(params_), progress(progress_), progress_start_time(0.0), @@ -465,6 +467,9 @@ BVHNode* BVHBuild::run() } spatial_free_index = 0; + need_prim_time = params.num_motion_curve_steps > 0 || + params.num_motion_triangle_steps > 0; + /* init progress updates */ double build_start_time; build_start_time = progress_start_time = time_dt(); @@ -475,6 +480,12 @@ BVHNode* BVHBuild::run() prim_type.resize(references.size()); prim_index.resize(references.size()); prim_object.resize(references.size()); + if(need_prim_time) { + prim_time.resize(references.size()); + } + else { + prim_time.resize(0); + } /* build recursively */ BVHNode *rootnode; @@ -849,6 +860,9 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, prim_type[start] = ref->prim_type(); prim_index[start] = ref->prim_index(); prim_object[start] = ref->prim_object(); + if(need_prim_time) { + prim_time[start] = make_float2(ref->time_from(), ref->time_to()); + } uint visibility = objects[ref->prim_object()]->visibility; BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start+1); @@ -896,6 +910,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL]; vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL]; vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL]; + vector<float2, LeafStackAllocator> p_time[PRIMITIVE_NUM_TOTAL]; vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL]; /* TODO(sergey): In theory we should be able to store references. */ @@ -918,6 +933,8 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, p_type[type_index].push_back(ref.prim_type()); p_index[type_index].push_back(ref.prim_index()); p_object[type_index].push_back(ref.prim_object()); + p_time[type_index].push_back(make_float2(ref.time_from(), + ref.time_to())); bounds[type_index].grow(ref.bounds()); visibility[type_index] |= objects[ref.prim_object()]->visibility; @@ -947,9 +964,13 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, vector<int, LeafStackAllocator> local_prim_type, local_prim_index, local_prim_object; + vector<float2, LeafStackAllocator> local_prim_time; local_prim_type.resize(num_new_prims); local_prim_index.resize(num_new_prims); local_prim_object.resize(num_new_prims); + if(need_prim_time) { + local_prim_time.resize(num_new_prims); + } for(int i = 0; i < PRIMITIVE_NUM_TOTAL; ++i) { int num = (int)p_type[i].size(); if(num != 0) { @@ -962,6 +983,9 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, local_prim_type[index] = p_type[i][j]; local_prim_index[index] = p_index[i][j]; local_prim_object[index] = p_object[i][j]; + if(need_prim_time) { + local_prim_time[index] = p_time[i][j]; + } if(params.use_unaligned_nodes && !alignment_found) { alignment_found = unaligned_heuristic.compute_aligned_space(p_ref[i][j], @@ -1028,11 +1052,17 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, prim_type.reserve(reserve); prim_index.reserve(reserve); prim_object.reserve(reserve); + if(need_prim_time) { + prim_time.reserve(reserve); + } } prim_type.resize(range_end); prim_index.resize(range_end); prim_object.resize(range_end); + if(need_prim_time) { + prim_time.resize(range_end); + } } spatial_spin_lock.unlock(); @@ -1041,6 +1071,9 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size); memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size); memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size); + if(need_prim_time) { + memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2)*num_new_leaf_data); + } } } else { @@ -1053,6 +1086,9 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size); memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size); memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size); + if(need_prim_time) { + memcpy(&prim_time[start_index], &local_prim_time[0], sizeof(float2)*num_new_leaf_data); + } } } diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index ee3cde66a2f..430efc3e0f6 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -48,6 +48,7 @@ public: array<int>& prim_type, array<int>& prim_index, array<int>& prim_object, + array<float2>& prim_time, const BVHParams& params, Progress& progress); ~BVHBuild(); @@ -112,6 +113,9 @@ protected: array<int>& prim_type; array<int>& prim_index; array<int>& prim_object; + array<float2>& prim_time; + + bool need_prim_time; /* Build parameters. */ BVHParams params; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 65f9da1c194..7b309504728 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -104,6 +104,7 @@ public: primitive_mask = PRIMITIVE_ALL; num_motion_curve_steps = 0; + num_motion_triangle_steps = 0; } /* SAH costs */ diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 36798982653..321983c1abc 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -357,7 +357,7 @@ ccl_device_inline float3 ray_offset(float3 P, float3 Ng) #endif } -#if defined(__SHADOW_RECORD_ALL__) || defined (__VOLUME_RECORD_ALL__) +#if defined(__VOLUME_RECORD_ALL__) || (defined(__SHADOW_RECORD_ALL__) && defined(__KERNEL_CPU__)) /* ToDo: Move to another file? */ ccl_device int intersections_compare(const void *a, const void *b) { @@ -373,5 +373,28 @@ ccl_device int intersections_compare(const void *a, const void *b) } #endif -CCL_NAMESPACE_END +#if defined(__SHADOW_RECORD_ALL__) +ccl_device_inline void sort_intersections(Intersection *hits, uint num_hits) +{ +#ifdef __KERNEL_GPU__ + /* Use bubble sort which has more friendly memory pattern on GPU. */ + bool swapped; + do { + swapped = false; + for(int j = 0; j < num_hits - 1; ++j) { + if(hits[j].t > hits[j + 1].t) { + struct Intersection tmp = hits[j]; + hits[j] = hits[j + 1]; + hits[j + 1] = tmp; + swapped = true; + } + } + --num_hits; + } while(swapped); +#else + qsort(hits, num_hits, sizeof(Intersection), intersections_compare); +#endif +} +#endif /* __SHADOW_RECORD_ALL__ | __VOLUME_RECORD_ALL__ */ +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 9de335403ce..712b67a1b55 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -229,6 +229,15 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte float3 P, float3 dir, uint visibility, int object, int curveAddr, float time,int type, uint *lcg_state, float difl, float extmax) #endif { + const bool is_curve_primitive = (type & PRIMITIVE_CURVE); + + if(!is_curve_primitive && kernel_data.bvh.use_bvh_steps) { + const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr); + if(time < prim_time.x || time > prim_time.y) { + return false; + } + } + int segment = PRIMITIVE_UNPACK_SEGMENT(type); float epsilon = 0.0f; float r_st, r_en; @@ -257,7 +266,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte #ifdef __KERNEL_AVX2__ avxf P_curve_0_1, P_curve_2_3; - if(type & PRIMITIVE_CURVE) { + if(is_curve_primitive) { P_curve_0_1 = _mm256_loadu2_m128(&kg->__curve_keys.data[k0].x, &kg->__curve_keys.data[ka].x); P_curve_2_3 = _mm256_loadu2_m128(&kg->__curve_keys.data[kb].x, &kg->__curve_keys.data[k1].x); } @@ -268,7 +277,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte #else /* __KERNEL_AVX2__ */ ssef P_curve[4]; - if(type & PRIMITIVE_CURVE) { + if(is_curve_primitive) { P_curve[0] = load4f(&kg->__curve_keys.data[ka].x); P_curve[1] = load4f(&kg->__curve_keys.data[k0].x); P_curve[2] = load4f(&kg->__curve_keys.data[k1].x); @@ -363,7 +372,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte float4 P_curve[4]; - if(type & PRIMITIVE_CURVE) { + if(is_curve_primitive) { P_curve[0] = kernel_tex_fetch(__curve_keys, ka); P_curve[1] = kernel_tex_fetch(__curve_keys, k0); P_curve[2] = kernel_tex_fetch(__curve_keys, k1); @@ -689,6 +698,15 @@ ccl_device_forceinline bool bvh_curve_intersect(KernelGlobals *kg, Intersection # define dot3(x, y) dot(x, y) #endif + const bool is_curve_primitive = (type & PRIMITIVE_CURVE); + + if(!is_curve_primitive && kernel_data.bvh.use_bvh_steps) { + const float2 prim_time = kernel_tex_fetch(__prim_time, curveAddr); + if(time < prim_time.x || time > prim_time.y) { + return false; + } + } + int segment = PRIMITIVE_UNPACK_SEGMENT(type); /* curve Intersection check */ int flags = kernel_data.curve.curveflags; @@ -703,7 +721,7 @@ ccl_device_forceinline bool bvh_curve_intersect(KernelGlobals *kg, Intersection #ifndef __KERNEL_SSE2__ float4 P_curve[2]; - if(type & PRIMITIVE_CURVE) { + if(is_curve_primitive) { P_curve[0] = kernel_tex_fetch(__curve_keys, k0); P_curve[1] = kernel_tex_fetch(__curve_keys, k1); } @@ -738,7 +756,7 @@ ccl_device_forceinline bool bvh_curve_intersect(KernelGlobals *kg, Intersection #else ssef P_curve[2]; - if(type & PRIMITIVE_CURVE) { + if(is_curve_primitive) { P_curve[0] = load4f(&kg->__curve_keys.data[k0].x); P_curve[1] = load4f(&kg->__curve_keys.data[k1].x); } diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index a0ee4970613..5dbea4481a3 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -83,7 +83,10 @@ typedef struct KernelGlobals { #ifdef __KERNEL_CUDA__ __constant__ KernelData __data; -typedef struct KernelGlobals {} KernelGlobals; +typedef struct KernelGlobals { + /* NOTE: Keep the size in sync with SHADOW_STACK_MAX_HITS. */ + Intersection hits_stack[64]; +} KernelGlobals; # ifdef __KERNEL_CUDA_TEX_STORAGE__ # define KERNEL_TEX(type, ttype, name) ttype name; diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 84b5fd254ca..6abfa9c3873 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -16,9 +16,84 @@ CCL_NAMESPACE_BEGIN -#ifdef __SHADOW_RECORD_ALL__ +/* Attenuate throughput accordingly to the given intersection event. + * Returns true if the throughput is zero and traversal can be aborted. + */ +ccl_device_forceinline bool shadow_handle_transparent_isect( + KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, +# ifdef __VOLUME__ + struct PathState *volume_state, +# endif + Intersection *isect, + Ray *ray, + float3 *throughput) +{ +#ifdef __VOLUME__ + /* Attenuation between last surface and next surface. */ + if(volume_state->volume_stack[0].shader != SHADER_NONE) { + Ray segment_ray = *ray; + segment_ray.t = isect->t; + kernel_volume_shadow(kg, + shadow_sd, + volume_state, + &segment_ray, + throughput); + } +#endif + /* Setup shader data at surface. */ + shader_setup_from_ray(kg, shadow_sd, isect, ray); + /* Attenuation from transparent surface. */ + if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { + path_state_modify_bounce(state, true); + shader_eval_surface(kg, + shadow_sd, + NULL, + state, + 0.0f, + PATH_RAY_SHADOW, + SHADER_CONTEXT_SHADOW); + path_state_modify_bounce(state, false); + *throughput *= shader_bsdf_transparency(kg, shadow_sd); + } + /* Stop if all light is blocked. */ + if(is_zero(*throughput)) { + return true; + } +#ifdef __VOLUME__ + /* Exit/enter volume. */ + kernel_volume_stack_enter_exit(kg, shadow_sd, volume_state->volume_stack); +#endif + return false; +} + +/* Special version which only handles opaque shadows. */ +ccl_device bool shadow_blocked_opaque(KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + Ray *ray, + Intersection *isect, + float3 *shadow) +{ + const bool blocked = scene_intersect(kg, + *ray, + PATH_RAY_SHADOW_OPAQUE, + isect, + NULL, + 0.0f, 0.0f); +#ifdef __VOLUME__ + if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { + /* Apply attenuation from current volume shader. */ + kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); + } +#endif + return blocked; +} -/* Shadow function to compute how much light is blocked, CPU variation. +#ifdef __TRANSPARENT_SHADOWS__ +# ifdef __SHADOW_RECORD_ALL__ +/* Shadow function to compute how much light is blocked, * * We trace a single ray. If it hits any opaque surface, or more than a given * number of transparent surfaces is hit, then we consider the geometry to be @@ -36,261 +111,355 @@ CCL_NAMESPACE_BEGIN * or there is a performance increase anyway due to avoiding the need to send * two rays with transparent shadows. * - * This is CPU only because of qsort, and malloc or high stack space usage to - * record all these intersections. */ + * On CPU it'll handle all transparent bounces (by allocating storage for + * intersections when they don't fit into the stack storage). + * + * On GPU it'll only handle SHADOW_STACK_MAX_HITS-1 intersections, so this + * is something to be kept an eye on. + */ -#define STACK_MAX_HITS 64 +# define SHADOW_STACK_MAX_HITS 64 -ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, PathState *state, Ray *ray, float3 *shadow) +/* Actual logic with traversal loop implementation which is free from device + * specific tweaks. + * + * Note that hits array should be as big as max_hits+1. + */ +ccl_device bool shadow_blocked_transparent_all_loop(KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + Ray *ray, + Intersection *hits, + uint max_hits, + float3 *shadow) { - *shadow = make_float3(1.0f, 1.0f, 1.0f); - - if(ray->t == 0.0f) - return false; - - bool blocked; - - if(kernel_data.integrator.transparent_shadows) { - /* check transparent bounces here, for volume scatter which can do - * lighting before surface path termination is checked */ - if(state->transparent_bounce >= kernel_data.integrator.transparent_max_bounce) - return true; - - /* intersect to find an opaque surface, or record all transparent surface hits */ - Intersection hits_stack[STACK_MAX_HITS]; - Intersection *hits = hits_stack; - const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce; - uint max_hits = transparent_max_bounce - state->transparent_bounce - 1; - - /* prefer to use stack but use dynamic allocation if too deep max hits - * we need max_hits + 1 storage space due to the logic in - * scene_intersect_shadow_all which will first store and then check if - * the limit is exceeded */ - if(max_hits + 1 > STACK_MAX_HITS) { - if(kg->transparent_shadow_intersections == NULL) { - kg->transparent_shadow_intersections = - (Intersection*)malloc(sizeof(Intersection)*(transparent_max_bounce + 1)); + /* Intersect to find an opaque surface, or record all transparent + * surface hits. + */ + uint num_hits; + const bool blocked = scene_intersect_shadow_all(kg, + ray, + hits, + max_hits, + &num_hits); + /* If no opaque surface found but we did find transparent hits, + * shade them. + */ + if(!blocked && num_hits > 0) { + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 Pend = ray->P + ray->D*ray->t; + float last_t = 0.0f; + int bounce = state->transparent_bounce; + Intersection *isect = hits; +# ifdef __VOLUME__ + PathState ps = *state; +# endif + sort_intersections(hits, num_hits); + for(int hit = 0; hit < num_hits; hit++, isect++) { + /* Adjust intersection distance for moving ray forward. */ + float new_t = isect->t; + isect->t -= last_t; + /* Skip hit if we did not move forward, step by step raytracing + * would have skipped it as well then. + */ + if(last_t == new_t) { + continue; } - hits = kg->transparent_shadow_intersections; - } - - uint num_hits; - blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits); - - /* if no opaque surface found but we did find transparent hits, shade them */ - if(!blocked && num_hits > 0) { - float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - float3 Pend = ray->P + ray->D*ray->t; - float last_t = 0.0f; - int bounce = state->transparent_bounce; - Intersection *isect = hits; + last_t = new_t; + /* Attenuate the throughput. */ + if(shadow_handle_transparent_isect(kg, + shadow_sd, + state, #ifdef __VOLUME__ - PathState ps = *state; + &ps, #endif - - qsort(hits, num_hits, sizeof(Intersection), intersections_compare); - - for(int hit = 0; hit < num_hits; hit++, isect++) { - /* adjust intersection distance for moving ray forward */ - float new_t = isect->t; - isect->t -= last_t; - - /* skip hit if we did not move forward, step by step raytracing - * would have skipped it as well then */ - if(last_t == new_t) - continue; - - last_t = new_t; - -#ifdef __VOLUME__ - /* attenuation between last surface and next surface */ - if(ps.volume_stack[0].shader != SHADER_NONE) { - Ray segment_ray = *ray; - segment_ray.t = isect->t; - kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput); - } -#endif - - /* setup shader data at surface */ - shader_setup_from_ray(kg, shadow_sd, isect, ray); - - /* attenuation from transparent surface */ - if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) { - path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); - path_state_modify_bounce(state, false); - - throughput *= shader_bsdf_transparency(kg, shadow_sd); - } - - /* stop if all light is blocked */ - if(is_zero(throughput)) { - return true; - } - - /* move ray forward */ - ray->P = shadow_sd->P; - if(ray->t != FLT_MAX) { - ray->D = normalize_len(Pend - ray->P, &ray->t); - } - -#ifdef __VOLUME__ - /* exit/enter volume */ - kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack); -#endif - - bounce++; + isect, + ray, + &throughput)) + { + return true; } - -#ifdef __VOLUME__ - /* attenuation for last line segment towards light */ - if(ps.volume_stack[0].shader != SHADER_NONE) - kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); -#endif - - *shadow = throughput; - - return is_zero(throughput); + /* Move ray forward. */ + ray->P = ccl_fetch(shadow_sd, P); + if(ray->t != FLT_MAX) { + ray->D = normalize_len(Pend - ray->P, &ray->t); + } + bounce++; } +# ifdef __VOLUME__ + /* Attenuation for last line segment towards light. */ + if(ps.volume_stack[0].shader != SHADER_NONE) { + kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); + } +# endif + *shadow = throughput; + return is_zero(throughput); } - else { - Intersection isect; - blocked = scene_intersect(kg, *ray, PATH_RAY_SHADOW_OPAQUE, &isect, NULL, 0.0f, 0.0f); - } - -#ifdef __VOLUME__ +# ifdef __VOLUME__ if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { - /* apply attenuation from current volume shader */ + /* Apply attenuation from current volume shader/ */ kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); } -#endif - +# endif return blocked; } -#undef STACK_MAX_HITS - -#else +/* Here we do all device specific trickery before invoking actual traversal + * loop to help readability of the actual logic. + */ +ccl_device bool shadow_blocked_transparent_all(KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + Ray *ray, + uint max_hits, + float3 *shadow) +{ +# ifdef __KERNEL_CUDA__ + Intersection *hits = kg->hits_stack; +# else + Intersection hits_stack[SHADOW_STACK_MAX_HITS]; + Intersection *hits = hits_stack; +# endif +# ifndef __KERNEL_GPU__ + /* Prefer to use stack but use dynamic allocation if too deep max hits + * we need max_hits + 1 storage space due to the logic in + * scene_intersect_shadow_all which will first store and then check if + * the limit is exceeded. + * + * Ignore this on GPU because of slow/unavailable malloc(). + */ + if(max_hits + 1 > SHADOW_STACK_MAX_HITS) { + if(kg->transparent_shadow_intersections == NULL) { + const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce; + kg->transparent_shadow_intersections = + (Intersection*)malloc(sizeof(Intersection)*(transparent_max_bounce + 1)); + } + hits = kg->transparent_shadow_intersections; + } +# endif /* __KERNEL_GPU__ */ + /* Invoke actual traversal. */ + return shadow_blocked_transparent_all_loop(kg, + shadow_sd, + state, + ray, + hits, + max_hits, + shadow); +} +# endif /* __SHADOW_RECORD_ALL__ */ -/* Shadow function to compute how much light is blocked, GPU variation. +# if defined(__KERNEL_GPU__) || !defined(__SHADOW_RECORD_ALL__) +/* Shadow function to compute how much light is blocked, * * Here we raytrace from one transparent surface to the next step by step. * To minimize overhead in cases where we don't need transparent shadows, we * first trace a regular shadow ray. We check if the hit primitive was * potentially transparent, and only in that case start marching. this gives - * one extra ray cast for the cases were we do want transparency. */ + * one extra ray cast for the cases were we do want transparency. + */ -ccl_device_noinline bool shadow_blocked(KernelGlobals *kg, - ShaderData *shadow_sd, - ccl_addr_space PathState *state, - ccl_addr_space Ray *ray_input, - float3 *shadow) +/* This function is only implementing device-independent traversal logic + * which requires some precalculation done. + */ +ccl_device bool shadow_blocked_transparent_stepped_loop( + KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + Ray *ray, + Intersection *isect, + const bool blocked, + const bool is_transparent_isect, + float3 *shadow) { - *shadow = make_float3(1.0f, 1.0f, 1.0f); + if(blocked && is_transparent_isect) { + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 Pend = ray->P + ray->D*ray->t; + int bounce = state->transparent_bounce; +# ifdef __VOLUME__ + PathState ps = *state; +# endif + for(;;) { + if(bounce >= kernel_data.integrator.transparent_max_bounce) { + return true; + } + if(!scene_intersect(kg, + *ray, + PATH_RAY_SHADOW_TRANSPARENT, + isect, + NULL, + 0.0f, 0.0f)) + { + break; + } + if(!shader_transparent_shadow(kg, isect)) { + return true; + } + /* Attenuate the throughput. */ + if(shadow_handle_transparent_isect(kg, + shadow_sd, + state, +#ifdef __VOLUME__ + &ps, +#endif + isect, + ray, + &throughput)) + { + return true; + } + /* Move ray forward. */ + ray->P = ray_offset(ccl_fetch(shadow_sd, P), -ccl_fetch(shadow_sd, Ng)); + if(ray->t != FLT_MAX) { + ray->D = normalize_len(Pend - ray->P, &ray->t); + } + bounce++; + } +# ifdef __VOLUME__ + /* Attenuation for last line segment towards light. */ + if(ps.volume_stack[0].shader != SHADER_NONE) { + kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); + } +# endif + *shadow *= throughput; + return is_zero(throughput); + } +# ifdef __VOLUME__ + if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { + /* Apply attenuation from current volume shader. */ + kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); + } +# endif + return blocked; +} - if(ray_input->t == 0.0f) - return false; +ccl_device bool shadow_blocked_transparent_stepped( + KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + Ray *ray, + Intersection *isect, + float3 *shadow) +{ + const bool blocked = scene_intersect(kg, + *ray, + PATH_RAY_SHADOW_OPAQUE, + isect, + NULL, + 0.0f, 0.0f); + const bool is_transparent_isect = blocked + ? shader_transparent_shadow(kg, isect) + : false; + return shadow_blocked_transparent_stepped_loop(kg, + shadow_sd, + state, + ray, + isect, + blocked, + is_transparent_isect, + shadow); +} +# endif /* __KERNEL_GPU__ || !__SHADOW_RECORD_ALL__ */ +#endif /* __TRANSPARENT_SHADOWS__ */ + +ccl_device_inline bool shadow_blocked(KernelGlobals *kg, + ShaderData *shadow_sd, + ccl_addr_space PathState *state, + ccl_addr_space Ray *ray_input, + float3 *shadow) +{ + /* Special trickery for split kernel: some data is coming from the + * global memory. + */ #ifdef __SPLIT_KERNEL__ Ray private_ray = *ray_input; Ray *ray = &private_ray; -#else - Ray *ray = ray_input; -#endif - -#ifdef __SPLIT_KERNEL__ Intersection *isect = &kernel_split_state.isect_shadow[SD_THREAD]; -#else +#else /* __SPLIT_KERNEL__ */ + Ray *ray = ray_input; Intersection isect_object; Intersection *isect = &isect_object; -#endif - - bool blocked = scene_intersect(kg, *ray, PATH_RAY_SHADOW_OPAQUE, isect, NULL, 0.0f, 0.0f); - +#endif /* __SPLIT_KERNEL__ */ + /* Some common early checks. */ + *shadow = make_float3(1.0f, 1.0f, 1.0f); + if(ray->t == 0.0f) { + return false; + } + /* Do actual shadow shading. */ + /* First of all, we check if integrator requires transparent shadows. + * if not, we use simplest and fastest ever way to calculate occlusion. + */ #ifdef __TRANSPARENT_SHADOWS__ - if(blocked && kernel_data.integrator.transparent_shadows) { - if(shader_transparent_shadow(kg, isect)) { - float3 throughput = make_float3(1.0f, 1.0f, 1.0f); - float3 Pend = ray->P + ray->D*ray->t; - int bounce = state->transparent_bounce; -#ifdef __VOLUME__ - PathState ps = *state; + if(!kernel_data.integrator.transparent_shadows) #endif - - for(;;) { - if(bounce >= kernel_data.integrator.transparent_max_bounce) - return true; - - if(!scene_intersect(kg, *ray, PATH_RAY_SHADOW_TRANSPARENT, isect, NULL, 0.0f, 0.0f)) - { -#ifdef __VOLUME__ - /* attenuation for last line segment towards light */ - if(ps.volume_stack[0].shader != SHADER_NONE) - kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput); -#endif - - *shadow *= throughput; - - return false; - } - - if(!shader_transparent_shadow(kg, isect)) { - return true; - } - -#ifdef __VOLUME__ - /* attenuation between last surface and next surface */ - if(ps.volume_stack[0].shader != SHADER_NONE) { - Ray segment_ray = *ray; - segment_ray.t = isect->t; - kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput); - } -#endif - - /* setup shader data at surface */ - shader_setup_from_ray(kg, shadow_sd, isect, ray); - - /* attenuation from transparent surface */ - if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { - path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); - path_state_modify_bounce(state, false); - - throughput *= shader_bsdf_transparency(kg, shadow_sd); - } - - /* stop if all light is blocked */ - if(is_zero(throughput)) { - return true; - } - - /* move ray forward */ - ray->P = ray_offset(ccl_fetch(shadow_sd, P), -ccl_fetch(shadow_sd, Ng)); - if(ray->t != FLT_MAX) { - ray->D = normalize_len(Pend - ray->P, &ray->t); - } - -#ifdef __VOLUME__ - /* exit/enter volume */ - kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack); -#endif - - bounce++; - } - } + { + return shadow_blocked_opaque(kg, + shadow_sd, + state, + ray, + isect, + shadow); } -#ifdef __VOLUME__ - else if(!blocked && state->volume_stack[0].shader != SHADER_NONE) { - /* apply attenuation from current volume shader */ - kernel_volume_shadow(kg, shadow_sd, state, ray, shadow); +#ifdef __TRANSPARENT_SHADOWS__ +# ifdef __SHADOW_RECORD_ALL__ + /* For the transparent shadows we try to use record-all logic on the + * devices which supports this. + */ + const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce; + /* Check transparent bounces here, for volume scatter which can do + * lighting before surface path termination is checked. + */ + if(state->transparent_bounce >= transparent_max_bounce) { + return true; } -#endif -#endif - - return blocked; + const uint max_hits = transparent_max_bounce - state->transparent_bounce - 1; +# ifdef __KERNEL_GPU__ + /* On GPU we do trickey with tracing opaque ray first, this avoids speed + * regressions in some files. + * + * TODO(sergey): Check why using record-all behavior causes slowdown in such + * cases. Could that be caused by a higher spill pressure? + */ + const bool blocked = scene_intersect(kg, + *ray, + PATH_RAY_SHADOW_OPAQUE, + isect, + NULL, + 0.0f, 0.0f); + const bool is_transparent_isect = blocked + ? shader_transparent_shadow(kg, isect) + : false; + if(!blocked || !is_transparent_isect || + max_hits + 1 >= SHADOW_STACK_MAX_HITS) + { + return shadow_blocked_transparent_stepped_loop(kg, + shadow_sd, + state, + ray, + isect, + blocked, + is_transparent_isect, + shadow); + } +# endif /* __KERNEL_GPU__ */ + return shadow_blocked_transparent_all(kg, + shadow_sd, + state, + ray, + max_hits, + shadow); +# else /* __SHADOW_RECORD_ALL__ */ + /* Fallback to a slowest version which works on all devices. */ + return shadow_blocked_transparent_stepped(kg, + shadow_sd, + state, + ray, + isect, + shadow); +# endif /* __SHADOW_RECORD_ALL__ */ +#endif /* __TRANSPARENT_SHADOWS__ */ } -#endif +#undef SHADOW_STACK_MAX_HITS CCL_NAMESPACE_END - diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 8d5bb75a428..cb1a3f40dee 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -32,6 +32,7 @@ KERNEL_TEX(uint, texture_uint, __prim_visibility) KERNEL_TEX(uint, texture_uint, __prim_index) KERNEL_TEX(uint, texture_uint, __prim_object) KERNEL_TEX(uint, texture_uint, __object_node) +KERNEL_TEX(float2, texture_float2, __prim_time) /* objects */ KERNEL_TEX(float4, texture_float4, __objects) @@ -177,7 +178,6 @@ KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_085) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_086) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_087) KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_088) -KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_byte4_089) # else /* bindless textures */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index b69cec21400..070933fdfd1 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -98,6 +98,7 @@ CCL_NAMESPACE_BEGIN # define __VOLUME_SCATTER__ # define __SUBSURFACE__ # define __CMJ__ +# define __SHADOW_RECORD_ALL__ # endif #endif /* __KERNEL_CUDA__ */ @@ -1218,7 +1219,8 @@ typedef struct KernelBVH { int have_curves; int have_instancing; int use_qbvh; - int pad1, pad2; + int use_bvh_steps; + int pad1; } KernelBVH; static_assert_align(KernelBVH, 16); diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu index bfa852235fc..52e541321e3 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel.cu @@ -36,8 +36,10 @@ kernel_cuda_path_trace(float *buffer, uint *rng_state, int sample, int sx, int s int x = sx + blockDim.x*blockIdx.x + threadIdx.x; int y = sy + blockDim.y*blockIdx.y + threadIdx.y; - if(x < sx + sw && y < sy + sh) - kernel_path_trace(NULL, buffer, rng_state, sample, x, y, offset, stride); + if(x < sx + sw && y < sy + sh) { + KernelGlobals kg; + kernel_path_trace(&kg, buffer, rng_state, sample, x, y, offset, stride); + } } #ifdef __BRANCHED_PATH__ @@ -48,8 +50,10 @@ kernel_cuda_branched_path_trace(float *buffer, uint *rng_state, int sample, int int x = sx + blockDim.x*blockIdx.x + threadIdx.x; int y = sy + blockDim.y*blockIdx.y + threadIdx.y; - if(x < sx + sw && y < sy + sh) - kernel_branched_path_trace(NULL, buffer, rng_state, sample, x, y, offset, stride); + if(x < sx + sw && y < sy + sh) { + KernelGlobals kg; + kernel_branched_path_trace(&kg, buffer, rng_state, sample, x, y, offset, stride); + } } #endif @@ -60,8 +64,9 @@ kernel_cuda_convert_to_byte(uchar4 *rgba, float *buffer, float sample_scale, int int x = sx + blockDim.x*blockIdx.x + threadIdx.x; int y = sy + blockDim.y*blockIdx.y + threadIdx.y; - if(x < sx + sw && y < sy + sh) + if(x < sx + sw && y < sy + sh) { kernel_film_convert_to_byte(NULL, rgba, buffer, sample_scale, x, y, offset, stride); + } } extern "C" __global__ void @@ -71,8 +76,9 @@ kernel_cuda_convert_to_half_float(uchar4 *rgba, float *buffer, float sample_scal int x = sx + blockDim.x*blockIdx.x + threadIdx.x; int y = sy + blockDim.y*blockIdx.y + threadIdx.y; - if(x < sx + sw && y < sy + sh) + if(x < sx + sw && y < sy + sh) { kernel_film_convert_to_half_float(NULL, rgba, buffer, sample_scale, x, y, offset, stride); + } } extern "C" __global__ void @@ -89,7 +95,8 @@ kernel_cuda_shader(uint4 *input, int x = sx + blockDim.x*blockIdx.x + threadIdx.x; if(x < sx + sw) { - kernel_shader_evaluate(NULL, + KernelGlobals kg; + kernel_shader_evaluate(&kg, input, output, output_luma, @@ -106,8 +113,10 @@ kernel_cuda_bake(uint4 *input, float4 *output, int type, int filter, int sx, int { int x = sx + blockDim.x*blockIdx.x + threadIdx.x; - if(x < sx + sw) - kernel_bake_evaluate(NULL, input, output, (ShaderEvalType)type, filter, x, offset, sample); + if(x < sx + sw) { + KernelGlobals kg; + kernel_bake_evaluate(&kg, input, output, (ShaderEvalType)type, filter, x, offset, sample); + } } #endif diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 2afdf61b476..0d6efb47223 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -144,7 +144,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, case 86: r = kernel_tex_image_interp(__tex_image_byte4_086, x, y); break; case 87: r = kernel_tex_image_interp(__tex_image_byte4_087, x, y); break; case 88: r = kernel_tex_image_interp(__tex_image_byte4_088, x, y); break; - case 89: r = kernel_tex_image_interp(__tex_image_byte4_089, x, y); break; default: kernel_assert(0); return make_float4(0.0f, 0.0f, 0.0f, 0.0f); diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h index 01547b60014..a7f15de7325 100644 --- a/intern/cycles/kernel/svm/svm_math_util.h +++ b/intern/cycles/kernel/svm/svm_math_util.h @@ -134,32 +134,37 @@ ccl_device float3 svm_math_blackbody_color(float t) { { 6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f }, }; - if(t >= 12000.0f) + int i; + if(t >= 12000.0f) { return make_float3(0.826270103f, 0.994478524f, 1.56626022f); + } + else if(t >= 6365.0f) { + i = 5; + } + else if(t >= 3315.0f) { + i = 4; + } + else if(t >= 1902.0f) { + i = 3; + } + else if(t >= 1449.0f) { + i = 2; + } + else if(t >= 1167.0f) { + i = 1; + } + else if(t >= 965.0f) { + i = 0; + } + else { + /* For 800 <= t < 965 color does not change in OSL implementation, so keep color the same */ + return make_float3(4.70366907f, 0.0f, 0.0f); + } - /* Define a macro to reduce stack usage for nvcc */ -#define MAKE_BB_RGB(i) make_float3(\ - rc[i][0] / t + rc[i][1] * t + rc[i][2],\ - gc[i][0] / t + gc[i][1] * t + gc[i][2],\ - ((bc[i][0] * t + bc[i][1]) * t + bc[i][2]) * t + bc[i][3]) - - if(t >= 6365.0f) - return MAKE_BB_RGB(5); - if(t >= 3315.0f) - return MAKE_BB_RGB(4); - if(t >= 1902.0f) - return MAKE_BB_RGB(3); - if(t >= 1449.0f) - return MAKE_BB_RGB(2); - if(t >= 1167.0f) - return MAKE_BB_RGB(1); - if(t >= 965.0f) - return MAKE_BB_RGB(0); - -#undef MAKE_BB_RGB - - /* For 800 <= t < 965 color does not change in OSL implementation, so keep color the same */ - return make_float3(4.70366907f, 0.0f, 0.0f); + const float t_inv = 1.0f / t; + return make_float3(rc[i][0] * t_inv + rc[i][1] * t + rc[i][2], + gc[i][0] * t_inv + gc[i][1] * t + gc[i][2], + ((bc[i][0] * t + bc[i][1]) * t + bc[i][2]) * t + bc[i][3]); } ccl_device_inline float3 svm_math_gamma_color(float3 color, float gamma) diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h index 25f5eb3c897..aed9c5a8e75 100644 --- a/intern/cycles/render/bake.h +++ b/intern/cycles/render/bake.h @@ -73,7 +73,7 @@ public: bool need_update; - int total_pixel_samples; + size_t total_pixel_samples; private: BakeData *m_bake_data; diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 473bf776abf..fc6790dc022 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -486,10 +486,18 @@ static void background_cdf(int start, float2 *cond_cdf) { /* Conditional CDFs (rows, U direction). */ + /* NOTE: It is possible to have some NaN pixels on background + * which will ruin CDF causing wrong shading. We replace such + * pixels with black. + */ for(int i = start; i < end; i++) { float sin_theta = sinf(M_PI_F * (i + 0.5f) / res); float3 env_color = (*pixels)[i * res]; float ave_luminance = average(env_color); + /* TODO(sergey): Consider adding average_safe(). */ + if(!isfinite(ave_luminance)) { + ave_luminance = 0.0f; + } cond_cdf[i * cdf_count].x = ave_luminance * sin_theta; cond_cdf[i * cdf_count].y = 0.0f; @@ -497,6 +505,9 @@ static void background_cdf(int start, for(int j = 1; j < res; j++) { env_color = (*pixels)[i * res + j]; ave_luminance = average(env_color); + if(!isfinite(ave_luminance)) { + ave_luminance = 0.0f; + } cond_cdf[i * cdf_count + j].x = ave_luminance * sin_theta; cond_cdf[i * cdf_count + j].y = cond_cdf[i * cdf_count + j - 1].y + cond_cdf[i * cdf_count + j - 1].x / res; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index c42b32919d4..b7660297f3e 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1873,9 +1873,14 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * dscene->prim_object.reference((uint*)&pack.prim_object[0], pack.prim_object.size()); device->tex_alloc("__prim_object", dscene->prim_object); } + if(pack.prim_time.size()) { + dscene->prim_time.reference((float2*)&pack.prim_time[0], pack.prim_time.size()); + device->tex_alloc("__prim_time", dscene->prim_time); + } dscene->data.bvh.root = pack.root_index; dscene->data.bvh.use_qbvh = scene->params.use_qbvh; + dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); } void MeshManager::device_update_flags(Device * /*device*/, @@ -2152,6 +2157,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->prim_visibility); device->tex_free(dscene->prim_index); device->tex_free(dscene->prim_object); + device->tex_free(dscene->prim_time); device->tex_free(dscene->tri_shader); device->tex_free(dscene->tri_vnormal); device->tex_free(dscene->tri_vindex); @@ -2173,6 +2179,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->prim_visibility.clear(); dscene->prim_index.clear(); dscene->prim_object.clear(); + dscene->prim_time.clear(); dscene->tri_shader.clear(); dscene->tri_vnormal.clear(); dscene->tri_vindex.clear(); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 8768682043f..9f398c444f4 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -69,6 +69,7 @@ public: device_vector<uint> prim_visibility; device_vector<uint> prim_index; device_vector<uint> prim_object; + device_vector<float2> prim_time; /* mesh */ device_vector<uint> tri_shader; diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp index 32b4c7265ee..3fc086cbc0c 100644 --- a/intern/cycles/test/render_graph_finalize_test.cpp +++ b/intern/cycles/test/render_graph_finalize_test.cpp @@ -92,7 +92,7 @@ public: template<typename T> ShaderGraphBuilder& add_node(const T& node) { - EXPECT_EQ(NULL, find_node(node.name())); + EXPECT_EQ(find_node(node.name()), (void*)NULL); graph_->add(node.node()); node_map_[node.name()] = node.node(); return *this; @@ -104,8 +104,8 @@ public: vector<string> tokens_from, tokens_to; string_split(tokens_from, from, "::"); string_split(tokens_to, to, "::"); - EXPECT_EQ(2, tokens_from.size()); - EXPECT_EQ(2, tokens_to.size()); + EXPECT_EQ(tokens_from.size(), 2); + EXPECT_EQ(tokens_to.size(), 2); ShaderNode *node_from = find_node(tokens_from[0]), *node_to = find_node(tokens_to[0]); EXPECT_NE((void*)NULL, node_from); diff --git a/intern/cycles/test/util_aligned_malloc_test.cpp b/intern/cycles/test/util_aligned_malloc_test.cpp index 479070f0513..9fb3aad0c3f 100644 --- a/intern/cycles/test/util_aligned_malloc_test.cpp +++ b/intern/cycles/test/util_aligned_malloc_test.cpp @@ -18,7 +18,7 @@ #include "util/util_aligned_malloc.h" -#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ(0, (size_t)ptr % align) +#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ((size_t)ptr % align, 0) CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/test/util_path_test.cpp b/intern/cycles/test/util_path_test.cpp index 92be1dd4cbe..c2f400c105d 100644 --- a/intern/cycles/test/util_path_test.cpp +++ b/intern/cycles/test/util_path_test.cpp @@ -26,63 +26,63 @@ CCL_NAMESPACE_BEGIN TEST(util_path_filename, simple_unix) { string str = path_filename("/tmp/foo.txt"); - EXPECT_EQ("foo.txt", str); + EXPECT_EQ(str, "foo.txt"); } TEST(util_path_filename, root_unix) { string str = path_filename("/"); - EXPECT_EQ("/", str); + EXPECT_EQ(str, "/"); } TEST(util_path_filename, last_slash_unix) { string str = path_filename("/tmp/foo.txt/"); - EXPECT_EQ(".", str); + EXPECT_EQ(str, "."); } TEST(util_path_filename, alternate_slash_unix) { string str = path_filename("/tmp\\foo.txt"); - EXPECT_EQ("tmp\\foo.txt", str); + EXPECT_EQ(str, "tmp\\foo.txt"); } #endif /* !_WIN32 */ TEST(util_path_filename, file_only) { string str = path_filename("foo.txt"); - EXPECT_EQ("foo.txt", str); + EXPECT_EQ(str, "foo.txt"); } TEST(util_path_filename, empty) { string str = path_filename(""); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } #ifdef _WIN32 TEST(util_path_filename, simple_windows) { string str = path_filename("C:\\tmp\\foo.txt"); - EXPECT_EQ("foo.txt", str); + EXPECT_EQ(str, "foo.txt"); } TEST(util_path_filename, root_windows) { string str = path_filename("C:\\"); - EXPECT_EQ("\\", str); + EXPECT_EQ(str, "\\"); } TEST(util_path_filename, last_slash_windows) { string str = path_filename("C:\\tmp\\foo.txt\\"); - EXPECT_EQ(".", str); + EXPECT_EQ(str, "."); } TEST(util_path_filename, alternate_slash_windows) { string str = path_filename("C:\\tmp/foo.txt"); - EXPECT_EQ("foo.txt", str); + EXPECT_EQ(str, "foo.txt"); } #endif /* _WIN32 */ @@ -92,63 +92,63 @@ TEST(util_path_filename, alternate_slash_windows) TEST(util_path_dirname, simple_unix) { string str = path_dirname("/tmp/foo.txt"); - EXPECT_EQ("/tmp", str); + EXPECT_EQ(str, "/tmp"); } TEST(util_path_dirname, root_unix) { string str = path_dirname("/"); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_path_dirname, last_slash_unix) { string str = path_dirname("/tmp/foo.txt/"); - EXPECT_EQ("/tmp/foo.txt", str); + EXPECT_EQ(str, "/tmp/foo.txt"); } TEST(util_path_dirname, alternate_slash_unix) { string str = path_dirname("/tmp\\foo.txt"); - EXPECT_EQ("/", str); + EXPECT_EQ(str, "/"); } #endif /* !_WIN32 */ TEST(util_path_dirname, file_only) { string str = path_dirname("foo.txt"); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_path_dirname, empty) { string str = path_dirname(""); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } #ifdef _WIN32 TEST(util_path_dirname, simple_windows) { string str = path_dirname("C:\\tmp\\foo.txt"); - EXPECT_EQ("C:\\tmp", str); + EXPECT_EQ(str, "C:\\tmp"); } TEST(util_path_dirname, root_windows) { string str = path_dirname("C:\\"); - EXPECT_EQ("C:", str); + EXPECT_EQ(str, "C:"); } TEST(util_path_dirname, last_slash_windows) { string str = path_dirname("C:\\tmp\\foo.txt\\"); - EXPECT_EQ("C:\\tmp\\foo.txt", str); + EXPECT_EQ(str, "C:\\tmp\\foo.txt"); } TEST(util_path_dirname, alternate_slash_windows) { string str = path_dirname("C:\\tmp/foo.txt"); - EXPECT_EQ("C:\\tmp", str); + EXPECT_EQ(str, "C:\\tmp"); } #endif /* _WIN32 */ @@ -157,152 +157,152 @@ TEST(util_path_dirname, alternate_slash_windows) TEST(util_path_join, empty_both) { string str = path_join("", ""); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_path_join, empty_directory) { string str = path_join("", "foo.txt"); - EXPECT_EQ("foo.txt", str); + EXPECT_EQ(str, "foo.txt"); } TEST(util_path_join, empty_filename) { string str = path_join("foo", ""); - EXPECT_EQ("foo", str); + EXPECT_EQ(str, "foo"); } #ifndef _WIN32 TEST(util_path_join, simple_unix) { string str = path_join("foo", "bar"); - EXPECT_EQ("foo/bar", str); + EXPECT_EQ(str, "foo/bar"); } TEST(util_path_join, directory_slash_unix) { string str = path_join("foo/", "bar"); - EXPECT_EQ("foo/bar", str); + EXPECT_EQ(str, "foo/bar"); } TEST(util_path_join, filename_slash_unix) { string str = path_join("foo", "/bar"); - EXPECT_EQ("foo/bar", str); + EXPECT_EQ(str, "foo/bar"); } TEST(util_path_join, both_slash_unix) { string str = path_join("foo/", "/bar"); - EXPECT_EQ("foo//bar", str); + EXPECT_EQ(str, "foo//bar"); } TEST(util_path_join, directory_alternate_slash_unix) { string str = path_join("foo\\", "bar"); - EXPECT_EQ("foo\\/bar", str); + EXPECT_EQ(str, "foo\\/bar"); } TEST(util_path_join, filename_alternate_slash_unix) { string str = path_join("foo", "\\bar"); - EXPECT_EQ("foo/\\bar", str); + EXPECT_EQ(str, "foo/\\bar"); } TEST(util_path_join, both_alternate_slash_unix) { string str = path_join("foo", "\\bar"); - EXPECT_EQ("foo/\\bar", str); + EXPECT_EQ(str, "foo/\\bar"); } TEST(util_path_join, empty_dir_filename_slash_unix) { string str = path_join("", "/foo.txt"); - EXPECT_EQ("/foo.txt", str); + EXPECT_EQ(str, "/foo.txt"); } TEST(util_path_join, empty_dir_filename_alternate_slash_unix) { string str = path_join("", "\\foo.txt"); - EXPECT_EQ("\\foo.txt", str); + EXPECT_EQ(str, "\\foo.txt"); } TEST(util_path_join, empty_filename_dir_slash_unix) { string str = path_join("foo/", ""); - EXPECT_EQ("foo/", str); + EXPECT_EQ(str, "foo/"); } TEST(util_path_join, empty_filename_dir_alternate_slash_unix) { string str = path_join("foo\\", ""); - EXPECT_EQ("foo\\", str); + EXPECT_EQ(str, "foo\\"); } #else /* !_WIN32 */ TEST(util_path_join, simple_windows) { string str = path_join("foo", "bar"); - EXPECT_EQ("foo\\bar", str); + EXPECT_EQ(str, "foo\\bar"); } TEST(util_path_join, directory_slash_windows) { string str = path_join("foo\\", "bar"); - EXPECT_EQ("foo\\bar", str); + EXPECT_EQ(str, "foo\\bar"); } TEST(util_path_join, filename_slash_windows) { string str = path_join("foo", "\\bar"); - EXPECT_EQ("foo\\bar", str); + EXPECT_EQ(str, "foo\\bar"); } TEST(util_path_join, both_slash_windows) { string str = path_join("foo\\", "\\bar"); - EXPECT_EQ("foo\\\\bar", str); + EXPECT_EQ(str, "foo\\\\bar"); } TEST(util_path_join, directory_alternate_slash_windows) { string str = path_join("foo/", "bar"); - EXPECT_EQ("foo/bar", str); + EXPECT_EQ(str, "foo/bar"); } TEST(util_path_join, filename_alternate_slash_windows) { string str = path_join("foo", "/bar"); - EXPECT_EQ("foo/bar", str); + EXPECT_EQ(str, "foo/bar"); } TEST(util_path_join, both_alternate_slash_windows) { string str = path_join("foo/", "/bar"); - EXPECT_EQ("foo//bar", str); + EXPECT_EQ(str, "foo//bar"); } TEST(util_path_join, empty_dir_filename_slash_windows) { string str = path_join("", "\\foo.txt"); - EXPECT_EQ("\\foo.txt", str); + EXPECT_EQ(str, "\\foo.txt"); } TEST(util_path_join, empty_dir_filename_alternate_slash_windows) { string str = path_join("", "/foo.txt"); - EXPECT_EQ("/foo.txt", str); + EXPECT_EQ(str, "/foo.txt"); } TEST(util_path_join, empty_filename_dir_slash_windows) { string str = path_join("foo\\", ""); - EXPECT_EQ("foo\\", str); + EXPECT_EQ(str, "foo\\"); } TEST(util_path_join, empty_filename_dir_alternate_slash_windows) { string str = path_join("foo/", ""); - EXPECT_EQ("foo/", str); + EXPECT_EQ(str, "foo/"); } #endif /* !_WIN32 */ @@ -311,31 +311,31 @@ TEST(util_path_join, empty_filename_dir_alternate_slash_windows) TEST(util_path_escape, no_escape_chars) { string str = path_escape("/tmp/foo/bar"); - EXPECT_EQ("/tmp/foo/bar", str); + EXPECT_EQ(str, "/tmp/foo/bar"); } TEST(util_path_escape, simple) { string str = path_escape("/tmp/foo bar"); - EXPECT_EQ("/tmp/foo\\ bar", str); + EXPECT_EQ(str, "/tmp/foo\\ bar"); } TEST(util_path_escape, simple_end) { string str = path_escape("/tmp/foo/bar "); - EXPECT_EQ("/tmp/foo/bar\\ ", str); + EXPECT_EQ(str, "/tmp/foo/bar\\ "); } TEST(util_path_escape, multiple) { string str = path_escape("/tmp/foo bar"); - EXPECT_EQ("/tmp/foo\\ \\ bar", str); + EXPECT_EQ(str, "/tmp/foo\\ \\ bar"); } TEST(util_path_escape, simple_multiple_end) { string str = path_escape("/tmp/foo/bar "); - EXPECT_EQ("/tmp/foo/bar\\ \\ ", str); + EXPECT_EQ(str, "/tmp/foo/bar\\ \\ "); } /* ******** Tests for path_is_relative() ******** */ diff --git a/intern/cycles/test/util_string_test.cpp b/intern/cycles/test/util_string_test.cpp index e502a35704b..22ec8e0ee8e 100644 --- a/intern/cycles/test/util_string_test.cpp +++ b/intern/cycles/test/util_string_test.cpp @@ -25,25 +25,25 @@ CCL_NAMESPACE_BEGIN TEST(util_string_printf, no_format) { string str = string_printf("foo bar"); - EXPECT_EQ(str, "foo bar"); + EXPECT_EQ("foo bar", str); } TEST(util_string_printf, int_number) { string str = string_printf("foo %d bar", 314); - EXPECT_EQ(str, "foo 314 bar"); + EXPECT_EQ("foo 314 bar", str); } TEST(util_string_printf, float_number_default_precision) { string str = string_printf("foo %f bar", 3.1415); - EXPECT_EQ(str, "foo 3.141500 bar"); + EXPECT_EQ("foo 3.141500 bar", str); } TEST(util_string_printf, float_number_custom_precision) { string str = string_printf("foo %.1f bar", 3.1415); - EXPECT_EQ(str, "foo 3.1 bar"); + EXPECT_EQ("foo 3.1 bar", str); } /* ******** Tests for string_printf() ******** */ @@ -78,44 +78,44 @@ TEST(util_string_split, empty) { vector<string> tokens; string_split(tokens, ""); - EXPECT_EQ(0, tokens.size()); + EXPECT_EQ(tokens.size(), 0); } TEST(util_string_split, only_spaces) { vector<string> tokens; string_split(tokens, " \t\t \t"); - EXPECT_EQ(0, tokens.size()); + EXPECT_EQ(tokens.size(), 0); } TEST(util_string_split, single) { vector<string> tokens; string_split(tokens, "foo"); - EXPECT_EQ(1, tokens.size()); - EXPECT_EQ("foo", tokens[0]); + EXPECT_EQ(tokens.size(), 1); + EXPECT_EQ(tokens[0], "foo"); } TEST(util_string_split, simple) { vector<string> tokens; string_split(tokens, "foo a bar b"); - EXPECT_EQ(4, tokens.size()); - EXPECT_EQ("foo", tokens[0]); - EXPECT_EQ("a", tokens[1]); - EXPECT_EQ("bar", tokens[2]); - EXPECT_EQ("b", tokens[3]); + EXPECT_EQ(tokens.size(), 4); + EXPECT_EQ(tokens[0], "foo"); + EXPECT_EQ(tokens[1], "a"); + EXPECT_EQ(tokens[2], "bar"); + EXPECT_EQ(tokens[3], "b"); } TEST(util_string_split, multiple_spaces) { vector<string> tokens; string_split(tokens, " \t foo \ta bar b\t "); - EXPECT_EQ(4, tokens.size()); - EXPECT_EQ("foo", tokens[0]); - EXPECT_EQ("a", tokens[1]); - EXPECT_EQ("bar", tokens[2]); - EXPECT_EQ("b", tokens[3]); + EXPECT_EQ(tokens.size(), 4); + EXPECT_EQ(tokens[0], "foo"); + EXPECT_EQ(tokens[1], "a"); + EXPECT_EQ(tokens[2], "bar"); + EXPECT_EQ(tokens[3], "b"); } /* ******** Tests for string_replace() ******** */ @@ -124,35 +124,35 @@ TEST(util_string_replace, empty_haystack_and_other) { string str = ""; string_replace(str, "x", ""); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_string_replace, empty_haystack) { string str = ""; string_replace(str, "x", "y"); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_string_replace, empty_other) { string str = "x"; string_replace(str, "x", ""); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_string_replace, long_haystack_empty_other) { string str = "a x b xxc"; string_replace(str, "x", ""); - EXPECT_EQ("a b c", str); + EXPECT_EQ(str, "a b c"); } TEST(util_string_replace, long_haystack) { string str = "a x b xxc"; string_replace(str, "x", "FOO"); - EXPECT_EQ("a FOO b FOOFOOc", str); + EXPECT_EQ(str, "a FOO b FOOFOOc"); } /* ******** Tests for string_endswith() ******** */ @@ -192,25 +192,25 @@ TEST(util_string_endswith, simple_false) TEST(util_string_strip, empty) { string str = string_strip(""); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_string_strip, only_spaces) { string str = string_strip(" "); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_string_strip, no_spaces) { string str = string_strip("foo bar"); - EXPECT_EQ("foo bar", str); + EXPECT_EQ(str, "foo bar"); } TEST(util_string_strip, with_spaces) { string str = string_strip(" foo bar "); - EXPECT_EQ("foo bar", str); + EXPECT_EQ(str, "foo bar"); } /* ******** Tests for string_remove_trademark() ******** */ @@ -218,31 +218,31 @@ TEST(util_string_strip, with_spaces) TEST(util_string_remove_trademark, empty) { string str = string_remove_trademark(""); - EXPECT_EQ("", str); + EXPECT_EQ(str, ""); } TEST(util_string_remove_trademark, no_trademark) { string str = string_remove_trademark("foo bar"); - EXPECT_EQ("foo bar", str); + EXPECT_EQ(str, "foo bar"); } TEST(util_string_remove_trademark, only_tm) { string str = string_remove_trademark("foo bar(TM) zzz"); - EXPECT_EQ("foo bar zzz", str); + EXPECT_EQ(str, "foo bar zzz"); } TEST(util_string_remove_trademark, only_r) { string str = string_remove_trademark("foo bar(R) zzz"); - EXPECT_EQ("foo bar zzz", str); + EXPECT_EQ(str, "foo bar zzz"); } TEST(util_string_remove_trademark, both) { string str = string_remove_trademark("foo bar(TM)(R) zzz"); - EXPECT_EQ("foo bar zzz", str); + EXPECT_EQ(str, "foo bar zzz"); } CCL_NAMESPACE_END diff --git a/intern/utfconv/utfconv.h b/intern/utfconv/utfconv.h index f00f4aeef27..d05ed61c8d8 100644 --- a/intern/utfconv/utfconv.h +++ b/intern/utfconv/utfconv.h @@ -93,7 +93,7 @@ wchar_t *alloc_utf16_from_8(const char *in8, size_t add); /* Easy allocation and conversion of new utf-16 string. New string has _16 suffix. Must be deallocated with UTF16_UN_ENCODE in right order*/ #define UTF16_ENCODE(in8str) if (1) { \ - wchar_t *in8str ## _16 = alloc_utf16_from_8((char *)in8str, 0) + wchar_t *in8str ## _16 = alloc_utf16_from_8((const char *)in8str, 0) #define UTF16_UN_ENCODE(in8str) \ free(in8str ## _16); } (void)0 @@ -5,8 +5,8 @@ REM This is for users who like to configure & build Blender with a single comman setlocal ENABLEEXTENSIONS set BLENDER_DIR=%~dp0 set BLENDER_DIR_NOSPACES=%BLENDER_DIR: =% -if not "%BLENDER_DIR%"=="%BLENDER_DIR_NOSPACES%" ( - echo There are spaces detected in the build path "%BLENDER_DIR%", this is currently not supported, exiting.... +if not "%BLENDER_DIR%"=="%BLENDER_DIR_NOSPACES%" ( + echo There are spaces detected in the build path "%BLENDER_DIR%", this is currently not supported, exiting.... goto EOF ) set BUILD_DIR=%BLENDER_DIR%..\build_windows @@ -79,7 +79,7 @@ if NOT "%1" == "" ( set NOBUILD=1 ) else if "%1" == "showhash" ( for /f "delims=" %%i in ('git rev-parse HEAD') do echo Branch_hash=%%i - cd release/datafiles/locale + cd release/datafiles/locale for /f "delims=" %%i in ('git rev-parse HEAD') do echo Locale_hash=%%i cd %~dp0 cd release/scripts/addons @@ -132,13 +132,13 @@ if "%BUILD_ARCH%"=="x64" ( if "%target%"=="Release" ( - rem for vc12 check for both cuda 7.5 and 8 + rem for vc12 check for both cuda 7.5 and 8 if "%CUDA_PATH%"=="" ( echo Cuda Not found, aborting! goto EOF ) set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\blender_release.cmake" + -C"%BLENDER_DIR%\build_files\cmake\config\blender_release.cmake" ) :DetectMSVC @@ -157,7 +157,7 @@ if DEFINED MSVC_VC_DIR goto msvc_detect_finally if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat" if DEFINED MSVC_VC_DIR goto sanity_checks -rem MSVC Build environment 2017 and up. +rem MSVC Build environment 2017 and up. for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SXS\VS7" /v %BUILD_VS_VER%.0 2^>nul`) DO set MSVC_VS_DIR=%%C if DEFINED MSVC_VS_DIR goto msvc_detect_finally_2017 REM Check 32 bits @@ -202,7 +202,7 @@ if NOT EXIST %BLENDER_DIR%..\lib\nul ( if "%TARGET%"=="" ( echo Error: Convenience target not set echo This is required for building, aborting! - echo . + echo . goto HELP ) @@ -266,15 +266,15 @@ echo. echo At any point you can optionally modify your build configuration by editing: echo "%BUILD_DIR%\CMakeCache.txt", then run "make" again to build with the changes applied. echo. -echo Blender successfully built, run from: "%BUILD_DIR%\bin\%BUILD_TYPE%" +echo Blender successfully built, run from: "%BUILD_DIR%\bin\%BUILD_TYPE%\blender.exe" echo. goto EOF :HELP echo. echo Convenience targets - echo - release ^(identical to the offical blender.org builds^) + echo - release ^(identical to the official blender.org builds^) echo - full ^(same as release minus the cuda kernels^) - echo - lite + echo - lite echo - headless echo - cycles echo - bpy @@ -289,11 +289,10 @@ goto EOF echo - with_tests ^(enable building unit tests^) echo - debug ^(Build an unoptimized debuggable build^) echo - packagename [newname] ^(override default cpack package name^) - echo - x86 ^(override host autodetect and build 32 bit code^) - echo - x64 ^(override host autodetect and build 64 bit code^) + echo - x86 ^(override host auto-detect and build 32 bit code^) + echo - x64 ^(override host auto-detect and build 64 bit code^) echo - 2013 ^(build with visual studio 2013^) echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL] echo. :EOF - diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg index e9c114ba1bd..d88788fa904 100644 --- a/release/datafiles/blender_icons.svg +++ b/release/datafiles/blender_icons.svg @@ -14,7 +14,7 @@ height="640" id="svg2" sodipodi:version="0.32" - inkscape:version="0.91 r" + inkscape:version="0.91 r13725" version="1.0" sodipodi:docname="blender_icons.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" @@ -31338,6 +31338,26 @@ d="m 125.5,433.5 23,0 0,41 -33,0 0,-31 10,-10 z" style="display:inline;fill:url(#linearGradient13110);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none" /> </clipPath> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient1610-6" + id="linearGradient18199" + gradientUnits="userSpaceOnUse" + x1="189.76083" + y1="248.13905" + x2="116.05637" + y2="183.6826" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient22562" + id="radialGradient23167-6" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.99220964,-0.12457927,0.11585516,0.92272644,-34.13325,22.766225)" + cx="-0.78262758" + cy="294.63174" + fx="-0.78262758" + fy="294.63174" + r="6.6750002" /> </defs> <sodipodi:namedview id="base" @@ -31349,16 +31369,16 @@ objecttolerance="10000" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="14.413868" - inkscape:cx="480.24726" - inkscape:cy="269.95478" + inkscape:zoom="19.997864" + inkscape:cx="462.52244" + inkscape:cy="435.14241" inkscape:document-units="px" - inkscape:current-layer="layer1" + inkscape:current-layer="g23149-4" showgrid="true" - inkscape:window-width="1680" - inkscape:window-height="1020" - inkscape:window-x="0" - inkscape:window-y="30" + inkscape:window-width="1920" + inkscape:window-height="1025" + inkscape:window-x="-8" + inkscape:window-y="-8" inkscape:snap-nodes="true" inkscape:snap-bbox="true" showguides="true" @@ -92660,6 +92680,56 @@ style="opacity:0.51999996;fill:url(#radialGradient21448-8-143);fill-opacity:1;fill-rule:evenodd;stroke:none" /> </g> </g> + <g + transform="translate(335.99871,21.048284)" + style="display:inline;enable-background:new" + id="ICON_ROTATE-7"> + <rect + y="178" + x="110" + height="16" + width="16" + id="rect37989-8" + style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#b3b3b3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate" /> + <path + style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:2.4000001;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" + d="m 114.5,192.5 -3,0 0,-3 m 13,0 0,3 -3,0 m -0.25,-13 3.25,0 0,3 m -13,0 0,-3 3,0" + id="path37498-7" + sodipodi:nodetypes="cccccccccccc" + inkscape:connector-curvature="0" /> + <path + sodipodi:nodetypes="cccccccccccc" + id="rect38140-7" + d="m 114.5,192.5 -3,0 0,-3 m 13,0 0,3 -3,0 m -0.25,-13 3.25,0 0,3 m -13,0 0,-3 3,0" + style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient18199);stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" + inkscape:connector-curvature="0" /> + <g + transform="matrix(0.59971056,0,0,0.59971056,116.78278,9.7425599)" + style="display:inline;enable-background:new" + id="g23145-9"> + <g + id="g23149-4"> + <path + id="path39832-9" + style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#1a1a1a;stroke-width:4.66725159;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" + d="m -4.3682386,287.81345 1.5,0 c 0.999089,0 2.07885534,1.30514 2.50490386,2.78207 1.06592652,3.69512 2.80867074,9.82446 5.88525404,9.96406 2.6782554,0 1.6181317,-5.11535 3.1736046,-5.26275 l 0.25,0" + sodipodi:nodetypes="cssccc" + inkscape:connector-curvature="0" /> + <path + sodipodi:nodetypes="ccscc" + d="m 9.3647983,295.22328 -0.4793018,0 c -2.2335161,0 0.1796731,4.94901 -3.4398065,5.09984 -4.44796752,0.18536 -5.37272213,-12.59185 -8.0767581,-12.56237 l -2,0" + style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#a8df84;stroke-width:2.93474906;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" + id="path39834-2" + inkscape:connector-curvature="0" /> + </g> + <path + id="path39836-9" + style="display:inline;overflow:visible;visibility:visible;opacity:0.35;fill:none;stroke:url(#radialGradient23167-6);stroke-width:3.53503864;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" + d="M 5.6770841,300.48165 C 0.7393262,300.21066 0.54777814,287.99792 -2.9522219,287.99792" + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" /> + </g> + </g> </g> <g inkscape:groupmode="layer" diff --git a/release/datafiles/blender_icons16/icon16_normalize_fcurves.dat b/release/datafiles/blender_icons16/icon16_normalize_fcurves.dat Binary files differnew file mode 100644 index 00000000000..fe118a23d79 --- /dev/null +++ b/release/datafiles/blender_icons16/icon16_normalize_fcurves.dat diff --git a/release/datafiles/blender_icons32/icon32_normalize_fcurves.dat b/release/datafiles/blender_icons32/icon32_normalize_fcurves.dat Binary files differnew file mode 100644 index 00000000000..5b1f546a563 --- /dev/null +++ b/release/datafiles/blender_icons32/icon32_normalize_fcurves.dat diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py index 93305cb7c5a..b093920a4cb 100644 --- a/release/scripts/freestyle/modules/parameter_editor.py +++ b/release/scripts/freestyle/modules/parameter_editor.py @@ -1170,6 +1170,7 @@ class Seed: _seed = Seed() + def get_dashed_pattern(linestyle): """Extracts the dashed pattern from the various UI options """ pattern = [] @@ -1185,6 +1186,15 @@ def get_dashed_pattern(linestyle): return pattern +def get_grouped_objects(group): + for ob in group.objects: + if ob.dupli_type == 'GROUP' and ob.dupli_group is not None: + for dupli in get_grouped_objects(ob.dupli_group): + yield dupli + else: + yield ob + + integration_types = { 'MEAN': IntegrationType.MEAN, 'MIN': IntegrationType.MIN, @@ -1267,7 +1277,7 @@ def process(layer_name, lineset_name): # prepare selection criteria by group of objects if lineset.select_by_group: if lineset.group is not None: - names = {getQualifiedObjectName(ob): True for ob in lineset.group.objects} + names = {getQualifiedObjectName(ob): True for ob in get_grouped_objects(lineset.group)} upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE') selection_criteria.append(upred) # prepare selection criteria by image border diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index d66fb08bcd6..b24b574f37b 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -1320,7 +1320,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): row.prop(md, "thickness_vertex_group", text="Factor") col.prop(md, "use_crease", text="Crease Edges") - col.prop(md, "crease_weight", text="Crease Weight") + row = col.row() + row.active = md.use_crease + row.prop(md, "crease_weight", text="Crease Weight") col = split.column() diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 3ff7a248c60..4a596981983 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -152,6 +152,33 @@ class OBJECT_PT_relations(ObjectButtonsPanel, Panel): sub.active = (parent is not None) +class OBJECT_PT_relations_extras(ObjectButtonsPanel, Panel): + bl_label = "Relations Extras" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + + ob = context.object + + split = layout.split() + + if context.scene.render.engine != 'BLENDER_GAME': + col = split.column() + col.label(text="Tracking Axes:") + col.prop(ob, "track_axis", text="Axis") + col.prop(ob, "up_axis", text="Up Axis") + + col = split.column() + col.prop(ob, "use_slow_parent") + row = col.row() + row.active = ((ob.parent is not None) and (ob.use_slow_parent)) + row.prop(ob, "slow_parent_offset", text="Offset") + + layout.prop(ob, "use_extra_recalc_object") + layout.prop(ob, "use_extra_recalc_data") + + class GROUP_MT_specials(Menu): bl_label = "Group Specials" @@ -296,33 +323,6 @@ class OBJECT_PT_duplication(ObjectButtonsPanel, Panel): layout.prop(ob, "dupli_group", text="Group") -class OBJECT_PT_relations_extras(ObjectButtonsPanel, Panel): - bl_label = "Relations Extras" - bl_options = {'DEFAULT_CLOSED'} - - def draw(self, context): - layout = self.layout - - ob = context.object - - split = layout.split() - - if context.scene.render.engine != 'BLENDER_GAME': - col = split.column() - col.label(text="Tracking Axes:") - col.prop(ob, "track_axis", text="Axis") - col.prop(ob, "up_axis", text="Up Axis") - - col = split.column() - col.prop(ob, "use_slow_parent") - row = col.row() - row.active = ((ob.parent is not None) and (ob.use_slow_parent)) - row.prop(ob, "slow_parent_offset", text="Offset") - - layout.prop(ob, "use_extra_recalc_object") - layout.prop(ob, "use_extra_recalc_data") - - from bl_ui.properties_animviz import ( MotionPathButtonsPanel, OnionSkinButtonsPanel, diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 446df9e6e79..cec3b26f35a 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -42,10 +42,11 @@ class GRAPH_HT_header(Header): dopesheet_filter(layout, context) - layout.prop(st, "use_normalization", text="Normalize") - row = layout.row() - row.active = st.use_normalization - row.prop(st, "use_auto_normalization", text="Auto") + row = layout.row(align=True) + row.prop(st, "use_normalization", icon='NORMALIZE_FCURVES', text="Normalize", toggle=True) + sub = row.row(align=True) + sub.active = st.use_normalization + sub.prop(st, "use_auto_normalization", icon='FILE_REFRESH', text="", toggle=True) row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 6bb516cf929..8ab5b4724b8 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -652,17 +652,39 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): col.prop(strip, "rotation_start", text="Rotation") elif strip.type == 'MULTICAM': - layout.prop(strip, "multicam_source") - - row = layout.row(align=True) - sub = row.row(align=True) - sub.scale_x = 2.0 - - sub.operator("screen.animation_play", text="", icon='PAUSE' if context.screen.is_animation_playing else 'PLAY') + col = layout.column(align=True) + strip_channel = strip.channel + + col.prop(strip, "multicam_source", text="Source Channel") + + # The multicam strip needs at least 2 strips to be useful + if strip_channel > 2: + BT_ROW = 4 + + col.label("Cut To:") + row = col.row() + + for i in range(1, strip_channel): + if (i % BT_ROW) == 1: + row = col.row(align=True) + + # Workaround - .active has to have a separate UI block to work + if i == strip.multicam_source: + sub = row.row(align=True) + sub.active = False + sub.operator("sequencer.cut_multicam", text="%d" % i).camera = i + else: + sub_1 = row.row(align=True) + sub_1.active = True + sub_1.operator("sequencer.cut_multicam", text="%d" % i).camera = i + + if strip.channel > BT_ROW and (strip_channel - 1) % BT_ROW: + for i in range(strip.channel, strip_channel + ((BT_ROW + 1 - strip_channel) % BT_ROW)): + row.label("") + else: + col.separator() + col.label(text="Two or more channels are needed below this strip.", icon="INFO") - row.label("Cut To") - for i in range(1, strip.channel): - row.operator("sequencer.cut_multicam", text="%d" % i).camera = i elif strip.type == 'TEXT': col = layout.column() diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 508e62e4f56..1f62d8d6968 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -49,7 +49,10 @@ class TIME_HT_header(Header): row.prop(scene, "frame_preview_start", text="Start") row.prop(scene, "frame_preview_end", text="End") - layout.prop(scene, "frame_current", text="") + if scene.show_subframe: + layout.prop(scene, "frame_float", text="") + else: + layout.prop(scene, "frame_current", text="") layout.separator() @@ -135,6 +138,7 @@ class TIME_MT_view(Menu): layout.prop(st, "show_frame_indicator") layout.prop(scene, "show_keys_from_selected_only") + layout.prop(scene, "show_subframe") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 5e936076d0e..b6479df3047 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1346,9 +1346,9 @@ class VIEW3D_MT_object_clear(Menu): def draw(self, context): layout = self.layout - layout.operator("object.location_clear", text="Location") - layout.operator("object.rotation_clear", text="Rotation") - layout.operator("object.scale_clear", text="Scale") + layout.operator("object.location_clear", text="Location").clear_delta = False + layout.operator("object.rotation_clear", text="Rotation").clear_delta = False + layout.operator("object.scale_clear", text="Scale").clear_delta = False layout.operator("object.origin_clear", text="Origin") @@ -1744,6 +1744,7 @@ class VIEW3D_MT_brush_paint_modes(Menu): layout.prop(brush, "use_paint_weight", text="Weight Paint") layout.prop(brush, "use_paint_image", text="Texture Paint") + # ********** Vertex paint menu ********** @@ -1813,6 +1814,7 @@ class VIEW3D_MT_vertex_group(Menu): layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True + # ********** Weight paint menu ********** @@ -1851,6 +1853,7 @@ class VIEW3D_MT_paint_weight(Menu): layout.operator("paint.weight_set") + # ********** Sculpt menu ********** @@ -2004,6 +2007,7 @@ class VIEW3D_MT_particle_specials(Menu): class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu): _operator_name = "particle" + # ********** Pose Menu ********** @@ -2277,6 +2281,7 @@ class VIEW3D_MT_bone_options_disable(Menu, BoneOptions): bl_label = "Disable Bone Options" type = 'DISABLE' + # ********** Edit Menus, suffix from ob.type ********** @@ -2444,6 +2449,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu): with_bullet = bpy.app.build_options.bullet layout.operator("mesh.merge") + layout.operator("mesh.remove_doubles") layout.operator("mesh.rip_move") layout.operator("mesh.rip_move_fill") layout.operator("mesh.rip_edge_move") @@ -2466,7 +2472,6 @@ class VIEW3D_MT_edit_mesh_vertices(Menu): if with_bullet: layout.operator("mesh.convex_hull") layout.operator("mesh.vertices_smooth") - layout.operator("mesh.remove_doubles") layout.operator("mesh.blend_from_shape") @@ -2623,6 +2628,7 @@ class VIEW3D_MT_edit_mesh_clean(Menu): layout.operator("mesh.face_make_planar") layout.operator("mesh.vert_connect_nonplanar") layout.operator("mesh.vert_connect_concave") + layout.operator("mesh.remove_doubles") layout.operator("mesh.fill_holes") diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc index 0985a06d732..5f8fc1a3739 100644 --- a/source/blender/alembic/intern/abc_archive.cc +++ b/source/blender/alembic/intern/abc_archive.cc @@ -113,25 +113,25 @@ static OArchive create_archive(std::ostream *ostream, Alembic::Abc::MetaData &md, bool ogawa) { - md.set(Alembic::Abc::kApplicationNameKey, "Blender"); + md.set(Alembic::Abc::kApplicationNameKey, "Blender"); md.set(Alembic::Abc::kUserDescriptionKey, scene_name); - time_t raw_time; - time(&raw_time); - char buffer[128]; + time_t raw_time; + time(&raw_time); + char buffer[128]; #if defined _WIN32 || defined _WIN64 - ctime_s(buffer, 128, &raw_time); + ctime_s(buffer, 128, &raw_time); #else - ctime_r(&raw_time, buffer); + ctime_r(&raw_time, buffer); #endif - const std::size_t buffer_len = strlen(buffer); - if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { - buffer[buffer_len - 1] = '\0'; - } + const std::size_t buffer_len = strlen(buffer); + if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { + buffer[buffer_len - 1] = '\0'; + } - md.set(Alembic::Abc::kDateWrittenKey, buffer); + md.set(Alembic::Abc::kDateWrittenKey, buffer); ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy; diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 4ecb9d944f2..0542255d84b 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -102,7 +102,7 @@ void AbcCurveWriter::do_write() const BPoint *point = nurbs->bp; for (int i = 0; i < totpoint; ++i, ++point) { - copy_zup_yup(temp_vert.getValue(), point->vec); + copy_yup_from_zup(temp_vert.getValue(), point->vec); verts.push_back(temp_vert); weights.push_back(point->vec[3]); widths.push_back(point->radius); @@ -118,7 +118,7 @@ void AbcCurveWriter::do_write() /* TODO(kevin): store info about handles, Alembic doesn't have this. */ for (int i = 0; i < totpoint; ++i, ++bezier) { - copy_zup_yup(temp_vert.getValue(), bezier->vec[1]); + copy_yup_from_zup(temp_vert.getValue(), bezier->vec[1]); verts.push_back(temp_vert); widths.push_back(bezier->radius); } @@ -322,7 +322,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) weight = (*weights)[idx]; } - copy_yup_zup(bp->vec, pos.getValue()); + copy_zup_from_yup(bp->vec, pos.getValue()); bp->vec[3] = weight; bp->f1 = SELECT; bp->radius = radius; @@ -361,7 +361,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) * object directly and create a new DerivedMesh from that. Also we might need to * create new or delete existing NURBS in the curve. */ -DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/, const char **/*err_str*/) +DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/, const float time, int /*read_flag*/, const char ** /*err_str*/) { ISampleSelector sample_sel(time); const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel); @@ -389,7 +389,7 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float t for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_yup_zup(point->vec, pos.getValue()); + copy_zup_from_yup(point->vec, pos.getValue()); } } else if (nurbs->bezt) { @@ -397,7 +397,7 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float t for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) { const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_yup_zup(bezier->vec[1], pos.getValue()); + copy_zup_from_yup(bezier->vec[1], pos.getValue()); } } } diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index ff8b0442ab6..90a99469389 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -47,7 +47,7 @@ extern "C" { #ifdef WIN32 /* needed for MSCV because of snprintf from BLI_string */ -# include "BLI_winstuff.h" +# include "BLI_winstuff.h" #endif #include "BKE_anim.h" @@ -382,7 +382,10 @@ void AbcExporter::createTransformWritersFlat() void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent) { - createTransformWriter(ob, parent, dupliObParent); + + if (export_object(&m_settings, ob) && object_is_shape(ob)) { + createTransformWriter(ob, parent, dupliObParent); + } ListBase *lb = object_duplilist(eval_ctx, m_scene, ob); @@ -410,8 +413,12 @@ void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupl { const std::string name = get_object_dag_path_name(ob, dupliObParent); + /* An object should not be its own parent, or we'll get infinite loops. */ + BLI_assert(ob != parent); + BLI_assert(ob != dupliObParent); + /* check if we have already created a transform writer for this object */ - if (m_xforms.find(name) != m_xforms.end()){ + if (getXForm(name) != NULL){ std::cerr << "xform " << name << " already exists\n"; return; } @@ -426,6 +433,14 @@ void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupl if (parent->parent) { createTransformWriter(parent, parent->parent, dupliObParent); } + else if (parent == dupliObParent) { + if (dupliObParent->parent == NULL) { + createTransformWriter(parent, NULL, NULL); + } + else { + createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent); + } + } else { createTransformWriter(parent, dupliObParent, dupliObParent); } diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc index 14bcf6731ea..e328df24e53 100644 --- a/source/blender/alembic/intern/abc_hair.cc +++ b/source/blender/alembic/intern/abc_hair.cc @@ -77,7 +77,6 @@ void AbcHairWriter::do_write() DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH); DM_ensure_tessface(dm); - DM_update_tessface_data(dm); std::vector<Imath::V3f> verts; std::vector<int32_t> hvertices; @@ -164,7 +163,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL); - copy_zup_yup(tmp_nor.getValue(), normal); + copy_yup_from_zup(tmp_nor.getValue(), normal); norm_values.push_back(tmp_nor); } } @@ -198,7 +197,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm, MVert *mv = mverts + vtx[o]; normal_short_to_float_v3(normal, mv->no); - copy_zup_yup(tmp_nor.getValue(), normal); + copy_yup_from_zup(tmp_nor.getValue(), normal); norm_values.push_back(tmp_nor); found = true; break; diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index bdd75f93189..8bc9c335054 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -112,7 +112,7 @@ static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points) MVert *verts = dm->getVertArray(dm); for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) { - copy_zup_yup(points[i].getValue(), verts[i].co); + copy_yup_from_zup(points[i].getValue(), verts[i].co); } } @@ -182,7 +182,7 @@ static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) { normal_short_to_float_v3(no, verts[i].no); - copy_zup_yup(normals[i].getValue(), no); + copy_yup_from_zup(normals[i].getValue(), no); } } @@ -211,7 +211,7 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals) for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { const int index = ml->v; - copy_zup_yup(normals[loop_index].getValue(), lnors[index]); + copy_yup_from_zup(normals[loop_index].getValue(), lnors[index]); } } } @@ -226,14 +226,14 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals) BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no); for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { - copy_zup_yup(normals[loop_index].getValue(), no); + copy_yup_from_zup(normals[loop_index].getValue(), no); } } else { /* Smooth shaded, use individual vert normals. */ for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { normal_short_to_float_v3(no, verts[ml->v].no); - copy_zup_yup(normals[loop_index].getValue(), no); + copy_yup_from_zup(normals[loop_index].getValue(), no); } } } @@ -590,7 +590,7 @@ void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities); for (int i = 0; i < totverts; ++i) { - copy_zup_yup(vels[i].getValue(), mesh_vels); + copy_yup_from_zup(vels[i].getValue(), mesh_vels); mesh_vels += 3; } } @@ -726,7 +726,7 @@ static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions const Imath::V3f &ceil_pos = (*ceil_positions)[i]; interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight); - copy_yup_zup(mvert.co, tmp); + copy_zup_from_yup(mvert.co, tmp); mvert.bweight = 0; } @@ -755,7 +755,7 @@ void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArr MVert &mvert = mverts[i]; Imath::V3f pos_in = (*positions)[i]; - copy_yup_zup(mvert.co, pos_in.getValue()); + copy_zup_from_yup(mvert.co, pos_in.getValue()); mvert.bweight = 0; @@ -765,7 +765,7 @@ void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArr short no[3]; normal_float_to_short_v3(no, nor_in.getValue()); - copy_yup_zup(mvert.no, no); + copy_zup_from_yup(mvert.no, no); } } } diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc index 4f57dfdae9e..d0b9561f679 100644 --- a/source/blender/alembic/intern/abc_nurbs.cc +++ b/source/blender/alembic/intern/abc_nurbs.cc @@ -153,7 +153,7 @@ void AbcNurbsWriter::do_write() const BPoint *bp = nu->bp; for (int i = 0; i < size; ++i, ++bp) { - copy_zup_yup(positions[i].getValue(), bp->vec); + copy_yup_from_zup(positions[i].getValue(), bp->vec); weights[i] = bp->vec[3]; } @@ -281,7 +281,7 @@ void AbcNurbsReader::readObjectData(Main *bmain, float time) posw_in = (*weights)[i]; } - copy_yup_zup(bp->vec, pos_in.getValue()); + copy_zup_from_yup(bp->vec, pos_in.getValue()); bp->vec[3] = posw_in; bp->f1 = SELECT; bp->radius = 1.0f; diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index 9dfccdb8c7f..a5b8af542fc 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -97,14 +97,14 @@ Imath::Box3d AbcObjectWriter::bounds() return Imath::Box3d(); } - /* Convert Z-up to Y-up. */ + /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */ this->m_bounds.min.x = bb->vec[0][0]; this->m_bounds.min.y = bb->vec[0][2]; - this->m_bounds.min.z = -bb->vec[0][1]; + this->m_bounds.min.z = -bb->vec[6][1]; this->m_bounds.max.x = bb->vec[6][0]; this->m_bounds.max.y = bb->vec[6][2]; - this->m_bounds.max.z = -bb->vec[6][1]; + this->m_bounds.max.z = -bb->vec[0][1]; return this->m_bounds; } diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index 4c78f3e83c7..fc84759b1d9 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -200,7 +200,7 @@ void read_points_sample(const IPointsSchema &schema, read_mverts(config.mvert, positions, vnormals); } -DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/, const char **/*err_str*/) +DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/, const char ** /*err_str*/) { ISampleSelector sample_sel(time); const IPointsSchema::Sample sample = m_schema.getValue(sample_sel); diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc index e2fc7674c4e..2c6ef09326c 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_transform.cc @@ -122,7 +122,7 @@ Imath::Box3d AbcTransformWriter::bounds() return Imath::transform(bounds, m_matrix); } -bool AbcTransformWriter::hasAnimation(Object */*ob*/) const +bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const { /* TODO(kevin): implement this. */ return true; @@ -146,6 +146,6 @@ bool AbcEmptyReader::valid() const void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/) { - m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str()); + m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_data_name.c_str()); m_object->data = NULL; } diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index f8ce72d845d..08c94f437e6 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -197,7 +197,7 @@ void create_transform_matrix(float r_mat[4][4]) copy_m4_m3(transform_mat, rot_mat); /* Add translation to transformation matrix. */ - copy_yup_zup(transform_mat[3], loc); + copy_zup_from_yup(transform_mat[3], loc); /* Create scale matrix. */ scale_mat[0][0] = scale[0]; @@ -417,7 +417,7 @@ void create_transform_matrix(Object *obj, float transform_mat[4][4]) copy_m4_m3(transform_mat, rot_mat); /* Add translation to transformation matrix. */ - copy_zup_yup(transform_mat[3], loc); + copy_yup_from_zup(transform_mat[3], loc); /* Create scale matrix. */ scale_mat[0][0] = scale[0]; diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index 60a96855d14..a7ac9df91c7 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -116,14 +116,14 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe /* Copy from Y-up to Z-up. */ -ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3]) +ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) { zup[0] = yup[0]; zup[1] = -yup[2]; zup[2] = yup[1]; } -ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3]) +ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) { zup[0] = yup[0]; zup[1] = -yup[2]; @@ -132,14 +132,14 @@ ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3]) /* Copy from Z-up to Y-up. */ -ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3]) +ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) { yup[0] = zup[0]; yup[1] = zup[2]; yup[2] = -zup[1]; } -ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3]) +ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3]) { yup[0] = zup[0]; yup[1] = zup[2]; diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 07db2217bac..ad729ad37dd 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -104,7 +104,7 @@ typedef struct BVHTreeFromMesh { * The tree is build in mesh space coordinates, this means special care must be made on queries * so that the coordinates and rays are first translated on the mesh local coordinates. * Reason for this is that bvh_from_mesh_* can use a cache in some cases and so it becomes possible to reuse a BVHTree. - * + * * free_bvhtree_from_mesh should be called when the tree is no longer needed. */ BVHTree *bvhtree_from_editmesh_verts( @@ -118,7 +118,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex( BVHTree *bvhtree_from_mesh_verts( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_mesh_verts_ex( - struct BVHTreeFromMesh *data, struct MVert *vert, const int numVerts, + struct BVHTreeFromMesh *data, const struct MVert *vert, const int numVerts, const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active, float epsilon, int tree_type, int axis); @@ -133,14 +133,20 @@ BVHTree *bvhtree_from_editmesh_edges_ex( BVHTree *bvhtree_from_mesh_edges( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_mesh_edges_ex( + struct BVHTreeFromMesh *data, + const struct MVert *vert, const bool vert_allocated, + const struct MEdge *edge, const int edges_num, const bool edge_allocated, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_mesh_faces( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_mesh_faces_ex( struct BVHTreeFromMesh *data, - struct MVert *vert, const bool vert_allocated, - struct MFace *face, const int numFaces, const bool face_allocated, + const struct MVert *vert, const bool vert_allocated, + const struct MFace *face, const int numFaces, const bool face_allocated, const BLI_bitmap *mask, int numFaces_active, float epsilon, int tree_type, int axis); diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h index 9948f21ba90..4876461bfe0 100644 --- a/source/blender/blenkernel/BKE_cdderivedmesh.h +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -79,6 +79,7 @@ DerivedMesh *CDDM_from_curve_displist(struct Object *ob, struct ListBase *dispba */ struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm); struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm); +struct DerivedMesh *CDDM_copy_with_tessface(struct DerivedMesh *dm); /* creates a CDDerivedMesh with the same layer stack configuration as the * given DerivedMesh and containing the requested numbers of elements. diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index d812ab832a1..89adbc4338f 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -139,8 +139,6 @@ void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], cons void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]); void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]); void BKE_boundbox_minmax(const struct BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3]); -struct BoundBox *BKE_boundbox_ensure_minimum_dimensions( - struct BoundBox *bb, struct BoundBox *bb_temp, const float epsilon); struct BoundBox *BKE_object_boundbox_get(struct Object *ob); void BKE_object_dimensions_get(struct Object *ob, float vec[3]); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 1c5ea946f59..9a60eb29957 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -42,6 +42,7 @@ struct Brush; struct ColorBand; struct EnvMap; struct FreestyleLineStyle; +struct ImagePool; struct Lamp; struct Main; struct Material; @@ -133,6 +134,12 @@ struct OceanTex *BKE_texture_ocean_copy(struct OceanTex *ot); bool BKE_texture_dependsOnTime(const struct Tex *texture); bool BKE_texture_is_image_user(const struct Tex *tex); +void BKE_texture_get_value_ex( + const struct Scene *scene, struct Tex *texture, + float *tex_co, struct TexResult *texres, + struct ImagePool *pool, + bool use_color_management); + void BKE_texture_get_value( const struct Scene *scene, struct Tex *texture, float *tex_co, struct TexResult *texres, bool use_color_management); diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index b1dcc40279f..9236a1b5853 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -121,7 +121,7 @@ static bool test_path(char *targetpath, const char *path_base, const char *path_ if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep); else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); - /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */ + /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */ if (folder_name) BLI_make_file_string("/", targetpath, tmppath, folder_name); else diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 0287d6ae9ca..02cc31e5977 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1037,6 +1037,17 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float if (use_dverts) { defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone"); defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * defbase_tot, "defnrToIndex"); + /* TODO(sergey): Some considerations here: + * + * - Make it more generic function, maybe even keep together with chanhash. + * - Check whether keeping this consistent across frames gives speedup. + * - Don't use hash for small armatures. + */ + GHash *idx_hash = BLI_ghash_ptr_new("pose channel index by name"); + int pchan_index = 0; + for (pchan = armOb->pose->chanbase.first; pchan != NULL; pchan = pchan->next, ++pchan_index) { + BLI_ghash_insert(idx_hash, pchan, SET_INT_IN_POINTER(pchan_index)); + } for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) { defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name); /* exclude non-deforming bones */ @@ -1045,10 +1056,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float defnrToPC[i] = NULL; } else { - defnrToPCIndex[i] = BLI_findindex(&armOb->pose->chanbase, defnrToPC[i]); + defnrToPCIndex[i] = GET_INT_FROM_POINTER(BLI_ghash_lookup(idx_hash, defnrToPC[i])); } } } + BLI_ghash_free(idx_hash, NULL, NULL); } } } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index a8670395fc4..afd60102453 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -234,7 +234,7 @@ int BKE_blender_test_break(void) * \note Don't use MEM_mallocN so functions can be registered at any time. * \{ */ -struct AtExitData { +static struct AtExitData { struct AtExitData *next; void (*func)(void *user_data); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 264d87b86f3..5a0006e679f 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -376,6 +376,45 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r } } +#define V3_MUL_ELEM(a, b) \ + (a)[0] * (b)[0], \ + (a)[1] * (b)[1], \ + (a)[2] * (b)[2] + +/* Callback to bvh tree nearest edge to ray. + * The tree must have been built using bvhtree_from_mesh_edges. + * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ +static void mesh_edges_nearest_to_ray( + void *userdata, const float ray_co[3], const float ray_dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct BVHTreeFromMesh *data = userdata; + const MVert *vert = data->vert; + const MEdge *e = &data->edge[index]; + + const float t0[3] = {V3_MUL_ELEM(vert[e->v1].co, scale)}; + const float t1[3] = {V3_MUL_ELEM(vert[e->v2].co, scale)}; + const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; + const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; + + float depth, point[3]; + const float dist_sq = dist_squared_ray_to_seg_v3(origin_sc, dir_sc, t0, t1, point, &depth); + + if (dist_sq < nearest->dist_sq) { + nearest->dist_sq = dist_sq; + nearest->index = index; + + point[0] /= scale[0]; + point[1] /= scale[1]; + point[2] /= scale[2]; + + copy_v3_v3(nearest->co, point); + sub_v3_v3v3(nearest->no, t0, t1); + } +} + +#undef V3_MUL_ELEM + /** \} */ /* @@ -393,8 +432,6 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree( BMEditMesh *em, const int verts_num, const BLI_bitmap *verts_mask, int verts_num_active) { - BVHTree *tree = NULL; - int i; BM_mesh_elem_table_ensure(em->bm, BM_VERT); if (verts_mask) { BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num)); @@ -403,15 +440,14 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree( verts_num_active = verts_num; } - tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); + BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); if (tree) { - BMIter iter; - BMVert *eve; - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + for (int i = 0; i < verts_num; i++) { if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { continue; } + BMVert *eve = BM_vert_at_index(em->bm, i); BLI_bvhtree_insert(tree, i, eve->co, 1); } BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); @@ -423,31 +459,28 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree( static BVHTree *bvhtree_from_mesh_verts_create_tree( float epsilon, int tree_type, int axis, - MVert *vert, const int verts_num, + const MVert *vert, const int verts_num, const BLI_bitmap *verts_mask, int verts_num_active) { - BVHTree *tree = NULL; - int i; - if (vert) { - if (verts_mask) { - BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num)); - } - else { - verts_num_active = verts_num; - } + BLI_assert(vert != NULL); + if (verts_mask) { + BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num)); + } + else { + verts_num_active = verts_num; + } - tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); + BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); - if (tree) { - for (i = 0; i < verts_num; i++) { - if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { - continue; - } - BLI_bvhtree_insert(tree, i, vert[i].co, 1); + if (tree) { + for (int i = 0; i < verts_num; i++) { + if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { + continue; } - BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); - BLI_bvhtree_balance(tree); + BLI_bvhtree_insert(tree, i, vert[i].co, 1); } + BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); + BLI_bvhtree_balance(tree); } return tree; @@ -455,31 +488,24 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree( static void bvhtree_from_mesh_verts_setup_data( BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon, - MVert *vert, const bool vert_allocated) + const MVert *vert, const bool vert_allocated) { memset(data, 0, sizeof(*data)); - if (tree) { - data->tree = tree; - data->cached = is_cached; + data->tree = tree; + data->cached = is_cached; - /* a NULL nearest callback works fine - * remember the min distance to point is the same as the min distance to BV of point */ - data->nearest_callback = NULL; - data->raycast_callback = mesh_verts_spherecast; - data->nearest_to_ray_callback = NULL; + /* a NULL nearest callback works fine + * remember the min distance to point is the same as the min distance to BV of point */ + data->nearest_callback = NULL; + data->raycast_callback = mesh_verts_spherecast; + data->nearest_to_ray_callback = NULL; - data->vert = vert; - data->vert_allocated = vert_allocated; - //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */ + data->vert = vert; + data->vert_allocated = vert_allocated; + //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */ - data->sphere_radius = epsilon; - } - else { - if (vert_allocated) { - MEM_freeN(vert); - } - } + data->sphere_radius = epsilon; } /* Builds a bvh tree where nodes are the vertices of the given em */ @@ -488,11 +514,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex( const BLI_bitmap *verts_mask, int verts_num_active, float epsilon, int tree_type, int axis) { - int vert_num = em->bm->totvert; - BVHTree *tree = bvhtree_from_editmesh_verts_create_tree( epsilon, tree_type, axis, - em, vert_num, verts_mask, verts_num_active); + em, em->bm->totvert, verts_mask, verts_num_active); if (tree) { memset(data, 0, sizeof(*data)); @@ -505,6 +529,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex( return tree; } + BVHTree *bvhtree_from_editmesh_verts( BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis) @@ -515,8 +540,8 @@ BVHTree *bvhtree_from_editmesh_verts( epsilon, tree_type, axis); } - -/* Builds a bvh tree where nodes are the vertices of the given dm */ +/* Builds a bvh tree where nodes are the vertices of the given dm + * and stores the BVHTree in dm->bvhCache */ BVHTree *bvhtree_from_mesh_verts( BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) @@ -556,10 +581,18 @@ BVHTree *bvhtree_from_mesh_verts( /* printf("BVHTree is already build, using cached tree\n"); */ } - /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_verts_setup_data(data, tree, true, epsilon, vert, vert_allocated); - - return data->tree; + if (tree) { + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_verts_setup_data( + data, tree, true, epsilon, vert, vert_allocated); + } + else { + if (vert_allocated) { + MEM_freeN(vert); + } + memset(data, 0, sizeof(*data)); + } + return tree; } /** @@ -569,7 +602,7 @@ BVHTree *bvhtree_from_mesh_verts( * \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_verts_ex( - BVHTreeFromMesh *data, MVert *vert, const int verts_num, const bool vert_allocated, + BVHTreeFromMesh *data, const MVert *vert, const int verts_num, const bool vert_allocated, const BLI_bitmap *verts_mask, int verts_num_active, float epsilon, int tree_type, int axis) { @@ -577,9 +610,10 @@ BVHTree *bvhtree_from_mesh_verts_ex( epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active); /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated); + bvhtree_from_mesh_verts_setup_data( + data, tree, false, epsilon, vert, vert_allocated); - return data->tree; + return tree; } /** \} */ @@ -595,8 +629,6 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree( BMEditMesh *em, const int edges_num, const BLI_bitmap *edges_mask, int edges_num_active) { - BVHTree *tree = NULL; - int i; BM_mesh_elem_table_ensure(em->bm, BM_EDGE); if (edges_mask) { BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num)); @@ -605,9 +637,10 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree( edges_num_active = edges_num; } - tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); if (tree) { + int i; BMIter iter; BMEdge *eed; BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) { @@ -627,6 +660,63 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree( return tree; } +static BVHTree *bvhtree_from_mesh_edges_create_tree( + const MVert *vert, const MEdge *edge, const int edge_num, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis) +{ + if (edges_mask) { + BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num)); + } + else { + edges_num_active = edge_num; + } + BLI_assert(vert != NULL); + BLI_assert(edge != NULL); + + /* Create a bvh-tree of the given target */ + BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + if (tree) { + for (int i = 0; i < edge_num; i++) { + if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) { + continue; + } + float co[2][3]; + copy_v3_v3(co[0], vert[edge[i].v1].co); + copy_v3_v3(co[1], vert[edge[i].v2].co); + + BLI_bvhtree_insert(tree, i, co[0], 2); + } + BLI_bvhtree_balance(tree); + } + + return tree; +} + +static void bvhtree_from_mesh_edges_setup_data( + BVHTreeFromMesh *data, BVHTree *tree, + const bool is_cached, float epsilon, + const MVert *vert, const bool vert_allocated, + const MEdge *edge, const bool edge_allocated) +{ + memset(data, 0, sizeof(*data)); + + data->tree = tree; + + data->cached = is_cached; + + data->nearest_callback = mesh_edges_nearest_point; + data->raycast_callback = mesh_edges_spherecast; + data->nearest_to_ray_callback = mesh_edges_nearest_to_ray; + + data->vert = vert; + data->vert_allocated = vert_allocated; + data->edge = edge; + data->edge_allocated = edge_allocated; + + data->sphere_radius = epsilon; +} + /* Builds a bvh tree where nodes are the edges of the given em */ BVHTree *bvhtree_from_editmesh_edges_ex( BVHTreeFromEditMesh *data, BMEditMesh *em, @@ -651,6 +741,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex( return tree; } + BVHTree *bvhtree_from_editmesh_edges( BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis) @@ -683,27 +774,13 @@ BVHTree *bvhtree_from_mesh_edges( BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES); if (tree == NULL) { - int i; - int numEdges = dm->getNumEdges(dm); - - if (vert != NULL && edge != NULL) { - /* Create a bvh-tree of the given target */ - tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis); - if (tree != NULL) { - for (i = 0; i < numEdges; i++) { - float co[2][3]; - copy_v3_v3(co[0], vert[edge[i].v1].co); - copy_v3_v3(co[1], vert[edge[i].v2].co); - - BLI_bvhtree_insert(tree, i, co[0], 2); - } - BLI_bvhtree_balance(tree); + tree = bvhtree_from_mesh_edges_create_tree( + vert, edge, dm->getNumEdges(dm), + NULL, -1, epsilon, tree_type, axis); - /* Save on cache for later use */ - /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES); - } - } + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES); } BLI_rw_mutex_unlock(&cache_rwlock); } @@ -711,24 +788,10 @@ BVHTree *bvhtree_from_mesh_edges( /* printf("BVHTree is already build, using cached tree\n"); */ } - - /* Setup BVHTreeFromMesh */ - memset(data, 0, sizeof(*data)); - data->tree = tree; - - if (data->tree) { - data->cached = true; - - data->nearest_callback = mesh_edges_nearest_point; - data->raycast_callback = mesh_edges_spherecast; - data->nearest_to_ray_callback = NULL; - - data->vert = vert; - data->vert_allocated = vert_allocated; - data->edge = edge; - data->edge_allocated = edge_allocated; - - data->sphere_radius = epsilon; + if (tree) { + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_edges_setup_data( + data, tree, true, epsilon, vert, vert_allocated, edge, edge_allocated); } else { if (vert_allocated) { @@ -737,8 +800,33 @@ BVHTree *bvhtree_from_mesh_edges( if (edge_allocated) { MEM_freeN(edge); } + memset(data, 0, sizeof(*data)); } - return data->tree; + return tree; +} + +/** + * Builds a bvh tree where nodes are the given edges . + * \param vert/edge_allocated if true, elem freeing will be done when freeing data. + * \param edges_mask if not null, true elements give which vert to add to BVH tree. + * \param edges_num_active if >= 0, number of active edges to add to BVH tree (else will be computed from mask). + */ +BVHTree *bvhtree_from_mesh_edges_ex( + BVHTreeFromMesh *data, + const MVert *vert, const bool vert_allocated, + const MEdge *edge, const int edges_num, const bool edge_allocated, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis) +{ + BVHTree *tree = bvhtree_from_mesh_edges_create_tree( + vert, edge, edges_num, edges_mask, edges_num_active, + epsilon, tree_type, axis); + + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_edges_setup_data( + data, tree, false, epsilon, vert, vert_allocated, edge, edge_allocated); + + return tree; } /** \} */ @@ -751,7 +839,7 @@ BVHTree *bvhtree_from_mesh_edges( static BVHTree *bvhtree_from_mesh_faces_create_tree( float epsilon, int tree_type, int axis, - MVert *vert, MFace *face, const int faces_num, + const MVert *vert, const MFace *face, const int faces_num, const BLI_bitmap *faces_mask, int faces_num_active) { BVHTree *tree = NULL; @@ -795,34 +883,24 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree( static void bvhtree_from_mesh_faces_setup_data( BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon, - MVert *vert, const bool vert_allocated, - MFace *face, const bool face_allocated) + const MVert *vert, const bool vert_allocated, + const MFace *face, const bool face_allocated) { memset(data, 0, sizeof(*data)); - if (tree) { - data->tree = tree; - data->cached = is_cached; + data->tree = tree; + data->cached = is_cached; - data->nearest_callback = mesh_faces_nearest_point; - data->raycast_callback = mesh_faces_spherecast; - data->nearest_to_ray_callback = NULL; + data->nearest_callback = mesh_faces_nearest_point; + data->raycast_callback = mesh_faces_spherecast; + data->nearest_to_ray_callback = NULL; - data->vert = vert; - data->vert_allocated = vert_allocated; - data->face = face; - data->face_allocated = face_allocated; + data->vert = vert; + data->vert_allocated = vert_allocated; + data->face = face; + data->face_allocated = face_allocated; - data->sphere_radius = epsilon; - } - else { - if (vert_allocated) { - MEM_freeN(vert); - } - if (face_allocated) { - MEM_freeN(face); - } - } + data->sphere_radius = epsilon; } /* Builds a bvh tree where nodes are the tesselated faces of the given dm */ @@ -865,10 +943,21 @@ BVHTree *bvhtree_from_mesh_faces( /* printf("BVHTree is already build, using cached tree\n"); */ } - /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_faces_setup_data(data, tree, true, epsilon, vert, vert_allocated, face, face_allocated); - - return data->tree; + if (tree) { + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_faces_setup_data( + data, tree, true, epsilon, vert, vert_allocated, face, face_allocated); + } + else { + if (vert_allocated) { + MEM_freeN(vert); + } + if (face_allocated) { + MEM_freeN(face); + } + memset(data, 0, sizeof(*data)); + } + return tree; } /** @@ -879,8 +968,8 @@ BVHTree *bvhtree_from_mesh_faces( * \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_faces_ex( - BVHTreeFromMesh *data, MVert *vert, const bool vert_allocated, - MFace *face, const int numFaces, const bool face_allocated, + BVHTreeFromMesh *data, const MVert *vert, const bool vert_allocated, + const MFace *face, const int numFaces, const bool face_allocated, const BLI_bitmap *faces_mask, int faces_num_active, float epsilon, int tree_type, int axis) { @@ -890,9 +979,10 @@ BVHTree *bvhtree_from_mesh_faces_ex( faces_mask, faces_num_active); /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_faces_setup_data(data, tree, false, epsilon, vert, vert_allocated, face, face_allocated); + bvhtree_from_mesh_faces_setup_data( + data, tree, false, epsilon, vert, vert_allocated, face, face_allocated); - return data->tree; + return tree; } /** \} */ @@ -1003,34 +1093,21 @@ static void bvhtree_from_mesh_looptri_setup_data( { memset(data, 0, sizeof(*data)); - if (tree) { - data->tree = tree; - data->cached = is_cached; + data->tree = tree; + data->cached = is_cached; - data->nearest_callback = mesh_looptri_nearest_point; - data->raycast_callback = mesh_looptri_spherecast; - data->nearest_to_ray_callback = NULL; + data->nearest_callback = mesh_looptri_nearest_point; + data->raycast_callback = mesh_looptri_spherecast; + data->nearest_to_ray_callback = NULL; - data->vert = vert; - data->vert_allocated = vert_allocated; - data->loop = mloop; - data->loop_allocated = loop_allocated; - data->looptri = looptri; - data->looptri_allocated = looptri_allocated; + data->vert = vert; + data->vert_allocated = vert_allocated; + data->loop = mloop; + data->loop_allocated = loop_allocated; + data->looptri = looptri; + data->looptri_allocated = looptri_allocated; - data->sphere_radius = epsilon; - } - else { - if (vert_allocated) { - MEM_freeN((void *)vert); - } - if (loop_allocated) { - MEM_freeN((void *)mloop); - } - if (looptri_allocated) { - MEM_freeN((void *)looptri); - } - } + data->sphere_radius = epsilon; } /** @@ -1157,14 +1234,28 @@ BVHTree *bvhtree_from_mesh_looptri( /* printf("BVHTree is already build, using cached tree\n"); */ } - /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_looptri_setup_data( - data, tree, true, epsilon, - mvert, vert_allocated, - mloop, loop_allocated, - looptri, looptri_allocated); + if (tree) { + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_looptri_setup_data( + data, tree, true, epsilon, + mvert, vert_allocated, + mloop, loop_allocated, + looptri, looptri_allocated); + } + else { + if (vert_allocated) { + MEM_freeN(mvert); + } + if (loop_allocated) { + MEM_freeN(mloop); + } + if (looptri_allocated) { + MEM_freeN((void *)looptri); + } + memset(data, 0, sizeof(*data)); + } - return data->tree; + return tree; } BVHTree *bvhtree_from_mesh_looptri_ex( @@ -1187,7 +1278,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex( mloop, loop_allocated, looptri, looptri_allocated); - return data->tree; + return tree; } /** \} */ @@ -1207,29 +1298,27 @@ void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data) /* Frees data allocated by a call to bvhtree_from_mesh_*. */ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) { - if (data->tree) { - if (!data->cached) { - BLI_bvhtree_free(data->tree); - } - - if (data->vert_allocated) { - MEM_freeN((void *)data->vert); - } - if (data->edge_allocated) { - MEM_freeN((void *)data->edge); - } - if (data->face_allocated) { - MEM_freeN((void *)data->face); - } - if (data->loop_allocated) { - MEM_freeN((void *)data->loop); - } - if (data->looptri_allocated) { - MEM_freeN((void *)data->looptri); - } + if (data->tree && !data->cached) { + BLI_bvhtree_free(data->tree); + } - memset(data, 0, sizeof(*data)); + if (data->vert_allocated) { + MEM_freeN((void *)data->vert); } + if (data->edge_allocated) { + MEM_freeN((void *)data->edge); + } + if (data->face_allocated) { + MEM_freeN((void *)data->face); + } + if (data->loop_allocated) { + MEM_freeN((void *)data->loop); + } + if (data->looptri_allocated) { + MEM_freeN((void *)data->looptri); + } + + memset(data, 0, sizeof(*data)); } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index fc3e358cb25..7042b46330b 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -2398,13 +2398,16 @@ DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bo use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris); } -static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces) +static DerivedMesh *cddm_copy_ex(DerivedMesh *source, + const bool need_tessface_data, + const bool faces_from_tessfaces) { + const bool copy_tessface_data = (faces_from_tessfaces || need_tessface_data); CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm"); DerivedMesh *dm = &cddm->dm; int numVerts = source->numVertData; int numEdges = source->numEdgeData; - int numTessFaces = source->numTessFaceData; + int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0; int numLoops = source->numLoopData; int numPolys = source->numPolyData; @@ -2414,20 +2417,29 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces) source->getVertDataArray(source, CD_ORIGINDEX); source->getEdgeDataArray(source, CD_ORIGINDEX); source->getPolyDataArray(source, CD_ORIGINDEX); + if (copy_tessface_data) { + source->getTessFaceDataArray(source, CD_ORIGINDEX); + } /* this initializes dm, and copies all non mvert/medge/mface layers */ - DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, - faces_from_tessfaces ? numTessFaces : 0, + DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys); dm->deformedOnly = source->deformedOnly; dm->cd_flag = source->cd_flag; dm->dirty = source->dirty; - /* Tessellation data is never copied, so tag it here. */ - dm->dirty |= DM_DIRTY_TESS_CDLAYERS; + /* Tessellation data is never copied, so tag it here. + * Only tag dirty layers if we really ignored tessellation faces. + */ + if (!copy_tessface_data) { + dm->dirty |= DM_DIRTY_TESS_CDLAYERS; + } CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts); CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges); + if (copy_tessface_data) { + CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces); + } /* now add mvert/medge/mface layers */ cddm->mvert = source->dupVertArray(source); @@ -2435,17 +2447,16 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces) CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts); CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges); - - if (!faces_from_tessfaces) { - DM_DupPolys(source, dm); - } - else { - source->getTessFaceDataArray(source, CD_ORIGINDEX); - CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces); + if (faces_from_tessfaces || copy_tessface_data) { cddm->mface = source->dupTessFaceArray(source); CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces); + } + if (!faces_from_tessfaces) { + DM_DupPolys(source, dm); + } + else { CDDM_tessfaces_to_faces(dm); } @@ -2457,12 +2468,17 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces) DerivedMesh *CDDM_copy(DerivedMesh *source) { - return cddm_copy_ex(source, 0); + return cddm_copy_ex(source, false, false); } DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source) { - return cddm_copy_ex(source, 1); + return cddm_copy_ex(source, false, true); +} + +DerivedMesh *CDDM_copy_with_tessface(DerivedMesh *source) +{ + return cddm_copy_ex(source, true, false); } /* note, the CD_ORIGINDEX layers are all 0, so if there is a direct diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 98d37fb07bf..c9f0b8ec9ca 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -2595,7 +2595,7 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT)) return false; -#undef TEST_RET +#undef LAYER_CMP /* if no layers are on either CustomData's, * then there was nothing to do... */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index a2d94ccc478..318f6480aaf 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -3159,7 +3159,7 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons struct ImBuf *ibuf; char name[FILE_MAX]; int flag; - ImageUser iuser_t; + ImageUser iuser_t = {0}; /* XXX temp stuff? */ if (ima->lastframe != frame) @@ -3167,8 +3167,12 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons ima->lastframe = frame; - if (iuser) + if (iuser) { iuser_t = *iuser; + } + else { + /* TODO(sergey): Do we need to initialize something here? */ + } iuser_t.view = view_id; BKE_image_user_file_path(&iuser_t, ima, name); diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index d098366aef4..69a2067f4e6 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -174,15 +174,10 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local) void BKE_lamp_free(Lamp *la) { - MTex *mtex; int a; for (a = 0; a < MAX_MTEX; a++) { - mtex = la->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(la->mtex[a]); } BKE_animdata_free((ID *)la, false); @@ -193,6 +188,7 @@ void BKE_lamp_free(Lamp *la) if (la->nodetree) { ntreeFreeTree(la->nodetree); MEM_freeN(la->nodetree); + la->nodetree = NULL; } BKE_previewimg_free(&la->preview); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index af02e02b017..24a01b17e53 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -66,6 +66,11 @@ #include "DEG_depsgraph.h" +/* Define for cases when you want extra validation of mesh + * after certain modifications. + */ +// #undef VALIDATE_MESH + enum { MESHCMP_DVERT_WEIGHTMISMATCH = 1, MESHCMP_DVERT_GROUPMISMATCH, @@ -2090,104 +2095,296 @@ void BKE_mesh_calc_normals_split(Mesh *mesh) } } -/* Spli faces based on the edge angle. - * Matches behavior of face splitting in render engines. +/* Split faces helper functions. */ + +enum { + /* Vertex is adjacent to some loop which normal is different, + * hence split of this vertex is required. + */ + SPLIT_VERT_NEED_SPLIT = (1 << 0), + /* Original vertex was already re-used by split logic. */ + SPLIT_VERT_REUSED = (1 << 1), +}; +enum { + /* Edge is adjacent to any of vertex tagged for split. + */ + SPLIT_EDGE_NEED_SPLIT = (1 << 0), + /* Original edge was already re-used by split logic. */ + SPLIT_EDGE_REUSED = (1 << 1), +}; + +/* Tag vertices which normals are not equal to any adjacent loop + * and hence split on that vertex is required. + * + * Returns truth if any of vertex needs to be split. */ -void BKE_mesh_split_faces(Mesh *mesh) +static bool split_faces_tag_verts(const Mesh *mesh, uchar *vert_flags) +{ + const int num_polys = mesh->totpoly; + const MVert *mvert = mesh->mvert; + const MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + float (*lnors)[3] = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + bool has_split_verts = false; + for (int poly = 0; poly < num_polys; poly++) { + const MPoly *mp = &mpoly[poly]; + for (int loop = 0; loop < mp->totloop; loop++) { + const MLoop *ml = &mloop[mp->loopstart + loop]; + const MVert *mv = &mvert[ml->v]; + float vn[3]; + normal_short_to_float_v3(vn, mv->no); + if (len_squared_v3v3(vn, lnors[mp->loopstart + loop]) > FLT_EPSILON) { + vert_flags[ml->v] |= SPLIT_VERT_NEED_SPLIT; + has_split_verts = true; + } + } + } + return has_split_verts; +} + +/* Count number of new vertices to be added. + * + * Note that one of the loop where split is required will re-use + * it's vertex in order to avoid creation of loose vertices. + */ +static int split_faces_count_new_verts(const Mesh *mesh, uchar *vert_flags) +{ + const int num_polys = mesh->totpoly; + const MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + int num_new_verts = 0; + for (int poly = 0; poly < num_polys; poly++) { + const MPoly *mp = &mpoly[poly]; + for (int loop = 0; loop < mp->totloop; loop++) { + const MLoop *ml = &mloop[mp->loopstart + loop]; + if (vert_flags[ml->v] & SPLIT_VERT_NEED_SPLIT) { + if (vert_flags[ml->v] & SPLIT_VERT_REUSED) { + ++num_new_verts; + } + else { + vert_flags[ml->v] |= SPLIT_VERT_REUSED; + } + } + } + } + return num_new_verts; +} + +/* Tag edges which are adjacent to at least one vertex tagged for split. */ +static void split_faces_tag_edges(Mesh *mesh, + const uchar *vert_flags, + uchar *edge_flags) +{ + const int num_polys = mesh->totpoly; + const MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + for (int poly = 0; poly < num_polys; poly++) { + const MPoly *mp = &mpoly[poly]; + int loop_prev = mp->totloop - 1; + for (int loop = 0; loop < mp->totloop; loop++) { + const int poly_loop_prev = mp->loopstart + loop_prev; + const MLoop *ml = &mloop[mp->loopstart + loop]; + const MLoop *ml_prev = &mloop[poly_loop_prev]; + const int mv_flag = vert_flags[ml->v]; + const int mv_prev_flag = vert_flags[ml_prev->v]; + bool need_split = false; + if (mv_flag & SPLIT_VERT_NEED_SPLIT) { + if (mv_prev_flag & SPLIT_VERT_NEED_SPLIT) { + /* Create new edge between twp split vertices. */ + need_split = true; + } + else { + /* Create new edge from existing vertex to a split one. */ + need_split = true; + } + } + else if (mv_prev_flag & SPLIT_VERT_NEED_SPLIT) { + /* Create new edge from split vertex to existing one. */ + need_split = true; + } + if (need_split) { + edge_flags[ml_prev->e] |= SPLIT_EDGE_NEED_SPLIT; + } + loop_prev = loop; + } + } +} + +/* Count number of new edges to be added. + * + * Note that one of the loop where split is required will re-use + * it's edge in order to avoid creation of loose edges. + */ +static int split_faces_count_new_edges(const Mesh *mesh, uchar *edge_flags) { - const int num_verts = mesh->totvert; - const int num_edges = mesh->totedge; + const int num_polys = mesh->totpoly; + const MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + int num_new_edges = 0; + for (int poly = 0; poly < num_polys; poly++) { + const MPoly *mp = &mpoly[poly]; + for (int loop = 0; loop < mp->totloop; loop++) { + const MLoop *ml = &mloop[mp->loopstart + loop]; + if (edge_flags[ml->e] & SPLIT_EDGE_NEED_SPLIT) { + if (edge_flags[ml->e] & SPLIT_EDGE_REUSED) { + ++num_new_edges; + } + else { + edge_flags[ml->e] |= SPLIT_EDGE_REUSED; + } + } + } + } + return num_new_edges; +} + +/* Perform actual split of vertices. + * + * NOTE: Will leave edges in inconsistent state. + */ +static void split_faces_split_verts(Mesh *mesh, + const int num_new_verts, + uchar *vert_flags) +{ + const int num_verts = mesh->totvert - num_new_verts; const int num_polys = mesh->totpoly; MVert *mvert = mesh->mvert; + MLoop *mloop = mesh->mloop; + MPoly *mpoly = mesh->mpoly; + const float (*lnors)[3] = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + int num_added_verts = 0; + /* Clear reused flag, we need it again. */ + for (int i = 0; i < num_verts; ++i) { + vert_flags[i] &= ~SPLIT_VERT_REUSED; + } + for (int poly = 0; poly < num_polys; poly++) { + MPoly *mp = &mpoly[poly]; + /* First we split all vertices to get proper flag whether they are + * split or not for all of them before handling edges. + */ + for (int loop = 0; loop < mp->totloop; loop++) { + int poly_loop = mp->loopstart + loop; + MLoop *ml = &mloop[poly_loop]; + if (vert_flags[ml->v] & SPLIT_VERT_NEED_SPLIT) { + if ((vert_flags[ml->v] & SPLIT_VERT_REUSED) == 0) { + /* Ignore first split on vertex, re-use it instead. */ + vert_flags[ml->v] |= SPLIT_VERT_REUSED; + continue; + } + /* Create new vertex. */ + int new_vert = num_verts + num_added_verts; + CustomData_copy_data(&mesh->vdata, &mesh->vdata, + ml->v, new_vert, 1); + normal_float_to_short_v3(mvert[new_vert].no, + lnors[poly_loop]); + ml->v = new_vert; + num_added_verts++; + } + } + } +} + +/* Perform actual split of edges. + * + * NOTE: Will correct all edges. + */ +static void split_faces_split_edges(Mesh *mesh, + const int num_new_edges, + uchar *edge_flags) +{ + const int num_edges = mesh->totedge - num_new_edges; + const int num_polys = mesh->totpoly; MEdge *medge = mesh->medge; MLoop *mloop = mesh->mloop; MPoly *mpoly = mesh->mpoly; - float (*lnors)[3]; - int poly, num_new_verts = 0; + int num_added_edges = 0; + /* Clear reused flag, we need it again. */ + for (int i = 0; i < num_edges; ++i) { + edge_flags[i] &= ~SPLIT_EDGE_REUSED; + } + for (int poly = 0; poly < num_polys; poly++) { + MPoly *mp = &mpoly[poly]; + for (int loop = 0, loop_prev = mp->totloop - 1; loop < mp->totloop; loop++) { + const int poly_loop_prev = mp->loopstart + loop_prev; + const MLoop *ml = &mloop[mp->loopstart + loop]; + MLoop *ml_prev = &mloop[poly_loop_prev]; + MEdge *me_prev = &medge[ml_prev->e]; + if (edge_flags[ml_prev->e] & SPLIT_EDGE_NEED_SPLIT) { + if ((edge_flags[ml_prev->e] & SPLIT_EDGE_REUSED) == 0) { + edge_flags[ml_prev->e] |= SPLIT_EDGE_REUSED; + me_prev->v1 = ml_prev->v; + me_prev->v2 = ml->v; + } + else { + const int index = num_edges + num_added_edges; + CustomData_copy_data(&mesh->edata, &mesh->edata, + ml_prev->e, index, 1); + MEdge *me_new = &medge[index]; + me_new->v1 = ml_prev->v; + me_new->v2 = ml->v; + ml_prev->e = index; + num_added_edges++; + } + } + loop_prev = loop; + } + } +} + +/* Split faces based on the edge angle. + * Matches behavior of face splitting in render engines. + */ +void BKE_mesh_split_faces(Mesh *mesh) +{ + const int num_verts = mesh->totvert; + const int num_edges = mesh->totedge; + const int num_polys = mesh->totpoly; if ((mesh->flag & ME_AUTOSMOOTH) == 0) { return; } + if (num_polys == 0) { + return; + } BKE_mesh_tessface_clear(mesh); /* Compute loop normals if needed. */ if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { BKE_mesh_calc_normals_split(mesh); } - lnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); - /* Count number of vertices to be split. */ - for (poly = 0; poly < num_polys; poly++) { - MPoly *mp = &mpoly[poly]; - int loop; - for (loop = 0; loop < mp->totloop; loop++) { - MLoop *ml = &mloop[mp->loopstart + loop]; - MVert *mv = &mvert[ml->v]; - float vn[3]; - normal_short_to_float_v3(vn, mv->no); - if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) { - num_new_verts++; - } - } - } - if (num_new_verts == 0) { - /* No new vertices are to be added, can do early exit. */ + /* Runtime flags. */ + uchar *vert_flags = MEM_callocN(sizeof(*vert_flags) * num_verts, + "split faces vert flags"); + /* Tag vertces and check whether anything is tagged. */ + if (!split_faces_tag_verts(mesh, vert_flags)) { + /* No new vertices to be split added, can do early exit. */ + MEM_freeN(vert_flags); return; } + /* Flush vertex flags to edges. */ + uchar *edge_flags = MEM_callocN(sizeof(*edge_flags) * num_edges, + "split faces edge flags"); + split_faces_tag_edges(mesh, vert_flags, edge_flags); + /* Count amount of new geometry. */ + int num_new_verts = split_faces_count_new_verts(mesh, vert_flags); + int num_new_edges = split_faces_count_new_edges(mesh, edge_flags); /* Reallocate all vert and edge related data. */ mesh->totvert += num_new_verts; - mesh->totedge += 2 * num_new_verts; + mesh->totedge += num_new_edges; CustomData_realloc(&mesh->vdata, mesh->totvert); CustomData_realloc(&mesh->edata, mesh->totedge); /* Update pointers to a newly allocated memory. */ BKE_mesh_update_customdata_pointers(mesh, false); - mvert = mesh->mvert; - medge = mesh->medge; - /* Perform actual vertex split. */ - num_new_verts = 0; - for (poly = 0; poly < num_polys; poly++) { - MPoly *mp = &mpoly[poly]; - int loop; - for (loop = 0; loop < mp->totloop; loop++) { - int poly_loop = mp->loopstart + loop; - MLoop *ml = &mloop[poly_loop]; - MVert *mv = &mvert[ml->v]; - float vn[3]; - normal_short_to_float_v3(vn, mv->no); - if (!equals_v3v3(vn, lnors[mp->loopstart + loop])) { - int poly_loop_prev = mp->loopstart + (loop + mp->totloop - 1) % mp->totloop; - MLoop *ml_prev = &mloop[poly_loop_prev]; - int new_edge_prev, new_edge; - /* Cretae new vertex. */ - int new_vert = num_verts + num_new_verts; - CustomData_copy_data(&mesh->vdata, &mesh->vdata, - ml->v, new_vert, 1); - normal_float_to_short_v3(mvert[new_vert].no, - lnors[poly_loop]); - /* Create new edges. */ - new_edge_prev = num_edges + 2 * num_new_verts; - new_edge = num_edges + 2 * num_new_verts + 1; - CustomData_copy_data(&mesh->edata, &mesh->edata, - ml_prev->e, new_edge_prev, 1); - CustomData_copy_data(&mesh->edata, &mesh->edata, - ml->e, new_edge, 1); - if (medge[new_edge_prev].v1 == ml->v) { - medge[new_edge_prev].v1 = new_vert; - } - else { - medge[new_edge_prev].v2 = new_vert; - } - if (medge[new_edge].v1 == ml->v) { - medge[new_edge].v1 = new_vert; - } - else { - medge[new_edge].v2 = new_vert; - } - - ml->v = new_vert; - ml_prev->e = new_edge_prev; - ml->e = new_edge; - num_new_verts++; - } - } - } + /* Perform actual split of vertices and adjacent edges. */ + split_faces_split_verts(mesh, num_new_verts, vert_flags); + split_faces_split_edges(mesh, num_new_edges, edge_flags); + /* CD_NORMAL is expected to be temporary only, and it's invalid at + * this point anyway. + */ + CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); + MEM_freeN(vert_flags); + MEM_freeN(edge_flags); +#ifdef VALIDATE_MESH + BKE_mesh_validate(mesh, true, true); +#endif } /* settings: 1 - preview, 2 - render */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ff8be5892e9..6e754755cf3 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2236,66 +2236,6 @@ void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3], } } -/** - * Returns a BBox which each dimensions are at least epsilon. - * \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range. - * - * \param bb the input bbox to check. - * \param bb_temp the temp bbox to modify (\a bb content is never changed). - * \param epsilon the minimum dimension to ensure. - * \return either bb (if nothing needed to be changed) or bb_temp. - */ -BoundBox *BKE_boundbox_ensure_minimum_dimensions(BoundBox *bb, BoundBox *bb_temp, const float epsilon) -{ - if (fabsf(bb->vec[0][0] - bb->vec[4][0]) < epsilon) { - /* Flat along X axis... */ - *bb_temp = *bb; - bb = bb_temp; - bb->vec[0][0] -= epsilon; - bb->vec[1][0] -= epsilon; - bb->vec[2][0] -= epsilon; - bb->vec[3][0] -= epsilon; - bb->vec[4][0] += epsilon; - bb->vec[5][0] += epsilon; - bb->vec[6][0] += epsilon; - bb->vec[7][0] += epsilon; - } - - if (fabsf(bb->vec[0][1] - bb->vec[3][1]) < epsilon) { - /* Flat along Y axis... */ - if (bb != bb_temp) { - *bb_temp = *bb; - bb = bb_temp; - } - bb->vec[0][1] -= epsilon; - bb->vec[1][1] -= epsilon; - bb->vec[4][1] -= epsilon; - bb->vec[5][1] -= epsilon; - bb->vec[2][1] += epsilon; - bb->vec[3][1] += epsilon; - bb->vec[6][1] += epsilon; - bb->vec[7][1] += epsilon; - } - - if (fabsf(bb->vec[0][2] - bb->vec[1][2]) < epsilon) { - /* Flat along Z axis... */ - if (bb != bb_temp) { - *bb_temp = *bb; - bb = bb_temp; - } - bb->vec[0][2] -= epsilon; - bb->vec[3][2] -= epsilon; - bb->vec[4][2] -= epsilon; - bb->vec[7][2] -= epsilon; - bb->vec[1][2] += epsilon; - bb->vec[2][2] += epsilon; - bb->vec[5][2] += epsilon; - bb->vec[6][2] += epsilon; - } - - return bb; -} - BoundBox *BKE_object_boundbox_get(Object *ob) { BoundBox *bb = NULL; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 1ea27558545..228ae6afaba 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -633,8 +633,9 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa data->childcachebufs.last = psys->childcachebufs.last; data->totchildcache = psys->totchildcache; - if (psmd->dm_final) - data->dm = CDDM_copy(psmd->dm_final); + if (psmd->dm_final) { + data->dm = CDDM_copy_with_tessface(psmd->dm_final); + } data->totdmvert = psmd->totdmvert; data->totdmedge = psmd->totdmedge; data->totdmface = psmd->totdmface; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 1d2f5aee440..6a491ba5ec4 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -480,55 +480,74 @@ void BKE_sequencer_editing_free(Scene *scene) static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf) { - if (ibuf->rect_float) { + if (ibuf->rect != NULL) { + IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name); + } + if (ibuf->rect_float != NULL) { IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name); } } void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float) { - const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); + /* Early output check: if both buffers are NULL we have nothing to convert. */ + if (ibuf->rect_float == NULL && ibuf->rect == NULL) { + return; + } + /* Get common conversion settings. */ const char *to_colorspace = scene->sequencer_colorspace_settings.name; - const char *float_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); - - if (!ibuf->rect_float) { - if (ibuf->rect) { - const char *byte_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); - if (make_float || !STREQ(to_colorspace, byte_colorspace)) { - /* If byte space is not in sequencer's working space, we deliver float color space, - * this is to to prevent data loss. - */ - - /* when converting byte buffer to float in sequencer we need to make float - * buffer be in sequencer's working space, which is currently only doable - * from linear space. - */ - - /* - * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's - */ - - IMB_float_from_rect(ibuf); - } - else { - return; - } + /* Perform actual conversion logic. */ + if (ibuf->rect_float == NULL) { + /* We are not requested to give float buffer and byte buffer is already + * in thee required colorspace. Can skip doing anything here. + */ + const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); + if (!make_float && STREQ(from_colorspace, to_colorspace)) { + return; + } + if (false) { + /* The idea here is to provide as fast playback as possible and + * enforcing float buffer here (a) uses more cache memory (b) might + * make some other effects slower to apply. + * + * However, this might also have negative effect by adding weird + * artifacts which will then not happen in final render. + */ + IMB_colormanagement_transform_byte_threaded( + (unsigned char*)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels, + from_colorspace, to_colorspace); } else { - return; + /* We perform conversion to a float buffer so we don't worry about + * precision loss. + */ + imb_addrectfloatImBuf(ibuf); + IMB_colormanagement_transform_from_byte_threaded( + ibuf->rect_float, (unsigned char*)ibuf->rect, + ibuf->x, ibuf->y, ibuf->channels, + from_colorspace, to_colorspace); + /* We don't need byte buffer anymore. */ + imb_freerectImBuf(ibuf); } } - - if (from_colorspace && from_colorspace[0] != '\0') { - if (ibuf->rect) + else { + const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); + /* Unknown input color space, can't perform conversion. */ + if (from_colorspace == NULL || from_colorspace[0] == '\0') { + return; + } + /* We don't want both byte and float buffers around: they'll either run + * out of sync or conversion of byte buffer will loose precision in there. + */ + if (ibuf->rect != NULL) { imb_freerectImBuf(ibuf); - - if (!STREQ(float_colorspace, to_colorspace)) { - IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, true); - sequencer_imbuf_assign_spaces(scene, ibuf); } + IMB_colormanagement_transform_threaded(ibuf->rect_float, + ibuf->x, ibuf->y, ibuf->channels, + from_colorspace, to_colorspace, + true); } + sequencer_imbuf_assign_spaces(scene, ibuf); } void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf) diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 22288127119..8469351c54a 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -147,12 +147,12 @@ void BKE_sound_free(bSound *sound) BKE_sound_free_waveform(sound); +#endif /* WITH_AUDASPACE */ if (sound->spinlock) { BLI_spin_end(sound->spinlock); MEM_freeN(sound->spinlock); sound->spinlock = NULL; - } -#endif /* WITH_AUDASPACE */ + } } void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 88575c7d3be..298790a9e9b 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1935,7 +1935,7 @@ void txt_do_undo(Text *text) int op = text->undo_buf[text->undo_pos]; int prev_flags; unsigned int linep; - unsigned int uchar; + unsigned int uni_char; unsigned int curln, selln; unsigned short curc, selc; unsigned short charp; @@ -1971,14 +1971,14 @@ void txt_do_undo(Text *text) case UNDO_BS_3: case UNDO_BS_4: charp = op - UNDO_BS_1 + 1; - uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); /* get and restore the cursors */ txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - txt_add_char(text, uchar); + txt_add_char(text, uni_char); text->undo_pos--; break; @@ -1988,14 +1988,14 @@ void txt_do_undo(Text *text) case UNDO_DEL_3: case UNDO_DEL_4: charp = op - UNDO_DEL_1 + 1; - uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); /* get and restore the cursors */ txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - txt_add_char(text, uchar); + txt_add_char(text, uni_char); txt_move_left(text, 0); @@ -2163,7 +2163,7 @@ void txt_do_redo(Text *text) char *buf; unsigned int linep; unsigned short charp; - unsigned int uchar; + unsigned int uni_uchar; unsigned int curln, selln; unsigned short curc, selc; @@ -2190,9 +2190,9 @@ void txt_do_redo(Text *text) txt_move_to(text, curln, curc, 1); charp = op - UNDO_INSERT_1 + 1; - uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp); - txt_add_char(text, uchar); + txt_add_char(text, uni_uchar); break; case UNDO_BS_1: diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 2d3ecad19ad..60990c03b0e 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -1485,9 +1485,11 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture) /* ------------------------------------------------------------------------- */ -void BKE_texture_get_value( +void BKE_texture_get_value_ex( const Scene *scene, Tex *texture, - float *tex_co, TexResult *texres, bool use_color_management) + float *tex_co, TexResult *texres, + struct ImagePool *pool, + bool use_color_management) { int result_type; bool do_color_manage = false; @@ -1497,7 +1499,7 @@ void BKE_texture_get_value( } /* no node textures for now */ - result_type = multitex_ext_safe(texture, tex_co, texres, NULL, do_color_manage, false); + result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false); /* if the texture gave an RGB value, we assume it didn't give a valid * intensity, since this is in the context of modifiers don't use perceptual color conversion. @@ -1510,3 +1512,10 @@ void BKE_texture_get_value( copy_v3_fl(&texres->tr, texres->tin); } } + +void BKE_texture_get_value( + const Scene *scene, Tex *texture, + float *tex_co, TexResult *texres, bool use_color_management) +{ + BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management); +} diff --git a/source/blender/blenlib/BLI_dynlib.h b/source/blender/blenlib/BLI_dynlib.h index 7d5eb888021..310db9ea051 100644 --- a/source/blender/blenlib/BLI_dynlib.h +++ b/source/blender/blenlib/BLI_dynlib.h @@ -34,7 +34,7 @@ typedef struct DynamicLibrary DynamicLibrary; -DynamicLibrary *BLI_dynlib_open(char *name); +DynamicLibrary *BLI_dynlib_open(const char *name); void *BLI_dynlib_find_symbol(DynamicLibrary *lib, const char *symname); char *BLI_dynlib_get_error_as_string(DynamicLibrary *lib); void BLI_dynlib_close(DynamicLibrary *lib); diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h index 7929e1d6551..9d8222c575d 100644 --- a/source/blender/blenlib/BLI_sys_types.h +++ b/source/blender/blenlib/BLI_sys_types.h @@ -80,6 +80,11 @@ typedef uint64_t u_int64_t; #include <stddef.h> /* size_t define */ #include <stdbool.h> +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef unsigned char uchar; + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/PIL_time_utildefines.h b/source/blender/blenlib/PIL_time_utildefines.h index 9157e04a7bf..412cfb3a090 100644 --- a/source/blender/blenlib/PIL_time_utildefines.h +++ b/source/blender/blenlib/PIL_time_utildefines.h @@ -80,9 +80,10 @@ } \ const float _delta_##var = TIMEIT_VALUE(var); \ _sum_##var += _delta_##var; \ + _num_##var++; \ printf("time end (" #var "): %.6f" " " AT "\n", _delta_##var); \ - printf("time averaged (" #var "): %.6f" " " AT "\n", \ - (_sum_##var / ++_num_##var)); \ + printf("time averaged (" #var "): %.6f (total: %.6f, in %d runs)\n", \ + (_sum_##var / _num_##var), _sum_##var, (int)_num_##var); \ fflush(stdout); \ } (void)0 diff --git a/source/blender/blenlib/intern/dynlib.c b/source/blender/blenlib/intern/dynlib.c index b47c2ee60a6..51b91fb360f 100644 --- a/source/blender/blenlib/intern/dynlib.c +++ b/source/blender/blenlib/intern/dynlib.c @@ -50,7 +50,7 @@ struct DynamicLibrary { #include "utf_winfunc.h" #include "utfconv.h" -DynamicLibrary *BLI_dynlib_open(char *name) +DynamicLibrary *BLI_dynlib_open(const char *name) { DynamicLibrary *lib; void *handle; @@ -106,7 +106,7 @@ void BLI_dynlib_close(DynamicLibrary *lib) #include <dlfcn.h> -DynamicLibrary *BLI_dynlib_open(char *name) +DynamicLibrary *BLI_dynlib_open(const char *name) { DynamicLibrary *lib; void *handle = dlopen(name, RTLD_LAZY); diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c index 8d9881e4539..2969b0eccf4 100644 --- a/source/blender/blenlib/intern/polyfill2d.c +++ b/source/blender/blenlib/intern/polyfill2d.c @@ -21,8 +21,15 @@ /** \file blender/blenlib/intern/polyfill2d.c * \ingroup bli * - * A simple implementation of the ear cutting algorithm - * to triangulate simple polygons without holes. + * An ear clipping algorithm to triangulate single boundary polygons. + * + * Details: + * + * - The algorithm guarantees all triangles are assigned (number of coords - 2) + * and that triangles will have non-overlapping indices (even for degenerate geometry). + * - Self-intersections are considered degenerate (resulting triangles will overlap). + * - While multiple polygons aren't supported, holes can still be defined using *key-holes* + * (where the polygon doubles back on its self with *exactly* matching coordinates). * * \note * @@ -74,6 +81,12 @@ typedef signed char eSign; #ifdef USE_KDTREE /** + * Spatial optimization for point-in-triangle intersection checks. + * The simple version of this algorithm is ``O(n^2)`` complexity + * (every point needing to check the triangle defined by every other point), + * Using a binary-tree reduces the complexity to ``O(n log n)`` + * plus some overhead of creating the tree. + * * This is a single purpose KDTree based on BLI_kdtree with some modifications * to better suit polyfill2d. * diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 6264336c096..7ea79fc5557 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -10395,6 +10395,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) else { mainptr->curlib->filedata = NULL; mainptr->curlib->id.tag |= LIB_TAG_MISSING; + /* Set lib version to current main one... Makes assert later happy. */ + mainptr->versionfile = mainptr->curlib->versionfile = mainl->versionfile; + mainptr->subversionfile = mainptr->curlib->subversionfile = mainl->subversionfile; } if (fd == NULL) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 7b8b95f0005..998d4161c2f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -78,7 +78,7 @@ * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional). * - write #GLOB (#FileGlobal struct) (some global vars). * - write #DNA1 (#SDNA struct) - * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``. + * - write #USER (#UserDef struct) if filename is ``~/.config/blender/X.XX/config/startup.blend``. */ @@ -799,22 +799,18 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) static void write_actions(WriteData *wd, ListBase *idbase) { - bAction *act; - bActionGroup *grp; - TimeMarker *marker; - - for (act = idbase->first; act; act = act->id.next) { + for (bAction *act = idbase->first; act; act = act->id.next) { if (act->id.us > 0 || wd->current) { writestruct(wd, ID_AC, bAction, 1, act); write_iddata(wd, &act->id); write_fcurves(wd, &act->curves); - for (grp = act->groups.first; grp; grp = grp->next) { + for (bActionGroup *grp = act->groups.first; grp; grp = grp->next) { writestruct(wd, DATA, bActionGroup, 1, grp); } - for (marker = act->markers.first; marker; marker = marker->next) { + for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) { writestruct(wd, DATA, TimeMarker, 1, marker); } } @@ -1280,13 +1276,7 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches) } static void write_particlesettings(WriteData *wd, ListBase *idbase) { - ParticleSettings *part; - ParticleDupliWeight *dw; - GroupObject *go; - int a; - - part = idbase->first; - while (part) { + for (ParticleSettings *part = idbase->first; part; part = part->id.next) { if (part->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_PA, ParticleSettings, 1, part); @@ -1306,24 +1296,23 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) write_curvemapping(wd, part->roughcurve); } - dw = part->dupliweights.first; - for (; dw; dw = dw->next) { + for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) { /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */ if (dw->ob != NULL) { dw->index = 0; if (part->dup_group) { /* can be NULL if lining fails or set to None */ - for (go = part->dup_group->gobject.first; go && go->ob != dw->ob; go = go->next, dw->index++); + for (GroupObject *go = part->dup_group->gobject.first; + go && go->ob != dw->ob; + go = go->next, dw->index++); } } writestruct(wd, DATA, ParticleDupliWeight, 1, dw); } if (part->boids && part->phystype == PART_PHYS_BOIDS) { - BoidState *state = part->boids->states.first; - writestruct(wd, DATA, BoidSettings, 1, part->boids); - for (; state; state = state->next) { + for (BoidState *state = part->boids->states.first; state; state = state->next) { write_boid_state(wd, state); } } @@ -1331,13 +1320,12 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid); } - for (a = 0; a < MAX_MTEX; a++) { + for (int a = 0; a < MAX_MTEX; a++) { if (part->mtex[a]) { writestruct(wd, DATA, MTex, 1, part->mtex[a]); } } } - part = part->id.next; } } static void write_particlesystems(WriteData *wd, ListBase *particles) @@ -1835,10 +1823,7 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) static void write_objects(WriteData *wd, ListBase *idbase) { - Object *ob; - - ob = idbase->first; - while (ob) { + for (Object *ob = idbase->first; ob; ob = ob->id.next) { if (ob->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_OB, Object, 1, ob); @@ -1894,11 +1879,9 @@ static void write_objects(WriteData *wd, ListBase *idbase) writelist(wd, DATA, LinkData, &ob->pc_ids); writelist(wd, DATA, LodLevel, &ob->lodlevels); - } - write_previews(wd, ob->preview); - - ob = ob->id.next; + write_previews(wd, ob->preview); + } } mywrite_flush(wd); @@ -1907,26 +1890,19 @@ static void write_objects(WriteData *wd, ListBase *idbase) static void write_vfonts(WriteData *wd, ListBase *idbase) { - VFont *vf; - PackedFile *pf; - - vf = idbase->first; - while (vf) { + for (VFont *vf = idbase->first; vf; vf = vf->id.next) { if (vf->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_VF, VFont, 1, vf); write_iddata(wd, &vf->id); /* direct data */ - if (vf->packedfile) { - pf = vf->packedfile; + PackedFile *pf = vf->packedfile; writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } - - vf = vf->id.next; } mywrite_flush(wd); @@ -1935,11 +1911,7 @@ static void write_vfonts(WriteData *wd, ListBase *idbase) static void write_keys(WriteData *wd, ListBase *idbase) { - Key *key; - KeyBlock *kb; - - key = idbase->first; - while (key) { + for (Key *key = idbase->first; key; key = key->id.next) { if (key->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_KE, Key, 1, key); @@ -1950,17 +1922,13 @@ static void write_keys(WriteData *wd, ListBase *idbase) } /* direct data */ - kb = key->block.first; - while (kb) { + for (KeyBlock *kb = key->block.first; kb; kb = kb->next) { writestruct(wd, DATA, KeyBlock, 1, kb); if (kb->data) { writedata(wd, DATA, kb->totelem * key->elemsize, kb->data); } - kb = kb->next; } } - - key = key->id.next; } mywrite_flush(wd); @@ -1968,10 +1936,7 @@ static void write_keys(WriteData *wd, ListBase *idbase) static void write_cameras(WriteData *wd, ListBase *idbase) { - Camera *cam; - - cam = idbase->first; - while (cam) { + for (Camera *cam = idbase->first; cam; cam = cam->id.next) { if (cam->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_CA, Camera, 1, cam); @@ -1981,18 +1946,12 @@ static void write_cameras(WriteData *wd, ListBase *idbase) write_animdata(wd, cam->adt); } } - - cam = cam->id.next; } } static void write_mballs(WriteData *wd, ListBase *idbase) { - MetaBall *mb; - MetaElem *ml; - - mb = idbase->first; - while (mb) { + for (MetaBall *mb = idbase->first; mb; mb = mb->id.next) { if (mb->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_MB, MetaBall, 1, mb); @@ -2004,23 +1963,16 @@ static void write_mballs(WriteData *wd, ListBase *idbase) write_animdata(wd, mb->adt); } - ml = mb->elems.first; - while (ml) { + for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) { writestruct(wd, DATA, MetaElem, 1, ml); - ml = ml->next; } } - mb = mb->id.next; } } static void write_curves(WriteData *wd, ListBase *idbase) { - Curve *cu; - Nurb *nu; - - cu = idbase->first; - while (cu) { + for (Curve *cu = idbase->first; cu; cu = cu->id.next) { if (cu->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_CU, Curve, 1, cu); @@ -2039,13 +1991,10 @@ static void write_curves(WriteData *wd, ListBase *idbase) } else { /* is also the order of reading */ - nu = cu->nurb.first; - while (nu) { + for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) { writestruct(wd, DATA, Nurb, 1, nu); - nu = nu->next; } - nu = cu->nurb.first; - while (nu) { + for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt); } @@ -2058,11 +2007,9 @@ static void write_curves(WriteData *wd, ListBase *idbase) writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv); } } - nu = nu->next; } } } - cu = cu->id.next; } mywrite_flush(wd); @@ -2184,15 +2131,13 @@ static void write_customdata( static void write_meshes(WriteData *wd, ListBase *idbase) { - Mesh *mesh; - bool save_for_old_blender = false; - #ifdef USE_BMESH_SAVE_AS_COMPAT - save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */ + const bool save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */ +#else + const bool save_for_old_blender = false; #endif - mesh = idbase->first; - while (mesh) { + for (Mesh *mesh = idbase->first; mesh; mesh = mesh->id.next) { CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; @@ -2336,8 +2281,6 @@ static void write_meshes(WriteData *wd, ListBase *idbase) if (players && players != players_buff) { MEM_freeN(players); } - - mesh = mesh->id.next; } mywrite_flush(wd); @@ -2345,10 +2288,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase) static void write_lattices(WriteData *wd, ListBase *idbase) { - Lattice *lt; - - lt = idbase->first; - while (lt) { + for (Lattice *lt = idbase->first; lt; lt = lt->id.next) { if (lt->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_LT, Lattice, 1, lt); @@ -2363,9 +2303,7 @@ static void write_lattices(WriteData *wd, ListBase *idbase) writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); - } - lt = lt->id.next; } mywrite_flush(wd); @@ -2373,14 +2311,10 @@ static void write_lattices(WriteData *wd, ListBase *idbase) static void write_images(WriteData *wd, ListBase *idbase) { - Image *ima; - PackedFile *pf; - ImageView *iv; - ImagePackedFile *imapf; - - ima = idbase->first; - while (ima) { + for (Image *ima = idbase->first; ima; ima = ima->id.next) { if (ima->id.us > 0 || wd->current) { + ImagePackedFile *imapf; + /* Some trickery to keep forward compatibility of packed images. */ BLI_assert(ima->packedfile == NULL); if (ima->packedfiles.first != NULL) { @@ -2395,7 +2329,7 @@ static void write_images(WriteData *wd, ListBase *idbase) for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { writestruct(wd, DATA, ImagePackedFile, 1, imapf); if (imapf->packedfile) { - pf = imapf->packedfile; + PackedFile *pf = imapf->packedfile; writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } @@ -2403,14 +2337,13 @@ static void write_images(WriteData *wd, ListBase *idbase) write_previews(wd, ima->preview); - for (iv = ima->views.first; iv; iv = iv->next) { + for (ImageView *iv = ima->views.first; iv; iv = iv->next) { writestruct(wd, DATA, ImageView, 1, iv); } writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format); ima->packedfile = NULL; } - ima = ima->id.next; } mywrite_flush(wd); @@ -2418,10 +2351,7 @@ static void write_images(WriteData *wd, ListBase *idbase) static void write_textures(WriteData *wd, ListBase *idbase) { - Tex *tex; - - tex = idbase->first; - while (tex) { + for (Tex *tex = idbase->first; tex; tex = tex->id.next) { if (tex->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_TE, Tex, 1, tex); @@ -2462,7 +2392,6 @@ static void write_textures(WriteData *wd, ListBase *idbase) write_previews(wd, tex->preview); } - tex = tex->id.next; } mywrite_flush(wd); @@ -2470,11 +2399,7 @@ static void write_textures(WriteData *wd, ListBase *idbase) static void write_materials(WriteData *wd, ListBase *idbase) { - Material *ma; - int a; - - ma = idbase->first; - while (ma) { + for (Material *ma = idbase->first; ma; ma = ma->id.next) { if (ma->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_MA, Material, 1, ma); @@ -2484,7 +2409,7 @@ static void write_materials(WriteData *wd, ListBase *idbase) write_animdata(wd, ma->adt); } - for (a = 0; a < MAX_MTEX; a++) { + for (int a = 0; a < MAX_MTEX; a++) { if (ma->mtex[a]) { writestruct(wd, DATA, MTex, 1, ma->mtex[a]); } @@ -2505,17 +2430,12 @@ static void write_materials(WriteData *wd, ListBase *idbase) write_previews(wd, ma->preview); } - ma = ma->id.next; } } static void write_worlds(WriteData *wd, ListBase *idbase) { - World *wrld; - int a; - - wrld = idbase->first; - while (wrld) { + for (World *wrld = idbase->first; wrld; wrld = wrld->id.next) { if (wrld->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_WO, World, 1, wrld); @@ -2525,7 +2445,7 @@ static void write_worlds(WriteData *wd, ListBase *idbase) write_animdata(wd, wrld->adt); } - for (a = 0; a < MAX_MTEX; a++) { + for (int a = 0; a < MAX_MTEX; a++) { if (wrld->mtex[a]) { writestruct(wd, DATA, MTex, 1, wrld->mtex[a]); } @@ -2539,17 +2459,12 @@ static void write_worlds(WriteData *wd, ListBase *idbase) write_previews(wd, wrld->preview); } - wrld = wrld->id.next; } } static void write_lamps(WriteData *wd, ListBase *idbase) { - Lamp *la; - int a; - - la = idbase->first; - while (la) { + for (Lamp *la = idbase->first; la; la = la->id.next) { if (la->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_LA, Lamp, 1, la); @@ -2560,7 +2475,7 @@ static void write_lamps(WriteData *wd, ListBase *idbase) } /* direct data */ - for (a = 0; a < MAX_MTEX; a++) { + for (int a = 0; a < MAX_MTEX; a++) { if (la->mtex[a]) { writestruct(wd, DATA, MTex, 1, la->mtex[a]); } @@ -2577,9 +2492,7 @@ static void write_lamps(WriteData *wd, ListBase *idbase) } write_previews(wd, la->preview); - } - la = la->id.next; } mywrite_flush(wd); @@ -2628,22 +2541,7 @@ static void write_paint(WriteData *wd, Paint *p) static void write_scenes(WriteData *wd, ListBase *scebase) { - Scene *sce; - Base *base; - Editing *ed; - Sequence *seq; - MetaStack *ms; - Strip *strip; - TimeMarker *marker; - TransformOrientation *ts; - SceneRenderLayer *srl; - SceneRenderView *srv; - ToolSettings *tos; - FreestyleModuleConfig *fmc; - FreestyleLineSet *fls; - - sce = scebase->first; - while (sce) { + for (Scene *sce = scebase->first; sce; sce = sce->id.next) { /* write LibData */ writestruct(wd, ID_SCE, Scene, 1, sce); write_iddata(wd, &sce->id); @@ -2654,13 +2552,11 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_keyingsets(wd, &sce->keyingsets); /* direct data */ - base = sce->base.first; - while (base) { + for (Base *base = sce->base.first; base; base = base->next) { writestruct(wd, DATA, Base, 1, base); - base = base->next; } - tos = sce->toolsettings; + ToolSettings *tos = sce->toolsettings; writestruct(wd, DATA, ToolSettings, 1, tos); if (tos->vpaint) { writestruct(wd, DATA, VPaint, 1, tos->vpaint); @@ -2699,8 +2595,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_paint(wd, &tos->imapaint.paint); - ed = sce->ed; + Editing *ed = sce->ed; if (ed) { + Sequence *seq; + writestruct(wd, DATA, Editing, 1, ed); /* reset write flags too */ @@ -2747,7 +2645,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase) writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format); - strip = seq->strip; + Strip *strip = seq->strip; writestruct(wd, DATA, Strip, 1, strip); if (seq->flag & SEQ_USE_CROP && strip->crop) { writestruct(wd, DATA, StripCrop, 1, strip->crop); @@ -2779,7 +2677,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase) SEQ_END /* new; meta stack too, even when its nasty restore code */ - for (ms = ed->metastack.first; ms; ms = ms->next) { + for (MetaStack *ms = ed->metastack.first; ms; ms = ms->next) { writestruct(wd, DATA, MetaStack, 1, ms); } } @@ -2805,27 +2703,27 @@ static void write_scenes(WriteData *wd, ListBase *scebase) } /* writing dynamic list of TimeMarkers to the blend file */ - for (marker = sce->markers.first; marker; marker = marker->next) { + for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) { writestruct(wd, DATA, TimeMarker, 1, marker); } /* writing dynamic list of TransformOrientations to the blend file */ - for (ts = sce->transform_spaces.first; ts; ts = ts->next) { + for (TransformOrientation *ts = sce->transform_spaces.first; ts; ts = ts->next) { writestruct(wd, DATA, TransformOrientation, 1, ts); } - for (srl = sce->r.layers.first; srl; srl = srl->next) { + for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) { writestruct(wd, DATA, SceneRenderLayer, 1, srl); - for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { + for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc); } - for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { + for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { writestruct(wd, DATA, FreestyleLineSet, 1, fls); } } /* writing MultiView to the blend file */ - for (srv = sce->r.views.first; srv; srv = srv->next) { + for (SceneRenderView *srv = sce->r.views.first; srv; srv = srv->next) { writestruct(wd, DATA, SceneRenderView, 1, srv); } @@ -2845,8 +2743,6 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_previews(wd, sce->preview); write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve); - - sce = sce->id.next; } mywrite_flush(wd); @@ -2854,13 +2750,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase) static void write_gpencils(WriteData *wd, ListBase *lb) { - bGPdata *gpd; - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps; - bGPDpalette *palette; - - for (gpd = lb->first; gpd; gpd = gpd->id.next) { + for (bGPdata *gpd = lb->first; gpd; gpd = gpd->id.next) { if (gpd->id.us > 0 || wd->current) { /* write gpd data block to file */ writestruct(wd, ID_GD, bGPdata, 1, gpd); @@ -2872,22 +2762,21 @@ static void write_gpencils(WriteData *wd, ListBase *lb) /* write grease-pencil layers to file */ writelist(wd, DATA, bGPDlayer, &gpd->layers); - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* write this layer's frames to file */ writelist(wd, DATA, bGPDframe, &gpl->frames); - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { /* write strokes */ writelist(wd, DATA, bGPDstroke, &gpf->strokes); - for (gps = gpf->strokes.first; gps; gps = gps->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points); } } } + /* write grease-pencil palettes */ writelist(wd, DATA, bGPDpalette, &gpd->palettes); - for (palette = gpd->palettes.first; palette; palette = palette->next) { + for (bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) { writelist(wd, DATA, bGPDpalettecolor, &palette->colors); } } @@ -2898,14 +2787,11 @@ static void write_gpencils(WriteData *wd, ListBase *lb) static void write_windowmanagers(WriteData *wd, ListBase *lb) { - wmWindowManager *wm; - wmWindow *win; - - for (wm = lb->first; wm; wm = wm->id.next) { + for (wmWindowManager *wm = lb->first; wm; wm = wm->id.next) { writestruct(wd, ID_WM, wmWindowManager, 1, wm); write_iddata(wd, &wm->id); - for (win = wm->windows.first; win; win = win->next) { + for (wmWindow *win = wm->windows.first; win; win = win->next) { writestruct(wd, DATA, wmWindow, 1, win); writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format); } @@ -2998,29 +2884,22 @@ static void write_soops(WriteData *wd, SpaceOops *so) static void write_screens(WriteData *wd, ListBase *scrbase) { - bScreen *sc; - ScrArea *sa; - ScrVert *sv; - ScrEdge *se; - - sc = scrbase->first; - while (sc) { - + for (bScreen *sc = scrbase->first; sc; sc = sc->id.next) { /* write LibData */ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ writestruct(wd, ID_SCRN, bScreen, 1, sc); write_iddata(wd, &sc->id); /* direct data */ - for (sv = sc->vertbase.first; sv; sv = sv->next) { + for (ScrVert *sv = sc->vertbase.first; sv; sv = sv->next) { writestruct(wd, DATA, ScrVert, 1, sv); } - for (se = sc->edgebase.first; se; se = se->next) { + for (ScrEdge *se = sc->edgebase.first; se; se = se->next) { writestruct(wd, DATA, ScrEdge, 1, se); } - for (sa = sc->areabase.first; sa; sa = sa->next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; Panel *pa; uiList *ui_list; @@ -3050,8 +2929,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase) } } - sl = sa->spacedata.first; - while (sl) { + for (sl = sa->spacedata.first; sl; sl = sl->next) { for (ar = sl->regionbase.first; ar; ar = ar->next) { write_region(wd, ar, sl->spacetype); } @@ -3165,12 +3043,8 @@ static void write_screens(WriteData *wd, ListBase *scrbase) else if (sl->spacetype == SPACE_INFO) { writestruct(wd, DATA, SpaceInfo, 1, sl); } - - sl = sl->next; } } - - sc = sc->id.next; } mywrite_flush(wd); @@ -3198,11 +3072,7 @@ static void write_bone(WriteData *wd, Bone *bone) static void write_armatures(WriteData *wd, ListBase *idbase) { - bArmature *arm; - Bone *bone; - - arm = idbase->first; - while (arm) { + for (bArmature *arm = idbase->first; arm; arm = arm->id.next) { if (arm->id.us > 0 || wd->current) { writestruct(wd, ID_AR, bArmature, 1, arm); write_iddata(wd, &arm->id); @@ -3212,13 +3082,10 @@ static void write_armatures(WriteData *wd, ListBase *idbase) } /* Direct data */ - bone = arm->bonebase.first; - while (bone) { + for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) { write_bone(wd, bone); - bone = bone->next; } } - arm = arm->id.next; } mywrite_flush(wd); @@ -3226,12 +3093,8 @@ static void write_armatures(WriteData *wd, ListBase *idbase) static void write_texts(WriteData *wd, ListBase *idbase) { - Text *text; - TextLine *tmp; - - text = idbase->first; - while (text) { - if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) { + for (Text *text = idbase->first; text; text = text->id.next) { + if ((text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) { text->flags &= ~TXT_ISEXT; } @@ -3245,21 +3108,14 @@ static void write_texts(WriteData *wd, ListBase *idbase) if (!(text->flags & TXT_ISEXT)) { /* now write the text data, in two steps for optimization in the readfunction */ - tmp = text->lines.first; - while (tmp) { + for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) { writestruct(wd, DATA, TextLine, 1, tmp); - tmp = tmp->next; } - tmp = text->lines.first; - while (tmp) { + for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) { writedata(wd, DATA, tmp->len + 1, tmp->line); - tmp = tmp->next; } } - - - text = text->id.next; } mywrite_flush(wd); @@ -3267,10 +3123,7 @@ static void write_texts(WriteData *wd, ListBase *idbase) static void write_speakers(WriteData *wd, ListBase *idbase) { - Speaker *spk; - - spk = idbase->first; - while (spk) { + for (Speaker *spk = idbase->first; spk; spk = spk->id.next) { if (spk->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_SPK, Speaker, 1, spk); @@ -3280,30 +3133,23 @@ static void write_speakers(WriteData *wd, ListBase *idbase) write_animdata(wd, spk->adt); } } - spk = spk->id.next; } } static void write_sounds(WriteData *wd, ListBase *idbase) { - bSound *sound; - - PackedFile *pf; - - sound = idbase->first; - while (sound) { + for (bSound *sound = idbase->first; sound; sound = sound->id.next) { if (sound->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_SO, bSound, 1, sound); write_iddata(wd, &sound->id); if (sound->packedfile) { - pf = sound->packedfile; + PackedFile *pf = sound->packedfile; writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } - sound = sound->id.next; } mywrite_flush(wd); @@ -3311,10 +3157,7 @@ static void write_sounds(WriteData *wd, ListBase *idbase) static void write_groups(WriteData *wd, ListBase *idbase) { - Group *group; - GroupObject *go; - - for (group = idbase->first; group; group = group->id.next) { + for (Group *group = idbase->first; group; group = group->id.next) { if (group->id.us > 0 || wd->current) { /* write LibData */ writestruct(wd, ID_GR, Group, 1, group); @@ -3322,10 +3165,8 @@ static void write_groups(WriteData *wd, ListBase *idbase) write_previews(wd, group->preview); - go = group->gobject.first; - while (go) { + for (GroupObject *go = group->gobject.first; go; go = go->next) { writestruct(wd, DATA, GroupObject, 1, go); - go = go->next; } } } @@ -3335,9 +3176,7 @@ static void write_groups(WriteData *wd, ListBase *idbase) static void write_nodetrees(WriteData *wd, ListBase *idbase) { - bNodeTree *ntree; - - for (ntree = idbase->first; ntree; ntree = ntree->id.next) { + for (bNodeTree *ntree = idbase->first; ntree; ntree = ntree->id.next) { if (ntree->id.us > 0 || wd->current) { writestruct(wd, ID_NT, bNodeTree, 1, ntree); /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot @@ -3421,9 +3260,7 @@ static void customnodes_free_deprecated_data(Main *mainvar) static void write_brushes(WriteData *wd, ListBase *idbase) { - Brush *brush; - - for (brush = idbase->first; brush; brush = brush->id.next) { + for (Brush *brush = idbase->first; brush; brush = brush->id.next) { if (brush->id.us > 0 || wd->current) { writestruct(wd, ID_BR, Brush, 1, brush); write_iddata(wd, &brush->id); @@ -3440,9 +3277,7 @@ static void write_brushes(WriteData *wd, ListBase *idbase) static void write_palettes(WriteData *wd, ListBase *idbase) { - Palette *palette; - - for (palette = idbase->first; palette; palette = palette->id.next) { + for (Palette *palette = idbase->first; palette; palette = palette->id.next) { if (palette->id.us > 0 || wd->current) { PaletteColor *color; writestruct(wd, ID_PAL, Palette, 1, palette); @@ -3457,9 +3292,7 @@ static void write_palettes(WriteData *wd, ListBase *idbase) static void write_paintcurves(WriteData *wd, ListBase *idbase) { - PaintCurve *pc; - - for (pc = idbase->first; pc; pc = pc->id.next) { + for (PaintCurve *pc = idbase->first; pc; pc = pc->id.next) { if (pc->id.us > 0 || wd->current) { writestruct(wd, ID_PC, PaintCurve, 1, pc); write_iddata(wd, &pc->id); @@ -3509,10 +3342,7 @@ static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction static void write_movieclips(WriteData *wd, ListBase *idbase) { - MovieClip *clip; - - clip = idbase->first; - while (clip) { + for (MovieClip *clip = idbase->first; clip; clip = clip->id.next) { if (clip->id.us > 0 || wd->current) { MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; @@ -3539,8 +3369,6 @@ static void write_movieclips(WriteData *wd, ListBase *idbase) object = object->next; } } - - clip = clip->id.next; } mywrite_flush(wd); @@ -3548,10 +3376,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase) static void write_masks(WriteData *wd, ListBase *idbase) { - Mask *mask; - - mask = idbase->first; - while (mask) { + for (Mask *mask = idbase->first; mask; mask = mask->id.next) { if (mask->id.us > 0 || wd->current) { MaskLayer *masklay; @@ -3599,8 +3424,6 @@ static void write_masks(WriteData *wd, ListBase *idbase) } } } - - mask = mask->id.next; } mywrite_flush(wd); @@ -3862,10 +3685,7 @@ static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifier static void write_linestyles(WriteData *wd, ListBase *idbase) { - FreestyleLineStyle *linestyle; - int a; - - for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) { + for (FreestyleLineStyle *linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) { if (linestyle->id.us > 0 || wd->current) { writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle); write_iddata(wd, &linestyle->id); @@ -3878,7 +3698,7 @@ static void write_linestyles(WriteData *wd, ListBase *idbase) write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers); write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers); write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers); - for (a = 0; a < MAX_MTEX; a++) { + for (int a = 0; a < MAX_MTEX; a++) { if (linestyle->mtex[a]) { writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]); } @@ -3893,9 +3713,7 @@ static void write_linestyles(WriteData *wd, ListBase *idbase) static void write_cachefiles(WriteData *wd, ListBase *idbase) { - CacheFile *cache_file; - - for (cache_file = idbase->first; cache_file; cache_file = cache_file->id.next) { + for (CacheFile *cache_file = idbase->first; cache_file; cache_file = cache_file->id.next) { if (cache_file->id.us > 0 || wd->current) { writestruct(wd, ID_CF, CacheFile, 1, cache_file); @@ -3915,7 +3733,6 @@ static void write_libraries(WriteData *wd, Main *main) bool found_one; for (; main; main = main->next) { - a = tot = set_listbasepointers(main, lbarray); /* test: is lib being used */ @@ -3924,16 +3741,13 @@ static void write_libraries(WriteData *wd, Main *main) } else { found_one = false; - while (tot--) { + while (!found_one && tot--) { for (id = lbarray[tot]->first; id; id = id->next) { if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { found_one = true; break; } } - if (found_one) { - break; - } } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 065f65659e6..3a042535d26 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -53,6 +53,7 @@ extern "C" { #include "intern/nodes/deg_node_component.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" /* Unfinished and unused, and takes quite some pre-processing time. */ @@ -362,6 +363,11 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, return; } + DEG_DEBUG_PRINTF("%s: layers:%u, graph->layers:%u\n", + __func__, + layers, + graph->layers); + /* Set time for the current graph evaluation context. */ TimeSourceDepsNode *time_src = graph->find_time_source(); eval_ctx->ctime = time_src->cfra; diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 33e44d73894..98900812bb2 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -46,6 +46,8 @@ #include "BLI_dlrbTree.h" #include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_nla.h" #include "BKE_mask.h" @@ -115,7 +117,8 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag) /* Draw a light green line to indicate current frame */ UI_ThemeColor(TH_CFRAME); - const float x = (float)(scene->r.cfra * scene->r.framelen); + const float time = scene->r.cfra + scene->r.subframe; + const float x = (float)(time * scene->r.framelen); glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0); @@ -308,7 +311,8 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo fcu->prev_norm_factor = 1.0f; if (fcu->bezt) { - BezTriple *bezt; + const bool use_preview_only = PRVRANGEON; + const BezTriple *bezt; int i; float max_coord = -FLT_MAX; float min_coord = FLT_MAX; @@ -318,28 +322,77 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo return 1.0f; } - if (PRVRANGEON) { - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - if (IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) { - max_coord = max_ff(max_coord, bezt->vec[0][1]); - max_coord = max_ff(max_coord, bezt->vec[1][1]); - max_coord = max_ff(max_coord, bezt->vec[2][1]); - - min_coord = min_ff(min_coord, bezt->vec[0][1]); - min_coord = min_ff(min_coord, bezt->vec[1][1]); - min_coord = min_ff(min_coord, bezt->vec[2][1]); - } + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0], + scene->r.psfra, + scene->r.pefra)) + { + continue; } - } - else { - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - max_coord = max_ff(max_coord, bezt->vec[0][1]); + + if (i == 0) { + /* We ignore extrapolation flags and handle here, and use the + * control point position only. so we normalize "interesting" + * part of the curve. + * + * Here we handle left extrapolation. + */ max_coord = max_ff(max_coord, bezt->vec[1][1]); - max_coord = max_ff(max_coord, bezt->vec[2][1]); - min_coord = min_ff(min_coord, bezt->vec[0][1]); min_coord = min_ff(min_coord, bezt->vec[1][1]); - min_coord = min_ff(min_coord, bezt->vec[2][1]); + } + else { + const BezTriple *prev_bezt = bezt - 1; + if (prev_bezt->ipo == BEZT_IPO_CONST) { + /* Constant interpolation: previous CV value is used up + * to the current keyframe. + */ + max_coord = max_ff(max_coord, bezt->vec[1][1]); + min_coord = min_ff(min_coord, bezt->vec[1][1]); + } + else if (prev_bezt->ipo == BEZT_IPO_LIN) { + /* Linear interpolation: min/max using both previous and + * and current CV. + */ + max_coord = max_ff(max_coord, bezt->vec[1][1]); + min_coord = min_ff(min_coord, bezt->vec[1][1]); + max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); + min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); + } + else if (prev_bezt->ipo == BEZT_IPO_BEZ) { + const int resol = fcu->driver + ? 32 + : min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), 32); + if (resol < 2) { + max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); + min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); + } + else { + float data[120]; + float v1[2], v2[2], v3[2], v4[2]; + + v1[0] = prev_bezt->vec[1][0]; + v1[1] = prev_bezt->vec[1][1]; + v2[0] = prev_bezt->vec[2][0]; + v2[1] = prev_bezt->vec[2][1]; + + v3[0] = bezt->vec[0][0]; + v3[1] = bezt->vec[0][1]; + v4[0] = bezt->vec[1][0]; + v4[1] = bezt->vec[1][1]; + + correct_bezpart(v1, v2, v3, v4); + + BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3); + BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3); + + for (int j = 0; j <= resol; ++j) { + const float *fp = &data[j * 3]; + max_coord = max_ff(max_coord, fp[1]); + min_coord = min_ff(min_coord, fp[1]); + } + } + } } } diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index c0d6963acbb..bb73cbf03b4 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -95,7 +95,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - int frame = RNA_int_get(op->ptr, "frame"); + float frame = RNA_float_get(op->ptr, "frame"); bool do_snap = RNA_boolean_get(op->ptr, "snap"); if (do_snap && CTX_wm_space_seq(C)) { @@ -103,10 +103,15 @@ static void change_frame_apply(bContext *C, wmOperator *op) } /* set the new frame number */ - CFRA = frame; + CFRA = (int)frame; + if (scene->r.flag & SCER_SHOW_SUBFRAME) { + SUBFRA = frame - (int)frame; + } + else { + SUBFRA = 0.0f; + } FRAMENUMBER_MIN_CLAMP(CFRA); - SUBFRA = 0.0f; - + /* do updates */ BKE_sound_seek_scene(bmain, scene); WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); @@ -125,18 +130,18 @@ static int change_frame_exec(bContext *C, wmOperator *op) /* ---- */ /* Get frame from mouse coordinates */ -static int frame_from_event(bContext *C, const wmEvent *event) +static float frame_from_event(bContext *C, const wmEvent *event) { ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); float viewx; - int frame; + float frame; /* convert from region coordinates to View2D 'tot' space */ viewx = UI_view2d_region_to_view_x(®ion->v2d, event->mval[0]); /* round result to nearest int (frames are ints!) */ - frame = iroundf(viewx); + frame = viewx; if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) { CLAMP(frame, PSFRA, PEFRA); @@ -187,7 +192,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event * as user could click on a single frame (jump to frame) as well as * click-dragging over a range (modal scrubbing). */ - RNA_int_set(op->ptr, "frame", frame_from_event(C, event)); + RNA_float_set(op->ptr, "frame", frame_from_event(C, event)); change_frame_seq_preview_begin(C, event); @@ -215,7 +220,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event) break; case MOUSEMOVE: - RNA_int_set(op->ptr, "frame", frame_from_event(C, event)); + RNA_float_set(op->ptr, "frame", frame_from_event(C, event)); change_frame_apply(C, op); break; @@ -268,7 +273,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->undo_group = "FRAME_CHANGE"; /* rna */ - ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); + ot->prop = RNA_def_float(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); prop = RNA_def_boolean(ot->srna, "snap", false, "Snap", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index cc4c1809fbc..f6c04e9570a 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -970,6 +970,9 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S ToolSettings *ts = CTX_data_tool_settings(C); int point_added = 0; + /* TODO: Since the function `ED_transform_snap_object_context_create_view3d` creates a cache, + * the ideal would be to call this function only at the beginning of the snap operation, + * or at the beginning of the operator itself */ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( CTX_data_main(C), CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); @@ -1038,6 +1041,8 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S } } + /* TODO: The ideal would be to call this function only once. + * At the end of the operator */ ED_transform_snap_object_context_destroy(snap_context); return point_added; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 5b011b679a6..e118e490f25 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -953,6 +953,9 @@ static int gp_dissolve_selected_points(bContext *C) /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(gpl, gps) == false) + continue; if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; @@ -1165,6 +1168,9 @@ static int gp_delete_selected_points(bContext *C) /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(gpl, gps) == false) + continue; if (gps->flag & GP_STROKE_SELECT) { @@ -1204,7 +1210,7 @@ static int gp_delete_exec(bContext *C, wmOperator *op) case GP_DELETEOP_POINTS: /* selected points (breaks the stroke into segments) */ result = gp_delete_selected_points(C); break; - + case GP_DELETEOP_FRAME: /* active frame */ result = gp_actframe_delete_exec(C, op); break; diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 7944b434057..6eaae49912c 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -65,10 +65,6 @@ struct SnapObjectParams { unsigned int use_object_edit_cage : 1; }; -enum { - SNAP_OBJECT_USE_CACHE = (1 << 0), -}; - typedef struct SnapObjectContext SnapObjectContext; SnapObjectContext *ED_transform_snap_object_context_create( struct Main *bmain, struct Scene *scene, int flag); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 8579778ff79..8420591aa3e 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -653,9 +653,9 @@ DEF_ICON(IPO_BACK) DEF_ICON(IPO_EASE_IN) DEF_ICON(IPO_EASE_OUT) DEF_ICON(IPO_EASE_IN_OUT) +DEF_ICON(NORMALIZE_FCURVES) #ifndef DEF_ICON_BLANK_SKIP /* available */ - DEF_ICON(BLANK203) DEF_ICON(BLANK204) DEF_ICON(BLANK205) DEF_ICON(BLANK206) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index d43a94c5514..b3736a71e74 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1584,7 +1584,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f); if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) { - widget_draw_icon(but, ICON_X, alpha, &temp, false); + widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, false); } else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 8f004bcf72b..65ee097e8e1 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -306,7 +306,7 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) ED_view3d_init_mats_rv3d(obedit, ar->regiondata); struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, + CTX_data_main(C), CTX_data_scene(C), 0, ar, CTX_wm_view3d(C)); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 56f59dca9a1..3c406764157 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -363,8 +363,8 @@ void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot /* matching index only */ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) { - MDeformVert **dvert_array_from, **dvf; - MDeformVert **dvert_array, **dv; + MDeformVert **dvert_array_from = NULL, **dvf; + MDeformVert **dvert_array = NULL, **dv; int dvert_tot_from; int dvert_tot; int i; @@ -375,26 +375,30 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) if (ob == ob_from) return true; - ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false); - ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - - if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) { + /* in case we copy vgroup between two objects using same data, we only have to care about object side of things. */ + if (ob->data != ob_from->data) { + ED_vgroup_parray_alloc(ob_from->data, &dvert_array_from, &dvert_tot_from, false); ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); - new_vgroup = true; - } - if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) { + if ((dvert_array == NULL) && (dvert_array_from != NULL) && BKE_object_defgroup_data_create(ob->data)) { + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); + new_vgroup = true; + } - if (dvert_array) MEM_freeN(dvert_array); - if (dvert_array_from) MEM_freeN(dvert_array_from); + if (dvert_tot == 0 || (dvert_tot != dvert_tot_from) || dvert_array_from == NULL || dvert_array == NULL) { + if (dvert_array) + MEM_freeN(dvert_array); + if (dvert_array_from) + MEM_freeN(dvert_array_from); - if (new_vgroup == true) { - /* free the newly added vgroup since it wasn't compatible */ - BKE_object_defgroup_remove_all(ob); - } + if (new_vgroup == true) { + /* free the newly added vgroup since it wasn't compatible */ + BKE_object_defgroup_remove_all(ob); + } - /* if true: both are 0 and nothing needs changing, consider this a success */ - return (dvert_tot == dvert_tot_from); + /* if true: both are 0 and nothing needs changing, consider this a success */ + return (dvert_tot == dvert_tot_from); + } } /* do the copy */ @@ -412,22 +416,23 @@ bool ED_vgroup_array_copy(Object *ob, Object *ob_from) MEM_freeN(remap); } - dvf = dvert_array_from; - dv = dvert_array; + if (dvert_array_from != NULL && dvert_array != NULL) { + dvf = dvert_array_from; + dv = dvert_array; - for (i = 0; i < dvert_tot; i++, dvf++, dv++) { - if ((*dv)->dw) - MEM_freeN((*dv)->dw); + for (i = 0; i < dvert_tot; i++, dvf++, dv++) { + MEM_SAFE_FREE((*dv)->dw); + *(*dv) = *(*dvf); - *(*dv) = *(*dvf); + if ((*dv)->dw) { + (*dv)->dw = MEM_dupallocN((*dv)->dw); + } + } - if ((*dv)->dw) - (*dv)->dw = MEM_dupallocN((*dv)->dw); + MEM_freeN(dvert_array); + MEM_freeN(dvert_array_from); } - MEM_freeN(dvert_array); - MEM_freeN(dvert_array_from); - return true; } diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 9097432a251..55c07140216 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -887,13 +887,13 @@ static void write_result_func(TaskPool * __restrict pool, ReportList reports; BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT); /* Do actual save logic here, depending on the file format. */ + Scene tmp_scene = *scene; + tmp_scene.r.cfra = cfra; if (is_movie) { /* We have to construct temporary scene with proper scene->r.cfra. * This is because underlying calls do not use r.cfra but use scene * for that. */ - Scene tmp_scene = *scene; - tmp_scene.r.cfra = cfra; ok = RE_WriteRenderViewsMovie(&reports, rr, &tmp_scene, @@ -917,8 +917,8 @@ static void write_result_func(TaskPool * __restrict pool, true, NULL); - BKE_render_result_stamp_info(scene, scene->camera, rr, false); - ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name); + BKE_render_result_stamp_info(&tmp_scene, tmp_scene.camera, rr, false); + ok = RE_WriteRenderViewsImage(NULL, rr, &tmp_scene, true, name); if (!ok) { BKE_reportf(&reports, RPT_ERROR, diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 075b1faf502..964f4bcdd9c 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1256,21 +1256,6 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot } break; } - - /* removed since BKE_image_user_frame_calc is now called in view3d_draw_bgpic because screen_ops doesnt call the notifier. */ -#if 0 - if (wmn->category == NC_SCENE && wmn->data == ND_FRAME) { - View3D *v3d = area->spacedata.first; - BGpic *bgpic = v3d->bgpicbase.first; - - for (; bgpic; bgpic = bgpic->next) { - if (bgpic->ima) { - Scene *scene = wmn->reference; - BKE_image_user_frame_calc(&bgpic->iuser, scene->r.cfra, 0); - } - } - } -#endif } const char *view3d_context_dir[] = { diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 688f459108b..aefe30bbe32 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -280,7 +280,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) } else if (state == RULER_STATE_DRAG) { ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, + CTX_data_main(C), CTX_data_scene(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } else { diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 17c08ed4205..542dc410bc3 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -588,7 +588,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; walk->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), walk->scene, SNAP_OBJECT_USE_CACHE, + CTX_data_main(C), walk->scene, 0, walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 31ffa019e4e..1916f9b4dab 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -3722,6 +3722,12 @@ static void initRotation(TransInfo *t) copy_v3_v3(t->axis_orig, t->axis); } +/** + * Applies values of rotation to `td->loc` and `td->ext->quat` + * based on a rotation matrix (mat) and a pivot (center). + * + * Protected axis and other transform settings are taken into account. + */ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center) { float vec[3], totmat[3][3], smat[3][3]; @@ -4339,9 +4345,22 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) { TransData *td = t->data; float tvec[3]; - int i; - for (i = 0; i < t->total; i++, td++) { + /* The ideal would be "apply_snap_align_rotation" only when a snap point is found + * so, maybe inside this function is not the best place to apply this rotation. + * but you need "handle snapping rotation before doing the translation" (really?) */ + const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT); + float pivot[3]; + if (apply_snap_align_rotation) { + copy_v3_v3(pivot, t->tsnap.snapTarget); + /* The pivot has to be in local-space (see T49494) */ + if (t->flag & (T_EDIT | T_POSE)) { + Object *ob = t->obedit ? t->obedit : t->poseobj; + mul_m4_v3(ob->imat, pivot); + } + } + + for (int i = 0; i < t->total; i++, td++) { if (td->flag & TD_NOACTION) break; @@ -4352,7 +4371,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) bool use_rotate_offset = false; /* handle snapping rotation before doing the translation */ - if (usingSnappingNormal(t)) { + if (apply_snap_align_rotation) { float mat[3][3]; if (validSnappingNormal(t)) { @@ -4370,7 +4389,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) unit_m3(mat); } - ElementRotation_ex(t, td, mat, t->tsnap.snapTarget); + ElementRotation_ex(t, td, mat, pivot); if (td->loc) { use_rotate_offset = true; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 7ea4448a44e..d60eb2f0778 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -84,8 +84,8 @@ typedef struct TransSnap { bool peel; bool snap_spatial_grid; short status; - float snapPoint[3]; /* snapping from this point */ - float snapTarget[3]; /* to this point */ + float snapPoint[3]; /* snapping from this point (in global-space)*/ + float snapTarget[3]; /* to this point (in global-space)*/ float snapNormal[3]; char snapNodeBorder; ListBase points; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index ce3d903b8f6..091a5773cf0 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2393,7 +2393,12 @@ static void createTransEditVerts(TransInfo *t) editmesh_set_connectivity_distance(em->bm, mtx, dists); } - if (t->around == V3D_AROUND_LOCAL_ORIGINS) { + /* Only in case of rotation and resize, we want the elements of the edited + * object to behave as groups whose pivot are the individual origins + * + * TODO: use island_info to detect the closest point when the "Snap Target" + * in Blender UI is "Closest" */ + if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode != TFM_TRANSLATION)) { island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map); } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 87ac54b2bd9..318d2718969 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -601,7 +601,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - G.main, t->scene, SNAP_OBJECT_USE_CACHE, + G.main, t->scene, 0, t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 85209b07677..53f6b37c22e 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -235,21 +235,6 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH /** \Common utilities * \{ */ -MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3]) -{ - float dvec[3]; - sub_v3_v3v3(dvec, co, ray_start); - return dot_v3v3(dvec, ray_dir); -} - -/** - * Struct that kepts basic information about a BVHTree build from a editmesh. - */ -typedef struct BVHTreeFromMeshType { - void *userdata; - char type; -} BVHTreeFromMeshType; - /** * Generates a struct with the immutable parameters that will be used on all objects. * @@ -286,52 +271,42 @@ static void snap_data_set( copy_v2_v2(snapdata->depth_range, depth_range); } -static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3]) +MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3]) { - switch (meshdata->type) { - case SNAP_MESH: - { - BVHTreeFromMesh *data = meshdata->userdata; - const MVert *vert = data->vert + index; - normal_short_to_float_v3(r_no, vert->no); - break; - } - case SNAP_EDIT_MESH: - { - BVHTreeFromEditMesh *data = meshdata->userdata; - BMVert *eve = BM_vert_at_index(data->em->bm, index); - copy_v3_v3(r_no, eve->no); - break; - } - } + float dvec[3]; + sub_v3_v3v3(dvec, co, ray_start); + return dot_v3v3(dvec, ray_dir); } -static void get_edge_verts( - const BVHTreeFromMeshType *meshdata, const int index, - const float *v_pair[2]) +static void copy_dm_vert_no(const int index, float r_no[3], const BVHTreeFromMesh *data) { - switch (meshdata->type) { - case SNAP_MESH: - { - BVHTreeFromMesh *data = meshdata->userdata; + const MVert *vert = data->vert + index; - const MVert *vert = data->vert; - const MEdge *edge = data->edge + index; + normal_short_to_float_v3(r_no, vert->no); +} - v_pair[0] = vert[edge->v1].co; - v_pair[1] = vert[edge->v2].co; - break; - } - case SNAP_EDIT_MESH: - { - BVHTreeFromEditMesh *data = meshdata->userdata; - BMEdge *eed = BM_edge_at_index(data->em->bm, index); +static void copy_bvert_no(const int index, float r_no[3], const BVHTreeFromEditMesh *data) +{ + BMVert *eve = BM_vert_at_index(data->em->bm, index); - v_pair[0] = eed->v1->co; - v_pair[1] = eed->v2->co; - break; - } - } + copy_v3_v3(r_no, eve->no); +} + +static void get_dm_edge_verts(const int index, const float *v_pair[2], const BVHTreeFromMesh *data) +{ + const MVert *vert = data->vert; + const MEdge *edge = data->edge + index; + + v_pair[0] = vert[edge->v1].co; + v_pair[1] = vert[edge->v2].co; +} + +static void get_bedge_verts(const int index, const float *v_pair[2], const BVHTreeFromEditMesh *data) +{ + BMEdge *eed = BM_edge_at_index(data->em->bm, index); + + v_pair[0] = eed->v1->co; + v_pair[1] = eed->v2->co; } static bool test_projected_vert_dist( @@ -422,6 +397,7 @@ static void dist_squared_to_projected_aabb_precalc( } } +/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */ static float dist_squared_to_projected_aabb( struct Nearest2dPrecalc *data, const float bbmin[3], const float bbmax[3], @@ -644,6 +620,10 @@ static float dist_aabb_to_plane( /** \Walk DFS * \{ */ + +typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const float *v_pair[2], void *data); +typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void *data); + typedef struct Nearest2dUserData { struct Nearest2dPrecalc data_precalc; @@ -652,7 +632,11 @@ typedef struct Nearest2dUserData { bool r_axis_closest[3]; float depth_range[2]; + void *userdata; + Nearest2DGetEdgeVertsCallback get_edge_verts; + Nearest2DCopyVertNoCallback copy_vert_no; + int index; float co[3]; float no[3]; @@ -688,7 +672,7 @@ static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, vo &data->dist_px_sq, data->co)) { - copy_vert_no(data->userdata, index, data->no); + data->copy_vert_no(index, data->no, data->userdata); data->index = index; } return true; @@ -700,7 +684,7 @@ static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int i struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc; const float *v_pair[2]; - get_edge_verts(data->userdata, index, v_pair); + data->get_edge_verts(index, v_pair, data->userdata); if (test_projected_edge_dist( data->depth_range, @@ -1067,7 +1051,6 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) static bool snapDerivedMesh( SnapObjectContext *sctx, SnapData *snapdata, Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, - bool do_bb, /* read/write args */ float *ray_depth, float *dist_px, /* return args */ @@ -1092,274 +1075,258 @@ static bool snapDerivedMesh( } } - { - bool need_ray_start_correction_init = - (snapdata->snap_to == SCE_SNAP_MODE_FACE) && - (snapdata->view_proj == VIEW_PROJ_ORTHO); - - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - float local_scale, local_depth, len_diff; - - invert_m4_m4(imat, obmat); - transpose_m3_m4(timat, imat); - - copy_v3_v3(ray_start_local, snapdata->ray_start); - copy_v3_v3(ray_normal_local, snapdata->ray_dir); + bool need_ray_start_correction_init = + (snapdata->snap_to == SCE_SNAP_MODE_FACE) && + (snapdata->view_proj == VIEW_PROJ_ORTHO); - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_start_local[3], ray_normal_local[3]; + float local_scale, local_depth, len_diff; - /* local scale in normal direction */ - local_scale = normalize_v3(ray_normal_local); - local_depth = *ray_depth; - if (local_depth != BVH_RAYCAST_DIST_MAX) { - local_depth *= local_scale; - } + invert_m4_m4(imat, obmat); + transpose_m3_m4(timat, imat); - float lpmat[4][4]; - float ray_org_local[3]; - float ray_min_dist; - if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { - mul_m4_m4m4(lpmat, snapdata->pmat, obmat); - ray_min_dist = snapdata->depth_range[0] * local_scale; - } + copy_v3_v3(ray_start_local, snapdata->ray_start); + copy_v3_v3(ray_normal_local, snapdata->ray_dir); - copy_v3_v3(ray_org_local, snapdata->ray_origin); - mul_m4_v3(imat, ray_org_local); + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); - if (do_bb) { - BoundBox *bb = BKE_object_boundbox_get(ob); + /* local scale in normal direction */ + local_scale = normalize_v3(ray_normal_local); + local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } - if (bb) { - BoundBox bb_temp; + float lpmat[4][4]; + float ray_org_local[3]; + float ray_min_dist; + if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { + mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + ray_min_dist = snapdata->depth_range[0] * local_scale; + } - /* We cannot afford a bounding box with some null dimension, which may happen in some cases... - * Threshold is rather high, but seems to be needed to get good behavior, see T46099. */ - bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f); + copy_v3_v3(ray_org_local, snapdata->ray_origin); + mul_m4_v3(imat, ray_org_local); - /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see T46816. */ - if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { - float dist_px_sq = dist_squared_to_projected_aabb_simple( - lpmat, snapdata->win_half, ray_min_dist, snapdata->mval, - ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]); - if (dist_px_sq > SQUARE(*dist_px)) - { - return retval; - } - } - else { - /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ - if (!isect_ray_aabb_v3_simple( - ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL)) - { - return retval; - } - } - /* was local_depth, see: T47838 */ - len_diff = dist_aabb_to_plane(bb->vec[0], bb->vec[6], ray_start_local, ray_normal_local); - if (len_diff < 0) len_diff = 0.0f; - need_ray_start_correction_init = false; + /* Test BoundBox */ + BoundBox *bb = BKE_object_boundbox_get(ob); + if (bb) { + /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */ + if (ELEM(snapdata->snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { + float dist_px_sq = dist_squared_to_projected_aabb_simple( + lpmat, snapdata->win_half, ray_min_dist, snapdata->mval, + ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]); + if (dist_px_sq > SQUARE(*dist_px)) + { + return retval; } } - - SnapObjectData_Mesh *sod = NULL; - BVHTreeFromMesh *treedata = NULL, treedata_stack; - - if (sctx->flag & SNAP_OBJECT_USE_CACHE) { - void **sod_p; - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { - sod = *sod_p; - } - else { - sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); - sod->sd.type = SNAP_MESH; + else { + /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ + if (!isect_ray_aabb_v3_simple( + ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], NULL, NULL)) + { + return retval; } + } + /* was local_depth, see: T47838 */ + len_diff = dist_aabb_to_plane(bb->vec[0], bb->vec[6], ray_start_local, ray_normal_local); + if (len_diff < 0) len_diff = 0.0f; + need_ray_start_correction_init = false; + } - int tree_index = -1; - switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - tree_index = 2; - break; - case SCE_SNAP_MODE_EDGE: - tree_index = 1; - break; - case SCE_SNAP_MODE_VERTEX: - tree_index = 0; - break; - } - if (tree_index != -1) { - if (sod->bvh_trees[tree_index] == NULL) { - sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); - } - treedata = sod->bvh_trees[tree_index]; + SnapObjectData_Mesh *sod = NULL; + BVHTreeFromMesh *treedata = NULL; - /* the tree is owned by the DM and may have been freed since we last used! */ - if (treedata && treedata->tree) { - if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) { - free_bvhtree_from_mesh(treedata); - } - } - } - } - else { - treedata = &treedata_stack; - memset(treedata, 0, sizeof(*treedata)); + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_MESH; + } + + int tree_index = -1; + switch (snapdata->snap_to) { + case SCE_SNAP_MODE_FACE: + tree_index = 2; + break; + case SCE_SNAP_MODE_EDGE: + tree_index = 1; + break; + case SCE_SNAP_MODE_VERTEX: + tree_index = 0; + break; + } + if (tree_index != -1) { + if (sod->bvh_trees[tree_index] == NULL) { + sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); } + treedata = sod->bvh_trees[tree_index]; - if (treedata && treedata->tree == NULL) { - switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); - break; - case SCE_SNAP_MODE_EDGE: - bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6); - break; - case SCE_SNAP_MODE_VERTEX: - bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6); - break; + /* the tree is owned by the DM and may have been freed since we last used! */ + if (treedata && treedata->tree) { + if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) { + free_bvhtree_from_mesh(treedata); } } + } - if (!treedata || !treedata->tree) { - return retval; + if (treedata && treedata->tree == NULL) { + switch (snapdata->snap_to) { + case SCE_SNAP_MODE_FACE: + bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); + break; + case SCE_SNAP_MODE_EDGE: + bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6); + break; + case SCE_SNAP_MODE_VERTEX: + bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6); + break; } + } + if (!treedata || !treedata->tree) { + return retval; + } - if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already - * been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! - */ - if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ - if (need_ray_start_correction_init) { - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. - */ - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); - if (nearest.index != -1) { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - } - } - /* You need to make sure that ray_start is really far away, - * because even in the Orthografic view, in some cases, - * the ray can start inside the object (see T50486) */ - if (len_diff > 400.0f) { - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with - * very far away ray_start values (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + snapdata->depth_range[0] * local_scale); - local_depth -= len_diff; + if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ + if (need_ray_start_correction_init) { + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); + if (nearest.index != -1) { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); } - else len_diff = 0.0f; } - else { - len_diff = 0.0f; - } - if (r_hit_list) { - struct RayCastAll_Data data; - - data.bvhdata = treedata; - data.raycast_callback = treedata->raycast_callback; - data.obmat = obmat; - data.timat = timat; - data.len_diff = len_diff; - data.local_scale = local_scale; - data.ob = ob; - data.ob_uuid = ob_index; - data.hit_list = r_hit_list; - data.retval = retval; - - BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); - - retval = data.retval; + /* You need to make sure that ray_start is really far away, + * because even in the Orthografic view, in some cases, + * the ray can start inside the object (see T50486) */ + if (len_diff > 400.0f) { + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with + * very far away ray_start values (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl( + ray_start_local, ray_org_local, ray_normal_local, + len_diff + snapdata->depth_range[0] * local_scale); + local_depth -= len_diff; } - else { - BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; + else len_diff = 0.0f; + } + else { + len_diff = 0.0f; + } + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - if (BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); - - if (r_no) { - copy_v3_v3(r_no, hit.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } + if (BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } - retval = true; + retval = true; - if (r_index) { - *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); - } + if (r_index) { + *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); } } } } - /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */ - else { - BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH}; - - Nearest2dUserData neasrest2d = { - .dist_px_sq = SQUARE(*dist_px), - .r_axis_closest = {1.0f, 1.0f, 1.0f}, - .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]}, - .userdata = &treedata_type, - .index = -1}; - - dist_squared_to_projected_aabb_precalc( - &neasrest2d.data_precalc, lpmat, - snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, - ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local); - - BVHTree_WalkLeafCallback cb_walk_leaf = - (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? - cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - - BLI_bvhtree_walk_dfs( - treedata->tree, - cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); - - if (neasrest2d.index != -1) { - copy_v3_v3(r_loc, neasrest2d.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, neasrest2d.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } - *dist_px = sqrtf(neasrest2d.dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + } + /* SCE_SNAP_MODE_VERTEX or SCE_SNAP_MODE_EDGE */ + else { - retval = true; + /* Warning: the depth_max is currently being used only in perspective view. + * It is not correct to limit the maximum depth for elements obtained with nearest + * since this limitation depends on the normal and the size of the occlusion face. + * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */ + const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0]; + + Nearest2dUserData neasrest2d = { + .dist_px_sq = SQUARE(*dist_px), + .r_axis_closest = {1.0f, 1.0f, 1.0f}, + .depth_range = {snapdata->depth_range[0], ray_depth_max_global}, + .userdata = treedata, + .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_dm_edge_verts, + .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_dm_vert_no, + .index = -1}; + + dist_squared_to_projected_aabb_precalc( + &neasrest2d.data_precalc, lpmat, + snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, + ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local); + + BVHTree_WalkLeafCallback cb_walk_leaf = + (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; + + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); + + if (neasrest2d.index != -1) { + copy_v3_v3(r_loc, neasrest2d.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest2d.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); } - } + *dist_px = sqrtf(neasrest2d.dist_px_sq); + *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); - if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) { - if (treedata) { - free_bvhtree_from_mesh(treedata); - } + retval = true; } } @@ -1393,268 +1360,246 @@ static bool snapEditMesh( } } - { - float imat[4][4]; - float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_normal_local[3]; + float imat[4][4]; + float timat[3][3]; /* transpose inverse matrix for normals */ + float ray_normal_local[3]; - invert_m4_m4(imat, obmat); - transpose_m3_m4(timat, imat); + invert_m4_m4(imat, obmat); + transpose_m3_m4(timat, imat); - copy_v3_v3(ray_normal_local, snapdata->ray_dir); + copy_v3_v3(ray_normal_local, snapdata->ray_dir); - mul_mat3_m4_v3(imat, ray_normal_local); + mul_mat3_m4_v3(imat, ray_normal_local); - /* local scale in normal direction */ - float local_scale = normalize_v3(ray_normal_local); - float local_depth = *ray_depth; - if (local_depth != BVH_RAYCAST_DIST_MAX) { - local_depth *= local_scale; - } + /* local scale in normal direction */ + float local_scale = normalize_v3(ray_normal_local); + float local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } - SnapObjectData_EditMesh *sod = NULL; + SnapObjectData_EditMesh *sod = NULL; - BVHTreeFromEditMesh *treedata = NULL, treedata_stack; + BVHTreeFromEditMesh *treedata = NULL; - if (sctx->flag & SNAP_OBJECT_USE_CACHE) { - void **sod_p; - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { - sod = *sod_p; - } - else { - sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); - sod->sd.type = SNAP_EDIT_MESH; - } + void **sod_p; + if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + sod = *sod_p; + } + else { + sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_EDIT_MESH; + } - int tree_index = -1; - switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - tree_index = 2; - break; - case SCE_SNAP_MODE_EDGE: - tree_index = 1; - break; - case SCE_SNAP_MODE_VERTEX: - tree_index = 0; - break; - } - if (tree_index != -1) { - if (sod->bvh_trees[tree_index] == NULL) { - sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); - } - treedata = sod->bvh_trees[tree_index]; - } - } - else { - treedata = &treedata_stack; - memset(treedata, 0, sizeof(*treedata)); + int tree_index = -1; + switch (snapdata->snap_to) { + case SCE_SNAP_MODE_FACE: + tree_index = 2; + break; + case SCE_SNAP_MODE_EDGE: + tree_index = 1; + break; + case SCE_SNAP_MODE_VERTEX: + tree_index = 0; + break; + } + if (tree_index != -1) { + if (sod->bvh_trees[tree_index] == NULL) { + sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata)); } + treedata = sod->bvh_trees[tree_index]; + } - if (treedata && treedata->tree == NULL) { - switch (snapdata->snap_to) { - case SCE_SNAP_MODE_FACE: - { - BLI_bitmap *looptri_mask = NULL; - int looptri_num_active = -1; - if (sctx->callbacks.edit_mesh.test_face_fn) { - looptri_mask = BLI_BITMAP_NEW(em->tottri, __func__); - looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( - em->bm, looptri_mask, - sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); - } - bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL); - if (looptri_mask) { - MEM_freeN(looptri_mask); - } - break; + if (treedata && treedata->tree == NULL) { + BLI_bitmap *elem_mask = NULL; + switch (snapdata->snap_to) { + case SCE_SNAP_MODE_FACE: + { + int looptri_num_active = -1; + if (sctx->callbacks.edit_mesh.test_face_fn) { + elem_mask = BLI_BITMAP_NEW(em->tottri, __func__); + looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface( + em->bm, elem_mask, + sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); } - case SCE_SNAP_MODE_EDGE: - { - BLI_bitmap *edges_mask = NULL; - int edges_num_active = -1; - if (sctx->callbacks.edit_mesh.test_edge_fn) { - edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__); - edges_num_active = BM_iter_mesh_bitmap_from_filter( - BM_EDGES_OF_MESH, em->bm, edges_mask, - (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn, - sctx->callbacks.edit_mesh.user_data); - } - bvhtree_from_editmesh_edges_ex(treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6); - if (edges_mask) { - MEM_freeN(edges_mask); - } - break; + bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL); + break; + } + case SCE_SNAP_MODE_EDGE: + { + int edges_num_active = -1; + if (sctx->callbacks.edit_mesh.test_edge_fn) { + elem_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__); + edges_num_active = BM_iter_mesh_bitmap_from_filter( + BM_EDGES_OF_MESH, em->bm, elem_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn, + sctx->callbacks.edit_mesh.user_data); } - case SCE_SNAP_MODE_VERTEX: - { - BLI_bitmap *verts_mask = NULL; - int verts_num_active = -1; - if (sctx->callbacks.edit_mesh.test_vert_fn) { - verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__); - verts_num_active = BM_iter_mesh_bitmap_from_filter( - BM_VERTS_OF_MESH, em->bm, verts_mask, - (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn, - sctx->callbacks.edit_mesh.user_data); - } - bvhtree_from_editmesh_verts_ex(treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6); - if (verts_mask) { - MEM_freeN(verts_mask); - } - break; + bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6); + break; + } + case SCE_SNAP_MODE_VERTEX: + { + int verts_num_active = -1; + if (sctx->callbacks.edit_mesh.test_vert_fn) { + elem_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__); + verts_num_active = BM_iter_mesh_bitmap_from_filter( + BM_VERTS_OF_MESH, em->bm, elem_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn, + sctx->callbacks.edit_mesh.user_data); } + bvhtree_from_editmesh_verts_ex(treedata, em, elem_mask, verts_num_active, 0.0f, 2, 6); + break; } } - - if (!treedata || !treedata->tree) { - return retval; + if (elem_mask) { + MEM_freeN(elem_mask); } + } - if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { - float ray_start_local[3]; - copy_v3_v3(ray_start_local, snapdata->ray_start); - mul_m4_v3(imat, ray_start_local); + if (!treedata || !treedata->tree) { + return retval; + } - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start - * may already been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + if (snapdata->snap_to == SCE_SNAP_MODE_FACE) { + float ray_start_local[3]; + copy_v3_v3(ray_start_local, snapdata->ray_start); + mul_m4_v3(imat, ray_start_local); + + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start + * may already been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! + */ + float len_diff = 0.0f; + if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. */ - float len_diff = 0.0f; - if (snapdata->view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. - */ - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - if (BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) - { - float dvec[3]; - sub_v3_v3v3(dvec, nearest.co, ray_start_local); - len_diff = dot_v3v3(dvec, ray_normal_local); - /* You need to make sure that ray_start is really far away, - * because even in the Orthografic view, in some cases, - * the ray can start inside the object (see T50486) */ - if (len_diff > 400.0f) { - float ray_org_local[3]; - - copy_v3_v3(ray_org_local, snapdata->ray_origin); - mul_m4_v3(imat, ray_org_local); - - /* We pass a temp ray_start, set from object's boundbox, - * to avoid precision issues with very far away ray_start values - * (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl( - ray_start_local, ray_org_local, ray_normal_local, - len_diff + snapdata->depth_range[0] * local_scale); - local_depth -= len_diff; - } - else len_diff = 0.0f; + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + if (BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) + { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); + /* You need to make sure that ray_start is really far away, + * because even in the Orthografic view, in some cases, + * the ray can start inside the object (see T50486) */ + if (len_diff > 400.0f) { + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, snapdata->ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, + * to avoid precision issues with very far away ray_start values + * (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl( + ray_start_local, ray_org_local, ray_normal_local, + len_diff + snapdata->depth_range[0] * local_scale); + local_depth -= len_diff; } + else len_diff = 0.0f; } - if (r_hit_list) { - struct RayCastAll_Data data; - - data.bvhdata = treedata; - data.raycast_callback = treedata->raycast_callback; - data.obmat = obmat; - data.timat = timat; - data.len_diff = len_diff; - data.local_scale = local_scale; - data.ob = ob; - data.ob_uuid = ob_index; - data.hit_list = r_hit_list; - data.retval = retval; - - BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); - - retval = data.retval; - } - else { - BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; + } + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - if (BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); - - if (r_no) { - copy_v3_v3(r_no, hit.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } + if (BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); + + if (r_no) { + copy_v3_v3(r_no, hit.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } - retval = true; + retval = true; - if (r_index) { - *r_index = hit.index; - } + if (r_index) { + *r_index = hit.index; } } } } - else { - float ray_org_local[3]; - copy_v3_v3(ray_org_local, snapdata->ray_origin); - mul_m4_v3(imat, ray_org_local); - - BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH}; - - Nearest2dUserData neasrest2d = { - .dist_px_sq = SQUARE(*dist_px), - .r_axis_closest = {1.0f, 1.0f, 1.0f}, - .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]}, - .userdata = &treedata_type, - .index = -1}; - - float lpmat[4][4]; - mul_m4_m4m4(lpmat, snapdata->pmat, obmat); - dist_squared_to_projected_aabb_precalc( - &neasrest2d.data_precalc, lpmat, - snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, - (snapdata->depth_range[0] * local_scale), snapdata->mval, - ray_org_local, ray_normal_local); - - BVHTree_WalkLeafCallback cb_walk_leaf = - (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? - cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; - - BLI_bvhtree_walk_dfs( - treedata->tree, - cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); - - if (neasrest2d.index != -1) { - copy_v3_v3(r_loc, neasrest2d.co); - mul_m4_v3(obmat, r_loc); - if (r_no) { - copy_v3_v3(r_no, neasrest2d.no); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } - *dist_px = sqrtf(neasrest2d.dist_px_sq); - *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + } + else { + float ray_org_local[3]; + copy_v3_v3(ray_org_local, snapdata->ray_origin); + mul_m4_v3(imat, ray_org_local); - retval = true; - } - } + Nearest2dUserData neasrest2d = { + .dist_px_sq = SQUARE(*dist_px), + .r_axis_closest = {1.0f, 1.0f, 1.0f}, + .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]}, + .userdata = treedata, + .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_bedge_verts, + .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_bvert_no, + .index = -1}; - if ((sctx->flag & SNAP_OBJECT_USE_CACHE) == 0) { - if (treedata) { - free_bvhtree_from_editmesh(treedata); + float lpmat[4][4]; + mul_m4_m4m4(lpmat, snapdata->pmat, obmat); + dist_squared_to_projected_aabb_precalc( + &neasrest2d.data_precalc, lpmat, + snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half, + (snapdata->depth_range[0] * local_scale), snapdata->mval, + ray_org_local, ray_normal_local); + + BVHTree_WalkLeafCallback cb_walk_leaf = + (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; + + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d); + + if (neasrest2d.index != -1) { + copy_v3_v3(r_loc, neasrest2d.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest2d.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); } + *dist_px = sqrtf(neasrest2d.dist_px_sq); + *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir); + + retval = true; } } @@ -1703,7 +1648,6 @@ static bool snapObject( } retval = snapDerivedMesh( sctx, snapdata, ob, dm, obmat, ob_index, - true, ray_depth, dist_px, r_loc, r_no, r_index, r_hit_list); @@ -1880,6 +1824,9 @@ SnapObjectContext *ED_transform_snap_object_context_create( sctx->bmain = bmain; sctx->scene = scene; + sctx->cache.object_map = BLI_ghash_ptr_new(__func__); + sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + return sctx; } @@ -1894,11 +1841,6 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d( sctx->v3d_data.ar = ar; sctx->v3d_data.v3d = v3d; - if (sctx->flag & SNAP_OBJECT_USE_CACHE) { - sctx->cache.object_map = BLI_ghash_ptr_new(__func__); - sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - } - return sctx; } @@ -1930,10 +1872,8 @@ static void snap_object_data_free(void *sod_v) void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) { - if (sctx->flag & SNAP_OBJECT_USE_CACHE) { - BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free); - BLI_memarena_free(sctx->cache.mem_arena); - } + BLI_ghash_free(sctx->cache.object_map, NULL, snap_object_data_free); + BLI_memarena_free(sctx->cache.mem_arena); MEM_freeN(sctx); } @@ -1956,7 +1896,7 @@ bool ED_transform_snap_object_project_ray_ex( SnapObjectContext *sctx, const unsigned short snap_to, const struct SnapObjectParams *params, - const float UNUSED(ray_start[3]), const float UNUSED(ray_normal[3]), + const float ray_start[3], const float ray_normal[3], float *ray_depth, float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) @@ -1964,7 +1904,9 @@ bool ED_transform_snap_object_project_ray_ex( const float depth_range[2] = {0.0f, FLT_MAX}; SnapData snapdata; - snap_data_set(&snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE, NULL, r_loc, r_loc, r_no, depth_range); + snap_data_set( + &snapdata, sctx->v3d_data.ar, snap_to, VIEW_PROJ_NONE, + NULL, ray_start, ray_start, ray_normal, depth_range); return snapObjectsRay( sctx, &snapdata, @@ -2083,11 +2025,13 @@ static bool transform_snap_context_project_view3d_mixed_impl( BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0); if (use_depth) { - const float dist_px_orig = *dist_px; + const float dist_px_orig = dist_px ? *dist_px : 0; for (int i = 2; i >= 0; i--) { if (snap_to_flag & (1 << i)) { - if (i == 0) + if (i == 0) { + BLI_assert(dist_px != NULL); *dist_px = dist_px_orig; + } if (ED_transform_snap_object_project_view3d( sctx, elem_type[i], params, diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 52febe642a0..4164f5fa75d 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -77,6 +77,16 @@ void IMB_colormanagement_transform(float *buffer, int width, int height, int cha const char *from_colorspace, const char *to_colorspace, bool predivide); void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide); +void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace); +void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace); +void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer, + int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace); +void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer, + int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace); void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace); void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], struct ColorSpace *colorspace); @@ -185,6 +195,8 @@ void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_proc void IMB_colormanagement_processor_apply_pixel(struct ColormanageProcessor *cm_processor, float *pixel, int channels); void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height, int channels, bool predivide); +void IMB_colormanagement_processor_apply_byte(struct ColormanageProcessor *cm_processor, + unsigned char *buffer, int width, int height, int channels); void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor); /* ** OpenGL drawing routines using GLSL for color space transform ** */ diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index a45346279d9..48cba3e0800 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -1555,21 +1555,25 @@ static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *displ typedef struct ProcessorTransformThread { ColormanageProcessor *cm_processor; - float *buffer; + unsigned char *byte_buffer; + float *float_buffer; int width; int start_line; int tot_line; int channels; bool predivide; + bool float_from_byte; } ProcessorTransformThread; typedef struct ProcessorTransformInit { ColormanageProcessor *cm_processor; - float *buffer; + unsigned char *byte_buffer; + float *float_buffer; int width; int height; int channels; bool predivide; + bool float_from_byte; } ProcessorTransformInitData; static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v) @@ -1577,17 +1581,24 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v; ProcessorTransformInitData *init_data = (ProcessorTransformInitData *) init_data_v; - int channels = init_data->channels; - int width = init_data->width; - bool predivide = init_data->predivide; + const int channels = init_data->channels; + const int width = init_data->width; + const bool predivide = init_data->predivide; + const bool float_from_byte = init_data->float_from_byte; - size_t offset = ((size_t)channels) * start_line * width; + const size_t offset = ((size_t)channels) * start_line * width; memset(handle, 0, sizeof(ProcessorTransformThread)); handle->cm_processor = init_data->cm_processor; - handle->buffer = init_data->buffer + offset; + if (init_data->byte_buffer != NULL) { + /* TODO(serge): Offset might be different for byte and float buffers. */ + handle->byte_buffer = init_data->byte_buffer + offset; + } + if (init_data->float_buffer != NULL) { + handle->float_buffer = init_data->float_buffer + offset; + } handle->width = width; @@ -1596,33 +1607,62 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int handle->channels = channels; handle->predivide = predivide; + handle->float_from_byte = float_from_byte; } static void *do_processor_transform_thread(void *handle_v) { ProcessorTransformThread *handle = (ProcessorTransformThread *) handle_v; - float *buffer = handle->buffer; - int channels = handle->channels; - int width = handle->width; - int height = handle->tot_line; - bool predivide = handle->predivide; - - IMB_colormanagement_processor_apply(handle->cm_processor, buffer, width, height, channels, predivide); + unsigned char *byte_buffer = handle->byte_buffer; + float *float_buffer = handle->float_buffer; + const int channels = handle->channels; + const int width = handle->width; + const int height = handle->tot_line; + const bool predivide = handle->predivide; + const bool float_from_byte = handle->float_from_byte; + + if (float_from_byte) { + IMB_buffer_float_from_byte(float_buffer, byte_buffer, + IB_PROFILE_SRGB, IB_PROFILE_SRGB, + true, + width, height, width, width); + IMB_colormanagement_processor_apply(handle->cm_processor, + float_buffer, + width, height, channels, + predivide); + } + else { + if (byte_buffer != NULL) { + IMB_colormanagement_processor_apply_byte(handle->cm_processor, + byte_buffer, + width, height, channels); + } + if (float_buffer != NULL) { + IMB_colormanagement_processor_apply(handle->cm_processor, + float_buffer, + width, height, channels, + predivide); + } + } return NULL; } -static void processor_transform_apply_threaded(float *buffer, int width, int height, int channels, - ColormanageProcessor *cm_processor, bool predivide) +static void processor_transform_apply_threaded(unsigned char *byte_buffer, float *float_buffer, + const int width, const int height, const int channels, + ColormanageProcessor *cm_processor, + const bool predivide, const bool float_from_byte) { ProcessorTransformInitData init_data; init_data.cm_processor = cm_processor; - init_data.buffer = buffer; + init_data.byte_buffer = byte_buffer; + init_data.float_buffer = float_buffer; init_data.width = width; init_data.height = height; init_data.channels = channels; init_data.predivide = predivide; + init_data.float_from_byte = float_from_byte; IMB_processor_apply_threaded(height, sizeof(ProcessorTransformThread), &init_data, processor_transform_init_handle, do_processor_transform_thread); @@ -1631,8 +1671,10 @@ static void processor_transform_apply_threaded(float *buffer, int width, int hei /*********************** Color space transformation functions *************************/ /* convert the whole buffer from specified by name color space to another - internal implementation */ -static void colormanagement_transform_ex(float *buffer, int width, int height, int channels, const char *from_colorspace, - const char *to_colorspace, bool predivide, bool do_threaded) +static void colormanagement_transform_ex(unsigned char *byte_buffer, float *float_buffer, + int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace, + bool predivide, bool do_threaded) { ColormanageProcessor *cm_processor; @@ -1649,10 +1691,19 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace); - if (do_threaded) - processor_transform_apply_threaded(buffer, width, height, channels, cm_processor, predivide); - else - IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide); + if (do_threaded) { + processor_transform_apply_threaded(byte_buffer, float_buffer, + width, height, channels, + cm_processor, predivide, false); + } + else { + if (byte_buffer != NULL) { + IMB_colormanagement_processor_apply_byte(cm_processor, byte_buffer, width, height, channels); + } + if (float_buffer != NULL) { + IMB_colormanagement_processor_apply(cm_processor, float_buffer, width, height, channels, predivide); + } + } IMB_colormanagement_processor_free(cm_processor); } @@ -1661,7 +1712,7 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide) { - colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false); + colormanagement_transform_ex(NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false); } /* convert the whole buffer from specified by name color space to another @@ -1670,7 +1721,54 @@ void IMB_colormanagement_transform(float *buffer, int width, int height, int cha void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide) { - colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true); + colormanagement_transform_ex(NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true); +} + +/* Similar to functions above, but operates on byte buffer. */ +void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace) +{ + colormanagement_transform_ex(buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, false); +} +void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace) +{ + colormanagement_transform_ex(buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true); +} + +/* Similar to above, but gets float buffer from display one. */ +void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer, + int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace) +{ + IMB_buffer_float_from_byte(float_buffer, byte_buffer, + IB_PROFILE_SRGB, IB_PROFILE_SRGB, + true, + width, height, width, width); + IMB_colormanagement_transform(float_buffer, + width, height, channels, + from_colorspace, to_colorspace, + true); +} +void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer, + int width, int height, int channels, + const char *from_colorspace, const char *to_colorspace) +{ + ColormanageProcessor *cm_processor; + if (from_colorspace == NULL || from_colorspace[0] == '\0') { + return; + } + if (STREQ(from_colorspace, to_colorspace)) { + /* If source and destination color spaces are identical, skip + * threading overhead and simply do nothing + */ + return; + } + cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace); + processor_transform_apply_threaded(byte_buffer, float_buffer, + width, height, channels, + cm_processor, true, true); + IMB_colormanagement_processor_free(cm_processor); } void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace) @@ -1974,12 +2072,14 @@ void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float); float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space"); + /* TODO(sergey): Convert float directly to byte buffer. */ + memcpy(display_buffer_float, buffer, float_buffer_size); cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); - processor_transform_apply_threaded(display_buffer_float, width, height, channels, - cm_processor, true); + processor_transform_apply_threaded(NULL, display_buffer_float, width, height, channels, + cm_processor, true, false); IMB_buffer_byte_from_float(display_buffer, display_buffer_float, channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, @@ -3100,6 +3200,25 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo } } +void IMB_colormanagement_processor_apply_byte(ColormanageProcessor *cm_processor, + unsigned char *buffer, + int width, int height, int channels) +{ + /* TODO(sergey): Would be nice to support arbitrary channels configurations, + * but for now it's not so important. + */ + BLI_assert(channels == 4); + float pixel[4]; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + size_t offset = channels * (((size_t)y) * width + x); + rgba_uchar_to_float(pixel, buffer + offset); + IMB_colormanagement_processor_apply_v4(cm_processor, pixel); + rgba_float_to_uchar(buffer + offset, pixel); + } + } +} + void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor) { if (cm_processor->curve_mapping) diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 8ee15ef21a3..918d0f00040 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1716,6 +1716,7 @@ typedef struct Scene { #define SCER_LOCK_FRAME_SELECTION (1<<1) /* timeline/keyframe jumping - only selected items (on by default) */ #define SCE_KEYS_NO_SELONLY (1<<2) +#define SCER_SHOW_SUBFRAME (1<<3) /* mode (int now) */ #define R_OSA 0x0001 diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 1166fb89a0a..8ee49045bc5 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -792,6 +792,21 @@ static void rna_Scene_frame_current_set(PointerRNA *ptr, int value) data->r.cfra = value; } +static float rna_Scene_frame_float_get(PointerRNA *ptr) +{ + Scene *data = (Scene *)ptr->data; + return (float)data->r.cfra + data->r.subframe; +} + +static void rna_Scene_frame_float_set(PointerRNA *ptr, float value) +{ + Scene *data = (Scene *)ptr->data; + /* if negative frames aren't allowed, then we can't use them */ + FRAMENUMBER_MIN_CLAMP(value); + data->r.cfra = (int)value; + data->r.subframe = value - data->r.cfra; +} + static float rna_Scene_frame_current_final_get(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->data; @@ -872,6 +887,12 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value) data->r.pefra = value; } +static void rna_Scene_show_subframe_update(Main *UNUSED(bmain), Scene *UNUSED(current_scene), PointerRNA *ptr) +{ + Scene *scene = (Scene *)ptr->id.data; + scene->r.subframe = 0.0f; +} + static void rna_Scene_frame_update(Main *bmain, Scene *UNUSED(current_scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->id.data; @@ -7081,8 +7102,19 @@ void RNA_def_scene(BlenderRNA *brna) prop = RNA_def_property(srna, "frame_subframe", PROP_FLOAT, PROP_TIME); RNA_def_property_float_sdna(prop, NULL, "r.subframe"); RNA_def_property_ui_text(prop, "Current Sub-Frame", ""); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); - + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2); + RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_frame_update"); + + prop = RNA_def_property(srna, "frame_float", PROP_FLOAT, PROP_TIME); + RNA_def_property_ui_text(prop, "Current Sub-Frame", ""); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_range(prop, MINAFRAME, MAXFRAME); + RNA_def_property_ui_range(prop, MINAFRAME, MAXFRAME, 0.1, 2); + RNA_def_property_float_funcs(prop, "rna_Scene_frame_float_get", "rna_Scene_frame_float_set", NULL); + RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_frame_update"); + prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_int_sdna(prop, NULL, "r.sfra"); @@ -7147,7 +7179,15 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_int_funcs(prop, NULL, "rna_Scene_preview_range_end_frame_set", NULL); RNA_def_property_ui_text(prop, "Preview Range End Frame", "Alternative end frame for UI playback"); RNA_def_property_update(prop, NC_SCENE | ND_FRAME, NULL); - + + /* Subframe for moblur debug. */ + prop = RNA_def_property(srna, "show_subframe", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_boolean_sdna(prop, NULL, "r.flag", SCER_SHOW_SUBFRAME); + RNA_def_property_ui_text(prop, "Show Subframe", + "Show current scene subframe and allow set it using interface tools"); + RNA_def_property_update(prop, NC_SCENE | ND_FRAME, "rna_Scene_show_subframe_update"); + /* Timeline / Time Navigation settings */ prop = RNA_def_property(srna, "show_keys_from_selected_only", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCE_KEYS_NO_SELONLY); diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 08d118a2026..f6acbef96e9 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -38,10 +38,12 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_task.h" #include "BKE_cdderivedmesh.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_image.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_texture.h" @@ -200,21 +202,130 @@ static void updateDepsgraph(ModifierData *md, } } +typedef struct DisplaceUserdata { + /*const*/ DisplaceModifierData *dmd; + struct ImagePool *pool; + MDeformVert *dvert; + float weight; + int defgrp_index; + int direction; + bool use_global_direction; + float (*tex_co)[3]; + float (*vertexCos)[3]; + float local_mat[4][4]; + MVert *mvert; + float (*vert_clnors)[3]; +} DisplaceUserdata; + +static void displaceModifier_do_task(void *userdata, const int iter) +{ + DisplaceUserdata *data = (DisplaceUserdata *)userdata; + DisplaceModifierData *dmd = data->dmd; + MDeformVert *dvert = data->dvert; + float weight = data->weight; + int defgrp_index = data->defgrp_index; + int direction = data->direction; + bool use_global_direction = data->use_global_direction; + float (*tex_co)[3] = data->tex_co; + float (*vertexCos)[3] = data->vertexCos; + MVert *mvert = data->mvert; + float (*vert_clnors)[3] = data->vert_clnors; + + const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */ + + TexResult texres; + float strength = dmd->strength; + float delta; + float local_vec[3]; + + if (dvert) { + weight = defvert_find_weight(dvert + iter, defgrp_index); + if (weight == 0.0f) { + return; + } + } + + if (dmd->texture) { + texres.nor = NULL; + BKE_texture_get_value_ex(dmd->modifier.scene, dmd->texture, tex_co[iter], &texres, data->pool, false); + delta = texres.tin - dmd->midlevel; + } + else { + delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */ + } + + if (dvert) { + strength *= weight; + } + + delta *= strength; + CLAMP(delta, -10000, 10000); + + switch (direction) { + case MOD_DISP_DIR_X: + if (use_global_direction) { + vertexCos[iter][0] += delta * data->local_mat[0][0]; + vertexCos[iter][1] += delta * data->local_mat[1][0]; + vertexCos[iter][2] += delta * data->local_mat[2][0]; + } + else { + vertexCos[iter][0] += delta; + } + break; + case MOD_DISP_DIR_Y: + if (use_global_direction) { + vertexCos[iter][0] += delta * data->local_mat[0][1]; + vertexCos[iter][1] += delta * data->local_mat[1][1]; + vertexCos[iter][2] += delta * data->local_mat[2][1]; + } + else { + vertexCos[iter][1] += delta; + } + break; + case MOD_DISP_DIR_Z: + if (use_global_direction) { + vertexCos[iter][0] += delta * data->local_mat[0][2]; + vertexCos[iter][1] += delta * data->local_mat[1][2]; + vertexCos[iter][2] += delta * data->local_mat[2][2]; + } + else { + vertexCos[iter][2] += delta; + } + break; + case MOD_DISP_DIR_RGB_XYZ: + local_vec[0] = texres.tr - dmd->midlevel; + local_vec[1] = texres.tg - dmd->midlevel; + local_vec[2] = texres.tb - dmd->midlevel; + if (use_global_direction) { + mul_transposed_mat3_m4_v3(data->local_mat, local_vec); + } + mul_v3_fl(local_vec, strength); + add_v3_v3(vertexCos[iter], local_vec); + break; + case MOD_DISP_DIR_NOR: + vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f); + vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f); + vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f); + break; + case MOD_DISP_DIR_CLNOR: + madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta); + break; + } +} + /* dm must be a CDDerivedMesh */ static void displaceModifier_do( DisplaceModifierData *dmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { - int i; MVert *mvert; MDeformVert *dvert; int direction = dmd->direction; int defgrp_index; float (*tex_co)[3]; float weight = 1.0f; /* init value unused but some compilers may complain */ - const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */ float (*vert_clnors)[3] = NULL; - float local_mat[4][4]; + float local_mat[4][4] = {0}; const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL; if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return; @@ -259,81 +370,25 @@ static void displaceModifier_do( copy_m4_m4(local_mat, ob->obmat); } - for (i = 0; i < numVerts; i++) { - TexResult texres; - float strength = dmd->strength; - float delta; - float local_vec[3]; - - if (dvert) { - weight = defvert_find_weight(dvert + i, defgrp_index); - if (weight == 0.0f) continue; - } - - if (dmd->texture) { - texres.nor = NULL; - BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false); - delta = texres.tin - dmd->midlevel; - } - else { - delta = delta_fixed; /* (1.0f - dmd->midlevel) */ /* never changes */ - } + DisplaceUserdata data = {NULL}; + data.dmd = dmd; + data.dvert = dvert; + data.weight = weight; + data.defgrp_index = defgrp_index; + data.direction = direction; + data.use_global_direction = use_global_direction; + data.tex_co = tex_co; + data.vertexCos = vertexCos; + copy_m4_m4(data.local_mat, local_mat); + data.mvert = mvert; + data.vert_clnors = vert_clnors; + if (dmd->texture != NULL) { + data.pool = BKE_image_pool_new(); + } + BLI_task_parallel_range(0, numVerts, &data, displaceModifier_do_task, numVerts > 512); - if (dvert) strength *= weight; - - delta *= strength; - CLAMP(delta, -10000, 10000); - - switch (direction) { - case MOD_DISP_DIR_X: - if (use_global_direction) { - vertexCos[i][0] += delta * local_mat[0][0]; - vertexCos[i][1] += delta * local_mat[1][0]; - vertexCos[i][2] += delta * local_mat[2][0]; - } - else { - vertexCos[i][0] += delta; - } - break; - case MOD_DISP_DIR_Y: - if (use_global_direction) { - vertexCos[i][0] += delta * local_mat[0][1]; - vertexCos[i][1] += delta * local_mat[1][1]; - vertexCos[i][2] += delta * local_mat[2][1]; - } - else { - vertexCos[i][1] += delta; - } - break; - case MOD_DISP_DIR_Z: - if (use_global_direction) { - vertexCos[i][0] += delta * local_mat[0][2]; - vertexCos[i][1] += delta * local_mat[1][2]; - vertexCos[i][2] += delta * local_mat[2][2]; - } - else { - vertexCos[i][2] += delta; - } - break; - case MOD_DISP_DIR_RGB_XYZ: - local_vec[0] = texres.tr - dmd->midlevel; - local_vec[1] = texres.tg - dmd->midlevel; - local_vec[2] = texres.tb - dmd->midlevel; - if (use_global_direction) { - mul_transposed_mat3_m4_v3(local_mat, local_vec); - } - mul_v3_fl(local_vec, strength); - add_v3_v3(vertexCos[i], local_vec); - break; - case MOD_DISP_DIR_NOR: - vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f); - vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f); - vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f); - break; - case MOD_DISP_DIR_CLNOR: - madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta); - break; - } + if (data.pool != NULL) { + BKE_image_pool_free(data.pool); } if (tex_co) { diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 38ffdaa709b..ca7b3ce8039 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -1001,8 +1001,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, ExplodeModifierData *emd = (ExplodeModifierData *) md; ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ob, md); - DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ - if (psmd) { ParticleSystem *psys = psmd->psys; @@ -1010,6 +1008,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, if (psys->part == NULL || psys->particles == NULL) return derivedData; if (psmd->dm_final == NULL) return derivedData; + DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ + /* 1. find faces to be exploded if needed */ if (emd->facepa == NULL || psmd->flag & eParticleSystemFlag_Pars || diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index a297dac0f55..08d00e9148a 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -235,13 +235,13 @@ struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name) void RE_texture_rng_init() RET_NONE void RE_texture_rng_exit() RET_NONE -bool RE_layers_have_name(struct RenderResult *result) {STUB_ASSERT(0); return 0;} +bool RE_layers_have_name(struct RenderResult *result) RET_ZERO const char *RE_engine_active_view_get(struct RenderEngine *engine) RET_NULL -void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) {STUB_ASSERT(0);} -void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) {STUB_ASSERT(0);} +void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) RET_NONE +void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) RET_NONE float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo) RET_ZERO int RE_engine_get_spherical_stereo(struct RenderEngine *engine, struct Object *camera) RET_ZERO -void RE_SetActiveRenderView(struct Render *re, const char *viewname) {STUB_ASSERT(0);} +void RE_SetActiveRenderView(struct Render *re, const char *viewname) RET_NONE struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL bool RE_HasFakeLayer(RenderResult *res) RET_ZERO @@ -460,17 +460,17 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex) RET_NONE void ED_node_tag_update_id(struct ID *id) RET_NONE void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node) RET_NONE void ED_node_tree_update(const struct bContext *C) RET_NONE -void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo){} -void ED_init_custom_node_type(struct bNodeType *ntype){} -void ED_init_custom_node_socket_type(struct bNodeSocketType *stype){} +void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo) RET_NONE +void ED_init_custom_node_type(struct bNodeType *ntype) RET_NONE +void ED_init_custom_node_socket_type(struct bNodeSocketType *stype) RET_NONE void ED_init_standard_node_socket_type(struct bNodeSocketType *stype) RET_NONE void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype) RET_NONE -int ED_node_tree_path_length(struct SpaceNode *snode){return 0;} -void ED_node_tree_path_get(struct SpaceNode *snode, char *value){} -void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length){} -void ED_node_tree_start(struct SpaceNode *snode, struct bNodeTree *ntree, struct ID *id, struct ID *from){} -void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode){} -void ED_node_tree_pop(struct SpaceNode *snode){} +int ED_node_tree_path_length(struct SpaceNode *snode) RET_ZERO +void ED_node_tree_path_get(struct SpaceNode *snode, char *value) RET_NONE +void ED_node_tree_path_get_fixedbuf(struct SpaceNode *snode, char *value, int max_length) RET_NONE +void ED_node_tree_start(struct SpaceNode *snode, struct bNodeTree *ntree, struct ID *id, struct ID *from) RET_NONE +void ED_node_tree_push(struct SpaceNode *snode, struct bNodeTree *ntree, struct bNode *gnode) RET_NONE +void ED_node_tree_pop(struct SpaceNode *snode) RET_NONE int ED_view3d_scene_layer_set(int lay, const int *values, int *active) RET_ZERO void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip) RET_NONE void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) RET_NONE @@ -668,9 +668,9 @@ struct RenderEngine *RE_engine_create(struct RenderEngineType *type) RET_NULL void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) RET_NONE void RE_FreePersistentData(void) RET_NONE void RE_point_density_cache(struct Scene *scene, struct PointDensity *pd, const bool use_render_params) RET_NONE -void RE_point_density_minmax(struct Scene *scene, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE; -void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int resolution, const bool use_render_params, float *values) RET_NONE; -void RE_point_density_free(struct PointDensity *pd) RET_NONE; +void RE_point_density_minmax(struct Scene *scene, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE +void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int resolution, const bool use_render_params, float *values) RET_NONE +void RE_point_density_free(struct PointDensity *pd) RET_NONE void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE void RE_FreeAllPersistentData(void) RET_NONE float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO @@ -752,7 +752,7 @@ void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb * void macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id) RET_ZERO struct PyObject *pyrna_id_CreatePyObject(struct ID *id) RET_NULL -void BPY_context_update(struct bContext *C) RET_NONE; +void BPY_context_update(struct bContext *C) RET_NONE const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid) RET_ARG(msgid) /* intern/dualcon */ diff --git a/tests/gtests/blenlib/BLI_array_store_test.cc b/tests/gtests/blenlib/BLI_array_store_test.cc index b71dc4575f1..5af6e639e64 100644 --- a/tests/gtests/blenlib/BLI_array_store_test.cc +++ b/tests/gtests/blenlib/BLI_array_store_test.cc @@ -280,8 +280,8 @@ static void testbuffer_run_tests_single( BArrayStore *bs, ListBase *lb) { testbuffer_list_store_populate(bs, lb); - EXPECT_EQ(true, testbuffer_list_validate(lb)); - EXPECT_EQ(true, BLI_array_store_is_valid(bs)); + EXPECT_TRUE(testbuffer_list_validate(lb)); + EXPECT_TRUE(BLI_array_store_is_valid(bs)); #ifdef DEBUG_PRINT print_mem_saved("data", bs); #endif @@ -326,7 +326,7 @@ TEST(array_store, NopState) BArrayStore *bs = BLI_array_store_create(1, 32); const unsigned char data[] = "test"; BArrayState *state = BLI_array_store_state_add(bs, data, sizeof(data) - 1, NULL); - EXPECT_EQ(sizeof(data) - 1, BLI_array_store_state_size_get(state)); + EXPECT_EQ(BLI_array_store_state_size_get(state), sizeof(data) - 1); BLI_array_store_state_remove(bs, state); BLI_array_store_destroy(bs); } @@ -340,7 +340,7 @@ TEST(array_store, Single) size_t data_dst_len; data_dst = (char *)BLI_array_store_state_data_get_alloc(state, &data_dst_len); EXPECT_STREQ(data_src, data_dst); - EXPECT_EQ(sizeof(data_src), data_dst_len); + EXPECT_EQ(data_dst_len, sizeof(data_src)); BLI_array_store_destroy(bs); MEM_freeN((void *)data_dst); } @@ -354,8 +354,8 @@ TEST(array_store, DoubleNop) BArrayState *state_a = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL); BArrayState *state_b = BLI_array_store_state_add(bs, data_src, sizeof(data_src), state_a); - EXPECT_EQ(sizeof(data_src), BLI_array_store_calc_size_compacted_get(bs)); - EXPECT_EQ(sizeof(data_src) * 2, BLI_array_store_calc_size_expanded_get(bs)); + EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), sizeof(data_src)); + EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src) * 2); size_t data_dst_len; @@ -367,7 +367,7 @@ TEST(array_store, DoubleNop) EXPECT_STREQ(data_src, data_dst); MEM_freeN((void *)data_dst); - EXPECT_EQ(sizeof(data_src), data_dst_len); + EXPECT_EQ(data_dst_len, sizeof(data_src)); BLI_array_store_destroy(bs); } @@ -382,8 +382,8 @@ TEST(array_store, DoubleDiff) BArrayState *state_b = BLI_array_store_state_add(bs, data_src_b, sizeof(data_src_b), state_a); size_t data_dst_len; - EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_compacted_get(bs)); - EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_expanded_get(bs)); + EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), sizeof(data_src_a) * 2); + EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src_a) * 2); data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len); EXPECT_STREQ(data_src_a, data_dst); @@ -423,19 +423,19 @@ TEST(array_store, TextDupeIncreaseDecrease) /* forward */ testbuffer_list_store_populate(bs, &lb); - EXPECT_EQ(true, testbuffer_list_validate(&lb)); - EXPECT_EQ(true, BLI_array_store_is_valid(bs)); - EXPECT_EQ(strlen(D), BLI_array_store_calc_size_compacted_get(bs)); + EXPECT_TRUE(testbuffer_list_validate(&lb)); + EXPECT_TRUE(BLI_array_store_is_valid(bs)); + EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), strlen(D)); testbuffer_list_store_clear(bs, &lb); BLI_listbase_reverse(&lb); /* backwards */ testbuffer_list_store_populate(bs, &lb); - EXPECT_EQ(true, testbuffer_list_validate(&lb)); - EXPECT_EQ(true, BLI_array_store_is_valid(bs)); + EXPECT_TRUE(testbuffer_list_validate(&lb)); + EXPECT_TRUE(BLI_array_store_is_valid(bs)); /* larger since first block doesn't de-duplicate */ - EXPECT_EQ(strlen(D) * 4, BLI_array_store_calc_size_compacted_get(bs)); + EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), strlen(D) * 4); #undef D testbuffer_list_free(&lb); \ @@ -708,7 +708,7 @@ static void random_chunk_mutate_helper( testbuffer_run_tests_single(bs, &lb); size_t expected_size = chunks_per_buffer * chunk_count * stride; - EXPECT_EQ(expected_size, BLI_array_store_calc_size_compacted_get(bs)); + EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), expected_size); BLI_array_store_destroy(bs); @@ -782,8 +782,8 @@ TEST(array_store, PlainTextFiles) /* forwards */ testbuffer_list_store_populate(bs, &lb); - EXPECT_EQ(true, testbuffer_list_validate(&lb)); - EXPECT_EQ(true, BLI_array_store_is_valid(bs)); + EXPECT_TRUE(testbuffer_list_validate(&lb)); + EXPECT_TRUE(BLI_array_store_is_valid(bs)); #ifdef DEBUG_PRINT print_mem_saved("source code forward", bs); #endif @@ -793,8 +793,8 @@ TEST(array_store, PlainTextFiles) /* backwards */ testbuffer_list_store_populate(bs, &lb); - EXPECT_EQ(true, testbuffer_list_validate(&lb)); - EXPECT_EQ(true, BLI_array_store_is_valid(bs)); + EXPECT_TRUE(testbuffer_list_validate(&lb)); + EXPECT_TRUE(BLI_array_store_is_valid(bs)); #ifdef DEBUG_PRINT print_mem_saved("source code backwards", bs); #endif diff --git a/tests/gtests/blenlib/BLI_array_utils_test.cc b/tests/gtests/blenlib/BLI_array_utils_test.cc index eabf5bc72cf..518cd097326 100644 --- a/tests/gtests/blenlib/BLI_array_utils_test.cc +++ b/tests/gtests/blenlib/BLI_array_utils_test.cc @@ -45,50 +45,50 @@ TEST(array_utils, ReverseInt4) TEST(array_utils, FindIndexStringEmpty) { char data[] = "", find = '0'; - EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); - EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), -1); + EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), -1); } TEST(array_utils, FindIndexStringSingle) { char data[] = "0", find = '0'; - EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); - EXPECT_EQ(0, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), 0); + EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), 0); } TEST(array_utils, FindIndexStringSingleMissing) { char data[] = "1", find = '0'; - EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); - EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), -1); + EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), -1); } TEST(array_utils, FindIndexString4) { char data[] = "0123", find = '3'; - EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); - EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), 3); + EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), 3); } TEST(array_utils, FindIndexInt4) { int data[] = {0, 1, 2, 3}, find = 3; - EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); - EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data), &find), 3); + EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data), &find), 3); } TEST(array_utils, FindIndexInt4_DupeEnd) { int data[] = {0, 1, 2, 0}, find = 0; - EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); - EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data), &find), 0); + EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data), &find), 3); } TEST(array_utils, FindIndexInt4_DupeMid) { int data[] = {1, 0, 0, 3}, find = 0; - EXPECT_EQ(1, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); - EXPECT_EQ(2, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data), &find), 1); + EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data), &find), 2); } TEST(array_utils, FindIndexPointer) @@ -102,18 +102,18 @@ TEST(array_utils, FindIndexPointer) #define STACK_PUSH_AND_CHECK_FORWARD(v, i) { \ STACK_PUSH(data, v); \ - EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \ + EXPECT_EQ(BLI_array_findindex(data, STACK_SIZE(data), &(v)), i); \ } ((void)0) #define STACK_PUSH_AND_CHECK_BACKWARD(v, i) { \ STACK_PUSH(data, v); \ - EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \ + EXPECT_EQ(BLI_array_rfindindex(data, STACK_SIZE(data), &(v)), i); \ } ((void)0) #define STACK_PUSH_AND_CHECK_BOTH(v, i) { \ STACK_PUSH(data, v); \ - EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \ - EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \ + EXPECT_EQ(BLI_array_findindex(data, STACK_SIZE(data), &(v)), i); \ + EXPECT_EQ(BLI_array_rfindindex(data, STACK_SIZE(data), &(v)), i); \ } ((void)0) STACK_PUSH_AND_CHECK_BOTH(a, 0); diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc index fb32cb3f0a5..924c84d72d0 100644 --- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc +++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc @@ -118,21 +118,21 @@ static void str_ghash_tests(GHash *ghash, const char *id) TIMEIT_START(string_lookup); v = BLI_ghash_lookup(ghash, data_bis); - EXPECT_EQ(data_bis[0], GET_INT_FROM_POINTER(v)); + EXPECT_EQ(GET_INT_FROM_POINTER(v), data_bis[0]); for (p = w = c = data_bis; *c; c++) { if (*c == '.') { *c = '\0'; v = BLI_ghash_lookup(ghash, w); - EXPECT_EQ(w[0], GET_INT_FROM_POINTER(v)); + EXPECT_EQ(GET_INT_FROM_POINTER(v), w[0]); v = BLI_ghash_lookup(ghash, p); - EXPECT_EQ(p[0], GET_INT_FROM_POINTER(v)); + EXPECT_EQ(GET_INT_FROM_POINTER(v), p[0]); p = w = c + 1; } else if (*c == ' ') { *c = '\0'; v = BLI_ghash_lookup(ghash, w); - EXPECT_EQ(w[0], GET_INT_FROM_POINTER(v)); + EXPECT_EQ(GET_INT_FROM_POINTER(v), w[0]); w = c + 1; } } @@ -195,7 +195,7 @@ static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr while (i--) { void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(i)); - EXPECT_EQ(i, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), i); } TIMEIT_END(int_lookup); @@ -214,7 +214,7 @@ static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr TIMEIT_END(int_pop); } - EXPECT_EQ(0, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), 0); BLI_ghash_free(ghash, NULL, NULL); @@ -292,7 +292,7 @@ static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int for (i = nbr, dt = data; i--; dt++) { void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*dt)); - EXPECT_EQ(*dt, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), *dt); } TIMEIT_END(int_lookup); @@ -403,7 +403,7 @@ static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nb for (i = nbr, dt = data; i--; dt++) { void *v = BLI_ghash_lookup(ghash, (void *)(*dt)); - EXPECT_EQ(i, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), i); } TIMEIT_END(int_v4_lookup); @@ -469,7 +469,7 @@ static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned i for (i = nbr, dt = data; i--; dt++) { void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*dt)); - EXPECT_EQ(*dt, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), *dt); } BLI_ghash_clear(ghash, NULL, NULL); diff --git a/tests/gtests/blenlib/BLI_ghash_test.cc b/tests/gtests/blenlib/BLI_ghash_test.cc index ffbe5f5547f..6d075e29114 100644 --- a/tests/gtests/blenlib/BLI_ghash_test.cc +++ b/tests/gtests/blenlib/BLI_ghash_test.cc @@ -62,11 +62,11 @@ TEST(ghash, InsertLookup) BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); } - EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), TESTCASE_SIZE); for (i = TESTCASE_SIZE, k = keys; i--; k++) { void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*k)); - EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), *k); } BLI_ghash_free(ghash, NULL, NULL); @@ -85,16 +85,16 @@ TEST(ghash, InsertRemove) BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); } - EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), TESTCASE_SIZE); bkt_size = BLI_ghash_buckets_size(ghash); for (i = TESTCASE_SIZE, k = keys; i--; k++) { void *v = BLI_ghash_popkey(ghash, SET_UINT_IN_POINTER(*k), NULL); - EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), *k); } - EXPECT_EQ(0, BLI_ghash_size(ghash)); - EXPECT_EQ(bkt_size, BLI_ghash_buckets_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), 0); + EXPECT_EQ(BLI_ghash_buckets_size(ghash), bkt_size); BLI_ghash_free(ghash, NULL, NULL); } @@ -113,15 +113,15 @@ TEST(ghash, InsertRemoveShrink) BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); } - EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), TESTCASE_SIZE); bkt_size = BLI_ghash_buckets_size(ghash); for (i = TESTCASE_SIZE, k = keys; i--; k++) { void *v = BLI_ghash_popkey(ghash, SET_UINT_IN_POINTER(*k), NULL); - EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), *k); } - EXPECT_EQ(0, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), 0); EXPECT_LT(BLI_ghash_buckets_size(ghash), bkt_size); BLI_ghash_free(ghash, NULL, NULL); @@ -141,16 +141,16 @@ TEST(ghash, Copy) BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); } - EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), TESTCASE_SIZE); ghash_copy = BLI_ghash_copy(ghash, NULL, NULL); - EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash_copy)); - EXPECT_EQ(BLI_ghash_buckets_size(ghash), BLI_ghash_buckets_size(ghash_copy)); + EXPECT_EQ(BLI_ghash_size(ghash_copy), TESTCASE_SIZE); + EXPECT_EQ(BLI_ghash_buckets_size(ghash_copy), BLI_ghash_buckets_size(ghash)); for (i = TESTCASE_SIZE, k = keys; i--; k++) { void *v = BLI_ghash_lookup(ghash_copy, SET_UINT_IN_POINTER(*k)); - EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + EXPECT_EQ(GET_UINT_FROM_POINTER(v), *k); } BLI_ghash_free(ghash, NULL, NULL); @@ -171,7 +171,7 @@ TEST(ghash, Pop) BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); } - EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), TESTCASE_SIZE); GHashIterState pop_state = {0}; @@ -179,14 +179,14 @@ TEST(ghash, Pop) void *k, *v; bool success = BLI_ghash_pop(ghash, &pop_state, &k, &v); EXPECT_EQ(k, v); - EXPECT_EQ(success, true); + EXPECT_TRUE(success); if (i % 2) { BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(i * 4), SET_UINT_IN_POINTER(i * 4)); } } - EXPECT_EQ((TESTCASE_SIZE - TESTCASE_SIZE / 2 + TESTCASE_SIZE / 4), BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), (TESTCASE_SIZE - TESTCASE_SIZE / 2 + TESTCASE_SIZE / 4)); { void *k, *v; @@ -194,7 +194,7 @@ TEST(ghash, Pop) EXPECT_EQ(k, v); } } - EXPECT_EQ(0, BLI_ghash_size(ghash)); + EXPECT_EQ(BLI_ghash_size(ghash), 0); BLI_ghash_free(ghash, NULL, NULL); } diff --git a/tests/gtests/blenlib/BLI_hash_mm2a_test.cc b/tests/gtests/blenlib/BLI_hash_mm2a_test.cc index b35a1a809d6..109c925af4c 100644 --- a/tests/gtests/blenlib/BLI_hash_mm2a_test.cc +++ b/tests/gtests/blenlib/BLI_hash_mm2a_test.cc @@ -19,9 +19,9 @@ TEST(hash_mm2a, MM2ABasic) BLI_hash_mm2a_init(&mm2, 0); BLI_hash_mm2a_add(&mm2, (const unsigned char *)data, strlen(data)); #ifdef __LITTLE_ENDIAN__ - EXPECT_EQ(1633988145, BLI_hash_mm2a_end(&mm2)); + EXPECT_EQ(BLI_hash_mm2a_end(&mm2), 1633988145); #else - EXPECT_EQ(959283772, BLI_hash_mm2a_end(&mm2)); + EXPECT_EQ(BLI_hash_mm2a_end(&mm2), 959283772); #endif } @@ -43,11 +43,11 @@ TEST(hash_mm2a, MM2AConcatenateStrings) BLI_hash_mm2a_init(&mm2, 0); BLI_hash_mm2a_add(&mm2, (const unsigned char *)data123, strlen(data123)); #ifdef __LITTLE_ENDIAN__ - EXPECT_EQ(1545105348, hash); + EXPECT_EQ(hash, 1545105348); #else - EXPECT_EQ(2604964730, hash); + EXPECT_EQ(hash, 2604964730); #endif - EXPECT_EQ(hash, BLI_hash_mm2a_end(&mm2)); + EXPECT_EQ(BLI_hash_mm2a_end(&mm2), hash); } TEST(hash_mm2a, MM2AIntegers) @@ -67,9 +67,9 @@ TEST(hash_mm2a, MM2AIntegers) BLI_hash_mm2a_add(&mm2, (const unsigned char *)ints, sizeof(ints)); /* Yes, same hash here on little and big endian. */ #ifdef __LITTLE_ENDIAN__ - EXPECT_EQ(405493096, hash); + EXPECT_EQ(hash, 405493096); #else - EXPECT_EQ(405493096, hash); + EXPECT_EQ(hash, 405493096); #endif - EXPECT_EQ(hash, BLI_hash_mm2a_end(&mm2)); + EXPECT_EQ(BLI_hash_mm2a_end(&mm2), hash); } diff --git a/tests/gtests/blenlib/BLI_listbase_test.cc b/tests/gtests/blenlib/BLI_listbase_test.cc index 994b8f74541..4dac2d05bd8 100644 --- a/tests/gtests/blenlib/BLI_listbase_test.cc +++ b/tests/gtests/blenlib/BLI_listbase_test.cc @@ -74,25 +74,25 @@ TEST(listbase, FindLinkOrIndex) /* Empty list */ BLI_listbase_clear(&lb); - EXPECT_EQ(NULL, BLI_findlink(&lb, -1)); - EXPECT_EQ(NULL, BLI_findlink(&lb, 0)); - EXPECT_EQ(NULL, BLI_findlink(&lb, 1)); - EXPECT_EQ(NULL, BLI_rfindlink(&lb, -1)); - EXPECT_EQ(NULL, BLI_rfindlink(&lb, 0)); - EXPECT_EQ(NULL, BLI_rfindlink(&lb, 1)); - EXPECT_EQ(-1, BLI_findindex(&lb, link1)); + EXPECT_EQ(BLI_findlink(&lb, -1), (void*)NULL); + EXPECT_EQ(BLI_findlink(&lb, 0), (void*)NULL); + EXPECT_EQ(BLI_findlink(&lb, 1), (void*)NULL); + EXPECT_EQ(BLI_rfindlink(&lb, -1), (void*)NULL); + EXPECT_EQ(BLI_rfindlink(&lb, 0), (void*)NULL); + EXPECT_EQ(BLI_rfindlink(&lb, 1), (void*)NULL); + EXPECT_EQ(BLI_findindex(&lb, link1), -1); /* One link */ BLI_addtail(&lb, link1); - EXPECT_EQ(link1, BLI_findlink(&lb, 0)); - EXPECT_EQ(link1, BLI_rfindlink(&lb, 0)); - EXPECT_EQ(0, BLI_findindex(&lb, link1)); + EXPECT_EQ(BLI_findlink(&lb, 0), link1); + EXPECT_EQ(BLI_rfindlink(&lb, 0), link1); + EXPECT_EQ(BLI_findindex(&lb, link1), 0); /* Two links */ BLI_addtail(&lb, link2); - EXPECT_EQ(link2, BLI_findlink(&lb, 1)); - EXPECT_EQ(link2, BLI_rfindlink(&lb, 0)); - EXPECT_EQ(1, BLI_findindex(&lb, link2)); + EXPECT_EQ(BLI_findlink(&lb, 1), link2); + EXPECT_EQ(BLI_rfindlink(&lb, 0), link2); + EXPECT_EQ(BLI_findindex(&lb, link2), 1); BLI_freelistN(&lb); } diff --git a/tests/gtests/blenlib/BLI_path_util_test.cc b/tests/gtests/blenlib/BLI_path_util_test.cc index c80987c3586..d017ab18b4d 100644 --- a/tests/gtests/blenlib/BLI_path_util_test.cc +++ b/tests/gtests/blenlib/BLI_path_util_test.cc @@ -121,42 +121,42 @@ TEST(path_util, PathUtilFrame) { char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 1); - EXPECT_EQ(1, ret); + EXPECT_EQ(ret, 1); EXPECT_STREQ("123", path); } { char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 12); - EXPECT_EQ(1, ret); + EXPECT_EQ(ret, 1); EXPECT_STREQ("000000000123", path); } { char path[FILE_MAX] = "test_"; ret = BLI_path_frame(path, 123, 1); - EXPECT_EQ(1, ret); + EXPECT_EQ(ret, 1); EXPECT_STREQ("test_123", path); } { char path[FILE_MAX] = "test_"; ret = BLI_path_frame(path, 1, 12); - EXPECT_EQ(1, ret); + EXPECT_EQ(ret, 1); EXPECT_STREQ("test_000000000001", path); } { char path[FILE_MAX] = "test_############"; ret = BLI_path_frame(path, 1, 0); - EXPECT_EQ(1, ret); + EXPECT_EQ(ret, 1); EXPECT_STREQ("test_000000000001", path); } { char path[FILE_MAX] = "test_#_#_middle"; ret = BLI_path_frame(path, 123, 0); - EXPECT_EQ(1, ret); + EXPECT_EQ(ret, 1); EXPECT_STREQ("test_#_123_middle", path); } @@ -164,14 +164,14 @@ TEST(path_util, PathUtilFrame) { char path[FILE_MAX] = ""; ret = BLI_path_frame(path, 123, 0); - EXPECT_EQ(0, ret); + EXPECT_EQ(ret, 0); EXPECT_STREQ("", path); } { char path[FILE_MAX] = "test_middle"; ret = BLI_path_frame(path, 123, 0); - EXPECT_EQ(0, ret); + EXPECT_EQ(ret, 0); EXPECT_STREQ("test_middle", path); } } diff --git a/tests/gtests/blenlib/BLI_polyfill2d_test.cc b/tests/gtests/blenlib/BLI_polyfill2d_test.cc index a4ed70fbec9..5d112751fa0 100644 --- a/tests/gtests/blenlib/BLI_polyfill2d_test.cc +++ b/tests/gtests/blenlib/BLI_polyfill2d_test.cc @@ -98,14 +98,14 @@ static void test_polyfill_topology( } } } - EXPECT_EQ(poly_tot + (poly_tot - 3), BLI_edgehash_size(edgehash)); + EXPECT_EQ(BLI_edgehash_size(edgehash), poly_tot + (poly_tot - 3)); for (i = 0; i < poly_tot; i++) { const unsigned int v1 = i; const unsigned int v2 = (i + 1) % poly_tot; void **p = BLI_edgehash_lookup_p(edgehash, v1, v2); - EXPECT_EQ(1, (void *)p != NULL); - EXPECT_EQ(1, (intptr_t)*p); + EXPECT_EQ((void *)p != NULL, 1); + EXPECT_EQ((intptr_t)*p, 1); } for (ehi = BLI_edgehashIterator_new(edgehash), i = 0; @@ -113,7 +113,7 @@ static void test_polyfill_topology( BLI_edgehashIterator_step(ehi), i++) { void **p = BLI_edgehashIterator_getValue_p(ehi); - EXPECT_EQ(true, ELEM((intptr_t)*p, 1, 2)); + EXPECT_TRUE(ELEM((intptr_t)*p, 1, 2)); } BLI_edgehashIterator_free(ehi); @@ -135,7 +135,7 @@ static void test_polyfill_winding( count[winding_test < 0.0f] += 1; } } - EXPECT_EQ(true, ELEM(0, count[0], count[1])); + EXPECT_TRUE(ELEM(0, count[0], count[1])); } /** diff --git a/tests/gtests/blenlib/BLI_stack_test.cc b/tests/gtests/blenlib/BLI_stack_test.cc index 4c0b95f4b6b..18188937355 100644 --- a/tests/gtests/blenlib/BLI_stack_test.cc +++ b/tests/gtests/blenlib/BLI_stack_test.cc @@ -24,7 +24,7 @@ TEST(stack, Empty) BLI_Stack *stack; stack = BLI_stack_new(sizeof(int), __func__); - EXPECT_EQ(BLI_stack_is_empty(stack), true); + EXPECT_TRUE(BLI_stack_is_empty(stack)); EXPECT_EQ(BLI_stack_count(stack), 0); BLI_stack_free(stack); } @@ -37,11 +37,11 @@ TEST(stack, One) stack = BLI_stack_new(sizeof(in), __func__); BLI_stack_push(stack, (void *)&in); - EXPECT_EQ(BLI_stack_is_empty(stack), false); + EXPECT_FALSE(BLI_stack_is_empty(stack)); EXPECT_EQ(BLI_stack_count(stack), 1); BLI_stack_pop(stack, (void *)&out); - EXPECT_EQ(in, out); - EXPECT_EQ(BLI_stack_is_empty(stack), true); + EXPECT_EQ(out, in); + EXPECT_TRUE(BLI_stack_is_empty(stack)); EXPECT_EQ(BLI_stack_count(stack), 0); BLI_stack_free(stack); } @@ -59,12 +59,12 @@ TEST(stack, Range) } for (in = tot - 1; in >= 0; in--) { - EXPECT_EQ(BLI_stack_is_empty(stack), false); + EXPECT_FALSE(BLI_stack_is_empty(stack)); BLI_stack_pop(stack, (void *)&out); - EXPECT_EQ(in, out); + EXPECT_EQ(out, in); } - EXPECT_EQ(BLI_stack_is_empty(stack), true); + EXPECT_TRUE(BLI_stack_is_empty(stack)); BLI_stack_free(stack); } @@ -86,12 +86,12 @@ TEST(stack, String) } for (i = tot - 1; i >= 0; i--) { - EXPECT_EQ(BLI_stack_is_empty(stack), false); + EXPECT_FALSE(BLI_stack_is_empty(stack)); *((int *)in) = i; BLI_stack_pop(stack, (void *)&out); EXPECT_STREQ(in, out); } - EXPECT_EQ(BLI_stack_is_empty(stack), true); + EXPECT_TRUE(BLI_stack_is_empty(stack)); BLI_stack_free(stack); } @@ -115,7 +115,7 @@ TEST(stack, Peek) EXPECT_EQ(*ret, in[i % ARRAY_SIZE(in)]); } - EXPECT_EQ(BLI_stack_is_empty(stack), true); + EXPECT_TRUE(BLI_stack_is_empty(stack)); BLI_stack_free(stack); } @@ -140,7 +140,7 @@ TEST(stack, Clear) } BLI_stack_clear(stack); - EXPECT_EQ(BLI_stack_is_empty(stack), true); + EXPECT_TRUE(BLI_stack_is_empty(stack)); /* and again, this time check its valid */ for (in = 0; in < tot; in++) { @@ -148,12 +148,12 @@ TEST(stack, Clear) } for (in = tot - 1; in >= 0; in--) { - EXPECT_EQ(BLI_stack_is_empty(stack), false); + EXPECT_FALSE(BLI_stack_is_empty(stack)); BLI_stack_pop(stack, (void *)&out); - EXPECT_EQ(in, out); + EXPECT_EQ(out, in); } - EXPECT_EQ(BLI_stack_is_empty(stack), true); + EXPECT_TRUE(BLI_stack_is_empty(stack)); /* without this, we wont test case when mixed free/used */ tot /= 2; @@ -204,10 +204,10 @@ TEST(stack, Reuse) while (!BLI_stack_is_empty(stack)) { i--; BLI_stack_pop(stack, (void *)&sizes_test[i]); - EXPECT_EQ(sizes[i], sizes_test[i]); + EXPECT_EQ(sizes_test[i], sizes[i]); EXPECT_GT(i, -1); } - EXPECT_EQ(i, 0); + EXPECT_EQ(0, i); EXPECT_EQ(memcmp(sizes, sizes_test, sizeof(sizes) - sizeof(int)), 0); diff --git a/tests/gtests/blenlib/BLI_string_test.cc b/tests/gtests/blenlib/BLI_string_test.cc index 08f2a745bdb..f6f7e17c8ca 100644 --- a/tests/gtests/blenlib/BLI_string_test.cc +++ b/tests/gtests/blenlib/BLI_string_test.cc @@ -44,7 +44,7 @@ TEST(string, StrPartition) /* "mat.e-r_ial" -> "mat", '.', "e-r_ial", 3 */ pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(3, pre_ln); + EXPECT_EQ(pre_ln, 3); EXPECT_EQ(&str[3], sep); EXPECT_STREQ("e-r_ial", suf); } @@ -55,7 +55,7 @@ TEST(string, StrPartition) /* ".mate-rial--" -> "", '.', "mate-rial--", 0 */ pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); + EXPECT_EQ(pre_ln, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ("mate-rial--", suf); } @@ -65,7 +65,7 @@ TEST(string, StrPartition) /* ".__.--_" -> "", '.', "__.--_", 0 */ pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); + EXPECT_EQ(pre_ln, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ("__.--_", suf); } @@ -75,9 +75,9 @@ TEST(string, StrPartition) /* "" -> "", NULL, NULL, 0 */ pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 0); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } { @@ -85,9 +85,9 @@ TEST(string, StrPartition) /* "material" -> "material", NULL, NULL, 8 */ pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(8, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 8); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } } @@ -103,7 +103,7 @@ TEST(string, StrRPartition) /* "mat.e-r_ial" -> "mat.e-r", '_', "ial", 7 */ pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(7, pre_ln); + EXPECT_EQ(pre_ln, 7); EXPECT_EQ(&str[7], sep); EXPECT_STREQ("ial", suf); } @@ -114,7 +114,7 @@ TEST(string, StrRPartition) /* ".mate-rial--" -> ".mate-rial-", '-', "", 11 */ pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(11, pre_ln); + EXPECT_EQ(pre_ln, 11); EXPECT_EQ(&str[11], sep); EXPECT_STREQ("", suf); } @@ -124,7 +124,7 @@ TEST(string, StrRPartition) /* ".__.--_" -> ".__.--", '_', "", 6 */ pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(6, pre_ln); + EXPECT_EQ(pre_ln, 6); EXPECT_EQ(&str[6], sep); EXPECT_STREQ("", suf); } @@ -134,9 +134,9 @@ TEST(string, StrRPartition) /* "" -> "", NULL, NULL, 0 */ pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 0); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } { @@ -144,9 +144,9 @@ TEST(string, StrRPartition) /* "material" -> "material", NULL, NULL, 8 */ pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(8, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 8); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } } @@ -164,7 +164,7 @@ TEST(string, StrPartitionEx) /* "mat.e-r_ia.l" over "mat.e-r" -> "mat.e", '.', "r_ia.l", 3 */ pre_ln = BLI_str_partition_ex(str, str + 6, delim, &sep, &suf, true); - EXPECT_EQ(5, pre_ln); + EXPECT_EQ(pre_ln, 5); EXPECT_EQ(&str[5], sep); EXPECT_STREQ("r_ia.l", suf); } @@ -175,9 +175,9 @@ TEST(string, StrPartitionEx) /* "mate.rial" over "mate" -> "mate.rial", NULL, NULL, 4 */ pre_ln = BLI_str_partition_ex(str, str + 4, delim, &sep, &suf, true); - EXPECT_EQ(4, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 4); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } } @@ -193,7 +193,7 @@ TEST(string, StrPartitionUtf8) /* "ma\xc3\xb1te-r\xe2\x98\xafial" -> "ma", '\xc3\xb1', "te-r\xe2\x98\xafial", 2 */ pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(2, pre_ln); + EXPECT_EQ(pre_ln, 2); EXPECT_EQ(&str[2], sep); EXPECT_STREQ("te-r\xe2\x98\xafial", suf); } @@ -204,7 +204,7 @@ TEST(string, StrPartitionUtf8) /* "\xe2\x98\xafmate-rial-\xc3\xb1" -> "", '\xe2\x98\xaf', "mate-rial-\xc3\xb1", 0 */ pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); + EXPECT_EQ(pre_ln, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ("mate-rial-\xc3\xb1", suf); } @@ -214,7 +214,7 @@ TEST(string, StrPartitionUtf8) /* "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1" -> "", '\xe2\x98\xaf', ".\xc3\xb1_.--\xc3\xb1", 0 */ pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); + EXPECT_EQ(pre_ln, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ(".\xc3\xb1_.--\xc3\xb1", suf); } @@ -224,9 +224,9 @@ TEST(string, StrPartitionUtf8) /* "" -> "", NULL, NULL, 0 */ pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 0); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } { @@ -234,9 +234,9 @@ TEST(string, StrPartitionUtf8) /* "material" -> "material", NULL, NULL, 8 */ pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(8, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 8); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } } @@ -252,7 +252,7 @@ TEST(string, StrRPartitionUtf8) /* "ma\xc3\xb1te-r\xe2\x98\xafial" -> "mat\xc3\xb1te-r", '\xe2\x98\xaf', "ial", 8 */ pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(8, pre_ln); + EXPECT_EQ(pre_ln, 8); EXPECT_EQ(&str[8], sep); EXPECT_STREQ("ial", suf); } @@ -263,7 +263,7 @@ TEST(string, StrRPartitionUtf8) /* "\xe2\x98\xafmate-rial-\xc3\xb1" -> "\xe2\x98\xafmate-rial-", '\xc3\xb1', "", 13 */ pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(13, pre_ln); + EXPECT_EQ(pre_ln, 13); EXPECT_EQ(&str[13], sep); EXPECT_STREQ("", suf); } @@ -273,7 +273,7 @@ TEST(string, StrRPartitionUtf8) /* "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1" -> "\xe2\x98\xaf.\xc3\xb1_.--", '\xc3\xb1', "", 10 */ pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(10, pre_ln); + EXPECT_EQ(pre_ln, 10); EXPECT_EQ(&str[10], sep); EXPECT_STREQ("", suf); } @@ -283,9 +283,9 @@ TEST(string, StrRPartitionUtf8) /* "" -> "", NULL, NULL, 0 */ pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(0, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 0); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } { @@ -293,9 +293,9 @@ TEST(string, StrRPartitionUtf8) /* "material" -> "material", NULL, NULL, 8 */ pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(8, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 8); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } } @@ -313,7 +313,7 @@ TEST(string, StrPartitionExUtf8) /* "ma\xc3\xb1te-r\xe2\x98\xafial" over "ma\xc3\xb1te" -> "ma", '\xc3\xb1', "te-r\xe2\x98\xafial", 2 */ pre_ln = BLI_str_partition_ex_utf8(str, str + 6, delim, &sep, &suf, true); - EXPECT_EQ(2, pre_ln); + EXPECT_EQ(pre_ln, 2); EXPECT_EQ(&str[2], sep); EXPECT_STREQ("te-r\xe2\x98\xafial", suf); } @@ -324,9 +324,9 @@ TEST(string, StrPartitionExUtf8) /* "mate\xe2\x98\xafrial" over "mate" -> "mate\xe2\x98\xafrial", NULL, NULL, 4 */ pre_ln = BLI_str_partition_ex_utf8(str, str + 4, delim, &sep, &suf, true); - EXPECT_EQ(4, pre_ln); - EXPECT_EQ(NULL, sep); - EXPECT_EQ(NULL, suf); + EXPECT_EQ(pre_ln, 4); + EXPECT_EQ(sep, (void*)NULL); + EXPECT_EQ(suf, (void*)NULL); } } @@ -373,7 +373,7 @@ TEST(string, StrFormatIntGrouped) const int word_cmp_size = ARRAY_SIZE(word_cmp); \ const int word_num = BLI_string_find_split_words( \ word_str_src, word_str_src_len, ' ', word_info, word_cmp_size_input); \ - EXPECT_EQ(word_num, word_cmp_size - 1); \ + EXPECT_EQ(word_cmp_size - 1, word_num); \ EXPECT_EQ_ARRAY_ND<const int[2]>(word_cmp, word_info, word_cmp_size, 2); \ } ((void)0) @@ -449,20 +449,20 @@ TEST(string, StringStrncasestr) const char *res; res = BLI_strncasestr(str_test0, "", 0); - EXPECT_EQ(str_test0, res); + EXPECT_EQ(res, str_test0); res = BLI_strncasestr(str_test0, " ", 1); - EXPECT_EQ(str_test0 + 6, res); + EXPECT_EQ(res, str_test0 + 6); res = BLI_strncasestr(str_test0, "her", 3); - EXPECT_EQ(str_test0 + 7, res); + EXPECT_EQ(res, str_test0 + 7); res = BLI_strncasestr(str_test0, "ARCh", 4); - EXPECT_EQ(str_test0 + 2, res); + EXPECT_EQ(res, str_test0 + 2); res = BLI_strncasestr(str_test0, "earcq", 4); - EXPECT_EQ(str_test0 + 1, res); + EXPECT_EQ(res, str_test0 + 1); res = BLI_strncasestr(str_test0, "not there", 9); - EXPECT_EQ(NULL, res); + EXPECT_EQ(res, (void*)NULL); } diff --git a/tests/gtests/blenlib/BLI_string_utf8_test.cc b/tests/gtests/blenlib/BLI_string_utf8_test.cc index c0beb92eeec..95d73b4242f 100644 --- a/tests/gtests/blenlib/BLI_string_utf8_test.cc +++ b/tests/gtests/blenlib/BLI_string_utf8_test.cc @@ -298,7 +298,7 @@ TEST(string, Utf8InvalidBytes) const int num_errors_found = BLI_utf8_invalid_strip(buff, sizeof(buff) - 1); printf("[%02d] -> [%02d] \"%s\" -> \"%s\"\n", num_errors, num_errors_found, tst, buff); - EXPECT_EQ(num_errors, num_errors_found); + EXPECT_EQ(num_errors_found, num_errors); EXPECT_STREQ(buff, tst_stripped); } } diff --git a/tests/gtests/bmesh/bmesh_core_test.cc b/tests/gtests/bmesh/bmesh_core_test.cc index f386abc0b2b..b2cb1a4e8a3 100644 --- a/tests/gtests/bmesh/bmesh_core_test.cc +++ b/tests/gtests/bmesh/bmesh_core_test.cc @@ -12,18 +12,18 @@ TEST(bmesh_core, BMVertCreate) { BMeshCreateParams bm_params; bm_params.use_toolflags = true; bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params); - EXPECT_EQ(0, bm->totvert); + EXPECT_EQ(bm->totvert, 0); /* make a custom layer so we can see if it is copied properly */ BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLT); bv1 = BM_vert_create(bm, co1, NULL, BM_CREATE_NOP); ASSERT_TRUE(bv1 != NULL); - EXPECT_EQ(1.0f, bv1->co[0]); - EXPECT_EQ(2.0f, bv1->co[1]); - EXPECT_EQ(0.0f, bv1->co[2]); + EXPECT_EQ(bv1->co[0], 1.0f); + EXPECT_EQ(bv1->co[1], 2.0f); + EXPECT_EQ(bv1->co[2], 0.0f); EXPECT_TRUE(is_zero_v3(bv1->no)); - EXPECT_EQ((char)BM_VERT, bv1->head.htype); - EXPECT_EQ(0, bv1->head.hflag); - EXPECT_EQ(0, bv1->head.api_flag); + EXPECT_EQ(bv1->head.htype, (char)BM_VERT); + EXPECT_EQ(bv1->head.hflag, 0); + EXPECT_EQ(bv1->head.api_flag, 0); bv2 = BM_vert_create(bm, NULL, NULL, BM_CREATE_NOP); ASSERT_TRUE(bv2 != NULL); EXPECT_TRUE(is_zero_v3(bv2->co)); @@ -33,7 +33,7 @@ TEST(bmesh_core, BMVertCreate) { bv3 = BM_vert_create(bm, co1, bv2, BM_CREATE_NOP); ASSERT_TRUE(bv3 != NULL); EXPECT_FALSE(BM_elem_flag_test((BMElem *)bv3, BM_ELEM_SELECT)); - EXPECT_EQ(1.5f, BM_elem_float_data_get(&bm->vdata, bv3, CD_PROP_FLT)); - EXPECT_EQ(3, BM_mesh_elem_count(bm, BM_VERT)); + EXPECT_EQ(BM_elem_float_data_get(&bm->vdata, bv3, CD_PROP_FLT), 1.5f); + EXPECT_EQ(BM_mesh_elem_count(bm, BM_VERT), 3); BM_mesh_free(bm); } diff --git a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc index 345c3824b63..01ff38f0528 100644 --- a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc +++ b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc @@ -8,7 +8,7 @@ extern "C" { #include "MEM_guardedalloc.h" -#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ(0, (size_t)ptr % align) +#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ((size_t)ptr % align, 0) namespace { diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 4b5666e9b5a..b76c47fcf25 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -95,6 +95,11 @@ add_test(bevel ${TEST_BLENDER_EXE} --python-text run_tests ) +add_test(split_faces ${TEST_BLENDER_EXE} + ${TEST_SRC_DIR}/modeling/split_faces_test.blend + --python-text run_tests +) + # ------------------------------------------------------------------------------ # IO TESTS @@ -417,7 +422,12 @@ if(WITH_CYCLES) -idiff "${OPENIMAGEIO_IDIFF}" ) endif() - endmacro() + endmacro() + if(WITH_OPENGL_TESTS) + add_cycles_render_test(opengl) + endif() + add_cycles_render_test(image) + add_cycles_render_test(mblur) add_cycles_render_test(reports) add_cycles_render_test(render) add_cycles_render_test(shader) diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 64a71da301a..a030cc5e0de 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -47,20 +47,41 @@ def printMessage(type, status, message): def render_file(filepath): - command = ( - BLENDER, - "--background", - "-noaudio", - "--factory-startup", - "--enable-autoexec", - filepath, - "-E", "CYCLES", - # Run with OSL enabled - # "--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True", - "-o", TEMP_FILE_MASK, - "-F", "PNG", - "-f", "1", + dirname = os.path.dirname(filepath) + basedir = os.path.dirname(dirname) + subject = os.path.basename(dirname) + if subject == 'opengl': + command = ( + BLENDER, + "--window-geometry", "0", "0", "1", "1", + "-noaudio", + "--factory-startup", + "--enable-autoexec", + filepath, + "-E", "CYCLES", + # Run with OSL enabled + # "--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True", + "-o", TEMP_FILE_MASK, + "-F", "PNG", + '--python', os.path.join(basedir, + "util", + "render_opengl.py") ) + else: + command = ( + BLENDER, + "--background", + "-noaudio", + "--factory-startup", + "--enable-autoexec", + filepath, + "-E", "CYCLES", + # Run with OSL enabled + # "--python-expr", "import bpy; bpy.context.scene.cycles.shading_system = True", + "-o", TEMP_FILE_MASK, + "-F", "PNG", + "-f", "1", + ) try: output = subprocess.check_output(command) if VERBOSE: |