diff options
Diffstat (limited to 'source')
82 files changed, 1500 insertions, 851 deletions
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h index e62713f57f5..e92d5f2d9f7 100644 --- a/source/blender/alembic/ABC_alembic.h +++ b/source/blender/alembic/ABC_alembic.h @@ -28,6 +28,7 @@ extern "C" { #endif struct bContext; +struct CacheReader; struct DerivedMesh; struct ListBase; struct Object; @@ -92,21 +93,25 @@ AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *objec void ABC_free_handle(AbcArchiveHandle *handle); -void ABC_get_transform(AbcArchiveHandle *handle, - struct Object *ob, - const char *object_path, +void ABC_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale); -struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, +struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader, struct Object *ob, struct DerivedMesh *dm, - const char *object_path, const float time, const char **err_str, int flags); +void CacheReader_free(struct CacheReader *reader); + +struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle, + struct CacheReader *reader, + struct Object *object, + const char *object_path); + #ifdef __cplusplus } #endif diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc index 5c34ec1391f..d5271e3ca31 100644 --- a/source/blender/alembic/intern/abc_camera.cc +++ b/source/blender/alembic/intern/abc_camera.cc @@ -119,7 +119,7 @@ bool AbcCameraReader::valid() const void AbcCameraReader::readObjectData(Main *bmain, float time) { - Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, "abc_camera")); + Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str())); ISampleSelector sample_sel(time); CameraSample cam_sample; @@ -155,8 +155,6 @@ void AbcCameraReader::readObjectData(Main *bmain, float time) bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance(); bcam->gpu_dof.fstop = cam_sample.getFStop(); - BLI_strncpy(bcam->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1); - m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); m_object->data = bcam; } diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 2b54741a5c5..7e5ea3b1853 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -37,6 +37,7 @@ extern "C" { #include "BLI_listbase.h" +#include "BKE_cdderivedmesh.h" #include "BKE_curve.h" #include "BKE_object.h" @@ -353,3 +354,54 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) BLI_addtail(BKE_curve_nurbs_get(cu), nu); } } + +/* NOTE: Alembic only stores data about control points, but the DerivedMesh + * passed from the cache modifier contains the displist, which has more data + * than the control points, so to avoid corrupting the displist we modify the + * 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*/) +{ + ISampleSelector sample_sel(time); + const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); + + int vertex_idx = 0; + int curve_idx = 0; + Curve *curve = static_cast<Curve *>(m_object->data); + + const int curve_count = BLI_listbase_count(&curve->nurb); + + if (curve_count != num_vertices->size()) { + BKE_nurbList_free(&curve->nurb); + read_curve_sample(curve, m_curves_schema, time); + } + else { + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (; nurbs; nurbs = nurbs->next, ++curve_idx) { + const int totpoint = (*num_vertices)[curve_idx]; + + if (nurbs->bp) { + BPoint *point = nurbs->bp; + + for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { + const Imath::V3f &pos = (*positions)[vertex_idx]; + copy_yup_zup(point->vec, pos.getValue()); + } + } + else if (nurbs->bezt) { + BezTriple *bezier = nurbs->bezt; + + 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()); + } + } + } + } + + return CDDM_from_curve(m_object); +} diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h index ee47f1931ea..979ee8af639 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_curves.h @@ -56,10 +56,11 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int); }; /* ************************************************************************** */ void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time); -#endif /* __ABC_CURVES_H__ */
\ No newline at end of file +#endif /* __ABC_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 9b19a063e4e..3d80756fcca 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -646,75 +646,6 @@ void AbcMeshWriter::getGeoGroups( /* Some helpers for mesh generation */ namespace utils { -void mesh_add_verts(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - const int totvert = mesh->totvert + len; - CustomData vdata; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); - CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); - - if (!CustomData_has_layer(&vdata, CD_MVERT)) { - CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); - } - - CustomData_free(&mesh->vdata, mesh->totvert); - mesh->vdata = vdata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totvert = totvert; -} - -static void mesh_add_mloops(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - /* new face count */ - const int totloops = mesh->totloop + len; - - CustomData ldata; - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloops); - CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); - - if (!CustomData_has_layer(&ldata, CD_MLOOP)) { - CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloops); - } - - CustomData_free(&mesh->ldata, mesh->totloop); - mesh->ldata = ldata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totloop = totloops; -} - -static void mesh_add_mpolygons(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - const int totpolys = mesh->totpoly + len; - - CustomData pdata; - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpolys); - CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); - - if (!CustomData_has_layer(&pdata, CD_MPOLY)) { - CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpolys); - } - - CustomData_free(&mesh->pdata, mesh->totpoly); - mesh->pdata = pdata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totpoly = totpolys; -} - static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map) { Material *material = static_cast<Material *>(bmain->mat.first); @@ -786,45 +717,6 @@ struct AbcMeshData { UInt32ArraySamplePtr uvs_indices; }; -static void *add_customdata_cb(void *user_data, const char *name, int data_type) -{ - Mesh *mesh = static_cast<Mesh *>(user_data); - CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); - void *cd_ptr = NULL; - - int index = -1; - if (cd_data_type == CD_MLOOPUV) { - index = ED_mesh_uv_texture_add(mesh, name, true); - cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type); - } - else if (cd_data_type == CD_MLOOPCOL) { - index = ED_mesh_color_add(mesh, name, true); - cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type); - } - - if (index == -1) { - return NULL; - } - - return cd_ptr; -} - -CDStreamConfig create_config(Mesh *mesh) -{ - CDStreamConfig config; - - config.mvert = mesh->mvert; - config.mpoly = mesh->mpoly; - config.mloop = mesh->mloop; - config.totpoly = mesh->totpoly; - config.totloop = mesh->totloop; - config.user_data = mesh; - config.loopdata = &mesh->ldata; - config.add_customdata_cb = add_customdata_cb; - - return config; -} - static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions, const P3fArraySamplePtr &ceil_positions, const float weight) { float tmp[3]; @@ -1002,23 +894,15 @@ void AbcMeshReader::readObjectData(Main *bmain, float time) m_object->data = mesh; const ISampleSelector sample_sel(time); - const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - utils::mesh_add_verts(mesh, positions->size()); - utils::mesh_add_mpolygons(mesh, face_counts->size()); - utils::mesh_add_mloops(mesh, face_indices->size()); - m_mesh_data = create_config(mesh); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); - bool has_smooth_normals = false; - read_mesh_sample(m_settings, m_schema, sample_sel, m_mesh_data, has_smooth_normals); + if (ndm != dm) { + dm->release(dm); + } - BKE_mesh_calc_normals(mesh); - BKE_mesh_calc_edges(mesh, false, false); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -1031,6 +915,120 @@ void AbcMeshReader::readObjectData(Main *bmain, float time) } } +static bool check_smooth_poly_flag(DerivedMesh *dm) +{ + MPoly *mpolys = dm->getPolyArray(dm); + + for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + MPoly &poly = mpolys[i]; + + if ((poly.flag & ME_SMOOTH) != 0) { + return true; + } + } + + return false; +} + +static void set_smooth_poly_flag(DerivedMesh *dm) +{ + MPoly *mpolys = dm->getPolyArray(dm); + + for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + MPoly &poly = mpolys[i]; + poly.flag |= ME_SMOOTH; + } +} + +static void *add_customdata_cb(void *user_data, const char *name, int data_type) +{ + DerivedMesh *dm = static_cast<DerivedMesh *>(user_data); + CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); + void *cd_ptr = NULL; + + if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { + cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name); + + if (cd_ptr == NULL) { + cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm), + cd_data_type, + CD_DEFAULT, + NULL, + dm->getNumLoops(dm), + name); + } + } + + return cd_ptr; +} + +CDStreamConfig get_config(DerivedMesh *dm) +{ + CDStreamConfig config; + + config.user_data = dm; + config.mvert = dm->getVertArray(dm); + config.mloop = dm->getLoopArray(dm); + config.mpoly = dm->getPolyArray(dm); + config.totloop = dm->getNumLoops(dm); + config.totpoly = dm->getNumPolys(dm); + config.loopdata = dm->getLoopDataLayout(dm); + config.add_customdata_cb = add_customdata_cb; + + return config; +} + +DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +{ + ISampleSelector sample_sel(time); + const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + DerivedMesh *new_dm = NULL; + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + ImportSettings settings; + settings.read_flag |= read_flag; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_from_template(dm, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); + + settings.read_flag |= MOD_MESHSEQ_READ_ALL; + } + + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + config.time = time; + + bool do_normals = false; + read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals); + + if (new_dm) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (!do_normals && check_smooth_poly_flag(dm)) { + set_smooth_poly_flag(new_dm); + } + + CDDM_calc_normals(new_dm); + CDDM_calc_edges(new_dm); + + return new_dm; + } + + if (do_normals) { + CDDM_calc_normals(dm); + } + + return dm; +} + void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const ISampleSelector &sample_sel) { @@ -1178,21 +1176,17 @@ void AbcSubDReader::readObjectData(Main *bmain, float time) m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; - const ISampleSelector sample_sel(time); - const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - utils::mesh_add_verts(mesh, positions->size()); - utils::mesh_add_mpolygons(mesh, face_counts->size()); - utils::mesh_add_mloops(mesh, face_indices->size()); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); - m_mesh_data = create_config(mesh); + if (ndm != dm) { + dm->release(dm); + } - read_subd_sample(m_settings, m_schema, sample_sel, m_mesh_data); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); + const ISampleSelector sample_sel(time); + const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); Int32ArraySamplePtr indices = sample.getCreaseIndices(); Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); @@ -1262,3 +1256,48 @@ void read_subd_sample(ImportSettings *settings, /* TODO: face sets */ } + +DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +{ + ISampleSelector sample_sel(time); + const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + DerivedMesh *new_dm = NULL; + + ImportSettings settings; + settings.read_flag |= read_flag; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_from_template(dm, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); + + settings.read_flag |= MOD_MESHSEQ_READ_ALL; + } + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + config.time = time; + read_subd_sample(&settings, m_schema, sample_sel, config); + + if (new_dm) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (check_smooth_poly_flag(dm)) { + set_smooth_poly_flag(new_dm); + } + + CDDM_calc_normals(new_dm); + CDDM_calc_edges(new_dm); + + return new_dm; + } + + return dm; +} diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 41abe78f75f..66e6585a3d3 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -102,6 +102,8 @@ public: void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); + private: void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const Alembic::AbcGeom::ISampleSelector &sample_sel); @@ -126,6 +128,7 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); }; void read_subd_sample(ImportSettings *settings, @@ -135,16 +138,10 @@ void read_subd_sample(ImportSettings *settings, /* ************************************************************************** */ -namespace utils { - -void mesh_add_verts(struct Mesh *mesh, size_t len); - -} - void read_mverts(MVert *mverts, const Alembic::AbcGeom::P3fArraySamplePtr &positions, const Alembic::AbcGeom::N3fArraySamplePtr &normals); -CDStreamConfig create_config(Mesh *mesh); +CDStreamConfig get_config(DerivedMesh *dm); #endif /* __ABC_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index 32468fdaded..314b2568bed 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -126,6 +126,7 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings , m_settings(&settings) , m_min_time(std::numeric_limits<chrono_t>::max()) , m_max_time(std::numeric_limits<chrono_t>::min()) + , m_refcount(0) { m_name = object.getFullName(); std::vector<std::string> parts; @@ -153,6 +154,11 @@ Object *AbcObjectReader::object() const return m_object; } +void AbcObjectReader::object(Object *ob) +{ + m_object = ob; +} + static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight) { float mat0[4][4], mat1[4][4], ret[4][4]; @@ -210,6 +216,28 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time) void AbcObjectReader::readObjectMatrix(const float time) { + bool is_constant = false; + + this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant); + invert_m4_m4(m_object->imat, m_object->obmat); + + BKE_object_apply_mat4(m_object, m_object->obmat, false, false); + + if (!is_constant) { + bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); + bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data); + BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + + data->cache_file = m_settings->cache_file; + id_us_plus(&data->cache_file->id); + + data->reader = reinterpret_cast<CacheReader *>(this); + this->incref(); + } +} + +void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant) +{ IXform ixform; bool has_alembic_parent = false; @@ -250,23 +278,12 @@ void AbcObjectReader::readObjectMatrix(const float time) } const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, m_object, m_object->obmat, m_settings->scale, has_alembic_parent); - - invert_m4_m4(m_object->imat, m_object->obmat); - - BKE_object_apply_mat4(m_object, m_object->obmat, false, false); - - if (!schema.isConstant()) { - bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); - bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data); - BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + convert_matrix(matrix, m_object, mat, scale, has_alembic_parent); - data->cache_file = m_settings->cache_file; - id_us_plus(&data->cache_file->id); - } + is_constant = schema.isConstant(); } -void AbcObjectReader::addCacheModifier() const +void AbcObjectReader::addCacheModifier() { ModifierData *md = modifier_new(eModifierType_MeshSequenceCache); BLI_addtail(&m_object->modifiers, md); @@ -277,6 +294,9 @@ void AbcObjectReader::addCacheModifier() const id_us_plus(&mcmd->cache_file->id); BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + + mcmd->reader = reinterpret_cast<CacheReader *>(this); + this->incref(); } chrono_t AbcObjectReader::minTime() const @@ -288,3 +308,18 @@ chrono_t AbcObjectReader::maxTime() const { return m_max_time; } + +int AbcObjectReader::refcount() const +{ + return m_refcount; +} + +void AbcObjectReader::incref() +{ + ++m_refcount; +} + +void AbcObjectReader::decref() +{ + --m_refcount; +} diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index a35faa37565..7ff927b4d33 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -130,6 +130,8 @@ static bool has_animations(Schema &schema, ImportSettings *settings) /* ************************************************************************** */ +struct DerivedMesh; + using Alembic::AbcCoreAbstract::chrono_t; class AbcObjectReader { @@ -145,6 +147,10 @@ protected: chrono_t m_min_time; chrono_t m_max_time; + /* Use reference counting since the same reader may be used by multiple + * modifiers and/or constraints. */ + int m_refcount; + public: explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings); @@ -153,17 +159,31 @@ public: const Alembic::Abc::IObject &iobject() const; Object *object() const; + void object(Object *ob); virtual bool valid() const = 0; virtual void readObjectData(Main *bmain, float time) = 0; + virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) + { + (void)time; + (void)read_flag; + return dm; + } + void readObjectMatrix(const float time); - void addCacheModifier() const; + void addCacheModifier(); chrono_t minTime() const; chrono_t maxTime() const; + + int refcount() const; + void incref(); + void decref(); + + void read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant); }; Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index bf9c483901d..291a19bd2d5 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -32,6 +32,7 @@ extern "C" { #include "DNA_mesh_types.h" #include "DNA_object_types.h" +#include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -156,14 +157,14 @@ void AbcPointsReader::readObjectData(Main *bmain, float time) { Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); - const ISampleSelector sample_sel(time); - m_sample = m_schema.getValue(sample_sel); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0); - const P3fArraySamplePtr &positions = m_sample.getPositions(); - utils::mesh_add_verts(mesh, positions->size()); + if (ndm != dm) { + dm->release(dm); + } - CDStreamConfig config = create_config(mesh); - read_points_sample(m_schema, sample_sel, config, time); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -199,3 +200,22 @@ 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*/) +{ + ISampleSelector sample_sel(time); + const IPointsSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + + DerivedMesh *new_dm = NULL; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_new(positions->size(), 0, 0, 0, 0); + } + + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + read_points_sample(m_schema, sample_sel, config, time); + + return new_dm ? new_dm : dm; +} diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h index cfa51e66a22..0e69639ad8e 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_points.h @@ -58,6 +58,8 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); }; void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 60c66bca1c8..f87d18605d4 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -22,6 +22,15 @@ #include "abc_util.h" +#include "abc_camera.h" +#include "abc_curves.h" +#include "abc_mesh.h" +#include "abc_nurbs.h" +#include "abc_points.h" +#include "abc_transform.h" + +#include <Alembic/AbcMaterial/IMaterial.h> + #include <algorithm> extern "C" { @@ -462,3 +471,56 @@ float get_weight_and_index(float time, return bias; } + +//#define USE_NURBS + +AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings) +{ + AbcObjectReader *reader = NULL; + + const Alembic::AbcGeom::MetaData &md = object.getMetaData(); + + if (Alembic::AbcGeom::IXform::matches(md)) { + reader = new AbcEmptyReader(object, settings); + } + else if (Alembic::AbcGeom::IPolyMesh::matches(md)) { + reader = new AbcMeshReader(object, settings); + } + else if (Alembic::AbcGeom::ISubD::matches(md)) { + reader = new AbcSubDReader(object, settings); + } + else if (Alembic::AbcGeom::INuPatch::matches(md)) { +#ifdef USE_NURBS + /* TODO(kevin): importing cyclic NURBS from other software crashes + * at the moment. This is due to the fact that NURBS in other + * software have duplicated points which causes buffer overflows in + * Blender. Need to figure out exactly how these points are + * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). + * Until this is fixed, disabling NURBS reading. */ + reader = new AbcNurbsReader(child, settings); +#endif + } + else if (Alembic::AbcGeom::ICamera::matches(md)) { + reader = new AbcCameraReader(object, settings); + } + else if (Alembic::AbcGeom::IPoints::matches(md)) { + reader = new AbcPointsReader(object, settings); + } + else if (Alembic::AbcMaterial::IMaterial::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::ILight::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::IFaceSet::matches(md)) { + /* Pass, those are handled in the mesh reader. */ + } + else if (Alembic::AbcGeom::ICurves::matches(md)) { + reader = new AbcCurveReader(object, settings); + } + else { + assert(false); + } + + return reader; +} diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index 9e9f0c397ba..2f423a9f8c5 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -32,8 +32,13 @@ # define ABC_INLINE static inline #endif +struct CacheReader { + int unused; +}; + using Alembic::Abc::chrono_t; +class AbcObjectReader; class ImportSettings; struct ID; @@ -100,6 +105,8 @@ float get_weight_and_index(float time, Alembic::AbcGeom::index_t &i0, Alembic::AbcGeom::index_t &i1); +AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings); + /* ************************** */ /* TODO(kevin): for now keeping these transformations hardcoded to make sure diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index c6988351db8..e690a255505 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -467,6 +467,7 @@ static void visit_object(const IObject &object, if (reader) { readers.push_back(reader); + reader->incref(); AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>( MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); @@ -710,7 +711,12 @@ static void import_endjob(void *user_data) } for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - delete *iter; + AbcObjectReader *reader = *iter; + reader->decref(); + + if (reader->refcount() == 0) { + delete reader; + } } if (data->parent_map) { @@ -771,296 +777,31 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence WM_jobs_start(CTX_wm_manager(C), wm_job); } -/* ******************************* */ +/* ************************************************************************** */ -void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale) +void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float scale) { - ArchiveReader *archive = archive_from_handle(handle); - - if (!archive || !archive->valid()) { + if (!reader) { return; } - IObject tmp; - find_iobject(archive->getTop(), tmp, object_path); - - IXform ixform; - - if (IXform::matches(tmp.getHeader())) { - ixform = IXform(tmp, kWrapExisting); - } - else { - ixform = IXform(tmp.getParent(), kWrapExisting); - } - - IXformSchema schema = ixform.getSchema(); - - if (!schema.valid()) { - return; - } - - const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, ob, r_mat, scale); -} - -/* ***************************************** */ - -static bool check_smooth_poly_flag(DerivedMesh *dm) -{ - MPoly *mpolys = dm->getPolyArray(dm); - - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { - MPoly &poly = mpolys[i]; - - if ((poly.flag & ME_SMOOTH) != 0) { - return true; - } - } - - return false; -} - -static void set_smooth_poly_flag(DerivedMesh *dm) -{ - MPoly *mpolys = dm->getPolyArray(dm); - - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { - MPoly &poly = mpolys[i]; - poly.flag |= ME_SMOOTH; - } -} - -static void *add_customdata_cb(void *user_data, const char *name, int data_type) -{ - DerivedMesh *dm = static_cast<DerivedMesh *>(user_data); - CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); - void *cd_ptr = NULL; - - if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { - cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name); - - if (cd_ptr == NULL) { - cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm), - cd_data_type, - CD_DEFAULT, - NULL, - dm->getNumLoops(dm), - name); - } - } - - return cd_ptr; -} - -ABC_INLINE CDStreamConfig get_config(DerivedMesh *dm) -{ - CDStreamConfig config; - - config.user_data = dm; - config.mvert = dm->getVertArray(dm); - config.mloop = dm->getLoopArray(dm); - config.mpoly = dm->getPolyArray(dm); - config.totloop = dm->getNumLoops(dm); - config.totpoly = dm->getNumPolys(dm); - config.loopdata = dm->getLoopDataLayout(dm); - config.add_customdata_cb = add_customdata_cb; - - return config; -} - -static DerivedMesh *read_mesh_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag) -{ - IPolyMesh mesh(iobject, kWrapExisting); - IPolyMeshSchema schema = mesh.getSchema(); - ISampleSelector sample_sel(time); - const IPolyMeshSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - DerivedMesh *new_dm = NULL; - - /* Only read point data when streaming meshes, unless we need to create new ones. */ - ImportSettings settings; - settings.read_flag |= read_flag; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - settings.read_flag |= MOD_MESHSEQ_READ_ALL; - } - - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - config.time = time; - - bool do_normals = false; - read_mesh_sample(&settings, schema, sample_sel, config, do_normals); - - if (new_dm) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (!do_normals && check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); - } - - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); - - return new_dm; - } - - if (do_normals) { - CDDM_calc_normals(dm); - } + AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); - return dm; + bool is_constant = false; + abc_reader->read_matrix(r_mat, time, scale, is_constant); } -using Alembic::AbcGeom::ISubDSchema; - -static DerivedMesh *read_subd_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag) -{ - ISubD mesh(iobject, kWrapExisting); - ISubDSchema schema = mesh.getSchema(); - ISampleSelector sample_sel(time); - const ISubDSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - DerivedMesh *new_dm = NULL; - - ImportSettings settings; - settings.read_flag |= read_flag; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - settings.read_flag |= MOD_MESHSEQ_READ_ALL; - } - - /* Only read point data when streaming meshes, unless we need to create new ones. */ - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - config.time = time; - read_subd_sample(&settings, schema, sample_sel, config); +/* ************************************************************************** */ - if (new_dm) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); - } - - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); - - return new_dm; - } - - return dm; -} - -static DerivedMesh *read_points_sample(DerivedMesh *dm, const IObject &iobject, const float time) -{ - IPoints points(iobject, kWrapExisting); - IPointsSchema schema = points.getSchema(); - ISampleSelector sample_sel(time); - const IPointsSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - - DerivedMesh *new_dm = NULL; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_new(positions->size(), 0, 0, 0, 0); - } - - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - read_points_sample(schema, sample_sel, config, time); - - return new_dm ? new_dm : dm; -} - -/* NOTE: Alembic only stores data about control points, but the DerivedMesh - * passed from the cache modifier contains the displist, which has more data - * than the control points, so to avoid corrupting the displist we modify the - * object directly and create a new DerivedMesh from that. Also we might need to - * create new or delete existing NURBS in the curve. - */ -static DerivedMesh *read_curves_sample(Object *ob, const IObject &iobject, const float time) -{ - ICurves points(iobject, kWrapExisting); - ICurvesSchema schema = points.getSchema(); - ISampleSelector sample_sel(time); - const ICurvesSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); - - int vertex_idx = 0; - int curve_idx = 0; - Curve *curve = static_cast<Curve *>(ob->data); - - const int curve_count = BLI_listbase_count(&curve->nurb); - - if (curve_count != num_vertices->size()) { - BKE_nurbList_free(&curve->nurb); - read_curve_sample(curve, schema, time); - } - else { - Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); - for (; nurbs; nurbs = nurbs->next, ++curve_idx) { - const int totpoint = (*num_vertices)[curve_idx]; - - if (nurbs->bp) { - BPoint *point = nurbs->bp; - - for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { - const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_yup_zup(point->vec, pos.getValue()); - } - } - else if (nurbs->bezt) { - BezTriple *bezier = nurbs->bezt; - - 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()); - } - } - } - } - - return CDDM_from_curve(ob); -} - -DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, +DerivedMesh *ABC_read_mesh(CacheReader *reader, Object *ob, DerivedMesh *dm, - const char *object_path, const float time, const char **err_str, int read_flag) { - ArchiveReader *archive = archive_from_handle(handle); - - if (!archive || !archive->valid()) { - *err_str = "Invalid archive!"; - return NULL; - } - - IObject iobject; - find_iobject(archive->getTop(), iobject, object_path); + AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); + IObject iobject = abc_reader->iobject(); if (!iobject.valid()) { *err_str = "Invalid object: verify object path"; @@ -1075,7 +816,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_mesh_sample(dm, iobject, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (ISubD::matches(header)) { if (ob->type != OB_MESH) { @@ -1083,7 +824,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_subd_sample(dm, iobject, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (IPoints::matches(header)) { if (ob->type != OB_MESH) { @@ -1091,7 +832,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_points_sample(dm, iobject, time); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (ICurves::matches(header)) { if (ob->type != OB_CURVE) { @@ -1099,9 +840,48 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_curves_sample(ob, iobject, time); + return abc_reader->read_derivedmesh(dm, time, read_flag); } *err_str = "Unsupported object type: verify object path"; // or poke developer return NULL; } + +/* ************************************************************************** */ + +void CacheReader_free(CacheReader *reader) +{ + AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); + abc_reader->decref(); + + if (abc_reader->refcount() == 0) { + delete abc_reader; + } +} + +CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path) +{ + if (object_path[0] == '\0') { + return reader; + } + + ArchiveReader *archive = archive_from_handle(handle); + + if (!archive || !archive->valid()) { + return reader; + } + + IObject iobject; + find_iobject(archive->getTop(), iobject, object_path); + + if (reader) { + CacheReader_free(reader); + } + + ImportSettings settings; + AbcObjectReader *abc_reader = create_reader(iobject, settings); + abc_reader->object(object); + abc_reader->incref(); + + return reinterpret_cast<CacheReader *>(abc_reader); +} diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index a55cb51766c..7e1c069df9a 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -63,6 +63,8 @@ bool BKE_cachefile_filepath_get( float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps); +void BKE_cachefile_clean(struct Scene *scene, struct CacheFile *cache_file); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index efef8d4be78..6944c5ccd28 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -114,6 +114,7 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read( const char *name, const char *path, const int source, bool force_update); void BKE_previewimg_cached_release(const char *name); +void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv); #define ICON_RENDER_DEFAULT_HEIGHT 32 diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 7882bdf1126..33c68158262 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -39,6 +39,7 @@ extern "C" { #include "BLI_compiler_attrs.h" struct BlendThumbnail; +struct GHash; struct ListBase; struct ID; struct ImBuf; @@ -125,7 +126,8 @@ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id); void BKE_library_free(struct Library *lib); void BKE_library_make_local( - struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake); + struct Main *bmain, const struct Library *lib, struct GHash *old_to_new_ids, + const bool untagged_only, const bool set_fake); /* use when "" is given to new_id() */ diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h index a0a885c2a04..19a2220006a 100644 --- a/source/blender/blenkernel/BKE_object_deform.h +++ b/source/blender/blenkernel/BKE_object_deform.h @@ -51,9 +51,11 @@ bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, const bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection); void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup); +void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked); void BKE_object_defgroup_remove_all(struct Object *ob); + /* Select helpers */ enum eVGroupSelect; bool *BKE_object_defgroup_subset_from_select_type( diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index a4c28121040..e57524af546 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -101,7 +101,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor IMB_colormanagement_check_file_config(bmain_dst); /* Append, rather than linking. */ Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath)); - BKE_library_make_local(bmain_dst, lib, true, false); + BKE_library_make_local(bmain_dst, lib, NULL, true, false); /* Important we unset, otherwise these object wont * link into other scenes from this blend file. */ @@ -150,7 +150,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re /* append, rather than linking */ lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath)); - BKE_library_make_local(bmain, lib, true, false); + BKE_library_make_local(bmain, lib, NULL, true, false); /* important we unset, otherwise these object wont * link into other scenes from this blend file */ diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index e62e652b4a6..6a08673144e 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -29,6 +29,8 @@ #include "DNA_anim_types.h" #include "DNA_cachefile_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BLI_fileops.h" @@ -43,6 +45,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_scene.h" #ifdef WITH_ALEMBIC @@ -196,3 +199,41 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f const float frame = (cache_file->override_frame ? cache_file->frame : time); return cache_file->is_sequence ? frame : frame / fps; } + +/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */ +void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) +{ + for (Base *base = scene->base.first; base; base = base->next) { + Object *ob = base->object; + + ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); + + if (md) { + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + + if (cache_file == mcmd->cache_file) { +#ifdef WITH_ALEMBIC + CacheReader_free(mcmd->reader); +#endif + mcmd->reader = NULL; + mcmd->object_path[0] = '\0'; + } + } + + for (bConstraint *con = ob->constraints.first; con; con = con->next) { + if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { + continue; + } + + bTransformCacheConstraint *data = con->data; + + if (cache_file == data->cache_file) { +#ifdef WITH_ALEMBIC + CacheReader_free(data->reader); +#endif + data->reader = NULL; + data->object_path[0] = '\0'; + } + } + } +} diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c4afa58b7d3..b85f1b838ff 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4364,8 +4364,14 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa BKE_cachefile_ensure_handle(G.main, cache_file); - ABC_get_transform(cache_file->handle, cob->ob, data->object_path, - cob->matrix, time, cache_file->scale); + if (!data->reader) { + data->reader = CacheReader_open_alembic_object(cache_file->handle, + data->reader, + cob->ob, + data->object_path); + } + + ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale); #else UNUSED_VARS(con, cob); #endif @@ -4393,6 +4399,12 @@ static void transformcache_free(bConstraint *con) if (data->cache_file) { id_us_min(&data->cache_file->id); } + + if (data->reader) { +#ifdef WITH_ALEMBIC + CacheReader_free(data->reader); +#endif + } } static void transformcache_new_data(void *cdata) diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 184688b5e74..1c0b11e287c 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2809,7 +2809,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; if (mcmd->cache_file && (&mcmd->cache_file->id == id)) { - ob->recalc |= OB_RECALC_DATA; + ob->recalc |= OB_RECALC_ALL; continue; } } @@ -2822,7 +2822,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) bTransformCacheConstraint *data = con->data; if (data->cache_file && (&data->cache_file->id == id)) { - ob->recalc |= OB_RECALC_DATA; + ob->recalc |= OB_RECALC_ALL; break; } } diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 2d5b15c8f9d..7669c4ba112 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -143,7 +143,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size) memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */ if (deferred_data_size) { - prv_img->use_deferred = true; + prv_img->tag |= PRV_TAG_DEFFERED; } for (i = 0; i < NUM_ICON_SIZES; ++i) { @@ -355,11 +355,14 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read( return prv; } -void BKE_previewimg_cached_release(const char *name) +void BKE_previewimg_cached_release_pointer(PreviewImage *prv) { - PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); - if (prv) { + if (prv->tag & PRV_TAG_DEFFERED_RENDERING) { + /* We cannot delete the preview while it is being loaded in another thread... */ + prv->tag |= PRV_TAG_DEFFERED_DELETE; + return; + } if (prv->icon_id) { BKE_icon_delete(prv->icon_id); } @@ -367,11 +370,18 @@ void BKE_previewimg_cached_release(const char *name) } } +void BKE_previewimg_cached_release(const char *name) +{ + PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); + + BKE_previewimg_cached_release_pointer(prv); +} + /** Handle deferred (lazy) loading/generation of preview image, if needed. * For now, only used with file thumbnails. */ void BKE_previewimg_ensure(PreviewImage *prv, const int size) { - if (prv->use_deferred) { + if ((prv->tag & PRV_TAG_DEFFERED) != 0) { const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]); const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index a4eef2f9230..df3a7630bb0 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1580,24 +1580,7 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i } /* planes */ - /* TODO(sergey): Channels doesn't correspond actual planes used for image buffer - * For example byte buffer will have 4 channels but it might easily - * be BW or RGB image. - * - * Need to use im_format->planes = imbuf->planes instead? - */ - switch (imbuf->channels) { - case 0: - case 4: im_format->planes = R_IMF_PLANES_RGBA; - break; - case 3: im_format->planes = R_IMF_PLANES_RGB; - break; - case 1: im_format->planes = R_IMF_PLANES_BW; - break; - default: im_format->planes = R_IMF_PLANES_RGB; - break; - } - + im_format->planes = imbuf->planes; } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 4ed1fad7323..9abf09a0944 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -73,6 +73,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_linklist.h" #include "BLI_memarena.h" @@ -1623,7 +1624,8 @@ void BKE_main_id_clear_newpoins(Main *bmain) * We'll probably need at some point a true dependency graph between datablocks, but for now this should work * good enough (performances is not a critical point here anyway). */ -void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake) +void BKE_library_make_local( + Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake) { ListBase *lbarray[MAX_LIBARRAY]; ID *id, *id_next; @@ -1695,6 +1697,9 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged BLI_assert(id->lib != NULL); BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE); + if (old_to_new_ids) { + BLI_ghash_insert(old_to_new_ids, id, id->newid); + } } /* Third step: remove datablocks that have been copied to be localized and are no more used in the end... diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 72968d1964c..91c67899dfb 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -399,8 +399,9 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) /** * Remove all vgroups from object. Work in Object and Edit modes. + * When only_unlocked=true, locked vertex groups are not removed. */ -void BKE_object_defgroup_remove_all(Object *ob) +void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked) { bDeformGroup *dg = (bDeformGroup *)ob->defbase.first; const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob); @@ -409,10 +410,12 @@ void BKE_object_defgroup_remove_all(Object *ob) while (dg) { bDeformGroup *next_dg = dg->next; - if (edit_mode) - object_defgroup_remove_edit_mode(ob, dg); - else - object_defgroup_remove_object_mode(ob, dg); + if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) { + if (edit_mode) + object_defgroup_remove_edit_mode(ob, dg); + else + object_defgroup_remove_object_mode(ob, dg); + } dg = next_dg; } @@ -437,6 +440,15 @@ void BKE_object_defgroup_remove_all(Object *ob) } /** + * Remove all vgroups from object. Work in Object and Edit modes. + */ +void BKE_object_defgroup_remove_all(struct Object *ob) +{ + BKE_object_defgroup_remove_all_ex(ob, false); +} + + +/** * Get MDeformVert vgroup data from given object. Should only be used in Object mode. * * \return True if the id type supports weights. diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 05356123727..1da263797f6 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -355,6 +355,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd) MEM_freeN(smd->domain->effector_weights); smd->domain->effector_weights = NULL; + if (smd->domain->coba) { + MEM_freeN(smd->domain->coba); + } + MEM_freeN(smd->domain); smd->domain = NULL; } @@ -531,6 +535,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->slice_depth = 0.5f; smd->domain->slice_axis = 0; smd->domain->vector_scale = 1.0f; + + smd->domain->coba = NULL; + smd->domain->coba_field = FLUID_FIELD_DENSITY; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -631,6 +638,10 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData tsmd->domain->draw_velocity = smd->domain->draw_velocity; tsmd->domain->vector_draw_type = smd->domain->vector_draw_type; tsmd->domain->vector_scale = smd->domain->vector_scale; + + if (smd->domain->coba) { + tsmd->domain->coba = MEM_dupallocN(smd->domain->coba); + } } else if (tsmd->flow) { tsmd->flow->noise_texture = smd->flow->noise_texture; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index a86606f1099..96ab8693122 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -44,6 +44,7 @@ #include "DNA_scene_types.h" #include "BLI_utildefines.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_math_base.h" @@ -997,9 +998,10 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height; } /* TODO: add an option to control whether AA is enabled or not */ - fill_poly_v2i_n(0, 0, mask_width, mask_height, - (const int (*)[2])mask_points, stroke->totpoints, - track_mask_set_pixel_cb, &data); + BLI_bitmap_draw_2d_poly_v2i_n( + 0, 0, mask_width, mask_height, + (const int (*)[2])mask_points, stroke->totpoints, + track_mask_set_pixel_cb, &data); MEM_freeN(mask_points); } stroke = stroke->next; diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h new file mode 100644 index 00000000000..fe890e94f1b --- /dev/null +++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_BITMAP_DRAW_2D_H__ +#define __BLI_BITMAP_DRAW_2D_H__ + +/** \file BLI_bitmap_draw_2d.h + * \ingroup bli + */ + +void BLI_bitmap_draw_2d_line_v2v2i( + const int p1[2], const int p2[2], + bool (*callback)(int, int, void *), void *userData); + +void BLI_bitmap_draw_2d_poly_v2i_n( + const int xmin, const int ymin, const int xmax, const int ymax, + const int polyXY[][2], const int polyCorners, + void (*callback)(int x, int x_end, int y, void *), void *userData); + +#endif /* __BLI_BITMAP_DRAW_2D_H__ */ diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 84a25f533bf..514b0300274 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -325,11 +325,6 @@ bool clip_segment_v3_plane_n( const float p1[3], const float p2[3], const float plane_array[][4], const int plane_tot, float r_p1[3], float r_p2[3]); -void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData); -void fill_poly_v2i_n( - const int xmin, const int ymin, const int xmax, const int ymax, - const int polyXY[][2], const int polyCorners, - void (*callback)(int x, int x_end, int y, void *), void *userData); /****************************** Interpolation ********************************/ /* tri or quad, d can be NULL */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 9978d1d19af..6e717a3ae7e 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -56,6 +56,7 @@ set(SRC intern/array_store_utils.c intern/array_utils.c intern/astar.c + intern/bitmap_draw_2d.c intern/boxpack2d.c intern/buffer.c intern/callbacks.c @@ -127,6 +128,7 @@ set(SRC BLI_array_utils.h BLI_astar.h BLI_bitmap.h + BLI_bitmap_draw_2d.h BLI_blenlib.h BLI_boxpack2d.h BLI_buffer.h diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index f943a8119c4..944ee18e6b2 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -1588,7 +1588,7 @@ double BLI_ghash_calc_quality_ex( if (r_variance) { /* We already know our mean (i.e. load factor), easy to compute variance. - * See http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm + * See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm */ double sum = 0.0; for (i = 0; i < gh->nbuckets; i++) { diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c index 21d974de1c4..0020dbe4612 100644 --- a/source/blender/blenlib/intern/astar.c +++ b/source/blender/blenlib/intern/astar.c @@ -35,7 +35,7 @@ * in addition to distance already walked. This heuristic allows more efficiency * in finding optimal path. * - * Implementation based on Wikipedia A* page [http://en.wikipedia.org/wiki/A*_search_algorithm]. + * Implementation based on Wikipedia A* page [https://en.wikipedia.org/wiki/A*_search_algorithm]. * * Note that most memory handling here is done through two different MemArena's. Those should also be used to allocate * custom data needed to a specific use of A*. diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c new file mode 100644 index 00000000000..afc54511d13 --- /dev/null +++ b/source/blender/blenlib/intern/bitmap_draw_2d.c @@ -0,0 +1,331 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: some of this file. + * + * ***** END GPL LICENSE BLOCK ***** + * */ + +/** \file blender/blenlib/intern/bitmap_draw_2d.c + * \ingroup bli + * + * Utility functions for primitive drawing operations. + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap_draw_2d.h" + +#include "BLI_math_base.h" +#include "BLI_sort.h" +#include "BLI_utildefines.h" + +#include "BLI_strict_flags.h" + +/* -------------------------------------------------------------------- */ +/* Draw Line */ + +/** + * Plot a line from \a p1 to \a p2 (inclusive). + */ +void BLI_bitmap_draw_2d_line_v2v2i( + const int p1[2], const int p2[2], + bool (*callback)(int, int, void *), void *userData) +{ + /* Bresenham's line algorithm. */ + int x1 = p1[0]; + int y1 = p1[1]; + int x2 = p2[0]; + int y2 = p2[1]; + + int ix; + int iy; + + /* if x1 == x2 or y1 == y2, then it does not matter what we set here */ + int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1; + int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1; + + if (callback(x1, y1, userData) == 0) { + return; + } + + if (delta_x >= delta_y) { + /* error may go below zero */ + int error = delta_y - (delta_x >> 1); + + while (x1 != x2) { + if (error >= 0) { + if (error || (ix > 0)) { + y1 += iy; + error -= delta_x; + } + /* else do nothing */ + } + /* else do nothing */ + + x1 += ix; + error += delta_y; + + if (callback(x1, y1, userData) == 0) { + return; + } + } + } + else { + /* error may go below zero */ + int error = delta_x - (delta_y >> 1); + + while (y1 != y2) { + if (error >= 0) { + if (error || (iy > 0)) { + x1 += ix; + error -= delta_y; + } + /* else do nothing */ + } + /* else do nothing */ + + y1 += iy; + error += delta_x; + + if (callback(x1, y1, userData) == 0) { + return; + } + } + } +} + + +/* -------------------------------------------------------------------- */ +/* Draw Filled Polygon */ + +/* sort edge-segments on y, then x axis */ +static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *verts_p) +{ + const int (*verts)[2] = verts_p; + const int *a = a_p; + const int *b = b_p; + const int *co_a = verts[a[0]]; + const int *co_b = verts[b[0]]; + + if (co_a[1] < co_b[1]) { + return -1; + } + else if (co_a[1] > co_b[1]) { + return 1; + } + else if (co_a[0] < co_b[0]) { + return -1; + } + else if (co_a[0] > co_b[0]) { + return 1; + } + else { + /* co_a & co_b are identical, use the line closest to the x-min */ + const int *co = co_a; + co_a = verts[a[1]]; + co_b = verts[b[1]]; + int ord = (((co_b[0] - co[0]) * (co_a[1] - co[1])) - + ((co_a[0] - co[0]) * (co_b[1] - co[1]))); + if (ord > 0) { + return -1; + } + if (ord < 0) { + return 1; + } + } + return 0; +} + +/** + * Draws a filled polyon with support for self intersections. + * + * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive), + * note that \a x_end will always be greater than \a x, so we can use: + * + * \code{.c} + * do { + * func(x, y); + * } while (++x != x_end); + * \endcode + */ +void BLI_bitmap_draw_2d_poly_v2i_n( + const int xmin, const int ymin, const int xmax, const int ymax, + const int verts[][2], const int nr, + void (*callback)(int x, int x_end, int y, void *), void *userData) +{ + /* Originally by Darel Rex Finley, 2007. + * Optimized by Campbell Barton, 2016 to track sorted intersections. */ + + int (*span_y)[2] = MEM_mallocN(sizeof(*span_y) * (size_t)nr, __func__); + int span_y_len = 0; + + for (int i_curr = 0, i_prev = nr - 1; i_curr < nr; i_prev = i_curr++) { + const int *co_prev = verts[i_prev]; + const int *co_curr = verts[i_curr]; + + if (co_prev[1] != co_curr[1]) { + /* Any segments entirely above or below the area of interest can be skipped. */ + if ((min_ii(co_prev[1], co_curr[1]) >= ymax) || + (max_ii(co_prev[1], co_curr[1]) < ymin)) + { + continue; + } + + int *s = span_y[span_y_len++]; + if (co_prev[1] < co_curr[1]) { + s[0] = i_prev; + s[1] = i_curr; + } + else { + s[0] = i_curr; + s[1] = i_prev; + } + } + } + + BLI_qsort_r(span_y, (size_t)span_y_len, sizeof(*span_y), draw_poly_v2i_n__span_y_sort, (void *)verts); + + struct NodeX { + int span_y_index; + int x; + } *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__); + int node_x_len = 0; + + int span_y_index = 0; + if (span_y_len != 0 && verts[span_y[0][0]][1] < ymin) { + while ((span_y_index < span_y_len) && + (verts[span_y[span_y_index][0]][1] < ymin)) + { + BLI_assert(verts[span_y[span_y_index][0]][1] < + verts[span_y[span_y_index][1]][1]); + if (verts[span_y[span_y_index][1]][1] >= ymin) { + struct NodeX *n = &node_x[node_x_len++]; + n->span_y_index = span_y_index; + } + span_y_index += 1; + } + } + + /* Loop through the rows of the image. */ + for (int pixel_y = ymin; pixel_y < ymax; pixel_y++) { + bool is_sorted = true; + bool do_remove = false; + + for (int i = 0, x_ix_prev = INT_MIN; i < node_x_len; i++) { + struct NodeX *n = &node_x[i]; + const int *s = span_y[n->span_y_index]; + const int *co_prev = verts[s[0]]; + const int *co_curr = verts[s[1]]; + + BLI_assert(co_prev[1] < pixel_y && co_curr[1] >= pixel_y); + + const double x = (co_prev[0] - co_curr[0]); + const double y = (co_prev[1] - co_curr[1]); + const double y_px = (pixel_y - co_curr[1]); + const int x_ix = (int)((double)co_curr[0] + ((y_px / y) * x)); + n->x = x_ix; + + if (is_sorted && (x_ix_prev > x_ix)) { + is_sorted = false; + } + if (do_remove == false && co_curr[1] == pixel_y) { + do_remove = true; + } + x_ix_prev = x_ix; + } + + /* Sort the nodes, via a simple "Bubble" sort. */ + if (is_sorted == false) { + int i = 0; + const int node_x_end = node_x_len - 1; + while (i < node_x_end) { + if (node_x[i].x > node_x[i + 1].x) { + SWAP(struct NodeX, node_x[i], node_x[i + 1]); + if (i != 0) { + i -= 1; + } + } + else { + i += 1; + } + } + } + + /* Fill the pixels between node pairs. */ + for (int i = 0; i < node_x_len; i += 2) { + int x_src = node_x[i].x; + int x_dst = node_x[i + 1].x; + + if (x_src >= xmax) { + break; + } + + if (x_dst > xmin) { + if (x_src < xmin) { + x_src = xmin; + } + if (x_dst > xmax) { + x_dst = xmax; + } + /* for single call per x-span */ + if (x_src < x_dst) { + callback(x_src - xmin, x_dst - xmin, pixel_y - ymin, userData); + } + } + } + + /* Clear finalized nodes in one pass, only when needed + * (avoids excessive array-resizing). */ + if (do_remove == true) { + int i_dst = 0; + for (int i_src = 0; i_src < node_x_len; i_src += 1) { + const int *s = span_y[node_x[i_src].span_y_index]; + const int *co = verts[s[1]]; + if (co[1] != pixel_y) { + if (i_dst != i_src) { + /* x is initialized for the next pixel_y (no need to adjust here) */ + node_x[i_dst].span_y_index = node_x[i_src].span_y_index; + } + i_dst += 1; + } + } + node_x_len = i_dst; + } + + /* Scan for new x-nodes */ + while ((span_y_index < span_y_len) && + (verts[span_y[span_y_index][0]][1] == pixel_y)) + { + /* note, node_x these are just added at the end, + * not ideal but sorting once will resolve. */ + + /* x is initialized for the next pixel_y */ + struct NodeX *n = &node_x[node_x_len++]; + n->span_y_index = span_y_index; + span_y_index += 1; + } + } + + MEM_freeN(span_y); + MEM_freeN(node_x); +} diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index abb8ff35a45..01a805a09b6 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -269,7 +269,7 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack) /** * ITU-R BT.709 primaries - * http://en.wikipedia.org/wiki/Relative_luminance + * https://en.wikipedia.org/wiki/Relative_luminance * * Real values are: * ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`` diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index dd30f267f78..f31d0935b77 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2885,142 +2885,6 @@ bool clip_segment_v3_plane_n( return true; } -void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData) -{ - int x1 = p1[0]; - int y1 = p1[1]; - int x2 = p2[0]; - int y2 = p2[1]; - - int ix; - int iy; - - /* if x1 == x2 or y1 == y2, then it does not matter what we set here */ - int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1; - int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1; - - if (callback(x1, y1, userData) == 0) { - return; - } - - if (delta_x >= delta_y) { - /* error may go below zero */ - int error = delta_y - (delta_x >> 1); - - while (x1 != x2) { - if (error >= 0) { - if (error || (ix > 0)) { - y1 += iy; - error -= delta_x; - } - /* else do nothing */ - } - /* else do nothing */ - - x1 += ix; - error += delta_y; - - if (callback(x1, y1, userData) == 0) { - return; - } - } - } - else { - /* error may go below zero */ - int error = delta_x - (delta_y >> 1); - - while (y1 != y2) { - if (error >= 0) { - if (error || (iy > 0)) { - x1 += ix; - error -= delta_y; - } - /* else do nothing */ - } - /* else do nothing */ - - y1 += iy; - error += delta_x; - - if (callback(x1, y1, userData) == 0) { - return; - } - } - } -} - -/** - * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive), - * note that \a x_end will always be greater than \a x, so we can use: - * - * \code{.c} - * do { - * func(x, y); - * } while (++x != x_end); - * \endcode - */ -void fill_poly_v2i_n( - const int xmin, const int ymin, const int xmax, const int ymax, - const int verts[][2], const int nr, - void (*callback)(int x, int x_end, int y, void *), void *userData) -{ - /* originally by Darel Rex Finley, 2007 */ - - int nodes, pixel_y, i, j, swap; - int *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__); - - /* Loop through the rows of the image. */ - for (pixel_y = ymin; pixel_y < ymax; pixel_y++) { - - /* Build a list of nodes. */ - nodes = 0; j = nr - 1; - for (i = 0; i < nr; i++) { - if ((verts[i][1] < pixel_y && verts[j][1] >= pixel_y) || - (verts[j][1] < pixel_y && verts[i][1] >= pixel_y)) - { - node_x[nodes++] = (int)(verts[i][0] + - ((double)(pixel_y - verts[i][1]) / (verts[j][1] - verts[i][1])) * - (verts[j][0] - verts[i][0])); - } - j = i; - } - - /* Sort the nodes, via a simple "Bubble" sort. */ - i = 0; - while (i < nodes - 1) { - if (node_x[i] > node_x[i + 1]) { - SWAP_TVAL(swap, node_x[i], node_x[i + 1]); - if (i) i--; - } - else { - i++; - } - } - - /* Fill the pixels between node pairs. */ - for (i = 0; i < nodes; i += 2) { - if (node_x[i] >= xmax) break; - if (node_x[i + 1] > xmin) { - if (node_x[i ] < xmin) node_x[i ] = xmin; - if (node_x[i + 1] > xmax) node_x[i + 1] = xmax; - -#if 0 - /* for many x/y calls */ - for (j = node_x[i]; j < node_x[i + 1]; j++) { - callback(j - xmin, pixel_y - ymin, userData); - } -#else - /* for single call per x-span */ - if (node_x[i] < node_x[i + 1]) { - callback(node_x[i] - xmin, node_x[i + 1] - xmin, pixel_y - ymin, userData); - } -#endif - } - } - } - MEM_freeN(node_x); -} - /****************************** Axis Utils ********************************/ /** diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index ded10ad7713..f0d0bd00dea 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -430,7 +430,7 @@ void BLI_cleanup_file(const char *relabase, char *path) * \return true if \a fname was changed, false otherwise. * * For now, simply replaces reserved chars (as listed in - * http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words ) + * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words ) * by underscores ('_'). * * \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c index 0b976e9612e..ccac221d836 100644 --- a/source/blender/blenlib/intern/smallhash.c +++ b/source/blender/blenlib/intern/smallhash.c @@ -34,7 +34,7 @@ * based on a doubling hashing approach (non-chaining) which uses more buckets then entries * stepping over buckets when two keys share the same hash so any key can find a free bucket. * - * See: http://en.wikipedia.org/wiki/Double_hashing + * See: https://en.wikipedia.org/wiki/Double_hashing * * \warning This should _only_ be used for small hashes where allocating a hash every time is unacceptable. * Otherwise #GHash should be used instead. diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 31839a59ce1..677c90051f7 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2145,6 +2145,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p prv->gputexture[i] = NULL; } prv->icon_id = 0; + prv->tag = 0; } return prv; @@ -4740,6 +4741,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) smd->domain->tex = NULL; smd->domain->tex_shadow = NULL; smd->domain->tex_wt = NULL; + smd->domain->coba = newdataadr(fd, smd->domain->coba); smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights); if (!smd->domain->effector_weights) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ed41ac0cb93..03436f4658a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1515,6 +1515,11 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); if (smd->domain) { + + if (smd->domain->coba) { + writestruct(wd, DATA, ColorBand, 1, smd->domain->coba); + } + writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights); } } diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 72ea7bd7f5d..104df625ee6 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -245,7 +245,7 @@ typedef struct BMesh { /* ID of the shape key this bmesh came from */ int shapenr; - int walkers, totflags; + int totflags; ListBase selected; BMFace *act_face; diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index e83b752947c..d2f638fa8f8 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -287,7 +287,7 @@ static BMLoop *bm_face_boundary_add( #endif BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag); - bmesh_radial_append(starte, l); + bmesh_radial_loop_append(starte, l); #ifdef USE_BMESH_HOLES lst->first = lst->last = l; @@ -295,8 +295,6 @@ static BMLoop *bm_face_boundary_add( #else f->l_first = l; #endif - - l->f = f; return l; } @@ -458,14 +456,11 @@ BMFace *BM_face_create( f = bm_face_create__internal(bm); startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag); - - startl->v = verts[0]; - startl->e = edges[0]; + for (i = 1; i < len; i++) { l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag); - - l->f = f; - bmesh_radial_append(edges[i], l); + + bmesh_radial_loop_append(edges[i], l); l->prev = lastl; lastl->next = l; @@ -904,7 +899,7 @@ void BM_face_kill(BMesh *bm, BMFace *f) do { l_next = l_iter->next; - bmesh_radial_loop_remove(l_iter, l_iter->e); + bmesh_radial_loop_remove(l_iter->e, l_iter); bm_kill_only_loop(bm, l_iter); } while ((l_iter = l_next) != l_first); @@ -949,7 +944,7 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) l_next = l_iter->next; e = l_iter->e; - bmesh_radial_loop_remove(l_iter, e); + bmesh_radial_loop_remove(e, l_iter); bm_kill_only_loop(bm, l_iter); if (e->l == NULL) { @@ -981,23 +976,8 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) */ void BM_edge_kill(BMesh *bm, BMEdge *e) { - - if (e->l) { - BMLoop *l = e->l, *lnext, *startl = e->l; - - do { - lnext = l->radial_next; - if (lnext->f == l->f) { - BM_face_kill(bm, l->f); - break; - } - - BM_face_kill(bm, l->f); - - if (l == lnext) - break; - l = lnext; - } while (l != startl); + while (e->l) { + BM_face_kill(bm, e->l->f); } bmesh_disk_edge_remove(e, e->v1); @@ -1011,15 +991,8 @@ void BM_edge_kill(BMesh *bm, BMEdge *e) */ void BM_vert_kill(BMesh *bm, BMVert *v) { - if (v->e) { - BMEdge *e, *e_next; - - e = v->e; - while (v->e) { - e_next = bmesh_disk_edge_next(e, v); - BM_edge_kill(bm, e); - e = e_next; - } + while (v->e) { + BM_edge_kill(bm, v->e); } bm_kill_only_vert(bm, v); @@ -1077,7 +1050,7 @@ static bool bm_loop_reverse_loop( int i, j, edok; for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - bmesh_radial_loop_remove(l_iter, (edar[i] = l_iter->e)); + bmesh_radial_loop_remove((edar[i] = l_iter->e), l_iter); } /* actually reverse the loop */ @@ -1113,7 +1086,7 @@ static bool bm_loop_reverse_loop( } /* rebuild radial */ for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) - bmesh_radial_append(l_iter->e, l_iter); + bmesh_radial_loop_append(l_iter->e, l_iter); #ifndef NDEBUG /* validate radial */ @@ -1585,8 +1558,8 @@ BMFace *bmesh_sfme( } while ((l_iter = l_iter->next) != l_first); /* link up the new loops into the new edges radial */ - bmesh_radial_append(e, l_f1); - bmesh_radial_append(e, l_f2); + bmesh_radial_loop_append(e, l_f1); + bmesh_radial_loop_append(e, l_f2); f2->len = f2len; @@ -1700,7 +1673,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l = l_next; l->f->len++; l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL; - bmesh_radial_loop_remove(l, NULL); + bmesh_radial_loop_unlink(l); l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0); l_new->prev = l; @@ -1725,8 +1698,8 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->radial_next = l->radial_prev = NULL; } - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) { l_new->e = e_new; @@ -1743,8 +1716,8 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->radial_next = l->radial_prev = NULL; } - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } } @@ -2619,8 +2592,8 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src) l = e_src->l; BLI_assert(BM_vert_in_edge(e_dst, l->v)); BLI_assert(BM_vert_in_edge(e_dst, l->next->v)); - bmesh_radial_loop_remove(l, e_src); - bmesh_radial_append(e_dst, l); + bmesh_radial_loop_remove(e_src, l); + bmesh_radial_loop_append(e_dst, l); } BLI_assert(bmesh_radial_length(e_src->l) == 0); @@ -2667,8 +2640,8 @@ void bmesh_edge_separate( } e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP); - bmesh_radial_loop_remove(l_sep, e); - bmesh_radial_append(e_new, l_sep); + bmesh_radial_loop_remove(e, l_sep); + bmesh_radial_loop_append(e_new, l_sep); l_sep->e = e_new; if (copy_select) { @@ -2855,8 +2828,8 @@ BMVert *bmesh_urmv_loop_multi( do { l_next = l_iter->radial_next; if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) { - bmesh_radial_loop_remove(l_iter, e); - bmesh_radial_append(e_new, l_iter); + bmesh_radial_loop_remove(e, l_iter); + bmesh_radial_loop_append(e_new, l_iter); l_iter->e = e_new; } } while ((l_iter = l_next) != l_first); diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c index 1f64f7b74cc..2591c33fc73 100644 --- a/source/blender/bmesh/intern/bmesh_log.c +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -45,7 +45,7 @@ #include "bmesh.h" #include "bmesh_log.h" -#include "range_tree_c_api.h" +#include "range_tree.h" #include "BLI_strict_flags.h" diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index 5ee0e904a33..6ce7c100b0d 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -161,7 +161,7 @@ static bool bm_face_split_edgenet_find_loop_pair( e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); if (edges_boundary_len > 2) { - BLI_SMALLSTACK_SWAP(edges_search, edges_wire); + BLI_SMALLSTACK_SWAP(edges_search, edges_boundary); } } else { diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index cb302139a4c..edde8cb5d31 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -143,7 +143,7 @@ void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) * to store non-manifold conditions since BM does not keep track of region/shell information. * * Functions relating to this cycle: - * - #bmesh_radial_append + * - #bmesh_radial_loop_append * - #bmesh_radial_loop_remove * - #bmesh_radial_facevert_count * - #bmesh_radial_facevert_check @@ -389,6 +389,30 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) return true; } +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) +{ + if (e->l == NULL) { + e->l = l; + l->radial_next = l->radial_prev = l; + } + else { + l->radial_prev = e->l; + l->radial_next = e->l->radial_next; + + e->l->radial_next->radial_prev = l; + e->l->radial_next = l; + + e->l = l; + } + + if (UNLIKELY(l->e && l->e != e)) { + /* l is already in a radial cycle for a different edge */ + BMESH_ASSERT(0); + } + + l->e = e; +} + /** * \brief BMESH RADIAL REMOVE LOOP * @@ -397,28 +421,27 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) * updated (in the case that the edge's link into the radial * cycle was the loop which is being removed from the cycle). */ -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) { /* if e is non-NULL, l must be in the radial cycle of e */ - if (UNLIKELY(e && e != l->e)) { + if (UNLIKELY(e != l->e)) { BMESH_ASSERT(0); } if (l->radial_next != l) { - if (e && l == e->l) + if (l == e->l) { e->l = l->radial_next; + } l->radial_next->radial_prev = l->radial_prev; l->radial_prev->radial_next = l->radial_next; } else { - if (e) { - if (l == e->l) { - e->l = NULL; - } - else { - BMESH_ASSERT(0); - } + if (l == e->l) { + e->l = NULL; + } + else { + BMESH_ASSERT(0); } } @@ -428,6 +451,22 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) l->e = NULL; } +/** + * A version of #bmesh_radial_loop_remove which only performs the radial unlink, + * leaving the edge untouched. + */ +void bmesh_radial_loop_unlink(BMLoop *l) +{ + if (l->radial_next != l) { + l->radial_next->radial_prev = l->radial_prev; + l->radial_prev->radial_next = l->radial_next; + } + + /* l is no longer in a radial cycle; empty the links + * to the cycle and the link back to an edge */ + l->radial_next = l->radial_prev = NULL; + l->e = NULL; +} /** * \brief BME RADIAL FIND FIRST FACE VERT @@ -484,30 +523,6 @@ int bmesh_radial_length(const BMLoop *l) return i; } -void bmesh_radial_append(BMEdge *e, BMLoop *l) -{ - if (e->l == NULL) { - e->l = l; - l->radial_next = l->radial_prev = l; - } - else { - l->radial_prev = e->l; - l->radial_next = e->l->radial_next; - - e->l->radial_next->radial_prev = l; - e->l->radial_next = l; - - e->l = l; - } - - if (UNLIKELY(l->e && l->e != e)) { - /* l is already in a radial cycle for a different edge */ - BMESH_ASSERT(0); - } - - l->e = e; -} - /** * \brief RADIAL COUNT FACE VERT * diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h index 07f94796bb2..679e7a269b3 100644 --- a/source/blender/bmesh/intern/bmesh_structure.h +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -55,8 +55,9 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WA BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* RADIAL CYCLE MANAGMENT */ -void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1); +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL(); /* note: * bmesh_radial_loop_next(BMLoop *l) / prev. * just use member access l->radial_next, l->radial_prev now */ diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp index a681583809c..70e0b2cfb57 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp @@ -186,8 +186,8 @@ struct BufferLineAccumulator { } /* TODO implement proper filtering here, see - * http://en.wikipedia.org/wiki/Lanczos_resampling - * http://en.wikipedia.org/wiki/Sinc_function + * https://en.wikipedia.org/wiki/Lanczos_resampling + * https://en.wikipedia.org/wiki/Sinc_function * * using lanczos with x = distance from the line segment, * normalized to a == 0.5f, could give a good result diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 76cd81f1b8f..da71db09f3d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -47,7 +47,7 @@ namespace DEG { /* -------------------------------------------------- */ /* Performs a transitive reduction to remove redundant relations. - * http://en.wikipedia.org/wiki/Transitive_reduction + * https://en.wikipedia.org/wiki/Transitive_reduction * * XXX The current implementation is somewhat naive and has O(V*E) worst case * runtime. diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 75fb55a1b4d..b61b31a6be6 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -209,6 +209,9 @@ void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag) if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) { DEG_graph_id_tag_update(bmain, graph, id); } + else if (flag & OB_RECALC_TIME) { + DEG_graph_id_tag_update(bmain, graph, id); + } } } } diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 262ce0b9e23..d7899061218 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -263,7 +263,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->poll = change_frame_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; /* rna */ ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 863f5e3852c..f3eeadb6604 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2219,7 +2219,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB /* ******************* copy and paste ******************** */ /* c = copy, v = paste */ -static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode) +static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, const char mode, const bool copy_array) { int buf_paste_len = 0; const char *buf_paste = ""; @@ -2255,6 +2255,46 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, if (but->poin == NULL && but->rnapoin.data == NULL) { /* pass */ } + else if (copy_array && but->rnapoin.data && but->rnaprop && + ELEM(RNA_property_subtype(but->rnaprop), PROP_COLOR, PROP_TRANSLATION, PROP_DIRECTION, + PROP_VELOCITY, PROP_ACCELERATION, PROP_MATRIX, PROP_EULER, PROP_QUATERNION, PROP_AXISANGLE, + PROP_XYZ, PROP_XYZ_LENGTH, PROP_COLOR_GAMMA, PROP_COORDS)) + { + float values[4]; + int array_length = RNA_property_array_length(&but->rnapoin, but->rnaprop); + + if (mode == 'c') { + char buf_copy[UI_MAX_DRAW_STR]; + + if (array_length == 4) { + values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); + } + else { + values[3] = 0.0f; + } + ui_but_v3_get(but, values); + + BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f, %f]", values[0], values[1], values[2], values[3]); + WM_clipboard_text_set(buf_copy, 0); + } + else { + if (sscanf(buf_paste, "[%f, %f, %f, %f]", &values[0], &values[1], &values[2], &values[3]) >= array_length) { + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); + + ui_but_v3_set(but, values); + if (but->rnaprop && array_length == 4) { + RNA_property_float_set_index(&but->rnapoin, but->rnaprop, 3, values[3]); + } + data->value = values[but->rnaindex]; + + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + else { + WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'"); + show_report = true; + } + } + } else if (mode == 'c') { /* Get many decimal places, then strip trailing zeros. * note: too high values start to give strange results */ @@ -6617,15 +6657,22 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) { bScreen *sc = CTX_wm_screen(C); + const bool has_panel_category = UI_panel_category_is_visible(ar); + const bool any_item_visible = has_panel_category; PointerRNA ptr; uiPopupMenu *pup; uiLayout *layout; + if (!any_item_visible) { + return; + } + RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr); pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE); layout = UI_popup_menu_layout(pup); - if (UI_panel_category_is_visible(ar)) { + + if (has_panel_category) { char tmpstr[80]; BLI_snprintf(tmpstr, sizeof(tmpstr), "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift+Left Mouse")); uiItemR(layout, &ptr, "use_pin", 0, tmpstr, ICON_NONE); @@ -6636,7 +6683,6 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) uiBut *but = block->buttons.last; but->flag |= UI_BUT_HAS_SEP_CHAR; } - } UI_popup_menu_end(C, pup); } @@ -6959,7 +7005,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) { /* handle copy-paste */ if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS && - IS_EVENT_MOD(event, ctrl, oskey) && !event->shift && !event->alt) + IS_EVENT_MOD(event, ctrl, oskey) && !event->shift) { /* Specific handling for listrows, we try to find their overlapping tex button. */ if (but->type == UI_BTYPE_LISTROW) { @@ -6969,7 +7015,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * data = but->active; } } - ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v'); + ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v', event->alt); return WM_UI_HANDLER_BREAK; } /* handle drop */ diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index f82ed82a922..02812f6a842 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1087,7 +1087,7 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi if (prv) { const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; - if (id || prv->use_deferred) { + if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) { ui_id_preview_image_render_size(C, NULL, id, prv, size, true); } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 462ad34582b..09c5854fb26 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3851,6 +3851,8 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c return; } + SpaceButs *sbuts = CTX_wm_space_buts(C); + uiLayout *row = uiLayoutRow(layout, false); uiBlock *block = uiLayoutGetBlock(row); uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, ""); @@ -3876,6 +3878,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE); row = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row, (sbuts->mainb == BCONTEXT_CONSTRAINT)); uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE); /* TODO: unused for now, so no need to expose. */ diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 2256bd7f8c5..a991f59e8e2 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -68,6 +68,8 @@ static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + RNA_boolean_set(op->ptr, "init_scene_frame_range", true); + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { Main *bmain = CTX_data_main(C); char filepath[FILE_MAX]; @@ -231,11 +233,22 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr) uiItemR(row, imfptr, "ngon_method", 0, NULL, ICON_NONE); } -static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op) +static void wm_alembic_export_draw(bContext *C, wmOperator *op) { PointerRNA ptr; RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + + /* Conveniently set start and end frame to match the scene's frame range. */ + Scene *scene = CTX_data_scene(C); + + if (scene != NULL && RNA_boolean_get(&ptr, "init_scene_frame_range")) { + RNA_int_set(&ptr, "start", SFRA); + RNA_int_set(&ptr, "end", EFRA); + + RNA_boolean_set(&ptr, "init_scene_frame_range", false); + } + ui_alembic_export_settings(op->layout, &ptr); } @@ -334,6 +347,11 @@ void WM_OT_alembic_export(wmOperatorType *ot) RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_quad_method_items, MOD_TRIANGULATE_NGON_BEAUTY, "Polygon Method", "Method for splitting the polygons into triangles"); + + /* This dummy prop is used to check whether we need to init the start and + * end frame values to that of the scene's, otherwise they are reset at + * every change, draw update. */ + RNA_def_boolean(ot->srna, "init_scene_frame_range", false, "", ""); } /* ************************************************************************** */ diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index c5eea94f5e1..ebe8898571d 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -59,7 +59,9 @@ static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *eve { if (!RNA_struct_property_is_set(op->ptr, "filepath")) { char filepath[FILE_MAX]; - BLI_strncpy(filepath, G.main->name, sizeof(filepath)); + Main *bmain = CTX_data_main(C); + + BLI_strncpy(filepath, bmain->name, sizeof(filepath)); BLI_replace_extension(filepath, sizeof(filepath), ".abc"); RNA_string_set(op->ptr, "filepath", filepath); } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 5d5731a7e16..a6de1b284b7 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -32,6 +32,7 @@ #include "MEM_guardedalloc.h" #include "BLI_bitmap.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_listbase.h" #include "BLI_linklist.h" #include "BLI_linklist_stack.h" @@ -294,7 +295,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short lasso_mask_data.px = dr_mask; lasso_mask_data.width = (xmax - xmin) + 1; - fill_poly_v2i_n( + BLI_bitmap_draw_2d_poly_v2i_n( xmin, ymin, xmax + 1, ymax + 1, mcords, tot, edbm_mask_lasso_px_cb, &lasso_mask_data); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 41c1669addd..b593ac0f2e8 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2233,7 +2233,7 @@ static int make_local_exec(bContext *C, wmOperator *op) "Orphan library objects added to the current scene to avoid loss"); } - BKE_library_make_local(bmain, NULL, false, false); /* NULL is all libs */ + BKE_library_make_local(bmain, NULL, NULL, false, false); /* NULL is all libs */ WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index bd016b7fcfb..82da6f58912 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -2604,6 +2604,8 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "all")) BKE_object_defgroup_remove_all(ob); + else if (RNA_boolean_get(op->ptr, "all_unlocked")) + BKE_object_defgroup_remove_all_ex(ob, true); else vgroup_delete_active(ob); @@ -2633,6 +2635,7 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups"); + RNA_def_boolean(ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups"); } static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index ddbf59b2cf7..87c08dc6583 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -1080,13 +1080,19 @@ static void icon_preview_add_size(IconPreview *ip, unsigned int *rect, int sizex static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short *do_update, float *progress) { IconPreview *ip = (IconPreview *)customdata; - IconPreviewSize *cur_size = ip->sizes.first; + IconPreviewSize *cur_size; const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene); - while (cur_size) { + for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) { PreviewImage *prv = ip->owner; + + if (prv->tag & PRV_TAG_DEFFERED_DELETE) { + /* Non-thread-protected reading is not an issue here. */ + continue; + } + ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); - const bool is_render = !prv->use_deferred; + const bool is_render = !(prv->tag & PRV_TAG_DEFFERED); /* construct shader preview from image size and previewcustomdata */ sp->scene = ip->scene; @@ -1117,8 +1123,6 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short common_preview_startjob(sp, stop, do_update, progress); shader_preview_free(sp); - - cur_size = cur_size->next; } } @@ -1147,6 +1151,15 @@ static void icon_preview_endjob(void *customdata) } #endif } + + if (ip->owner) { + PreviewImage *prv_img = ip->owner; + prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING; + if (prv_img->tag & PRV_TAG_DEFFERED_DELETE) { + BLI_assert(prv_img->tag & PRV_TAG_DEFFERED); + BKE_previewimg_cached_release_pointer(prv_img); + } + } } static void icon_preview_free(void *customdata) @@ -1205,6 +1218,14 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r icon_preview_add_size(ip, rect, sizex, sizey); + /* Special threading hack: warn main code that this preview is being rendered and cannot be freed... */ + { + PreviewImage *prv_img = owner; + if (prv_img->tag & PRV_TAG_DEFFERED) { + prv_img->tag |= PRV_TAG_DEFFERED_RENDERING; + } + } + /* setup job */ WM_jobs_customdata_set(wm_job, ip, icon_preview_free); WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index a47b9a0b936..a4887c579ac 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -37,6 +37,7 @@ #include "BIF_glutil.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_math_matrix.h" #include "BLI_math_geom.h" #include "BLI_utildefines.h" @@ -439,7 +440,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.width = data.rect.xmax - data.rect.xmin; data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__); - fill_poly_v2i_n( + BLI_bitmap_draw_2d_poly_v2i_n( data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax, mcords, mcords_tot, mask_lasso_px_cb, &data); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 1ca75246ba8..e1f577d1724 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -7629,10 +7629,6 @@ afterdraw: if (!render_override && sds->draw_velocity) { draw_smoke_velocity(sds, viewnormal); } - -#ifdef SMOKE_DEBUG_HEAT - draw_smoke_heat(smd->domain, ob); -#endif } } diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 9cfcd6cef05..584f442bd44 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -1,4 +1,4 @@ -/* +/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -42,6 +42,7 @@ #include "BLI_math.h" #include "BKE_DerivedMesh.h" +#include "BKE_texture.h" #include "smoke_API.h" @@ -62,28 +63,33 @@ struct GPUTexture; # include "PIL_time_utildefines.h" #endif -static GPUTexture *create_flame_spectrum_texture(void) +/* *************************** Transfer functions *************************** */ + +enum { + TFUNC_FLAME_SPECTRUM = 0, + TFUNC_COLOR_RAMP = 1, +}; + +#define TFUNC_WIDTH 256 + +static void create_flame_spectrum_texture(float *data) { -#define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 - GPUTexture *tex; - int i, j, k; - float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data"); - float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); + float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); - blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000); + blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); - for (i = 0; i < 16; i++) { - for (j = 0; j < 16; j++) { - for (k = 0; k < SPEC_WIDTH; k++) { - int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + for (int k = 0; k < TFUNC_WIDTH; k++) { + int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { - spec_pixels[index] = (spec_data[k * 4]); - spec_pixels[index + 1] = (spec_data[k * 4 + 1]); - spec_pixels[index + 2] = (spec_data[k * 4 + 2]); + spec_pixels[index] = (data[k * 4]); + spec_pixels[index + 1] = (data[k * 4 + 1]); + spec_pixels[index + 2] = (data[k * 4 + 2]); spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } @@ -94,19 +100,69 @@ static GPUTexture *create_flame_spectrum_texture(void) } } - tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); + memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); - MEM_freeN(spec_data); MEM_freeN(spec_pixels); -#undef SPEC_WIDTH #undef FIRE_THRESH #undef MAX_FIRE_ALPHA #undef FULL_ON_FIRE +} + +static void create_color_ramp(const ColorBand *coba, float *data) +{ + for (int i = 0; i < TFUNC_WIDTH; i++) { + do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + } +} + +static GPUTexture *create_transfer_function(int type, const ColorBand *coba) +{ + float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); + + switch (type) { + case TFUNC_FLAME_SPECTRUM: + create_flame_spectrum_texture(data); + break; + case TFUNC_COLOR_RAMP: + create_color_ramp(coba, data); + break; + } + + GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL); + + MEM_freeN(data); return tex; } +static GPUTexture *create_field_texture(SmokeDomainSettings *sds) +{ + float *field = NULL; + + switch (sds->coba_field) { +#ifdef WITH_SMOKE + case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break; + case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break; + case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break; + case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break; + case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break; + case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break; + case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break; + case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break; + case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break; + case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break; + case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break; + case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break; +#endif + default: return NULL; + } + + return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field); +} + typedef struct VolumeSlicer { float size[3]; float min[3]; @@ -347,6 +403,7 @@ static int create_view_aligned_slices(VolumeSlicer *slicer, } static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec, + GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire, const float min[3], const float ob_sizei[3], const float invsize[3]) { @@ -359,6 +416,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture int densityscale_location; int spec_location, flame_location; int shadow_location, actcol_location; + int tfunc_location = 0; + int coba_location = 0; if (use_fire) { spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); @@ -370,6 +429,11 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture soot_location = GPU_shader_get_uniform(shader, "soot_texture"); stepsize_location = GPU_shader_get_uniform(shader, "step_size"); densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); + + if (sds->use_coba) { + tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture"); + coba_location = GPU_shader_get_uniform(shader, "color_band_texture"); + } } GPU_shader_bind(shader); @@ -397,6 +461,14 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) mul_v3_v3(active_color, sds->active_color); GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); + + if (sds->use_coba) { + GPU_texture_bind(tex_tfunc, 4); + GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc); + + GPU_texture_bind(tex_coba, 5); + GPU_shader_uniform_texture(shader, coba_location, tex_coba); + } } GPU_shader_uniform_vector(shader, min_location, 3, 1, min); @@ -404,7 +476,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); } -static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire) +static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, + GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire) { GPU_shader_unbind(); @@ -417,20 +490,30 @@ static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool u } else { GPU_texture_unbind(sds->tex_shadow); + + if (sds->use_coba) { + GPU_texture_unbind(tex_tfunc); + GPU_texture_free(tex_tfunc); + + GPU_texture_unbind(tex_coba); + GPU_texture_free(tex_coba); + } } } static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer, const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire) { - GPUTexture *tex_spec = (do_fire) ? create_flame_spectrum_texture() : NULL; + GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL; + GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL; + GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : NULL; GLuint vertex_buffer; glGenBuffers(1, &vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW); - bind_shader(sds, shader, tex_spec, do_fire, slicer->min, ob_sizei, invsize); + bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, NULL); @@ -439,7 +522,7 @@ static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const Volum glDisableClientState(GL_VERTEX_ARRAY); - unbind_shader(sds, tex_spec, do_fire); + unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire); /* cleanup */ @@ -459,7 +542,16 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; - GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE); + GPUBuiltinShader builtin_shader; + + if (sds->use_coba) { + builtin_shader = GPU_SHADER_SMOKE_COBA; + } + else { + builtin_shader = GPU_SHADER_SMOKE; + } + + GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader); if (!shader) { fprintf(stderr, "Unable to create GLSL smoke shader.\n"); @@ -549,7 +641,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false); /* Draw fire separately (T47639). */ - if (use_fire) { + if (use_fire && !sds->use_coba) { glBlendFunc(GL_ONE, GL_ONE); draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true); } @@ -759,50 +851,3 @@ void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3]) UNUSED_VARS(domain, viewnormal); #endif } - -#ifdef SMOKE_DEBUG_HEAT -void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob) -{ - float x, y, z; - float x0, y0, z0; - int *base_res = domain->base_res; - int *res = domain->res; - int *res_min = domain->res_min; - int *res_max = domain->res_max; - float *heat = smoke_get_heat(domain->fluid); - - float min[3]; - float *cell_size = domain->cell_size; - float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f; - float vf = domain->scale / 16.f * 2.f; /* velocity factor */ - - /* set first position so that it doesn't jump when domain moves */ - x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size); - y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size); - z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size); - if (x0 < res_min[0]) x0 += step_size; - if (y0 < res_min[1]) y0 += step_size; - if (z0 < res_min[2]) z0 += step_size; - add_v3_v3v3(min, domain->p0, domain->obj_shift_f); - - for (x = floor(x0); x < res_max[0]; x += step_size) - for (y = floor(y0); y < res_max[1]; y += step_size) - for (z = floor(z0); z < res_max[2]; z += step_size) { - int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1]; - - float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]}; - - /* draw heat as different sized points */ - if (heat[index] >= 0.01f) { - float col_gb = 1.0f - heat[index]; - CLAMP(col_gb, 0.0f, 1.0f); - glColor3f(1.0f, col_gb, col_gb); - glPointSize(24.0f * heat[index]); - - glBegin(GL_POINTS); - glVertex3f(pos[0], pos[1], pos[2]); - glEnd(); - } - } -} -#endif diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 2c4b04ebd34..6b53e9b0ae8 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -41,6 +41,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_blenlib.h" #include "BLI_kdopbvh.h" #include "BLI_math.h" @@ -5048,7 +5049,7 @@ bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int copy_v2_v2_int(p1, mval_sta); copy_v2_v2_int(p2, mval_end); - plot_line_v2v2i(p1, p2, depth_segment_cb, &data); + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); *depth = data.depth; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index fb3ef8bd599..a5d8ebb7ce1 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -310,14 +310,8 @@ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, const float min[3], const float max[3], const float viewnormal[3]); -//#define SMOKE_DEBUG_HEAT - void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]); -#ifdef SMOKE_DEBUG_HEAT -void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob); -#endif - /* workaround for trivial but noticeable camera bug caused by imprecision * between view border calculation in 2D/3D space, workaround for bug [#28037]. * without this define we get the old behavior which is to try and align them diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index aead5baaaf1..74dc91b55ef 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -89,6 +89,7 @@ typedef enum GPUBuiltinShader { GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, GPU_SHADER_SMOKE = 2, GPU_SHADER_SMOKE_FIRE = 3, + GPU_SHADER_SMOKE_COBA = 4, /* specialized drawing */ GPU_SHADER_TEXT, diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 2e1c3b70a6e..699028d6570 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -106,6 +106,7 @@ static struct GPUShadersGlobal { GPUShader *sep_gaussian_blur; GPUShader *smoke; GPUShader *smoke_fire; + GPUShader *smoke_coba; /* cache for shader fx. Those can exist in combinations so store them here */ GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; /* specialized drawing */ @@ -653,6 +654,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) NULL, NULL, NULL, 0, 0, 0); retval = GG.shaders.smoke_fire; break; + case GPU_SHADER_SMOKE_COBA: + if (!GG.shaders.smoke_coba) + GG.shaders.smoke_coba = GPU_shader_create( + datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, + NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); + retval = GG.shaders.smoke_coba; + break; case GPU_SHADER_TEXT: if (!GG.shaders.text) GG.shaders.text = GPU_shader_create( @@ -954,6 +962,11 @@ void GPU_shader_free_builtin_shaders(void) GG.shaders.smoke_fire = NULL; } + if (GG.shaders.smoke_coba) { + GPU_shader_free(GG.shaders.smoke_coba); + GG.shaders.smoke_coba = NULL; + } + if (GG.shaders.text) { GPU_shader_free(GG.shaders.text); GG.shaders.text = NULL; diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl index fd790009e02..6ded453225e 100644 --- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl @@ -8,10 +8,17 @@ uniform float density_scale; uniform sampler3D soot_texture; uniform sampler3D shadow_texture; +#ifdef USE_COBA +uniform sampler1D transfer_texture; +uniform sampler3D color_band_texture; +#endif + void main() { /* compute color and density from volume texture */ vec4 soot = texture3D(soot_texture, coords); + +#ifndef USE_COBA vec3 soot_color; if (soot.a != 0) { soot_color = active_color * soot.rgb / soot.a; @@ -31,6 +38,11 @@ void main() /* premultiply alpha */ vec4 color = vec4(soot_alpha * soot_color, soot_alpha); +#else + float color_band = texture3D(color_band_texture, coords).r; + vec4 transfer_function = texture1D(transfer_texture, color_band); + vec4 color = transfer_function * density_scale; +#endif gl_FragColor = color; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 45eb31235f5..7bbbb8addcc 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -172,6 +172,13 @@ enum ePreviewImage_Flag { PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */ }; +/* for PreviewImage->tag */ +enum { + PRV_TAG_DEFFERED = (1 << 0), /* Actual loading of preview is deffered. */ + PRV_TAG_DEFFERED_RENDERING = (1 << 1), /* Deffered preview is being loaded. */ + PRV_TAG_DEFFERED_DELETE = (1 << 2), /* Deffered preview should be deleted asap. */ +}; + typedef struct PreviewImage { /* All values of 2 are really NUM_ICON_SIZES */ unsigned int w[2]; @@ -184,12 +191,12 @@ typedef struct PreviewImage { struct GPUTexture *gputexture[2]; int icon_id; /* Used by previews outside of ID context. */ - char pad[3]; - char use_deferred; /* for now a mere bool, if we add more deferred loading methods we can switch to bitflag. */ + short tag; /* Runtime data. */ + char pad[2]; } PreviewImage; #define PRV_DEFERRED_DATA(prv) \ - (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->use_deferred), (void *)((prv) + 1)) + (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->tag & PRV_TAG_DEFFERED), (void *)((prv) + 1)) /** * Defines for working with IDs. diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index dd47d63fc19..46b1adf2725 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -36,10 +36,10 @@ extern "C" { #endif - /* CacheFile::flag */ enum { CACHEFILE_DS_EXPAND = (1 << 0), + CACHEFILE_DIRTY = (1 << 1), }; /* CacheFile::draw_flag */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index fc4e7de73f5..ca774864e95 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -461,6 +461,7 @@ typedef struct bObjectSolverConstraint { /* Transform matrix cache constraint */ typedef struct bTransformCacheConstraint { struct CacheFile *cache_file; + struct CacheReader *reader; char object_path[1024]; /* FILE_MAX */ } bTransformCacheConstraint; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 7872ee09259..4a3d330a698 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1517,6 +1517,7 @@ typedef struct MeshSeqCacheModifierData { ModifierData modifier; struct CacheFile *cache_file; + struct CacheReader *reader; char object_path[1024]; /* 1024 = FILE_MAX */ char read_flag; diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 68b7f559fce..4ee83346fe3 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -77,6 +77,23 @@ enum { VECTOR_DRAW_STREAMLINE = 1, }; +enum { + FLUID_FIELD_DENSITY = 0, + FLUID_FIELD_HEAT = 1, + FLUID_FIELD_FUEL = 2, + FLUID_FIELD_REACT = 3, + FLUID_FIELD_FLAME = 4, + FLUID_FIELD_VELOCITY_X = 5, + FLUID_FIELD_VELOCITY_Y = 6, + FLUID_FIELD_VELOCITY_Z = 7, + FLUID_FIELD_COLOR_R = 8, + FLUID_FIELD_COLOR_G = 9, + FLUID_FIELD_COLOR_B = 10, + FLUID_FIELD_FORCE_X = 11, + FLUID_FIELD_FORCE_Y = 12, + FLUID_FIELD_FORCE_Z = 13, +}; + /* cache compression */ #define SM_CACHE_LIGHT 0 #define SM_CACHE_HEAVY 1 @@ -190,9 +207,13 @@ typedef struct SmokeDomainSettings { float slice_per_voxel; float slice_depth; float display_thickness; + + struct ColorBand *coba; float vector_scale; char vector_draw_type; - char pad2[3]; + char use_coba; + char coba_field; /* simulation field used for the color mapping */ + char pad2; } SmokeDomainSettings; diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index 7249ebd5feb..09fdeb15b10 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -37,6 +37,8 @@ #include "BKE_cachefile.h" #include "BKE_depsgraph.h" +#include "BLI_string.h" + #include "DEG_depsgraph.h" #include "WM_api.h" @@ -60,6 +62,12 @@ static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *p { CacheFile *cache_file = ptr->data; + if ((cache_file->flag & CACHEFILE_DIRTY) != 0) { + BKE_cachefile_clean(scene, cache_file); + BLI_freelistN(&cache_file->object_paths); + cache_file->flag &= ~CACHEFILE_DIRTY; + } + BKE_cachefile_reload(bmain, cache_file); rna_CacheFile_update(bmain, scene, ptr); @@ -71,6 +79,20 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL); } +static void rna_CacheFile_filename_set(PointerRNA *ptr, const char *value) +{ + CacheFile *cache_file = ptr->data; + + if (STREQ(cache_file->filepath, value)) { + return; + } + + /* Different file is opened, close all readers. */ + cache_file->flag |= CACHEFILE_DIRTY; + + BLI_strncpy(cache_file->filepath, value, sizeof(cache_file->filepath)); +} + #else /* cachefile.object_paths */ @@ -103,6 +125,7 @@ static void rna_def_cachefile(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_FILE); PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheFile_filename_set"); RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file"); RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle"); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index db3f76f3cfc..de1a0f24c31 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -148,12 +148,17 @@ static EnumPropertyItem space_object_items[] = { {0, NULL, 0, NULL, NULL} }; +#include "DNA_cachefile_types.h" + #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#ifdef WITH_ALEMBIC +# include "ABC_alembic.h" +#endif static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr) { @@ -471,6 +476,22 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v } } +static void rna_Constraint_transformCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ +#ifdef WITH_ALEMBIC + bConstraint *con = (bConstraint *)ptr->data; + bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; + Object *ob = (Object *)ptr->id.data; + + data->reader = CacheReader_open_alembic_object(data->cache_file->handle, + data->reader, + ob, + data->object_path); +#endif + + rna_Constraint_update(bmain, scene, ptr); +} + #else static EnumPropertyItem constraint_distance_items[] = { @@ -2593,7 +2614,7 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna) prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup the transform matrix"); - RNA_def_property_update(prop, 0, "rna_Constraint_update"); + RNA_def_property_update(prop, 0, "rna_Constraint_transformCache_object_path_update"); } /* base struct for constraints */ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index de5dd2b2b56..5d78df105da 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1117,6 +1117,21 @@ static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr) return (csmd->bind_coords != NULL); } +static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ +#ifdef WITH_ALEMBIC + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data; + Object *ob = (Object *)ptr->id.data; + + mcmd->reader = CacheReader_open_alembic_object(mcmd->cache_file->handle, + mcmd->reader, + ob, + mcmd->object_path); +#endif + + rna_Modifier_update(bmain, scene, ptr); +} + #else static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[]) @@ -4135,7 +4150,7 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna) prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup geometric data"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_def_property_update(prop, 0, "rna_MeshSequenceCache_object_path_update"); static EnumPropertyItem read_flag_items[] = { {MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""}, diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 6baf2f3631d..08054315334 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -30,6 +30,7 @@ #include <limits.h> #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -51,6 +52,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_texture.h" #include "smoke_API.h" @@ -354,6 +356,17 @@ static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value) rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name)); } +static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value) +{ + SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; + + sds->use_coba = value; + + if (value && sds->coba == NULL) { + sds->coba = add_colorband(false); + } +} + #else static void rna_def_smoke_domain_settings(BlenderRNA *brna) @@ -744,6 +757,41 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3); RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + /* --------- Color mapping. --------- */ + + prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set"); + RNA_def_property_ui_text(prop, "Use Color Ramp", + "Render a simulation field while mapping its voxels values to the colors of a ramp"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + static EnumPropertyItem coba_field_items[] = { + {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"}, + {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"}, + {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"}, + {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"}, + {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"}, + {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"}, + {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"}, + {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"}, + {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"}, + {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "coba_field"); + RNA_def_property_enum_items(prop, coba_field_items); + RNA_def_property_ui_text(prop, "Field", "Simulation field to color map"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "coba"); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); } static void rna_def_smoke_flow_settings(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 355ac9563dd..d25e8e38de3 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -65,6 +65,7 @@ static void copyData(ModifierData *md, ModifierData *target) if (tmcmd->cache_file) { id_us_plus(&tmcmd->cache_file->id); + tmcmd->reader = NULL; } } @@ -75,6 +76,12 @@ static void freeData(ModifierData *md) if (mcmd->cache_file) { id_us_min(&mcmd->cache_file->id); } + + if (mcmd->reader) { +#ifdef WITH_ALEMBIC + CacheReader_free(mcmd->reader); +#endif + } } static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) @@ -102,10 +109,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, BKE_cachefile_ensure_handle(G.main, cache_file); - DerivedMesh *result = ABC_read_mesh(cache_file->handle, + if (!mcmd->reader) { + mcmd->reader = CacheReader_open_alembic_object(cache_file->handle, + mcmd->reader, + ob, + mcmd->object_path); + } + + DerivedMesh *result = ABC_read_mesh(mcmd->reader, ob, dm, - mcmd->object_path, time, &err_str, mcmd->read_flag); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c index bb7f2166a8a..0be47c4f751 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c @@ -36,6 +36,7 @@ static bNodeSocketTemplate sh_node_tex_brick_in[] = { { SOCK_RGBA, 1, N_("Mortar"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Mortar Size"), 0.02f, 0.0f, 0.0f, 0.0f, 0.0f, 0.125f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, + { SOCK_FLOAT, 1, N_("Mortar Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Bias"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Brick Width"), 0.5f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Row Height"), 0.25f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, @@ -60,6 +61,12 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node) tex->squash_freq = 2; node->storage = tex; + + for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) { + if (STREQ(sock->name, "Mortar Smooth")) { + ((bNodeSocketValueFloat*)sock->default_value)->value = 0.1f; + } + } } static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp index d79cf7d8c31..5cc1231e6cb 100644 --- a/source/blender/physics/intern/hair_volume.cpp +++ b/source/blender/physics/intern/hair_volume.cpp @@ -710,7 +710,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target * div(grad(p)) = div(v) * * The finite difference approximation yields the linear equation system described here: - * http://en.wikipedia.org/wiki/Discrete_Poisson_equation + * https://en.wikipedia.org/wiki/Discrete_Poisson_equation */ lMatrix A(num_cellsA, num_cellsA); /* Reserve space for the base equation system (without boundary conditions). @@ -888,7 +888,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target #if 0 /* XXX weighting is incorrect, disabled for now */ /* Velocity filter kernel - * See http://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29 + * See https://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29 */ BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float invD, const int kernel_size[3], int i, int j, int k) diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index ec69abbb1df..15f3c665fcf 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -33,6 +33,7 @@ #include <stddef.h> #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_string.h" #include "BLI_linklist.h" #include "BLI_path_util.h" @@ -405,6 +406,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BLO_blendhandle_close(self->blo_handle); self->blo_handle = NULL; + GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__); + /* copied from wm_operator.c */ { /* mark all library linked objects to be updated */ @@ -412,7 +415,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* append, rather than linking */ if ((self->flag & FILE_LINK) == 0) { - BKE_library_make_local(bmain, lib, true, false); + BKE_library_make_local(bmain, lib, old_to_new_ids, true, false); } } @@ -439,6 +442,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) ID *id; id = PyCapsule_GetPointer(item, NULL); + id = BLI_ghash_lookup_default(old_to_new_ids, id, id); Py_DECREF(item); RNA_id_pointer_create(id, &id_ptr); @@ -452,6 +456,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) } #endif /* USE_RNA_DATABLOCKS */ + BLI_ghash_free(old_to_new_ids, NULL, NULL); Py_RETURN_NONE; } } diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 71288871104..4e980e4c0e6 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1394,7 +1394,7 @@ PyDoc_STRVAR(Matrix_invert_doc, " (instead of raising a :exc:`ValueError` exception).\n" " :type fallback: :class:`Matrix`\n" "\n" -" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n" +" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n" ); static PyObject *Matrix_invert(MatrixObject *self, PyObject *args) { @@ -1505,7 +1505,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc, " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n" " If tweaked matrix is still degenerated, set to the identity matrix instead.\n" "\n" -" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n" +" .. seealso:: <https://en.wikipedia.org/wiki/Inverse_matrix>\n" ); static PyObject *Matrix_invert_safe(MatrixObject *self) { @@ -1556,7 +1556,7 @@ PyDoc_STRVAR(Matrix_adjugate_doc, "\n" " .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n" "\n" -" .. seealso:: <http://en.wikipedia.org/wiki/Adjugate_matrix>\n" +" .. seealso:: <https://en.wikipedia.org/wiki/Adjugate_matrix>\n" ); static PyObject *Matrix_adjugate(MatrixObject *self) { @@ -1733,7 +1733,7 @@ PyDoc_STRVAR(Matrix_determinant_doc, " :return: Return the determinant of a matrix.\n" " :rtype: float\n" "\n" -" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n" +" .. seealso:: <https://en.wikipedia.org/wiki/Determinant>\n" ); static PyObject *Matrix_determinant(MatrixObject *self) { @@ -1755,7 +1755,7 @@ PyDoc_STRVAR(Matrix_transpose_doc, "\n" " Set the matrix to its transpose.\n" "\n" -" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n" +" .. seealso:: <https://en.wikipedia.org/wiki/Transpose>\n" ); static PyObject *Matrix_transpose(MatrixObject *self) { @@ -1890,7 +1890,7 @@ PyDoc_STRVAR(Matrix_identity_doc, " .. note:: An object with zero location and rotation, a scale of one,\n" " will have an identity matrix.\n" "\n" -" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n" +" .. seealso:: <https://en.wikipedia.org/wiki/Identity_matrix>\n" ); static PyObject *Matrix_identity(MatrixObject *self) { diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index e872ec1a524..3b733f9558c 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -419,7 +419,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive"); if (use_recursive) { - BKE_library_make_local(bmain, NULL, true, set_fake); + BKE_library_make_local(bmain, NULL, NULL, true, set_fake); } else { LinkNode *itemlink; @@ -430,7 +430,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id; if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) { - BKE_library_make_local(bmain, new_id->lib, true, set_fake); + BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake); BLI_gset_insert(done_libraries, new_id->lib); } } diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 1357729e898..46203333eb5 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -37,6 +37,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -272,7 +273,7 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt) unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__); struct LassoFillData lasso_fill_data = {pixel_buf, w}; - fill_poly_v2i_n( + BLI_bitmap_draw_2d_poly_v2i_n( rect.xmin, rect.ymin, rect.xmax, rect.ymax, (const int (*)[2])moves, tot, draw_filled_lasso_px_cb, &lasso_fill_data); |