diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
111 files changed, 7101 insertions, 7023 deletions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index d76a4d8f859..98deddb4316 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -32,13 +32,6 @@ #include "CCGSubSurf.h" #include "CCGSubSurf_intern.h" -#ifdef WITH_OPENSUBDIV -# include "opensubdiv_capi.h" -# include "opensubdiv_converter_capi.h" -# include "opensubdiv_evaluator_capi.h" -# include "opensubdiv_topology_refiner_capi.h" -#endif - #include "GPU_glew.h" /***/ @@ -305,21 +298,6 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, ss->tempVerts = NULL; ss->tempEdges = NULL; -#ifdef WITH_OPENSUBDIV - ss->osd_evaluator = NULL; - ss->osd_mesh = NULL; - ss->osd_topology_refiner = NULL; - ss->osd_mesh_invalid = false; - ss->osd_coarse_coords_invalid = false; - ss->osd_vao = 0; - ss->skip_grids = false; - ss->osd_compute = 0; - ss->osd_next_face_ptex_index = 0; - ss->osd_coarse_coords = NULL; - ss->osd_num_coarse_coords = 0; - ss->osd_subdiv_uvs = false; -#endif - return ss; } } @@ -328,23 +306,6 @@ void ccgSubSurf_free(CCGSubSurf *ss) { CCGAllocatorIFC allocatorIFC = ss->allocatorIFC; CCGAllocatorHDL allocator = ss->allocator; -#ifdef WITH_OPENSUBDIV - if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluator(ss->osd_evaluator); - } - if (ss->osd_mesh != NULL) { - ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); - } - if (ss->osd_vao != 0) { - ccgSubSurf__delete_vertex_array(ss->osd_vao); - } - if (ss->osd_coarse_coords != NULL) { - MEM_freeN(ss->osd_coarse_coords); - } - if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); - } -#endif if (ss->syncState) { ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_free, ss); @@ -529,9 +490,6 @@ CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges"); ss->syncState = eSyncState_Vert; -#ifdef WITH_OPENSUBDIV - ss->osd_next_face_ptex_index = 0; -#endif return eCCGError_None; } @@ -671,9 +629,6 @@ CCGError ccgSubSurf_syncVert( ccg_ehash_insert(ss->vMap, (EHEntry *)v); v->flags = 0; } -#ifdef WITH_OPENSUBDIV - v->osd_index = ss->vMap->numEntries - 1; -#endif } if (v_r) { @@ -874,15 +829,6 @@ CCGError ccgSubSurf_syncFace( } } } -#ifdef WITH_OPENSUBDIV - f->osd_index = ss->osd_next_face_ptex_index; - if (numVerts == 4) { - ss->osd_next_face_ptex_index++; - } - else { - ss->osd_next_face_ptex_index += numVerts; - } -#endif } if (f_r) { @@ -893,15 +839,7 @@ CCGError ccgSubSurf_syncFace( static void ccgSubSurf__sync(CCGSubSurf *ss) { -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - ccgSubSurf__sync_opensubdiv(ss); - } - else -#endif - { - ccgSubSurf__sync_legacy(ss); - } + ccgSubSurf__sync_legacy(ss); } CCGError ccgSubSurf_processSync(CCGSubSurf *ss) @@ -1615,12 +1553,6 @@ int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss) ss->fMap->numEntries + ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2)))); -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - return 0; - } -#endif - return numFinalVerts; } int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss) @@ -1629,22 +1561,12 @@ int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss) int gridSize = ccg_gridsize(ss->subdivLevels); int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) + ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1)))); -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - return 0; - } -#endif return numFinalEdges; } int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss) { int gridSize = ccg_gridsize(ss->subdivLevels); int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1)); -#ifdef WITH_OPENSUBDIV - if (ss->skip_grids) { - return 0; - } -#endif return numFinalFaces; } diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index 83b59941ac7..2e5100db6de 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -211,57 +211,4 @@ CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi); int ccgFaceIterator_isStopped(CCGFaceIterator *fi); void ccgFaceIterator_next(CCGFaceIterator *fi); -#ifdef WITH_OPENSUBDIV -struct DerivedMesh; - -/* Check if topology changed and evaluators are to be re-created. */ -void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm); - -/* Create topology refiner from give derived mesh which then later will be - * used for GL mesh creation. - */ -void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm); - -/* Make sure GL mesh exists, up to date and ready to draw. */ -bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index); - -/* Draw given partitions of the GL mesh. - * - * TODO(sergey): fill_quads is actually an invariant and should be part - * of the prepare routine. - */ -void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, - bool fill_quads, - int start_partition, - int num_partitions); - -/* Get number of base faces in a particular GL mesh. */ -int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss); - -/* Get number of vertices in base faces in a particular GL mesh. */ -int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face); - -/* Controls whether CCG are needed (Cmeaning CPU evaluation) or fully GPU compute - * and draw is allowed. - */ -void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids); -bool ccgSubSurf_needGrids(CCGSubSurf *ss); - -/* Set evaluator's face varying data from UV coordinates. - * Used for CPU evaluation. - */ -void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, struct DerivedMesh *dm, int layer_index); - -/* TODO(sergey): Temporary call to test things. */ -void ccgSubSurf_evaluatorFVarUV( - CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2]); - -void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss); - -void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]); - -void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs); - -#endif - #endif /* __CCGSUBSURF_H__ */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h index 51486db1bdc..7c35d2ccfce 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -157,9 +157,6 @@ typedef enum { eSyncState_Edge, eSyncState_Face, eSyncState_Partial, -#ifdef WITH_OPENSUBDIV - eSyncState_OpenSubdiv, -#endif } SyncState; struct CCGSubSurf { @@ -202,58 +199,6 @@ struct CCGSubSurf { int lenTempArrays; CCGVert **tempVerts; CCGEdge **tempEdges; - -#ifdef WITH_OPENSUBDIV - /* Skip grids means no CCG geometry is created and subsurf is possible - * to be completely done on GPU. - */ - bool skip_grids; - - /* ** GPU backend. ** */ - - /* Compute device used by GL mesh. */ - short osd_compute; - /* Coarse (base mesh) vertex coordinates. - * - * Filled in from the modifier stack and passed to OpenSubdiv compute - * on mesh display. - */ - float (*osd_coarse_coords)[3]; - int osd_num_coarse_coords; - /* Denotes whether coarse positions in the GL mesh are invalid. - * Used to avoid updating GL mesh coords on every redraw. - */ - bool osd_coarse_coords_invalid; - - /* GL mesh descriptor, used for refinement and draw. */ - struct OpenSubdiv_GLMesh *osd_mesh; - /* Refiner which is used to create GL mesh. - * - * Refiner is created from the modifier stack and used later from the main - * thread to construct GL mesh to avoid threaded access to GL. - */ - struct OpenSubdiv_TopologyRefiner - *osd_topology_refiner; /* Only used at synchronization stage. */ - /* Denotes whether osd_mesh is invalid now due to topology changes and needs - * to be reconstructed. - * - * Reconstruction happens from main thread due to OpenGL communication. - */ - bool osd_mesh_invalid; - /* Vertex array used for osd_mesh draw. */ - unsigned int osd_vao; - - /* ** CPU backend. ** */ - - /* Limit evaluator, used to evaluate CCG. */ - struct OpenSubdiv_Evaluator *osd_evaluator; - /* Next PTex face index, used while CCG synchronization - * to fill in PTex index of CCGFace. - */ - int osd_next_face_ptex_index; - - bool osd_subdiv_uvs; -#endif }; /* ** Utility macros ** */ @@ -322,16 +267,6 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss); void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss); -/* Delayed free routines. Will do actual free if called from - * main thread and schedule free for later free otherwise. - */ - -#ifdef WITH_OPENSUBDIV -void ccgSubSurf__delete_osdGLMesh(struct OpenSubdiv_GLMesh *osd_mesh); -void ccgSubSurf__delete_vertex_array(unsigned int vao); -void ccgSubSurf__delete_pending(void); -#endif - /* * CCGSubSurf_opensubdiv_converter.c * */ struct OpenSubdiv_Converter; diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c deleted file mode 100644 index 3257dd2334c..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ /dev/null @@ -1,970 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup bke - */ - -#ifdef WITH_OPENSUBDIV - -# include "BLI_sys_types.h" // for intptr_t support -# include "MEM_guardedalloc.h" - -# include "BLI_listbase.h" -# include "BLI_math.h" -# include "BLI_threads.h" -# include "BLI_utildefines.h" /* for BLI_assert */ - -# include "CCGSubSurf.h" -# include "CCGSubSurf_intern.h" - -# include "BKE_DerivedMesh.h" -# include "BKE_subsurf.h" - -# include "DNA_userdef_types.h" - -# include "opensubdiv_capi.h" -# include "opensubdiv_converter_capi.h" -# include "opensubdiv_evaluator_capi.h" -# include "opensubdiv_gl_mesh_capi.h" -# include "opensubdiv_topology_refiner_capi.h" - -# include "GPU_extensions.h" -# include "GPU_glew.h" - -# define OSD_LOG \ - if (false) \ - printf - -static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) -{ - const int num_verts = dm->getNumVerts(dm); - const int num_edges = dm->getNumEdges(dm); - const int num_polys = dm->getNumPolys(dm); - const MEdge *medge = dm->getEdgeArray(dm); - const MLoop *mloop = dm->getLoopArray(dm); - const MPoly *mpoly = dm->getPolyArray(dm); - - /* Quick preliminary tests based on the number of verts and facces. */ - { - if (num_verts != ss->vMap->numEntries || num_edges != ss->eMap->numEntries || - num_polys != ss->fMap->numEntries) { - return false; - } - } - - /* Rather slow check for faces topology change. */ - { - CCGFaceIterator ccg_face_iter; - for (ccgSubSurf_initFaceIterator(ss, &ccg_face_iter); - !ccgFaceIterator_isStopped(&ccg_face_iter); - ccgFaceIterator_next(&ccg_face_iter)) { - /*const*/ CCGFace *ccg_face = ccgFaceIterator_getCurrent(&ccg_face_iter); - const int poly_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face)); - const MPoly *mp = &mpoly[poly_index]; - int corner; - if (ccg_face->numVerts != mp->totloop) { - return false; - } - for (corner = 0; corner < ccg_face->numVerts; corner++) { - /*const*/ CCGVert *ccg_vert = FACE_getVerts(ccg_face)[corner]; - const int vert_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert)); - if (vert_index != mloop[mp->loopstart + corner].v) { - return false; - } - } - } - } - - /* Check for edge topology change. */ - { - CCGEdgeIterator ccg_edge_iter; - for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter); - !ccgEdgeIterator_isStopped(&ccg_edge_iter); - ccgEdgeIterator_next(&ccg_edge_iter)) { - /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter); - /* const */ CCGVert *ccg_vert1 = ccg_edge->v0; - /* const */ CCGVert *ccg_vert2 = ccg_edge->v1; - const int ccg_vert1_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1)); - const int ccg_vert2_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert2)); - const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - const MEdge *me = &medge[edge_index]; - if (me->v1 != ccg_vert1_index || me->v2 != ccg_vert2_index) { - return false; - } - } - } - - /* TODO(sergey): Crease topology changes detection. */ - { - CCGEdgeIterator ccg_edge_iter; - for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter); - !ccgEdgeIterator_isStopped(&ccg_edge_iter); - ccgEdgeIterator_next(&ccg_edge_iter)) { - /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter); - const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - if (ccg_edge->crease != medge[edge_index].crease) { - return false; - } - } - } - - return true; -} - -static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) -{ - OpenSubdiv_Converter converter; - bool result; - if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) { - return true; - } - /* TODO(sergey): De-duplicate with topology counter at the bottom of - * the file. - */ - ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); - result = openSubdiv_topologyRefinerCompareWithConverter(ss->osd_topology_refiner, &converter); - ccgSubSurf_converter_free(&converter); - return result; -} - -static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm) -{ - if (ss->osd_compute != U.opensubdiv_compute_type) { - return true; - } - if (ss->osd_topology_refiner != NULL) { - const int levels = ss->osd_topology_refiner->getSubdivisionLevel(ss->osd_topology_refiner); - BLI_assert(ss->osd_mesh_invalid == true); - if (levels != ss->subdivLevels) { - return true; - } - } - if (ss->skip_grids == false) { - return compare_ccg_derivedmesh_topology(ss, dm) == false; - } - else { - return compare_osd_derivedmesh_topology(ss, dm) == false; - } - return false; -} - -void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm) -{ - if (opensubdiv_is_topology_changed(ss, dm)) { - /* ** Make sure both GPU and CPU backends are properly reset. ** */ - - ss->osd_coarse_coords_invalid = true; - - /* Reset GPU part. */ - ss->osd_mesh_invalid = true; - if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); - ss->osd_topology_refiner = NULL; - } - - /* Reset CPU side. */ - if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluator(ss->osd_evaluator); - ss->osd_evaluator = NULL; - } - } -} - -static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss) -{ - BLI_assert(ss->meshIFC.numLayers == 3); - ss->osd_mesh->setCoarsePositions( - ss->osd_mesh, (float *)ss->osd_coarse_coords, 0, ss->osd_num_coarse_coords); -} - -bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index) -{ - int compute_type; - - switch (U.opensubdiv_compute_type) { -# define CHECK_COMPUTE_TYPE(type) \ - case USER_OPENSUBDIV_COMPUTE_##type: \ - compute_type = OPENSUBDIV_EVALUATOR_##type; \ - break; - CHECK_COMPUTE_TYPE(CPU) - CHECK_COMPUTE_TYPE(OPENMP) - CHECK_COMPUTE_TYPE(OPENCL) - CHECK_COMPUTE_TYPE(CUDA) - CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK) - CHECK_COMPUTE_TYPE(GLSL_COMPUTE) - default: - compute_type = OPENSUBDIV_EVALUATOR_CPU; - break; -# undef CHECK_COMPUTE_TYPE - } - - if (ss->osd_vao == 0) { - glGenVertexArrays(1, &ss->osd_vao); - } - - if (ss->osd_mesh_invalid) { - if (ss->osd_mesh != NULL) { - ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); - ss->osd_mesh = NULL; - } - ss->osd_mesh_invalid = false; - } - - if (ss->osd_mesh == NULL) { - if (ss->osd_topology_refiner == NULL) { - /* Happens with empty meshes. */ - /* TODO(sergey): Add assert that mesh is indeed empty. */ - return false; - } - - ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(ss->osd_topology_refiner, - compute_type); - - if (UNLIKELY(ss->osd_mesh == NULL)) { - /* Most likely compute device is not available. */ - return false; - } - - ccgSubSurf__updateGLMeshCoords(ss); - ss->osd_mesh->refine(ss->osd_mesh); - ss->osd_mesh->synchronize(ss->osd_mesh); - ss->osd_coarse_coords_invalid = false; - - glBindVertexArray(ss->osd_vao); - ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)12); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - else if (ss->osd_coarse_coords_invalid) { - ccgSubSurf__updateGLMeshCoords(ss); - ss->osd_mesh->refine(ss->osd_mesh); - ss->osd_mesh->synchronize(ss->osd_mesh); - ss->osd_coarse_coords_invalid = false; - } - - ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index); - - return true; -} - -void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, - bool fill_quads, - int start_partition, - int num_partitions) -{ - if (LIKELY(ss->osd_mesh != NULL)) { - glBindVertexArray(ss->osd_vao); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh)); - - ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); - glBindVertexArray(ss->osd_vao); - ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, start_partition, num_partitions); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } -} - -int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss) -{ - if (ss->osd_topology_refiner != NULL) { - return ss->osd_topology_refiner->getNumFaces(ss->osd_topology_refiner); - } - return 0; -} - -/* Get number of vertices in base faces in a particular GL mesh. */ -int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face) -{ - if (ss->osd_topology_refiner != NULL) { - return ss->osd_topology_refiner->getNumFaceVertices(ss->osd_topology_refiner, face); - } - return 0; -} - -void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids) -{ - ss->skip_grids = skip_grids; -} - -bool ccgSubSurf_needGrids(CCGSubSurf *ss) -{ - return ss->skip_grids == false; -} - -BLI_INLINE void ccgSubSurf__mapGridToFace( - int S, float grid_u, float grid_v, float *face_u, float *face_v) -{ - float u, v; - - /* - Each grid covers half of the face along the edges. - * - Grid's (0, 0) starts from the middle of the face. - */ - u = 0.5f - 0.5f * grid_u; - v = 0.5f - 0.5f * grid_v; - - if (S == 0) { - *face_u = v; - *face_v = u; - } - else if (S == 1) { - *face_u = 1.0f - u; - *face_v = v; - } - else if (S == 2) { - *face_u = 1.0f - v; - *face_v = 1.0f - u; - } - else { - *face_u = u; - *face_v = 1.0f - v; - } -} - -BLI_INLINE void ccgSubSurf__mapEdgeToFace( - int S, int edge_segment, bool inverse_edge, int edgeSize, float *face_u, float *face_v) -{ - int t = inverse_edge ? edgeSize - edge_segment - 1 : edge_segment; - if (S == 0) { - *face_u = (float)t / (edgeSize - 1); - *face_v = 0.0f; - } - else if (S == 1) { - *face_u = 1.0f; - *face_v = (float)t / (edgeSize - 1); - } - else if (S == 2) { - *face_u = 1.0f - (float)t / (edgeSize - 1); - *face_v = 1.0f; - } - else { - *face_u = 0.0f; - *face_v = 1.0f - (float)t / (edgeSize - 1); - } -} - -void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, DerivedMesh *dm, int layer_index) -{ - MPoly *mpoly = dm->getPolyArray(dm); - MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index); - int num_polys = dm->getNumPolys(dm); - int index, poly; - BLI_assert(ss->osd_evaluator != NULL); - for (poly = 0, index = 0; poly < num_polys; poly++) { - int loop; - MPoly *mp = &mpoly[poly]; - for (loop = 0; loop < mp->totloop; loop++, index++) { - MLoopUV *mluv = &mloopuv[loop + mp->loopstart]; - (void)mluv; - /* TODO(sergey): Send mluv->uv to the evaluator's face varying - * buffer. - */ - } - } - (void)ss; -} - -void ccgSubSurf_evaluatorFVarUV( - CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2]) -{ - float face_u, face_v; - ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v); - (void)ss; - (void)face_index; - /* TODO(sergey): Evaluate face varying coordinate. */ - zero_v2(uv); -} - -static bool opensubdiv_createEvaluator(CCGSubSurf *ss) -{ - OpenSubdiv_Converter converter; - OpenSubdiv_TopologyRefiner *topology_refiner; - if (ss->fMap->numEntries == 0) { - /* OpenSubdiv doesn't support meshes without faces. */ - return false; - } - ccgSubSurf_converter_setup_from_ccg(ss, &converter); - OpenSubdiv_TopologyRefinerSettings settings; - settings.level = ss->subdivLevels; - settings.is_adaptive = false; - topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, &settings); - ccgSubSurf_converter_free(&converter); - ss->osd_evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner); - if (ss->osd_evaluator == NULL) { - BLI_assert(!"OpenSubdiv initialization failed, should not happen."); - return false; - } - return true; -} - -static bool opensubdiv_ensureEvaluator(CCGSubSurf *ss) -{ - if (ss->osd_evaluator == NULL) { - OSD_LOG("Allocating new evaluator, %d verts\n", ss->vMap->numEntries); - opensubdiv_createEvaluator(ss); - } - return ss->osd_evaluator != NULL; -} - -static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss) -{ - float(*positions)[3]; - int vertDataSize = ss->meshIFC.vertDataSize; - int num_basis_verts = ss->vMap->numEntries; - int i; - - /* TODO(sergey): Avoid allocation on every update. We could either update - * coordinates in chunks of 1K vertices (which will only use stack memory) - * or do some callback magic for OSD evaluator can invoke it and fill in - * buffer directly. - */ - if (ss->meshIFC.numLayers == 3) { - /* If all the components are to be initialized, no need to memset the - * new memory block. - */ - positions = MEM_mallocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points"); - } - else { - /* Calloc in order to have z component initialized to 0 for Uvs */ - positions = MEM_callocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points"); - } -# pragma omp parallel for - for (i = 0; i < ss->vMap->curSize; i++) { - CCGVert *v = (CCGVert *)ss->vMap->buckets[i]; - for (; v; v = v->next) { - float *co = VERT_getCo(v, 0); - BLI_assert(v->osd_index < ss->vMap->numEntries); - VertDataCopy(positions[v->osd_index], co, ss); - OSD_LOG("Point %d has value %f %f %f\n", - v->osd_index, - positions[v->osd_index][0], - positions[v->osd_index][1], - positions[v->osd_index][2]); - } - } - - ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, (float *)positions, 0, num_basis_verts); - ss->osd_evaluator->refine(ss->osd_evaluator); - - MEM_freeN(positions); -} - -static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss, - CCGFace *face, - const int osd_face_index) -{ - int normalDataOffset = ss->normalDataOffset; - int subdivLevels = ss->subdivLevels; - int gridSize = ccg_gridsize(subdivLevels); - int edgeSize = ccg_edgesize(subdivLevels); - int vertDataSize = ss->meshIFC.vertDataSize; - int S; - bool do_normals = ss->meshIFC.numLayers == 3; - -# pragma omp parallel for - for (S = 0; S < face->numVerts; S++) { - int x, y, k; - CCGEdge *edge = NULL; - bool inverse_edge = false; - - for (x = 0; x < gridSize; x++) { - for (y = 0; y < gridSize; y++) { - float *co = FACE_getIFCo(face, subdivLevels, S, x, y); - float *no = FACE_getIFNo(face, subdivLevels, S, x, y); - float grid_u = (float)x / (gridSize - 1), grid_v = (float)y / (gridSize - 1); - float face_u, face_v; - float P[3], dPdu[3], dPdv[3]; - - ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v); - - /* TODO(sergey): Need proper port. */ - ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, - osd_face_index, - face_u, - face_v, - P, - do_normals ? dPdu : NULL, - do_normals ? dPdv : NULL); - - OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n", - osd_face_index, - S, - grid_u, - grid_v, - face_u, - face_v, - P[0], - P[1], - P[2]); - - VertDataCopy(co, P, ss); - if (do_normals) { - cross_v3_v3v3(no, dPdu, dPdv); - normalize_v3(no); - } - - if (x == gridSize - 1 && y == gridSize - 1) { - float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_co, co, ss); - if (do_normals) { - float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_no, no, ss); - } - } - if (S == 0 && x == 0 && y == 0) { - float *center_co = (float *)FACE_getCenterData(face); - VertDataCopy(center_co, co, ss); - if (do_normals) { - float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset); - VertDataCopy(center_no, no, ss); - } - } - } - } - - for (x = 0; x < gridSize; x++) { - VertDataCopy( - FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss); - if (do_normals) { - VertDataCopy( - FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss); - } - } - - for (k = 0; k < face->numVerts; k++) { - CCGEdge *current_edge = FACE_getEdges(face)[k]; - CCGVert **face_verts = FACE_getVerts(face); - if (current_edge->v0 == face_verts[S] && - current_edge->v1 == face_verts[(S + 1) % face->numVerts]) { - edge = current_edge; - inverse_edge = false; - break; - } - if (current_edge->v1 == face_verts[S] && - current_edge->v0 == face_verts[(S + 1) % face->numVerts]) { - edge = current_edge; - inverse_edge = true; - break; - } - } - - BLI_assert(edge != NULL); - - for (x = 0; x < edgeSize; x++) { - float u = 0, v = 0; - float *co = EDGE_getCo(edge, subdivLevels, x); - float *no = EDGE_getNo(edge, subdivLevels, x); - float P[3], dPdu[3], dPdv[3]; - ccgSubSurf__mapEdgeToFace(S, x, inverse_edge, edgeSize, &u, &v); - - /* TODO(sergey): Ideally we will re-use grid here, but for now - * let's just re-evaluate for simplicity. - */ - /* TODO(sergey): Need proper port. */ - ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv); - VertDataCopy(co, P, ss); - if (do_normals) { - cross_v3_v3v3(no, dPdu, dPdv); - normalize_v3(no); - } - } - } -} - -static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss, - CCGFace *face, - const int osd_face_index) -{ - CCGVert **all_verts = FACE_getVerts(face); - int normalDataOffset = ss->normalDataOffset; - int subdivLevels = ss->subdivLevels; - int gridSize = ccg_gridsize(subdivLevels); - int edgeSize = ccg_edgesize(subdivLevels); - int vertDataSize = ss->meshIFC.vertDataSize; - int S; - bool do_normals = ss->meshIFC.numLayers == 3; - - /* Note about handling non-quad faces. - * - * In order to deal with non-quad faces we need to split them - * into a quads in the following way: - * - * | - * (vert_next) - * | - * | - * | - * (face_center) ------------------- (v2) - * | (o)--------------------> | - * | | v | - * | | | - * | | | - * | | | - * | | y ^ | - * | | | | - * | v u x | | - * | <---(o) | - * ---- (vert_prev) ---- (v1) -------------------- (vert) - * - * This is how grids are expected to be stored and it's how - * OpenSubdiv deals with non-quad faces using ptex face indices. - * We only need to convert ptex (x, y) to grid (u, v) by some - * simple flips and evaluate the ptex face. - */ - - /* Evaluate face grids. */ -# pragma omp parallel for - for (S = 0; S < face->numVerts; S++) { - int x, y; - for (x = 0; x < gridSize; x++) { - for (y = 0; y < gridSize; y++) { - float *co = FACE_getIFCo(face, subdivLevels, S, x, y); - float *no = FACE_getIFNo(face, subdivLevels, S, x, y); - float u = 1.0f - (float)y / (gridSize - 1), v = 1.0f - (float)x / (gridSize - 1); - float P[3], dPdu[3], dPdv[3]; - - /* TODO(sergey): Need proper port. */ - ss->osd_evaluator->evaluateLimit( - ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv); - - OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n", - osd_face_index + S, - S, - u, - v, - P[0], - P[1], - P[2]); - - VertDataCopy(co, P, ss); - if (do_normals) { - cross_v3_v3v3(no, dPdu, dPdv); - normalize_v3(no); - } - - /* TODO(sergey): De-dpuplicate with the quad case. */ - if (x == gridSize - 1 && y == gridSize - 1) { - float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_co, co, ss); - if (do_normals) { - float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels); - VertDataCopy(vert_no, no, ss); - } - } - if (S == 0 && x == 0 && y == 0) { - float *center_co = (float *)FACE_getCenterData(face); - VertDataCopy(center_co, co, ss); - if (do_normals) { - float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset); - VertDataCopy(center_no, no, ss); - } - } - } - } - for (x = 0; x < gridSize; x++) { - VertDataCopy( - FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss); - if (do_normals) { - VertDataCopy( - FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss); - } - } - } - - /* Evaluate edges. */ - for (S = 0; S < face->numVerts; S++) { - CCGEdge *edge = FACE_getEdges(face)[S]; - int x, S0 = 0, S1 = 0; - bool flip; - - for (x = 0; x < face->numVerts; x++) { - if (all_verts[x] == edge->v0) { - S0 = x; - } - else if (all_verts[x] == edge->v1) { - S1 = x; - } - } - if (S == face->numVerts - 1) { - flip = S0 > S1; - } - else { - flip = S0 < S1; - } - - for (x = 0; x <= edgeSize / 2; x++) { - float *edge_co = EDGE_getCo(edge, subdivLevels, x); - float *edge_no = EDGE_getNo(edge, subdivLevels, x); - float *face_edge_co; - float *face_edge_no; - if (flip) { - face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x); - face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x); - } - else { - face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1); - face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1); - } - VertDataCopy(edge_co, face_edge_co, ss); - if (do_normals) { - VertDataCopy(edge_no, face_edge_no, ss); - } - } - for (x = edgeSize / 2 + 1; x < edgeSize; x++) { - float *edge_co = EDGE_getCo(edge, subdivLevels, x); - float *edge_no = EDGE_getNo(edge, subdivLevels, x); - float *face_edge_co; - float *face_edge_no; - if (flip) { - face_edge_co = FACE_getIFCo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1); - face_edge_no = FACE_getIFNo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1); - } - else { - face_edge_co = FACE_getIFCo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2); - face_edge_no = FACE_getIFNo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2); - } - VertDataCopy(edge_co, face_edge_co, ss); - if (do_normals) { - VertDataCopy(edge_no, face_edge_no, ss); - } - } - } -} - -static void opensubdiv_evaluateGrids(CCGSubSurf *ss) -{ - int i; - for (i = 0; i < ss->fMap->curSize; i++) { - CCGFace *face = (CCGFace *)ss->fMap->buckets[i]; - for (; face; face = face->next) { - if (face->numVerts == 4) { - /* For quads we do special magic with converting face coords - * into corner coords and interpolating grids from it. - */ - opensubdiv_evaluateQuadFaceGrids(ss, face, face->osd_index); - } - else { - /* NGons and tris are split into separate osd faces which - * evaluates onto grids directly. - */ - opensubdiv_evaluateNGonFaceGrids(ss, face, face->osd_index); - } - } - } -} - -CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss) -{ - if (ss->syncState != eSyncState_None) { - return eCCGError_InvalidSyncState; - } - ss->syncState = eSyncState_OpenSubdiv; - return eCCGError_None; -} - -void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm) -{ - if (ss->osd_mesh == NULL || ss->osd_mesh_invalid) { - if (dm->getNumPolys(dm) != 0) { - OpenSubdiv_Converter converter; - ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); - /* TODO(sergey): Remove possibly previously allocated refiner. */ - OpenSubdiv_TopologyRefinerSettings settings; - settings.level = ss->subdivLevels; - settings.is_adaptive = false; - ss->osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, - &settings); - ccgSubSurf_converter_free(&converter); - } - } - - /* Update number of grids, needed for things like final faces - * counter, used by display drawing. - */ - { - const int num_polys = dm->getNumPolys(dm); - const MPoly *mpoly = dm->getPolyArray(dm); - int poly; - ss->numGrids = 0; - for (poly = 0; poly < num_polys; poly++) { - ss->numGrids += mpoly[poly].totloop; - } - } - - { - const int num_verts = dm->getNumVerts(dm); - const MVert *mvert = dm->getVertArray(dm); - int vert; - if (ss->osd_coarse_coords != NULL && num_verts != ss->osd_num_coarse_coords) { - MEM_freeN(ss->osd_coarse_coords); - ss->osd_coarse_coords = NULL; - } - if (ss->osd_coarse_coords == NULL) { - ss->osd_coarse_coords = MEM_mallocN(sizeof(float) * 6 * num_verts, "osd coarse positions"); - } - for (vert = 0; vert < num_verts; vert++) { - copy_v3_v3(ss->osd_coarse_coords[vert * 2 + 0], mvert[vert].co); - normal_short_to_float_v3(ss->osd_coarse_coords[vert * 2 + 1], mvert[vert].no); - } - ss->osd_num_coarse_coords = num_verts; - ss->osd_coarse_coords_invalid = true; - } -} - -void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss) -{ - BLI_assert(ss->meshIFC.numLayers == 2 || ss->meshIFC.numLayers == 3); - - /* Common synchronization steps */ - ss->osd_compute = U.opensubdiv_compute_type; - - if (ss->skip_grids == false) { - /* Make sure OSD evaluator is up-to-date. */ - if (opensubdiv_ensureEvaluator(ss)) { - /* Update coarse points in the OpenSubdiv evaluator. */ - opensubdiv_updateEvaluatorCoarsePositions(ss); - - /* Evaluate opensubdiv mesh into the CCG grids. */ - opensubdiv_evaluateGrids(ss); - } - } - else { - BLI_assert(ss->meshIFC.numLayers == 3); - } - -# ifdef DUMP_RESULT_GRIDS - ccgSubSurf__dumpCoords(ss); -# endif -} - -void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss) -{ - if (ss->osd_mesh != NULL) { - ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); - ss->osd_mesh = NULL; - } - if (ss->osd_vao != 0) { - glDeleteVertexArrays(1, &ss->osd_vao); - ss->osd_vao = 0; - } -} - -void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]) -{ - int i; - BLI_assert(ss->skip_grids == true); - if (ss->osd_num_coarse_coords == 0) { - zero_v3(r_min); - zero_v3(r_max); - } - for (i = 0; i < ss->osd_num_coarse_coords; i++) { - /* Coarse coordinates has normals interleaved into the array. */ - DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max); - } -} - -/* ** Delayed delete routines ** */ - -typedef struct OsdDeletePendingItem { - struct OsdDeletePendingItem *next, *prev; - OpenSubdiv_GLMesh *osd_mesh; - unsigned int vao; -} OsdDeletePendingItem; - -static SpinLock delete_spin; -static ListBase delete_pool = {NULL, NULL}; - -static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh, unsigned int vao) -{ - OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem), - "opensubdiv delete entry"); - new_entry->osd_mesh = osd_mesh; - new_entry->vao = vao; - BLI_spin_lock(&delete_spin); - BLI_addtail(&delete_pool, new_entry); - BLI_spin_unlock(&delete_spin); -} - -void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh) -{ - if (BLI_thread_is_main()) { - openSubdiv_deleteOsdGLMesh(osd_mesh); - } - else { - delete_pending_push(osd_mesh, 0); - } -} - -void ccgSubSurf__delete_vertex_array(unsigned int vao) -{ - if (BLI_thread_is_main()) { - glDeleteVertexArrays(1, &vao); - } - else { - delete_pending_push(NULL, vao); - } -} - -void ccgSubSurf__delete_pending(void) -{ - OsdDeletePendingItem *entry; - BLI_assert(BLI_thread_is_main()); - BLI_spin_lock(&delete_spin); - for (entry = delete_pool.first; entry != NULL; entry = entry->next) { - if (entry->osd_mesh != NULL) { - openSubdiv_deleteOsdGLMesh(entry->osd_mesh); - } - if (entry->vao != 0) { - glDeleteVertexArrays(1, &entry->vao); - } - } - BLI_freelistN(&delete_pool); - BLI_spin_unlock(&delete_spin); -} - -void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs) -{ - ss->osd_subdiv_uvs = subdiv_uvs; -} - -/* ** Public API ** */ - -void BKE_subsurf_osd_init(void) -{ - openSubdiv_init(); - BLI_spin_init(&delete_spin); -} - -void BKE_subsurf_free_unused_buffers(void) -{ - ccgSubSurf__delete_pending(); -} - -void BKE_subsurf_osd_cleanup(void) -{ - openSubdiv_cleanup(); - ccgSubSurf__delete_pending(); - BLI_spin_end(&delete_spin); -} - -#endif /* WITH_OPENSUBDIV */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c deleted file mode 100644 index 16766d52e57..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c +++ /dev/null @@ -1,777 +0,0 @@ -/* - * 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. - */ - -/** \file - * \ingroup bke - */ - -#ifdef WITH_OPENSUBDIV - -# include <stdlib.h> - -# include "BLI_sys_types.h" // for intptr_t support -# include "MEM_guardedalloc.h" - -# include "BLI_math.h" -# include "BLI_utildefines.h" /* for BLI_assert */ - -# include "CCGSubSurf.h" -# include "CCGSubSurf_intern.h" - -# include "BKE_DerivedMesh.h" -# include "BKE_mesh_mapping.h" - -# include "opensubdiv_capi.h" -# include "opensubdiv_converter_capi.h" - -/* Use mesh element mapping structures during conversion. - * Uses more memory but is much faster than naive algorithm. - */ -# define USE_MESH_ELEMENT_MAPPING - -/** - * Converter from DerivedMesh. - */ - -typedef struct ConvDMStorage { - CCGSubSurf *ss; - DerivedMesh *dm; - -# ifdef USE_MESH_ELEMENT_MAPPING - MeshElemMap *vert_edge_map, *vert_poly_map, *edge_poly_map; - int *vert_edge_mem, *vert_poly_mem, *edge_poly_mem; -# endif - - MVert *mvert; - MEdge *medge; - MLoop *mloop; - MPoly *mpoly; - - MeshIslandStore island_store; - int num_uvs; - float *uvs; - int *face_uvs; -} ConvDMStorage; - -static OpenSubdiv_SchemeType conv_dm_get_type(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - if (storage->ss->meshIFC.simpleSubdiv) { - return OSD_SCHEME_BILINEAR; - } - else { - return OSD_SCHEME_CATMARK; - } -} - -static OpenSubdiv_VtxBoundaryInterpolation conv_dm_get_vtx_boundary_interpolation( - const OpenSubdiv_Converter *UNUSED(converter)) -{ - return OSD_VTX_BOUNDARY_EDGE_ONLY; -} - -static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation( - const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - if (storage->ss->osd_subdiv_uvs) { - return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY; - } - return OSD_FVAR_LINEAR_INTERPOLATION_ALL; -} - -static bool conv_dm_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return true; -} - -static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - return dm->getNumPolys(dm); -} - -static int conv_dm_get_num_edges(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - return dm->getNumEdges(dm); -} - -static int conv_dm_get_num_verts(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - return dm->getNumVerts(dm); -} - -static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter, int face) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - return mpoly->totloop; -} - -static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter, - int face, - int *face_verts) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v; - } -} - -static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter, - int face, - int *face_edges) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e; - } -} - -static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter, - int edge, - int *edge_verts) -{ - ConvDMStorage *storage = converter->user_data; - const MEdge *medge = &storage->medge[edge]; - edge_verts[0] = medge->v1; - edge_verts[1] = medge->v2; -} - -static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &user_data->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->e == edge) { - num++; - break; - } - } - } - return num; -# else - return storage->edge_poly_map[edge].count; -# endif -} - -static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter, - int edge, - int *edge_faces) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &user_data->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->e == edge) { - edge_faces[num++] = poly; - break; - } - } - } -# else - memcpy(edge_faces, - storage->edge_poly_map[edge].indices, - sizeof(int) * storage->edge_poly_map[edge].count); -# endif -} - -static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge) -{ - ConvDMStorage *storage = converter->user_data; - CCGSubSurf *ss = storage->ss; - const MEdge *medge = storage->medge; - return (float)medge[edge].crease / 255.0f * ss->subdivLevels; -} - -static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, edge; - for (edge = 0; edge < dm->getNumEdges(dm); edge++) { - const MEdge *medge = &user_data->medge[edge]; - if (medge->v1 == vert || medge->v2 == vert) { - num++; - } - } - return num; -# else - return storage->vert_edge_map[vert].count; -# endif -} - -static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter, - int vert, - int *vert_edges) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, edge; - for (edge = 0; edge < dm->getNumEdges(dm); edge++) { - const MEdge *medge = &user_data->medge[edge]; - if (medge->v1 == vert || medge->v2 == vert) { - vert_edges[num++] = edge; - } - } -# else - memcpy(vert_edges, - storage->vert_edge_map[vert].indices, - sizeof(int) * storage->vert_edge_map[vert].count); -# endif -} - -static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &user_data->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->v == vert) { - num++; - break; - } - } - } - return num; -# else - return storage->vert_poly_map[vert].count; -# endif -} - -static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter, - int vert, - int *vert_faces) -{ - ConvDMStorage *storage = converter->user_data; -# ifndef USE_MESH_ELEMENT_MAPPING - DerivedMesh *dm = storage->dm; - int num = 0, poly; - for (poly = 0; poly < dm->getNumPolys(dm); poly++) { - const MPoly *mpoly = &storage->mpoly[poly]; - int loop; - for (loop = 0; loop < mpoly->totloop; loop++) { - const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop]; - if (mloop->v == vert) { - vert_faces[num++] = poly; - break; - } - } - } -# else - memcpy(vert_faces, - storage->vert_poly_map[vert].indices, - sizeof(int) * storage->vert_poly_map[vert].count); -# endif -} - -static bool conv_dm_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return false; -} - -static float conv_dm_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return 0.0f; -} - -static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); - return num_uv_layers; -} - -static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int layer) -{ - ConvDMStorage *storage = converter->user_data; - DerivedMesh *dm = storage->dm; - - const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer); - const int num_loops = dm->getNumLoops(dm); - - /* Initialize memory required for the operations. */ - if (storage->uvs == NULL) { - storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs"); - } - if (storage->face_uvs == NULL) { - storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs"); - } - - /* Calculate islands connectivity of the UVs. */ - BKE_mesh_calc_islands_loop_poly_uvmap(storage->mvert, - dm->getNumVerts(dm), - storage->medge, - dm->getNumEdges(dm), - storage->mpoly, - dm->getNumPolys(dm), - storage->mloop, - dm->getNumLoops(dm), - mloopuv, - &storage->island_store); - - /* Here we "weld" duplicated vertices from island to the same UV value. - * The idea here is that we need to pass individual islands to OpenSubdiv. - */ - storage->num_uvs = 0; - for (int island = 0; island < storage->island_store.islands_num; island++) { - MeshElemMap *island_poly_map = storage->island_store.islands[island]; - for (int poly = 0; poly < island_poly_map->count; poly++) { - int poly_index = island_poly_map->indices[poly]; - /* Within the same UV island we should share UV points across - * loops. Otherwise each poly will be subdivided individually - * which we don't really want. - */ - const MPoly *mpoly = &storage->mpoly[poly_index]; - for (int loop = 0; loop < mpoly->totloop; loop++) { - const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop]; - bool found = false; - /* TODO(sergey): Quite bad loop, which gives us O(N^2) - * complexity here. But how can we do it smarter, hopefully - * without requiring lots of additional memory. - */ - for (int i = 0; i < storage->num_uvs; i++) { - if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) { - storage->face_uvs[mpoly->loopstart + loop] = i; - found = true; - break; - } - } - if (!found) { - copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv); - storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs; - ++storage->num_uvs; - } - } - } - } -} - -static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - BKE_mesh_loop_islands_free(&storage->island_store); -} - -static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *storage = converter->user_data; - return storage->num_uvs; -} - -static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter, - int face, - int corner) -{ - ConvDMStorage *storage = converter->user_data; - const MPoly *mpoly = &storage->mpoly[face]; - return storage->face_uvs[mpoly->loopstart + corner]; -} - -static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter) -{ - ConvDMStorage *user_data = converter->user_data; - if (user_data->uvs != NULL) { - MEM_freeN(user_data->uvs); - } - if (user_data->face_uvs != NULL) { - MEM_freeN(user_data->face_uvs); - } - -# ifdef USE_MESH_ELEMENT_MAPPING - MEM_freeN(user_data->vert_edge_map); - MEM_freeN(user_data->vert_edge_mem); - MEM_freeN(user_data->vert_poly_map); - MEM_freeN(user_data->vert_poly_mem); - MEM_freeN(user_data->edge_poly_map); - MEM_freeN(user_data->edge_poly_mem); -# endif - MEM_freeN(user_data); -} - -void ccgSubSurf_converter_setup_from_derivedmesh(CCGSubSurf *ss, - DerivedMesh *dm, - OpenSubdiv_Converter *converter) -{ - ConvDMStorage *user_data; - - converter->getSchemeType = conv_dm_get_type; - - converter->getVtxBoundaryInterpolation = conv_dm_get_vtx_boundary_interpolation; - converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation; - converter->specifiesFullTopology = conv_dm_specifies_full_topology; - - converter->getNumFaces = conv_dm_get_num_faces; - converter->getNumEdges = conv_dm_get_num_edges; - converter->getNumVertices = conv_dm_get_num_verts; - - converter->getNumFaceVertices = conv_dm_get_num_face_verts; - converter->getFaceVertices = conv_dm_get_face_verts; - converter->getFaceEdges = conv_dm_get_face_edges; - - converter->getEdgeVertices = conv_dm_get_edge_verts; - converter->getNumEdgeFaces = conv_dm_get_num_edge_faces; - converter->getEdgeFaces = conv_dm_get_edge_faces; - converter->getEdgeSharpness = conv_dm_get_edge_sharpness; - - converter->getNumVertexEdges = conv_dm_get_num_vert_edges; - converter->getVertexEdges = conv_dm_get_vert_edges; - converter->getNumVertexFaces = conv_dm_get_num_vert_faces; - converter->getVertexFaces = conv_dm_get_vert_faces; - converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex; - converter->getVertexSharpness = conv_dm_get_vertex_sharpness; - - converter->getNumUVLayers = conv_dm_get_num_uv_layers; - converter->precalcUVLayer = conv_dm_precalc_uv_layer; - converter->finishUVLayer = conv_dm_finish_uv_layer; - converter->getNumUVCoordinates = conv_dm_get_num_uvs; - converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index; - - user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__); - user_data->ss = ss; - user_data->dm = dm; - - user_data->mvert = dm->getVertArray(dm); - user_data->medge = dm->getEdgeArray(dm); - user_data->mloop = dm->getLoopArray(dm); - user_data->mpoly = dm->getPolyArray(dm); - - memset(&user_data->island_store, 0, sizeof(user_data->island_store)); - - user_data->uvs = NULL; - user_data->face_uvs = NULL; - - converter->freeUserData = conv_dm_free_user_data; - converter->user_data = user_data; - -# ifdef USE_MESH_ELEMENT_MAPPING - { - const MEdge *medge = dm->getEdgeArray(dm); - const MLoop *mloop = dm->getLoopArray(dm); - const MPoly *mpoly = dm->getPolyArray(dm); - const int num_vert = dm->getNumVerts(dm), num_edge = dm->getNumEdges(dm), - num_loop = dm->getNumLoops(dm), num_poly = dm->getNumPolys(dm); - BKE_mesh_vert_edge_map_create( - &user_data->vert_edge_map, &user_data->vert_edge_mem, medge, num_vert, num_edge); - - BKE_mesh_vert_poly_map_create(&user_data->vert_poly_map, - &user_data->vert_poly_mem, - mpoly, - mloop, - num_vert, - num_poly, - num_loop); - - BKE_mesh_edge_poly_map_create(&user_data->edge_poly_map, - &user_data->edge_poly_mem, - medge, - num_edge, - mpoly, - num_poly, - mloop, - num_loop); - } -# endif /* USE_MESH_ELEMENT_MAPPING */ -} - -/** - * Converter from CCGSubSurf - */ - -static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - if (ss->meshIFC.simpleSubdiv) { - return OSD_SCHEME_BILINEAR; - } - else { - return OSD_SCHEME_CATMARK; - } -} - -static OpenSubdiv_VtxBoundaryInterpolation conv_ccg_get_vtx_boundary_interpolation( - const OpenSubdiv_Converter *UNUSED(converter)) -{ - return OSD_VTX_BOUNDARY_EDGE_ONLY; -} - -static OpenSubdiv_FVarLinearInterpolation conv_ccg_get_fvar_linear_interpolation( - const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - if (ss->osd_subdiv_uvs) { - return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY; - } - return OSD_FVAR_LINEAR_INTERPOLATION_ALL; -} - -static bool conv_ccg_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return true; -} - -static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - return ss->fMap->numEntries; -} - -static int conv_ccg_get_num_edges(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - return ss->eMap->numEntries; -} - -static int conv_ccg_get_num_verts(const OpenSubdiv_Converter *converter) -{ - CCGSubSurf *ss = converter->user_data; - return ss->vMap->numEntries; -} - -static int conv_ccg_get_num_face_verts(const OpenSubdiv_Converter *converter, int face) -{ - CCGSubSurf *ss = converter->user_data; - CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face)); - return ccgSubSurf_getFaceNumVerts(ccg_face); -} - -static void conv_ccg_get_face_verts(const OpenSubdiv_Converter *converter, - int face, - int *face_verts) -{ - CCGSubSurf *ss = converter->user_data; - CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face)); - int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face); - int loop; - for (loop = 0; loop < num_face_verts; loop++) { - CCGVert *ccg_vert = ccgSubSurf_getFaceVert(ccg_face, loop); - face_verts[loop] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert)); - } -} - -static void conv_ccg_get_face_edges(const OpenSubdiv_Converter *converter, - int face, - int *face_edges) -{ - CCGSubSurf *ss = converter->user_data; - CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face)); - int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face); - int loop; - for (loop = 0; loop < num_face_verts; loop++) { - CCGEdge *ccg_edge = ccgSubSurf_getFaceEdge(ccg_face, loop); - face_edges[loop] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - } -} - -static void conv_ccg_get_edge_verts(const OpenSubdiv_Converter *converter, - int edge, - int *edge_verts) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - CCGVert *ccg_vert0 = ccgSubSurf_getEdgeVert0(ccg_edge); - CCGVert *ccg_vert1 = ccgSubSurf_getEdgeVert1(ccg_edge); - edge_verts[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert0)); - edge_verts[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1)); -} - -static int conv_ccg_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - return ccgSubSurf_getEdgeNumFaces(ccg_edge); -} - -static void conv_ccg_get_edge_faces(const OpenSubdiv_Converter *converter, - int edge, - int *edge_faces) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - int num_edge_faces = ccgSubSurf_getEdgeNumFaces(ccg_edge); - int face; - for (face = 0; face < num_edge_faces; face++) { - CCGFace *ccg_face = ccgSubSurf_getEdgeFace(ccg_edge, face); - edge_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face)); - } -} - -static float conv_ccg_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge) -{ - CCGSubSurf *ss = converter->user_data; - CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge)); - /* TODO(sergey): Multiply by subdivision level once CPU evaluator - * is switched to uniform subdivision type. - */ - return ccg_edge->crease; -} - -static int conv_ccg_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - return ccgSubSurf_getVertNumEdges(ccg_vert); -} - -static void conv_ccg_get_vert_edges(const OpenSubdiv_Converter *converter, - int vert, - int *vert_edges) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - int num_vert_edges = ccgSubSurf_getVertNumEdges(ccg_vert); - int edge; - for (edge = 0; edge < num_vert_edges; edge++) { - CCGEdge *ccg_edge = ccgSubSurf_getVertEdge(ccg_vert, edge); - vert_edges[edge] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge)); - } -} - -static int conv_ccg_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - return ccgSubSurf_getVertNumFaces(ccg_vert); -} - -static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter, - int vert, - int *vert_faces) -{ - CCGSubSurf *ss = converter->user_data; - CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert)); - int num_vert_faces = ccgSubSurf_getVertNumFaces(ccg_vert); - int face; - for (face = 0; face < num_vert_faces; face++) { - CCGFace *ccg_face = ccgSubSurf_getVertFace(ccg_vert, face); - vert_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face)); - } -} - -static bool conv_ccg_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return false; -} - -static float conv_ccg_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(manifold_vertex_index)) -{ - return 0.0f; -} - -static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return 0; -} - -static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(layer)) -{ -} - -static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter)) -{ -} - -static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter)) -{ - return 0; -} - -static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter), - int UNUSED(face), - int UNUSED(corner_)) -{ - return 0; -} - -void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter) -{ - converter->getSchemeType = conv_ccg_get_bilinear_type; - - converter->getVtxBoundaryInterpolation = conv_ccg_get_vtx_boundary_interpolation; - converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation; - converter->specifiesFullTopology = conv_ccg_specifies_full_topology; - - converter->getNumFaces = conv_ccg_get_num_faces; - converter->getNumEdges = conv_ccg_get_num_edges; - converter->getNumVertices = conv_ccg_get_num_verts; - - converter->getNumFaceVertices = conv_ccg_get_num_face_verts; - converter->getFaceVertices = conv_ccg_get_face_verts; - converter->getFaceEdges = conv_ccg_get_face_edges; - - converter->getEdgeVertices = conv_ccg_get_edge_verts; - converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces; - converter->getEdgeFaces = conv_ccg_get_edge_faces; - converter->getEdgeSharpness = conv_ccg_get_edge_sharpness; - - converter->getNumVertexEdges = conv_ccg_get_num_vert_edges; - converter->getVertexEdges = conv_ccg_get_vert_edges; - converter->getNumVertexFaces = conv_ccg_get_num_vert_faces; - converter->getVertexFaces = conv_ccg_get_vert_faces; - converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex; - converter->getVertexSharpness = conv_ccg_get_vertex_sharpness; - - converter->getNumUVLayers = conv_ccg_get_num_uv_layers; - converter->precalcUVLayer = conv_ccg_precalc_uv_layer; - converter->finishUVLayer = conv_ccg_finish_uv_layer; - converter->getNumUVCoordinates = conv_ccg_get_num_uvs; - converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index; - - converter->freeUserData = NULL; - converter->user_data = ss; -} - -void ccgSubSurf_converter_free(struct OpenSubdiv_Converter *converter) -{ - if (converter->freeUserData) { - converter->freeUserData(converter); - } -} - -#endif /* WITH_OPENSUBDIV */ diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index baef2b2290e..52fe51afcb2 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -698,7 +698,8 @@ static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free) /* apply shape key for cloth, this should really be solved * by a more flexible customdata system, but not simple */ if (!em) { - ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth); + ClothModifierData *clmd = (ClothModifierData *)BKE_modifiers_findby_type( + ob, eModifierType_Cloth); KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob), clmd->sim_parms->shapekey_rest); @@ -901,21 +902,21 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Sculpt can skip certain modifiers. */ MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); - const bool has_multires = (mmd && BKE_multires_sculpt_level_get(mmd) != 0); + const bool has_multires = (mmd && mmd->sculptlvl != 0); bool multires_applied = false; const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render; const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render; /* Modifier evaluation contexts for different types of modifiers. */ - ModifierApplyFlag app_render = use_render ? MOD_APPLY_RENDER : 0; - ModifierApplyFlag app_cache = use_cache ? MOD_APPLY_USECACHE : 0; - const ModifierEvalContext mectx = {depsgraph, ob, app_render | app_cache}; - const ModifierEvalContext mectx_orco = {depsgraph, ob, app_render | MOD_APPLY_ORCO}; + ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0; + ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : 0; + const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache}; + const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO}; /* Get effective list of modifiers to execute. Some effects like shape keys * are added as virtual modifiers before the user created modifiers. */ VirtualModifierData virtualModifierData; - ModifierData *firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *firstmd = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); ModifierData *md = firstmd; /* Preview colors by modifiers such as dynamic paint, to show the results @@ -929,7 +930,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* XXX Currently, DPaint modifier just ignores this. * Needs a stupid hack... * The whole "modifier preview" thing has to be (re?)designed, anyway! */ - previewmd = modifiers_getLastPreview(scene, md, required_mode); + previewmd = BKE_modifier_get_last_preview(scene, md, required_mode); } /* Compute accumulated datamasks needed by each modifier. It helps to do @@ -937,21 +938,21 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, * an armature modifier, but not through a following subsurf modifier where * subdividing them is expensive. */ CustomData_MeshMasks final_datamask = *dataMask; - CDMaskLink *datamasks = modifiers_calcDataMasks( + CDMaskLink *datamasks = BKE_modifier_calc_data_masks( scene, ob, md, &final_datamask, required_mode, previewmd, &previewmask); CDMaskLink *md_datamask = datamasks; /* XXX Always copying POLYINDEX, else tessellated data are no more valid! */ CustomData_MeshMasks append_mask = CD_MASK_BAREMESH_ORIGINDEX; /* Clear errors before evaluation. */ - modifiers_clearErrors(ob); + BKE_modifiers_clear_errors(ob); /* Apply all leading deform modifiers. */ if (useDeform) { for (; md; md = md->next, md_datamask = md_datamask->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (!modifier_isEnabled(scene, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; } @@ -971,7 +972,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); } - modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); + BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); isPrevDeform = true; } @@ -1001,9 +1002,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Apply all remaining constructive and deforming modifiers. */ bool have_non_onlydeform_modifiers_appled = false; for (; md; md = md->next, md_datamask = md_datamask->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (!modifier_isEnabled(scene, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; } @@ -1013,15 +1014,14 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && have_non_onlydeform_modifiers_appled) { - modifier_setError(md, "Modifier requires original data, bad stack position"); + BKE_modifier_set_error(md, "Modifier requires original data, bad stack position"); continue; } if (sculpt_mode && (!has_multires || multires_applied || sculpt_dyntopo)) { bool unsupported = false; - if (md->type == eModifierType_Multires && - BKE_multires_sculpt_level_get((MultiresModifierData *)md) == 0) { + if (md->type == eModifierType_Multires && ((MultiresModifierData *)md)->sculptlvl == 0) { /* If multires is on level 0 skip it silently without warning message. */ if (!sculpt_dyntopo) { continue; @@ -1040,19 +1040,19 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (unsupported) { if (sculpt_dyntopo) { - modifier_setError(md, "Not supported in dyntopo"); + BKE_modifier_set_error(md, "Not supported in dyntopo"); } else { - modifier_setError(md, "Not supported in sculpt mode"); + BKE_modifier_set_error(md, "Not supported in sculpt mode"); } continue; } else { - modifier_setError(md, "Sculpt: Hide, Mask and optimized display disabled"); + BKE_modifier_set_error(md, "Sculpt: Hide, Mask and optimized display disabled"); } } - if (need_mapping && !modifier_supportsMapping(md)) { + if (need_mapping && !BKE_modifier_supports_mapping(md)) { continue; } @@ -1094,7 +1094,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); } - modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); + BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); } else { have_non_onlydeform_modifiers_appled = true; @@ -1176,7 +1176,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } } - Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final); + Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { @@ -1212,7 +1212,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask); mesh_set_only_copy(mesh_orco, &temp_cddata_masks); - mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco); + mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { @@ -1238,7 +1238,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, nextmask.pmask |= CD_MASK_ORIGINDEX; mesh_set_only_copy(mesh_orco_cloth, &nextmask); - mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco_cloth); + mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { @@ -1276,7 +1276,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, BLI_linklist_free((LinkNode *)datamasks, NULL); for (md = firstmd; md; md = md->next) { - modifier_freeTemporaryData(md); + BKE_modifier_free_temporary_data(md); } /* Yay, we are done. If we have a Mesh and deformed vertices, @@ -1376,15 +1376,15 @@ float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3] bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; - if (!modifier_isEnabled(scene, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { return false; } if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) { - modifier_setError(md, "Modifier requires original data, bad stack position"); + BKE_modifier_set_error(md, "Modifier requires original data, bad stack position"); return false; } @@ -1486,30 +1486,30 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* Get effective list of modifiers to execute. Some effects like shape keys * are added as virtual modifiers before the user created modifiers. */ VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); /* Compute accumulated datamasks needed by each modifier. It helps to do * this fine grained so that for example vertex groups are preserved up to * an armature modifier, but not through a following subsurf modifier where * subdividing them is expensive. */ CustomData_MeshMasks final_datamask = *dataMask; - CDMaskLink *datamasks = modifiers_calcDataMasks( + CDMaskLink *datamasks = BKE_modifier_calc_data_masks( scene, ob, md, &final_datamask, required_mode, NULL, NULL); CDMaskLink *md_datamask = datamasks; CustomData_MeshMasks append_mask = CD_MASK_BAREMESH; /* Evaluate modifiers up to certain index to get the mesh cage. */ - int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1); if (r_cage && cageIndex == -1) { mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( em_input, &final_datamask, NULL, mesh_input); } /* Clear errors before evaluation. */ - modifiers_clearErrors(ob); + BKE_modifiers_clear_errors(ob); for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (!editbmesh_modifier_is_enabled(scene, md, mesh_final != NULL)) { continue; @@ -1550,11 +1550,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } if (mti->deformVertsEM) { - modwrap_deformVertsEM( + BKE_modifier_deform_vertsEM( md, &mectx, em_input, mesh_final, deformed_verts, num_deformed_verts); } else { - modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); + BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts); } } else { @@ -1595,7 +1595,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, mask.pmask |= CD_MASK_ORIGINDEX; mesh_set_only_copy(mesh_orco, &mask); - Mesh *mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco); + Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { @@ -1626,7 +1626,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } } - Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final); + Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { @@ -1798,9 +1798,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph, } } - if (mesh_eval != NULL) { - mesh_runtime_check_normals_valid(mesh_eval); - } + mesh_runtime_check_normals_valid(mesh_eval); mesh_build_extra_data(depsgraph, ob, mesh_eval); } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index ba77538bfb6..bd39ffc65e7 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -52,6 +52,7 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_object.h" @@ -154,6 +155,15 @@ static void action_free_data(struct ID *id) BLI_freelistN(&action->markers); } +static void action_foreach_id(ID *id, LibraryForeachIDData *data) +{ + bAction *act = (bAction *)id; + + LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { + BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP); + } +} + IDTypeInfo IDType_ID_AC = { .id_code = ID_AC, .id_filter = FILTER_ID_AC, @@ -168,6 +178,7 @@ IDTypeInfo IDType_ID_AC = { .copy_data = action_copy_data, .free_data = action_free_data, .make_local = NULL, + .foreach_id = action_foreach_id, }; /* ***************** Library data level operations on action ************** */ @@ -1665,6 +1676,6 @@ void what_does_obaction( adt.action = act; /* execute effects of Action on to workob (or it's PoseChannels) */ - BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM, false); + BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM, false); } } diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 41bfc5b59e4..02b7763a9b4 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -29,6 +29,7 @@ #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -95,6 +96,7 @@ bool id_type_can_have_animdata(const short id_type) case ID_HA: case ID_PT: case ID_VO: + case ID_SIM: return true; /* no AnimData */ @@ -1321,6 +1323,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use /* volumes */ ANIMDATA_IDS_CB(bmain->volumes.first); + + /* simulations */ + ANIMDATA_IDS_CB(bmain->simulations.first); } /* Fix all RNA-Paths throughout the database (directly access the Global.main version) @@ -1430,6 +1435,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, /* volumes */ RENAMEFIX_ANIM_IDS(bmain->volumes.first); + /* simulations */ + RENAMEFIX_ANIM_IDS(bmain->simulations.first); + /* scenes */ RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene); } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 18320ef0f8d..5e4b280d0d0 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -2500,7 +2500,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) * have been set already by the depsgraph. Now, we use the recalc */ void BKE_animsys_evaluate_animdata( - Scene *scene, ID *id, AnimData *adt, float ctime, short recalc, const bool flush_to_original) + ID *id, AnimData *adt, float ctime, eAnimData_Recalc recalc, const bool flush_to_original) { PointerRNA id_ptr; @@ -2547,13 +2547,6 @@ void BKE_animsys_evaluate_animdata( * - It is best that we execute this every time, so that no errors are likely to occur. */ animsys_evaluate_overrides(&id_ptr, adt); - - /* execute and clear all cached property update functions */ - if (scene) { - Main *bmain = G.main; // xxx - to get passed in! - RNA_property_update_cache_flush(bmain, scene); - RNA_property_update_cache_free(); - } } /* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only @@ -2563,10 +2556,7 @@ void BKE_animsys_evaluate_animdata( * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a * standard 'root') block are overridden by a larger 'user' */ -void BKE_animsys_evaluate_all_animation(Main *main, - Depsgraph *depsgraph, - Scene *scene, - float ctime) +void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float ctime) { ID *id; @@ -2585,7 +2575,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, for (id = first; id; id = id->next) { \ if (ID_REAL_USERS(id) > 0) { \ AnimData *adt = BKE_animdata_from_id(id); \ - BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \ + BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \ } \ } \ (void)0 @@ -2604,9 +2594,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, if (ntp->nodetree) { \ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ BKE_animsys_evaluate_animdata( \ - scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \ + &ntp->nodetree->id, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \ } \ - BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \ + BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \ } \ } \ (void)0 @@ -2690,6 +2680,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, /* volumes */ EVAL_ANIM_IDS(main->volumes.first, ADT_RECALC_ANIM); + /* simulations */ + EVAL_ANIM_IDS(main->simulations.first, ADT_RECALC_ANIM); + /* objects */ /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets * this tagged by Depsgraph on framechange. This optimization means that objects @@ -2718,10 +2711,9 @@ void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id) AnimData *adt = BKE_animdata_from_id(id); /* XXX: this is only needed for flushing RNA updates, * which should get handled as part of the dependency graph instead. */ - Scene *scene = NULL; DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime); const bool flush_to_original = DEG_is_active(depsgraph); - BKE_animsys_evaluate_animdata(scene, id, adt, ctime, ADT_RECALC_ANIM, flush_to_original); + BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM, flush_to_original); } void BKE_animsys_update_driver_array(ID *id) diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 4071cc024aa..8189385a69d 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -359,7 +359,7 @@ static bool get_path_user(char *targetpath, * \param folder_name: default name of folder within installation area * \param subfolder_name: optional name of subfolder within folder * \param ver: Blender version, used to construct a subdirectory name - * \return true if it was able to construct such a path. + * \return true if it was able to construct such a path. */ static bool get_path_system(char *targetpath, size_t targetpath_len, diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 04051edd334..36921bd2662 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -61,6 +61,7 @@ #include "BKE_idtype.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -151,6 +152,24 @@ static void armature_free_data(struct ID *id) } } +static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data) +{ + IDP_foreach_property( + bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + + LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { + armature_foreach_id_bone(curbone, data); + } +} + +static void armature_foreach_id(ID *id, LibraryForeachIDData *data) +{ + bArmature *arm = (bArmature *)id; + LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { + armature_foreach_id_bone(bone, data); + } +} + IDTypeInfo IDType_ID_AR = { .id_code = ID_AR, .id_filter = FILTER_ID_AR, @@ -165,6 +184,7 @@ IDTypeInfo IDType_ID_AR = { .copy_data = armature_copy_data, .free_data = armature_free_data, .make_local = NULL, + .foreach_id = armature_foreach_id, }; /* **************** Generic Functions, data level *************** */ diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 5c000fbcb36..13dcc7b06f6 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -279,9 +279,6 @@ static void setup_app_data(bContext *C, // CTX_wm_manager_set(C, NULL); BKE_blender_globals_clear(); - /* clear old property update cache, in case some old references are left dangling */ - RNA_property_update_cache_free(); - bmain = G_MAIN = bfd->main; bfd->main = NULL; diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index a493d5f49c8..6197b9dbefd 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -861,7 +861,7 @@ static Object *boid_find_ground(BoidBrainData *bbd, SurfaceModifierData *surmd = NULL; float x[3], v[3]; - surmd = (SurfaceModifierData *)modifiers_findByType(bpa->ground, eModifierType_Surface); + surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(bpa->ground, eModifierType_Surface); /* take surface velocity into account */ closest_point_on_surface(surmd, pa->state.co, x, NULL, v); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index ab107218214..133917e441c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -49,7 +49,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "RE_render_ext.h" /* externtex */ +#include "RE_render_ext.h" /* RE_texture_evaluate */ static void brush_init_data(ID *id) { @@ -89,6 +89,19 @@ static void brush_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c brush_src->gpencil_settings->curve_strength); brush_dst->gpencil_settings->curve_jitter = BKE_curvemapping_copy( brush_src->gpencil_settings->curve_jitter); + + brush_dst->gpencil_settings->curve_rand_pressure = BKE_curvemapping_copy( + brush_src->gpencil_settings->curve_rand_pressure); + brush_dst->gpencil_settings->curve_rand_strength = BKE_curvemapping_copy( + brush_src->gpencil_settings->curve_rand_strength); + brush_dst->gpencil_settings->curve_rand_uv = BKE_curvemapping_copy( + brush_src->gpencil_settings->curve_rand_uv); + brush_dst->gpencil_settings->curve_rand_hue = BKE_curvemapping_copy( + brush_src->gpencil_settings->curve_rand_hue); + brush_dst->gpencil_settings->curve_rand_saturation = BKE_curvemapping_copy( + brush_src->gpencil_settings->curve_rand_saturation); + brush_dst->gpencil_settings->curve_rand_value = BKE_curvemapping_copy( + brush_src->gpencil_settings->curve_rand_value); } /* enable fake user by default */ @@ -107,6 +120,14 @@ static void brush_free_data(ID *id) BKE_curvemapping_free(brush->gpencil_settings->curve_sensitivity); BKE_curvemapping_free(brush->gpencil_settings->curve_strength); BKE_curvemapping_free(brush->gpencil_settings->curve_jitter); + + BKE_curvemapping_free(brush->gpencil_settings->curve_rand_pressure); + BKE_curvemapping_free(brush->gpencil_settings->curve_rand_strength); + BKE_curvemapping_free(brush->gpencil_settings->curve_rand_uv); + BKE_curvemapping_free(brush->gpencil_settings->curve_rand_hue); + BKE_curvemapping_free(brush->gpencil_settings->curve_rand_saturation); + BKE_curvemapping_free(brush->gpencil_settings->curve_rand_value); + MEM_SAFE_FREE(brush->gpencil_settings); } @@ -160,6 +181,20 @@ static void brush_make_local(Main *bmain, ID *id, const int flags) } } +static void brush_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Brush *brush = (Brush *)id; + + BKE_LIB_FOREACHID_PROCESS(data, brush->toggle_brush, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, brush->clone.image, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, brush->paint_curve, IDWALK_CB_USER); + if (brush->gpencil_settings) { + BKE_LIB_FOREACHID_PROCESS(data, brush->gpencil_settings->material, IDWALK_CB_USER); + } + BKE_texture_mtex_foreach_id(data, &brush->mtex); + BKE_texture_mtex_foreach_id(data, &brush->mask_mtex); +} + IDTypeInfo IDType_ID_BR = { .id_code = ID_BR, .id_filter = FILTER_ID_BR, @@ -174,6 +209,7 @@ IDTypeInfo IDType_ID_BR = { .copy_data = brush_copy_data, .free_data = brush_free_data, .make_local = brush_make_local, + .foreach_id = brush_foreach_id, }; static RNG *brush_rng; @@ -280,6 +316,13 @@ void BKE_brush_init_gpencil_settings(Brush *brush) brush->gpencil_settings->curve_sensitivity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); brush->gpencil_settings->curve_strength = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); brush->gpencil_settings->curve_jitter = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + + brush->gpencil_settings->curve_rand_pressure = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_rand_strength = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_rand_uv = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_rand_hue = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_rand_saturation = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); } /* add a new gp-brush */ @@ -1649,8 +1692,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene, else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { /* Get strength by feeding the vertex * location directly into a texture */ - hasrgb = externtex( - mtex, point, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + hasrgb = RE_texture_evaluate(mtex, point, thread, pool, false, false, &intensity, rgba); } else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) { float rotation = -mtex->rot; @@ -1680,8 +1722,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene, co[1] = y; co[2] = 0.0f; - hasrgb = externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } else { float rotation = -mtex->rot; @@ -1737,8 +1778,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene, co[1] = y; co[2] = 0.0f; - hasrgb = externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } intensity += br->texture_sample_bias; @@ -1795,8 +1835,7 @@ float BKE_brush_sample_masktex( co[1] = y; co[2] = 0.0f; - externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } else { float rotation = -mtex->rot; @@ -1852,8 +1891,7 @@ float BKE_brush_sample_masktex( co[1] = y; co[2] = 0.0f; - externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); } CLAMP(intensity, 0.0f, 1.0f); @@ -2157,7 +2195,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec unsigned int *texcache = NULL; MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex; float intensity; - float rgba[4]; + float rgba_dummy[4]; int ix, iy; int side = half_side * 2; @@ -2175,11 +2213,8 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec /* This is copied from displace modifier code */ /* TODO(sergey): brush are always caching with CM enabled for now. */ - externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false); - - ((char *)texcache)[(iy * side + ix) * 4] = ((char *)texcache)[(iy * side + ix) * 4 + 1] = - ((char *)texcache)[(iy * side + ix) * 4 + 2] = (( - char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(intensity * 255.0f); + RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba_dummy); + copy_v4_uchar((uchar *)&texcache[iy * side + ix], (char)(intensity * 255.0f)); } } } diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 8f6b8bd6980..cd90ebc2eed 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -517,7 +517,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data, float epsilon, int tree_type, int axis, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { BVHTree *tree = NULL; @@ -581,7 +581,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data, float epsilon, int tree_type, int axis, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { bool in_cache = false; @@ -734,7 +734,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data, float epsilon, int tree_type, int axis, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { BVHTree *tree = NULL; @@ -801,7 +801,7 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data, float epsilon, int tree_type, int axis, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { bool in_cache = false; @@ -936,7 +936,7 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data, float epsilon, int tree_type, int axis, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { bool in_cache = false; @@ -1112,7 +1112,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data, float epsilon, int tree_type, int axis, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { /* BMESH specific check that we have tessfaces, @@ -1176,7 +1176,7 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data, float epsilon, int tree_type, int axis, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { bool in_cache = false; @@ -1311,7 +1311,7 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly, */ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, struct Mesh *mesh, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, const int tree_type) { BVHTree *tree = NULL; @@ -1492,7 +1492,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data, struct BMEditMesh *em, const int tree_type, - const int bvh_cache_type, + const BVHCacheType bvh_cache_type, BVHCache **bvh_cache) { BVHTree *tree = NULL; @@ -1621,7 +1621,7 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data) * \{ */ typedef struct BVHCacheItem { - int type; + BVHCacheType type; BVHTree *tree; } BVHCacheItem; @@ -1629,7 +1629,7 @@ typedef struct BVHCacheItem { /** * Queries a bvhcache for the cache bvhtree of the request type */ -bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree) +bool bvhcache_find(const BVHCache *cache, BVHCacheType type, BVHTree **r_tree) { while (cache) { const BVHCacheItem *item = cache->link; @@ -1662,7 +1662,7 @@ bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree) * A call to this assumes that there was no previous cached tree of the given type * \warning The #BVHTree can be NULL. */ -void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type) +void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, BVHCacheType type) { BVHCacheItem *item = NULL; diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index d23b643ce70..da9dab36044 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -97,6 +97,7 @@ IDTypeInfo IDType_ID_CF = { .copy_data = cache_file_copy_data, .free_data = cache_file_free_data, .make_local = NULL, + .foreach_id = NULL, }; /* TODO: make this per cache file to avoid global locks. */ diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 71a2b6f703a..5ec4c84c013 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -42,6 +42,7 @@ #include "BKE_idtype.h" #include "BKE_layer.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -63,17 +64,6 @@ static void camera_init_data(ID *id) MEMCPY_STRUCT_AFTER(cam, DNA_struct_default_get(Camera), id); } -void *BKE_camera_add(Main *bmain, const char *name) -{ - Camera *cam; - - cam = BKE_libblock_alloc(bmain, ID_CA, name, 0); - - camera_init_data(&cam->id); - - return cam; -} - /** * Only copy internal data of Camera ID from source * to already allocated/initialized destination. @@ -94,13 +84,6 @@ static void camera_copy_data(Main *UNUSED(bmain), BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images); } -Camera *BKE_camera_copy(Main *bmain, const Camera *cam) -{ - Camera *cam_copy; - BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy); - return cam_copy; -} - static void camera_make_local(Main *bmain, ID *id, const int flags) { BKE_lib_id_make_local_generic(bmain, id, flags); @@ -113,6 +96,21 @@ static void camera_free_data(ID *id) BLI_freelistN(&cam->bg_images); } +static void camera_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Camera *camera = (Camera *)id; + + BKE_LIB_FOREACHID_PROCESS(data, camera->dof.focus_object, IDWALK_CB_NOP); + LISTBASE_FOREACH (CameraBGImage *, bgpic, &camera->bg_images) { + if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) { + BKE_LIB_FOREACHID_PROCESS(data, bgpic->ima, IDWALK_CB_USER); + } + else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) { + BKE_LIB_FOREACHID_PROCESS(data, bgpic->clip, IDWALK_CB_USER); + } + } +} + IDTypeInfo IDType_ID_CA = { .id_code = ID_CA, .id_filter = FILTER_ID_CA, @@ -127,10 +125,29 @@ IDTypeInfo IDType_ID_CA = { .copy_data = camera_copy_data, .free_data = camera_free_data, .make_local = camera_make_local, + .foreach_id = camera_foreach_id, }; /******************************** Camera Usage *******************************/ +void *BKE_camera_add(Main *bmain, const char *name) +{ + Camera *cam; + + cam = BKE_libblock_alloc(bmain, ID_CA, name, 0); + + camera_init_data(&cam->id); + + return cam; +} + +Camera *BKE_camera_copy(Main *bmain, const Camera *cam) +{ + Camera *cam_copy; + BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy); + return cam_copy; +} + /* get the camera's dof value, takes the dof object into account */ float BKE_camera_object_dof_distance(Object *ob) { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 8a0df6375be..879313783d9 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -10,7 +10,7 @@ * 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, + * 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) 2006 Blender Foundation. diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 04663115424..0b9780ac81c 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -333,13 +333,13 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int if (clmd->clothObject == NULL) { if (!cloth_from_object(ob, clmd, result, framenr, 1)) { BKE_ptcache_invalidate(cache); - modifier_setError(&(clmd->modifier), "Can't initialize cloth"); + BKE_modifier_set_error(&(clmd->modifier), "Can't initialize cloth"); return 0; } if (clmd->clothObject == NULL) { BKE_ptcache_invalidate(cache); - modifier_setError(&(clmd->modifier), "Null cloth object"); + BKE_modifier_set_error(&(clmd->modifier), "Null cloth object"); return 0; } @@ -841,7 +841,7 @@ static int cloth_from_object( clmd->clothObject->edgeset = NULL; } else { - modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject"); + BKE_modifier_set_error(&(clmd->modifier), "Out of memory on allocating clmd->clothObject"); return 0; } @@ -913,7 +913,7 @@ static int cloth_from_object( if (!cloth_build_springs(clmd, mesh)) { cloth_free_modifier(clmd); - modifier_setError(&(clmd->modifier), "Cannot build springs"); + BKE_modifier_set_error(&(clmd->modifier), "Cannot build springs"); return 0; } @@ -943,7 +943,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) "clothVertex"); if (clmd->clothObject->verts == NULL) { cloth_free_modifier(clmd); - modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts"); + BKE_modifier_set_error(&(clmd->modifier), + "Out of memory on allocating clmd->clothObject->verts"); printf("cloth_free_modifier clmd->clothObject->verts\n"); return; } @@ -959,7 +960,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris"); if (clmd->clothObject->tri == NULL) { cloth_free_modifier(clmd); - modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri"); + BKE_modifier_set_error(&(clmd->modifier), + "Out of memory on allocating clmd->clothObject->looptri"); printf("cloth_free_modifier clmd->clothObject->looptri\n"); return; } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 583bb39a851..c1d77fd5f9e 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -34,6 +34,7 @@ #include "BKE_idtype.h" #include "BKE_layer.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_object.h" @@ -128,6 +129,28 @@ static void collection_free_data(ID *id) BKE_collection_object_cache_free(collection); } +static void collection_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Collection *collection = (Collection *)id; + + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + BKE_LIB_FOREACHID_PROCESS(data, cob->ob, IDWALK_CB_USER); + } + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + BKE_LIB_FOREACHID_PROCESS(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER); + } + LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) { + /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad + * anyway... */ + const int cb_flag = ((parent->collection != NULL && + (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS( + data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag); + } +} + IDTypeInfo IDType_ID_GR = { .id_code = ID_GR, .id_filter = FILTER_ID_GR, @@ -142,6 +165,7 @@ IDTypeInfo IDType_ID_GR = { .copy_data = collection_copy_data, .free_data = collection_free_data, .make_local = NULL, + .foreach_id = collection_foreach_id, }; /***************************** Add Collection *******************************/ diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 7cc40007e26..daf1602319f 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1307,7 +1307,7 @@ static void add_collision_object(ListBase *relations, /* only get objects with collision modifier */ if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) || (modifier_type != eModifierType_Collision)) { - cmd = (CollisionModifierData *)modifiers_findByType(ob, modifier_type); + cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, modifier_type); } if (cmd) { @@ -1426,7 +1426,7 @@ ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collecti continue; } - CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType( + CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type( ob, eModifierType_Collision); if (cmd && cmd->bvhtree) { if (cache == NULL) { @@ -1527,7 +1527,7 @@ static int cloth_bvh_objcollisions_resolve(ClothModifierData *clmd, for (i = 0; i < numcollobj; i++) { Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( + CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type( collob, eModifierType_Collision); if (collmd->bvhtree) { @@ -1658,7 +1658,7 @@ int cloth_bvh_collision( for (i = 0; i < numcollobj; i++) { Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( + CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type( collob, eModifierType_Collision); if (!collmd->bvhtree) { @@ -1693,7 +1693,7 @@ int cloth_bvh_collision( for (i = 0; i < numcollobj; i++) { Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( + CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type( collob, eModifierType_Collision); if (!collmd->bvhtree) { diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index f82b8b6675c..3da384a2745 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -1383,8 +1383,6 @@ typedef struct ScopesUpdateData { struct ColormanageProcessor *cm_processor; const unsigned char *display_buffer; const int ycc_mode; - - unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a; } ScopesUpdateData; typedef struct ScopesUpdateDataChunk { @@ -1495,23 +1493,24 @@ static void scopes_update_cb(void *__restrict userdata, } } -static void scopes_update_finalize(void *__restrict userdata, void *__restrict userdata_chunk) +static void scopes_update_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - const ScopesUpdateData *data = userdata; - const ScopesUpdateDataChunk *data_chunk = userdata_chunk; - - unsigned int *bin_lum = data->bin_lum; - unsigned int *bin_r = data->bin_r; - unsigned int *bin_g = data->bin_g; - unsigned int *bin_b = data->bin_b; - unsigned int *bin_a = data->bin_a; + ScopesUpdateDataChunk *join_chunk = chunk_join; + const ScopesUpdateDataChunk *data_chunk = chunk; + + unsigned int *bin_lum = join_chunk->bin_lum; + unsigned int *bin_r = join_chunk->bin_r; + unsigned int *bin_g = join_chunk->bin_g; + unsigned int *bin_b = join_chunk->bin_b; + unsigned int *bin_a = join_chunk->bin_a; const unsigned int *bin_lum_c = data_chunk->bin_lum; const unsigned int *bin_r_c = data_chunk->bin_r; const unsigned int *bin_g_c = data_chunk->bin_g; const unsigned int *bin_b_c = data_chunk->bin_b; const unsigned int *bin_a_c = data_chunk->bin_a; - float(*minmax)[2] = data->scopes->minmax; const float *min = data_chunk->min; const float *max = data_chunk->max; @@ -1524,11 +1523,11 @@ static void scopes_update_finalize(void *__restrict userdata, void *__restrict u } for (int c = 3; c--;) { - if (min[c] < minmax[c][0]) { - minmax[c][0] = min[c]; + if (min[c] < join_chunk->min[c]) { + join_chunk->min[c] = min[c]; } - if (max[c] > minmax[c][1]) { - minmax[c][1] = max[c]; + if (max[c] > join_chunk->max[c]) { + join_chunk->max[c] = max[c]; } } } @@ -1542,7 +1541,6 @@ void BKE_scopes_update(Scopes *scopes, unsigned int nl, na, nr, ng, nb; double divl, diva, divr, divg, divb; const unsigned char *display_buffer = NULL; - uint bin_lum[256] = {0}, bin_r[256] = {0}, bin_g[256] = {0}, bin_b[256] = {0}, bin_a[256] = {0}; int ycc_mode = -1; void *cache_handle = NULL; struct ColormanageProcessor *cm_processor = NULL; @@ -1638,11 +1636,6 @@ void BKE_scopes_update(Scopes *scopes, .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode, - .bin_lum = bin_lum, - .bin_r = bin_r, - .bin_g = bin_g, - .bin_b = bin_b, - .bin_a = bin_a, }; ScopesUpdateDataChunk data_chunk = {{0}}; INIT_MINMAX(data_chunk.min, data_chunk.max); @@ -1652,26 +1645,26 @@ void BKE_scopes_update(Scopes *scopes, settings.use_threading = (ibuf->y > 256); settings.userdata_chunk = &data_chunk; settings.userdata_chunk_size = sizeof(data_chunk); - settings.func_finalize = scopes_update_finalize; + settings.func_reduce = scopes_update_reduce; BLI_task_parallel_range(0, ibuf->y, &data, scopes_update_cb, &settings); /* convert hist data to float (proportional to max count) */ nl = na = nr = nb = ng = 0; for (a = 0; a < 256; a++) { - if (bin_lum[a] > nl) { - nl = bin_lum[a]; + if (data_chunk.bin_lum[a] > nl) { + nl = data_chunk.bin_lum[a]; } - if (bin_r[a] > nr) { - nr = bin_r[a]; + if (data_chunk.bin_r[a] > nr) { + nr = data_chunk.bin_r[a]; } - if (bin_g[a] > ng) { - ng = bin_g[a]; + if (data_chunk.bin_g[a] > ng) { + ng = data_chunk.bin_g[a]; } - if (bin_b[a] > nb) { - nb = bin_b[a]; + if (data_chunk.bin_b[a] > nb) { + nb = data_chunk.bin_b[a]; } - if (bin_a[a] > na) { - na = bin_a[a]; + if (data_chunk.bin_a[a] > na) { + na = data_chunk.bin_a[a]; } } divl = nl ? 1.0 / (double)nl : 1.0; @@ -1681,11 +1674,11 @@ void BKE_scopes_update(Scopes *scopes, divb = nb ? 1.0 / (double)nb : 1.0; for (a = 0; a < 256; a++) { - scopes->hist.data_luma[a] = bin_lum[a] * divl; - scopes->hist.data_r[a] = bin_r[a] * divr; - scopes->hist.data_g[a] = bin_g[a] * divg; - scopes->hist.data_b[a] = bin_b[a] * divb; - scopes->hist.data_a[a] = bin_a[a] * diva; + scopes->hist.data_luma[a] = data_chunk.bin_lum[a] * divl; + scopes->hist.data_r[a] = data_chunk.bin_r[a] * divr; + scopes->hist.data_g[a] = data_chunk.bin_g[a] * divg; + scopes->hist.data_b[a] = data_chunk.bin_b[a] * divb; + scopes->hist.data_a[a] = data_chunk.bin_a[a] * diva; } if (cm_processor) { diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 099fdacf401..679fe703b13 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -62,7 +62,7 @@ #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_editmesh.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" @@ -1009,8 +1009,8 @@ static void trackto_new_data(void *cdata) { bTrackToConstraint *data = (bTrackToConstraint *)cdata; - data->reserved1 = TRACK_Y; - data->reserved2 = UP_Z; + data->reserved1 = TRACK_nZ; + data->reserved2 = UP_Y; } static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -4590,230 +4590,390 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void func(con, (ID **)&data->depth_ob, false, userdata); } -static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) +static MovieClip *followtrack_tracking_clip_get(bConstraint *con, bConstraintOb *cob) { - Depsgraph *depsgraph = cob->depsgraph; - Scene *scene = cob->scene; bFollowTrackConstraint *data = con->data; - MovieClip *clip = data->clip; + + if (data->flag & FOLLOWTRACK_ACTIVECLIP) { + Scene *scene = cob->scene; + return scene->clip; + } + + return data->clip; +} + +static MovieTrackingObject *followtrack_tracking_object_get(bConstraint *con, bConstraintOb *cob) +{ + MovieClip *clip = followtrack_tracking_clip_get(con, cob); + MovieTracking *tracking = &clip->tracking; + bFollowTrackConstraint *data = con->data; + + if (data->object[0]) { + return BKE_tracking_object_get_named(tracking, data->object); + } + return BKE_tracking_object_get_camera(tracking); +} + +static Object *followtrack_camera_object_get(bConstraint *con, bConstraintOb *cob) +{ + bFollowTrackConstraint *data = con->data; + + if (data->camera == NULL) { + Scene *scene = cob->scene; + return scene->camera; + } + + return data->camera; +} + +typedef struct FollowTrackContext { + int flag; + int frame_method; + + Depsgraph *depsgraph; + Scene *scene; + + MovieClip *clip; + Object *camera_object; + Object *depth_object; + MovieTracking *tracking; - MovieTrackingTrack *track; MovieTrackingObject *tracking_object; - Object *camob = data->camera ? data->camera : scene->camera; + MovieTrackingTrack *track; - float ctime = DEG_get_ctime(depsgraph); - float framenr; + float depsgraph_time; + float clip_frame; +} FollowTrackContext; - if (data->flag & FOLLOWTRACK_ACTIVECLIP) { - clip = scene->clip; - } +static bool followtrack_context_init(FollowTrackContext *context, + bConstraint *con, + bConstraintOb *cob) +{ + bFollowTrackConstraint *data = con->data; - if (!clip || !data->track[0] || !camob) { - return; + context->flag = data->flag; + context->frame_method = data->frame_method; + + context->depsgraph = cob->depsgraph; + context->scene = cob->scene; + + context->clip = followtrack_tracking_clip_get(con, cob); + context->camera_object = followtrack_camera_object_get(con, cob); + if (context->clip == NULL || context->camera_object == NULL) { + return false; } + context->depth_object = data->depth_ob; - tracking = &clip->tracking; + context->tracking = &context->clip->tracking; + context->tracking_object = followtrack_tracking_object_get(con, cob); + if (context->tracking_object == NULL) { + return false; + } - if (data->object[0]) { - tracking_object = BKE_tracking_object_get_named(tracking, data->object); + context->track = BKE_tracking_track_get_named( + context->tracking, context->tracking_object, data->track); + if (context->track == NULL) { + return false; } - else { - tracking_object = BKE_tracking_object_get_camera(tracking); + + context->depsgraph_time = DEG_get_ctime(context->depsgraph); + context->clip_frame = BKE_movieclip_remap_scene_to_clip_frame(context->clip, + context->depsgraph_time); + + return true; +} + +static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *context, + bConstraintOb *cob) +{ + Object *camera_object = context->camera_object; + MovieTracking *tracking = context->tracking; + MovieTrackingTrack *track = context->track; + MovieTrackingObject *tracking_object = context->tracking_object; + + /* Matrix of the object which is being solved prior to this contraint. */ + float obmat[4][4]; + copy_m4_m4(obmat, cob->matrix); + + /* Object matrix of the camera. */ + float camera_obmat[4][4]; + copy_m4_m4(camera_obmat, camera_object->obmat); + + /* Calculate inverted matrix of the solved camera at the current time. */ + float reconstructed_camera_mat[4][4]; + BKE_tracking_camera_get_reconstructed_interpolate( + tracking, tracking_object, context->clip_frame, reconstructed_camera_mat); + float reconstructed_camera_mat_inv[4][4]; + invert_m4_m4(reconstructed_camera_mat_inv, reconstructed_camera_mat); + + mul_m4_series(cob->matrix, obmat, camera_obmat, reconstructed_camera_mat_inv); + translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); +} + +static void followtrack_evaluate_using_3d_position_camera(FollowTrackContext *context, + bConstraintOb *cob) +{ + Object *camera_object = context->camera_object; + MovieTrackingTrack *track = context->track; + + /* Matrix of the object which is being solved prior to this contraint. */ + float obmat[4][4]; + copy_m4_m4(obmat, cob->matrix); + + float reconstructed_camera_mat[4][4]; + BKE_tracking_get_camera_object_matrix(camera_object, reconstructed_camera_mat); + + mul_m4_m4m4(cob->matrix, obmat, reconstructed_camera_mat); + translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); +} + +static void followtrack_evaluate_using_3d_position(FollowTrackContext *context, bConstraintOb *cob) +{ + MovieTrackingTrack *track = context->track; + if ((track->flag & TRACK_HAS_BUNDLE) == 0) { + return; } - if (!tracking_object) { + if ((context->tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { + followtrack_evaluate_using_3d_position_object(context, cob); return; } - track = BKE_tracking_track_get_named(tracking, tracking_object, data->track); + followtrack_evaluate_using_3d_position_camera(context, cob); +} - if (!track) { +/* Apply undistortion if it is enabled in constraint settings. */ +static void followtrack_undistort_if_needed(FollowTrackContext *context, + const int clip_width, + const int clip_height, + float marker_position[2]) +{ + if ((context->flag & FOLLOWTRACK_USE_UNDISTORTION) == 0) { return; } - framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); + /* Undistortion need to happen in pixel space. */ + marker_position[0] *= clip_width; + marker_position[1] *= clip_height; - if (data->flag & FOLLOWTRACK_USE_3D_POSITION) { - if (track->flag & TRACK_HAS_BUNDLE) { - float obmat[4][4], mat[4][4]; + BKE_tracking_undistort_v2( + context->tracking, clip_width, clip_height, marker_position, marker_position); - copy_m4_m4(obmat, cob->matrix); + /* Normalize pixel coordinates back. */ + marker_position[0] /= clip_width; + marker_position[1] /= clip_height; +} - if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { - float imat[4][4]; +/* Modify the marker position matching the frame fitting method. */ +static void followtrack_fit_frame(FollowTrackContext *context, + const int clip_width, + const int clip_height, + float marker_position[2]) +{ + if (context->frame_method == FOLLOWTRACK_FRAME_STRETCH) { + return; + } - copy_m4_m4(mat, camob->obmat); + Scene *scene = context->scene; + MovieClip *clip = context->clip; - BKE_tracking_camera_get_reconstructed_interpolate( - tracking, tracking_object, framenr, imat); - invert_m4(imat); + /* apply clip display aspect */ + const float w_src = clip_width * clip->aspx; + const float h_src = clip_height * clip->aspy; - mul_m4_series(cob->matrix, obmat, mat, imat); - translate_m4( - cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); - } - else { - BKE_tracking_get_camera_object_matrix(camob, mat); + const float w_dst = scene->r.xsch * scene->r.xasp; + const float h_dst = scene->r.ysch * scene->r.yasp; - mul_m4_m4m4(cob->matrix, obmat, mat); - translate_m4( - cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); - } - } + const float asp_src = w_src / h_src; + const float asp_dst = w_dst / h_dst; + + if (fabsf(asp_src - asp_dst) < FLT_EPSILON) { + return; + } + + if ((asp_src > asp_dst) == (context->frame_method == FOLLOWTRACK_FRAME_CROP)) { + /* fit X */ + float div = asp_src / asp_dst; + float cent = (float)clip_width / 2.0f; + + marker_position[0] = (((marker_position[0] * clip_width - cent) * div) + cent) / clip_width; } else { - float vec[3], disp[3], axis[3], mat[4][4]; - float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp); - float len, d; + /* fit Y */ + float div = asp_dst / asp_src; + float cent = (float)clip_height / 2.0f; - BKE_object_where_is_calc_mat4(camob, mat); + marker_position[1] = (((marker_position[1] * clip_height - cent) * div) + cent) / clip_height; + } +} - /* camera axis */ - vec[0] = 0.0f; - vec[1] = 0.0f; - vec[2] = 1.0f; - mul_v3_m4v3(axis, mat, vec); +/* Effectively this is a Z-depth of the object form the movie clip camera. + * The idea is to preserve this depth while moving the object in 2D. */ +static float followtrack_distance_from_viewplane_get(FollowTrackContext *context, + bConstraintOb *cob) +{ + Object *camera_object = context->camera_object; - /* distance to projection plane */ - copy_v3_v3(vec, cob->matrix[3]); - sub_v3_v3(vec, mat[3]); - project_v3_v3v3(disp, vec, axis); + float camera_matrix[4][4]; + BKE_object_where_is_calc_mat4(camera_object, camera_matrix); - len = len_v3(disp); + const float z_axis[3] = {0.0f, 0.0f, 1.0f}; - if (len > FLT_EPSILON) { - CameraParams params; - int width, height; - float pos[2], rmat[4][4]; + /* Direction of camera's local Z axis in the world space. */ + float camera_axis[3]; + mul_v3_mat3_m4v3(camera_axis, camera_matrix, z_axis); - BKE_movieclip_get_size(clip, NULL, &width, &height); - BKE_tracking_marker_get_subframe_position(track, framenr, pos); + /* Distance to projection plane. */ + float vec[3]; + copy_v3_v3(vec, cob->matrix[3]); + sub_v3_v3(vec, camera_matrix[3]); - if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) { - /* Undistortion need to happen in pixel space. */ - pos[0] *= width; - pos[1] *= height; + float projection[3]; + project_v3_v3v3(projection, vec, camera_axis); - BKE_tracking_undistort_v2(tracking, pos, pos); + return len_v3(projection); +} - /* Normalize pixel coordinates back. */ - pos[0] /= width; - pos[1] /= height; - } +/* For the evaluated constraint object project it to the surface of the depth object. */ +static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *context, + bConstraintOb *cob) +{ + if (context->depth_object == NULL) { + return; + } - /* aspect correction */ - if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) { - float w_src, h_src, w_dst, h_dst, asp_src, asp_dst; + Object *depth_object = context->depth_object; + Mesh *depth_mesh = BKE_object_get_evaluated_mesh(depth_object); + if (depth_mesh == NULL) { + return; + } - /* apply clip display aspect */ - w_src = width * clip->aspx; - h_src = height * clip->aspy; + float depth_object_mat_inv[4][4]; + invert_m4_m4(depth_object_mat_inv, depth_object->obmat); - w_dst = scene->r.xsch * scene->r.xasp; - h_dst = scene->r.ysch * scene->r.yasp; + float ray_start[3], ray_end[3]; + mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->obmat[3]); + mul_v3_m4v3(ray_end, depth_object_mat_inv, cob->matrix[3]); - asp_src = w_src / h_src; - asp_dst = w_dst / h_dst; + float ray_direction[3]; + sub_v3_v3v3(ray_direction, ray_end, ray_start); + normalize_v3(ray_direction); - if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { - if ((asp_src > asp_dst) == (data->frame_method == FOLLOWTRACK_FRAME_CROP)) { - /* fit X */ - float div = asp_src / asp_dst; - float cent = (float)width / 2.0f; + BVHTreeFromMesh tree_data = NULL_BVHTreeFromMesh; + BKE_bvhtree_from_mesh_get(&tree_data, depth_mesh, BVHTREE_FROM_LOOPTRI, 4); - pos[0] = (((pos[0] * width - cent) * div) + cent) / width; - } - else { - /* fit Y */ - float div = asp_dst / asp_src; - float cent = (float)height / 2.0f; + BVHTreeRayHit hit; + hit.dist = BVH_RAYCAST_DIST_MAX; + hit.index = -1; - pos[1] = (((pos[1] * height - cent) * div) + cent) / height; - } - } - } + const int result = BLI_bvhtree_ray_cast(tree_data.tree, + ray_start, + ray_direction, + 0.0f, + &hit, + tree_data.raycast_callback, + &tree_data); - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, camob); + if (result != -1) { + mul_v3_m4v3(cob->matrix[3], depth_object->obmat, hit.co); + } - if (params.is_ortho) { - vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx); - vec[1] = params.ortho_scale * (pos[1] - 0.5f + params.shifty); - vec[2] = -len; + free_bvhtree_from_mesh(&tree_data); +} - if (aspect > 1.0f) { - vec[1] /= aspect; - } - else { - vec[0] *= aspect; - } +static void followtrack_evaluate_using_2d_position(FollowTrackContext *context, bConstraintOb *cob) +{ + Scene *scene = context->scene; + MovieClip *clip = context->clip; + MovieTrackingTrack *track = context->track; + Object *camera_object = context->camera_object; + const float clip_frame = context->clip_frame; + const float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp); - mul_v3_m4v3(disp, camob->obmat, vec); + const float object_depth = followtrack_distance_from_viewplane_get(context, cob); + if (object_depth < FLT_EPSILON) { + return; + } - copy_m4_m4(rmat, camob->obmat); - zero_v3(rmat[3]); - mul_m4_m4m4(cob->matrix, cob->matrix, rmat); + int clip_width, clip_height; + BKE_movieclip_get_size(clip, NULL, &clip_width, &clip_height); - copy_v3_v3(cob->matrix[3], disp); - } - else { - d = (len * params.sensor_x) / (2.0f * params.lens); + float marker_position[2]; + BKE_tracking_marker_get_subframe_position(track, clip_frame, marker_position); - vec[0] = d * (2.0f * (pos[0] + params.shiftx) - 1.0f); - vec[1] = d * (2.0f * (pos[1] + params.shifty) - 1.0f); - vec[2] = -len; + followtrack_undistort_if_needed(context, clip_width, clip_height, marker_position); + followtrack_fit_frame(context, clip_width, clip_height, marker_position); - if (aspect > 1.0f) { - vec[1] /= aspect; - } - else { - vec[0] *= aspect; - } + float rmat[4][4]; + CameraParams params; + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, camera_object); - mul_v3_m4v3(disp, camob->obmat, vec); + if (params.is_ortho) { + float vec[3]; + vec[0] = params.ortho_scale * (marker_position[0] - 0.5f + params.shiftx); + vec[1] = params.ortho_scale * (marker_position[1] - 0.5f + params.shifty); + vec[2] = -object_depth; - /* apply camera rotation so Z-axis would be co-linear */ - copy_m4_m4(rmat, camob->obmat); - zero_v3(rmat[3]); - mul_m4_m4m4(cob->matrix, cob->matrix, rmat); + if (aspect > 1.0f) { + vec[1] /= aspect; + } + else { + vec[0] *= aspect; + } - copy_v3_v3(cob->matrix[3], disp); - } + float disp[3]; + mul_v3_m4v3(disp, camera_object->obmat, vec); - if (data->depth_ob) { - Object *depth_ob = data->depth_ob; - Mesh *target_eval = BKE_object_get_evaluated_mesh(depth_ob); - if (target_eval) { - BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; - BVHTreeRayHit hit; - float ray_start[3], ray_end[3], ray_nor[3], imat[4][4]; - int result; + copy_m4_m4(rmat, camera_object->obmat); + zero_v3(rmat[3]); + mul_m4_m4m4(cob->matrix, cob->matrix, rmat); - invert_m4_m4(imat, depth_ob->obmat); + copy_v3_v3(cob->matrix[3], disp); + } + else { + const float d = (object_depth * params.sensor_x) / (2.0f * params.lens); - mul_v3_m4v3(ray_start, imat, camob->obmat[3]); - mul_v3_m4v3(ray_end, imat, cob->matrix[3]); + float vec[3]; + vec[0] = d * (2.0f * (marker_position[0] + params.shiftx) - 1.0f); + vec[1] = d * (2.0f * (marker_position[1] + params.shifty) - 1.0f); + vec[2] = -object_depth; + + if (aspect > 1.0f) { + vec[1] /= aspect; + } + else { + vec[0] *= aspect; + } - sub_v3_v3v3(ray_nor, ray_end, ray_start); - normalize_v3(ray_nor); + float disp[3]; + mul_v3_m4v3(disp, camera_object->obmat, vec); - BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4); + /* apply camera rotation so Z-axis would be co-linear */ + copy_m4_m4(rmat, camera_object->obmat); + zero_v3(rmat[3]); + mul_m4_m4m4(cob->matrix, cob->matrix, rmat); - hit.dist = BVH_RAYCAST_DIST_MAX; - hit.index = -1; + copy_v3_v3(cob->matrix[3], disp); + } - result = BLI_bvhtree_ray_cast( - treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData); + followtrack_project_to_depth_object_if_needed(context, cob); +} - if (result != -1) { - mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co); - } +static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) +{ + FollowTrackContext context; + if (!followtrack_context_init(&context, con, cob)) { + return; + } - free_bvhtree_from_mesh(&treeData); - } - } - } + bFollowTrackConstraint *data = con->data; + if (data->flag & FOLLOWTRACK_USE_3D_POSITION) { + followtrack_evaluate_using_3d_position(&context, cob); + return; } + + followtrack_evaluate_using_2d_position(&context, cob); } static bConstraintTypeInfo CTI_FOLLOWTRACK = { diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 7ec1da8eab4..f4acbdca772 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -84,7 +84,7 @@ static void set_crazy_vertex_quat(float r_quat[4], static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob) { bool disabled = false; - int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1); ModifierData *md = ob->modifiers.first; for (int i = 0; md && i <= cageIndex; i++, md = md->next) { @@ -265,20 +265,20 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra Mesh *me_input = ob->data; Mesh *me = NULL; int i, a, numleft = 0, numVerts = 0; - int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1); float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; VirtualModifierData virtualModifierData; ModifierEvalContext mectx = {depsgraph, ob, 0}; - modifiers_clearErrors(ob); + BKE_modifiers_clear_errors(ob); - md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); /* compute the deformation matrices and coordinates for the first * modifiers with on cage editing that are enabled and support computing * deform matrices */ for (i = 0; md && i <= cageIndex; i++, md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) { continue; @@ -288,7 +288,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra if (!defmats) { const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; CustomData_MeshMasks cd_mask_extra = CD_MASK_BAREMESH; - CDMaskLink *datamasks = modifiers_calcDataMasks( + CDMaskLink *datamasks = BKE_modifier_calc_data_masks( scene, ob, md, &cd_mask_extra, required_mode, NULL, NULL); cd_mask_extra = datamasks->mask; BLI_linklist_free((LinkNode *)datamasks, NULL); @@ -310,7 +310,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra for (; md && i <= cageIndex; md = md->next, i++) { if (editbmesh_modifier_is_enabled(scene, md, me != NULL) && - modifier_isCorrectableDeformed(md)) { + BKE_modifier_is_correctable_deformed(md)) { numleft++; } } @@ -361,13 +361,13 @@ static bool crazyspace_modifier_supports_deform_matrices(ModifierData *md) if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) { return true; } - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return (mti->type == eModifierTypeType_OnlyDeform); } static bool crazyspace_modifier_supports_deform(ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return (mti->type == eModifierTypeType_OnlyDeform); } @@ -386,7 +386,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, crazyspace_init_object_for_eval(depsgraph, object, &object_eval); MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0); const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0; - const bool has_multires = mmd != NULL && BKE_multires_sculpt_level_get(mmd) > 0; + const bool has_multires = mmd != NULL && mmd->sculptlvl > 0; const ModifierEvalContext mectx = {depsgraph, &object_eval, 0}; if (is_sculpt_mode && has_multires) { @@ -395,15 +395,15 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, return numleft; } - md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData); + md = BKE_modifiers_get_virtual_modifierlist(&object_eval, &virtualModifierData); for (; md; md = md->next) { - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } if (crazyspace_modifier_supports_deform_matrices(md)) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (defmats == NULL) { /* NOTE: Evaluated object si re-set to its original undeformed * state. */ @@ -425,7 +425,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, } for (; md; md = md->next) { - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } @@ -471,16 +471,16 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, VirtualModifierData virtualModifierData; Object object_eval; crazyspace_init_object_for_eval(depsgraph, object, &object_eval); - ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(&object_eval, &virtualModifierData); const ModifierEvalContext mectx = {depsgraph, &object_eval, 0}; for (; md; md = md->next) { - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } if (crazyspace_modifier_supports_deform(md)) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); /* skip leading modifiers which have been already * handled in sculpt_get_first_deform_matrices */ diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index d8fd405b6e5..0798bc95797 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -52,6 +52,7 @@ #include "BKE_idtype.h" #include "BKE_key.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_object.h" @@ -117,6 +118,22 @@ static void curve_free_data(ID *id) MEM_SAFE_FREE(curve->tb); } +static void curve_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Curve *curve = (Curve *)id; + BKE_LIB_FOREACHID_PROCESS(data, curve->bevobj, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, curve->taperobj, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, curve->textoncurve, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, curve->key, IDWALK_CB_USER); + for (int i = 0; i < curve->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, curve->mat[i], IDWALK_CB_USER); + } + BKE_LIB_FOREACHID_PROCESS(data, curve->vfont, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, curve->vfontb, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, curve->vfonti, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, curve->vfontbi, IDWALK_CB_USER); +} + IDTypeInfo IDType_ID_CU = { .id_code = ID_CU, .id_filter = FILTER_ID_CU, @@ -131,6 +148,7 @@ IDTypeInfo IDType_ID_CU = { .copy_data = curve_copy_data, .free_data = curve_free_data, .make_local = NULL, + .foreach_id = curve_foreach_id, }; static int cu_isectLL(const float v1[3], @@ -5511,6 +5529,20 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int #undef MAT_NR_REMAP } +void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth) +{ + if (use_smooth) { + for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) { + nu->flag |= CU_SMOOTH; + } + } + else { + for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) { + nu->flag &= ~CU_SMOOTH; + } + } +} + void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 14f090f7825..a022f3f5d14 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -10,7 +10,7 @@ * 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, + * 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) 2006 Blender Foundation. diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 55fdfdac63a..a3e1eeb89c7 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -805,7 +805,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, const bool editmode) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); ModifierData *pretessellatePoint; int required_mode; @@ -822,9 +822,9 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, pretessellatePoint = NULL; for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (!modifier_isEnabled(scene, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; } if (mti->type == eModifierTypeType_Constructive) { @@ -853,31 +853,31 @@ static bool curve_calc_modifiers_pre( Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, const bool for_render) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); ModifierData *pretessellatePoint; Curve *cu = ob->data; int numElems = 0, numVerts = 0; const bool editmode = (!for_render && (cu->editnurb || cu->editfont)); - ModifierApplyFlag app_flag = 0; + ModifierApplyFlag apply_flag = 0; float(*deformedVerts)[3] = NULL; float *keyVerts = NULL; int required_mode; bool modified = false; - modifiers_clearErrors(ob); + BKE_modifiers_clear_errors(ob); if (editmode) { - app_flag |= MOD_APPLY_USECACHE; + apply_flag |= MOD_APPLY_USECACHE; } if (for_render) { - app_flag |= MOD_APPLY_RENDER; + apply_flag |= MOD_APPLY_RENDER; required_mode = eModifierMode_Render; } else { required_mode = eModifierMode_Realtime; } - const ModifierEvalContext mectx = {depsgraph, ob, app_flag}; + const ModifierEvalContext mectx = {depsgraph, ob, apply_flag}; pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode); @@ -901,9 +901,9 @@ static bool curve_calc_modifiers_pre( if (pretessellatePoint) { for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (!modifier_isEnabled(scene, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; } if (mti->type != eModifierTypeType_OnlyDeform) { @@ -982,7 +982,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, const bool force_mesh_conversion) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); ModifierData *pretessellatePoint; Curve *cu = ob->data; int required_mode = 0, totvert = 0; @@ -990,10 +990,10 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, Mesh *modified = NULL, *mesh_applied; float(*vertCos)[3] = NULL; int useCache = !for_render; - ModifierApplyFlag app_flag = 0; + ModifierApplyFlag apply_flag = 0; if (for_render) { - app_flag |= MOD_APPLY_RENDER; + apply_flag |= MOD_APPLY_RENDER; required_mode = eModifierMode_Render; } else { @@ -1001,9 +1001,9 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, } const ModifierEvalContext mectx_deform = { - depsgraph, ob, editmode ? app_flag | MOD_APPLY_USECACHE : app_flag}; + depsgraph, ob, editmode ? apply_flag | MOD_APPLY_USECACHE : apply_flag}; const ModifierEvalContext mectx_apply = { - depsgraph, ob, useCache ? app_flag | MOD_APPLY_USECACHE : app_flag}; + depsgraph, ob, useCache ? apply_flag | MOD_APPLY_USECACHE : apply_flag}; pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode); @@ -1020,9 +1020,9 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, } for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (!modifier_isEnabled(scene, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; } @@ -1100,7 +1100,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, if (need_normal) { BKE_mesh_ensure_normals(modified); } - mesh_applied = mti->applyModifier(md, &mectx_apply, modified); + mesh_applied = mti->modifyMesh(md, &mectx_apply, modified); if (mesh_applied) { /* Modifier returned a new derived mesh */ diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index a704e199007..f3cc17f46f6 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -540,7 +540,7 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgr for (int i = 0; i < numobjects; i++) { Object *brushObj = objects[i]; - ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); + ModifierData *md = BKE_modifiers_findby_type(brushObj, eModifierType_DynamicPaint); if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md; @@ -653,15 +653,15 @@ static void grid_bound_insert_cb_ex(void *__restrict userdata, boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v); } -static void grid_bound_insert_finalize(void *__restrict userdata, void *__restrict userdata_chunk) +static void grid_bound_insert_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - PaintBakeData *bData = userdata; - VolumeGrid *grid = bData->grid; - - Bounds3D *grid_bound = userdata_chunk; + Bounds3D *join = chunk_join; + Bounds3D *grid_bound = chunk; - boundInsert(&grid->grid_bounds, grid_bound->min); - boundInsert(&grid->grid_bounds, grid_bound->max); + boundInsert(join, grid_bound->min); + boundInsert(join, grid_bound->max); } static void grid_cell_points_cb_ex(void *__restrict userdata, @@ -685,17 +685,20 @@ static void grid_cell_points_cb_ex(void *__restrict userdata, s_num[temp_t_index[i]]++; } -static void grid_cell_points_finalize(void *__restrict userdata, void *__restrict userdata_chunk) +static void grid_cell_points_reduce(const void *__restrict userdata, + void *__restrict chunk_join, + void *__restrict chunk) { - PaintBakeData *bData = userdata; - VolumeGrid *grid = bData->grid; + const PaintBakeData *bData = userdata; + const VolumeGrid *grid = bData->grid; const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2]; - int *s_num = userdata_chunk; + int *join_s_num = chunk_join; + int *s_num = chunk; /* calculate grid indexes */ for (int i = 0; i < grid_cells; i++) { - grid->s_num[i] += s_num[i]; + join_s_num[i] += s_num[i]; } } @@ -753,7 +756,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) settings.use_threading = (sData->total_points > 1000); settings.userdata_chunk = &grid->grid_bounds; settings.userdata_chunk_size = sizeof(grid->grid_bounds); - settings.func_finalize = grid_bound_insert_finalize; + settings.func_reduce = grid_bound_insert_reduce; BLI_task_parallel_range(0, sData->total_points, bData, grid_bound_insert_cb_ex, &settings); } /* get dimensions */ @@ -814,7 +817,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) settings.use_threading = (sData->total_points > 1000); settings.userdata_chunk = grid->s_num; settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells; - settings.func_finalize = grid_cell_points_finalize; + settings.func_reduce = grid_cell_points_reduce; BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings); } @@ -1096,7 +1099,7 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c surface->wave_spring = 0.20f; surface->wave_smoothness = 1.0f; - modifier_path_init( + BKE_modifier_path_init( surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint"); /* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */ @@ -4643,9 +4646,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, return 1; } - /* begin thread safe malloc */ - BLI_threaded_malloc_begin(); - /* only continue if particle bb is close enough to canvas bb */ if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) { int c_index; @@ -4681,7 +4681,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, &settings); } } - BLI_threaded_malloc_end(); BLI_kdtree_3d_free(tree); return 1; @@ -4882,7 +4881,7 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, cons 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings); /* calculate average values (single thread). - * Note: tried to put this in threaded callback (using _finalize feature), + * Note: tried to put this in threaded callback (using _reduce feature), * but gave ~30% slower result! */ bData->average_dist = 0.0; for (index = 0; index < sData->total_points; index++) { @@ -6245,7 +6244,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph, Object *brushObj = objects[i]; /* check if target has an active dp modifier */ - ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); + ModifierData *md = BKE_modifiers_findby_type(brushObj, eModifierType_DynamicPaint); if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md; /* make sure we're dealing with a brush */ diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c index c3ae2a54e13..6fcaf84d4ca 100644 --- a/source/blender/blenkernel/intern/editmesh_tangent.c +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -251,9 +251,7 @@ finally: pRes[3] = fSign; } -static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) { struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; /* new computation method */ @@ -362,9 +360,8 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, #endif /* Calculation */ if (em->tottri != 0) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW); tangent_mask_curr = 0; /* Calculate tangent layers */ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index e1e818a5a34..fe2c9ed51b8 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -113,7 +113,7 @@ PartDeflect *BKE_partdeflect_new(int type) case PFIELD_TEXTURE: pd->f_size = 1.0f; break; - case PFIELD_SMOKEFLOW: + case PFIELD_FLUIDFLOW: pd->f_flow = 1.0f; break; } @@ -177,7 +177,7 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef } } else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) { - eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface); + eff->surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(eff->ob, eModifierType_Surface); if (eff->ob->type == OB_CURVE) { eff->flag |= PE_USE_NORMAL_DATA; } @@ -1024,7 +1024,7 @@ static void do_physical_effector(EffectorCache *eff, mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp)); break; - case PFIELD_SMOKEFLOW: + case PFIELD_FLUIDFLOW: zero_v3(force); #ifdef WITH_FLUID if (pd->f_source) { @@ -1046,7 +1046,7 @@ static void do_physical_effector(EffectorCache *eff, if (pd->flag & PFIELD_DO_LOCATION) { madd_v3_v3fl(total_force, force, 1.0f / point->vel_to_sec); - if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW) == 0 && + if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_FLUIDFLOW) == 0 && pd->f_flow != 0.0f) { madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff); } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index a75f89435c8..5d2207b5b80 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -30,49 +30,28 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" -#include "DNA_constraint_types.h" #include "DNA_object_types.h" -#include "BLI_alloca.h" #include "BLI_blenlib.h" #include "BLI_easing.h" -#include "BLI_expr_pylike_eval.h" #include "BLI_math.h" -#include "BLI_string_utils.h" -#include "BLI_threads.h" -#include "BLI_utildefines.h" -#include "BLT_translation.h" - -#include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_animsys.h" -#include "BKE_armature.h" -#include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_nla.h" -#include "BKE_object.h" #include "RNA_access.h" -#include "atomic_ops.h" - #include "CLG_log.h" -#ifdef WITH_PYTHON -# include "BPY_extern.h" -#endif - #define SMALL -1.0e-10 #define SELECT 1 -#ifdef WITH_PYTHON -static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; -#endif - static CLG_LogRef LOG = {"bke.fcurve"}; /* ************************** Data-Level Functions ************************* */ @@ -1256,1236 +1235,6 @@ short test_time_fcurve(FCurve *fcu) return 0; } -/* ***************************** Drivers ********************************* */ - -/* Driver Variables --------------------------- */ - -/* TypeInfo for Driver Variables (dvti) */ -typedef struct DriverVarTypeInfo { - /* evaluation callback */ - float (*get_value)(ChannelDriver *driver, DriverVar *dvar); - - /* allocation of target slots */ - int num_targets; /* number of target slots required */ - const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */ - short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */ -} DriverVarTypeInfo; - -/* Macro to begin definitions */ -#define BEGIN_DVAR_TYPEDEF(type) { - -/* Macro to end definitions */ -#define END_DVAR_TYPEDEF } - -/* ......... */ - -static ID *dtar_id_ensure_proxy_from(ID *id) -{ - if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) { - return (ID *)(((Object *)id)->proxy_from); - } - return id; -} - -/** - * Helper function to obtain a value using RNA from the specified source - * (for evaluating drivers). - */ -static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar) -{ - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - ID *id; - int index = -1; - float value = 0.0f; - - /* sanity check */ - if (ELEM(NULL, driver, dtar)) { - return 0.0f; - } - - id = dtar_id_ensure_proxy_from(dtar->id); - - /* error check for missing pointer... */ - if (id == NULL) { - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - - /* get RNA-pointer for the ID-block given in target */ - RNA_id_pointer_create(id, &id_ptr); - - /* get property to read from, and get value as appropriate */ - if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { - /* path couldn't be resolved */ - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, - "Driver Evaluation Error: cannot resolve target for %s -> %s", - id->name, - dtar->rna_path); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - - if (RNA_property_array_check(prop)) { - /* array */ - if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) { - /* out of bounds */ - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, - "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)", - id->name, - dtar->rna_path, - index); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - value = (float)RNA_property_boolean_get_index(&ptr, prop, index); - break; - case PROP_INT: - value = (float)RNA_property_int_get_index(&ptr, prop, index); - break; - case PROP_FLOAT: - value = RNA_property_float_get_index(&ptr, prop, index); - break; - default: - break; - } - } - else { - /* not an array */ - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - value = (float)RNA_property_boolean_get(&ptr, prop); - break; - case PROP_INT: - value = (float)RNA_property_int_get(&ptr, prop); - break; - case PROP_FLOAT: - value = RNA_property_float_get(&ptr, prop); - break; - case PROP_ENUM: - value = (float)RNA_property_enum_get(&ptr, prop); - break; - default: - break; - } - } - - /* if we're still here, we should be ok... */ - dtar->flag &= ~DTAR_FLAG_INVALID; - return value; -} - -/** - * Same as 'dtar_get_prop_val'. but get the RNA property. - */ -bool driver_get_variable_property(ChannelDriver *driver, - DriverTarget *dtar, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index) -{ - PointerRNA id_ptr; - PointerRNA ptr; - PropertyRNA *prop; - ID *id; - int index = -1; - - /* sanity check */ - if (ELEM(NULL, driver, dtar)) { - return false; - } - - id = dtar_id_ensure_proxy_from(dtar->id); - - /* error check for missing pointer... */ - if (id == NULL) { - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); - } - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return false; - } - - /* get RNA-pointer for the ID-block given in target */ - RNA_id_pointer_create(id, &id_ptr); - - /* get property to read from, and get value as appropriate */ - if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') { - ptr = PointerRNA_NULL; - prop = NULL; /* ok */ - } - else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { - /* ok */ - } - else { - /* path couldn't be resolved */ - if (G.debug & G_DEBUG) { - CLOG_ERROR(&LOG, - "Driver Evaluation Error: cannot resolve target for %s -> %s", - id->name, - dtar->rna_path); - } - - ptr = PointerRNA_NULL; - *r_prop = NULL; - *r_index = -1; - - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return false; - } - - *r_ptr = ptr; - *r_prop = prop; - *r_index = index; - - /* if we're still here, we should be ok... */ - dtar->flag &= ~DTAR_FLAG_INVALID; - return true; -} - -static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar) -{ - short valid_targets = 0; - - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - - /* check if this target has valid data */ - if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { - /* invalid target, so will not have enough targets */ - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - } - else { - /* target seems to be OK now... */ - dtar->flag &= ~DTAR_FLAG_INVALID; - valid_targets++; - } - } - DRIVER_TARGETS_LOOPER_END; - - return valid_targets; -} - -/* ......... */ - -/* evaluate 'single prop' driver variable */ -static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar) -{ - /* just evaluate the first target slot */ - return dtar_get_prop_val(driver, &dvar->targets[0]); -} - -/* evaluate 'rotation difference' driver variable */ -static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) -{ - short valid_targets = driver_check_valid_targets(driver, dvar); - - /* make sure we have enough valid targets to use - all or nothing for now... */ - if (driver_check_valid_targets(driver, dvar) != 2) { - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, - "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", - valid_targets, - dvar->targets[0].id, - dvar->targets[1].id); - } - return 0.0f; - } - - float(*mat[2])[4]; - - /* NOTE: for now, these are all just worldspace */ - for (int i = 0; i < 2; i++) { - /* get pointer to loc values to store in */ - DriverTarget *dtar = &dvar->targets[i]; - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - bPoseChannel *pchan; - - /* after the checks above, the targets should be valid here... */ - BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); - - /* try to get posechannel */ - pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - - /* check if object or bone */ - if (pchan) { - /* bone */ - mat[i] = pchan->pose_mat; - } - else { - /* object */ - mat[i] = ob->obmat; - } - } - - float q1[4], q2[4], quat[4], angle; - - /* use the final posed locations */ - mat4_to_quat(q1, mat[0]); - mat4_to_quat(q2, mat[1]); - - invert_qt_normalized(q1); - mul_qt_qtqt(quat, q1, q2); - angle = 2.0f * (saacos(quat[0])); - angle = fabsf(angle); - - return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle); -} - -/* evaluate 'location difference' driver variable */ -/* TODO: this needs to take into account space conversions... */ -static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) -{ - float loc1[3] = {0.0f, 0.0f, 0.0f}; - float loc2[3] = {0.0f, 0.0f, 0.0f}; - short valid_targets = driver_check_valid_targets(driver, dvar); - - /* make sure we have enough valid targets to use - all or nothing for now... */ - if (valid_targets < dvar->num_targets) { - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, - "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", - valid_targets, - dvar->targets[0].id, - dvar->targets[1].id); - } - return 0.0f; - } - - /* SECOND PASS: get two location values */ - /* NOTE: for now, these are all just worldspace */ - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - /* get pointer to loc values to store in */ - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - bPoseChannel *pchan; - float tmp_loc[3]; - - /* after the checks above, the targets should be valid here... */ - BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); - - /* try to get posechannel */ - pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - - /* check if object or bone */ - if (pchan) { - /* bone */ - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - float mat[4][4]; - - /* extract transform just like how the constraints do it! */ - copy_m4_m4(mat, pchan->pose_mat); - BKE_constraint_mat_convertspace( - ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); - - /* ... and from that, we get our transform */ - copy_v3_v3(tmp_loc, mat[3]); - } - else { - /* transform space (use transform values directly) */ - copy_v3_v3(tmp_loc, pchan->loc); - } - } - else { - /* convert to worldspace */ - copy_v3_v3(tmp_loc, pchan->pose_head); - mul_m4_v3(ob->obmat, tmp_loc); - } - } - else { - /* object */ - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - /* XXX: this should practically be the same as transform space... */ - float mat[4][4]; - - /* extract transform just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace( - ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); - - /* ... and from that, we get our transform */ - copy_v3_v3(tmp_loc, mat[3]); - } - else { - /* transform space (use transform values directly) */ - copy_v3_v3(tmp_loc, ob->loc); - } - } - else { - /* worldspace */ - copy_v3_v3(tmp_loc, ob->obmat[3]); - } - } - - /* copy the location to the right place */ - if (tarIndex) { - copy_v3_v3(loc2, tmp_loc); - } - else { - copy_v3_v3(loc1, tmp_loc); - } - } - DRIVER_TARGETS_LOOPER_END; - - /* if we're still here, there should now be two targets to use, - * so just take the length of the vector between these points - */ - return len_v3v3(loc1, loc2); -} - -/* evaluate 'transform channel' driver variable */ -static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) -{ - DriverTarget *dtar = &dvar->targets[0]; - Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); - bPoseChannel *pchan; - float mat[4][4]; - float oldEul[3] = {0.0f, 0.0f, 0.0f}; - bool use_eulers = false; - short rot_order = ROT_MODE_EUL; - - /* check if this target has valid data */ - if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { - /* invalid target, so will not have enough targets */ - driver->flag |= DRIVER_FLAG_INVALID; - dtar->flag |= DTAR_FLAG_INVALID; - return 0.0f; - } - else { - /* target should be valid now */ - dtar->flag &= ~DTAR_FLAG_INVALID; - } - - /* try to get posechannel */ - pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - - /* check if object or bone, and get transform matrix accordingly - * - "useEulers" code is used to prevent the problems associated with non-uniqueness - * of euler decomposition from matrices [#20870] - * - localspace is for [#21384], where parent results are not wanted - * but local-consts is for all the common "corrective-shapes-for-limbs" situations - */ - if (pchan) { - /* bone */ - if (pchan->rotmode > 0) { - copy_v3_v3(oldEul, pchan->eul); - rot_order = pchan->rotmode; - use_eulers = true; - } - - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - /* just like how the constraints do it! */ - copy_m4_m4(mat, pchan->pose_mat); - BKE_constraint_mat_convertspace( - ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); - } - else { - /* specially calculate local matrix, since chan_mat is not valid - * since it stores delta transform of pose_mat so that deforms work - * so it cannot be used here for "transform" space - */ - BKE_pchan_to_mat4(pchan, mat); - } - } - else { - /* worldspace matrix */ - mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); - } - } - else { - /* object */ - if (ob->rotmode > 0) { - copy_v3_v3(oldEul, ob->rot); - rot_order = ob->rotmode; - use_eulers = true; - } - - if (dtar->flag & DTAR_FLAG_LOCALSPACE) { - if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { - /* just like how the constraints do it! */ - copy_m4_m4(mat, ob->obmat); - BKE_constraint_mat_convertspace( - ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); - } - else { - /* transforms to matrix */ - BKE_object_to_mat4(ob, mat); - } - } - else { - /* worldspace matrix - just the good-old one */ - copy_m4_m4(mat, ob->obmat); - } - } - - /* check which transform */ - if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) { - /* not valid channel */ - return 0.0f; - } - else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) { - /* Cubic root of the change in volume, equal to the geometric mean - * of scale over all three axes unless the matrix includes shear. */ - return cbrtf(mat4_to_volume_scale(mat)); - } - else if (ELEM(dtar->transChan, - DTAR_TRANSCHAN_SCALEX, - DTAR_TRANSCHAN_SCALEY, - DTAR_TRANSCHAN_SCALEZ)) { - /* Extract scale, and choose the right axis, - * inline 'mat4_to_size'. */ - return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]); - } - else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) { - /* extract rotation as eulers (if needed) - * - definitely if rotation order isn't eulers already - * - if eulers, then we have 2 options: - * a) decompose transform matrix as required, then try to make eulers from - * there compatible with original values - * b) [NOT USED] directly use the original values (no decomposition) - * - only an option for "transform space", if quality is really bad with a) - */ - float quat[4]; - int channel; - - if (dtar->transChan == DTAR_TRANSCHAN_ROTW) { - channel = 0; - } - else { - channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX; - BLI_assert(channel < 4); - } - - BKE_driver_target_matrix_to_rot_channels( - mat, rot_order, dtar->rotation_mode, channel, false, quat); - - if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) { - compatible_eul(quat + 1, oldEul); - } - - return quat[channel]; - } - else { - /* extract location and choose right axis */ - return mat[3][dtar->transChan]; - } -} - -/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */ -static void quaternion_to_angles(float quat[4], int channel) -{ - if (channel < 0) { - quat[0] = 2.0f * saacosf(quat[0]); - - for (int i = 1; i < 4; i++) { - quat[i] = 2.0f * saasinf(quat[i]); - } - } - else if (channel == 0) { - quat[0] = 2.0f * saacosf(quat[0]); - } - else { - quat[channel] = 2.0f * saasinf(quat[channel]); - } -} - -/* Compute channel values for a rotational Transform Channel driver variable. */ -void BKE_driver_target_matrix_to_rot_channels( - float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]) -{ - float *const quat = r_buf; - float *const eul = r_buf + 1; - - zero_v4(r_buf); - - if (rotation_mode == DTAR_ROTMODE_AUTO) { - mat4_to_eulO(eul, auto_order, mat); - } - else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) { - mat4_to_eulO(eul, rotation_mode, mat); - } - else if (rotation_mode == DTAR_ROTMODE_QUATERNION) { - mat4_to_quat(quat, mat); - - /* For Transformation constraint convenience, convert to pseudo-angles. */ - if (angles) { - quaternion_to_angles(quat, channel); - } - } - else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X && - rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) { - int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X; - float raw_quat[4], twist; - - mat4_to_quat(raw_quat, mat); - - if (channel == axis + 1) { - /* If only the twist angle is needed, skip computing swing. */ - twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL); - } - else { - twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL); - - quaternion_to_angles(quat, channel); - } - - quat[axis + 1] = twist; - } - else { - BLI_assert(false); - } -} - -/* ......... */ - -/* Table of Driver Variable Type Info Data */ -static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = { - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */ - 1, /* number of targets used */ - {"Property"}, /* UI names for targets */ - {0} /* flags */ - END_DVAR_TYPEDEF, - - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */ - 2, /* number of targets used */ - {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ - {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, - DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ - END_DVAR_TYPEDEF, - - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */ - 2, /* number of targets used */ - {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ - {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, - DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ - END_DVAR_TYPEDEF, - - BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */ - 1, /* number of targets used */ - {"Object/Bone"}, /* UI names for targets */ - {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ - END_DVAR_TYPEDEF, -}; - -/* Get driver variable typeinfo */ -static const DriverVarTypeInfo *get_dvar_typeinfo(int type) -{ - /* check if valid type */ - if ((type >= 0) && (type < MAX_DVAR_TYPES)) { - return &dvar_types[type]; - } - else { - return NULL; - } -} - -/* Driver API --------------------------------- */ - -/* Perform actual freeing driver variable and remove it from the given list */ -void driver_free_variable(ListBase *variables, DriverVar *dvar) -{ - /* sanity checks */ - if (dvar == NULL) { - return; - } - - /* free target vars - * - need to go over all of them, not just up to the ones that are used - * currently, since there may be some lingering RNA paths from - * previous users needing freeing - */ - DRIVER_TARGETS_LOOPER_BEGIN (dvar) { - /* free RNA path if applicable */ - if (dtar->rna_path) { - MEM_freeN(dtar->rna_path); - } - } - DRIVER_TARGETS_LOOPER_END; - - /* remove the variable from the driver */ - BLI_freelinkN(variables, dvar); -} - -/* Free the driver variable and do extra updates */ -void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar) -{ - /* remove and free the driver variable */ - driver_free_variable(&driver->variables, dvar); - - /* since driver variables are cached, the expression needs re-compiling too */ - BKE_driver_invalidate_expression(driver, false, true); -} - -/* Copy driver variables from src_vars list to dst_vars list */ -void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars) -{ - BLI_assert(BLI_listbase_is_empty(dst_vars)); - BLI_duplicatelist(dst_vars, src_vars); - - LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) { - /* need to go over all targets so that we don't leave any dangling paths */ - DRIVER_TARGETS_LOOPER_BEGIN (dvar) { - /* make a copy of target's rna path if available */ - if (dtar->rna_path) { - dtar->rna_path = MEM_dupallocN(dtar->rna_path); - } - } - DRIVER_TARGETS_LOOPER_END; - } -} - -/* Change the type of driver variable */ -void driver_change_variable_type(DriverVar *dvar, int type) -{ - const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type); - - /* sanity check */ - if (ELEM(NULL, dvar, dvti)) { - return; - } - - /* set the new settings */ - dvar->type = type; - dvar->num_targets = dvti->num_targets; - - /* make changes to the targets based on the defines for these types - * NOTE: only need to make sure the ones we're using here are valid... - */ - DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - short flags = dvti->target_flags[tarIndex]; - - /* store the flags */ - dtar->flag = flags; - - /* object ID types only, or idtype not yet initialized */ - if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) { - dtar->idtype = ID_OB; - } - } - DRIVER_TARGETS_LOOPER_END; -} - -/* Validate driver name (after being renamed) */ -void driver_variable_name_validate(DriverVar *dvar) -{ - /* Special character blacklist */ - const char special_char_blacklist[] = { - '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\', - '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r', - }; - - /* sanity checks */ - if (dvar == NULL) { - return; - } - - /* clear all invalid-name flags */ - dvar->flag &= ~DVAR_ALL_INVALID_FLAGS; - - /* 0) Zero-length identifiers are not allowed */ - if (dvar->name[0] == '\0') { - dvar->flag |= DVAR_FLAG_INVALID_EMPTY; - } - - /* 1) Must start with a letter */ - /* XXX: We assume that valid unicode letters in other languages are ok too, - * hence the blacklisting. */ - if (IN_RANGE_INCL(dvar->name[0], '0', '9')) { - dvar->flag |= DVAR_FLAG_INVALID_START_NUM; - } - else if (dvar->name[0] == '_') { - /* NOTE: We don't allow names to start with underscores - * (i.e. it helps when ruling out security risks) */ - dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; - } - - /* 2) Must not contain invalid stuff in the middle of the string */ - if (strchr(dvar->name, ' ')) { - dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE; - } - if (strchr(dvar->name, '.')) { - dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT; - } - - /* 3) Check for special characters - Either at start, or in the middle */ - for (int i = 0; i < sizeof(special_char_blacklist); i++) { - char *match = strchr(dvar->name, special_char_blacklist[i]); - - if (match == dvar->name) { - dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; - } - else if (match != NULL) { - dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL; - } - } - - /* 4) Check if the name is a reserved keyword - * NOTE: These won't confuse Python, but it will be impossible to use the variable - * in an expression without Python misinterpreting what these are for - */ -#ifdef WITH_PYTHON - if (BPY_string_is_keyword(dvar->name)) { - dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD; - } -#endif - - /* If any these conditions match, the name is invalid */ - if (dvar->flag & DVAR_ALL_INVALID_FLAGS) { - dvar->flag |= DVAR_FLAG_INVALID_NAME; - } -} - -/* Add a new driver variable */ -DriverVar *driver_add_new_variable(ChannelDriver *driver) -{ - DriverVar *dvar; - - /* sanity checks */ - if (driver == NULL) { - return NULL; - } - - /* make a new variable */ - dvar = MEM_callocN(sizeof(DriverVar), "DriverVar"); - BLI_addtail(&driver->variables, dvar); - - /* give the variable a 'unique' name */ - strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var")); - BLI_uniquename(&driver->variables, - dvar, - CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"), - '_', - offsetof(DriverVar, name), - sizeof(dvar->name)); - - /* set the default type to 'single prop' */ - driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP); - - /* since driver variables are cached, the expression needs re-compiling too */ - BKE_driver_invalidate_expression(driver, false, true); - - /* return the target */ - return dvar; -} - -/* This frees the driver itself */ -void fcurve_free_driver(FCurve *fcu) -{ - ChannelDriver *driver; - DriverVar *dvar, *dvarn; - - /* sanity checks */ - if (ELEM(NULL, fcu, fcu->driver)) { - return; - } - driver = fcu->driver; - - /* free driver targets */ - for (dvar = driver->variables.first; dvar; dvar = dvarn) { - dvarn = dvar->next; - driver_free_variable_ex(driver, dvar); - } - -#ifdef WITH_PYTHON - /* free compiled driver expression */ - if (driver->expr_comp) { - BPY_DECREF(driver->expr_comp); - } -#endif - - BLI_expr_pylike_free(driver->expr_simple); - - /* Free driver itself, then set F-Curve's point to this to NULL - * (as the curve may still be used). */ - MEM_freeN(driver); - fcu->driver = NULL; -} - -/* This makes a copy of the given driver */ -ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver) -{ - ChannelDriver *ndriver; - - /* sanity checks */ - if (driver == NULL) { - return NULL; - } - - /* copy all data */ - ndriver = MEM_dupallocN(driver); - ndriver->expr_comp = NULL; - ndriver->expr_simple = NULL; - - /* copy variables */ - - /* to get rid of refs to non-copied data (that's still used on original) */ - BLI_listbase_clear(&ndriver->variables); - driver_variables_copy(&ndriver->variables, &driver->variables); - - /* return the new driver */ - return ndriver; -} - -/* Driver Expression Evaluation --------------- */ - -/* Index constants for the expression parameter array. */ -enum { - /* Index of the 'frame' variable. */ - VAR_INDEX_FRAME = 0, - /* Index of the first user-defined driver variable. */ - VAR_INDEX_CUSTOM -}; - -static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver) -{ - /* Prepare parameter names. */ - int names_len = BLI_listbase_count(&driver->variables); - const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM); - int i = VAR_INDEX_CUSTOM; - - names[VAR_INDEX_FRAME] = "frame"; - - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - names[i++] = dvar->name; - } - - return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM); -} - -static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr) -{ - /* Check if the 'frame' parameter is actually used. */ - return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME); -} - -static bool driver_evaluate_simple_expr(ChannelDriver *driver, - ExprPyLike_Parsed *expr, - float *result, - float time) -{ - /* Prepare parameter values. */ - int vars_len = BLI_listbase_count(&driver->variables); - double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM); - int i = VAR_INDEX_CUSTOM; - - vars[VAR_INDEX_FRAME] = time; - - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - vars[i++] = driver_get_variable_value(driver, dvar); - } - - /* Evaluate expression. */ - double result_val; - eExprPyLike_EvalStatus status = BLI_expr_pylike_eval( - expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val); - const char *message; - - switch (status) { - case EXPR_PYLIKE_SUCCESS: - if (isfinite(result_val)) { - *result = (float)result_val; - } - return true; - - case EXPR_PYLIKE_DIV_BY_ZERO: - case EXPR_PYLIKE_MATH_ERROR: - message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error"; - CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression); - - driver->flag |= DRIVER_FLAG_INVALID; - return true; - - default: - /* arriving here means a bug, not user error */ - CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression); - return false; - } -} - -/* Compile and cache the driver expression if necessary, with thread safety. */ -static bool driver_compile_simple_expr(ChannelDriver *driver) -{ - if (driver->expr_simple != NULL) { - return true; - } - - if (driver->type != DRIVER_TYPE_PYTHON) { - return false; - } - - /* It's safe to parse in multiple threads; at worst it'll - * waste some effort, but in return avoids mutex contention. */ - ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver); - - /* Store the result if the field is still NULL, or discard - * it if another thread got here first. */ - if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) { - BLI_expr_pylike_free(expr); - } - - return true; -} - -/* Try using the simple expression evaluator to compute the result of the driver. - * On success, stores the result and returns true; on failure result is set to 0. */ -static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, - ChannelDriver *driver_orig, - float *result, - float time) -{ - *result = 0.0f; - - return driver_compile_simple_expr(driver_orig) && - BLI_expr_pylike_is_valid(driver_orig->expr_simple) && - driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time); -} - -/* Check if the expression in the driver conforms to the simple subset. */ -bool BKE_driver_has_simple_expression(ChannelDriver *driver) -{ - return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple); -} - -/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive - * time dependencies nor special exceptions in the depsgraph evaluation. */ -static bool python_driver_exression_depends_on_time(const char *expression) -{ - if (expression[0] == '\0') { - /* Empty expression depends on nothing. */ - return false; - } - if (strchr(expression, '(') != NULL) { - /* Function calls are considered dependent on a time. */ - return true; - } - if (strstr(expression, "frame") != NULL) { - /* Variable `frame` depends on time. */ - /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */ - return true; - } - /* Possible indirect time relation s should be handled via variable targets. */ - return false; -} - -/* Check if the expression in the driver may depend on the current frame. */ -bool BKE_driver_expression_depends_on_time(ChannelDriver *driver) -{ - if (driver->type != DRIVER_TYPE_PYTHON) { - return false; - } - - if (BKE_driver_has_simple_expression(driver)) { - /* Simple expressions can be checked exactly. */ - return driver_check_simple_expr_depends_on_time(driver->expr_simple); - } - else { - /* Otherwise, heuristically scan the expression string for certain patterns. */ - return python_driver_exression_depends_on_time(driver->expression); - } -} - -/* Reset cached compiled expression data */ -void BKE_driver_invalidate_expression(ChannelDriver *driver, - bool expr_changed, - bool varname_changed) -{ - if (expr_changed || varname_changed) { - BLI_expr_pylike_free(driver->expr_simple); - driver->expr_simple = NULL; - } - -#ifdef WITH_PYTHON - if (expr_changed) { - driver->flag |= DRIVER_FLAG_RECOMPILE; - } - - if (varname_changed) { - driver->flag |= DRIVER_FLAG_RENAMEVAR; - } -#endif -} - -/* Driver Evaluation -------------------------- */ - -/* Evaluate a Driver Variable to get a value that contributes to the final */ -float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) -{ - const DriverVarTypeInfo *dvti; - - /* sanity check */ - if (ELEM(NULL, driver, dvar)) { - return 0.0f; - } - - /* call the relevant callbacks to get the variable value - * using the variable type info, storing the obtained value - * in dvar->curval so that drivers can be debugged - */ - dvti = get_dvar_typeinfo(dvar->type); - - if (dvti && dvti->get_value) { - dvar->curval = dvti->get_value(driver, dvar); - } - else { - dvar->curval = 0.0f; - } - - return dvar->curval; -} - -static void evaluate_driver_sum(ChannelDriver *driver) -{ - DriverVar *dvar; - - /* check how many variables there are first (i.e. just one?) */ - if (BLI_listbase_is_single(&driver->variables)) { - /* just one target, so just use that */ - dvar = driver->variables.first; - driver->curval = driver_get_variable_value(driver, dvar); - return; - } - - /* more than one target, so average the values of the targets */ - float value = 0.0f; - int tot = 0; - - /* loop through targets, adding (hopefully we don't get any overflow!) */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - value += driver_get_variable_value(driver, dvar); - tot++; - } - - /* perform operations on the total if appropriate */ - if (driver->type == DRIVER_TYPE_AVERAGE) { - driver->curval = tot ? (value / (float)tot) : 0.0f; - } - else { - driver->curval = value; - } -} - -static void evaluate_driver_min_max(ChannelDriver *driver) -{ - DriverVar *dvar; - float value = 0.0f; - - /* loop through the variables, getting the values and comparing them to existing ones */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* get value */ - float tmp_val = driver_get_variable_value(driver, dvar); - - /* store this value if appropriate */ - if (dvar->prev) { - /* check if greater/smaller than the baseline */ - if (driver->type == DRIVER_TYPE_MAX) { - /* max? */ - if (tmp_val > value) { - value = tmp_val; - } - } - else { - /* min? */ - if (tmp_val < value) { - value = tmp_val; - } - } - } - else { - /* first item - make this the baseline for comparisons */ - value = tmp_val; - } - } - - /* store value in driver */ - driver->curval = value; -} - -static void evaluate_driver_python(PathResolvedRNA *anim_rna, - ChannelDriver *driver, - ChannelDriver *driver_orig, - const float evaltime) -{ - /* check for empty or invalid expression */ - if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) { - driver->curval = 0.0f; - } - else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) { -#ifdef WITH_PYTHON - /* this evaluates the expression using Python, and returns its result: - * - on errors it reports, then returns 0.0f - */ - BLI_mutex_lock(&python_driver_lock); - - driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime); - - BLI_mutex_unlock(&python_driver_lock); -#else /* WITH_PYTHON*/ - UNUSED_VARS(anim_rna, evaltime); -#endif /* WITH_PYTHON*/ - } -} - -/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime" - * - "evaltime" is the frame at which F-Curve is being evaluated - * - has to return a float value - * - driver_orig is where we cache Python expressions, in case of COW - */ -float evaluate_driver(PathResolvedRNA *anim_rna, - ChannelDriver *driver, - ChannelDriver *driver_orig, - const float evaltime) -{ - /* check if driver can be evaluated */ - if (driver_orig->flag & DRIVER_FLAG_INVALID) { - return 0.0f; - } - - switch (driver->type) { - case DRIVER_TYPE_AVERAGE: /* average values of driver targets */ - case DRIVER_TYPE_SUM: /* sum values of driver targets */ - evaluate_driver_sum(driver); - break; - case DRIVER_TYPE_MIN: /* smallest value */ - case DRIVER_TYPE_MAX: /* largest value */ - evaluate_driver_min_max(driver); - break; - case DRIVER_TYPE_PYTHON: /* expression */ - evaluate_driver_python(anim_rna, driver, driver_orig, evaltime); - break; - default: - /* special 'hack' - just use stored value - * This is currently used as the mechanism which allows animated settings to be able - * to be changed via the UI. - */ - break; - } - - /* return value for driver */ - return driver->curval; -} - /* ***************************** Curve Calculations ********************************* */ /* The total length of the handles is not allowed to be more @@ -2666,437 +1415,327 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) /* -------------------------- */ -/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ -static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +static float fcurve_eval_keyframes_extrapolate( + FCurve *fcu, BezTriple *bezts, float evaltime, int endpoint_offset, int direction_to_neighbor) +{ + BezTriple *endpoint_bezt = bezts + endpoint_offset; /* The first/last keyframe. */ + BezTriple *neighbor_bezt = endpoint_bezt + + direction_to_neighbor; /* The second (to last) keyframe. */ + + if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT || + (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) { + /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend the + * endpoint's value. */ + return endpoint_bezt->vec[1][1]; + } + + if (endpoint_bezt->ipo == BEZT_IPO_LIN) { + /* Use the next center point instead of our own handle for linear interpolated extrapolate. */ + if (fcu->totvert == 1) { + return endpoint_bezt->vec[1][1]; + } + + float dx = endpoint_bezt->vec[1][0] - evaltime; + float fac = neighbor_bezt->vec[1][0] - endpoint_bezt->vec[1][0]; + + /* Prevent division by zero. */ + if (fac == 0.0f) { + return endpoint_bezt->vec[1][1]; + } + + fac = (neighbor_bezt->vec[1][1] - endpoint_bezt->vec[1][1]) / fac; + return endpoint_bezt->vec[1][1] - (fac * dx); + } + + /* Use the gradient of the second handle (later) of neighbour to calculate the gradient and thus + * the value of the curve at evaltime */ + int handle = direction_to_neighbor > 0 ? 0 : 2; + float dx = endpoint_bezt->vec[1][0] - evaltime; + float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0]; + + /* Prevent division by zero. */ + if (fac == 0.0f) { + return endpoint_bezt->vec[1][1]; + } + + fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[handle][1]) / fac; + return endpoint_bezt->vec[1][1] - (fac * dx); +} + +static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, float evaltime) { const float eps = 1.e-8f; - BezTriple *bezt, *prevbezt, *lastbezt; - float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac; + BezTriple *bezt, *prevbezt; unsigned int a; - int b; - float cvalue = 0.0f; - /* get pointers */ - a = fcu->totvert - 1; - prevbezt = bezts; - bezt = prevbezt + 1; - lastbezt = prevbezt + a; + /* evaltime occurs somewhere in the middle of the curve */ + bool exact = false; + + /* Use binary search to find appropriate keyframes... + * + * The threshold here has the following constraints: + * - 0.001 is too coarse: + * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332) + * + * - 0.00001 is too fine: + * Weird errors, like selecting the wrong keyframe range (see T39207), occur. + * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. + */ + a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); + bezt = bezts + a; - /* evaluation time at or past endpoints? */ - if (prevbezt->vec[1][0] >= evaltime) { - /* before or on first keyframe */ - if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) && - !(fcu->flag & FCURVE_DISCRETE_VALUES)) { - /* linear or bezier interpolation */ - if (prevbezt->ipo == BEZT_IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate - */ - if (fcu->totvert == 1) { - cvalue = prevbezt->vec[1][1]; - } - else { - bezt = prevbezt + 1; - dx = prevbezt->vec[1][0] - evaltime; - fac = bezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue = prevbezt->vec[1][1] - (fac * dx); - } - else { - cvalue = prevbezt->vec[1][1]; - } - } - } - else { - /* Use the first handle (earlier) of first BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ - dx = prevbezt->vec[1][0] - evaltime; - fac = prevbezt->vec[1][0] - prevbezt->vec[0][0]; + if (exact) { + /* index returned must be interpreted differently when it sits on top of an existing keyframe + * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) + */ + return bezt->vec[1][1]; + } - /* prevent division by zero */ - if (fac) { - fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac; - cvalue = prevbezt->vec[1][1] - (fac * dx); - } - else { - cvalue = prevbezt->vec[1][1]; - } - } - } - else { - /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, - * so just extend first keyframe's value - */ - cvalue = prevbezt->vec[1][1]; + /* index returned refers to the keyframe that the eval-time occurs *before* + * - hence, that keyframe marks the start of the segment we're dealing with + */ + prevbezt = (a > 0) ? (bezt - 1) : bezt; + + /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead. + * XXX: consult T39207 for examples of files where failure of these checks can cause issues */ + if (fabsf(bezt->vec[1][0] - evaltime) < eps) { + return bezt->vec[1][1]; + } + + if (evaltime < prevbezt->vec[1][0] || bezt->vec[1][0] < evaltime) { + if (G.debug & G_DEBUG) { + printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", + prevbezt->vec[1][0], + bezt->vec[1][0], + evaltime, + fabsf(bezt->vec[1][0] - evaltime)); } + return 0.0f; } - else if (lastbezt->vec[1][0] <= evaltime) { - /* after or on last keyframe */ - if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) && - !(fcu->flag & FCURVE_DISCRETE_VALUES)) { - /* linear or bezier interpolation */ - if (lastbezt->ipo == BEZT_IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate + + /* Evaltime occurs within the interval defined by these two keyframes. */ + const float begin = prevbezt->vec[1][1]; + const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; + const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; + const float time = evaltime - prevbezt->vec[1][0]; + const float amplitude = prevbezt->amplitude; + const float period = prevbezt->period; + + /* value depends on interpolation mode */ + if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || + (duration == 0)) { + /* constant (evaltime not relevant, so no interpolation needed) */ + return prevbezt->vec[1][1]; + } + + switch (prevbezt->ipo) { + /* interpolation ...................................... */ + case BEZT_IPO_BEZ: { + float v1[2], v2[2], v3[2], v4[2], opl[32]; + + /* bezier interpolation */ + /* (v1, v2) are the first keyframe and its 2nd handle */ + v1[0] = prevbezt->vec[1][0]; + v1[1] = prevbezt->vec[1][1]; + v2[0] = prevbezt->vec[2][0]; + v2[1] = prevbezt->vec[2][1]; + /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ + v3[0] = bezt->vec[0][0]; + v3[1] = bezt->vec[0][1]; + v4[0] = bezt->vec[1][0]; + v4[1] = bezt->vec[1][1]; + + if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && + fabsf(v3[1] - v4[1]) < FLT_EPSILON) { + /* Optimization: If all the handles are flat/at the same values, + * the value is simply the shared value (see T40372 -> F91346) */ - if (fcu->totvert == 1) { - cvalue = lastbezt->vec[1][1]; - } - else { - prevbezt = lastbezt - 1; - dx = evaltime - lastbezt->vec[1][0]; - fac = lastbezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue = lastbezt->vec[1][1] + (fac * dx); - } - else { - cvalue = lastbezt->vec[1][1]; - } + return v1[1]; + } + /* adjust handles so that they don't overlap (forming a loop) */ + correct_bezpart(v1, v2, v3, v4); + + /* try to get a value for this position - if failure, try another set of points */ + if (!findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl)) { + if (G.debug & G_DEBUG) { + printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", + evaltime, + v1[0], + v2[0], + v3[0], + v4[0]); } + return 0.0; } - else { - /* Use the gradient of the second handle (later) of last BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ - dx = evaltime - lastbezt->vec[1][0]; - fac = lastbezt->vec[2][0] - lastbezt->vec[1][0]; - /* prevent division by zero */ - if (fac) { - fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac; - cvalue = lastbezt->vec[1][1] + (fac * dx); - } - else { - cvalue = lastbezt->vec[1][1]; - } + berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); + return opl[0]; + } + case BEZT_IPO_LIN: + /* linear - simply linearly interpolate between values of the two keyframes */ + return BLI_easing_linear_ease(time, begin, change, duration); + + /* easing ............................................ */ + case BEZT_IPO_BACK: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); + case BEZT_IPO_EASE_OUT: + return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back); + + default: /* default/auto: same as ease out */ + return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); } - } - else { - /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, - * so just extend last keyframe's value - */ - cvalue = lastbezt->vec[1][1]; - } - } - else { - /* evaltime occurs somewhere in the middle of the curve */ - bool exact = false; - - /* Use binary search to find appropriate keyframes... - * - * The threshold here has the following constraints: - * - 0.001 is too coarse: - * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332) - * - * - 0.00001 is too fine: - * Weird errors, like selecting the wrong keyframe range (see T39207), occur. - * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd. - */ - a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact); + break; - if (exact) { - /* index returned must be interpreted differently when it sits on top of an existing keyframe - * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207) - */ - prevbezt = bezts + a; - bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt; - } - else { - /* index returned refers to the keyframe that the eval-time occurs *before* - * - hence, that keyframe marks the start of the segment we're dealing with - */ - bezt = bezts + a; - prevbezt = (a > 0) ? (bezt - 1) : bezt; - } + case BEZT_IPO_BOUNCE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_bounce_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_bounce_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_bounce_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease out */ + return BLI_easing_bounce_ease_out(time, begin, change, duration); + } + break; - /* use if the key is directly on the frame, - * rare cases this is needed else we get 0.0 instead. */ - /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */ - if (exact) { - cvalue = prevbezt->vec[1][1]; - } - else if (fabsf(bezt->vec[1][0] - evaltime) < eps) { - cvalue = bezt->vec[1][1]; - } - /* evaltime occurs within the interval defined by these two keyframes */ - else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) { - const float begin = prevbezt->vec[1][1]; - const float change = bezt->vec[1][1] - prevbezt->vec[1][1]; - const float duration = bezt->vec[1][0] - prevbezt->vec[1][0]; - const float time = evaltime - prevbezt->vec[1][0]; - const float amplitude = prevbezt->amplitude; - const float period = prevbezt->period; - - /* value depends on interpolation mode */ - if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || - (duration == 0)) { - /* constant (evaltime not relevant, so no interpolation needed) */ - cvalue = prevbezt->vec[1][1]; + case BEZT_IPO_CIRC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_circ_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_circ_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_circ_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_circ_ease_in(time, begin, change, duration); } - else { - switch (prevbezt->ipo) { - /* interpolation ...................................... */ - case BEZT_IPO_BEZ: - /* bezier interpolation */ - /* (v1, v2) are the first keyframe and its 2nd handle */ - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - v2[0] = prevbezt->vec[2][0]; - v2[1] = prevbezt->vec[2][1]; - /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ - v3[0] = bezt->vec[0][0]; - v3[1] = bezt->vec[0][1]; - v4[0] = bezt->vec[1][0]; - v4[1] = bezt->vec[1][1]; - - if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON && - fabsf(v3[1] - v4[1]) < FLT_EPSILON) { - /* Optimization: If all the handles are flat/at the same values, - * the value is simply the shared value (see T40372 -> F91346) - */ - cvalue = v1[1]; - } - else { - /* adjust handles so that they don't overlap (forming a loop) */ - correct_bezpart(v1, v2, v3, v4); - - /* try to get a value for this position - if failure, try another set of points */ - b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); - if (b) { - berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); - cvalue = opl[0]; - /* break; */ - } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", - evaltime, - v1[0], - v2[0], - v3[0], - v4[0]); - } - } - } - break; - - case BEZT_IPO_LIN: - /* linear - simply linearly interpolate between values of the two keyframes */ - cvalue = BLI_easing_linear_ease(time, begin, change, duration); - break; - - /* easing ............................................ */ - case BEZT_IPO_BACK: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_back_ease_in_out( - time, begin, change, duration, prevbezt->back); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back); - break; - } - break; - - case BEZT_IPO_BOUNCE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_CIRC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_circ_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_circ_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_CUBIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_ELASTIC: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_elastic_ease_in( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_elastic_ease_in_out( - time, begin, change, duration, amplitude, period); - break; - - default: /* default/auto: same as ease out */ - cvalue = BLI_easing_elastic_ease_out( - time, begin, change, duration, amplitude, period); - break; - } - break; - - case BEZT_IPO_EXPO: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_expo_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_expo_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUAD: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quad_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quad_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUART: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quart_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quart_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_QUINT: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_quint_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_quint_ease_in(time, begin, change, duration); - break; - } - break; - - case BEZT_IPO_SINE: - switch (prevbezt->easing) { - case BEZT_IPO_EASE_IN: - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - case BEZT_IPO_EASE_OUT: - cvalue = BLI_easing_sine_ease_out(time, begin, change, duration); - break; - case BEZT_IPO_EASE_IN_OUT: - cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration); - break; - - default: /* default/auto: same as ease in */ - cvalue = BLI_easing_sine_ease_in(time, begin, change, duration); - break; - } - break; + break; - default: - cvalue = prevbezt->vec[1][1]; - break; - } + case BEZT_IPO_CUBIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_cubic_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_cubic_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_cubic_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_cubic_ease_in(time, begin, change, duration); } - } - else { - if (G.debug & G_DEBUG) { - printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", - prevbezt->vec[1][0], - bezt->vec[1][0], - evaltime, - fabsf(bezt->vec[1][0] - evaltime)); + break; + + case BEZT_IPO_ELASTIC: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period); + case BEZT_IPO_EASE_OUT: + return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period); + + default: /* default/auto: same as ease out */ + return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); } - } + break; + + case BEZT_IPO_EXPO: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_expo_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_expo_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_expo_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_expo_ease_in(time, begin, change, duration); + } + break; + + case BEZT_IPO_QUAD: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_quad_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_quad_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_quad_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_quad_ease_in(time, begin, change, duration); + } + break; + + case BEZT_IPO_QUART: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_quart_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_quart_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_quart_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_quart_ease_in(time, begin, change, duration); + } + break; + + case BEZT_IPO_QUINT: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_quint_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_quint_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_quint_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_quint_ease_in(time, begin, change, duration); + } + break; + + case BEZT_IPO_SINE: + switch (prevbezt->easing) { + case BEZT_IPO_EASE_IN: + return BLI_easing_sine_ease_in(time, begin, change, duration); + case BEZT_IPO_EASE_OUT: + return BLI_easing_sine_ease_out(time, begin, change, duration); + case BEZT_IPO_EASE_IN_OUT: + return BLI_easing_sine_ease_in_out(time, begin, change, duration); + + default: /* default/auto: same as ease in */ + return BLI_easing_sine_ease_in(time, begin, change, duration); + } + break; + + default: + return prevbezt->vec[1][1]; } - /* return value */ - return cvalue; + return 0.0f; +} + +/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ +static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime) +{ + if (evaltime <= bezts->vec[1][0]) { + return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1); + } + + BezTriple *lastbezt = bezts + fcu->totvert - 1; + if (lastbezt->vec[1][0] <= evaltime) { + return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1); + } + + return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime); } /* Calculate F-Curve value for 'evaltime' using FPoint samples */ diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c new file mode 100644 index 00000000000..78a6cf28824 --- /dev/null +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -0,0 +1,1294 @@ +/* + * 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) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +// #include <float.h> +// #include <math.h> +// #include <stddef.h> +// #include <stdio.h> +// #include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" + +#include "BLI_alloca.h" +#include "BLI_expr_pylike_eval.h" +#include "BLI_math.h" +#include "BLI_string_utils.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_constraint.h" +#include "BKE_fcurve_driver.h" +#include "BKE_global.h" +#include "BKE_object.h" + +#include "RNA_access.h" + +#include "atomic_ops.h" + +#include "CLG_log.h" + +#ifdef WITH_PYTHON +# include "BPY_extern.h" +#endif + +#ifdef WITH_PYTHON +static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER; +#endif + +static CLG_LogRef LOG = {"bke.fcurve"}; + +/* Driver Variables --------------------------- */ + +/* TypeInfo for Driver Variables (dvti) */ +typedef struct DriverVarTypeInfo { + /* evaluation callback */ + float (*get_value)(ChannelDriver *driver, DriverVar *dvar); + + /* allocation of target slots */ + int num_targets; /* number of target slots required */ + const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */ + short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */ +} DriverVarTypeInfo; + +/* Macro to begin definitions */ +#define BEGIN_DVAR_TYPEDEF(type) { + +/* Macro to end definitions */ +#define END_DVAR_TYPEDEF } + +/* ......... */ + +static ID *dtar_id_ensure_proxy_from(ID *id) +{ + if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) { + return (ID *)(((Object *)id)->proxy_from); + } + return id; +} + +/** + * Helper function to obtain a value using RNA from the specified source + * (for evaluating drivers). + */ +static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar) +{ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + ID *id; + int index = -1; + float value = 0.0f; + + /* sanity check */ + if (ELEM(NULL, driver, dtar)) { + return 0.0f; + } + + id = dtar_id_ensure_proxy_from(dtar->id); + + /* error check for missing pointer... */ + if (id == NULL) { + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + + /* get RNA-pointer for the ID-block given in target */ + RNA_id_pointer_create(id, &id_ptr); + + /* get property to read from, and get value as appropriate */ + if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { + /* path couldn't be resolved */ + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, + "Driver Evaluation Error: cannot resolve target for %s -> %s", + id->name, + dtar->rna_path); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + + if (RNA_property_array_check(prop)) { + /* array */ + if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) { + /* out of bounds */ + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, + "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)", + id->name, + dtar->rna_path, + index); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + value = (float)RNA_property_boolean_get_index(&ptr, prop, index); + break; + case PROP_INT: + value = (float)RNA_property_int_get_index(&ptr, prop, index); + break; + case PROP_FLOAT: + value = RNA_property_float_get_index(&ptr, prop, index); + break; + default: + break; + } + } + else { + /* not an array */ + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + value = (float)RNA_property_boolean_get(&ptr, prop); + break; + case PROP_INT: + value = (float)RNA_property_int_get(&ptr, prop); + break; + case PROP_FLOAT: + value = RNA_property_float_get(&ptr, prop); + break; + case PROP_ENUM: + value = (float)RNA_property_enum_get(&ptr, prop); + break; + default: + break; + } + } + + /* if we're still here, we should be ok... */ + dtar->flag &= ~DTAR_FLAG_INVALID; + return value; +} + +/** + * Same as 'dtar_get_prop_val'. but get the RNA property. + */ +bool driver_get_variable_property(ChannelDriver *driver, + DriverTarget *dtar, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index) +{ + PointerRNA id_ptr; + PointerRNA ptr; + PropertyRNA *prop; + ID *id; + int index = -1; + + /* sanity check */ + if (ELEM(NULL, driver, dtar)) { + return false; + } + + id = dtar_id_ensure_proxy_from(dtar->id); + + /* error check for missing pointer... */ + if (id == NULL) { + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path); + } + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return false; + } + + /* get RNA-pointer for the ID-block given in target */ + RNA_id_pointer_create(id, &id_ptr); + + /* get property to read from, and get value as appropriate */ + if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') { + ptr = PointerRNA_NULL; + prop = NULL; /* ok */ + } + else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) { + /* ok */ + } + else { + /* path couldn't be resolved */ + if (G.debug & G_DEBUG) { + CLOG_ERROR(&LOG, + "Driver Evaluation Error: cannot resolve target for %s -> %s", + id->name, + dtar->rna_path); + } + + ptr = PointerRNA_NULL; + *r_prop = NULL; + *r_index = -1; + + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return false; + } + + *r_ptr = ptr; + *r_prop = prop; + *r_index = index; + + /* if we're still here, we should be ok... */ + dtar->flag &= ~DTAR_FLAG_INVALID; + return true; +} + +static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar) +{ + short valid_targets = 0; + + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + + /* check if this target has valid data */ + if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { + /* invalid target, so will not have enough targets */ + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + } + else { + /* target seems to be OK now... */ + dtar->flag &= ~DTAR_FLAG_INVALID; + valid_targets++; + } + } + DRIVER_TARGETS_LOOPER_END; + + return valid_targets; +} + +/* ......... */ + +/* evaluate 'single prop' driver variable */ +static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar) +{ + /* just evaluate the first target slot */ + return dtar_get_prop_val(driver, &dvar->targets[0]); +} + +/* evaluate 'rotation difference' driver variable */ +static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) +{ + short valid_targets = driver_check_valid_targets(driver, dvar); + + /* make sure we have enough valid targets to use - all or nothing for now... */ + if (driver_check_valid_targets(driver, dvar) != 2) { + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", + valid_targets, + dvar->targets[0].id, + dvar->targets[1].id); + } + return 0.0f; + } + + float(*mat[2])[4]; + + /* NOTE: for now, these are all just worldspace */ + for (int i = 0; i < 2; i++) { + /* get pointer to loc values to store in */ + DriverTarget *dtar = &dvar->targets[i]; + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + bPoseChannel *pchan; + + /* after the checks above, the targets should be valid here... */ + BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); + + /* try to get posechannel */ + pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + + /* check if object or bone */ + if (pchan) { + /* bone */ + mat[i] = pchan->pose_mat; + } + else { + /* object */ + mat[i] = ob->obmat; + } + } + + float q1[4], q2[4], quat[4], angle; + + /* use the final posed locations */ + mat4_to_quat(q1, mat[0]); + mat4_to_quat(q2, mat[1]); + + invert_qt_normalized(q1); + mul_qt_qtqt(quat, q1, q2); + angle = 2.0f * (saacos(quat[0])); + angle = fabsf(angle); + + return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle); +} + +/* evaluate 'location difference' driver variable */ +/* TODO: this needs to take into account space conversions... */ +static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) +{ + float loc1[3] = {0.0f, 0.0f, 0.0f}; + float loc2[3] = {0.0f, 0.0f, 0.0f}; + short valid_targets = driver_check_valid_targets(driver, dvar); + + /* make sure we have enough valid targets to use - all or nothing for now... */ + if (valid_targets < dvar->num_targets) { + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)", + valid_targets, + dvar->targets[0].id, + dvar->targets[1].id); + } + return 0.0f; + } + + /* SECOND PASS: get two location values */ + /* NOTE: for now, these are all just worldspace */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + /* get pointer to loc values to store in */ + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + bPoseChannel *pchan; + float tmp_loc[3]; + + /* after the checks above, the targets should be valid here... */ + BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB)); + + /* try to get posechannel */ + pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + + /* check if object or bone */ + if (pchan) { + /* bone */ + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + BKE_constraint_mat_convertspace( + ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); + + /* ... and from that, we get our transform */ + copy_v3_v3(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + copy_v3_v3(tmp_loc, pchan->loc); + } + } + else { + /* convert to worldspace */ + copy_v3_v3(tmp_loc, pchan->pose_head); + mul_m4_v3(ob->obmat, tmp_loc); + } + } + else { + /* object */ + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* XXX: this should practically be the same as transform space... */ + float mat[4][4]; + + /* extract transform just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + BKE_constraint_mat_convertspace( + ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); + + /* ... and from that, we get our transform */ + copy_v3_v3(tmp_loc, mat[3]); + } + else { + /* transform space (use transform values directly) */ + copy_v3_v3(tmp_loc, ob->loc); + } + } + else { + /* worldspace */ + copy_v3_v3(tmp_loc, ob->obmat[3]); + } + } + + /* copy the location to the right place */ + if (tarIndex) { + copy_v3_v3(loc2, tmp_loc); + } + else { + copy_v3_v3(loc1, tmp_loc); + } + } + DRIVER_TARGETS_LOOPER_END; + + /* if we're still here, there should now be two targets to use, + * so just take the length of the vector between these points + */ + return len_v3v3(loc1, loc2); +} + +/* evaluate 'transform channel' driver variable */ +static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) +{ + DriverTarget *dtar = &dvar->targets[0]; + Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id); + bPoseChannel *pchan; + float mat[4][4]; + float oldEul[3] = {0.0f, 0.0f, 0.0f}; + bool use_eulers = false; + short rot_order = ROT_MODE_EUL; + + /* check if this target has valid data */ + if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) { + /* invalid target, so will not have enough targets */ + driver->flag |= DRIVER_FLAG_INVALID; + dtar->flag |= DTAR_FLAG_INVALID; + return 0.0f; + } + else { + /* target should be valid now */ + dtar->flag &= ~DTAR_FLAG_INVALID; + } + + /* try to get posechannel */ + pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); + + /* check if object or bone, and get transform matrix accordingly + * - "useEulers" code is used to prevent the problems associated with non-uniqueness + * of euler decomposition from matrices [#20870] + * - localspace is for [#21384], where parent results are not wanted + * but local-consts is for all the common "corrective-shapes-for-limbs" situations + */ + if (pchan) { + /* bone */ + if (pchan->rotmode > 0) { + copy_v3_v3(oldEul, pchan->eul); + rot_order = pchan->rotmode; + use_eulers = true; + } + + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, pchan->pose_mat); + BKE_constraint_mat_convertspace( + ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); + } + else { + /* specially calculate local matrix, since chan_mat is not valid + * since it stores delta transform of pose_mat so that deforms work + * so it cannot be used here for "transform" space + */ + BKE_pchan_to_mat4(pchan, mat); + } + } + else { + /* worldspace matrix */ + mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); + } + } + else { + /* object */ + if (ob->rotmode > 0) { + copy_v3_v3(oldEul, ob->rot); + rot_order = ob->rotmode; + use_eulers = true; + } + + if (dtar->flag & DTAR_FLAG_LOCALSPACE) { + if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { + /* just like how the constraints do it! */ + copy_m4_m4(mat, ob->obmat); + BKE_constraint_mat_convertspace( + ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); + } + else { + /* transforms to matrix */ + BKE_object_to_mat4(ob, mat); + } + } + else { + /* worldspace matrix - just the good-old one */ + copy_m4_m4(mat, ob->obmat); + } + } + + /* check which transform */ + if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) { + /* not valid channel */ + return 0.0f; + } + else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) { + /* Cubic root of the change in volume, equal to the geometric mean + * of scale over all three axes unless the matrix includes shear. */ + return cbrtf(mat4_to_volume_scale(mat)); + } + else if (ELEM(dtar->transChan, + DTAR_TRANSCHAN_SCALEX, + DTAR_TRANSCHAN_SCALEY, + DTAR_TRANSCHAN_SCALEZ)) { + /* Extract scale, and choose the right axis, + * inline 'mat4_to_size'. */ + return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]); + } + else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) { + /* extract rotation as eulers (if needed) + * - definitely if rotation order isn't eulers already + * - if eulers, then we have 2 options: + * a) decompose transform matrix as required, then try to make eulers from + * there compatible with original values + * b) [NOT USED] directly use the original values (no decomposition) + * - only an option for "transform space", if quality is really bad with a) + */ + float quat[4]; + int channel; + + if (dtar->transChan == DTAR_TRANSCHAN_ROTW) { + channel = 0; + } + else { + channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX; + BLI_assert(channel < 4); + } + + BKE_driver_target_matrix_to_rot_channels( + mat, rot_order, dtar->rotation_mode, channel, false, quat); + + if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) { + compatible_eul(quat + 1, oldEul); + } + + return quat[channel]; + } + else { + /* extract location and choose right axis */ + return mat[3][dtar->transChan]; + } +} + +/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */ +static void quaternion_to_angles(float quat[4], int channel) +{ + if (channel < 0) { + quat[0] = 2.0f * saacosf(quat[0]); + + for (int i = 1; i < 4; i++) { + quat[i] = 2.0f * saasinf(quat[i]); + } + } + else if (channel == 0) { + quat[0] = 2.0f * saacosf(quat[0]); + } + else { + quat[channel] = 2.0f * saasinf(quat[channel]); + } +} + +/* Compute channel values for a rotational Transform Channel driver variable. */ +void BKE_driver_target_matrix_to_rot_channels( + float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]) +{ + float *const quat = r_buf; + float *const eul = r_buf + 1; + + zero_v4(r_buf); + + if (rotation_mode == DTAR_ROTMODE_AUTO) { + mat4_to_eulO(eul, auto_order, mat); + } + else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) { + mat4_to_eulO(eul, rotation_mode, mat); + } + else if (rotation_mode == DTAR_ROTMODE_QUATERNION) { + mat4_to_quat(quat, mat); + + /* For Transformation constraint convenience, convert to pseudo-angles. */ + if (angles) { + quaternion_to_angles(quat, channel); + } + } + else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X && + rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) { + int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X; + float raw_quat[4], twist; + + mat4_to_quat(raw_quat, mat); + + if (channel == axis + 1) { + /* If only the twist angle is needed, skip computing swing. */ + twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL); + } + else { + twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL); + + quaternion_to_angles(quat, channel); + } + + quat[axis + 1] = twist; + } + else { + BLI_assert(false); + } +} + +/* ......... */ + +/* Table of Driver Variable Type Info Data */ +static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = { + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */ + 1, /* number of targets used */ + {"Property"}, /* UI names for targets */ + {0} /* flags */ + END_DVAR_TYPEDEF, + + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */ + 2, /* number of targets used */ + {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ + {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, + DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ + END_DVAR_TYPEDEF, + + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */ + 2, /* number of targets used */ + {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */ + {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, + DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ + END_DVAR_TYPEDEF, + + BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */ + 1, /* number of targets used */ + {"Object/Bone"}, /* UI names for targets */ + {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */ + END_DVAR_TYPEDEF, +}; + +/* Get driver variable typeinfo */ +static const DriverVarTypeInfo *get_dvar_typeinfo(int type) +{ + /* check if valid type */ + if ((type >= 0) && (type < MAX_DVAR_TYPES)) { + return &dvar_types[type]; + } + else { + return NULL; + } +} + +/* Driver API --------------------------------- */ + +/* Perform actual freeing driver variable and remove it from the given list */ +void driver_free_variable(ListBase *variables, DriverVar *dvar) +{ + /* sanity checks */ + if (dvar == NULL) { + return; + } + + /* free target vars + * - need to go over all of them, not just up to the ones that are used + * currently, since there may be some lingering RNA paths from + * previous users needing freeing + */ + DRIVER_TARGETS_LOOPER_BEGIN (dvar) { + /* free RNA path if applicable */ + if (dtar->rna_path) { + MEM_freeN(dtar->rna_path); + } + } + DRIVER_TARGETS_LOOPER_END; + + /* remove the variable from the driver */ + BLI_freelinkN(variables, dvar); +} + +/* Free the driver variable and do extra updates */ +void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar) +{ + /* remove and free the driver variable */ + driver_free_variable(&driver->variables, dvar); + + /* since driver variables are cached, the expression needs re-compiling too */ + BKE_driver_invalidate_expression(driver, false, true); +} + +/* Copy driver variables from src_vars list to dst_vars list */ +void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars) +{ + BLI_assert(BLI_listbase_is_empty(dst_vars)); + BLI_duplicatelist(dst_vars, src_vars); + + LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) { + /* need to go over all targets so that we don't leave any dangling paths */ + DRIVER_TARGETS_LOOPER_BEGIN (dvar) { + /* make a copy of target's rna path if available */ + if (dtar->rna_path) { + dtar->rna_path = MEM_dupallocN(dtar->rna_path); + } + } + DRIVER_TARGETS_LOOPER_END; + } +} + +/* Change the type of driver variable */ +void driver_change_variable_type(DriverVar *dvar, int type) +{ + const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type); + + /* sanity check */ + if (ELEM(NULL, dvar, dvti)) { + return; + } + + /* set the new settings */ + dvar->type = type; + dvar->num_targets = dvti->num_targets; + + /* make changes to the targets based on the defines for these types + * NOTE: only need to make sure the ones we're using here are valid... + */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + short flags = dvti->target_flags[tarIndex]; + + /* store the flags */ + dtar->flag = flags; + + /* object ID types only, or idtype not yet initialized */ + if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) { + dtar->idtype = ID_OB; + } + } + DRIVER_TARGETS_LOOPER_END; +} + +/* Validate driver name (after being renamed) */ +void driver_variable_name_validate(DriverVar *dvar) +{ + /* Special character blacklist */ + const char special_char_blacklist[] = { + '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\', + '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r', + }; + + /* sanity checks */ + if (dvar == NULL) { + return; + } + + /* clear all invalid-name flags */ + dvar->flag &= ~DVAR_ALL_INVALID_FLAGS; + + /* 0) Zero-length identifiers are not allowed */ + if (dvar->name[0] == '\0') { + dvar->flag |= DVAR_FLAG_INVALID_EMPTY; + } + + /* 1) Must start with a letter */ + /* XXX: We assume that valid unicode letters in other languages are ok too, + * hence the blacklisting. */ + if (IN_RANGE_INCL(dvar->name[0], '0', '9')) { + dvar->flag |= DVAR_FLAG_INVALID_START_NUM; + } + else if (dvar->name[0] == '_') { + /* NOTE: We don't allow names to start with underscores + * (i.e. it helps when ruling out security risks) */ + dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; + } + + /* 2) Must not contain invalid stuff in the middle of the string */ + if (strchr(dvar->name, ' ')) { + dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE; + } + if (strchr(dvar->name, '.')) { + dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT; + } + + /* 3) Check for special characters - Either at start, or in the middle */ + for (int i = 0; i < sizeof(special_char_blacklist); i++) { + char *match = strchr(dvar->name, special_char_blacklist[i]); + + if (match == dvar->name) { + dvar->flag |= DVAR_FLAG_INVALID_START_CHAR; + } + else if (match != NULL) { + dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL; + } + } + + /* 4) Check if the name is a reserved keyword + * NOTE: These won't confuse Python, but it will be impossible to use the variable + * in an expression without Python misinterpreting what these are for + */ +#ifdef WITH_PYTHON + if (BPY_string_is_keyword(dvar->name)) { + dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD; + } +#endif + + /* If any these conditions match, the name is invalid */ + if (dvar->flag & DVAR_ALL_INVALID_FLAGS) { + dvar->flag |= DVAR_FLAG_INVALID_NAME; + } +} + +/* Add a new driver variable */ +DriverVar *driver_add_new_variable(ChannelDriver *driver) +{ + DriverVar *dvar; + + /* sanity checks */ + if (driver == NULL) { + return NULL; + } + + /* make a new variable */ + dvar = MEM_callocN(sizeof(DriverVar), "DriverVar"); + BLI_addtail(&driver->variables, dvar); + + /* give the variable a 'unique' name */ + strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var")); + BLI_uniquename(&driver->variables, + dvar, + CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"), + '_', + offsetof(DriverVar, name), + sizeof(dvar->name)); + + /* set the default type to 'single prop' */ + driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP); + + /* since driver variables are cached, the expression needs re-compiling too */ + BKE_driver_invalidate_expression(driver, false, true); + + /* return the target */ + return dvar; +} + +/* This frees the driver itself */ +void fcurve_free_driver(FCurve *fcu) +{ + ChannelDriver *driver; + DriverVar *dvar, *dvarn; + + /* sanity checks */ + if (ELEM(NULL, fcu, fcu->driver)) { + return; + } + driver = fcu->driver; + + /* free driver targets */ + for (dvar = driver->variables.first; dvar; dvar = dvarn) { + dvarn = dvar->next; + driver_free_variable_ex(driver, dvar); + } + +#ifdef WITH_PYTHON + /* free compiled driver expression */ + if (driver->expr_comp) { + BPY_DECREF(driver->expr_comp); + } +#endif + + BLI_expr_pylike_free(driver->expr_simple); + + /* Free driver itself, then set F-Curve's point to this to NULL + * (as the curve may still be used). */ + MEM_freeN(driver); + fcu->driver = NULL; +} + +/* This makes a copy of the given driver */ +ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver) +{ + ChannelDriver *ndriver; + + /* sanity checks */ + if (driver == NULL) { + return NULL; + } + + /* copy all data */ + ndriver = MEM_dupallocN(driver); + ndriver->expr_comp = NULL; + ndriver->expr_simple = NULL; + + /* copy variables */ + + /* to get rid of refs to non-copied data (that's still used on original) */ + BLI_listbase_clear(&ndriver->variables); + driver_variables_copy(&ndriver->variables, &driver->variables); + + /* return the new driver */ + return ndriver; +} + +/* Driver Expression Evaluation --------------- */ + +/* Index constants for the expression parameter array. */ +enum { + /* Index of the 'frame' variable. */ + VAR_INDEX_FRAME = 0, + /* Index of the first user-defined driver variable. */ + VAR_INDEX_CUSTOM +}; + +static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver) +{ + /* Prepare parameter names. */ + int names_len = BLI_listbase_count(&driver->variables); + const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM); + int i = VAR_INDEX_CUSTOM; + + names[VAR_INDEX_FRAME] = "frame"; + + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + names[i++] = dvar->name; + } + + return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM); +} + +static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr) +{ + /* Check if the 'frame' parameter is actually used. */ + return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME); +} + +static bool driver_evaluate_simple_expr(ChannelDriver *driver, + ExprPyLike_Parsed *expr, + float *result, + float time) +{ + /* Prepare parameter values. */ + int vars_len = BLI_listbase_count(&driver->variables); + double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM); + int i = VAR_INDEX_CUSTOM; + + vars[VAR_INDEX_FRAME] = time; + + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + vars[i++] = driver_get_variable_value(driver, dvar); + } + + /* Evaluate expression. */ + double result_val; + eExprPyLike_EvalStatus status = BLI_expr_pylike_eval( + expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val); + const char *message; + + switch (status) { + case EXPR_PYLIKE_SUCCESS: + if (isfinite(result_val)) { + *result = (float)result_val; + } + return true; + + case EXPR_PYLIKE_DIV_BY_ZERO: + case EXPR_PYLIKE_MATH_ERROR: + message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error"; + CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression); + + driver->flag |= DRIVER_FLAG_INVALID; + return true; + + default: + /* arriving here means a bug, not user error */ + CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression); + return false; + } +} + +/* Compile and cache the driver expression if necessary, with thread safety. */ +static bool driver_compile_simple_expr(ChannelDriver *driver) +{ + if (driver->expr_simple != NULL) { + return true; + } + + if (driver->type != DRIVER_TYPE_PYTHON) { + return false; + } + + /* It's safe to parse in multiple threads; at worst it'll + * waste some effort, but in return avoids mutex contention. */ + ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver); + + /* Store the result if the field is still NULL, or discard + * it if another thread got here first. */ + if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) { + BLI_expr_pylike_free(expr); + } + + return true; +} + +/* Try using the simple expression evaluator to compute the result of the driver. + * On success, stores the result and returns true; on failure result is set to 0. */ +static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, + ChannelDriver *driver_orig, + float *result, + float time) +{ + *result = 0.0f; + + return driver_compile_simple_expr(driver_orig) && + BLI_expr_pylike_is_valid(driver_orig->expr_simple) && + driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time); +} + +/* Check if the expression in the driver conforms to the simple subset. */ +bool BKE_driver_has_simple_expression(ChannelDriver *driver) +{ + return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple); +} + +/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive + * time dependencies nor special exceptions in the depsgraph evaluation. */ +static bool python_driver_exression_depends_on_time(const char *expression) +{ + if (expression[0] == '\0') { + /* Empty expression depends on nothing. */ + return false; + } + if (strchr(expression, '(') != NULL) { + /* Function calls are considered dependent on a time. */ + return true; + } + if (strstr(expression, "frame") != NULL) { + /* Variable `frame` depends on time. */ + /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */ + return true; + } + /* Possible indirect time relation s should be handled via variable targets. */ + return false; +} + +/* Check if the expression in the driver may depend on the current frame. */ +bool BKE_driver_expression_depends_on_time(ChannelDriver *driver) +{ + if (driver->type != DRIVER_TYPE_PYTHON) { + return false; + } + + if (BKE_driver_has_simple_expression(driver)) { + /* Simple expressions can be checked exactly. */ + return driver_check_simple_expr_depends_on_time(driver->expr_simple); + } + else { + /* Otherwise, heuristically scan the expression string for certain patterns. */ + return python_driver_exression_depends_on_time(driver->expression); + } +} + +/* Reset cached compiled expression data */ +void BKE_driver_invalidate_expression(ChannelDriver *driver, + bool expr_changed, + bool varname_changed) +{ + if (expr_changed || varname_changed) { + BLI_expr_pylike_free(driver->expr_simple); + driver->expr_simple = NULL; + } + +#ifdef WITH_PYTHON + if (expr_changed) { + driver->flag |= DRIVER_FLAG_RECOMPILE; + } + + if (varname_changed) { + driver->flag |= DRIVER_FLAG_RENAMEVAR; + } +#endif +} + +/* Driver Evaluation -------------------------- */ + +/* Evaluate a Driver Variable to get a value that contributes to the final */ +float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) +{ + const DriverVarTypeInfo *dvti; + + /* sanity check */ + if (ELEM(NULL, driver, dvar)) { + return 0.0f; + } + + /* call the relevant callbacks to get the variable value + * using the variable type info, storing the obtained value + * in dvar->curval so that drivers can be debugged + */ + dvti = get_dvar_typeinfo(dvar->type); + + if (dvti && dvti->get_value) { + dvar->curval = dvti->get_value(driver, dvar); + } + else { + dvar->curval = 0.0f; + } + + return dvar->curval; +} + +static void evaluate_driver_sum(ChannelDriver *driver) +{ + DriverVar *dvar; + + /* check how many variables there are first (i.e. just one?) */ + if (BLI_listbase_is_single(&driver->variables)) { + /* just one target, so just use that */ + dvar = driver->variables.first; + driver->curval = driver_get_variable_value(driver, dvar); + return; + } + + /* more than one target, so average the values of the targets */ + float value = 0.0f; + int tot = 0; + + /* loop through targets, adding (hopefully we don't get any overflow!) */ + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + value += driver_get_variable_value(driver, dvar); + tot++; + } + + /* perform operations on the total if appropriate */ + if (driver->type == DRIVER_TYPE_AVERAGE) { + driver->curval = tot ? (value / (float)tot) : 0.0f; + } + else { + driver->curval = value; + } +} + +static void evaluate_driver_min_max(ChannelDriver *driver) +{ + DriverVar *dvar; + float value = 0.0f; + + /* loop through the variables, getting the values and comparing them to existing ones */ + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + /* get value */ + float tmp_val = driver_get_variable_value(driver, dvar); + + /* store this value if appropriate */ + if (dvar->prev) { + /* check if greater/smaller than the baseline */ + if (driver->type == DRIVER_TYPE_MAX) { + /* max? */ + if (tmp_val > value) { + value = tmp_val; + } + } + else { + /* min? */ + if (tmp_val < value) { + value = tmp_val; + } + } + } + else { + /* first item - make this the baseline for comparisons */ + value = tmp_val; + } + } + + /* store value in driver */ + driver->curval = value; +} + +static void evaluate_driver_python(PathResolvedRNA *anim_rna, + ChannelDriver *driver, + ChannelDriver *driver_orig, + const float evaltime) +{ + /* check for empty or invalid expression */ + if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) { + driver->curval = 0.0f; + } + else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) { +#ifdef WITH_PYTHON + /* this evaluates the expression using Python, and returns its result: + * - on errors it reports, then returns 0.0f + */ + BLI_mutex_lock(&python_driver_lock); + + driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime); + + BLI_mutex_unlock(&python_driver_lock); +#else /* WITH_PYTHON*/ + UNUSED_VARS(anim_rna, evaltime); +#endif /* WITH_PYTHON*/ + } +} + +/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime" + * - "evaltime" is the frame at which F-Curve is being evaluated + * - has to return a float value + * - driver_orig is where we cache Python expressions, in case of COW + */ +float evaluate_driver(PathResolvedRNA *anim_rna, + ChannelDriver *driver, + ChannelDriver *driver_orig, + const float evaltime) +{ + /* check if driver can be evaluated */ + if (driver_orig->flag & DRIVER_FLAG_INVALID) { + return 0.0f; + } + + switch (driver->type) { + case DRIVER_TYPE_AVERAGE: /* average values of driver targets */ + case DRIVER_TYPE_SUM: /* sum values of driver targets */ + evaluate_driver_sum(driver); + break; + case DRIVER_TYPE_MIN: /* smallest value */ + case DRIVER_TYPE_MAX: /* largest value */ + evaluate_driver_min_max(driver); + break; + case DRIVER_TYPE_PYTHON: /* expression */ + evaluate_driver_python(anim_rna, driver, driver_orig, evaltime); + break; + default: + /* special 'hack' - just use stored value + * This is currently used as the mechanism which allows animated settings to be able + * to be changed via the UI. + */ + break; + } + + /* return value for driver */ + return driver->curval; +} diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index c06cefbb493..b75592836e0 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -81,6 +81,8 @@ # include "RE_shader_ext.h" +# include "CLG_log.h" + # include "manta_fluid_API.h" #endif /* WITH_FLUID */ @@ -96,6 +98,8 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need #ifdef WITH_FLUID // #define DEBUG_PRINT +static CLG_LogRef LOG = {"bke.fluid"}; + /* -------------------------------------------------------------------- */ /** \name Fluid API * \{ */ @@ -346,7 +350,7 @@ void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) { char temp_dir[FILE_MAX]; int flags = mds->cache_flag; - const char *relbase = modifier_path_relbase_from_global(ob); + const char *relbase = BKE_modifier_path_relbase_from_global(ob); if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) { flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); @@ -487,32 +491,6 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *mds, mds->cell_size[2] /= (float)mds->base_res[2]; } -static void manta_set_domain_gravity(Scene *scene, FluidDomainSettings *mds) -{ - const float normalization_factor = 1.0f / 9.81f; - - /* Use global gravity if enabled. */ - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - float gravity[3]; - copy_v3_v3(gravity, scene->physics_settings.gravity); - /* Map default value to 1.0. */ - mul_v3_fl(gravity, normalization_factor); - - /* Convert gravity to domain space. */ - float gravity_mag = len_v3(gravity); - mul_mat3_m4_v3(mds->imat, gravity); - normalize_v3(gravity); - mul_v3_fl(gravity, gravity_mag); - - copy_v3_v3(mds->gravity, gravity); - } - else { - mul_v3_fl(mds->gravity, normalization_factor); - } - - mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); -} - static bool BKE_fluid_modifier_init( FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me) { @@ -523,8 +501,11 @@ static bool BKE_fluid_modifier_init( int res[3]; /* Set domain dimensions from mesh. */ manta_set_domain_from_mesh(mds, ob, me, true); - /* Set domain gravity. */ - manta_set_domain_gravity(scene, mds); + /* Set domain gravity, use global gravity if enabled. */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(mds->gravity, scene->physics_settings.gravity); + } + mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); /* Reset domain values. */ zero_v3_int(mds->shift); zero_v3(mds->shift_f); @@ -552,7 +533,6 @@ static bool BKE_fluid_modifier_init( /* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */ mds->dt = mds->frame_length; mds->time_per_frame = 0; - mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length; mmd->time = scene_framenr; @@ -948,11 +928,7 @@ static void sample_effector(FluidEffectorSettings *mes, velocity_map[index * 3 + 2] += hit_vel[2]; # ifdef DEBUG_PRINT /* Debugging: Print object velocities. */ - printf("adding effector object vel: [%f, %f, %f], dx is: %f\n", - hit_vel[0], - hit_vel[1], - hit_vel[2], - mds->dx); + printf("adding effector object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]); # endif } } @@ -1165,8 +1141,8 @@ static void update_obstacleflags(FluidDomainSettings *mds, /* Monitor active fields based on flow settings */ for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) { Object *coll_ob = coll_ob_array[coll_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(coll_ob, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -1238,8 +1214,8 @@ static void compute_obstaclesemission(Scene *scene, /* Prepare effector maps. */ for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) { Object *effecobj = effecobjs[effec_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -1411,8 +1387,8 @@ static void update_obstacles(Depsgraph *depsgraph, /* Prepare grids from effector objects. */ for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) { Object *effecobj = effecobjs[effec_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -1996,9 +1972,9 @@ static void sample_mesh(FluidFlowSettings *mfs, normalize_v3(hit_normal); /* Apply normal directional velocity. */ - velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f; - velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f; - velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f; + velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal; + velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal; + velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal; } /* Apply object velocity. */ if (has_velocity && mfs->vel_multi) { @@ -2651,8 +2627,8 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n /* Monitor active fields based on flow settings */ for (flow_index = 0; flow_index < numflowobj; flow_index++) { Object *flow_ob = flowobjs[flow_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flow_ob, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flow_ob, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -2782,8 +2758,8 @@ static void compute_flowsemission(Scene *scene, /* Prepare flow emission maps. */ for (int flow_index = 0; flow_index < numflowobjs; flow_index++) { Object *flowobj = flowobjs[flow_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -3002,8 +2978,8 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, /* Apply emission data for every flow object. */ for (int flow_index = 0; flow_index < numflowobjs; flow_index++) { Object *flowobj = flowobjs[flow_index]; - FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, - eModifierType_Fluid); + FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj, + eModifierType_Fluid); /* Sanity check. */ if (!mmd2) { @@ -3220,7 +3196,7 @@ static void update_effectors( { ListBase *effectors; /* make sure smoke flow influence is 0.0f */ - mds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; + mds->effector_weights->weight[PFIELD_FLUIDFLOW] = 0.0f; effectors = BKE_effectors_create(depsgraph, ob, NULL, mds->effector_weights); if (effectors) { @@ -3580,7 +3556,7 @@ static int manta_step( Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *mmd, int frame) { FluidDomainSettings *mds = mmd->domain; - float dt, frame_length, time_total; + float dt, frame_length, time_total, time_total_old; float time_per_frame; bool init_resolution = true; @@ -3604,6 +3580,8 @@ static int manta_step( dt = mds->dt; time_per_frame = 0; time_total = mds->time_total; + /* Keep track of original total time to correct small errors at end of step. */ + time_total_old = mds->time_total; BLI_mutex_lock(&object_update_lock); @@ -3649,6 +3627,8 @@ static int manta_step( mds->time_per_frame = time_per_frame; mds->time_total = time_total; } + /* Total time must not exceed framecount times framelength. Correct tiny errors here. */ + CLAMP(mds->time_total, mds->time_total, time_total_old + mds->frame_length); if (mds->type == FLUID_DOMAIN_TYPE_GAS && result) { manta_smoke_calc_transparency(mds, DEG_get_evaluated_view_layer(depsgraph)); @@ -3755,7 +3735,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } /* Ensure cache directory is not relative. */ - const char *relbase = modifier_path_relbase_from_global(ob); + const char *relbase = BKE_modifier_path_relbase_from_global(ob); BLI_path_abs(mds->cache_directory, relbase); /* Ensure that all flags are up to date before doing any baking and/or cache reading. */ @@ -3785,6 +3765,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Fluid domain init must not fail in order to continue modifier evaluation. */ if (!mds->fluid && !BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) { + CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!"); return; } BLI_assert(mds->fluid); @@ -3792,7 +3773,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Guiding parent res pointer needs initialization. */ guide_parent = mds->guide_parent; if (guide_parent) { - mmd_parent = (FluidModifierData *)modifiers_findByType(guide_parent, eModifierType_Fluid); + mmd_parent = (FluidModifierData *)BKE_modifiers_findby_type(guide_parent, eModifierType_Fluid); if (mmd_parent && mmd_parent->domain) { copy_v3_v3_int(mds->guide_res, mmd_parent->domain->res); } @@ -3803,8 +3784,12 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale; mds->dt = mds->frame_length; mds->time_per_frame = 0; - /* Get distance between cache start and current frame for total time. */ - mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length; + + /* Ensure that gravity is copied over every frame (could be keyframed). */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(mds->gravity, scene->physics_settings.gravity); + mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity); + } int next_frame = scene_framenr + 1; int prev_frame = scene_framenr - 1; @@ -3831,12 +3816,13 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, with_guide = mds->flags & FLUID_DOMAIN_USE_GUIDE; with_particles = drops || bubble || floater; - bool has_data, has_noise, has_mesh, has_particles, has_guide; + bool has_data, has_noise, has_mesh, has_particles, has_guide, has_config; has_data = manta_has_data(mds->fluid, mmd, scene_framenr); has_noise = manta_has_noise(mds->fluid, mmd, scene_framenr); has_mesh = manta_has_mesh(mds->fluid, mmd, scene_framenr); has_particles = manta_has_particles(mds->fluid, mmd, scene_framenr); has_guide = manta_has_guiding(mds->fluid, mmd, scene_framenr, guide_parent); + has_config = false; bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide; baking_data = mds->cache_flag & FLUID_DOMAIN_BAKING_DATA; @@ -3947,12 +3933,16 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Read mesh cache. */ if (with_liquid && with_mesh) { + has_config = manta_read_config(mds->fluid, mmd, mesh_frame); + /* Update mesh data from file is faster than via Python (manta_read_mesh()). */ has_mesh = manta_update_mesh_structures(mds->fluid, mmd, mesh_frame); } /* Read particles cache. */ if (with_liquid && with_particles) { + has_config = manta_read_config(mds->fluid, mmd, particles_frame); + if (!baking_data && !baking_particles && next_particles) { /* Update particle data from file is faster than via Python (manta_read_particles()). */ has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame); @@ -3970,10 +3960,10 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Read noise and data cache */ if (with_smoke && with_noise) { + has_config = manta_read_config(mds->fluid, mmd, noise_frame); /* Only reallocate when just reading cache or when resuming during bake. */ - if ((!baking_noise || (baking_noise && resume_noise)) && - manta_read_config(mds->fluid, mmd, noise_frame) && + if ((!baking_noise || (baking_noise && resume_noise)) && has_config && manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_fluid(mds, mds->res, 1); } @@ -3991,16 +3981,13 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, copy_v3_v3_int(o_min, mds->res_min); copy_v3_v3_int(o_max, mds->res_max); copy_v3_v3_int(o_shift, mds->shift); - if (manta_read_config(mds->fluid, mmd, data_frame) && - manta_needs_realloc(mds->fluid, mmd)) { + if (has_config && manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_copy_fluid( mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift); } } if (!baking_data && !baking_noise && next_data && next_noise) { - /* TODO (sebbas): Confirm if this read call is really needed or not. - * Currently only important to load the shadow grid. */ - has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame); + /* Nothing to do here since we already loaded noise grids. */ } else { has_data = manta_read_data(mds->fluid, mmd, data_frame); @@ -4008,10 +3995,11 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } /* Read data cache only */ else { + has_config = manta_read_config(mds->fluid, mmd, data_frame); + if (with_smoke) { /* Read config and realloc fluid object if needed. */ - if (manta_read_config(mds->fluid, mmd, data_frame) && - manta_needs_realloc(mds->fluid, mmd)) { + if (has_config && manta_needs_realloc(mds->fluid, mmd)) { BKE_fluid_reallocate_fluid(mds, mds->res, 1); } /* Read data cache */ @@ -4400,26 +4388,25 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *v } } -/* get smoke velocity and density at given coordinates - * returns fluid density or -1.0f if outside domain. */ +/* Get fluid velocity and density at given coordinates + * Returns fluid density or -1.0f if outside domain. */ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]) { - FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); zero_v3(velocity); if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) { FluidDomainSettings *mds = mmd->domain; float time_mult = 25.f * DT_DEFAULT; + float size_mult = MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2]) / + mds->maxres; float vel_mag; - float *velX = manta_get_velocity_x(mds->fluid); - float *velY = manta_get_velocity_y(mds->fluid); - float *velZ = manta_get_velocity_z(mds->fluid); float density = 0.0f, fuel = 0.0f; float pos[3]; copy_v3_v3(pos, position); manta_pos_to_cell(mds, pos); - /* check if point is outside domain max bounds */ + /* Check if position is outside domain max bounds. */ if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) { return -1.0f; } @@ -4432,9 +4419,8 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]); pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]); - /* check if point is outside active area */ - if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS && - mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + /* Check if position is outside active area. */ + if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) { return 0.0f; } @@ -4443,21 +4429,22 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo } } - /* get interpolated velocity */ - velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] * - time_mult; - velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] * - time_mult; - velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] * - time_mult; + /* Get interpolated velocity at given position. */ + velocity[0] = BLI_voxel_sample_trilinear(manta_get_velocity_x(mds->fluid), mds->res, pos); + velocity[1] = BLI_voxel_sample_trilinear(manta_get_velocity_y(mds->fluid), mds->res, pos); + velocity[2] = BLI_voxel_sample_trilinear(manta_get_velocity_z(mds->fluid), mds->res, pos); + + /* Convert simulation units to Blender units. */ + mul_v3_fl(velocity, size_mult); + mul_v3_fl(velocity, time_mult); - /* convert velocity direction to global space */ + /* Convert velocity direction to global space. */ vel_mag = len_v3(velocity); mul_mat3_m4_v3(mds->obmat, velocity); normalize_v3(velocity); mul_v3_fl(velocity, vel_mag); - /* use max value of fuel or smoke density */ + /* Use max value of fuel or smoke density. */ density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos); if (manta_smoke_has_fuel(mds->fluid)) { fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos); @@ -4511,11 +4498,11 @@ void BKE_fluid_particle_system_create(struct Main *bmain, BLI_addtail(&ob->particlesystem, psys); /* add modifier */ - pmmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem); + pmmd = (ParticleSystemModifierData *)BKE_modifier_new(eModifierType_ParticleSystem); BLI_strncpy(pmmd->modifier.name, psys_name, sizeof(pmmd->modifier.name)); pmmd->psys = psys; BLI_addtail(&ob->modifiers, pmmd); - modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd); + BKE_modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd); } void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type) @@ -4529,7 +4516,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ /* clear modifier */ pmmd = psys_get_modifier(ob, psys); BLI_remlink(&ob->modifiers, pmmd); - modifier_free((ModifierData *)pmmd); + BKE_modifier_free((ModifierData *)pmmd); /* clear particle system */ BLI_remlink(&ob->particlesystem, psys); @@ -4942,7 +4929,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) /* cache options */ mmd->domain->cache_frame_start = 1; - mmd->domain->cache_frame_end = 50; + mmd->domain->cache_frame_end = 250; mmd->domain->cache_frame_pause_data = 0; mmd->domain->cache_frame_pause_noise = 0; mmd->domain->cache_frame_pause_mesh = 0; @@ -4962,7 +4949,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) #endif char cache_name[64]; BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name); - modifier_path_init( + BKE_modifier_path_init( mmd->domain->cache_directory, sizeof(mmd->domain->cache_directory), cache_name); /* time options */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 92eb6ea03e2..54f2492af93 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -134,6 +134,7 @@ IDTypeInfo IDType_ID_VF = { .copy_data = vfont_copy_data, .free_data = vfont_free_data, .make_local = NULL, + .foreach_id = NULL, }; /***************************** VFont *******************************/ diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 04d3c32f599..4311e425abf 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -55,6 +55,7 @@ #include "BKE_idtype.h" #include "BKE_image.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_paint.h" @@ -97,6 +98,19 @@ static void greasepencil_free_data(ID *id) BKE_gpencil_free((bGPdata *)id, true); } +static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data) +{ + bGPdata *gpencil = (bGPdata *)id; + /* materials */ + for (int i = 0; i < gpencil->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, gpencil->mat[i], IDWALK_CB_USER); + } + + LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) { + BKE_LIB_FOREACHID_PROCESS(data, gplayer->parent, IDWALK_CB_NOP); + } +} + IDTypeInfo IDType_ID_GD = { .id_code = ID_GD, .id_filter = FILTER_ID_GD, @@ -111,6 +125,7 @@ IDTypeInfo IDType_ID_GD = { .copy_data = greasepencil_copy_data, .free_data = greasepencil_free_data, .make_local = NULL, + .foreach_id = greasepencil_foreach_id, }; /* ************************************************** */ diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c new file mode 100644 index 00000000000..8299943cc49 --- /dev/null +++ b/source/blender/blenkernel/intern/gpencil_curve.c @@ -0,0 +1,450 @@ +/* + * 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) 2008, Blender Foundation + * This is a new part of Blender + */ + +/** \file + * \ingroup bke + */ + +#include <math.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "CLG_log.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math_vector.h" + +#include "BLT_translation.h" + +#include "DNA_gpencil_types.h" + +#include "BKE_collection.h" +#include "BKE_curve.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_curve.h" +#include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_object.h" + +#include "DEG_depsgraph_query.h" + +/* Helper: Check materials with same color. */ +static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat) +{ + Material *ma = NULL; + float color_cu[4]; + linearrgb_to_srgb_v3_v3(color_cu, color); + float hsv1[4]; + rgb_to_hsv_v(color_cu, hsv1); + hsv1[3] = color[3]; + + for (int i = 1; i <= ob_gp->totcol; i++) { + ma = BKE_object_material_get(ob_gp, i); + MaterialGPencilStyle *gp_style = ma->gp_style; + /* Check color with small tolerance (better in HSV). */ + float hsv2[4]; + rgb_to_hsv_v(gp_style->fill_rgba, hsv2); + hsv2[3] = gp_style->fill_rgba[3]; + if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) && + (compare_v4v4(hsv1, hsv2, 0.01f))) { + *r_mat = ma; + return i - 1; + } + } + + *r_mat = NULL; + return -1; +} + +/* Helper: Add gpencil material using curve material as base. */ +static Material *gpencil_add_from_curve_material(Main *bmain, + Object *ob_gp, + const float cu_color[4], + const bool gpencil_lines, + const bool fill, + int *r_idx) +{ + Material *mat_gp = BKE_gpencil_object_material_new( + bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx); + MaterialGPencilStyle *gp_style = mat_gp->gp_style; + + /* Stroke color. */ + if (gpencil_lines) { + ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f); + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + } + else { + linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color); + gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; + } + + /* Fill color. */ + linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color); + /* Fill is false if the original curve hasn't material assigned, so enable it. */ + if (fill) { + gp_style->flag |= GP_MATERIAL_FILL_SHOW; + } + + /* Check at least one is enabled. */ + if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) && + ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) { + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + } + + return mat_gp; +} + +/* Helper: Create new stroke section. */ +static void gpencil_add_new_points(bGPDstroke *gps, + float *coord_array, + float pressure, + int init, + int totpoints, + const float init_co[3], + bool last) +{ + for (int i = 0; i < totpoints; i++) { + bGPDspoint *pt = &gps->points[i + init]; + copy_v3_v3(&pt->x, &coord_array[3 * i]); + /* Be sure the last point is not on top of the first point of the curve or + * the close of the stroke will produce glitches. */ + if ((last) && (i > 0) && (i == totpoints - 1)) { + float dist = len_v3v3(init_co, &pt->x); + if (dist < 0.1f) { + /* Interpolate between previous point and current to back slightly. */ + bGPDspoint *pt_prev = &gps->points[i + init - 1]; + interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f); + } + } + + pt->pressure = pressure; + pt->strength = 1.0f; + } +} + +/* Helper: Get the first collection that includes the object. */ +static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob) +{ + Collection *mycol = NULL; + FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + if ((mycol == NULL) && (cob->ob == ob)) { + mycol = collection; + } + } + } + FOREACH_SCENE_COLLECTION_END; + + return mycol; +} + +/* Helper: Convert one spline to grease pencil stroke. */ +static void gpencil_convert_spline(Main *bmain, + Object *ob_gp, + Object *ob_cu, + const bool gpencil_lines, + const bool only_stroke, + bGPDframe *gpf, + Nurb *nu) +{ + Curve *cu = (Curve *)ob_cu->data; + bool cyclic = true; + + /* Create Stroke. */ + bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); + gps->thickness = 10.0f; + gps->fill_opacity_fac = 1.0f; + gps->hardeness = 1.0f; + gps->uv_scale = 1.0f; + + ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f); + ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND); + gps->inittime = 0.0f; + + gps->flag &= ~GP_STROKE_SELECT; + gps->flag |= GP_STROKE_3DSPACE; + + gps->mat_nr = 0; + /* Count total points + * The total of points must consider that last point of each segment is equal to the first + * point of next segment. + */ + int totpoints = 0; + int segments = 0; + int resolu = nu->resolu + 1; + segments = nu->pntsu; + if ((nu->flagu & CU_NURB_CYCLIC) == 0) { + segments--; + cyclic = false; + } + totpoints = (resolu * segments) - (segments - 1); + + /* Materials + * Notice: The color of the material is the color of viewport and not the final shader color. + */ + Material *mat_gp = NULL; + bool fill = true; + /* Check if grease pencil has a material with same color.*/ + float color[4]; + if ((cu->mat) && (*cu->mat)) { + Material *mat_cu = *cu->mat; + copy_v4_v4(color, &mat_cu->r); + } + else { + /* Gray (unassigned from SVG add-on) */ + zero_v4(color); + add_v3_fl(color, 0.6f); + color[3] = 1.0f; + fill = false; + } + + /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and + * there is only one color, the stroke must not be closed, fill to false and use for + * stroke the fill color. + */ + bool do_stroke = false; + if (ob_cu->totcol == 1) { + Material *ma_stroke = BKE_object_material_get(ob_cu, 1); + if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) { + do_stroke = true; + } + } + + int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp); + if ((ob_cu->totcol > 0) && (r_idx < 0)) { + Material *mat_curve = BKE_object_material_get(ob_cu, 1); + mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx); + + if ((mat_curve) && (mat_curve->gp_style != NULL)) { + MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style; + MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style; + + copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba); + gp_style_gp->fill_style = gp_style_cur->fill_style; + gp_style_gp->mix_factor = gp_style_cur->mix_factor; + } + + /* If object has more than 1 material, use second material for stroke color. */ + if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) { + mat_curve = BKE_object_material_get(ob_cu, 2); + if (mat_curve) { + linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); + mat_gp->gp_style->stroke_rgba[3] = mat_curve->a; + } + } + else if ((only_stroke) || (do_stroke)) { + /* Also use the first color if the fill is none for stroke color. */ + if (ob_cu->totcol > 0) { + mat_curve = BKE_object_material_get(ob_cu, 1); + if (mat_curve) { + copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); + mat_gp->gp_style->stroke_rgba[3] = mat_curve->a; + /* Set fill and stroke depending of curve type (3D or 2D). */ + if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) { + mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; + } + else { + mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW; + } + } + } + } + } + CLAMP_MIN(r_idx, 0); + + /* Assign material index to stroke. */ + gps->mat_nr = r_idx; + + /* Add stroke to frame.*/ + BLI_addtail(&gpf->strokes, gps); + + float *coord_array = NULL; + float init_co[3]; + + switch (nu->type) { + case CU_POLY: { + /* Allocate memory for storage points. */ + gps->totpoints = nu->pntsu; + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + /* Increase thickness for this type. */ + gps->thickness = 10.0f; + + /* Get all curve points */ + for (int s = 0; s < gps->totpoints; s++) { + BPoint *bp = &nu->bp[s]; + bGPDspoint *pt = &gps->points[s]; + copy_v3_v3(&pt->x, bp->vec); + pt->pressure = bp->radius; + pt->strength = 1.0f; + } + break; + } + case CU_BEZIER: { + /* Allocate memory for storage points. */ + gps->totpoints = totpoints; + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + + int init = 0; + resolu = nu->resolu + 1; + segments = nu->pntsu; + if ((nu->flagu & CU_NURB_CYCLIC) == 0) { + segments--; + } + /* Get all interpolated curve points of Beziert */ + for (int s = 0; s < segments; s++) { + int inext = (s + 1) % nu->pntsu; + BezTriple *prevbezt = &nu->bezt[s]; + BezTriple *bezt = &nu->bezt[inext]; + bool last = (bool)(s == segments - 1); + + coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__); + + for (int j = 0; j < 3; j++) { + BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], + prevbezt->vec[2][j], + bezt->vec[0][j], + bezt->vec[1][j], + coord_array + j, + resolu - 1, + 3 * sizeof(float)); + } + /* Save first point coordinates. */ + if (s == 0) { + copy_v3_v3(init_co, &coord_array[0]); + } + /* Add points to the stroke */ + gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last); + /* Free memory. */ + MEM_SAFE_FREE(coord_array); + + /* As the last point of segment is the first point of next segment, back one array + * element to avoid duplicated points on the same location. + */ + init += resolu - 1; + } + break; + } + case CU_NURBS: { + if (nu->pntsv == 1) { + + int nurb_points; + if (nu->flagu & CU_NURB_CYCLIC) { + resolu++; + nurb_points = nu->pntsu * resolu; + } + else { + nurb_points = (nu->pntsu - 1) * resolu; + } + /* Get all curve points. */ + coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__); + BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3])); + + /* Allocate memory for storage points. */ + gps->totpoints = nurb_points - 1; + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + + /* Add points. */ + gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false); + + MEM_SAFE_FREE(coord_array); + } + break; + } + default: { + break; + } + } + /* Cyclic curve, close stroke. */ + if ((cyclic) && (!do_stroke)) { + BKE_gpencil_stroke_close(gps); + } + + /* Recalc fill geometry. */ + BKE_gpencil_stroke_geometry_update(gps); +} + +/* Convert a curve object to grease pencil stroke. + * + * \param bmain: Main thread pointer + * \param scene: Original scene. + * \param ob_gp: Grease pencil object to add strokes. + * \param ob_cu: Curve to convert. + * \param gpencil_lines: Use lines for strokes. + * \param use_collections: Create layers using collection names. + * \param only_stroke: The material must be only stroke without fill. + */ +void BKE_gpencil_convert_curve(Main *bmain, + Scene *scene, + Object *ob_gp, + Object *ob_cu, + const bool gpencil_lines, + const bool use_collections, + const bool only_stroke) +{ + if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) { + return; + } + + Curve *cu = (Curve *)ob_cu->data; + bGPdata *gpd = (bGPdata *)ob_gp->data; + bGPDlayer *gpl = NULL; + + /* If the curve is empty, cancel. */ + if (cu->nurb.first == NULL) { + return; + } + + /* Check if there is an active layer. */ + if (use_collections) { + Collection *collection = gpencil_get_parent_collection(scene, ob_cu); + if (collection != NULL) { + gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2); + if (gpl == NULL) { + gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true); + } + } + } + + if (gpl == NULL) { + gpl = BKE_gpencil_layer_active_get(gpd); + if (gpl == NULL) { + gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); + } + } + + /* Check if there is an active frame and add if needed. */ + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); + + /* Read all splines of the curve and create a stroke for each. */ + LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { + gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu); + } + + /* Tag for recalculation */ + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c index 413e28c431b..d200e4e3a15 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.c +++ b/source/blender/blenkernel/intern/gpencil_geom.c @@ -35,18 +35,12 @@ #include "BLI_math_vector.h" #include "BLI_polyfill_2d.h" -#include "BLT_translation.h" - #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" -#include "BKE_collection.h" -#include "BKE_curve.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" -#include "BKE_main.h" -#include "BKE_material.h" #include "BKE_object.h" #include "DEG_depsgraph_query.h" @@ -1586,404 +1580,6 @@ void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf, BKE_gpencil_stroke_geometry_update(gps); } -/* Helper: Check materials with same color. */ -static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat) -{ - Material *ma = NULL; - float color_cu[4]; - linearrgb_to_srgb_v3_v3(color_cu, color); - float hsv1[4]; - rgb_to_hsv_v(color_cu, hsv1); - hsv1[3] = color[3]; - - for (int i = 1; i <= ob_gp->totcol; i++) { - ma = BKE_object_material_get(ob_gp, i); - MaterialGPencilStyle *gp_style = ma->gp_style; - /* Check color with small tolerance (better in HSV). */ - float hsv2[4]; - rgb_to_hsv_v(gp_style->fill_rgba, hsv2); - hsv2[3] = gp_style->fill_rgba[3]; - if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) && - (compare_v4v4(hsv1, hsv2, 0.01f))) { - *r_mat = ma; - return i - 1; - } - } - - *r_mat = NULL; - return -1; -} - -/* Helper: Add gpencil material using curve material as base. */ -static Material *gpencil_add_from_curve_material(Main *bmain, - Object *ob_gp, - const float cu_color[4], - const bool gpencil_lines, - const bool fill, - int *r_idx) -{ - Material *mat_gp = BKE_gpencil_object_material_new( - bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx); - MaterialGPencilStyle *gp_style = mat_gp->gp_style; - - /* Stroke color. */ - if (gpencil_lines) { - ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f); - gp_style->flag |= GP_MATERIAL_STROKE_SHOW; - } - else { - linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color); - gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; - } - - /* Fill color. */ - linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color); - /* Fill is false if the original curve hasn't material assigned, so enable it. */ - if (fill) { - gp_style->flag |= GP_MATERIAL_FILL_SHOW; - } - - /* Check at least one is enabled. */ - if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) && - ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) { - gp_style->flag |= GP_MATERIAL_STROKE_SHOW; - } - - return mat_gp; -} - -/* Helper: Create new stroke section. */ -static void gpencil_add_new_points(bGPDstroke *gps, - float *coord_array, - float pressure, - int init, - int totpoints, - const float init_co[3], - bool last) -{ - for (int i = 0; i < totpoints; i++) { - bGPDspoint *pt = &gps->points[i + init]; - copy_v3_v3(&pt->x, &coord_array[3 * i]); - /* Be sure the last point is not on top of the first point of the curve or - * the close of the stroke will produce glitches. */ - if ((last) && (i > 0) && (i == totpoints - 1)) { - float dist = len_v3v3(init_co, &pt->x); - if (dist < 0.1f) { - /* Interpolate between previous point and current to back slightly. */ - bGPDspoint *pt_prev = &gps->points[i + init - 1]; - interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f); - } - } - - pt->pressure = pressure; - pt->strength = 1.0f; - } -} - -/* Helper: Get the first collection that includes the object. */ -static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob) -{ - Collection *mycol = NULL; - FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - if ((mycol == NULL) && (cob->ob == ob)) { - mycol = collection; - } - } - } - FOREACH_SCENE_COLLECTION_END; - - return mycol; -} - -/* Helper: Convert one spline to grease pencil stroke. */ -static void gpencil_convert_spline(Main *bmain, - Object *ob_gp, - Object *ob_cu, - const bool gpencil_lines, - const bool only_stroke, - bGPDframe *gpf, - Nurb *nu) -{ - Curve *cu = (Curve *)ob_cu->data; - bool cyclic = true; - - /* Create Stroke. */ - bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); - gps->thickness = 10.0f; - gps->fill_opacity_fac = 1.0f; - gps->hardeness = 1.0f; - gps->uv_scale = 1.0f; - - ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f); - ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND); - gps->inittime = 0.0f; - - gps->flag &= ~GP_STROKE_SELECT; - gps->flag |= GP_STROKE_3DSPACE; - - gps->mat_nr = 0; - /* Count total points - * The total of points must consider that last point of each segment is equal to the first - * point of next segment. - */ - int totpoints = 0; - int segments = 0; - int resolu = nu->resolu + 1; - segments = nu->pntsu; - if ((nu->flagu & CU_NURB_CYCLIC) == 0) { - segments--; - cyclic = false; - } - totpoints = (resolu * segments) - (segments - 1); - - /* Materials - * Notice: The color of the material is the color of viewport and not the final shader color. - */ - Material *mat_gp = NULL; - bool fill = true; - /* Check if grease pencil has a material with same color.*/ - float color[4]; - if ((cu->mat) && (*cu->mat)) { - Material *mat_cu = *cu->mat; - copy_v4_v4(color, &mat_cu->r); - } - else { - /* Gray (unassigned from SVG add-on) */ - zero_v4(color); - add_v3_fl(color, 0.6f); - color[3] = 1.0f; - fill = false; - } - - /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and - * there is only one color, the stroke must not be closed, fill to false and use for - * stroke the fill color. - */ - bool do_stroke = false; - if (ob_cu->totcol == 1) { - Material *ma_stroke = BKE_object_material_get(ob_cu, 1); - if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) { - do_stroke = true; - } - } - - int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp); - if ((ob_cu->totcol > 0) && (r_idx < 0)) { - Material *mat_curve = BKE_object_material_get(ob_cu, 1); - mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx); - - if ((mat_curve) && (mat_curve->gp_style != NULL)) { - MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style; - MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style; - - copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba); - gp_style_gp->fill_style = gp_style_cur->fill_style; - gp_style_gp->mix_factor = gp_style_cur->mix_factor; - } - - /* If object has more than 1 material, use second material for stroke color. */ - if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) { - mat_curve = BKE_object_material_get(ob_cu, 2); - if (mat_curve) { - linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); - mat_gp->gp_style->stroke_rgba[3] = mat_curve->a; - } - } - else if ((only_stroke) || (do_stroke)) { - /* Also use the first color if the fill is none for stroke color. */ - if (ob_cu->totcol > 0) { - mat_curve = BKE_object_material_get(ob_cu, 1); - if (mat_curve) { - copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); - mat_gp->gp_style->stroke_rgba[3] = mat_curve->a; - /* Set fill and stroke depending of curve type (3D or 2D). */ - if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) { - mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; - mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; - } - else { - mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; - mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW; - } - } - } - } - } - CLAMP_MIN(r_idx, 0); - - /* Assign material index to stroke. */ - gps->mat_nr = r_idx; - - /* Add stroke to frame.*/ - BLI_addtail(&gpf->strokes, gps); - - float *coord_array = NULL; - float init_co[3]; - - switch (nu->type) { - case CU_POLY: { - /* Allocate memory for storage points. */ - gps->totpoints = nu->pntsu; - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); - /* Increase thickness for this type. */ - gps->thickness = 10.0f; - - /* Get all curve points */ - for (int s = 0; s < gps->totpoints; s++) { - BPoint *bp = &nu->bp[s]; - bGPDspoint *pt = &gps->points[s]; - copy_v3_v3(&pt->x, bp->vec); - pt->pressure = bp->radius; - pt->strength = 1.0f; - } - break; - } - case CU_BEZIER: { - /* Allocate memory for storage points. */ - gps->totpoints = totpoints; - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); - - int init = 0; - resolu = nu->resolu + 1; - segments = nu->pntsu; - if ((nu->flagu & CU_NURB_CYCLIC) == 0) { - segments--; - } - /* Get all interpolated curve points of Beziert */ - for (int s = 0; s < segments; s++) { - int inext = (s + 1) % nu->pntsu; - BezTriple *prevbezt = &nu->bezt[s]; - BezTriple *bezt = &nu->bezt[inext]; - bool last = (bool)(s == segments - 1); - - coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__); - - for (int j = 0; j < 3; j++) { - BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], - prevbezt->vec[2][j], - bezt->vec[0][j], - bezt->vec[1][j], - coord_array + j, - resolu - 1, - 3 * sizeof(float)); - } - /* Save first point coordinates. */ - if (s == 0) { - copy_v3_v3(init_co, &coord_array[0]); - } - /* Add points to the stroke */ - gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last); - /* Free memory. */ - MEM_SAFE_FREE(coord_array); - - /* As the last point of segment is the first point of next segment, back one array - * element to avoid duplicated points on the same location. - */ - init += resolu - 1; - } - break; - } - case CU_NURBS: { - if (nu->pntsv == 1) { - - int nurb_points; - if (nu->flagu & CU_NURB_CYCLIC) { - resolu++; - nurb_points = nu->pntsu * resolu; - } - else { - nurb_points = (nu->pntsu - 1) * resolu; - } - /* Get all curve points. */ - coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__); - BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3])); - - /* Allocate memory for storage points. */ - gps->totpoints = nurb_points - 1; - gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); - - /* Add points. */ - gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false); - - MEM_SAFE_FREE(coord_array); - } - break; - } - default: { - break; - } - } - /* Cyclic curve, close stroke. */ - if ((cyclic) && (!do_stroke)) { - BKE_gpencil_stroke_close(gps); - } - - /* Recalc fill geometry. */ - BKE_gpencil_stroke_geometry_update(gps); -} - -/* Convert a curve object to grease pencil stroke. - * - * \param bmain: Main thread pointer - * \param scene: Original scene. - * \param ob_gp: Grease pencil object to add strokes. - * \param ob_cu: Curve to convert. - * \param gpencil_lines: Use lines for strokes. - * \param use_collections: Create layers using collection names. - * \param only_stroke: The material must be only stroke without fill. - */ -void BKE_gpencil_convert_curve(Main *bmain, - Scene *scene, - Object *ob_gp, - Object *ob_cu, - const bool gpencil_lines, - const bool use_collections, - const bool only_stroke) -{ - if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) { - return; - } - - Curve *cu = (Curve *)ob_cu->data; - bGPdata *gpd = (bGPdata *)ob_gp->data; - bGPDlayer *gpl = NULL; - - /* If the curve is empty, cancel. */ - if (cu->nurb.first == NULL) { - return; - } - - /* Check if there is an active layer. */ - if (use_collections) { - Collection *collection = gpencil_get_parent_collection(scene, ob_cu); - if (collection != NULL) { - gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2); - if (gpl == NULL) { - gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true); - } - } - } - - if (gpl == NULL) { - gpl = BKE_gpencil_layer_active_get(gpd); - if (gpl == NULL) { - gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); - } - } - - /* Check if there is an active frame and add if needed. */ - bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); - - /* Read all splines of the curve and create a stroke for each. */ - LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) { - gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu); - } - - /* Tag for recalculation */ - DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); -} - /* Apply Transforms */ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) { diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index b732d9cdd4c..b889b91e366 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -318,7 +318,7 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob) { GpencilModifierData *md; for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti && mti->generateStrokes) { return true; @@ -332,7 +332,7 @@ bool BKE_gpencil_has_time_modifiers(Object *ob) { GpencilModifierData *md; for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti && mti->remapTime) { return true; @@ -369,7 +369,7 @@ static int gpencil_time_modifier( for (md = ob->greasepencil_modifiers.first; md; md = md->next) { if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) { continue; @@ -421,7 +421,7 @@ void BKE_gpencil_modifier_init(void) GpencilModifierData *BKE_gpencil_modifier_new(int type) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type); GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name); /* note, this name must be made unique later */ @@ -456,7 +456,7 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData), void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { if (mti->foreachIDLink) { @@ -487,7 +487,7 @@ void BKE_gpencil_modifier_free(GpencilModifierData *md) bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd) { if (modifiers && gmd) { - const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type); + const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifier_get_info(gmd->type); return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), @@ -498,14 +498,14 @@ bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData * return false; } -bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md) +bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); return mti->dependsOnTime && mti->dependsOnTime(md); } -const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type) +const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type) { /* type unsigned, no need to check < 0 */ if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') { @@ -516,10 +516,10 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierT } } -void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, +void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md_src->type); /* md_dst may have already be fully initialized with some extra allocated data, * we need to free it now to avoid memleak. */ @@ -545,11 +545,11 @@ static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), } } -void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, +void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); target->mode = md->mode; target->flag = md->flag; @@ -569,12 +569,12 @@ void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, } } -void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target) +void BKE_gpencil_modifier_copydata(GpencilModifierData *md, GpencilModifierData *target) { - BKE_gpencil_modifier_copyData_ex(md, target, 0); + BKE_gpencil_modifier_copydata_ex(md, target, 0); } -GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type) +GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifierType type) { GpencilModifierData *md = ob->greasepencil_modifiers.first; @@ -587,12 +587,12 @@ GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifie return md; } -void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData) +void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData) { GpencilModifierData *md = ob->greasepencil_modifiers.first; for (; md; md = md->next) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti->foreachIDLink) { mti->foreachIDLink(md, ob, walk, userData); @@ -605,12 +605,14 @@ void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk } } -void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData) +void BKE_gpencil_modifiers_foreach_tex_link(Object *ob, + GreasePencilTexWalkFunc walk, + void *userData) { GpencilModifierData *md = ob->greasepencil_modifiers.first; for (; md; md = md->next) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti->foreachTexLink) { mti->foreachTexLink(md, ob, walk, userData); @@ -618,7 +620,7 @@ void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc wa } } -GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name) +GpencilModifierData *BKE_gpencil_modifiers_findby_name(Object *ob, const char *name) { return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name)); } @@ -881,7 +883,7 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob) LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) { continue; diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c index 5cdb7761540..90761d24b73 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.c @@ -22,6 +22,7 @@ #include "DNA_defaults.h" #include "DNA_hair_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "BLI_listbase.h" @@ -48,50 +49,7 @@ /* Hair datablock */ -static void hair_random(Hair *hair) -{ - const int numpoints = 8; - - hair->totcurve = 500; - hair->totpoint = hair->totcurve * numpoints; - - CustomData_realloc(&hair->pdata, hair->totpoint); - CustomData_realloc(&hair->cdata, hair->totcurve); - BKE_hair_update_customdata_pointers(hair); - - RNG *rng = BLI_rng_new(0); - - for (int i = 0; i < hair->totcurve; i++) { - HairCurve *curve = &hair->curves[i]; - curve->firstpoint = i * numpoints; - curve->numpoints = numpoints; - - float theta = 2.0f * M_PI * BLI_rng_get_float(rng); - float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f); - - float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)}; - normalize_v3(no); - - float co[3]; - copy_v3_v3(co, no); - - float(*curve_co)[3] = hair->co + curve->firstpoint; - float *curve_radius = hair->radius + curve->firstpoint; - for (int key = 0; key < numpoints; key++) { - float t = key / (float)(numpoints - 1); - copy_v3_v3(curve_co[key], co); - curve_radius[key] = 0.02f * (1.0f - t); - - float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f, - 2.0f * BLI_rng_get_float(rng) - 1.0f, - 2.0f * BLI_rng_get_float(rng) - 1.0f}; - add_v3_v3(offset, no); - madd_v3_v3fl(co, offset, 1.0f / numpoints); - } - } - - BLI_rng_free(rng); -} +static void hair_random(Hair *hair); static void hair_init_data(ID *id) { @@ -111,15 +69,6 @@ static void hair_init_data(ID *id) hair_random(hair); } -void *BKE_hair_add(Main *bmain, const char *name) -{ - Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0); - - hair_init_data(&hair->id); - - return hair; -} - static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) { Hair *hair_dst = (Hair *)id_dst; @@ -134,18 +83,6 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co hair_dst->batch_cache = NULL; } -Hair *BKE_hair_copy(Main *bmain, const Hair *hair) -{ - Hair *hair_copy; - BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy); - return hair_copy; -} - -static void hair_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - static void hair_free_data(ID *id) { Hair *hair = (Hair *)id; @@ -159,6 +96,14 @@ static void hair_free_data(ID *id) MEM_SAFE_FREE(hair->mat); } +static void hair_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Hair *hair = (Hair *)id; + for (int i = 0; i < hair->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, hair->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_HA = { .id_code = ID_HA, .id_filter = FILTER_ID_HA, @@ -172,9 +117,71 @@ IDTypeInfo IDType_ID_HA = { .init_data = hair_init_data, .copy_data = hair_copy_data, .free_data = hair_free_data, - .make_local = hair_make_local, + .make_local = NULL, + .foreach_id = hair_foreach_id, }; +static void hair_random(Hair *hair) +{ + const int numpoints = 8; + + hair->totcurve = 500; + hair->totpoint = hair->totcurve * numpoints; + + CustomData_realloc(&hair->pdata, hair->totpoint); + CustomData_realloc(&hair->cdata, hair->totcurve); + BKE_hair_update_customdata_pointers(hair); + + RNG *rng = BLI_rng_new(0); + + for (int i = 0; i < hair->totcurve; i++) { + HairCurve *curve = &hair->curves[i]; + curve->firstpoint = i * numpoints; + curve->numpoints = numpoints; + + float theta = 2.0f * M_PI * BLI_rng_get_float(rng); + float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f); + + float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)}; + normalize_v3(no); + + float co[3]; + copy_v3_v3(co, no); + + float(*curve_co)[3] = hair->co + curve->firstpoint; + float *curve_radius = hair->radius + curve->firstpoint; + for (int key = 0; key < numpoints; key++) { + float t = key / (float)(numpoints - 1); + copy_v3_v3(curve_co[key], co); + curve_radius[key] = 0.02f * (1.0f - t); + + float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f, + 2.0f * BLI_rng_get_float(rng) - 1.0f, + 2.0f * BLI_rng_get_float(rng) - 1.0f}; + add_v3_v3(offset, no); + madd_v3_v3fl(co, offset, 1.0f / numpoints); + } + } + + BLI_rng_free(rng); +} + +void *BKE_hair_add(Main *bmain, const char *name) +{ + Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0); + + hair_init_data(&hair->id); + + return hair; +} + +Hair *BKE_hair_copy(Main *bmain, const Hair *hair) +{ + Hair *hair_copy; + BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy); + return hair_copy; +} + BoundBox *BKE_hair_boundbox_get(Object *ob) { BLI_assert(ob->type == OB_HAIR); @@ -247,12 +254,65 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference) return result; } -static Hair *hair_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph), - struct Scene *UNUSED(scene), - Object *UNUSED(object), +static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph, + struct Scene *scene, + Object *object, Hair *hair_input) { - return hair_input; + Hair *hair = hair_input; + + /* Modifier evaluation modes. */ + const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; + const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; + + /* Get effective list of modifiers to execute. Some effects like shape keys + * are added as virtual modifiers before the user created modifiers. */ + VirtualModifierData virtualModifierData; + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); + + /* Evaluate modifiers. */ + for (; md; md = md->next) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { + continue; + } + + if ((mti->type == eModifierTypeType_OnlyDeform) && + (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) { + /* Ensure we are not modifying the input. */ + if (hair == hair_input) { + hair = BKE_hair_copy_for_eval(hair, true); + } + + /* Ensure we are not overwriting referenced data. */ + CustomData_duplicate_referenced_layer(&hair->pdata, CD_LOCATION, hair->totpoint); + BKE_hair_update_customdata_pointers(hair); + + /* Created deformed coordinates array on demand. */ + mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint); + } + else if (mti->modifyHair) { + /* Ensure we are not modifying the input. */ + if (hair == hair_input) { + hair = BKE_hair_copy_for_eval(hair, true); + } + + Hair *hair_next = mti->modifyHair(md, &mectx, hair); + + if (hair_next && hair_next != hair) { + /* If the modifier returned a new hair, release the old one. */ + if (hair != hair_input) { + BKE_id_free(NULL, hair); + } + hair = hair_next; + } + } + } + + return hair; } void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object) diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c index 5a6e8f532c9..fcd3bc9c5b4 100644 --- a/source/blender/blenkernel/intern/idtype.c +++ b/source/blender/blenkernel/intern/idtype.c @@ -10,7 +10,7 @@ * 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, + * 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) 2005 by the Blender Foundation. @@ -92,6 +92,7 @@ static void id_type_init(void) INIT_TYPE(ID_HA); INIT_TYPE(ID_PT); INIT_TYPE(ID_VO); + INIT_TYPE(ID_SIM); /* Special naughty boy... */ BLI_assert(IDType_ID_LINK_PLACEHOLDER.main_listbase_index == INDEX_ID_NULL); @@ -251,6 +252,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode) CASE_IDFILTER(PT); CASE_IDFILTER(LP); CASE_IDFILTER(SCE); + CASE_IDFILTER(SIM); CASE_IDFILTER(SPK); CASE_IDFILTER(SO); CASE_IDFILTER(TE); @@ -302,6 +304,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter) CASE_IDFILTER(PT); CASE_IDFILTER(LP); CASE_IDFILTER(SCE); + CASE_IDFILTER(SIM); CASE_IDFILTER(SPK); CASE_IDFILTER(SO); CASE_IDFILTER(TE); @@ -356,6 +359,7 @@ int BKE_idtype_idcode_to_index(const short idcode) CASE_IDINDEX(LP); CASE_IDINDEX(SCE); CASE_IDINDEX(SCR); + CASE_IDINDEX(SIM); CASE_IDINDEX(SPK); CASE_IDINDEX(SO); CASE_IDINDEX(TE); @@ -417,6 +421,7 @@ short BKE_idtype_idcode_from_index(const int index) CASE_IDCODE(LP); CASE_IDCODE(SCE); CASE_IDCODE(SCR); + CASE_IDCODE(SIM); CASE_IDCODE(SPK); CASE_IDCODE(SO); CASE_IDCODE(TE); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 906d76dfed8..b4a3f249c63 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -199,6 +199,7 @@ IDTypeInfo IDType_ID_IM = { .copy_data = image_copy_data, .free_data = image_free_data, .make_local = NULL, + .foreach_id = NULL, }; /* prototypes */ @@ -571,7 +572,7 @@ ImageTile *BKE_image_get_tile(Image *ima, int tile_number) return NULL; } -ImageTile *BKE_image_get_tile_from_iuser(Image *ima, ImageUser *iuser) +ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser) { return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001); } @@ -4796,7 +4797,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry, return ibuf; } -BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser) +BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser) { if (ima == NULL) { return false; diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index b0b88a13a75..780c3c2f14a 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -60,6 +60,7 @@ #include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_ipo.h" @@ -122,6 +123,7 @@ IDTypeInfo IDType_ID_IP = { .copy_data = NULL, .free_data = ipo_free_data, .make_local = NULL, + .foreach_id = NULL, }; /* *************************************************** */ diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 2ca6e54b5c8..af8ab22e14b 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -51,6 +51,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_scene.h" @@ -91,6 +92,12 @@ static void shapekey_free_data(ID *id) } } +static void shapekey_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Key *key = (Key *)id; + BKE_LIB_FOREACHID_PROCESS_ID(data, key->from, IDWALK_CB_LOOPBACK); +} + IDTypeInfo IDType_ID_KE = { .id_code = ID_KE, .id_filter = 0, @@ -105,6 +112,7 @@ IDTypeInfo IDType_ID_KE = { .copy_data = shapekey_copy_data, .free_data = shapekey_free_data, .make_local = NULL, + .foreach_id = shapekey_foreach_id, }; #define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */ diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index d371af93bb7..e7a2421a625 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -52,6 +52,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -121,6 +122,12 @@ static void lattice_free_data(ID *id) } } +static void lattice_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Lattice *lattice = (Lattice *)id; + BKE_LIB_FOREACHID_PROCESS(data, lattice->key, IDWALK_CB_USER); +} + IDTypeInfo IDType_ID_LT = { .id_code = ID_LT, .id_filter = FILTER_ID_LT, @@ -135,6 +142,7 @@ IDTypeInfo IDType_ID_LT = { .copy_data = lattice_copy_data, .free_data = lattice_free_data, .make_local = NULL, + .foreach_id = lattice_foreach_id, }; int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w) @@ -1119,7 +1127,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec * otherwise we get already-modified coordinates. */ Object *ob_orig = DEG_get_original_object(ob); VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); float(*vert_coords)[3] = NULL; int numVerts, editmode = (lt->editlatt != NULL); const ModifierEvalContext mectx = {depsgraph, ob, 0}; @@ -1132,9 +1140,9 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec } for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) { + if (!(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) { continue; } if (!(md->mode & eModifierMode_Realtime)) { diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index cd10d8b1670..9ef5c549235 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -36,38 +36,12 @@ #include "MEM_guardedalloc.h" /* all types are needed here, in order to do memory operations */ +#include "DNA_ID.h" #include "DNA_anim_types.h" -#include "DNA_armature_types.h" -#include "DNA_brush_types.h" -#include "DNA_cachefile_types.h" -#include "DNA_camera_types.h" -#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" -#include "DNA_hair_types.h" -#include "DNA_ipo_types.h" #include "DNA_key_types.h" -#include "DNA_lattice_types.h" -#include "DNA_light_types.h" -#include "DNA_lightprobe_types.h" -#include "DNA_linestyle_types.h" -#include "DNA_mask_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_movieclip_types.h" #include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_pointcloud_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_sound_types.h" -#include "DNA_speaker_types.h" -#include "DNA_text_types.h" -#include "DNA_vfont_types.h" -#include "DNA_volume_types.h" -#include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" -#include "DNA_world_types.h" #include "BLI_utildefines.h" @@ -80,50 +54,21 @@ #include "BLT_translation.h" -#include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_armature.h" #include "BKE_bpath.h" -#include "BKE_brush.h" -#include "BKE_cachefile.h" -#include "BKE_camera.h" -#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_curve.h" -#include "BKE_font.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_hair.h" #include "BKE_idprop.h" #include "BKE_idtype.h" -#include "BKE_image.h" #include "BKE_key.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_lib_remap.h" -#include "BKE_light.h" -#include "BKE_lightprobe.h" -#include "BKE_linestyle.h" #include "BKE_main.h" -#include "BKE_mask.h" -#include "BKE_material.h" -#include "BKE_mball.h" -#include "BKE_mesh.h" -#include "BKE_movieclip.h" #include "BKE_node.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" -#include "BKE_pointcloud.h" #include "BKE_rigidbody.h" -#include "BKE_scene.h" -#include "BKE_sound.h" -#include "BKE_speaker.h" -#include "BKE_text.h" -#include "BKE_texture.h" -#include "BKE_volume.h" -#include "BKE_world.h" #include "DEG_depsgraph.h" @@ -663,7 +608,7 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id) * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). * - * \param bmain May be NULL, in which case there will be no remapping of internal pointers to + * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to * itself. */ void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b) @@ -675,7 +620,7 @@ void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b) * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note All internal ID data itself is also swapped. * - * \param bmain May be NULL, in which case there will be no remapping of internal pointers to + * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to * itself. */ void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b) @@ -1256,7 +1201,7 @@ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *nam * * \note All other IDs beside given one are assumed already properly sorted in the list. * - * \param id_sorting_hint Ignored if NULL. Otherwise, used to check if we can insert \a id + * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id * immediately before or after that pointer. It must always be into given \a lb list. */ void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint) diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index 9b1abf4d76c..7c96d0a6401 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -23,80 +23,20 @@ #include "MEM_guardedalloc.h" /* all types are needed here, in order to do memory operations */ -#include "DNA_armature_types.h" -#include "DNA_brush_types.h" -#include "DNA_cachefile_types.h" -#include "DNA_camera_types.h" -#include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_ipo_types.h" -#include "DNA_key_types.h" -#include "DNA_lattice_types.h" -#include "DNA_light_types.h" -#include "DNA_lightprobe_types.h" -#include "DNA_linestyle_types.h" -#include "DNA_mask_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_sound_types.h" -#include "DNA_speaker_types.h" -#include "DNA_text_types.h" -#include "DNA_vfont_types.h" -#include "DNA_windowmanager_types.h" -#include "DNA_workspace_types.h" -#include "DNA_world_types.h" +#include "DNA_ID.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" -#include "BKE_action.h" #include "BKE_anim_data.h" -#include "BKE_armature.h" -#include "BKE_brush.h" -#include "BKE_cachefile.h" -#include "BKE_camera.h" -#include "BKE_collection.h" -#include "BKE_curve.h" -#include "BKE_font.h" -#include "BKE_gpencil.h" #include "BKE_idprop.h" #include "BKE_idtype.h" -#include "BKE_image.h" -#include "BKE_ipo.h" -#include "BKE_key.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_remap.h" #include "BKE_library.h" -#include "BKE_light.h" -#include "BKE_lightprobe.h" -#include "BKE_linestyle.h" #include "BKE_main.h" -#include "BKE_mask.h" -#include "BKE_material.h" -#include "BKE_mball.h" -#include "BKE_mesh.h" -#include "BKE_movieclip.h" -#include "BKE_node.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" -#include "BKE_scene.h" -#include "BKE_screen.h" -#include "BKE_sound.h" -#include "BKE_speaker.h" -#include "BKE_text.h" -#include "BKE_texture.h" -#include "BKE_workspace.h" -#include "BKE_world.h" #include "lib_intern.h" diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 2ca03fd5d7e..015fa235a06 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -49,6 +49,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" +#include "DNA_simulation_types.h" #include "DNA_sound_types.h" #include "DNA_space_types.h" #include "DNA_speaker_types.h" @@ -67,9 +68,10 @@ #include "BKE_anim_data.h" #include "BKE_collection.h" #include "BKE_constraint.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_gpencil_modifier.h" #include "BKE_idprop.h" +#include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" @@ -77,63 +79,12 @@ #include "BKE_node.h" #include "BKE_particle.h" #include "BKE_rigidbody.h" +#include "BKE_screen.h" #include "BKE_sequencer.h" #include "BKE_shader_fx.h" +#include "BKE_texture.h" #include "BKE_workspace.h" -#define FOREACH_FINALIZE _finalize -#define FOREACH_FINALIZE_VOID \ - if (0) { \ - goto FOREACH_FINALIZE; \ - } \ - FOREACH_FINALIZE: \ - ((void)0) - -#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \ - CHECK_TYPE(id_pp, ID **); \ - if (!((_data)->status & IDWALK_STOP)) { \ - const int _flag = (_data)->flag; \ - ID *old_id = *(id_pp); \ - const int callback_return = (_data)->callback(&(struct LibraryIDLinkCallbackData){ \ - .user_data = (_data)->user_data, \ - .id_owner = (_data)->owner_id, \ - .id_self = (_data)->self_id, \ - .id_pointer = id_pp, \ - .cb_flag = ((_cb_flag | (_data)->cb_flag) & ~(_data)->cb_flag_clear)}); \ - if (_flag & IDWALK_READONLY) { \ - BLI_assert(*(id_pp) == old_id); \ - } \ - if (old_id && (_flag & IDWALK_RECURSE)) { \ - if (BLI_gset_add((_data)->ids_handled, old_id)) { \ - if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \ - BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \ - } \ - } \ - } \ - if (callback_return & IDWALK_RET_STOP_ITER) { \ - (_data)->status |= IDWALK_STOP; \ - goto FOREACH_FINALIZE; \ - } \ - } \ - else { \ - goto FOREACH_FINALIZE; \ - } \ - ((void)0) - -#define FOREACH_CALLBACK_INVOKE_ID(_data, id, cb_flag) \ - { \ - CHECK_TYPE_ANY(id, ID *, void *); \ - FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \ - } \ - ((void)0) - -#define FOREACH_CALLBACK_INVOKE(_data, id_super, cb_flag) \ - { \ - CHECK_TYPE(&((id_super)->id), ID *); \ - FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \ - } \ - ((void)0) - /* status */ enum { IDWALK_STOP = 1 << 0, @@ -164,100 +115,80 @@ typedef struct LibraryForeachIDData { BLI_LINKSTACK_DECLARE(ids_todo, ID *); } LibraryForeachIDData; -static void library_foreach_ID_link(Main *bmain, - ID *id_owner, - ID *id, - LibraryIDLinkCallback callback, - void *user_data, - int flag, - LibraryForeachIDData *inherit_data); - -static void library_foreach_idpropertiesForeachIDLink(IDProperty *id_prop, void *user_data) +bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag) { - BLI_assert(id_prop->type == IDP_ID); - - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID(data, id_prop->data.pointer, IDWALK_CB_USER); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw), - ID **id_pointer, - void *user_data, - int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; + if (!(data->status & IDWALK_STOP)) { + const int flag = data->flag; + ID *old_id = *id_pp; + const int callback_return = data->callback(&(struct LibraryIDLinkCallbackData){ + .user_data = data->user_data, + .id_owner = data->owner_id, + .id_self = data->self_id, + .id_pointer = id_pp, + .cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear)}); + if (flag & IDWALK_READONLY) { + BLI_assert(*(id_pp) == old_id); + } + if (old_id && (flag & IDWALK_RECURSE)) { + if (BLI_gset_add((data)->ids_handled, old_id)) { + if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { + BLI_LINKSTACK_PUSH(data->ids_todo, old_id); + } + } + } + if (callback_return & IDWALK_RET_STOP_ITER) { + data->status |= IDWALK_STOP; + return false; + } + return true; + } + else { + return false; + } } -static void library_foreach_modifiersForeachIDLink(void *user_data, - Object *UNUSED(object), - ID **id_pointer, - int cb_flag) +int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data) { - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; + return data->flag; } -static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, - Object *UNUSED(object), - ID **id_pointer, - int cb_flag) +int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData *data, + const int cb_flag, + const bool do_replace) { - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; + const int cb_flag_backup = data->cb_flag; + if (do_replace) { + data->cb_flag = cb_flag; + } + else { + data->cb_flag |= cb_flag; + } + return cb_flag_backup; } -static void library_foreach_shaderfxForeachIDLink(void *user_data, - Object *UNUSED(object), - ID **id_pointer, - int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} +static void library_foreach_ID_link(Main *bmain, + ID *id_owner, + ID *id, + LibraryIDLinkCallback callback, + void *user_data, + int flag, + LibraryForeachIDData *inherit_data); -static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), - ID **id_pointer, - bool is_reference, - void *user_data) +void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void *user_data) { - LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} + BLI_assert(id_prop->type == IDP_ID); -static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys), - ID **id_pointer, - void *user_data, - int cb_flag) -{ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; + BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, IDWALK_CB_USER); } static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip) { - FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER); LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { library_foreach_nla_strip(data, substrip); } - - FOREACH_FINALIZE_VOID; } static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) @@ -268,248 +199,37 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { /* only used targets */ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { - FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS_ID(data, dtar->id, IDWALK_CB_NOP); } DRIVER_TARGETS_LOOPER_END; } } - FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER); - FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, adt->action, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, adt->tmpact, IDWALK_CB_USER); LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) { LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) { library_foreach_nla_strip(data, nla_strip); } } - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex) -{ - FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) -{ - FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER); - for (int i = 0; i < paint->tool_slots_len; i++) { - FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER); - } - FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER); - - FOREACH_FINALIZE_VOID; } -static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone) +bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) { - IDP_foreach_property( - bone->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, data); - - LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { - library_foreach_bone(data, curbone); - } - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) -{ - LISTBASE_FOREACH (LayerCollection *, lc, lb) { - /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad - * anyway... */ - const int cb_flag = (lc->collection != NULL && - (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? - IDWALK_CB_EMBEDDED : - IDWALK_CB_NOP; - FOREACH_CALLBACK_INVOKE(data, lc->collection, cb_flag); - library_foreach_layer_collection(data, &lc->layer_collections); - } - - FOREACH_FINALIZE_VOID; -} - -/* Used by both real Collection data-blocks, and the fake horror of master collection from Scene. - */ -static void library_foreach_collection(LibraryForeachIDData *data, Collection *collection) -{ - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - FOREACH_CALLBACK_INVOKE(data, cob->ob, IDWALK_CB_USER); - } - LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - FOREACH_CALLBACK_INVOKE(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER); - } - LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) { - /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad - * anyway... */ - const int cb_flag = ((parent->collection != NULL && - (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? - IDWALK_CB_EMBEDDED : - IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE( - data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag); - } - - FOREACH_FINALIZE_VOID; -} + /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ + ID *id = *id_pp; + const int flag = data->flag; -static void library_foreach_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads) -{ - if (ads != NULL) { - FOREACH_CALLBACK_INVOKE_ID(data, ads->source, IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE(data, ads->filter_grp, IDWALK_CB_NOP); + if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) { + return false; } + BLI_assert(id == *id_pp); - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *area) -{ - FOREACH_CALLBACK_INVOKE(data, area->full, IDWALK_CB_NOP); - - LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - switch (sl->spacetype) { - case SPACE_VIEW3D: { - View3D *v3d = (View3D *)sl; - - FOREACH_CALLBACK_INVOKE(data, v3d->camera, IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE(data, v3d->ob_center, IDWALK_CB_NOP); - - if (v3d->localvd) { - FOREACH_CALLBACK_INVOKE(data, v3d->localvd->camera, IDWALK_CB_NOP); - } - break; - } - case SPACE_GRAPH: { - SpaceGraph *sipo = (SpaceGraph *)sl; - - library_foreach_dopesheet(data, sipo->ads); - break; - } - case SPACE_PROPERTIES: { - SpaceProperties *sbuts = (SpaceProperties *)sl; - - FOREACH_CALLBACK_INVOKE_ID(data, sbuts->pinid, IDWALK_CB_NOP); - break; - } - case SPACE_FILE: - break; - case SPACE_ACTION: { - SpaceAction *saction = (SpaceAction *)sl; - - library_foreach_dopesheet(data, &saction->ads); - FOREACH_CALLBACK_INVOKE(data, saction->action, IDWALK_CB_NOP); - break; - } - case SPACE_IMAGE: { - SpaceImage *sima = (SpaceImage *)sl; - - FOREACH_CALLBACK_INVOKE(data, sima->image, IDWALK_CB_USER_ONE); - FOREACH_CALLBACK_INVOKE(data, sima->mask_info.mask, IDWALK_CB_USER_ONE); - FOREACH_CALLBACK_INVOKE(data, sima->gpd, IDWALK_CB_USER); - break; - } - case SPACE_SEQ: { - SpaceSeq *sseq = (SpaceSeq *)sl; - - FOREACH_CALLBACK_INVOKE(data, sseq->gpd, IDWALK_CB_USER); - break; - } - case SPACE_NLA: { - SpaceNla *snla = (SpaceNla *)sl; - - library_foreach_dopesheet(data, snla->ads); - break; - } - case SPACE_TEXT: { - SpaceText *st = (SpaceText *)sl; - - FOREACH_CALLBACK_INVOKE(data, st->text, IDWALK_CB_NOP); - break; - } - case SPACE_SCRIPT: { - SpaceScript *scpt = (SpaceScript *)sl; - - FOREACH_CALLBACK_INVOKE(data, scpt->script, IDWALK_CB_NOP); - break; - } - case SPACE_OUTLINER: { - SpaceOutliner *so = (SpaceOutliner *)sl; - - FOREACH_CALLBACK_INVOKE_ID(data, so->search_tse.id, IDWALK_CB_NOP); - - if (so->treestore != NULL) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - FOREACH_CALLBACK_INVOKE_ID(data, tselem->id, IDWALK_CB_NOP); - } - } - break; - } - case SPACE_NODE: { - SpaceNode *snode = (SpaceNode *)sl; - - const bool is_private_nodetree = snode->id != NULL && - ntreeFromID(snode->id) == snode->nodetree; - - FOREACH_CALLBACK_INVOKE_ID(data, snode->id, IDWALK_CB_NOP); - FOREACH_CALLBACK_INVOKE_ID(data, snode->from, IDWALK_CB_NOP); - - FOREACH_CALLBACK_INVOKE( - data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); - - LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) { - if (path == snode->treepath.first) { - /* first nodetree in path is same as snode->nodetree */ - FOREACH_CALLBACK_INVOKE(data, - path->nodetree, - is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); - } - else { - FOREACH_CALLBACK_INVOKE(data, path->nodetree, IDWALK_CB_USER_ONE); - } - - if (path->nodetree == NULL) { - break; - } - } - - FOREACH_CALLBACK_INVOKE(data, snode->edittree, IDWALK_CB_NOP); - break; - } - case SPACE_CLIP: { - SpaceClip *sclip = (SpaceClip *)sl; - - FOREACH_CALLBACK_INVOKE(data, sclip->clip, IDWALK_CB_USER_ONE); - FOREACH_CALLBACK_INVOKE(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE); - break; - } - default: - break; - } + if (id == NULL) { + return true; } - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_ID_as_subdata_link(ID **id_pp, - LibraryIDLinkCallback callback, - void *user_data, - int flag, - LibraryForeachIDData *data) -{ - /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ - ID *id = *id_pp; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED); - BLI_assert(id == *id_pp); - if (flag & IDWALK_IGNORE_EMBEDDED_ID) { /* Do Nothing. */ } @@ -523,10 +243,11 @@ static void library_foreach_ID_as_subdata_link(ID **id_pp, } } else { - library_foreach_ID_link(data->bmain, data->owner_id, id, callback, user_data, flag, data); + library_foreach_ID_link( + data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data); } - FOREACH_FINALIZE_VOID; + return true; } static void library_foreach_ID_link(Main *bmain, @@ -538,7 +259,6 @@ static void library_foreach_ID_link(Main *bmain, LibraryForeachIDData *inherit_data) { LibraryForeachIDData data = {.bmain = bmain}; - int i; BLI_assert(inherit_data == NULL || data.bmain == inherit_data->bmain); @@ -559,10 +279,11 @@ static void library_foreach_ID_link(Main *bmain, data.callback = callback; data.user_data = user_data; -#define CALLBACK_INVOKE_ID(check_id, cb_flag) FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag) +#define CALLBACK_INVOKE_ID(check_id, cb_flag) \ + BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag) #define CALLBACK_INVOKE(check_id_super, cb_flag) \ - FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag) + BKE_LIB_FOREACHID_PROCESS(&data, check_id_super, cb_flag) for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; @@ -598,7 +319,7 @@ static void library_foreach_ID_link(Main *bmain, * especially if/when it starts modifying Main database). */ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id); for (; entry != NULL; entry = entry->next) { - FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag); + BKE_lib_query_foreachid_process(&data, entry->id_pointer, entry->usage_flag); } continue; } @@ -613,657 +334,26 @@ static void library_foreach_ID_link(Main *bmain, IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE); } - IDP_foreach_property( - id->properties, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); + IDP_foreach_property(id->properties, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + &data); AnimData *adt = BKE_animdata_from_id(id); if (adt) { library_foreach_animationData(&data, adt); } - switch ((ID_Type)GS(id->name)) { - case ID_LI: { - Library *lib = (Library *)id; - CALLBACK_INVOKE(lib->parent, IDWALK_CB_NEVER_SELF); - break; - } - case ID_SCE: { - Scene *scene = (Scene *)id; - ToolSettings *toolsett = scene->toolsettings; - - CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP); - CALLBACK_INVOKE(scene->world, IDWALK_CB_USER); - CALLBACK_INVOKE(scene->set, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER); - CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); - CALLBACK_INVOKE(scene->r.bake.cage_object, IDWALK_CB_NOP); - if (scene->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&scene->nodetree, callback, user_data, flag, &data); - } - if (scene->ed) { - Sequence *seq; - SEQP_BEGIN (scene->ed, seq) { - CALLBACK_INVOKE(seq->scene, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP); - CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER); - CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER); - CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER); - IDP_foreach_property( - seq->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) { - CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER); - } - - if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) { - TextVars *text_data = seq->effectdata; - CALLBACK_INVOKE(text_data->text_font, IDWALK_CB_USER); - } - } - SEQ_END; - } - - /* This pointer can be NULL during old files reading, better be safe than sorry. */ - if (scene->master_collection != NULL) { - library_foreach_collection(&data, scene->master_collection); - } - - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER); - - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - CALLBACK_INVOKE(base->object, IDWALK_CB_NOP); - } - - library_foreach_layer_collection(&data, &view_layer->layer_collections); - - LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { - if (fmc->script) { - CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP); - } - } - - LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { - if (fls->group) { - CALLBACK_INVOKE(fls->group, IDWALK_CB_USER); - } - - if (fls->linestyle) { - CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER); - } - } - } - - LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { - CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP); - } - - if (toolsett) { - CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP); - CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP); - CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP); - - library_foreach_paint(&data, &toolsett->imapaint.paint); - CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER); - CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER); - CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER); - - if (toolsett->vpaint) { - library_foreach_paint(&data, &toolsett->vpaint->paint); - } - if (toolsett->wpaint) { - library_foreach_paint(&data, &toolsett->wpaint->paint); - } - if (toolsett->sculpt) { - library_foreach_paint(&data, &toolsett->sculpt->paint); - CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP); - } - if (toolsett->uvsculpt) { - library_foreach_paint(&data, &toolsett->uvsculpt->paint); - } - if (toolsett->gp_paint) { - library_foreach_paint(&data, &toolsett->gp_paint->paint); - } - if (toolsett->gp_vertexpaint) { - library_foreach_paint(&data, &toolsett->gp_vertexpaint->paint); - } - if (toolsett->gp_sculptpaint) { - library_foreach_paint(&data, &toolsett->gp_sculptpaint->paint); - } - if (toolsett->gp_weightpaint) { - library_foreach_paint(&data, &toolsett->gp_weightpaint->paint); - } - - CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP); - } - - if (scene->rigidbody_world) { - BKE_rigidbody_world_id_loop( - scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data); - } - - break; - } - - case ID_OB: { - Object *object = (Object *)id; - - /* Object is special, proxies make things hard... */ - const int data_cb_flag = data.cb_flag; - const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && - (object->proxy || object->proxy_group)) ? - IDWALK_CB_INDIRECT_USAGE : - 0; - - /* object data special case */ - data.cb_flag |= proxy_cb_flag; - if (object->type == OB_EMPTY) { - /* empty can have NULL or Image */ - CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER); - } - else { - /* when set, this can't be NULL */ - if (object->data) { - CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); - } - } - data.cb_flag = data_cb_flag; - - CALLBACK_INVOKE(object->parent, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(object->track, IDWALK_CB_NEVER_SELF); - /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ - CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP); - - /* Special case! - * Since this field is set/owned by 'user' of this ID (and not ID itself), - * it is only indirect usage if proxy object is linked... Twisted. */ - if (object->proxy_from) { - data.cb_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0; - } - CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF); - data.cb_flag = data_cb_flag; - - CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER); - - data.cb_flag |= proxy_cb_flag; - for (i = 0; i < object->totcol; i++) { - CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER); - } - data.cb_flag = data_cb_flag; - - /* Note that ob->gpd is deprecated, so no need to handle it here. */ - CALLBACK_INVOKE(object->instance_collection, IDWALK_CB_USER); - - if (object->pd) { - CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER); - CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP); - } - /* Note that ob->effect is deprecated, so no need to handle it here. */ - - if (object->pose) { - data.cb_flag |= proxy_cb_flag; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - IDP_foreach_property( - pchan->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER); - BKE_constraints_id_loop( - &pchan->constraints, library_foreach_constraintObjectLooper, &data); - } - data.cb_flag = data_cb_flag; - } - - if (object->rigidbody_constraint) { - CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF); - } - - if (object->lodlevels.first) { - LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) { - CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF); - } - } - - modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data); - BKE_gpencil_modifiers_foreachIDLink( - object, library_foreach_gpencil_modifiersForeachIDLink, &data); - BKE_constraints_id_loop( - &object->constraints, library_foreach_constraintObjectLooper, &data); - BKE_shaderfx_foreachIDLink(object, library_foreach_shaderfxForeachIDLink, &data); - - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data); - } - - if (object->soft) { - CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP); - - if (object->soft->effector_weights) { - CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP); - } - } - break; - } - - case ID_AR: { - bArmature *arm = (bArmature *)id; - - LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { - library_foreach_bone(&data, bone); - } - break; - } + const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); + if (id_type->foreach_id != NULL) { + id_type->foreach_id(id, &data); - case ID_ME: { - Mesh *mesh = (Mesh *)id; - CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_NEVER_SELF); - CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER); - for (i = 0; i < mesh->totcol; i++) { - CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER); - } - break; - } - - case ID_CU: { - Curve *curve = (Curve *)id; - CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP); - CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP); - CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP); - CALLBACK_INVOKE(curve->key, IDWALK_CB_USER); - for (i = 0; i < curve->totcol; i++) { - CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER); - } - CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER); - CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER); - CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER); - CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER); - break; - } - - case ID_MB: { - MetaBall *metaball = (MetaBall *)id; - for (i = 0; i < metaball->totcol; i++) { - CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER); - } - break; - } - - case ID_MA: { - Material *material = (Material *)id; - if (material->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&material->nodetree, callback, user_data, flag, &data); - } - if (material->texpaintslot != NULL) { - CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP); - } - if (material->gp_style != NULL) { - CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER); - CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER); - } - break; - } - - case ID_TE: { - Tex *texture = (Tex *)id; - if (texture->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&texture->nodetree, callback, user_data, flag, &data); - } - CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER); - break; - } - - case ID_LT: { - Lattice *lattice = (Lattice *)id; - CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER); - break; - } - - case ID_LA: { - Light *lamp = (Light *)id; - if (lamp->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&lamp->nodetree, callback, user_data, flag, &data); - } - break; - } - - case ID_CA: { - Camera *camera = (Camera *)id; - CALLBACK_INVOKE(camera->dof.focus_object, IDWALK_CB_NOP); - LISTBASE_FOREACH (CameraBGImage *, bgpic, &camera->bg_images) { - if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) { - CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER); - } - else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) { - CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER); - } - } - - break; - } - - case ID_KE: { - Key *key = (Key *)id; - CALLBACK_INVOKE_ID(key->from, IDWALK_CB_LOOPBACK); - break; - } - - case ID_WO: { - World *world = (World *)id; - if (world->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&world->nodetree, callback, user_data, flag, &data); - } - break; - } - - case ID_SPK: { - Speaker *speaker = (Speaker *)id; - CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER); - break; - } - - case ID_LP: { - LightProbe *probe = (LightProbe *)id; - CALLBACK_INVOKE(probe->image, IDWALK_CB_USER); - CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP); - break; - } - - case ID_GR: { - Collection *collection = (Collection *)id; - library_foreach_collection(&data, collection); - break; - } - - case ID_NT: { - bNodeTree *ntree = (bNodeTree *)id; - - CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER); - - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER); - - IDP_foreach_property( - node->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - IDP_foreach_property( - sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - } - LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - IDP_foreach_property( - sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - } - } - - LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { - IDP_foreach_property( - sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - } - LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { - IDP_foreach_property( - sock->prop, IDP_TYPE_FILTER_ID, library_foreach_idpropertiesForeachIDLink, &data); - } + if (data.status & IDWALK_STOP) { break; } - - case ID_BR: { - Brush *brush = (Brush *)id; - CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP); - CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP); - CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER); - if (brush->gpencil_settings) { - CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER); - } - library_foreach_mtex(&data, &brush->mtex); - library_foreach_mtex(&data, &brush->mask_mtex); - break; - } - - case ID_PA: { - ParticleSettings *psett = (ParticleSettings *)id; - CALLBACK_INVOKE(psett->instance_collection, IDWALK_CB_USER); - CALLBACK_INVOKE(psett->instance_object, IDWALK_CB_NOP); - CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP); - CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP); - - for (i = 0; i < MAX_MTEX; i++) { - if (psett->mtex[i]) { - library_foreach_mtex(&data, psett->mtex[i]); - } - } - - if (psett->effector_weights) { - CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP); - } - - if (psett->pd) { - CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER); - CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP); - } - if (psett->pd2) { - CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER); - CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP); - } - - if (psett->boids) { - LISTBASE_FOREACH (BoidState *, state, &psett->boids->states) { - LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { - if (rule->type == eBoidRuleType_Avoid) { - BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; - CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP); - } - else if (rule->type == eBoidRuleType_FollowLeader) { - BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; - CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP); - } - } - } - } - - LISTBASE_FOREACH (ParticleDupliWeight *, dw, &psett->instance_weights) { - CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP); - } - break; - } - - case ID_MC: { - MovieClip *clip = (MovieClip *)id; - MovieTracking *tracking = &clip->tracking; - - CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER); - - LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) { - CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER); - } - LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) { - LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) { - CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER); - } - } - - LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) { - CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER); - } - break; - } - - case ID_MSK: { - Mask *mask = (Mask *)id; - - LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { - LISTBASE_FOREACH (MaskSpline *, mask_spline, &mask_layer->splines) { - for (i = 0; i < mask_spline->tot_point; i++) { - MaskSplinePoint *point = &mask_spline->points[i]; - CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER); - } - } - } - break; - } - - case ID_LS: { - FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; - - for (i = 0; i < MAX_MTEX; i++) { - if (linestyle->mtex[i]) { - library_foreach_mtex(&data, linestyle->mtex[i]); - } - } - if (linestyle->nodetree) { - /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link( - (ID **)&linestyle->nodetree, callback, user_data, flag, &data); - } - - LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) { - if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - LineStyleColorModifier_DistanceFromObject *p = - (LineStyleColorModifier_DistanceFromObject *)lsm; - if (p->target) { - CALLBACK_INVOKE(p->target, IDWALK_CB_NOP); - } - } - } - LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->alpha_modifiers) { - if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - LineStyleAlphaModifier_DistanceFromObject *p = - (LineStyleAlphaModifier_DistanceFromObject *)lsm; - if (p->target) { - CALLBACK_INVOKE(p->target, IDWALK_CB_NOP); - } - } - } - LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->thickness_modifiers) { - if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - LineStyleThicknessModifier_DistanceFromObject *p = - (LineStyleThicknessModifier_DistanceFromObject *)lsm; - if (p->target) { - CALLBACK_INVOKE(p->target, IDWALK_CB_NOP); - } - } - } - break; - } - - case ID_AC: { - bAction *act = (bAction *)id; - - LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { - CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP); - } - break; - } - - case ID_WM: { - wmWindowManager *wm = (wmWindowManager *)id; - - LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE); - - /* This pointer can be NULL during old files reading, better be safe than sorry. */ - if (win->workspace_hook != NULL) { - ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); - CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP); - /* allow callback to set a different workspace */ - BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); - } - if (data.flag & IDWALK_INCLUDE_UI) { - LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { - library_foreach_screen_area(&data, area); - } - } - } - break; - } - - case ID_WS: { - WorkSpace *workspace = (WorkSpace *)id; - ListBase *layouts = BKE_workspace_layouts_get(workspace); - - LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { - bScreen *screen = BKE_workspace_layout_screen_get(layout); - - /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer. - * However we can't access layout->screen here - * since we are outside the workspace project. */ - CALLBACK_INVOKE(screen, IDWALK_CB_USER); - /* allow callback to set a different screen */ - BKE_workspace_layout_screen_set(layout, screen); - } - break; - } - - case ID_GD: { - bGPdata *gpencil = (bGPdata *)id; - /* materials */ - for (i = 0; i < gpencil->totcol; i++) { - CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER); - } - - LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) { - CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP); - } - - break; - } - case ID_HA: { - Hair *hair = (Hair *)id; - for (i = 0; i < hair->totcol; i++) { - CALLBACK_INVOKE(hair->mat[i], IDWALK_CB_USER); - } - break; - } - case ID_PT: { - PointCloud *pointcloud = (PointCloud *)id; - for (i = 0; i < pointcloud->totcol; i++) { - CALLBACK_INVOKE(pointcloud->mat[i], IDWALK_CB_USER); - } - break; - } - case ID_VO: { - Volume *volume = (Volume *)id; - for (i = 0; i < volume->totcol; i++) { - CALLBACK_INVOKE(volume->mat[i], IDWALK_CB_USER); - } - break; - } - - case ID_SCR: { - if (data.flag & IDWALK_INCLUDE_UI) { - bScreen *screen = (bScreen *)id; - - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - library_foreach_screen_area(&data, area); - } - } - break; - } - - /* Nothing needed for those... */ - case ID_IM: - case ID_VF: - case ID_TXT: - case ID_SO: - case ID_PAL: - case ID_PC: - case ID_CF: - break; - - /* Deprecated. */ - case ID_IP: - break; } } -FOREACH_FINALIZE: if (data.ids_handled) { BLI_gset_free(data.ids_handled, NULL); BLI_LINKSTACK_FREE(data.ids_todo); @@ -1273,9 +363,6 @@ FOREACH_FINALIZE: #undef CALLBACK_INVOKE } -#undef FOREACH_CALLBACK_INVOKE_ID -#undef FOREACH_CALLBACK_INVOKE - /** * Loop over all of the ID's this data-block links to. */ @@ -1300,14 +387,11 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag) } /** - * Say whether given \a id_type_owner can use (in any way) a data-block of \a id_type_used. + * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used. * * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above, - * quite useful to reduce* useless iterations in some cases. + * quite useful to reduce useless iterations in some cases. */ -/* XXX This has to be fully rethink, basing check on ID type is not really working anymore - * (and even worth once IDProps will support ID pointers), - * we'll have to do some quick checks on IDs themselves... */ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) { /* any type of ID can be used in custom props. */ @@ -1417,6 +501,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) case ID_PAL: case ID_PC: case ID_CF: + case ID_SIM: /* Those types never use/reference other IDs... */ return false; case ID_IP: diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 72ae4629dba..ba986b1661b 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -334,7 +334,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o default: break; } - test_object_modifiers(ob); + BKE_modifiers_test_object(ob); BKE_object_materials_test(bmain, ob, new_id); } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index e3ed21aa536..64ffea22363 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -38,6 +38,7 @@ #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_packedFile.h" @@ -53,6 +54,12 @@ static void library_free_data(ID *id) } } +static void library_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Library *lib = (Library *)id; + BKE_LIB_FOREACHID_PROCESS(data, lib->parent, IDWALK_CB_NEVER_SELF); +} + IDTypeInfo IDType_ID_LI = { .id_code = ID_LI, .id_filter = 0, @@ -67,6 +74,7 @@ IDTypeInfo IDType_ID_LI = { .copy_data = NULL, .free_data = library_free_data, .make_local = NULL, + .foreach_id = library_foreach_id, }; void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath) diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index 3d0503b2e70..9dc338ce580 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -41,6 +41,7 @@ #include "BKE_icons.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_light.h" #include "BKE_main.h" #include "BKE_node.h" @@ -97,7 +98,7 @@ static void light_free_data(ID *id) /* is no lib link block, but light extension */ if (la->nodetree) { - ntreeFreeNestedTree(la->nodetree); + ntreeFreeEmbeddedTree(la->nodetree); MEM_freeN(la->nodetree); la->nodetree = NULL; } @@ -107,6 +108,15 @@ static void light_free_data(ID *id) la->id.icon_id = 0; } +static void light_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Light *lamp = (Light *)id; + if (lamp->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree); + } +} + IDTypeInfo IDType_ID_LA = { .id_code = ID_LA, .id_filter = FILTER_ID_LA, @@ -121,6 +131,7 @@ IDTypeInfo IDType_ID_LA = { .copy_data = light_copy_data, .free_data = light_free_data, .make_local = NULL, + .foreach_id = light_foreach_id, }; Light *BKE_light_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index 22f12831aa0..f73df66b43d 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -23,6 +23,7 @@ #include <string.h> +#include "DNA_collection_types.h" #include "DNA_defaults.h" #include "DNA_lightprobe_types.h" #include "DNA_object_types.h" @@ -31,6 +32,7 @@ #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_lightprobe.h" #include "BKE_main.h" @@ -44,6 +46,31 @@ static void lightprobe_init_data(ID *id) MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id); } +static void lightprobe_foreach_id(ID *id, LibraryForeachIDData *data) +{ + LightProbe *probe = (LightProbe *)id; + + BKE_LIB_FOREACHID_PROCESS(data, probe->image, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, probe->visibility_grp, IDWALK_CB_NOP); +} + +IDTypeInfo IDType_ID_LP = { + .id_code = ID_LP, + .id_filter = FILTER_ID_LP, + .main_listbase_index = INDEX_ID_LP, + .struct_size = sizeof(LightProbe), + .name = "LightProbe", + .name_plural = "lightprobes", + .translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE, + .flags = 0, + + .init_data = lightprobe_init_data, + .copy_data = NULL, + .free_data = NULL, + .make_local = NULL, + .foreach_id = lightprobe_foreach_id, +}; + void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type) { probe->type = lightprobe_type; @@ -79,48 +106,9 @@ void *BKE_lightprobe_add(Main *bmain, const char *name) return probe; } -/** - * Only copy internal data of #LightProbe ID from source - * to already allocated/initialized destination. - * You probably never want to use that directly, - * use #BKE_id_copy or #BKE_id_copy_ex for typical needs. - * - * WARNING! This function will not handle ID user count! - * - * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more). - */ -static void lightprobe_copy_data(Main *UNUSED(bmain), - ID *UNUSED(id_dst), - const ID *UNUSED(id_src), - const int UNUSED(flag)) -{ - /* Nothing to do here. */ -} - LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe) { LightProbe *probe_copy; BKE_id_copy(bmain, &probe->id, (ID **)&probe_copy); return probe_copy; } - -static void lightprobe_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - -IDTypeInfo IDType_ID_LP = { - .id_code = ID_LP, - .id_filter = FILTER_ID_LP, - .main_listbase_index = INDEX_ID_LP, - .struct_size = sizeof(LightProbe), - .name = "LightProbe", - .name_plural = "lightprobes", - .translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE, - .flags = 0, - - .init_data = lightprobe_init_data, - .copy_data = lightprobe_copy_data, - .free_data = NULL, - .make_local = lightprobe_make_local, -}; diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 42506e0d7c8..a389af5c47f 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -45,9 +45,11 @@ #include "BKE_freestyle.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_texture.h" static void linestyle_init_data(ID *id) { @@ -125,7 +127,7 @@ static void linestyle_free_data(ID *id) /* is no lib link block, but linestyle extension */ if (linestyle->nodetree) { - ntreeFreeNestedTree(linestyle->nodetree); + ntreeFreeEmbeddedTree(linestyle->nodetree); MEM_freeN(linestyle->nodetree); linestyle->nodetree = NULL; } @@ -144,6 +146,49 @@ static void linestyle_free_data(ID *id) } } +static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data) +{ + FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; + + for (int i = 0; i < MAX_MTEX; i++) { + if (linestyle->mtex[i]) { + BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]); + } + } + if (linestyle->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree); + } + + LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) { + if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { + LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *) + lsm; + if (p->target) { + BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP); + } + } + } + LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->alpha_modifiers) { + if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { + LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *) + lsm; + if (p->target) { + BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP); + } + } + } + LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->thickness_modifiers) { + if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { + LineStyleThicknessModifier_DistanceFromObject *p = + (LineStyleThicknessModifier_DistanceFromObject *)lsm; + if (p->target) { + BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP); + } + } + } +} + IDTypeInfo IDType_ID_LS = { .id_code = ID_LS, .id_filter = FILTER_ID_LS, @@ -158,6 +203,7 @@ IDTypeInfo IDType_ID_LS = { .copy_data = linestyle_copy_data, .free_data = linestyle_free_data, .make_local = NULL, + .foreach_id = linestyle_foreach_id, }; static const char *modifier_name[LS_MODIFIER_NUM] = { diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c index caa29f7817a..ea3bee8b2f6 100644 --- a/source/blender/blenkernel/intern/main.c +++ b/source/blender/blenkernel/intern/main.c @@ -479,6 +479,8 @@ ListBase *which_libbase(Main *bmain, short type) return &(bmain->pointclouds); case ID_VO: return &(bmain->volumes); + case ID_SIM: + return &(bmain->simulations); } return NULL; } @@ -554,6 +556,7 @@ int set_listbasepointers(Main *bmain, ListBase **lb) lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */ lb[INDEX_ID_WM] = &(bmain->wm); lb[INDEX_ID_MSK] = &(bmain->masks); + lb[INDEX_ID_SIM] = &(bmain->simulations); lb[INDEX_ID_NULL] = NULL; diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 6c835dc5fb2..49c909850de 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -45,6 +45,7 @@ #include "BKE_image.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_mask.h" #include "BKE_movieclip.h" @@ -79,6 +80,20 @@ static void mask_free_data(ID *id) BKE_mask_layer_free_list(&mask->masklayers); } +static void mask_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Mask *mask = (Mask *)id; + + LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { + LISTBASE_FOREACH (MaskSpline *, mask_spline, &mask_layer->splines) { + for (int i = 0; i < mask_spline->tot_point; i++) { + MaskSplinePoint *point = &mask_spline->points[i]; + BKE_LIB_FOREACHID_PROCESS_ID(data, point->parent.id, IDWALK_CB_USER); + } + } + } +} + IDTypeInfo IDType_ID_MSK = { .id_code = ID_MSK, .id_filter = FILTER_ID_MSK, @@ -93,6 +108,7 @@ IDTypeInfo IDType_ID_MSK = { .copy_data = mask_copy_data, .free_data = mask_free_data, .make_local = NULL, + .foreach_id = mask_foreach_id, }; static struct { diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 1b21ff9b36e..d4de04a9e98 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -64,6 +64,7 @@ #include "BKE_idtype.h" #include "BKE_image.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -130,7 +131,7 @@ static void material_free_data(ID *id) /* is no lib link block, but material extension */ if (material->nodetree) { - ntreeFreeNestedTree(material->nodetree); + ntreeFreeEmbeddedTree(material->nodetree); MEM_freeN(material->nodetree); material->nodetree = NULL; } @@ -143,6 +144,22 @@ static void material_free_data(ID *id) BKE_previewimg_free(&material->preview); } +static void material_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Material *material = (Material *)id; + /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */ + if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) { + return; + } + if (material->texpaintslot != NULL) { + BKE_LIB_FOREACHID_PROCESS(data, material->texpaintslot->ima, IDWALK_CB_NOP); + } + if (material->gp_style != NULL) { + BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->sima, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->ima, IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_MA = { .id_code = ID_MA, .id_filter = FILTER_ID_MA, @@ -157,6 +174,7 @@ IDTypeInfo IDType_ID_MA = { .copy_data = material_copy_data, .free_data = material_free_data, .make_local = NULL, + .foreach_id = material_foreach_id, }; void BKE_gpencil_material_attr_init(Material *ma) @@ -1601,7 +1619,7 @@ void BKE_material_copybuf_paste(Main *bmain, Material *ma) GPU_material_free(&ma->gpumaterial); if (ma->nodetree) { - ntreeFreeNestedTree(ma->nodetree); + ntreeFreeEmbeddedTree(ma->nodetree); MEM_freeN(ma->nodetree); } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 4294d279c36..94e5f435a43 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -54,6 +54,7 @@ #include "BKE_displist.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_object.h" @@ -101,6 +102,14 @@ static void metaball_free_data(ID *id) } } +static void metaball_foreach_id(ID *id, LibraryForeachIDData *data) +{ + MetaBall *metaball = (MetaBall *)id; + for (int i = 0; i < metaball->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, metaball->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_MB = { .id_code = ID_MB, .id_filter = FILTER_ID_MB, @@ -115,6 +124,7 @@ IDTypeInfo IDType_ID_MB = { .copy_data = metaball_copy_data, .free_data = metaball_free_data, .make_local = NULL, + .foreach_id = metaball_foreach_id, }; /* Functions */ diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 2a86b899290..aeef287bb87 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -25,6 +25,7 @@ #include "DNA_defaults.h" #include "DNA_key_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -47,6 +48,7 @@ #include "BKE_idtype.h" #include "BKE_key.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -142,6 +144,16 @@ static void mesh_free_data(ID *id) MEM_SAFE_FREE(mesh->mat); } +static void mesh_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Mesh *mesh = (Mesh *)id; + BKE_LIB_FOREACHID_PROCESS(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, mesh->key, IDWALK_CB_USER); + for (int i = 0; i < mesh->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, mesh->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_ME = { .id_code = ID_ME, .id_filter = FILTER_ID_ME, @@ -156,6 +168,7 @@ IDTypeInfo IDType_ID_ME = { .copy_data = mesh_copy_data, .free_data = mesh_free_data, .make_local = NULL, + .foreach_id = mesh_foreach_id, }; enum { @@ -1128,7 +1141,7 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) BKE_object_materials_test(bmain, ob, (ID *)me); - test_object_modifiers(ob); + BKE_modifiers_test_object(ob); } void BKE_mesh_material_index_remove(Mesh *me, short index) diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 28a32e1573b..655c70bcf61 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -1313,7 +1313,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, int build_shapekey_layers) { Mesh *me = ob_eval->runtime.data_orig ? ob_eval->runtime.data_orig : ob_eval->data; - const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type); Mesh *result; KeyBlock *kb; ModifierEvalContext mectx = {depsgraph, ob_eval, MOD_APPLY_TO_BASE_MESH}; @@ -1353,7 +1353,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, add_shapekey_layers(mesh_temp, me); } - result = mti->applyModifier(md_eval, &mectx, mesh_temp); + result = mti->modifyMesh(md_eval, &mectx, mesh_temp); ASSERT_IS_VALID_MESH(result); if (mesh_temp != result) { diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index e5be85b5ec7..f0d19f01aab 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -1300,9 +1300,9 @@ static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data, } } -static void loop_split_worker(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) +static void loop_split_worker(TaskPool *__restrict pool, void *taskdata) { - LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool); + LoopSplitTaskDataCommon *common_data = BLI_task_pool_user_data(pool); LoopSplitTaskData *data = taskdata; /* Temp edge vectors stack, only used when computing lnor spacearr. */ @@ -1704,11 +1704,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts, loop_split_generator(NULL, &common_data); } else { - TaskScheduler *task_scheduler; - TaskPool *task_pool; - - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &common_data, TASK_PRIORITY_HIGH); + TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH); loop_split_generator(task_pool, &common_data); diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c index a2a198cdb0d..d6f945cf34f 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.c +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -452,9 +452,7 @@ finally: pRes[3] = fSign; } -static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata) { struct SGLSLMeshToTangent *mesh2tangent = taskdata; /* new computation method */ @@ -658,9 +656,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert, /* Calculation */ if (looptri_len != 0) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL, TASK_PRIORITY_LOW); + TaskPool *task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW); tangent_mask_curr = 0; /* Calculate tangent layers */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 0a76b61cdb1..e872edf0784 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -10,7 +10,7 @@ * 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, + * 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) 2005 by the Blender Foundation. @@ -59,7 +59,7 @@ #include "BKE_multires.h" #include "BKE_object.h" -/* may move these, only for modifier_path_relbase */ +/* may move these, only for BKE_modifier_path_relbase */ #include "BKE_main.h" /* end */ @@ -82,21 +82,21 @@ void BKE_modifier_init(void) modifier_type_init(modifier_types); /* MOD_utils.c */ /* Initialize global cmmon storage used for virtual modifier list */ - md = modifier_new(eModifierType_Armature); + md = BKE_modifier_new(eModifierType_Armature); virtualModifierCommonData.amd = *((ArmatureModifierData *)md); - modifier_free(md); + BKE_modifier_free(md); - md = modifier_new(eModifierType_Curve); + md = BKE_modifier_new(eModifierType_Curve); virtualModifierCommonData.cmd = *((CurveModifierData *)md); - modifier_free(md); + BKE_modifier_free(md); - md = modifier_new(eModifierType_Lattice); + md = BKE_modifier_new(eModifierType_Lattice); virtualModifierCommonData.lmd = *((LatticeModifierData *)md); - modifier_free(md); + BKE_modifier_free(md); - md = modifier_new(eModifierType_ShapeKey); + md = BKE_modifier_new(eModifierType_ShapeKey); virtualModifierCommonData.smd = *((ShapeKeyModifierData *)md); - modifier_free(md); + BKE_modifier_free(md); virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual; virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual; @@ -104,7 +104,7 @@ void BKE_modifier_init(void) virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual; } -const ModifierTypeInfo *modifierType_getInfo(ModifierType type) +const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type) { /* type unsigned, no need to check < 0 */ if (type < NUM_MODIFIER_TYPES && modifier_types[type] && modifier_types[type]->name[0] != '\0') { @@ -117,9 +117,9 @@ const ModifierTypeInfo *modifierType_getInfo(ModifierType type) /***/ -ModifierData *modifier_new(int type) +ModifierData *BKE_modifier_new(int type) { - const ModifierTypeInfo *mti = modifierType_getInfo(type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(type); ModifierData *md = MEM_callocN(mti->structSize, mti->structName); /* note, this name must be made unique later */ @@ -151,9 +151,9 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData), } } -void modifier_free_ex(ModifierData *md, const int flag) +void BKE_modifier_free_ex(ModifierData *md, const int flag) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { if (mti->foreachIDLink) { @@ -174,15 +174,15 @@ void modifier_free_ex(ModifierData *md, const int flag) MEM_freeN(md); } -void modifier_free(ModifierData *md) +void BKE_modifier_free(ModifierData *md) { - modifier_free_ex(md, 0); + BKE_modifier_free_ex(md, 0); } -bool modifier_unique_name(ListBase *modifiers, ModifierData *md) +bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md) { if (modifiers && md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return BLI_uniquename( modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name)); @@ -190,24 +190,24 @@ bool modifier_unique_name(ListBase *modifiers, ModifierData *md) return false; } -bool modifier_dependsOnTime(ModifierData *md) +bool BKE_modifier_depends_ontime(ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return mti->dependsOnTime && mti->dependsOnTime(md); } -bool modifier_supportsMapping(ModifierData *md) +bool BKE_modifier_supports_mapping(ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return (mti->type == eModifierTypeType_OnlyDeform || (mti->flags & eModifierTypeFlag_SupportsMapping)); } -bool modifier_isPreview(ModifierData *md) +bool BKE_modifier_is_preview(ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); /* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */ if (!((mti->flags & eModifierTypeFlag_UsesPreview) || @@ -222,7 +222,7 @@ bool modifier_isPreview(ModifierData *md) return false; } -ModifierData *modifiers_findByType(Object *ob, ModifierType type) +ModifierData *BKE_modifiers_findby_type(Object *ob, ModifierType type) { ModifierData *md = ob->modifiers.first; @@ -235,12 +235,12 @@ ModifierData *modifiers_findByType(Object *ob, ModifierType type) return md; } -ModifierData *modifiers_findByName(Object *ob, const char *name) +ModifierData *BKE_modifiers_findny_name(Object *ob, const char *name) { return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name)); } -void modifiers_clearErrors(Object *ob) +void BKE_modifiers_clear_errors(Object *ob) { ModifierData *md = ob->modifiers.first; /* int qRedraw = 0; */ @@ -255,12 +255,12 @@ void modifiers_clearErrors(Object *ob) } } -void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData) +void BKE_modifiers_foreach_object_link(Object *ob, ObjectWalkFunc walk, void *userData) { ModifierData *md = ob->modifiers.first; for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (mti->foreachObjectLink) { mti->foreachObjectLink(md, ob, walk, userData); @@ -268,12 +268,12 @@ void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData } } -void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData) +void BKE_modifiers_foreach_ID_link(Object *ob, IDWalkFunc walk, void *userData) { ModifierData *md = ob->modifiers.first; for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (mti->foreachIDLink) { mti->foreachIDLink(md, ob, walk, userData); @@ -286,12 +286,12 @@ void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData) } } -void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData) +void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData) { ModifierData *md = ob->modifiers.first; for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (mti->foreachTexLink) { mti->foreachTexLink(md, ob, walk, userData); @@ -302,11 +302,11 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData) /* callback's can use this * to avoid copying every member. */ -void modifier_copyData_generic(const ModifierData *md_src, - ModifierData *md_dst, - const int UNUSED(flag)) +void BKE_modifier_copydata_generic(const ModifierData *md_src, + ModifierData *md_dst, + const int UNUSED(flag)) { - const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md_src->type); /* md_dst may have already be fully initialized with some extra allocated data, * we need to free it now to avoid memleak. */ @@ -335,9 +335,9 @@ static void modifier_copy_data_id_us_cb(void *UNUSED(userData), } } -void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag) +void BKE_modifier_copydata_ex(ModifierData *md, ModifierData *target, const int flag) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); target->mode = md->mode; target->flag = md->flag; @@ -356,40 +356,41 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag } } -void modifier_copyData(ModifierData *md, ModifierData *target) +void BKE_modifier_copydata(ModifierData *md, ModifierData *target) { - modifier_copyData_ex(md, target, 0); + BKE_modifier_copydata_ex(md, target, 0); } -bool modifier_supportsCage(struct Scene *scene, ModifierData *md) +bool BKE_modifier_supports_cage(struct Scene *scene, ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && - (mti->flags & eModifierTypeFlag_SupportsEditmode) && modifier_supportsMapping(md)); + (mti->flags & eModifierTypeFlag_SupportsEditmode) && BKE_modifier_supports_mapping(md)); } -bool modifier_couldBeCage(struct Scene *scene, ModifierData *md) +bool BKE_modifier_couldbe_cage(struct Scene *scene, ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return ((md->mode & eModifierMode_Realtime) && (md->mode & eModifierMode_Editmode) && - (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && modifier_supportsMapping(md)); + (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && + BKE_modifier_supports_mapping(md)); } -bool modifier_isSameTopology(ModifierData *md) +bool BKE_modifier_is_same_topology(ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical); } -bool modifier_isNonGeometrical(ModifierData *md) +bool BKE_modifier_is_non_geometrical(ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return (mti->type == eModifierTypeType_NonGeometrical); } -void modifier_setError(ModifierData *md, const char *_format, ...) +void BKE_modifier_set_error(ModifierData *md, const char *_format, ...) { char buffer[512]; va_list ap; @@ -416,14 +417,15 @@ void modifier_setError(ModifierData *md, const char *_format, ...) * then is NULL) * also used for some mesh tools to give warnings */ -int modifiers_getCageIndex(struct Scene *scene, - Object *ob, - int *r_lastPossibleCageIndex, - bool is_virtual) +int BKE_modifiers_get_cage_index(struct Scene *scene, + Object *ob, + int *r_lastPossibleCageIndex, + bool is_virtual) { VirtualModifierData virtualModifierData; - ModifierData *md = (is_virtual) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) : - ob->modifiers.first; + ModifierData *md = (is_virtual) ? + BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) : + ob->modifiers.first; int i, cageIndex = -1; if (r_lastPossibleCageIndex) { @@ -433,7 +435,7 @@ int modifiers_getCageIndex(struct Scene *scene, /* Find the last modifier acting on the cage. */ for (i = 0; md; i++, md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); bool supports_mapping; if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { @@ -446,7 +448,7 @@ int modifiers_getCageIndex(struct Scene *scene, continue; } - supports_mapping = modifier_supportsMapping(md); + supports_mapping = BKE_modifier_supports_mapping(md); if (r_lastPossibleCageIndex && supports_mapping) { *r_lastPossibleCageIndex = i; } @@ -470,30 +472,30 @@ int modifiers_getCageIndex(struct Scene *scene, return cageIndex; } -bool modifiers_isSoftbodyEnabled(Object *ob) +bool BKE_modifiers_is_softbody_enabled(Object *ob) { - ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody); return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } -bool modifiers_isClothEnabled(Object *ob) +bool BKE_modifiers_is_cloth_enabled(Object *ob) { - ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth); return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } -bool modifiers_isModifierEnabled(Object *ob, int modifierType) +bool BKE_modifiers_is_modifier_enabled(Object *ob, int modifierType) { - ModifierData *md = modifiers_findByType(ob, modifierType); + ModifierData *md = BKE_modifiers_findby_type(ob, modifierType); return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } -bool modifiers_isParticleEnabled(Object *ob) +bool BKE_modifiers_is_particle_enabled(Object *ob) { - ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_ParticleSystem); return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } @@ -504,9 +506,9 @@ bool modifiers_isParticleEnabled(Object *ob) * \param scene: Current scene, may be NULL, * in which case isDisabled callback of the modifier is never called. */ -bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode) +bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int required_mode) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if ((md->mode & required_mode) != required_mode) { return false; @@ -526,13 +528,13 @@ bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int require return true; } -CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, - Object *ob, - ModifierData *md, - CustomData_MeshMasks *final_datamask, - int required_mode, - ModifierData *previewmd, - const CustomData_MeshMasks *previewmask) +CDMaskLink *BKE_modifier_calc_data_masks(struct Scene *scene, + Object *ob, + ModifierData *md, + CustomData_MeshMasks *final_datamask, + int required_mode, + ModifierData *previewmd, + const CustomData_MeshMasks *previewmask) { CDMaskLink *dataMasks = NULL; CDMaskLink *curr, *prev; @@ -540,11 +542,11 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, /* build a list of modifier data requirements in reverse order */ for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink"); - if (modifier_isEnabled(scene, md, required_mode)) { + if (BKE_modifier_is_enabled(scene, md, required_mode)) { if (mti->type == eModifierTypeType_OnlyDeform) { have_deform_modifier = true; } @@ -594,7 +596,9 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, return dataMasks; } -ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, int required_mode) +ModifierData *BKE_modifier_get_last_preview(struct Scene *scene, + ModifierData *md, + int required_mode) { ModifierData *tmp_md = NULL; @@ -604,7 +608,7 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in /* Find the latest modifier in stack generating preview. */ for (; md; md = md->next) { - if (modifier_isEnabled(scene, md, required_mode) && modifier_isPreview(md)) { + if (BKE_modifier_is_enabled(scene, md, required_mode) && BKE_modifier_is_preview(md)) { tmp_md = md; } } @@ -613,8 +617,8 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in /* This is to include things that are not modifiers in the evaluation of the modifier stack, for * example parenting to an armature. */ -ModifierData *modifiers_getVirtualModifierList(const Object *ob, - VirtualModifierData *virtualModifierData) +ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob, + VirtualModifierData *virtualModifierData) { ModifierData *md; @@ -661,10 +665,10 @@ ModifierData *modifiers_getVirtualModifierList(const Object *ob, /* Takes an object and returns its first selected armature, else just its armature * This should work for multiple armatures per object */ -Object *modifiers_isDeformedByArmature(Object *ob) +Object *BKE_modifiers_is_deformed_by_armature(Object *ob) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); ArmatureModifierData *amd = NULL; /* return the first selected armature, this lets us use multiple armatures */ @@ -684,10 +688,10 @@ Object *modifiers_isDeformedByArmature(Object *ob) return NULL; } -Object *modifiers_isDeformedByMeshDeform(Object *ob) +Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); MeshDeformModifierData *mdmd = NULL; /* return the first selected armature, this lets us use multiple armatures */ @@ -710,10 +714,10 @@ Object *modifiers_isDeformedByMeshDeform(Object *ob) /* Takes an object and returns its first selected lattice, else just its lattice * This should work for multiple lattices per object */ -Object *modifiers_isDeformedByLattice(Object *ob) +Object *BKE_modifiers_is_deformed_by_lattice(Object *ob) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); LatticeModifierData *lmd = NULL; /* return the first selected lattice, this lets us use multiple lattices */ @@ -736,10 +740,10 @@ Object *modifiers_isDeformedByLattice(Object *ob) /* Takes an object and returns its first selected curve, else just its curve * This should work for multiple curves per object */ -Object *modifiers_isDeformedByCurve(Object *ob) +Object *BKE_modifiers_is_deformed_by_curve(Object *ob) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); CurveModifierData *cmd = NULL; /* return the first selected curve, this lets us use multiple curves */ @@ -759,10 +763,10 @@ Object *modifiers_isDeformedByCurve(Object *ob) return NULL; } -bool modifiers_usesMultires(Object *ob) +bool BKE_modifiers_uses_multires(Object *ob) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); MultiresModifierData *mmd = NULL; for (; md; md = md->next) { @@ -776,10 +780,10 @@ bool modifiers_usesMultires(Object *ob) return false; } -bool modifiers_usesArmature(Object *ob, bArmature *arm) +bool BKE_modifiers_uses_armature(Object *ob, bArmature *arm) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); for (; md; md = md->next) { if (md->type == eModifierType_Armature) { @@ -793,13 +797,13 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm) return false; } -bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob) +bool BKE_modifiers_uses_subsurf_facedots(struct Scene *scene, Object *ob) { /* Search (backward) in the modifier stack to find if we have a subsurf modifier (enabled) before * the last modifier displayed on cage (or if the subsurf is the last). */ VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); - int cage_index = modifiers_getCageIndex(scene, ob, NULL, 1); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); + int cage_index = BKE_modifiers_get_cage_index(scene, ob, NULL, 1); if (cage_index == -1) { return false; } @@ -809,10 +813,10 @@ bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob) } /* Now from this point, search for subsurf modifier. */ for (; md; md = md->prev) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (md->type == eModifierType_Subsurf) { ModifierMode mode = eModifierMode_Realtime | eModifierMode_Editmode; - if (modifier_isEnabled(scene, md, mode)) { + if (BKE_modifier_is_enabled(scene, md, mode)) { return true; } } @@ -828,48 +832,33 @@ bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob) return false; } -bool modifier_isCorrectableDeformed(ModifierData *md) +bool BKE_modifier_is_correctable_deformed(ModifierData *md) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); return mti->deformMatricesEM != NULL; } -bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob) +bool BKE_modifiers_is_correctable_deformed(struct Scene *scene, Object *ob) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); int required_mode = eModifierMode_Realtime; if (ob->mode == OB_MODE_EDIT) { required_mode |= eModifierMode_Editmode; } for (; md; md = md->next) { - if (!modifier_isEnabled(scene, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { /* pass */ } - else if (modifier_isCorrectableDeformed(md)) { + else if (BKE_modifier_is_correctable_deformed(md)) { return true; } } return false; } -/* Check whether the given object has a modifier in its stack that uses WEIGHT_MCOL CD layer - * to preview something... Used by DynamicPaint and WeightVG currently. */ -bool modifiers_isPreview(Object *ob) -{ - ModifierData *md = ob->modifiers.first; - - for (; md; md = md->next) { - if (modifier_isPreview(md)) { - return true; - } - } - - return false; -} - -void modifier_freeTemporaryData(ModifierData *md) +void BKE_modifier_free_temporary_data(ModifierData *md) { if (md->type == eModifierType_Armature) { ArmatureModifierData *amd = (ArmatureModifierData *)md; @@ -882,7 +871,7 @@ void modifier_freeTemporaryData(ModifierData *md) } /* ensure modifier correctness when changing ob->data */ -void test_object_modifiers(Object *ob) +void BKE_modifiers_test_object(Object *ob) { ModifierData *md; @@ -913,7 +902,7 @@ void test_object_modifiers(Object *ob) * - else if the file has been saved return the blend file path. * - else if the file isn't saved and the ID isn't from a library, return the temp dir. */ -const char *modifier_path_relbase(Main *bmain, Object *ob) +const char *BKE_modifier_path_relbase(Main *bmain, Object *ob) { if (G.relbase_valid || ID_IS_LINKED(ob)) { return ID_BLEND_PATH(bmain, &ob->id); @@ -925,7 +914,7 @@ const char *modifier_path_relbase(Main *bmain, Object *ob) } } -const char *modifier_path_relbase_from_global(Object *ob) +const char *BKE_modifier_path_relbase_from_global(Object *ob) { if (G.relbase_valid || ID_IS_LINKED(ob)) { return ID_BLEND_PATH_FROM_GLOBAL(&ob->id); @@ -938,35 +927,35 @@ const char *modifier_path_relbase_from_global(Object *ob) } /* initializes the path with either */ -void modifier_path_init(char *path, int path_maxlen, const char *name) +void BKE_modifier_path_init(char *path, int path_maxlen, const char *name) { /* elubie: changed this to default to the same dir as the render output * to prevent saving to C:\ on Windows */ BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name); } -/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */ +/* wrapper around ModifierTypeInfo.modifyMesh that ensures valid normals */ -struct Mesh *modwrap_applyModifier(ModifierData *md, - const ModifierEvalContext *ctx, - struct Mesh *me) +struct Mesh *BKE_modifier_modify_mesh(ModifierData *md, + const ModifierEvalContext *ctx, + struct Mesh *me) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false); if (mti->dependsOnNormals && mti->dependsOnNormals(md)) { BKE_mesh_calc_normals(me); } - return mti->applyModifier(md, ctx, me); + return mti->modifyMesh(md, ctx, me); } -void modwrap_deformVerts(ModifierData *md, - const ModifierEvalContext *ctx, - Mesh *me, - float (*vertexCos)[3], - int numVerts) +void BKE_modifier_deform_verts(ModifierData *md, + const ModifierEvalContext *ctx, + Mesh *me, + float (*vertexCos)[3], + int numVerts) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false); if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) { @@ -975,14 +964,14 @@ void modwrap_deformVerts(ModifierData *md, mti->deformVerts(md, ctx, me, vertexCos, numVerts); } -void modwrap_deformVertsEM(ModifierData *md, - const ModifierEvalContext *ctx, - struct BMEditMesh *em, - Mesh *me, - float (*vertexCos)[3], - int numVerts) +void BKE_modifier_deform_vertsEM(ModifierData *md, + const ModifierEvalContext *ctx, + struct BMEditMesh *em, + Mesh *me, + float (*vertexCos)[3], + int numVerts) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false); if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) { @@ -1025,7 +1014,7 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, return me; } -ModifierData *modifier_get_original(ModifierData *md) +ModifierData *BKE_modifier_get_original(ModifierData *md) { if (md->orig_modifier_data == NULL) { return md; @@ -1033,11 +1022,13 @@ ModifierData *modifier_get_original(ModifierData *md) return md->orig_modifier_data; } -struct ModifierData *modifier_get_evaluated(Depsgraph *depsgraph, Object *object, ModifierData *md) +struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph, + Object *object, + ModifierData *md) { Object *object_eval = DEG_get_evaluated_object(depsgraph, object); if (object_eval == object) { return md; } - return modifiers_findByName(object_eval, md->name); + return BKE_modifiers_findny_name(object_eval, md->name); } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 193fe859def..fe7c2055aef 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_movieclip_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -58,6 +59,7 @@ #include "BKE_idtype.h" #include "BKE_image.h" /* openanim */ #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_movieclip.h" #include "BKE_node.h" @@ -106,6 +108,27 @@ static void movie_clip_free_data(ID *id) BKE_tracking_free(&movie_clip->tracking); } +static void movie_clip_foreach_id(ID *id, LibraryForeachIDData *data) +{ + MovieClip *movie_clip = (MovieClip *)id; + MovieTracking *tracking = &movie_clip->tracking; + + BKE_LIB_FOREACHID_PROCESS(data, movie_clip->gpd, IDWALK_CB_USER); + + LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) { + BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER); + } + LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) { + LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) { + BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER); + } + } + + LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) { + BKE_LIB_FOREACHID_PROCESS(data, plane_track->image, IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_MC = { .id_code = ID_MC, .id_filter = FILTER_ID_MC, @@ -120,6 +143,7 @@ IDTypeInfo IDType_ID_MC = { .copy_data = movie_clip_copy_data, .free_data = movie_clip_free_data, .make_local = NULL, + .foreach_id = movie_clip_foreach_id, }; /*********************** movieclip buffer loaders *************************/ @@ -460,6 +484,7 @@ typedef struct MovieClipCache { float principal[2]; float polynomial_k[3]; float division_k[2]; + float nuke_k[2]; short distortion_model; bool undistortion_used; @@ -908,6 +933,9 @@ static bool check_undistortion_cache_flags(const MovieClip *clip) if (!equals_v2v2(&camera->division_k1, cache->postprocessed.division_k)) { return false; } + if (!equals_v2v2(&camera->nuke_k1, cache->postprocessed.nuke_k)) { + return false; + } return true; } @@ -1010,6 +1038,7 @@ static void put_postprocessed_frame_to_cache( copy_v2_v2(cache->postprocessed.principal, camera->principal); copy_v3_v3(cache->postprocessed.polynomial_k, &camera->k1); copy_v2_v2(cache->postprocessed.division_k, &camera->division_k1); + copy_v2_v2(cache->postprocessed.nuke_k, &camera->nuke_k1); cache->postprocessed.undistortion_used = true; } else { @@ -1512,7 +1541,8 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip undist_marker.pos[0] *= width; undist_marker.pos[1] *= height * aspy; - BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos); + BKE_tracking_undistort_v2( + &clip->tracking, width, height, undist_marker.pos, undist_marker.pos); undist_marker.pos[0] /= width; undist_marker.pos[1] /= height * aspy; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 69cd338e15f..7e78be6d66e 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -10,7 +10,7 @@ * 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, + * 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) 2007 by Nicholas Bishop @@ -289,8 +289,8 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, }; - const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type); - Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh); + const ModifierTypeInfo *mti = BKE_modifier_get_info(mmd->modifier.type); + Mesh *result = mti->modifyMesh(&mmd->modifier, &modifier_ctx, deformed_mesh); if (result == deformed_mesh) { result = BKE_mesh_copy_for_eval(deformed_mesh, true); @@ -318,8 +318,8 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; VirtualModifierData virtual_modifier_data; - ModifierData *first_md = modifiers_getVirtualModifierList(&object_for_eval, - &virtual_modifier_data); + ModifierData *first_md = BKE_modifiers_get_virtual_modifierlist(&object_for_eval, + &virtual_modifier_data); Mesh *base_mesh = object->data; @@ -327,13 +327,13 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(base_mesh, &num_deformed_verts); for (ModifierData *md = first_md; md != NULL; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (md == &mmd->modifier) { break; } - if (!modifier_isEnabled(scene_eval, md, required_mode)) { + if (!BKE_modifier_is_enabled(scene_eval, md, required_mode)) { continue; } @@ -341,7 +341,8 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep break; } - modwrap_deformVerts(md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts); + BKE_modifier_deform_verts( + md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts); } if (r_num_deformed_verts != NULL) { @@ -356,7 +357,7 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData * for (md = lastmd; md; md = md->prev) { if (md->type == eModifierType_Multires) { - if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { return (MultiresModifierData *)md; } } @@ -380,7 +381,7 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f firstmmd = (MultiresModifierData *)md; } - if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { mmd = (MultiresModifierData *)md; break; } @@ -407,7 +408,7 @@ int multires_get_level(const Scene *scene, mmd->renderlvl; } else if (ob->mode == OB_MODE_SCULPT) { - return BKE_multires_sculpt_level_get(mmd); + return mmd->sculptlvl; } else if (ignore_simplify) { return mmd->lvl; @@ -2193,10 +2194,10 @@ void multires_load_old(Object *ob, Mesh *me) /* Add a multires modifier to the object */ md = ob->modifiers.first; - while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) { + while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) { md = md->next; } - mmd = (MultiresModifierData *)modifier_new(eModifierType_Multires); + mmd = (MultiresModifierData *)BKE_modifier_new(eModifierType_Multires); BLI_insertlinkbefore(&ob->modifiers, md, mmd); for (i = 0; i < me->mr->level_count - 1; i++) { @@ -2234,7 +2235,14 @@ void multiresModifier_sync_levels_ex(Object *ob_dst, } if (mmd_src->totlvl > mmd_dst->totlvl) { - multiresModifier_subdivide_to_level(ob_dst, mmd_dst, mmd_src->totlvl); + if (mmd_dst->simple) { + multiresModifier_subdivide_to_level( + ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_SIMPLE); + } + else { + multiresModifier_subdivide_to_level( + ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_CATMULL_CLARK); + } } else { multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); @@ -2516,12 +2524,3 @@ int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert), return S; } - -/* This is a workaround for T58473. - * Force sculpting on the highest level for until the root of the issue is solved. - * - * When that issue is solved simple replace call of this function with mmd->sculptlvl. */ -int BKE_multires_sculpt_level_get(const struct MultiresModifierData *mmd) -{ - return mmd->totlvl; -} diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index 01e7b87cac0..64cc9130e25 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. @@ -28,8 +28,6 @@ #include "DNA_modifier_types.h" #include "DNA_scene_types.h" -#include "BLI_math_vector.h" - #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" @@ -37,14 +35,16 @@ #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_subdiv.h" +#include "BKE_subsurf.h" +#include "BLI_math_vector.h" #include "DEG_depsgraph_query.h" #include "multires_reshape.h" -/* ================================================================================================ - * Reshape from object. - */ +/* -------------------------------------------------------------------- */ +/** \name Reshape from object + * \{ */ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph, struct Object *object, @@ -93,9 +93,11 @@ bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph, return result; } -/* ================================================================================================ - * Reshape from modifier. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reshape from modifier + * \{ */ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, struct Object *object, @@ -119,7 +121,7 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, .object = object, .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, }; - modwrap_deformVerts( + BKE_modifier_deform_verts( deform_md, &modifier_ctx, multires_mesh, deformed_verts, multires_mesh->totvert); BKE_id_free(NULL, multires_mesh); @@ -133,9 +135,11 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, return result; } -/* ================================================================================================ - * Reshape from grids. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reshape from grids + * \{ */ bool multiresModifier_reshapeFromCCG(const int tot_level, Mesh *coarse_mesh, @@ -161,19 +165,24 @@ bool multiresModifier_reshapeFromCCG(const int tot_level, return true; } -/* ================================================================================================ - * Subdivision. - */ +/** \} */ -void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd) +/* -------------------------------------------------------------------- */ +/** \name Subdivision + * \{ */ + +void multiresModifier_subdivide(Object *object, + MultiresModifierData *mmd, + const eMultiresSubdivideModeType mode) { const int top_level = mmd->totlvl + 1; - multiresModifier_subdivide_to_level(object, mmd, top_level); + multiresModifier_subdivide_to_level(object, mmd, top_level, mode); } void multiresModifier_subdivide_to_level(struct Object *object, struct MultiresModifierData *mmd, - const int top_level) + const int top_level, + const eMultiresSubdivideModeType mode) { if (top_level <= mmd->totlvl) { return; @@ -199,7 +208,12 @@ void multiresModifier_subdivide_to_level(struct Object *object, * that the mdisps layer is also synchronized. */ if (!has_mdisps || top_level == 1 || mmd->totlvl == 0) { multires_reshape_ensure_grids(coarse_mesh, top_level); - multires_set_tot_level(object, mmd, top_level); + if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) { + multires_subdivide_create_tangent_displacement_linear_grids(object, mmd); + } + else { + multires_set_tot_level(object, mmd, top_level); + } return; } @@ -208,25 +222,34 @@ void multiresModifier_subdivide_to_level(struct Object *object, if (!multires_reshape_context_create_from_subdivide(&reshape_context, object, mmd, top_level)) { return; } + multires_reshape_store_original_grids(&reshape_context); multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level); - multires_reshape_assign_final_coords_from_orig_mdisps(&reshape_context); + multires_reshape_assign_final_elements_from_orig_mdisps(&reshape_context); /* Free original grids which makes it so smoothing with details thinks all the details were * added against base mesh's limit surface. This is similar behavior to as if we've done all - * displacement in sculpt mode at the old top level and then propagated to the new top level. */ + * displacement in sculpt mode at the old top level and then propagated to the new top level.*/ multires_reshape_free_original_grids(&reshape_context); - multires_reshape_smooth_object_grids_with_details(&reshape_context); + if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) { + multires_reshape_smooth_object_grids(&reshape_context, mode); + } + else { + multires_reshape_smooth_object_grids_with_details(&reshape_context); + } + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); multires_reshape_context_free(&reshape_context); multires_set_tot_level(object, mmd, top_level); } -/* ================================================================================================ - * Apply base. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Apply base + * \{ */ void multiresModifier_base_apply(struct Depsgraph *depsgraph, Object *object, @@ -272,3 +295,5 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph, multires_reshape_context_free(&reshape_context); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h index adfa2659661..12816a455ee 100644 --- a/source/blender/blenkernel/intern/multires_reshape.h +++ b/source/blender/blenkernel/intern/multires_reshape.h @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. @@ -26,6 +26,8 @@ #include "BLI_sys_types.h" +#include "BKE_multires.h" + struct Depsgraph; struct GridPaintMask; struct MDisps; @@ -138,7 +140,7 @@ typedef struct ReshapeConstGridElement { float mask; } ReshapeConstGridElement; -/* ================================================================================================ +/* -------------------------------------------------------------------- * Construct/destruct reshape context. */ @@ -156,6 +158,11 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape struct Object *object, struct MultiresModifierData *mmd); +bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context, + struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd); + bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context, struct SubdivCCG *subdiv_ccg, struct Mesh *base_mesh, @@ -169,7 +176,7 @@ bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *resh void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context); void multires_reshape_context_free(MultiresReshapeContext *reshape_context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Helper accessors. */ @@ -214,7 +221,7 @@ ReshapeGridElement multires_reshape_grid_element_for_ptex_coord( ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord( const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Sample limit surface of the base mesh. */ @@ -225,14 +232,14 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha float r_P[3], float r_tangent_matrix[3][3]); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Custom data preparation. */ /* Make sure custom data is allocated for the given level. */ void multires_reshape_ensure_grids(struct Mesh *mesh, const int level); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Functions specific to reshaping from a set of vertices in a object position. */ @@ -245,17 +252,21 @@ bool multires_reshape_assign_final_coords_from_vertcos( const float (*vert_coords)[3], const int num_vert_coords); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Functions specific to reshaping from CCG. */ -/* NOTE: Displacement grids to be at least at a reshape level. +/* Store final object-space coordinates in the displacement grids. + * The reason why displacement grids are used for storage is based on memory + * footprint optimization. + * + * NOTE: Displacement grids to be at least at a reshape level. * * Return truth if all coordinates have been updated. */ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context, struct SubdivCCG *subdiv_ccg); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Functions specific to reshaping from MDISPS. */ @@ -264,10 +275,10 @@ void multires_reshape_assign_final_coords_from_mdisps( const MultiresReshapeContext *reshape_context); /* Reads from original CD_MIDTSPS, writes to the current mesh CD_MDISPS. */ -void multires_reshape_assign_final_coords_from_orig_mdisps( +void multires_reshape_assign_final_elements_from_orig_mdisps( const MultiresReshapeContext *reshape_context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Displacement smooth. */ @@ -284,9 +295,10 @@ void multires_reshape_smooth_object_grids_with_details( * * Makes it so surface on top level looks smooth. Details are not preserved */ -void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context); +void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context, + const enum eMultiresSubdivideModeType mode); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Displacement, space conversion. */ @@ -297,7 +309,7 @@ void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_conte void multires_reshape_object_grids_to_tangent_displacement( const MultiresReshapeContext *reshape_context); -/* ================================================================================================ +/* -------------------------------------------------------------------- * Apply base. */ @@ -319,5 +331,4 @@ void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshap * * NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */ void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context); - #endif /* __BKE_INTERN_MULTIRES_RESHAPE_H__ */ diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c index e67e553e8ed..105e56e4219 100644 --- a/source/blender/blenkernel/intern/multires_reshape_apply_base.c +++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. diff --git a/source/blender/blenkernel/intern/multires_reshape_ccg.c b/source/blender/blenkernel/intern/multires_reshape_ccg.c index 1f8c782ed46..8273845e820 100644 --- a/source/blender/blenkernel/intern/multires_reshape_ccg.c +++ b/source/blender/blenkernel/intern/multires_reshape_ccg.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index d99e27ad9dd..7312ac2bf5e 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. @@ -48,6 +48,15 @@ #include "atomic_ops.h" #include "subdiv_converter.h" +/* -------------------------------------------------------------------- */ +/** \name Local Structs + * \{ */ + +/* Surface refers to a simplified and lower-memory footprint representation of the limit surface. + * + * Used to store pre-calculated information which is expensive or impossible to evaluate when + * travesing the final limit surface. */ + typedef struct SurfacePoint { float P[3]; float tangent_matrix[3][3]; @@ -57,6 +66,9 @@ typedef struct SurfaceGrid { SurfacePoint *points; } SurfaceGrid; +/* Geometry elements which are used to simplify creation of topology refiner at the sculpt level. + * Contains a limited subset of information needed to construct topology refiner. */ + typedef struct Vertex { /* All grid coordinates which the vertex corresponding to. * For a vertices which are created from inner points of grids there is always one coordinate. */ @@ -83,6 +95,32 @@ typedef struct Edge { float sharpness; } Edge; +/* Storage of data which is linearly interpolated from the reshape level to the top level. */ + +typedef struct LinearGridElement { + float mask; +} LinearGridElement; + +typedef struct LinearGrid { + LinearGridElement *elements; +} LinearGrid; + +typedef struct LinearGrids { + int num_grids; + int level; + + /* Cached size for the grid, for faster lookup. */ + int grid_size; + + /* Indexed by grid index. */ + LinearGrid *grids; + + /* Elements for all grids are allocated in a single array, for the allocation performance. */ + LinearGridElement *elements_storage; +} LinearGrids; + +/* Context which holds all information eeded during propagation and smoothing. */ + typedef struct MultiresReshapeSmoothContext { const MultiresReshapeContext *reshape_context; @@ -108,66 +146,118 @@ typedef struct MultiresReshapeSmoothContext { Face *faces; } geometry; + /* Grids of data which is linearly interpolated between grid elements at the reshape level. + * The data is actually stored as a delta, which is then to be added to the higher levels. */ + LinearGrids linear_delta_grids; + /* Index i of this map indicates that base edge i is adjacent to at least one face. */ BLI_bitmap *non_loose_base_edge_map; /* Subdivision surface created for geometry at a reshape level. */ Subdiv *reshape_subdiv; + /* Limit surface of the base mesh with original sculpt level details on it, subdivided up to the + * top level. + * Is used as a base point to calculate how much displacement has been made in the sculpt mode. + * + * NOTE: Referring to sculpt as it is the main user of this functionality and it is clear to + * understand what it actually means in a concrete example. This is a generic code which is also + * used by Subdivide operation, but the idea is exactly the same as propagation in the sculpt + * mode. */ SurfaceGrid *base_surface_grids; + + /* Defines how displacement is interpolated on the higher levels (for example, whether + * displacement is smoothed in Catmull-Clark mode or interpolated linearly preserving sharp edges + * of the current sculpt level). + * + * NOTE: Uses same enumerator type as Subdivide operator, since the values are the same and + * decoupling type just adds extra headache to convert one enumerator to another. */ + eMultiresSubdivideModeType smoothing_type; } MultiresReshapeSmoothContext; -/* ================================================================================================ - * Masks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Linear grids manipulation + * \{ */ -/* Interpolate mask grid at a reshape level. - * Will return 0 if there is no masks custom data layer. */ -static float interpolate_masks_grid(const MultiresReshapeSmoothContext *reshape_smooth_context, - const GridCoord *grid_coord) +static void linear_grids_init(LinearGrids *linear_grids) { - const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; - if (reshape_context->orig.grid_paint_masks == NULL) { - return 0.0f; - } + linear_grids->num_grids = 0; + linear_grids->level = 0; - const GridPaintMask *grid = &reshape_context->orig.grid_paint_masks[grid_coord->grid_index]; - const int grid_size = BKE_subdiv_grid_size_from_level(grid->level); - const int grid_size_1 = grid_size - 1; - const float grid_size_1_inv = 1.0f / (float)(grid_size_1); + linear_grids->grids = NULL; + linear_grids->elements_storage = NULL; +} - const float x_f = grid_coord->u * grid_size_1; - const float y_f = grid_coord->v * grid_size_1; +static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level) +{ + const size_t grid_size = BKE_subdiv_grid_size_from_level(level); + const size_t grid_area = grid_size * grid_size; + const size_t num_grid_elements = num_grids * grid_area; - const int x_i = x_f; - const int y_i = y_f; - const int x_n_i = (x_i == grid_size - 1) ? (x_i) : (x_i + 1); - const int y_n_i = (y_i == grid_size - 1) ? (y_i) : (y_i + 1); + linear_grids->num_grids = num_grids; + linear_grids->level = level; + linear_grids->grid_size = grid_size; - const int corners[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}}; - float mask_elements[4]; - for (int i = 0; i < 4; ++i) { - GridCoord corner_grid_coord; - corner_grid_coord.grid_index = grid_coord->grid_index; - corner_grid_coord.u = corners[i][0] * grid_size_1_inv; - corner_grid_coord.v = corners[i][1] * grid_size_1_inv; + linear_grids->grids = MEM_malloc_arrayN(num_grids, sizeof(LinearGrid), "linear grids"); + linear_grids->elements_storage = MEM_calloc_arrayN( + num_grid_elements, sizeof(LinearGridElement), "linear elements storage"); - ReshapeConstGridElement element = multires_reshape_orig_grid_element_for_grid_coord( - reshape_context, &corner_grid_coord); - mask_elements[i] = element.mask; + for (int i = 0; i < num_grids; ++i) { + const size_t element_offset = grid_area * i; + linear_grids->grids[i].elements = &linear_grids->elements_storage[element_offset]; } +} - const float u = x_f - x_i; - const float v = y_f - y_i; - const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), (1.0f - u) * v, u * v}; +static LinearGridElement *linear_grid_element_get(const LinearGrids *linear_grids, + const GridCoord *grid_coord) +{ + BLI_assert(grid_coord->grid_index >= 0); + BLI_assert(grid_coord->grid_index < linear_grids->num_grids); + + const int grid_size = linear_grids->grid_size; - return mask_elements[0] * weights[0] + mask_elements[1] * weights[1] + - mask_elements[2] * weights[2] + mask_elements[3] * weights[3]; + const int grid_x = lround(grid_coord->u * (grid_size - 1)); + const int grid_y = lround(grid_coord->v * (grid_size - 1)); + const int grid_element_index = grid_y * grid_size + grid_x; + + LinearGrid *grid = &linear_grids->grids[grid_coord->grid_index]; + return &grid->elements[grid_element_index]; } -/* ================================================================================================ - * Surface. - */ +static void linear_grids_free(LinearGrids *linear_grids) +{ + MEM_SAFE_FREE(linear_grids->grids); + MEM_SAFE_FREE(linear_grids->elements_storage); +} + +static void linear_grid_element_init(LinearGridElement *linear_grid_element) +{ + linear_grid_element->mask = 0.0f; +} + +/* result = a - b. */ +static void linear_grid_element_sub(LinearGridElement *result, + const LinearGridElement *a, + const LinearGridElement *b) +{ + result->mask = a->mask - b->mask; +} + +static void linear_grid_element_interpolate(LinearGridElement *result, + const LinearGridElement elements[4], + const float weights[4]) +{ + result->mask = elements[0].mask * weights[0] + elements[1].mask * weights[1] + + elements[2].mask * weights[2] + elements[3].mask * weights[3]; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Surface + * \{ */ static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context) { @@ -227,9 +317,11 @@ static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape copy_m3_m3(point->tangent_matrix, tangent_matrix); } -/* ================================================================================================ - * Evaluation of subdivision surface at a reshape level. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation of subdivision surface at a reshape level + * \{ */ typedef void (*ForeachTopLevelGridCoordCallback)( const MultiresReshapeSmoothContext *reshape_smooth_context, @@ -383,11 +475,14 @@ static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *resh 0, num_faces, &data, foreach_toplevel_grid_coord_task, ¶llel_range_settings); } -/* ================================================================================================ - * Generation of a topology information for OpenSubdiv converter. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generation of a topology information for OpenSubdiv converter * * Calculates vertices, their coordinates in the original grids, and connections of them so then - * it's easy to create OpenSubdiv's topology refiner. */ + * it's easy to create OpenSubdiv's topology refiner. + * \{ */ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context) { @@ -399,15 +494,17 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co static char get_effective_edge_crease_char( const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge) { - const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; - if (reshape_context->subdiv->settings.is_simple) { + if (ELEM(reshape_smooth_context->smoothing_type, + MULTIRES_SUBDIVIDE_LINEAR, + MULTIRES_SUBDIVIDE_SIMPLE)) { return 255; } return base_edge->crease; } static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context, - const MultiresReshapeContext *reshape_context) + const MultiresReshapeContext *reshape_context, + const eMultiresSubdivideModeType mode) { reshape_smooth_context->reshape_context = reshape_context; @@ -424,9 +521,13 @@ static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context, reshape_smooth_context->geometry.num_faces = 0; reshape_smooth_context->geometry.faces = NULL; + linear_grids_init(&reshape_smooth_context->linear_delta_grids); + reshape_smooth_context->non_loose_base_edge_map = NULL; reshape_smooth_context->reshape_subdiv = NULL; reshape_smooth_context->base_surface_grids = NULL; + + reshape_smooth_context->smoothing_type = mode; } static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context) @@ -440,6 +541,8 @@ static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_c MEM_SAFE_FREE(reshape_smooth_context->geometry.corners); MEM_SAFE_FREE(reshape_smooth_context->geometry.faces); MEM_SAFE_FREE(reshape_smooth_context->geometry.edges); + + linear_grids_free(&reshape_smooth_context->linear_delta_grids); } static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context) @@ -461,12 +564,14 @@ static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context) static bool foreach_topology_info(const SubdivForeachContext *foreach_context, const int num_vertices, - const int UNUSED(num_edges), + const int num_edges, const int num_loops, const int num_polygons) { MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; - const int max_edges = reshape_smooth_context->geometry.max_edges; + const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ? + num_edges : + reshape_smooth_context->geometry.max_edges; /* NOTE: Calloc so the counters are re-set to 0 "for free". */ reshape_smooth_context->geometry.num_vertices = num_vertices; @@ -659,6 +764,22 @@ static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *fore } } +static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context, + const int subdiv_v1, + const int subdiv_v2, + const char crease) +{ + /* This is a bit overhead to use atomics in such a simple function called from many threads, + * but this allows to save quite measurable amount of memory. */ + const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1); + BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges); + + Edge *edge = &reshape_smooth_context->geometry.edges[edge_index]; + edge->v1 = subdiv_v1; + edge->v2 = subdiv_v2; + edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease); +} + static void foreach_edge(const struct SubdivForeachContext *foreach_context, void *UNUSED(tls), const int coarse_edge_index, @@ -669,8 +790,15 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context, MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; - /* Ignore all inner face edges as they have sharpness of zero. */ - if (coarse_edge_index == ORIGINDEX_NONE) { + if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) { + store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, (char)255); + return; + } + + /* Ignore all inner face edges as they have sharpness of zero when using Catmull-Clark mode. In + * simple mode, all edges have maximum sharpness, so they can't be skipped. */ + if (coarse_edge_index == ORIGINDEX_NONE && + reshape_smooth_context->smoothing_type != MULTIRES_SUBDIVIDE_SIMPLE) { return; } /* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */ @@ -684,16 +812,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context, if (crease == 0) { return; } - - /* This is a bit overhead to use atomics in such a simple function called from many threads, - * but this allows to save quite measurable amount of memory. */ - const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1); - BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges); - - Edge *edge = &reshape_smooth_context->geometry.edges[edge_index]; - edge->v1 = subdiv_v1; - edge->v2 = subdiv_v2; - edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease); + store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, crease); } static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshape_smooth_context) @@ -757,9 +876,11 @@ static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh); } -/* ================================================================================================ - * Generation of OpenSubdiv evaluator for topology created form reshape level. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generation of OpenSubdiv evaluator for topology created form reshape level + * \{ */ static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *UNUSED(converter)) { @@ -1037,9 +1158,138 @@ static void reshape_subdiv_evaluate_limit_at_grid( BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, corner); } -/* ================================================================================================ - * Evaluation of base surface. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Linearly interpolated data + * \{ */ + +static LinearGridElement linear_grid_element_orig_get( + const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const ReshapeConstGridElement orig_grid_element = + multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord); + + LinearGridElement linear_grid_element; + linear_grid_element_init(&linear_grid_element); + + linear_grid_element.mask = orig_grid_element.mask; + + return linear_grid_element; +} + +static LinearGridElement linear_grid_element_final_get( + const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const ReshapeGridElement final_grid_element = multires_reshape_grid_element_for_grid_coord( + reshape_context, grid_coord); + + LinearGridElement linear_grid_element; + linear_grid_element_init(&linear_grid_element); + + if (final_grid_element.mask != NULL) { + linear_grid_element.mask = *final_grid_element.mask; + } + + return linear_grid_element; +} + +/* Interpolate difference of the linear data. + * + * Will access final data and original data at the grid elements at the reshape level, + * calculate difference between final and original, and linearly interpolate to get value at the + * top level. */ +static void linear_grid_element_delta_interpolate( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const GridCoord *grid_coord, + LinearGridElement *result) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + const int reshape_level = reshape_context->reshape.level; + const int reshape_level_grid_size = BKE_subdiv_grid_size_from_level(reshape_level); + const int reshape_level_grid_size_1 = reshape_level_grid_size - 1; + const float reshape_level_grid_size_1_inv = 1.0f / (float)(reshape_level_grid_size_1); + + const float x_f = grid_coord->u * reshape_level_grid_size_1; + const float y_f = grid_coord->v * reshape_level_grid_size_1; + + const int x_i = x_f; + const int y_i = y_f; + const int x_n_i = (x_i == reshape_level_grid_size - 1) ? (x_i) : (x_i + 1); + const int y_n_i = (y_i == reshape_level_grid_size - 1) ? (y_i) : (y_i + 1); + + const int corners_int_coords[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}}; + + LinearGridElement corner_elements[4]; + for (int i = 0; i < 4; ++i) { + GridCoord corner_grid_coord; + corner_grid_coord.grid_index = grid_coord->grid_index; + corner_grid_coord.u = corners_int_coords[i][0] * reshape_level_grid_size_1_inv; + corner_grid_coord.v = corners_int_coords[i][1] * reshape_level_grid_size_1_inv; + + const LinearGridElement orig_element = linear_grid_element_orig_get(reshape_smooth_context, + &corner_grid_coord); + const LinearGridElement final_element = linear_grid_element_final_get(reshape_smooth_context, + &corner_grid_coord); + linear_grid_element_sub(&corner_elements[i], &final_element, &orig_element); + } + + const float u = x_f - x_i; + const float v = y_f - y_i; + const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v}; + + linear_grid_element_interpolate(result, corner_elements, weights); +} + +static void evaluate_linear_delta_grids_callback( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const PTexCoord *UNUSED(ptex_coord), + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) +{ + LinearGridElement *linear_delta_element = linear_grid_element_get( + &reshape_smooth_context->linear_delta_grids, grid_coord); + + linear_grid_element_delta_interpolate(reshape_smooth_context, grid_coord, linear_delta_element); +} + +static void evaluate_linear_delta_grids(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const int num_grids = reshape_context->num_grids; + const int top_level = reshape_context->top.level; + + linear_grids_allocate(&reshape_smooth_context->linear_delta_grids, num_grids, top_level); + + foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_linear_delta_grids_callback, NULL); +} + +static void propagate_linear_data_delta(const MultiresReshapeSmoothContext *reshape_smooth_context, + ReshapeGridElement *final_grid_element, + const GridCoord *grid_coord) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + LinearGridElement *linear_delta_element = linear_grid_element_get( + &reshape_smooth_context->linear_delta_grids, grid_coord); + + const ReshapeConstGridElement orig_grid_element = + multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord); + + if (final_grid_element->mask != NULL) { + *final_grid_element->mask = clamp_f( + orig_grid_element.mask + linear_delta_element->mask, 0.0f, 1.0f); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation of base surface + * \{ */ static void evaluate_base_surface_grids_callback( const MultiresReshapeSmoothContext *reshape_smooth_context, @@ -1060,9 +1310,11 @@ static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *resh foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_base_surface_grids_callback, NULL); } -/* ================================================================================================ - * Evaluation of new surface. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation of new surface + * \{ */ /* Evaluate final position of the original (pre-sculpt-edit) point position at a given grid * coordinate. */ @@ -1136,7 +1388,11 @@ static void evaluate_higher_grid_positions_with_details_callback( grid_coord); add_v3_v3v3(grid_element.displacement, smooth_limit_P, smooth_delta); + + /* Propagate non-coordinate data. */ + propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord); } + static void evaluate_higher_grid_positions_with_details( const MultiresReshapeSmoothContext *reshape_smooth_context) { @@ -1157,17 +1413,14 @@ static void evaluate_higher_grid_positions_callback( grid_coord); /* Surface. */ - float P[3]; BKE_subdiv_eval_limit_point( reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P); copy_v3_v3(grid_element.displacement, P); - /* Masks. */ - if (grid_element.mask != NULL) { - *grid_element.mask = interpolate_masks_grid(reshape_smooth_context, grid_coord); - } + /* Propagate non-coordinate data. */ + propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord); } static void evaluate_higher_grid_positions( @@ -1176,9 +1429,12 @@ static void evaluate_higher_grid_positions( foreach_toplevel_grid_coord( reshape_smooth_context, evaluate_higher_grid_positions_callback, NULL); } -/* ================================================================================================ - * Entry point. - */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Entry point + * \{ */ void multires_reshape_smooth_object_grids_with_details( const MultiresReshapeContext *reshape_context) @@ -1190,9 +1446,15 @@ void multires_reshape_smooth_object_grids_with_details( } MultiresReshapeSmoothContext reshape_smooth_context; - context_init(&reshape_smooth_context, reshape_context); + if (reshape_context->subdiv->settings.is_simple) { + context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_SIMPLE); + } + else { + context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_CATMULL_CLARK); + } geometry_create(&reshape_smooth_context); + evaluate_linear_delta_grids(&reshape_smooth_context); reshape_subdiv_create(&reshape_smooth_context); @@ -1206,7 +1468,8 @@ void multires_reshape_smooth_object_grids_with_details( context_free(&reshape_smooth_context); } -void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context) +void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context, + const eMultiresSubdivideModeType mode) { const int level_difference = (reshape_context->top.level - reshape_context->reshape.level); if (level_difference == 0) { @@ -1215,9 +1478,10 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_ } MultiresReshapeSmoothContext reshape_smooth_context; - context_init(&reshape_smooth_context, reshape_context); + context_init(&reshape_smooth_context, reshape_context, mode); geometry_create(&reshape_smooth_context); + evaluate_linear_delta_grids(&reshape_smooth_context); reshape_subdiv_create(&reshape_smooth_context); @@ -1226,3 +1490,5 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_ context_free(&reshape_smooth_context); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c new file mode 100644 index 00000000000..7b7c1efc533 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c @@ -0,0 +1,106 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subsurf.h" +#include "BLI_math_vector.h" + +#include "DEG_depsgraph_query.h" + +#include "multires_reshape.h" + +static void multires_subdivide_create_object_space_linear_grids(Mesh *mesh) +{ + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + const int totpoly = mesh->totpoly; + for (int p = 0; p < totpoly; p++) { + MPoly *poly = &mesh->mpoly[p]; + float poly_center[3]; + BKE_mesh_calc_poly_center(poly, &mesh->mloop[poly->loopstart], mesh->mvert, poly_center); + for (int l = 0; l < poly->totloop; l++) { + const int loop_index = poly->loopstart + l; + + float(*disps)[3] = mdisps[loop_index].disps; + mdisps[loop_index].totdisp = 4; + mdisps[loop_index].level = 1; + + int prev_loop_index = l - 1 >= 0 ? loop_index - 1 : loop_index + poly->totloop - 1; + int next_loop_index = l + 1 < poly->totloop ? loop_index + 1 : poly->loopstart; + + MLoop *loop = &mesh->mloop[loop_index]; + MLoop *loop_next = &mesh->mloop[next_loop_index]; + MLoop *loop_prev = &mesh->mloop[prev_loop_index]; + + copy_v3_v3(disps[0], poly_center); + mid_v3_v3v3(disps[1], mesh->mvert[loop->v].co, mesh->mvert[loop_next->v].co); + mid_v3_v3v3(disps[2], mesh->mvert[loop->v].co, mesh->mvert[loop_prev->v].co); + copy_v3_v3(disps[3], mesh->mvert[loop->v].co); + } + } +} + +void multires_subdivide_create_tangent_displacement_linear_grids(Object *object, + MultiresModifierData *mmd) +{ + Mesh *coarse_mesh = object->data; + multires_force_sculpt_rebuild(object); + + MultiresReshapeContext reshape_context; + + const int new_top_level = mmd->totlvl + 1; + + const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); + if (!has_mdisps) { + CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + } + + if (new_top_level == 1) { + /* No MDISPS. Create new grids for level 1 using the edges mid point and poly centers. */ + multires_reshape_ensure_grids(coarse_mesh, 1); + multires_subdivide_create_object_space_linear_grids(coarse_mesh); + } + + /* Convert the new grids to tangent displacement. */ + multires_set_tot_level(object, mmd, new_top_level); + + if (!multires_reshape_context_create_from_subdivide( + &reshape_context, object, mmd, new_top_level)) { + return; + } + + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_reshape_context_free(&reshape_context); +} diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c index 57d790d2c34..e9a779dafeb 100644 --- a/source/blender/blenkernel/intern/multires_reshape_util.c +++ b/source/blender/blenkernel/intern/multires_reshape_util.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. @@ -43,9 +43,9 @@ #include "DEG_depsgraph_query.h" -/* ================================================================================================ - * Construct/destruct reshape context. - */ +/* -------------------------------------------------------------------- */ +/** \name Construct/destruct reshape context + * \{ */ /* Create subdivision surface descriptor which is configured for surface evaluation at a given * multires modifier. */ @@ -152,6 +152,39 @@ static bool context_verify_or_free(MultiresReshapeContext *reshape_context) return is_valid; } +bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context, + Depsgraph *depsgraph, + Object *object, + MultiresModifierData *mmd) +{ + context_zero(reshape_context); + + const bool use_render_params = false; + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Mesh *base_mesh = (Mesh *)object->data; + + reshape_context->depsgraph = depsgraph; + reshape_context->object = object; + reshape_context->mmd = mmd; + + reshape_context->base_mesh = base_mesh; + + reshape_context->subdiv = multires_reshape_create_subdiv(NULL, object, mmd); + reshape_context->need_free_subdiv = true; + + reshape_context->reshape.level = multires_get_level( + scene_eval, object, mmd, use_render_params, true); + reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level( + reshape_context->reshape.level); + + reshape_context->top.level = mmd->totlvl; + reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level); + + context_init_commoon(reshape_context); + + return context_verify_or_free(reshape_context); +} + bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context, Depsgraph *depsgraph, Object *object, @@ -272,14 +305,16 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context) multires_reshape_free_original_grids(reshape_context); - MEM_freeN(reshape_context->face_start_grid_index); - MEM_freeN(reshape_context->ptex_start_grid_index); - MEM_freeN(reshape_context->grid_to_face_index); + MEM_SAFE_FREE(reshape_context->face_start_grid_index); + MEM_SAFE_FREE(reshape_context->ptex_start_grid_index); + MEM_SAFE_FREE(reshape_context->grid_to_face_index); } -/* ================================================================================================ - * Helper accessors. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Helper accessors + * \{ */ /* For the given grid index get index of face it was created for. */ int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context, @@ -453,9 +488,11 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord( return grid_element; } -/* ================================================================================================ - * Sample limit surface of the base mesh. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample limit surface of the base mesh + * \{ */ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord, @@ -475,9 +512,11 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix); } -/* ================================================================================================ - * Custom data preparation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom data preparation + * \{ */ static void allocate_displacement_grid(MDisps *displacement_grid, const int level) { @@ -539,9 +578,11 @@ void multires_reshape_ensure_grids(Mesh *mesh, const int level) ensure_mask_grids(mesh, level); } -/* ================================================================================================ - * Displacement, space conversion. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Displacement, space conversion + * \{ */ void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context) { @@ -678,10 +719,13 @@ void multires_reshape_object_grids_to_tangent_displacement( NULL); } -/* ================================================================================================ - * MDISPS - * - * TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name MDISPS + * \{ */ + +/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to * own file. */ static void assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context, @@ -707,9 +751,9 @@ void multires_reshape_assign_final_coords_from_mdisps( reshape_context, reshape_context->top.level, assign_final_coords_from_mdisps, NULL); } -static void assign_final_coords_from_orig_mdisps(const MultiresReshapeContext *reshape_context, - const GridCoord *grid_coord, - void *UNUSED(userdata_v)) +static void assign_final_elements_from_orig_mdisps(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) { float P[3]; float tangent_matrix[3][3]; @@ -724,11 +768,17 @@ static void assign_final_coords_from_orig_mdisps(const MultiresReshapeContext *r ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context, grid_coord); add_v3_v3v3(grid_element.displacement, P, D); + + if (grid_element.mask != NULL) { + *grid_element.mask = orig_grid_element.mask; + } } -void multires_reshape_assign_final_coords_from_orig_mdisps( +void multires_reshape_assign_final_elements_from_orig_mdisps( const MultiresReshapeContext *reshape_context) { foreach_grid_coordinate( - reshape_context, reshape_context->top.level, assign_final_coords_from_orig_mdisps, NULL); + reshape_context, reshape_context->top.level, assign_final_elements_from_orig_mdisps, NULL); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c index 1ece7344f37..04df5698cf9 100644 --- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c +++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c @@ -10,7 +10,7 @@ * 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, + * 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) 2020 Blender Foundation. diff --git a/source/blender/blenkernel/intern/multires_subdiv.c b/source/blender/blenkernel/intern/multires_subdiv.c index f7e42942f3e..fc092d3ccce 100644 --- a/source/blender/blenkernel/intern/multires_subdiv.c +++ b/source/blender/blenkernel/intern/multires_subdiv.c @@ -10,7 +10,7 @@ * 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, + * 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) 2018 Blender Foundation. diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c new file mode 100644 index 00000000000..e5000e7774f --- /dev/null +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -0,0 +1,1297 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + * + * This implements the un-subdivide algorithm, which generates a lower resolution base mesh and + * its corresponding grids to match a given original mesh. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BLI_gsqueue.h" +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subsurf.h" + +#include "bmesh.h" + +#include "DEG_depsgraph_query.h" + +#include "multires_reshape.h" +#include "multires_unsubdivide.h" + +/* This is done in the following steps: + * + * - If there are already grids in the original mesh, + * convert them from tangent displacement to object space coordinates. + * - Assign data-layers to the original mesh to map vertices to a new base mesh. + * These data-layers store the indices of the elements in the original mesh. + * This way the original indices are + * preserved when doing mesh modifications (removing and dissolving vertices) + * when building the new base mesh. + * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the + * center vertices of the lower level grid. + * If the algorithm can tag all vertices correctly, + * the lower level base mesh is generated by dissolving the tagged vertices. + * - Use the data-layers to map vertices from the base mesh to the original mesh and original to + * base mesh. + * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh + * to original mesh + * - Extract the grid from the original mesh from that loop. If there are no grids in the original + * mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern + * over them. If there are grids in the original mesh, iterate in a grid pattern over the polys, + * reorder all the coordinates of the grid in that poly and copy those coordinates to the new + * base mesh grid. + * - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store + * the new levels. + * - Convert the grid data from object space to tangent displacement. + */ + +/** + * Used to check if a vertex is in a disconnected element ID. + */ +static bool is_vertex_in_id(BMVert *v, int *elem_id, int elem) +{ + const int v_index = BM_elem_index_get(v); + return elem_id[v_index] == elem; +} + +static bool is_vertex_pole_three(BMVert *v) +{ + return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3); +} + +static bool is_vertex_pole(BMVert *v) +{ + return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5); +} + +/** + * Returns the first pole that is found in an element ID. + * + * Tries to give priority to 3 vert poles as they generally generate better results in cases were + * the un-subdivide solution is ambiguous. + */ +static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem) +{ + BMIter iter; + BMVert *v; + BMVert *pole = NULL; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole_three(v)) { + return v; + } + else if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole(v)) { + pole = v; + } + } + return pole; +} + +/** + * Checks if the mesh is all quads. + * + * TODO(pablodp606): This can perform additional checks if they are faster than trying to search + * for an un-subdivide solution. This way it is possible to cancel the operation faster. + */ +static bool unsubdivide_is_all_quads(BMesh *bm) +{ + BMIter iter; + BMIter iter_a; + BMFace *f; + BMVert *v; + int count = 0; + if (bm->totface < 3) { + return false; + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + count = 0; + BM_ITER_ELEM (v, &iter_a, f, BM_VERTS_OF_FACE) { + count++; + } + + if (count != 4) { + return false; + } + } + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_vert_is_wire(v)) { + return false; + } + if (BM_vert_edge_count(v) == 0) { + return false; + } + } + + return true; +} + +/** + * Returns true if from_v and to_v, which should be part of the same quad face, are diagonals. + */ +static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v) +{ + return !BM_edge_exists(from_v, to_v); +} + +/** + * Generates a possible solution for un-subdivision by tagging the (0,0) + * vertices of the possible grids. + * + * This works using a flood fill operation using the quads diagonals to jump to the next vertex. + * + * If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0) + * vertices of the grids that need to be dissolved, and nothing else. + */ +static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex) +{ + bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices"); + GSQueue *queue; + queue = BLI_gsqueue_new(sizeof(BMVert *)); + + /* Add and tag the vertices connected by a diagonal to initial_vertex to the flood fill queue. If + * initial_vertex is a pole and there is a valid solution, those vertices should be the (0,0) of + * the grids for the loops of initial_vertex. */ + BMIter iter; + BMIter iter_a; + BMFace *f; + BMVert *neighbor_v; + BM_ITER_ELEM (f, &iter, initial_vertex, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) { + int neighbor_vertex_index = BM_elem_index_get(neighbor_v); + if (neighbor_v != initial_vertex && is_vertex_diagonal(neighbor_v, initial_vertex)) { + BLI_gsqueue_push(queue, &neighbor_v); + visited_vertices[neighbor_vertex_index] = true; + BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true); + } + } + } + + /* Repeat a similar operation for all vertices in the queue. */ + /* In this case, add to the queue the vertices connected by 2 steps using the diagonals in any + * direction. If a solution exists and intial_vertex was a pole, this is guaranteed that will tag + * all the (0,0) vertices of the grids, and nothing else. */ + /* If it was not a pole, it may or may not find a solution, even if the solution exists. */ + while (!BLI_gsqueue_is_empty(queue)) { + BMVert *from_v; + BLI_gsqueue_pop(queue, &from_v); + + /* Get the diagonals (first connected step) */ + GSQueue *diagonals; + diagonals = BLI_gsqueue_new(sizeof(BMVert *)); + BM_ITER_ELEM (f, &iter, from_v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) { + if (neighbor_v != from_v && is_vertex_diagonal(neighbor_v, from_v)) { + BLI_gsqueue_push(diagonals, &neighbor_v); + } + } + } + + /* Do the second connected step. This vertices are the ones that are added to the flood fill + * queue. */ + while (!BLI_gsqueue_is_empty(diagonals)) { + BMVert *diagonal_v; + BLI_gsqueue_pop(diagonals, &diagonal_v); + BM_ITER_ELEM (f, &iter, diagonal_v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) { + int neighbor_vertex_index = BM_elem_index_get(neighbor_v); + if (!visited_vertices[neighbor_vertex_index] && neighbor_v != diagonal_v && + is_vertex_diagonal(neighbor_v, diagonal_v)) { + BLI_gsqueue_push(queue, &neighbor_v); + visited_vertices[neighbor_vertex_index] = true; + BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true); + } + } + } + } + BLI_gsqueue_free(diagonals); + } + + BLI_gsqueue_free(queue); + MEM_freeN(visited_vertices); +} + +/** + * This function checks if the current status of the #BMVert tags + * corresponds to a valid un-subdivide solution. + * + * This means that all vertices corresponding to the (0,0) grid coordinate should be tagged. + * + * On a valid solution, the following things should happen: + * - No boundary vertices should be tagged + * - No vertices connected by an edge or a quad diagonal to a tagged vertex should be tagged + * - All boundary vertices should have one vertex connected by an edge or a diagonal tagged + */ +static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem) +{ + BMVert *v, *neighbor_v; + BMIter iter, iter_a, iter_b; + BMFace *f; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (is_vertex_in_id(v, elem_id, elem)) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + /* Tagged vertex in boundary */ + if (BM_vert_is_boundary(v)) { + return false; + } + /* Tagged vertex with connected tagged vertex. */ + BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) { + if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) { + return false; + } + } + } + } + if (BM_vert_is_boundary(v)) { + /* Un-tagged vertex in boundary without connected tagged vertices. */ + bool any_tagged = false; + BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) { + if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) { + any_tagged = true; + } + } + } + if (!any_tagged) { + return false; + } + } + } + } + + return true; +} + +/** + * Search and validates an un-subdivide solution for a given element ID. + */ +static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem) +{ + /* First, get vertex candidates to try to generate possible un-subdivide solution. */ + /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be + * part of the base mesh. If it isn't, then there is no solution. */ + GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *)); + BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem); + if (initial_vertex_pole != NULL) { + BLI_gsqueue_push(initial_vertex, &initial_vertex_pole); + } + + /* Also try from the different 4 vertices of a quad in the current + * disconnected element ID. If a solution exists the search should return a valid solution from + * one of these vertices.*/ + BMFace *f, *init_face = NULL; + BMVert *v; + BMIter iter_a, iter_b; + BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { + if (is_vertex_in_id(v, elem_id, elem)) { + init_face = f; + break; + } + } + if (init_face != NULL) { + break; + } + } + + BM_ITER_ELEM (v, &iter_a, init_face, BM_VERTS_OF_FACE) { + BLI_gsqueue_push(initial_vertex, &v); + } + + bool valid_tag_found = false; + + /* Check all vertex candidates to a solution. */ + while (!BLI_gsqueue_is_empty(initial_vertex)) { + + BMVert *iv; + BLI_gsqueue_pop(initial_vertex, &iv); + + /* Generate a possible solution. */ + unsubdivide_face_center_vertex_tag(bm, iv); + + /* Check if the solution is valid. If it is, stop searching. */ + if (unsubdivide_is_center_vertex_tag_valid(bm, elem_id, elem)) { + valid_tag_found = true; + break; + } + + /* If the solution is not valid, reset the state of all tags in this disconnected element ID + * and try again. */ + BMVert *v_reset; + BMIter iter; + BM_ITER_MESH (v_reset, &iter, bm, BM_VERTS_OF_MESH) { + if (is_vertex_in_id(v_reset, elem_id, elem)) { + BM_elem_flag_set(v_reset, BM_ELEM_TAG, false); + } + } + } + BLI_gsqueue_free(initial_vertex); + return valid_tag_found; +} + +/** + * Uses a flood fill operation to generate a different ID for each disconnected mesh element. + */ +static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id) +{ + bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices"); + int current_id = 0; + for (int i = 0; i < bm->totvert; i++) { + if (!visited_vertices[i]) { + GSQueue *queue; + queue = BLI_gsqueue_new(sizeof(BMVert *)); + + visited_vertices[i] = true; + elem_id[i] = current_id; + BMVert *iv = BM_vert_at_index(bm, i); + BLI_gsqueue_push(queue, &iv); + + while (!BLI_gsqueue_is_empty(queue)) { + BMIter iter; + BMVert *current_v, *neighbor_v; + BMEdge *ed; + BLI_gsqueue_pop(queue, ¤t_v); + BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) { + neighbor_v = BM_edge_other_vert(ed, current_v); + const int neighbor_index = BM_elem_index_get(neighbor_v); + if (!visited_vertices[neighbor_index]) { + visited_vertices[neighbor_index] = true; + elem_id[neighbor_index] = current_id; + BLI_gsqueue_push(queue, &neighbor_v); + } + } + } + current_id++; + BLI_gsqueue_free(queue); + } + } + MEM_freeN(visited_vertices); + return current_id; +} + +/** + * Builds a base mesh one subdivision level down from the current original mesh if the original + * mesh has a valid solution stored in the #BMVert tags. + */ +static void unsubdivide_build_base_mesh_from_tags(BMesh *bm) +{ + BMVert *v; + BMIter iter; + + /* Stores the vertices which correspond to (1, 0) and (0, 1) of the grids in the select flag. */ + BM_mesh_elem_hflag_enable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BMVert *v_neighbor; + BMIter iter_a; + BMEdge *ed; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_ELEM (ed, &iter_a, v, BM_EDGES_OF_VERT) { + v_neighbor = BM_edge_other_vert(ed, v); + if (BM_elem_flag_test(v_neighbor, BM_ELEM_TAG)) { + BM_elem_flag_set(v, BM_ELEM_SELECT, false); + } + } + } + + /* Dissolves the (0,0) vertices of the grids. */ + BMO_op_callf(bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_TAG, + false, + true); + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + /* Copy the select flag to the tag flag. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) { + BM_elem_flag_set(v, BM_ELEM_TAG, true); + } + } + + /* Dissolves the (1,0) and (0,1) vertices of the grids. */ + BMO_op_callf(bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_TAG, + false, + true); +} + +/** + * Main function to get a base mesh one level down from the current original mesh if it exists. + * + * This searches for different un-subdivide solutions and stores them as a combination of #BMVert + * flags for each disconnected mesh element. + * + * If the solution for all elements are valid, it builds a new base mesh based on those tags by + * dissolving and merging vertices. + */ +static bool multires_unsubdivide_single_level(BMesh *bm) +{ + + /* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh. + */ + if (!unsubdivide_is_all_quads(bm)) { + return false; + }; + + /* Initialize the vertex table. */ + BM_mesh_elem_table_init(bm, BM_VERT); + BM_mesh_elem_table_ensure(bm, BM_VERT); + + /* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */ + int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID"); + const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id); + + bool valid_tag_found = true; + + /* Reset the #BMesh flags as they are used to store data during the un-subdivide process. */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + /* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The + * whole un-subdivide process fails if a single disconnected mesh element fails. */ + for (int id = 0; id < tot_ids; id++) { + /* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */ + if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) { + valid_tag_found = false; + break; + } + } + + /* If a solution was found for all elements IDs, build the new base mesh using the solution + * stored in the BMVert tags. */ + if (valid_tag_found) { + unsubdivide_build_base_mesh_from_tags(bm); + } + + MEM_freeN(elem_id); + return valid_tag_found; +} + +/** + * Returns the next edge and vertex in the direction of a given edge. + */ +static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex) +{ + BMIter iter; + BMEdge *test_edge; + if (edge == NULL) { + (*r_next_vertex) = v; + return edge; + } + (*r_next_vertex) = BM_edge_other_vert(edge, v); + BM_ITER_ELEM (test_edge, &iter, (*r_next_vertex), BM_EDGES_OF_VERT) { + if (!BM_edge_share_quad_check(test_edge, edge)) { + return test_edge; + } + } + return NULL; +} + +static BMFace *face_step(BMEdge *edge, BMFace *f) +{ + BMIter iter; + BMFace *face_iter; + + BM_ITER_ELEM (face_iter, &iter, edge, BM_FACES_OF_EDGE) { + if (BM_face_share_edge_check(face_iter, f)) { + return face_iter; + } + } + return f; +} + +/** + * Returns the other edge which belongs to the face f which is different from edge_x and shares + * initial_vertex. + */ +static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex) +{ + BMIter iter; + BMEdge *test_edge; + BM_ITER_ELEM (test_edge, &iter, f, BM_EDGES_OF_FACE) { + if (edge_x != test_edge) { + if (test_edge->v1 != initial_vertex && test_edge->v2 == initial_vertex) { + return test_edge; + } + if (test_edge->v2 != initial_vertex && test_edge->v1 == initial_vertex) { + return test_edge; + } + } + } + return NULL; +} + +/** + * Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop. + */ +static void write_loop_in_face_grid( + float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop) +{ + int origin[2]; + int step_x[2]; + int step_y[2]; + + const int grid_offset = orig_grid_size - 1; + origin[0] = grid_offset; + origin[1] = grid_offset; + + switch (loop) { + case 0: + step_x[0] = -1; + step_x[1] = 0; + + step_y[0] = 0; + step_y[1] = -1; + + break; + case 1: + step_x[0] = 0; + step_x[1] = 1; + + step_y[0] = -1; + step_y[1] = -0; + break; + case 2: + step_x[0] = 1; + step_x[1] = 0; + + step_y[0] = 0; + step_y[1] = 1; + break; + case 3: + step_x[0] = 0; + step_x[1] = -1; + + step_y[0] = 1; + step_y[1] = 0; + break; + default: + BLI_assert(!"Should never happen"); + break; + } + + for (int y = 0; y < orig_grid_size; y++) { + for (int x = 0; x < orig_grid_size; x++) { + const int remap_x = origin[1] + (step_x[1] * x) + (step_y[1] * y); + const int remap_y = origin[0] + (step_x[0] * x) + (step_y[0] * y); + + const int final_index = remap_x + remap_y * face_grid_size; + copy_v3_v3(face_grid[final_index], mdisp->disps[x + y * orig_grid_size]); + } + } +} + +/** + * Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into + * the main #MultiresUnsubdivideGrid that is being extracted. + */ +static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid, + float (*face_grid)[3], + int face_grid_size, + int gunsub_x, + int gunsub_y) +{ + const int grid_it = face_grid_size - 1; + for (int y = 0; y < face_grid_size; y++) { + for (int x = 0; x < face_grid_size; x++) { + const int remap_x = (grid_it * gunsub_x) + x; + const int remap_y = (grid_it * gunsub_y) + y; + + const int remap_index_y = grid->grid_size - remap_x - 1; + const int remap_index_x = grid->grid_size - remap_y - 1; + const int grid_index = remap_index_x + (remap_index_y * grid->grid_size); + copy_v3_v3(grid->grid_co[grid_index], face_grid[x + y * face_grid_size]); + } + } +} + +/** + * Stores the data from the mdisps grids of the loops of the face f + * into the new grid for the new base mesh. + * + * Used when there are already grids in the original mesh. + */ +static void store_grid_data(MultiresUnsubdivideContext *context, + MultiresUnsubdivideGrid *grid, + BMVert *v, + BMFace *f, + int grid_x, + int grid_y) +{ + + Mesh *original_mesh = context->original_mesh; + MPoly *poly = &original_mesh->mpoly[BM_elem_index_get(f)]; + + const int corner_vertex_index = BM_elem_index_get(v); + + /* Calculates an offset to write the grids correctly oriented in the main + * #MultiresUnsubdivideGrid. */ + int loop_offset = 0; + for (int i = 0; i < poly->totloop; i++) { + const int loop_index = poly->loopstart + i; + MLoop *l = &original_mesh->mloop[loop_index]; + if (l->v == corner_vertex_index) { + loop_offset = i; + break; + } + } + + /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */ + const int grid_size = BKE_ccg_gridsize(context->num_original_levels); + const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1); + const int face_grid_area = face_grid_size * face_grid_size; + float(*face_grid)[3] = MEM_calloc_arrayN(face_grid_area, 3 * sizeof(float), "face_grid"); + + for (int i = 0; i < poly->totloop; i++) { + const int loop_index = poly->loopstart + i; + MDisps *mdisp = &context->original_mdisp[loop_index]; + int quad_loop = i - loop_offset; + if (quad_loop < 0) { + quad_loop += 4; + } + if (quad_loop >= 4) { + quad_loop -= 4; + } + write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop); + } + + /* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is + * being extracted. */ + write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y); + + MEM_freeN(face_grid); +} + +/** + * Stores the data into the new grid from a #BMVert. + * Used when there are no grids in the original mesh. + */ +static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y) +{ + const int remap_index_y = grid->grid_size - 1 - grid_x; + const int remap_index_x = grid->grid_size - 1 - grid_y; + + const int grid_index = remap_index_x + (remap_index_y * grid->grid_size); + + copy_v3_v3(grid->grid_co[grid_index], v->co); +} + +/** + * Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh. + */ +static void multires_unsubdivide_extract_single_grid_from_face_edge( + MultiresUnsubdivideContext *context, + BMFace *f1, + BMEdge *e1, + bool flip_grid, + MultiresUnsubdivideGrid *grid) +{ + BMVert *initial_vertex; + BMEdge *initial_edge_x; + BMEdge *initial_edge_y; + + const int grid_size = BKE_ccg_gridsize(context->num_new_levels); + const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels); + grid->grid_size = unsubdiv_grid_size; + grid->grid_co = MEM_calloc_arrayN( + unsubdiv_grid_size * unsubdiv_grid_size, 3 * sizeof(float), "grids coordinates"); + + /* Get the vertex on the corner of the grid. This vertex was tagged previously as it also exist + * on the base mesh. */ + initial_edge_x = e1; + if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) { + initial_vertex = initial_edge_x->v1; + } + else { + initial_vertex = initial_edge_x->v2; + } + + /* From that vertex, get the edge that defines the grid Y axis for extraction. */ + initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex); + + if (flip_grid) { + BMEdge *edge_temp; + edge_temp = initial_edge_x; + initial_edge_x = initial_edge_y; + initial_edge_y = edge_temp; + } + + int grid_x = 0; + int grid_y = 0; + + BMVert *current_vertex_x = initial_vertex; + BMEdge *edge_x = initial_edge_x; + + BMVert *current_vertex_y = initial_vertex; + BMEdge *edge_y = initial_edge_y; + BMEdge *prev_edge_y = initial_edge_y; + + BMFace *current_face = f1; + BMFace *grid_face = f1; + + /* If the data is going to be extracted from the already existing grids, there is no need to go + * to the last vertex of the iteration as that coordinate is also included in the grids + * corresponding to the loop of the face of the previous iteration. */ + int grid_iteration_max_steps = grid_size; + if (context->num_original_levels > 0) { + grid_iteration_max_steps = grid_size - 1; + } + + /* Iterate over the mesh vertices in a grid pattern using the axis defined by the two initial + * edges. */ + while (grid_y < grid_iteration_max_steps) { + + grid_face = current_face; + + while (grid_x < grid_iteration_max_steps) { + if (context->num_original_levels == 0) { + /* If there were no grids on the original mesh, extract the data directly from the + * vertices. */ + store_vertex_data(grid, current_vertex_x, grid_x, grid_y); + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + } + else { + /* If there were grids in the original mesh, extract the data from the grids and iterate + * over the faces. */ + store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y); + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + grid_face = face_step(edge_x, grid_face); + } + + grid_x++; + } + grid_x = 0; + + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + current_vertex_x = current_vertex_y; + + /* Get the next edge_x to extract the next row of the grid. This needs to be done because there + * may be two edges connected to current_vertex_x that belong to two different grids. */ + BMIter iter; + BMEdge *ed; + BMFace *f; + BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) { + if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) { + edge_x = ed; + break; + } + } + BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) { + if (f != current_face) { + current_face = f; + break; + } + } + + prev_edge_y = edge_y; + grid_y++; + } +} + +/** + * Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge + * e1 is going to be extracted. + * + * These vertices should always have an corresponding existing vertex on the base mesh. + */ +static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1, + BMEdge *e1, + BMVert **r_corner_x, + BMVert **r_corner_y) +{ + BMVert *initial_vertex; + BMEdge *initial_edge_x; + BMEdge *initial_edge_y; + + initial_edge_x = e1; + if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) { + initial_vertex = initial_edge_x->v1; + } + else { + initial_vertex = initial_edge_x->v2; + } + + /* From that vertex, get the edge that defines the grid Y axis for extraction. */ + initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex); + + BMVert *current_vertex_x = initial_vertex; + BMEdge *edge_x = initial_edge_x; + + BMVert *current_vertex_y = initial_vertex; + BMEdge *edge_y = initial_edge_y; + + /* Do an edge step until it finds a tagged vertex, which is part of the base mesh. */ + /* x axis */ + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) { + edge_x = edge_step(current_vertex_x, edge_x, ¤t_vertex_x); + } + (*r_corner_x) = current_vertex_x; + + /* Same for y axis */ + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) { + edge_y = edge_step(current_vertex_y, edge_y, ¤t_vertex_y); + } + (*r_corner_y) = current_vertex_y; +} + +static BMesh *get_bmesh_from_mesh(Mesh *mesh) +{ + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); + BMesh *bm = BM_mesh_create(&allocsize, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + + BM_mesh_bm_from_me(bm, + mesh, + (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, + })); + + return bm; +} + +/* Data-layer names to store the original indices of the elements before modifying the mesh. */ +static const char lname[] = "l_remap_index"; +static const char vname[] = "v_remap_index"; + +static void multires_unsubdivide_free_original_datalayers(Mesh *mesh) +{ + const int l_layer_index = CustomData_get_named_layer_index(&mesh->ldata, CD_PROP_INT, lname); + if (l_layer_index != -1) { + CustomData_free_layer(&mesh->ldata, CD_PROP_INT, mesh->totloop, l_layer_index); + } + + const int v_layer_index = CustomData_get_named_layer_index(&mesh->vdata, CD_PROP_INT, vname); + if (v_layer_index != -1) { + CustomData_free_layer(&mesh->vdata, CD_PROP_INT, mesh->totvert, v_layer_index); + } +} + +/** + * Generates two data-layers to map loops and vertices from base mesh to original mesh after + * dissolving the vertices. + */ +static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) +{ + multires_unsubdivide_free_original_datalayers(mesh); + + int *l_index = CustomData_add_layer_named( + &mesh->ldata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totloop, lname); + + int *v_index = CustomData_add_layer_named( + &mesh->vdata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totvert, vname); + + /* Initialize these data-layer with the indices in the current mesh. */ + for (int i = 0; i < mesh->totloop; i++) { + l_index[i] = i; + } + for (int i = 0; i < mesh->totvert; i++) { + v_index[i] = i; + } +} + +static void multires_unsubdivide_prepare_original_bmesh_for_extract( + MultiresUnsubdivideContext *context) +{ + + Mesh *original_mesh = context->original_mesh; + Mesh *base_mesh = context->base_mesh; + + BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh); + + /* Initialize the elem tables. */ + BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE); + BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE); + BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT); + + /* Disable all flags. */ + BM_mesh_elem_hflag_disable_all( + bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_mesh_elem_hflag_disable_all( + bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + /* Get the mapping data-layer. */ + context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname); + + /* Tag the base mesh vertices in the original mesh. */ + for (int i = 0; i < base_mesh->totvert; i++) { + int vert_basemesh_index = context->base_to_orig_vmap[i]; + BMVert *v = BM_vert_at_index(bm_original_mesh, vert_basemesh_index); + BM_elem_flag_set(v, BM_ELEM_TAG, true); + } + + /* Create a map from loop index to poly index for the original mesh. */ + context->loop_to_face_map = MEM_calloc_arrayN(sizeof(int), original_mesh->totloop, "loop map"); + + for (int i = 0; i < original_mesh->totpoly; i++) { + MPoly *poly = &original_mesh->mpoly[i]; + for (int l = 0; l < poly->totloop; l++) { + int original_loop_index = l + poly->loopstart; + context->loop_to_face_map[original_loop_index] = i; + } + } +} + +/** + * Checks the orientation of the loops to flip the x and y axis when extracting the grid if + * necessary. + */ +static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x) +{ + MPoly *p = &mesh->mpoly[poly]; + + MLoop *l_first = &mesh->mloop[p->loopstart]; + if ((loop == (p->loopstart + (p->totloop - 1))) && l_first->v == v_x) { + return true; + } + + int next_l_index = loop + 1; + if (next_l_index < p->loopstart + p->totloop) { + MLoop *l_next = &mesh->mloop[next_l_index]; + if (l_next->v == v_x) { + return true; + } + } + + return false; +} + +static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *context) +{ + Mesh *original_mesh = context->original_mesh; + Mesh *base_mesh = context->base_mesh; + + BMesh *bm_original_mesh = context->bm_original_mesh; + + context->num_grids = base_mesh->totloop; + context->base_mesh_grids = MEM_calloc_arrayN( + sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids"); + + /* Based on the existing indices in the data-layers, generate two vertex indices maps. */ + /* From vertex index in original to vertex index in base and from vertex index in base to vertex + * index in original. */ + int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap"); + int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap"); + + context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname); + for (int i = 0; i < base_mesh->totvert; i++) { + base_to_orig_vmap[i] = context->base_to_orig_vmap[i]; + } + + /* If an index in original does not exist in base (it was dissolved when creating the new base + * mesh, return -1. */ + for (int i = 0; i < original_mesh->totvert; i++) { + orig_to_base_vmap[i] = -1; + } + + for (int i = 0; i < base_mesh->totvert; i++) { + const int orig_vertex_index = context->base_to_orig_vmap[i]; + orig_to_base_vmap[orig_vertex_index] = i; + } + + /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer, + * so they can be used from #BMesh. */ + multires_unsubdivide_add_original_index_datalayers(base_mesh); + + const int base_l_layer_index = CustomData_get_named_layer_index( + &base_mesh->ldata, CD_PROP_INT, lname); + BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh); + BMIter iter, iter_a, iter_b; + BMVert *v; + BMLoop *l, *lb; + + BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT); + BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE); + + /* Get the data-layer that contains the loops indices. */ + const int base_l_offset = CustomData_get_n_offset( + &bm_base_mesh->ldata, CD_PROP_INT, base_l_layer_index); + + /* Main loop for extracting the grids. Iterates over the base mesh vertices. */ + BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) { + + /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the + * vertex map. */ + const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)]; + BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index); + + /* Iterate over the loops of that vertex in the original mesh. */ + BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) { + /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the + * base mesh of the poly of grid that is going to be extracted. */ + BMVert *corner_x, *corner_y; + multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y); + + /* Map the two obtained vertices to the base mesh. */ + const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)]; + const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)]; + + /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained + * vertices and the current vertex it is possible to get the index of the loop in the base + * mesh the grid that is going to be extracted belongs to. */ + BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) { + BMFace *base_face = lb->f; + BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index); + BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index); + /* If this is the correct loop in the base mesh, the original vertex and the two corners + * should be in the loop's face. */ + if (BM_vert_in_face(base_corner_x, base_face) && + BM_vert_in_face(base_corner_y, base_face)) { + /* Get the index of the loop. */ + const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset); + const int base_mesh_face_index = BM_elem_index_get(base_face); + + /* Check the orientation of the loops in case that is needed to flip the x and y axis + * when extracting the grid. */ + const bool flip_grid = multires_unsubdivide_flip_grid_x_axis( + base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index); + + /* Extract the grid for that loop. */ + context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index; + multires_unsubdivide_extract_single_grid_from_face_edge( + context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]); + + break; + } + } + } + } + + MEM_freeN(orig_to_base_vmap); + MEM_freeN(base_to_orig_vmap); + + BM_mesh_free(bm_base_mesh); + multires_unsubdivide_free_original_datalayers(base_mesh); +} + +static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context) +{ + if (context->bm_original_mesh != NULL) { + BM_mesh_free(context->bm_original_mesh); + } + MEM_SAFE_FREE(context->loop_to_face_map); +} + +void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context, + Mesh *original_mesh, + struct MultiresModifierData *mmd) +{ + context->original_mesh = original_mesh; + context->num_new_levels = 0; + context->num_total_levels = 0; + context->num_original_levels = mmd->totlvl; +} + +bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context) +{ + Mesh *original_mesh = context->original_mesh; + + /* Prepare the data-layers to map base to original. */ + multires_unsubdivide_add_original_index_datalayers(original_mesh); + BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh); + + /* Un-subdivide as many iterations as possible. */ + context->num_new_levels = 0; + int num_levels_left = context->max_new_levels; + while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) { + context->num_new_levels++; + num_levels_left--; + } + + /* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */ + if (context->num_new_levels == 0) { + multires_unsubdivide_free_original_datalayers(original_mesh); + BM_mesh_free(bm_base_mesh); + return false; + } + + /* Calculate the final levels for the new grids over base mesh. */ + context->num_total_levels = context->num_new_levels + context->num_original_levels; + + /* Store the new base-mesh as a mesh in context, free bmesh. */ + context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0); + BM_mesh_bm_to_me(NULL, + bm_base_mesh, + context->base_mesh, + (&(struct BMeshToMeshParams){ + .calc_object_remap = true, + })); + BM_mesh_free(bm_base_mesh); + + /* Initialize bmesh and maps for the original mesh and extract the grids. */ + + multires_unsubdivide_prepare_original_bmesh_for_extract(context); + multires_unsubdivide_extract_grids(context); + + return true; +} + +void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context) +{ + multires_unsubdivide_private_extract_data_free(context); + for (int i = 0; i < context->num_grids; i++) { + if (context->base_mesh_grids[i].grid_size > 0) { + MEM_SAFE_FREE(context->base_mesh_grids[i].grid_co); + } + } + MEM_SAFE_FREE(context->base_mesh_grids); +} + +/** + * This function allocates new mdisps with the right size to fit the new extracted grids from the + * base mesh and copies the data to them. + */ +static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideContext *context, + Mesh *base_mesh) +{ + /* Free the current MDISPS and create a new ones. */ + if (CustomData_has_layer(&base_mesh->ldata, CD_MDISPS)) { + CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop); + } + MDisps *mdisps = CustomData_add_layer( + &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop); + + const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2); + const int totloop = base_mesh->totloop; + + BLI_assert(base_mesh->totloop == context->num_grids); + + /* Allocate the MDISPS grids and copy the extracted data from context. */ + for (int i = 0; i < totloop; i++) { + float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); + + if (mdisps[i].disps) { + MEM_freeN(mdisps[i].disps); + } + + for (int j = 0; j < totdisp; j++) { + if (context->base_mesh_grids[i].grid_co) { + copy_v3_v3(disps[j], context->base_mesh_grids[i].grid_co[j]); + } + } + + mdisps[i].disps = disps; + mdisps[i].totdisp = totdisp; + mdisps[i].level = context->num_total_levels; + } +} + +int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd, + int rebuild_limit, + bool switch_view_to_lower_level) +{ + Mesh *mesh = object->data; + + multires_force_sculpt_rebuild(object); + + MultiresUnsubdivideContext unsubdiv_context = {0}; + MultiresReshapeContext reshape_context = {0}; + + multires_unsubdivide_context_init(&unsubdiv_context, mesh, mmd); + + /* Convert and store the existing grids in object space if available. */ + if (mmd->totlvl != 0) { + if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) { + return 0; + } + + multires_reshape_store_original_grids(&reshape_context); + multires_reshape_assign_final_coords_from_mdisps(&reshape_context); + unsubdiv_context.original_mdisp = reshape_context.mdisps; + } + + /* Set the limit for the levels that should be rebuild. */ + unsubdiv_context.max_new_levels = rebuild_limit; + + /* Un-subdivide and create the data for the new grids. */ + if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) { + /* If there was no possible to rebuild any level, free the data and return. */ + if (mmd->totlvl != 0) { + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_unsubdivide_context_free(&unsubdiv_context); + } + multires_reshape_context_free(&reshape_context); + return 0; + } + + /* Free the reshape context used to convert the data from the original grids to object space. */ + if (mmd->totlvl != 0) { + multires_reshape_context_free(&reshape_context); + } + + /* Copy the new base mesh to the original mesh. */ + BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object, &CD_MASK_MESH, true); + Mesh *base_mesh = object->data; + multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh); + + /* Update the levels in the modifier. Force always to display at level 0 as it contains the new + * created level. */ + mmd->totlvl = (char)unsubdiv_context.num_total_levels; + + if (switch_view_to_lower_level) { + mmd->sculptlvl = 0; + mmd->lvl = 0; + } + else { + mmd->sculptlvl = (char)(mmd->sculptlvl + unsubdiv_context.num_new_levels); + mmd->lvl = (char)(mmd->lvl + unsubdiv_context.num_new_levels); + } + + mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels); + + /* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the + * same as the previous one as a new Subdivision needs to be created for the new base mesh. */ + if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) { + return 0; + } + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_reshape_context_free(&reshape_context); + + /* Free the un-subdivide context and return the total number of levels that were rebuild. */ + const int rebuild_subdvis = unsubdiv_context.num_new_levels; + multires_unsubdivide_context_free(&unsubdiv_context); + + return rebuild_subdvis; +} diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h new file mode 100644 index 00000000000..e00a1ae6d8b --- /dev/null +++ b/source/blender/blenkernel/intern/multires_unsubdivide.h @@ -0,0 +1,94 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#ifndef __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ +#define __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ + +#include "BLI_sys_types.h" + +struct BMesh; +struct Depsgraph; +struct Mesh; +struct MultiresModifierData; +struct Object; + +typedef struct MultiresUnsubdivideGrid { + /* For sanity checks. */ + int grid_index; + int grid_size; + + /** Grid coordinates in object space. */ + float (*grid_co)[3]; + +} MultiresUnsubdivideGrid; + +typedef struct MultiresUnsubdivideContext { + /* Input Mesh to un-subdivide. */ + struct Mesh *original_mesh; + struct MDisps *original_mdisp; + + /** Number of subdivision in the grids of the input mesh. */ + int num_original_levels; + + /** Level 0 base mesh after applying the maximum amount of unsubdivisions. */ + struct Mesh *base_mesh; + + /** Limit on how many levels down the unsubdivide operation should create, if possible. */ + int max_new_levels; + + /** New levels that were created after unsubdividing. */ + int num_new_levels; + + /** + * Number of subdivisions that should be applied to the base mesh. + * (num_new_levels + num_original_levels). + */ + int num_total_levels; + + /** Data for the new grids, indexed by base mesh loop index. */ + int num_grids; + struct MultiresUnsubdivideGrid *base_mesh_grids; + + /* Private data. */ + struct BMesh *bm_original_mesh; + int *loop_to_face_map; + int *base_to_orig_vmap; +} MultiresUnsubdivideContext; + +/* -------------------------------------------------------------------- + * Construct/destruct reshape context. + */ + +void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context, + struct Mesh *original_mesh, + struct MultiresModifierData *mmd); +void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context); + +/* -------------------------------------------------------------------- + * Rebuild Lower Subdivisions. + */ + +/* Rebuilds all subdivision to the level 0 base mesh. */ +bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context); + +#endif /* __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 5ae44247e13..48c6727add5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -32,11 +32,13 @@ #include "DNA_action_types.h" #include "DNA_anim_types.h" +#include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" +#include "DNA_simulation_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" @@ -56,6 +58,7 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_node.h" @@ -66,7 +69,9 @@ #include "NOD_common.h" #include "NOD_composite.h" +#include "NOD_function.h" #include "NOD_shader.h" +#include "NOD_simulation.h" #include "NOD_socket.h" #include "NOD_texture.h" @@ -86,7 +91,9 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo); static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag); static void free_localized_node_groups(bNodeTree *ntree); static void node_free_node(bNodeTree *ntree, bNode *node); -static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock); +static void node_socket_interface_free(bNodeTree *UNUSED(ntree), + bNodeSocket *sock, + const bool do_id_user); static void ntree_init_data(ID *id) { @@ -229,12 +236,12 @@ static void ntree_free_data(ID *id) /* free interface sockets */ for (sock = ntree->inputs.first; sock; sock = nextsock) { nextsock = sock->next; - node_socket_interface_free(ntree, sock); + node_socket_interface_free(ntree, sock, false); MEM_freeN(sock); } for (sock = ntree->outputs.first; sock; sock = nextsock) { nextsock = sock->next; - node_socket_interface_free(ntree, sock); + node_socket_interface_free(ntree, sock, false); MEM_freeN(sock); } @@ -248,6 +255,66 @@ static void ntree_free_data(ID *id) } } +static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) +{ + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + + switch ((eNodeSocketDatatype)sock->type) { + case SOCK_OBJECT: { + bNodeSocketValueObject *default_value = sock->default_value; + BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); + break; + } + case SOCK_IMAGE: { + bNodeSocketValueImage *default_value = sock->default_value; + BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); + break; + } + case SOCK_FLOAT: + case SOCK_VECTOR: + case SOCK_RGBA: + case SOCK_BOOLEAN: + case SOCK_INT: + case SOCK_STRING: + case __SOCK_MESH: + case SOCK_CUSTOM: + case SOCK_SHADER: + case SOCK_EMITTERS: + case SOCK_EVENTS: + case SOCK_FORCES: + case SOCK_CONTROL_FLOW: + break; + } +} + +static void node_foreach_id(ID *id, LibraryForeachIDData *data) +{ + bNodeTree *ntree = (bNodeTree *)id; + + BKE_LIB_FOREACHID_PROCESS(data, ntree->gpd, IDWALK_CB_USER); + + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER); + + IDP_foreach_property( + node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + library_foreach_node_socket(data, sock); + } + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { + library_foreach_node_socket(data, sock); + } + } + + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { + library_foreach_node_socket(data, sock); + } + LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { + library_foreach_node_socket(data, sock); + } +} + IDTypeInfo IDType_ID_NT = { .id_code = ID_NT, .id_filter = FILTER_ID_NT, @@ -262,6 +329,7 @@ IDTypeInfo IDType_ID_NT = { .copy_data = ntree_copy_data, .free_data = ntree_free_data, .make_local = NULL, + .foreach_id = node_foreach_id, }; static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) @@ -744,6 +812,66 @@ static bNodeSocket *make_socket(bNodeTree *ntree, return sock; } +static void socket_id_user_increment(bNodeSocket *sock) +{ + switch ((eNodeSocketDatatype)sock->type) { + case SOCK_OBJECT: { + bNodeSocketValueObject *default_value = sock->default_value; + id_us_plus(&default_value->value->id); + break; + } + case SOCK_IMAGE: { + bNodeSocketValueImage *default_value = sock->default_value; + id_us_plus(&default_value->value->id); + break; + } + case SOCK_FLOAT: + case SOCK_VECTOR: + case SOCK_RGBA: + case SOCK_BOOLEAN: + case SOCK_INT: + case SOCK_STRING: + case __SOCK_MESH: + case SOCK_CUSTOM: + case SOCK_SHADER: + case SOCK_EMITTERS: + case SOCK_EVENTS: + case SOCK_FORCES: + case SOCK_CONTROL_FLOW: + break; + } +} + +static void socket_id_user_decrement(bNodeSocket *sock) +{ + switch ((eNodeSocketDatatype)sock->type) { + case SOCK_OBJECT: { + bNodeSocketValueObject *default_value = sock->default_value; + id_us_min(&default_value->value->id); + break; + } + case SOCK_IMAGE: { + bNodeSocketValueImage *default_value = sock->default_value; + id_us_min(&default_value->value->id); + break; + } + case SOCK_FLOAT: + case SOCK_VECTOR: + case SOCK_RGBA: + case SOCK_BOOLEAN: + case SOCK_INT: + case SOCK_STRING: + case __SOCK_MESH: + case SOCK_CUSTOM: + case SOCK_SHADER: + case SOCK_EMITTERS: + case SOCK_EVENTS: + case SOCK_FORCES: + case SOCK_CONTROL_FLOW: + break; + } +} + void nodeModifySocketType( bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, int type, int subtype) { @@ -755,6 +883,7 @@ void nodeModifySocketType( } if (sock->default_value) { + socket_id_user_decrement(sock); MEM_freeN(sock->default_value); sock->default_value = NULL; } @@ -862,6 +991,18 @@ const char *nodeStaticSocketType(int type, int subtype) return "NodeSocketString"; case SOCK_SHADER: return "NodeSocketShader"; + case SOCK_OBJECT: + return "NodeSocketObject"; + case SOCK_IMAGE: + return "NodeSocketImage"; + case SOCK_EMITTERS: + return "NodeSocketEmitters"; + case SOCK_EVENTS: + return "NodeSocketEvents"; + case SOCK_FORCES: + return "NodeSocketForces"; + case SOCK_CONTROL_FLOW: + return "NodeSocketControlFlow"; } return NULL; } @@ -923,6 +1064,18 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype) return "NodeSocketInterfaceString"; case SOCK_SHADER: return "NodeSocketInterfaceShader"; + case SOCK_OBJECT: + return "NodeSocketInterfaceObject"; + case SOCK_IMAGE: + return "NodeSocketInterfaceImage"; + case SOCK_EMITTERS: + return "NodeSocketInterfaceEmitters"; + case SOCK_EVENTS: + return "NodeSocketInterfaceEvents"; + case SOCK_FORCES: + return "NodeSocketInterfaceForces"; + case SOCK_CONTROL_FLOW: + return "NodeSocketInterfaceControlFlow"; } return NULL; } @@ -981,6 +1134,9 @@ static void node_socket_free(bNodeTree *UNUSED(ntree), } if (sock->default_value) { + if (do_id_user) { + socket_id_user_decrement(sock); + } MEM_freeN(sock->default_value); } } @@ -1267,6 +1423,10 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, if (sock_src->default_value) { sock_dst->default_value = MEM_dupallocN(sock_src->default_value); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + socket_id_user_increment(sock_dst); + } } sock_dst->stack_index = 0; @@ -2087,6 +2247,13 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) if (node->id) { id_us_min(node->id); } + + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + socket_id_user_decrement(sock); + } + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { + socket_id_user_decrement(sock); + } } /* Remove animation data. */ @@ -2106,13 +2273,18 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) node_free_node(ntree, node); } -static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock) +static void node_socket_interface_free(bNodeTree *UNUSED(ntree), + bNodeSocket *sock, + const bool do_id_user) { if (sock->prop) { - IDP_FreeProperty(sock->prop); + IDP_FreeProperty_ex(sock->prop, do_id_user); } if (sock->default_value) { + if (do_id_user) { + socket_id_user_decrement(sock); + } MEM_freeN(sock->default_value); } } @@ -2147,7 +2319,7 @@ void ntreeFreeTree(bNodeTree *ntree) BKE_animdata_free(&ntree->id, false); } -void ntreeFreeNestedTree(bNodeTree *ntree) +void ntreeFreeEmbeddedTree(bNodeTree *ntree) { ntreeFreeTree(ntree); BKE_libblock_free_data(&ntree->id, true); @@ -2270,6 +2442,8 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id) return &((Scene *)id)->nodetree; case ID_LS: return &((FreestyleLineStyle *)id)->nodetree; + case ID_SIM: + return &((Simulation *)id)->nodetree; default: return NULL; } @@ -2533,7 +2707,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock) BLI_remlink(&ntree->inputs, sock); BLI_remlink(&ntree->outputs, sock); - node_socket_interface_free(ntree, sock); + node_socket_interface_free(ntree, sock, true); MEM_freeN(sock); ntree->update |= NTREE_UPDATE_GROUP; @@ -4118,6 +4292,33 @@ static void registerTextureNodes(void) register_node_type_tex_proc_distnoise(); } +static void registerSimulationNodes(void) +{ + register_node_type_sim_group(); + + register_node_type_sim_particle_simulation(); + register_node_type_sim_force(); + register_node_type_sim_set_particle_attribute(); + register_node_type_sim_particle_birth_event(); + register_node_type_sim_particle_time_step_event(); + register_node_type_sim_execute_condition(); + register_node_type_sim_multi_execute(); + register_node_type_sim_particle_mesh_emitter(); + register_node_type_sim_particle_mesh_collision_event(); + register_node_type_sim_emit_particles(); + register_node_type_sim_time(); + register_node_type_sim_particle_attribute(); +} + +static void registerFunctionNodes(void) +{ + register_node_type_fn_boolean_math(); + register_node_type_fn_float_compare(); + register_node_type_fn_switch(); + register_node_type_fn_group_instance_id(); + register_node_type_fn_combine_strings(); +} + void init_nodesystem(void) { nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh"); @@ -4131,6 +4332,7 @@ void init_nodesystem(void) register_node_tree_type_cmp(); register_node_tree_type_sh(); register_node_tree_type_tex(); + register_node_tree_type_sim(); register_node_type_frame(); register_node_type_reroute(); @@ -4140,6 +4342,8 @@ void init_nodesystem(void) registerCompositNodes(); registerShaderNodes(); registerTextureNodes(); + registerSimulationNodes(); + registerFunctionNodes(); } void free_nodesystem(void) @@ -4196,6 +4400,7 @@ void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *b ntreeiter->light = bmain->lights.first; ntreeiter->world = bmain->worlds.first; ntreeiter->linestyle = bmain->linestyles.first; + ntreeiter->simulation = bmain->simulations.first; } bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, bNodeTree **r_nodetree, @@ -4236,6 +4441,11 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, *r_id = (ID *)ntreeiter->linestyle; ntreeiter->linestyle = ntreeiter->linestyle->id.next; } + else if (ntreeiter->simulation) { + *r_nodetree = ntreeiter->simulation->nodetree; + *r_id = (ID *)ntreeiter->simulation; + ntreeiter->simulation = ntreeiter->simulation->id.next; + } else { return false; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 849b42ccb2c..d17575195e3 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -83,6 +83,7 @@ #include "BKE_editmesh.h" #include "BKE_effect.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_gpencil.h" @@ -205,9 +206,9 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in BLI_listbase_clear(&ob_dst->modifiers); LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) { - ModifierData *nmd = modifier_new(md->type); + ModifierData *nmd = BKE_modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); - modifier_copyData_ex(md, nmd, flag_subdata); + BKE_modifier_copydata_ex(md, nmd, flag_subdata); BLI_addtail(&ob_dst->modifiers, nmd); } @@ -216,7 +217,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in LISTBASE_FOREACH (GpencilModifierData *, gmd, &ob_src->greasepencil_modifiers) { GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type); BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name)); - BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata); + BKE_gpencil_modifier_copydata_ex(gmd, nmd, flag_subdata); BLI_addtail(&ob_dst->greasepencil_modifiers, nmd); } @@ -225,7 +226,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in LISTBASE_FOREACH (ShaderFxData *, fx, &ob_src->shader_fx) { ShaderFxData *nfx = BKE_shaderfx_new(fx->type); BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name)); - BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata); + BKE_shaderfx_copydata_ex(fx, nfx, flag_subdata); BLI_addtail(&ob_dst->shader_fx, nfx); } @@ -374,6 +375,153 @@ static void object_make_local(Main *bmain, ID *id, const int flags) } } +static void library_foreach_modifiersForeachIDLink(void *user_data, + Object *UNUSED(object), + ID **id_pointer, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, + Object *UNUSED(object), + ID **id_pointer, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_shaderfxForeachIDLink(void *user_data, + Object *UNUSED(object), + ID **id_pointer, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), + ID **id_pointer, + bool is_reference, + void *user_data) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys), + ID **id_pointer, + void *user_data, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void object_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Object *object = (Object *)id; + + /* Object is special, proxies make things hard... */ + const int proxy_cb_flag = ((BKE_lib_query_foreachid_process_flags_get(data) & + IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && + (object->proxy || object->proxy_group)) ? + IDWALK_CB_INDIRECT_USAGE : + 0; + + /* object data special case */ + if (object->type == OB_EMPTY) { + /* empty can have NULL or Image */ + BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, proxy_cb_flag | IDWALK_CB_USER); + } + else { + /* when set, this can't be NULL */ + if (object->data) { + BKE_LIB_FOREACHID_PROCESS_ID( + data, object->data, proxy_cb_flag | IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); + } + } + + BKE_LIB_FOREACHID_PROCESS(data, object->parent, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, object->track, IDWALK_CB_NEVER_SELF); + /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ + BKE_LIB_FOREACHID_PROCESS(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, object->proxy_group, IDWALK_CB_NOP); + + /* Special case! + * Since this field is set/owned by 'user' of this ID (and not ID itself), + * it is only indirect usage if proxy object is linked... Twisted. */ + { + const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( + data, + (object->proxy_from != NULL && ID_IS_LINKED(object->proxy_from)) ? + IDWALK_CB_INDIRECT_USAGE : + 0, + true); + BKE_LIB_FOREACHID_PROCESS(data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF); + BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); + } + + BKE_LIB_FOREACHID_PROCESS(data, object->poselib, IDWALK_CB_USER); + + for (int i = 0; i < object->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER); + } + + /* Note that ob->gpd is deprecated, so no need to handle it here. */ + BKE_LIB_FOREACHID_PROCESS(data, object->instance_collection, IDWALK_CB_USER); + + if (object->pd) { + BKE_LIB_FOREACHID_PROCESS(data, object->pd->tex, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, object->pd->f_source, IDWALK_CB_NOP); + } + /* Note that ob->effect is deprecated, so no need to handle it here. */ + + if (object->pose) { + const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( + data, proxy_cb_flag, false); + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + IDP_foreach_property( + pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS(data, pchan->custom, IDWALK_CB_USER); + BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data); + } + BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); + } + + if (object->rigidbody_constraint) { + BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF); + } + + if (object->lodlevels.first) { + LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) { + BKE_LIB_FOREACHID_PROCESS(data, level->source, IDWALK_CB_NEVER_SELF); + } + } + + BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data); + BKE_gpencil_modifiers_foreach_ID_link( + object, library_foreach_gpencil_modifiersForeachIDLink, data); + BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data); + BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data); + + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data); + } + + if (object->soft) { + BKE_LIB_FOREACHID_PROCESS(data, object->soft->collision_group, IDWALK_CB_NOP); + + if (object->soft->effector_weights) { + BKE_LIB_FOREACHID_PROCESS(data, object->soft->effector_weights->group, IDWALK_CB_NOP); + } + } +} + IDTypeInfo IDType_ID_OB = { .id_code = ID_OB, .id_filter = FILTER_ID_OB, @@ -388,6 +536,7 @@ IDTypeInfo IDType_ID_OB = { .copy_data = object_copy_data, .free_data = object_free_data, .make_local = object_make_local, + .foreach_id = object_foreach_id, }; void BKE_object_workob_clear(Object *workob) @@ -433,7 +582,7 @@ void BKE_object_free_modifiers(Object *ob, const int flag) GpencilModifierData *gp_md; while ((md = BLI_pophead(&ob->modifiers))) { - modifier_free_ex(md, flag); + BKE_modifier_free_ex(md, flag); } while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) { @@ -509,23 +658,33 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) { const ModifierTypeInfo *mti; - mti = modifierType_getInfo(modifier_type); + mti = BKE_modifier_get_info(modifier_type); - /* only geometry objects should be able to get modifiers [#25291] */ - if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { - return false; + /* Only geometry objects should be able to get modifiers [#25291] */ + if (ob->type == OB_HAIR) { + return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly); } - - if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) { - return false; + else if (ob->type == OB_POINTCLOUD) { + return (mti->modifyPointCloud != NULL) || + (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly); + } + else if (ob->type == OB_VOLUME) { + return (mti->modifyVolume != NULL); } + else if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) { + return false; + } - if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) || - (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) { - return false; + if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) || + (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) { + return false; + } + + return true; } - return true; + return false; } void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) @@ -561,7 +720,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr break; } - nmd = modifier_new(md->type); + nmd = BKE_modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); if (md->type == eModifierType_Multires) { @@ -570,9 +729,9 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); } - modifier_copyData(md, nmd); + BKE_modifier_copydata(md, nmd); BLI_addtail(&ob_dst->modifiers, nmd); - modifier_unique_name(&ob_dst->modifiers, nmd); + BKE_modifier_unique_name(&ob_dst->modifiers, nmd); } } @@ -584,7 +743,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr nmd = BKE_gpencil_modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); mti->copyData(md, nmd); BLI_addtail(&ob_dst->greasepencil_modifiers, nmd); @@ -1297,8 +1456,8 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f psys_copy_particles(psysn, psys); if (psys->clmd) { - psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth); - modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag); + psysn->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth); + BKE_modifier_copydata_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag); psys->hair_in_mesh = psys->hair_out_mesh = NULL; } @@ -1451,7 +1610,7 @@ Object *BKE_object_pose_armature_get(Object *ob) return ob; } - ob = modifiers_isDeformedByArmature(ob); + ob = BKE_modifiers_is_deformed_by_armature(ob); /* Only use selected check when non-active. */ if (BKE_object_pose_context_check(ob)) { @@ -2692,7 +2851,7 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o { /* Execute drivers and animation. */ const bool flush_to_original = DEG_is_active(depsgraph); - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original); + BKE_animsys_evaluate_animdata(&ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original); object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL); } @@ -3889,16 +4048,16 @@ int BKE_object_is_modified(Scene *scene, Object *ob) ModifierData *md; VirtualModifierData virtualModifierData; /* cloth */ - for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); md && (flag != (eModifierMode_Render | eModifierMode_Realtime)); md = md->next) { if ((flag & eModifierMode_Render) == 0 && - modifier_isEnabled(scene, md, eModifierMode_Render)) { + BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) { flag |= eModifierMode_Render; } if ((flag & eModifierMode_Realtime) == 0 && - modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { flag |= eModifierMode_Realtime; } } @@ -4031,10 +4190,10 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob) } /* cloth */ - for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); md && (flag != (eModifierMode_Render | eModifierMode_Realtime)); md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); bool can_deform = mti->type == eModifierTypeType_OnlyDeform || is_modifier_animated; if (!can_deform) { @@ -4042,12 +4201,13 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob) } if (can_deform) { - if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render)) { + if (!(flag & eModifierMode_Render) && + BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) { flag |= eModifierMode_Render; } if (!(flag & eModifierMode_Realtime) && - modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { flag |= eModifierMode_Realtime; } } @@ -4382,7 +4542,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) { - if (modifier_dependsOnTime(md)) { + if (BKE_modifier_depends_ontime(md)) { return true; } @@ -4425,7 +4585,7 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md) { - if (BKE_gpencil_modifier_dependsOnTime(md)) { + if (BKE_gpencil_modifier_depends_ontime(md)) { return true; } @@ -4460,7 +4620,7 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md) bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx) { - if (BKE_shaderfx_dependsOnTime(fx)) { + if (BKE_shaderfx_depends_ontime(fx)) { return true; } @@ -4526,7 +4686,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph, int type) { const bool flush_to_original = DEG_is_active(depsgraph); - ModifierData *md = modifiers_findByType(ob, (ModifierType)type); + ModifierData *md = BKE_modifiers_findby_type(ob, (ModifierType)type); bConstraint *con; if (type == eModifierType_DynamicPaint) { @@ -4590,8 +4750,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph, /* TODO(sergey): What about animation? */ ob->id.recalc |= ID_RECALC_ALL; if (update_mesh) { - BKE_animsys_evaluate_animdata( - scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original); + BKE_animsys_evaluate_animdata(&ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original); /* ignore cache clear during subframe updates * to not mess up cache validity */ object_cacheIgnoreClear(ob, 1); @@ -4605,14 +4764,12 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph, /* for curve following objects, parented curve has to be updated too */ if (ob->type == OB_CURVE) { Curve *cu = ob->data; - BKE_animsys_evaluate_animdata( - scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original); + BKE_animsys_evaluate_animdata(&cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original); } /* and armatures... */ if (ob->type == OB_ARMATURE) { bArmature *arm = ob->data; - BKE_animsys_evaluate_animdata( - scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original); + BKE_animsys_evaluate_animdata(&arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original); BKE_pose_where_is(depsgraph, scene, ob); } diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index a75180867cb..6ca1442497a 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -620,7 +620,7 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot) /* now loop through the armature modifiers and identify deform bones */ for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0), - modifiers_getVirtualModifierList(ob, &virtualModifierData) : + BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) : md->next) { if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual))) { continue; diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 2683d384bc7..8957628c76a 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -453,21 +453,17 @@ static void ocean_compute_htilda(void *__restrict userdata, } } -static void ocean_compute_displacement_y(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_displacement_y(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; fftw_execute(o->_disp_y_plan); } -static void ocean_compute_displacement_x(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_displacement_x(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; const float scale = osd->scale; const float chop_amount = osd->chop_amount; @@ -494,11 +490,9 @@ static void ocean_compute_displacement_x(TaskPool *__restrict pool, fftw_execute(o->_disp_x_plan); } -static void ocean_compute_displacement_z(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_displacement_z(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; const float scale = osd->scale; const float chop_amount = osd->chop_amount; @@ -525,11 +519,9 @@ static void ocean_compute_displacement_z(TaskPool *__restrict pool, fftw_execute(o->_disp_z_plan); } -static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; const float chop_amount = osd->chop_amount; int i, j; @@ -560,11 +552,9 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, } } -static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; const float chop_amount = osd->chop_amount; int i, j; @@ -595,11 +585,9 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, } } -static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; const float chop_amount = osd->chop_amount; int i, j; @@ -624,11 +612,9 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, fftw_execute(o->_Jxz_plan); } -static void ocean_compute_normal_x(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_normal_x(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; int i, j; @@ -645,11 +631,9 @@ static void ocean_compute_normal_x(TaskPool *__restrict pool, fftw_execute(o->_N_x_plan); } -static void ocean_compute_normal_z(TaskPool *__restrict pool, - void *UNUSED(taskdata), - int UNUSED(threadid)) +static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskdata)) { - OceanSimulateData *osd = BLI_task_pool_userdata(pool); + OceanSimulateData *osd = BLI_task_pool_user_data(pool); const Ocean *o = osd->o; int i, j; @@ -668,7 +652,6 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool, void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); TaskPool *pool; OceanSimulateData osd; @@ -680,7 +663,7 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount osd.scale = scale; osd.chop_amount = chop_amount; - pool = BLI_task_pool_create(scheduler, &osd, TASK_PRIORITY_HIGH); + pool = BLI_task_pool_create(&osd, TASK_PRIORITY_HIGH); BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 0c9b1721f79..f26b478c680 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -10,7 +10,7 @@ * 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, + * 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) 2009 by Nicholas Bishop @@ -116,6 +116,7 @@ IDTypeInfo IDType_ID_PAL = { .copy_data = palette_copy_data, .free_data = palette_free_data, .make_local = NULL, + .foreach_id = NULL, }; static void paint_curve_copy_data(Main *UNUSED(bmain), @@ -153,6 +154,7 @@ IDTypeInfo IDType_ID_PC = { .copy_data = paint_curve_copy_data, .free_data = paint_curve_free_data, .make_local = NULL, + .foreach_id = NULL, }; const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; @@ -1406,15 +1408,15 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob) return NULL; } - for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) { + for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); md; md = md->next) { if (md->type == eModifierType_Multires) { MultiresModifierData *mmd = (MultiresModifierData *)md; - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } - if (BKE_multires_sculpt_level_get(mmd) > 0) { + if (mmd->sculptlvl > 0) { return mmd; } else { @@ -1443,12 +1445,12 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) return true; } - md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) { @@ -1692,7 +1694,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) * isn't one already */ if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) { GridPaintMask *gmask; - int level = max_ii(1, BKE_multires_sculpt_level_get(mmd)); + int level = max_ii(1, mmd->sculptlvl); int gridsize = BKE_ccg_gridsize(level); int gridarea = gridsize * gridsize; int i, j; diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c index 5e5b5c84997..0ea0173f8a3 100644 --- a/source/blender/blenkernel/intern/paint_toolslots.c +++ b/source/blender/blenkernel/intern/paint_toolslots.c @@ -10,7 +10,7 @@ * 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, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 56d114ebab5..015c67806c6 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -55,21 +55,22 @@ #include "BKE_cloth.h" #include "BKE_collection.h" #include "BKE_colortools.h" -#include "BKE_effect.h" -#include "BKE_idtype.h" -#include "BKE_lattice.h" -#include "BKE_main.h" - #include "BKE_deform.h" #include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_idtype.h" #include "BKE_key.h" +#include "BKE_lattice.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" +#include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_scene.h" +#include "BKE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -146,6 +147,53 @@ static void particle_settings_free_data(ID *id) fluid_free_settings(particle_settings->fluid); } +static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data) +{ + ParticleSettings *psett = (ParticleSettings *)id; + BKE_LIB_FOREACHID_PROCESS(data, psett->instance_collection, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, psett->instance_object, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, psett->bb_ob, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, psett->collision_group, IDWALK_CB_NOP); + + for (int i = 0; i < MAX_MTEX; i++) { + if (psett->mtex[i]) { + BKE_texture_mtex_foreach_id(data, psett->mtex[i]); + } + } + + if (psett->effector_weights) { + BKE_LIB_FOREACHID_PROCESS(data, psett->effector_weights->group, IDWALK_CB_NOP); + } + + if (psett->pd) { + BKE_LIB_FOREACHID_PROCESS(data, psett->pd->tex, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, psett->pd->f_source, IDWALK_CB_NOP); + } + if (psett->pd2) { + BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->tex, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->f_source, IDWALK_CB_NOP); + } + + if (psett->boids) { + LISTBASE_FOREACH (BoidState *, state, &psett->boids->states) { + LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { + if (rule->type == eBoidRuleType_Avoid) { + BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; + BKE_LIB_FOREACHID_PROCESS(data, gabr->ob, IDWALK_CB_NOP); + } + else if (rule->type == eBoidRuleType_FollowLeader) { + BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; + BKE_LIB_FOREACHID_PROCESS(data, flbr->ob, IDWALK_CB_NOP); + } + } + } + } + + LISTBASE_FOREACH (ParticleDupliWeight *, dw, &psett->instance_weights) { + BKE_LIB_FOREACHID_PROCESS(data, dw->ob, IDWALK_CB_NOP); + } +} + IDTypeInfo IDType_ID_PA = { .id_code = ID_PA, .id_filter = FILTER_ID_PA, @@ -160,6 +208,7 @@ IDTypeInfo IDType_ID_PA = { .copy_data = particle_settings_copy_data, .free_data = particle_settings_free_data, .make_local = NULL, + .foreach_id = particle_settings_foreach_id, }; unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT]; @@ -583,7 +632,7 @@ void free_hair(Object *object, ParticleSystem *psys, int dynamics) if (psys->clmd) { if (dynamics) { - modifier_free((ModifierData *)psys->clmd); + BKE_modifier_free((ModifierData *)psys->clmd); psys->clmd = NULL; PTCacheID pid; BKE_ptcache_id_from_particles(&pid, object, psys); @@ -735,7 +784,7 @@ void psys_free(Object *ob, ParticleSystem *psys) */ free_hair(ob, psys, 0); if (psys->clmd != NULL) { - modifier_free((ModifierData *)psys->clmd); + BKE_modifier_free((ModifierData *)psys->clmd); } psys_free_particles(psys); @@ -2788,9 +2837,7 @@ static void psys_thread_create_path(ParticleTask *task, } } -static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool), void *taskdata) { ParticleTask *task = taskdata; ParticleThreadContext *ctx = task->ctx; @@ -2811,7 +2858,6 @@ void psys_cache_child_paths(ParticleSimulationData *sim, const bool editupdate, const bool use_render_params) { - TaskScheduler *task_scheduler; TaskPool *task_pool; ParticleThreadContext ctx; ParticleTask *tasks_parent, *tasks_child; @@ -2827,8 +2873,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, return; } - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &ctx, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW); totchild = ctx.totchild; totparent = ctx.totparent; @@ -3378,7 +3423,6 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings); edit->totcached = totpart; @@ -3591,9 +3635,9 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob, psys->part = BKE_particlesettings_add(bmain, psys->name); - md = modifier_new(eModifierType_ParticleSystem); + md = BKE_modifier_new(eModifierType_ParticleSystem); BLI_strncpy(md->name, psys->name, sizeof(md->name)); - modifier_unique_name(&ob->modifiers, md); + BKE_modifier_unique_name(&ob->modifiers, md); psmd = (ParticleSystemModifierData *)md; psmd->psys = psys; @@ -3621,7 +3665,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob } /* Clear particle system in fluid modifier. */ - if ((md = modifiers_findByType(ob, eModifierType_Fluid))) { + if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid))) { FluidModifierData *mmd = (FluidModifierData *)md; /* Clear particle system pointer in flow settings. */ @@ -3663,7 +3707,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob } } - if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint))) { + if ((md = BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint))) { DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; if (pmd->brush && pmd->brush->psys) { if (pmd->brush->psys == psys) { @@ -3676,7 +3720,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob psmd = psys_get_modifier(ob, psys); if (psmd) { BLI_remlink(&ob->modifiers, psmd); - modifier_free((ModifierData *)psmd); + BKE_modifier_free((ModifierData *)psmd); } /* Clear particle system. */ @@ -4010,7 +4054,7 @@ static void get_cpa_texture(Mesh *mesh, break; } - externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false); + RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba); if ((event & mtex->mapto) & PAMAP_ROUGH) { ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend( @@ -4125,7 +4169,7 @@ void psys_get_texture( break; } - externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false); + RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba); if ((event & mtex->mapto) & PAMAP_TIME) { /* the first time has to set the base value for time regardless of blend mode */ diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index d91e27a92d8..7b9b2484dbe 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -773,9 +773,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i } } -static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), void *taskdata) { ParticleTask *task = taskdata; ParticleSystem *psys = task->ctx->sim.psys; @@ -804,9 +802,7 @@ static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), } } -static void exec_distribute_child(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void exec_distribute_child(TaskPool *__restrict UNUSED(pool), void *taskdata) { ParticleTask *task = taskdata; ParticleSystem *psys = task->ctx->sim.psys; @@ -1324,7 +1320,6 @@ static void psys_task_init_distribute(ParticleTask *task, ParticleSimulationData static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) { - TaskScheduler *task_scheduler; TaskPool *task_pool; ParticleThreadContext ctx; ParticleTask *tasks; @@ -1336,8 +1331,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) return; } - task_scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create(task_scheduler, &ctx, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW); totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart); psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index f7400264131..df74b7a75da 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3450,7 +3450,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim) bool realloc_roots; if (!psys->clmd) { - psys->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth); + psys->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth); psys->clmd->sim_parms->goalspring = 0.0f; psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS; psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF; @@ -3693,10 +3693,11 @@ typedef struct DynamicStepSolverTaskData { SpinLock spin; } DynamicStepSolverTaskData; -static void dynamics_step_finalize_sphdata(void *__restrict UNUSED(userdata), - void *__restrict tls_userdata_chunk) +static void dynamics_step_sphdata_reduce(const void *__restrict UNUSED(userdata), + void *__restrict UNUSED(join_v), + void *__restrict chunk_v) { - SPHData *sphdata = tls_userdata_chunk; + SPHData *sphdata = chunk_v; psys_sph_flush_springs(sphdata); } @@ -3987,7 +3988,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) settings.use_threading = (psys->totpart > 100); settings.userdata_chunk = &sphdata; settings.userdata_chunk_size = sizeof(sphdata); - settings.func_finalize = dynamics_step_finalize_sphdata; + settings.func_reduce = dynamics_step_sphdata_reduce; BLI_task_parallel_range( 0, psys->totpart, &task_data, dynamics_step_sph_ddr_task_cb_ex, &settings); @@ -4019,7 +4020,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) settings.use_threading = (psys->totpart > 100); settings.userdata_chunk = &sphdata; settings.userdata_chunk_size = sizeof(sphdata); - settings.func_finalize = dynamics_step_finalize_sphdata; + settings.func_reduce = dynamics_step_sphdata_reduce; BLI_task_parallel_range(0, psys->totpart, &task_data, @@ -4034,7 +4035,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) settings.use_threading = (psys->totpart > 100); settings.userdata_chunk = &sphdata; settings.userdata_chunk_size = sizeof(sphdata); - settings.func_finalize = dynamics_step_finalize_sphdata; + settings.func_reduce = dynamics_step_sphdata_reduce; BLI_task_parallel_range(0, psys->totpart, &task_data, @@ -4182,7 +4183,8 @@ static void particles_fluid_step(ParticleSimulationData *sim, #else { Object *ob = sim->ob; - FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, + eModifierType_Fluid); if (mmd && mmd->domain && mmd->domain->fluid) { FluidDomainSettings *mds = mmd->domain; @@ -4190,7 +4192,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, ParticleSettings *part = psys->part; ParticleData *pa = NULL; - int p, totpart, tottypepart = 0; + int p, totpart = 0, tottypepart = 0; int flagActivePart, activeParts = 0; float posX, posY, posZ, velX, velY, velZ; float resX, resY, resZ; @@ -4848,7 +4850,7 @@ void particle_system_update(struct Depsgraph *depsgraph, hcfra = 100.0f * (float)i / (float)psys->part->hair_step; if ((part->flag & PART_HAIR_REGROW) == 0) { BKE_animsys_evaluate_animdata( - scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false); + &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false); } system_step(&sim, hcfra, use_render_params); psys->cfra = hcfra; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 17edf94a53c..e31d2a8e005 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1120,11 +1120,11 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode) .vnors = vnors, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); MEM_freeN(vnors); } @@ -1174,9 +1174,9 @@ static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, in .flag = flag, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); } static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata, @@ -1212,9 +1212,9 @@ static void pbvh_update_visibility_redraw(PBVH *bvh, PBVHNode **nodes, int totno .flag = flag, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings); } static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata, @@ -1250,9 +1250,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) .flag = flag, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); } static int pbvh_get_buffers_update_flags(PBVH *UNUSED(bvh)) @@ -1362,9 +1362,9 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, i .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); } static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) @@ -1555,9 +1555,9 @@ static void pbvh_update_visibility(PBVH *bvh, PBVHNode **nodes, int totnode) .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings); } void BKE_pbvh_update_visibility(PBVH *bvh) @@ -1924,7 +1924,7 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, /** * \note doing a full search on all vertices here seems expensive, - * however this is important to avoid having to recalculate boundbox & sync the buffers to the + * however this is important to avoid having to recalculate bound-box & sync the buffers to the * GPU (which is far more expensive!) See: T47232. */ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node) @@ -3003,7 +3003,7 @@ void BKE_pbvh_get_frustum_planes(PBVH *bvh, PBVHFrustumPlanes *planes) } } -void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings, +void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings, bool use_threading, int totnode) { diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenkernel/intern/pbvh_parallel.cc deleted file mode 100644 index aced73ec817..00000000000 --- a/source/blender/blenkernel/intern/pbvh_parallel.cc +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_task.h" -#include "BLI_threads.h" - -#include "BKE_pbvh.h" - -#include "atomic_ops.h" - -#ifdef WITH_TBB - -/* Quiet top level deprecation message, unrelated to API usage here. */ -# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1 - -# include <tbb/tbb.h> - -/* Functor for running TBB parallel_for and parallel_reduce. */ -struct PBVHTask { - PBVHParallelRangeFunc func; - void *userdata; - const PBVHParallelSettings *settings; - - void *userdata_chunk; - - /* Root constructor. */ - PBVHTask(PBVHParallelRangeFunc func, void *userdata, const PBVHParallelSettings *settings) - : func(func), userdata(userdata), settings(settings) - { - init_chunk(settings->userdata_chunk); - } - - /* Copy constructor. */ - PBVHTask(const PBVHTask &other) - : func(other.func), userdata(other.userdata), settings(other.settings) - { - init_chunk(settings->userdata_chunk); - } - - /* Splitting constructor for parallel reduce. */ - PBVHTask(PBVHTask &other, tbb::split) - : func(other.func), userdata(other.userdata), settings(other.settings) - { - init_chunk(settings->userdata_chunk); - } - - ~PBVHTask() - { - MEM_SAFE_FREE(userdata_chunk); - } - - void init_chunk(void *from_chunk) - { - if (from_chunk) { - userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask"); - memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size); - } - else { - userdata_chunk = NULL; - } - } - - void operator()(const tbb::blocked_range<int> &r) const - { - TaskParallelTLS tls; - tls.thread_id = get_thread_id(); - tls.userdata_chunk = userdata_chunk; - for (int i = r.begin(); i != r.end(); ++i) { - func(userdata, i, &tls); - } - } - - void join(const PBVHTask &other) - { - settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk); - } - - int get_thread_id() const - { - /* Get a unique thread ID for texture nodes. In the future we should get rid - * of the thread ID and change texture evaluation to not require per-thread - * storage that can't be efficiently allocated on the stack. */ - static tbb::enumerable_thread_specific<int> pbvh_thread_id(-1); - static int pbvh_thread_id_counter = 0; - - int &thread_id = pbvh_thread_id.local(); - if (thread_id == -1) { - thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1); - if (thread_id >= BLENDER_MAX_THREADS) { - BLI_assert(!"Maximum number of threads exceeded for sculpting"); - thread_id = thread_id % BLENDER_MAX_THREADS; - } - } - return thread_id; - } -}; - -#endif - -void BKE_pbvh_parallel_range(const int start, - const int stop, - void *userdata, - PBVHParallelRangeFunc func, - const struct PBVHParallelSettings *settings) -{ -#ifdef WITH_TBB - /* Multithreading. */ - if (settings->use_threading) { - BLI_threaded_malloc_begin(); - - PBVHTask task(func, userdata, settings); - - if (settings->func_reduce) { - parallel_reduce(tbb::blocked_range<int>(start, stop), task); - if (settings->userdata_chunk) { - memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size); - } - } - else { - parallel_for(tbb::blocked_range<int>(start, stop), task); - } - - BLI_threaded_malloc_end(); - return; - } -#endif - - /* Single threaded. Nothing to reduce as everything is accumulated into the - * main userdata chunk directly. */ - TaskParallelTLS tls; - tls.thread_id = 0; - tls.userdata_chunk = settings->userdata_chunk; - for (int i = start; i < stop; i++) { - func(userdata, i, &tls); - } -} diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 77b3f1580ac..5ee61667eca 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -583,7 +583,7 @@ static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra)) static void ptcache_cloth_error(void *cloth_v, const char *message) { ClothModifierData *clmd = cloth_v; - modifier_setError(&clmd->modifier, "%s", message); + BKE_modifier_set_error(&clmd->modifier, "%s", message); } #ifdef WITH_SMOKE @@ -604,7 +604,7 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra)) static void ptcache_smoke_error(void *smoke_v, const char *message) { FluidModifierData *mmd = (FluidModifierData *)smoke_v; - modifier_setError(&mmd->modifier, "%s", message); + BKE_modifier_set_error(&mmd->modifier, "%s", message); } # define SMOKE_CACHE_VERSION "1.04" diff --git a/source/blender/blenkernel/intern/pointcloud.c b/source/blender/blenkernel/intern/pointcloud.c index 31b8de53291..e03888dcad7 100644 --- a/source/blender/blenkernel/intern/pointcloud.c +++ b/source/blender/blenkernel/intern/pointcloud.c @@ -21,6 +21,7 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_pointcloud_types.h" @@ -48,23 +49,7 @@ /* PointCloud datablock */ -static void pointcloud_random(PointCloud *pointcloud) -{ - pointcloud->totpoint = 400; - CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); - BKE_pointcloud_update_customdata_pointers(pointcloud); - - RNG *rng = BLI_rng_new(0); - - for (int i = 0; i < pointcloud->totpoint; i++) { - pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f; - pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng); - } - - BLI_rng_free(rng); -} +static void pointcloud_random(PointCloud *pointcloud); static void pointcloud_init_data(ID *id) { @@ -81,15 +66,6 @@ static void pointcloud_init_data(ID *id) pointcloud_random(pointcloud); } -void *BKE_pointcloud_add(Main *bmain, const char *name) -{ - PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0); - - pointcloud_init_data(&pointcloud->id); - - return pointcloud; -} - static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag) { PointCloud *pointcloud_dst = (PointCloud *)id_dst; @@ -105,18 +81,6 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s BKE_pointcloud_update_customdata_pointers(pointcloud_dst); } -PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud) -{ - PointCloud *pointcloud_copy; - BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy); - return pointcloud_copy; -} - -static void pointcloud_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - static void pointcloud_free_data(ID *id) { PointCloud *pointcloud = (PointCloud *)id; @@ -126,6 +90,14 @@ static void pointcloud_free_data(ID *id) MEM_SAFE_FREE(pointcloud->mat); } +static void pointcloud_foreach_id(ID *id, LibraryForeachIDData *data) +{ + PointCloud *pointcloud = (PointCloud *)id; + for (int i = 0; i < pointcloud->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, pointcloud->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_PT = { .id_code = ID_PT, .id_filter = FILTER_ID_PT, @@ -139,9 +111,44 @@ IDTypeInfo IDType_ID_PT = { .init_data = pointcloud_init_data, .copy_data = pointcloud_copy_data, .free_data = pointcloud_free_data, - .make_local = pointcloud_make_local, + .make_local = NULL, + .foreach_id = pointcloud_foreach_id, }; +static void pointcloud_random(PointCloud *pointcloud) +{ + pointcloud->totpoint = 400; + CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); + BKE_pointcloud_update_customdata_pointers(pointcloud); + + RNG *rng = BLI_rng_new(0); + + for (int i = 0; i < pointcloud->totpoint; i++) { + pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f; + pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f; + pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f; + pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng); + } + + BLI_rng_free(rng); +} + +void *BKE_pointcloud_add(Main *bmain, const char *name) +{ + PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0); + + pointcloud_init_data(&pointcloud->id); + + return pointcloud; +} + +PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud) +{ + PointCloud *pointcloud_copy; + BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy); + return pointcloud_copy; +} + BoundBox *BKE_pointcloud_boundbox_get(Object *ob) { BLI_assert(ob->type == OB_POINTCLOUD); @@ -184,7 +191,7 @@ void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud) PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int totpoint) { - PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_HA, NULL); + PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_PT, NULL); STRNCPY(pointcloud_dst->id.name, pointcloud_src->id.name); pointcloud_dst->mat = MEM_dupallocN(pointcloud_src->mat); @@ -211,12 +218,65 @@ PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool return result; } -static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph), - struct Scene *UNUSED(scene), - Object *UNUSED(object), +static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph, + struct Scene *scene, + Object *object, PointCloud *pointcloud_input) { - return pointcloud_input; + PointCloud *pointcloud = pointcloud_input; + + /* Modifier evaluation modes. */ + const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; + const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; + + /* Get effective list of modifiers to execute. Some effects like shape keys + * are added as virtual modifiers before the user created modifiers. */ + VirtualModifierData virtualModifierData; + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); + + /* Evaluate modifiers. */ + for (; md; md = md->next) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { + continue; + } + + if ((mti->type == eModifierTypeType_OnlyDeform) && + (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) { + /* Ensure we are not modifying the input. */ + if (pointcloud == pointcloud_input) { + pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true); + } + + /* Ensure we are not overwriting referenced data. */ + CustomData_duplicate_referenced_layer(&pointcloud->pdata, CD_LOCATION, pointcloud->totpoint); + BKE_pointcloud_update_customdata_pointers(pointcloud); + + /* Created deformed coordinates array on demand. */ + mti->deformVerts(md, &mectx, NULL, pointcloud->co, pointcloud->totpoint); + } + else if (mti->modifyPointCloud) { + /* Ensure we are not modifying the input. */ + if (pointcloud == pointcloud_input) { + pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true); + } + + PointCloud *pointcloud_next = mti->modifyPointCloud(md, &mectx, pointcloud); + + if (pointcloud_next && pointcloud_next != pointcloud) { + /* If the modifier returned a new pointcloud, release the old one. */ + if (pointcloud != pointcloud_input) { + BKE_id_free(NULL, pointcloud); + } + pointcloud = pointcloud_next; + } + } + } + + return pointcloud; } void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object) diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 410d5b41057..34249e0a8f7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -33,6 +33,7 @@ #include "DNA_defaults.h" #include "DNA_gpencil_types.h" #include "DNA_linestyle_types.h" +#include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -42,6 +43,7 @@ #include "DNA_sequence_types.h" #include "DNA_sound_types.h" #include "DNA_space_types.h" +#include "DNA_text_types.h" #include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" @@ -77,6 +79,7 @@ #include "BKE_image.h" #include "BKE_layer.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_linestyle.h" #include "BKE_main.h" @@ -343,7 +346,7 @@ static void scene_free_data(ID *id) /* is no lib link block, but scene extension */ if (scene->nodetree) { - ntreeFreeNestedTree(scene->nodetree); + ntreeFreeEmbeddedTree(scene->nodetree); MEM_freeN(scene->nodetree); scene->nodetree = NULL; } @@ -418,6 +421,155 @@ static void scene_free_data(ID *id) BLI_assert(scene->layer_properties == NULL); } +static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw), + ID **id_pointer, + void *user_data, + int cb_flag) +{ + LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; + BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); +} + +static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) +{ + BKE_LIB_FOREACHID_PROCESS(data, paint->brush, IDWALK_CB_USER); + for (int i = 0; i < paint->tool_slots_len; i++) { + BKE_LIB_FOREACHID_PROCESS(data, paint->tool_slots[i].brush, IDWALK_CB_USER); + } + BKE_LIB_FOREACHID_PROCESS(data, paint->palette, IDWALK_CB_USER); +} + +static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) +{ + LISTBASE_FOREACH (LayerCollection *, lc, lb) { + /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad + * anyway... */ + const int cb_flag = (lc->collection != NULL && + (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : + IDWALK_CB_NOP; + BKE_LIB_FOREACHID_PROCESS(data, lc->collection, cb_flag); + library_foreach_layer_collection(data, &lc->layer_collections); + } +} + +static void scene_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Scene *scene = (Scene *)id; + + BKE_LIB_FOREACHID_PROCESS(data, scene->camera, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, scene->world, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, scene->set, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, scene->clip, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, scene->gpd, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, scene->r.bake.cage_object, IDWALK_CB_NOP); + if (scene->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree); + } + if (scene->ed) { + Sequence *seq; + SEQP_BEGIN (scene->ed, seq) { + BKE_LIB_FOREACHID_PROCESS(data, seq->scene, IDWALK_CB_NEVER_SELF); + BKE_LIB_FOREACHID_PROCESS(data, seq->scene_camera, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, seq->clip, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, seq->mask, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, seq->sound, IDWALK_CB_USER); + IDP_foreach_property( + seq->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) { + BKE_LIB_FOREACHID_PROCESS(data, smd->mask_id, IDWALK_CB_USER); + } + + if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) { + TextVars *text_data = seq->effectdata; + BKE_LIB_FOREACHID_PROCESS(data, text_data->text_font, IDWALK_CB_USER); + } + } + SEQ_END; + } + + /* This pointer can be NULL during old files reading, better be safe than sorry. */ + if (scene->master_collection != NULL) { + BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection); + } + + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + BKE_LIB_FOREACHID_PROCESS(data, view_layer->mat_override, IDWALK_CB_USER); + + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + BKE_LIB_FOREACHID_PROCESS(data, base->object, IDWALK_CB_NOP); + } + + library_foreach_layer_collection(data, &view_layer->layer_collections); + + LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { + if (fmc->script) { + BKE_LIB_FOREACHID_PROCESS(data, fmc->script, IDWALK_CB_NOP); + } + } + + LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { + if (fls->group) { + BKE_LIB_FOREACHID_PROCESS(data, fls->group, IDWALK_CB_USER); + } + + if (fls->linestyle) { + BKE_LIB_FOREACHID_PROCESS(data, fls->linestyle, IDWALK_CB_USER); + } + } + } + + LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { + BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP); + } + + ToolSettings *toolsett = scene->toolsettings; + if (toolsett) { + BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.scene, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.object, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.shape_object, IDWALK_CB_NOP); + + library_foreach_paint(data, &toolsett->imapaint.paint); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.stencil, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.clone, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.canvas, IDWALK_CB_USER); + + if (toolsett->vpaint) { + library_foreach_paint(data, &toolsett->vpaint->paint); + } + if (toolsett->wpaint) { + library_foreach_paint(data, &toolsett->wpaint->paint); + } + if (toolsett->sculpt) { + library_foreach_paint(data, &toolsett->sculpt->paint); + BKE_LIB_FOREACHID_PROCESS(data, toolsett->sculpt->gravity_object, IDWALK_CB_NOP); + } + if (toolsett->uvsculpt) { + library_foreach_paint(data, &toolsett->uvsculpt->paint); + } + if (toolsett->gp_paint) { + library_foreach_paint(data, &toolsett->gp_paint->paint); + } + if (toolsett->gp_vertexpaint) { + library_foreach_paint(data, &toolsett->gp_vertexpaint->paint); + } + if (toolsett->gp_sculptpaint) { + library_foreach_paint(data, &toolsett->gp_sculptpaint->paint); + } + if (toolsett->gp_weightpaint) { + library_foreach_paint(data, &toolsett->gp_weightpaint->paint); + } + + BKE_LIB_FOREACHID_PROCESS(data, toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP); + } + + if (scene->rigidbody_world) { + BKE_rigidbody_world_id_loop( + scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, data); + } +} + IDTypeInfo IDType_ID_SCE = { .id_code = ID_SCE, .id_filter = FILTER_ID_SCE, @@ -434,6 +586,7 @@ IDTypeInfo IDType_ID_SCE = { /* For now default `BKE_lib_id_make_local_generic()` should work, may need more work though to * support all possible corner cases. */ .make_local = NULL, + .foreach_id = scene_foreach_id, }; const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE"; @@ -1175,34 +1328,6 @@ int BKE_scene_orientation_slot_get_index(const TransformOrientationSlot *orient_ /** \} */ -/* That's like really a bummer, because currently animation data for armatures - * might want to use pose, and pose might be missing on the object. - * This happens when changing visible layers, which leads to situations when - * pose is missing or marked for recalc, animation will change it and then - * object update will restore the pose. - * - * This could be solved by the new dependency graph, but for until then we'll - * do an extra pass on the objects to ensure it's all fine. - */ -#define POSE_ANIMATION_WORKAROUND - -#ifdef POSE_ANIMATION_WORKAROUND -static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph) -{ - Object *ob; - if (BLI_listbase_is_empty(&bmain->armatures) || !DEG_id_type_updated(depsgraph, ID_OB)) { - return; - } - for (ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->type == OB_ARMATURE && ob->adt) { - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(bmain, ob, ob->data, true); - } - } - } -} -#endif - static bool check_rendered_viewport_visible(Main *bmain) { wmWindowManager *wm = bmain->wm.first; @@ -1387,9 +1512,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain) BKE_image_editors_update_frame(bmain, scene->r.cfra); BKE_sound_set_cfra(scene->r.cfra); DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); -#ifdef POSE_ANIMATION_WORKAROUND - scene_armature_depsgraph_workaround(bmain, depsgraph); -#endif /* Update all objects: drivers, matrices, displists, etc. flags set * by depgraph or manual, no layer check here, gets correct flushed. * @@ -2110,7 +2232,7 @@ static Depsgraph **scene_get_depsgraph_p(Main *bmain, if (allocate_depsgraph) { *depsgraph_ptr = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT); /* TODO(sergey): Would be cool to avoid string format print, - * but is a bit tricky because we can't know in advance whether + * but is a bit tricky because we can't know in advance whether * we will ever enable debug messages for this depsgraph. */ char name[1024]; diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 997e807a253..bfc0d437994 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -32,14 +32,18 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_gpencil_types.h" +#include "DNA_mask_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_text_types.h" #include "DNA_view3d_types.h" #include "DNA_workspace_types.h" #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_mempool.h" #include "BLI_rect.h" #include "BLI_utildefines.h" @@ -48,6 +52,8 @@ #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" +#include "BKE_lib_query.h" +#include "BKE_node.h" #include "BKE_screen.h" #include "BKE_workspace.h" @@ -72,6 +78,158 @@ static void screen_free_data(ID *id) MEM_SAFE_FREE(screen->tool_tip); } +static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads) +{ + if (ads != NULL) { + BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP); + } +} + +void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area) +{ + BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP); + + /* TODO this should be moved to a callback in `SpaceType`, defined in each editor's own code. + * Will be for a later round of cleanup though... */ + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + switch (sl->spacetype) { + case SPACE_VIEW3D: { + View3D *v3d = (View3D *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP); + + if (v3d->localvd) { + BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP); + } + break; + } + case SPACE_GRAPH: { + SpaceGraph *sipo = (SpaceGraph *)sl; + + screen_foreach_id_dopesheet(data, sipo->ads); + break; + } + case SPACE_PROPERTIES: { + SpaceProperties *sbuts = (SpaceProperties *)sl; + + BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP); + break; + } + case SPACE_FILE: + break; + case SPACE_ACTION: { + SpaceAction *saction = (SpaceAction *)sl; + + screen_foreach_id_dopesheet(data, &saction->ads); + BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP); + break; + } + case SPACE_IMAGE: { + SpaceImage *sima = (SpaceImage *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE); + BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE); + BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER); + break; + } + case SPACE_SEQ: { + SpaceSeq *sseq = (SpaceSeq *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER); + break; + } + case SPACE_NLA: { + SpaceNla *snla = (SpaceNla *)sl; + + screen_foreach_id_dopesheet(data, snla->ads); + break; + } + case SPACE_TEXT: { + SpaceText *st = (SpaceText *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP); + break; + } + case SPACE_SCRIPT: { + SpaceScript *scpt = (SpaceScript *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP); + break; + } + case SPACE_OUTLINER: { + SpaceOutliner *so = (SpaceOutliner *)sl; + + BKE_LIB_FOREACHID_PROCESS_ID(data, so->search_tse.id, IDWALK_CB_NOP); + + if (so->treestore != NULL) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + BKE_LIB_FOREACHID_PROCESS_ID(data, tselem->id, IDWALK_CB_NOP); + } + } + break; + } + case SPACE_NODE: { + SpaceNode *snode = (SpaceNode *)sl; + + const bool is_private_nodetree = snode->id != NULL && + ntreeFromID(snode->id) == snode->nodetree; + + BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP); + + BKE_LIB_FOREACHID_PROCESS( + data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); + + LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) { + if (path == snode->treepath.first) { + /* first nodetree in path is same as snode->nodetree */ + BKE_LIB_FOREACHID_PROCESS(data, + path->nodetree, + is_private_nodetree ? IDWALK_CB_EMBEDDED : + IDWALK_CB_USER_ONE); + } + else { + BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE); + } + + if (path->nodetree == NULL) { + break; + } + } + + BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP); + break; + } + case SPACE_CLIP: { + SpaceClip *sclip = (SpaceClip *)sl; + + BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE); + BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE); + break; + } + default: + break; + } + } +} + +static void screen_foreach_id(ID *id, LibraryForeachIDData *data) +{ + if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { + bScreen *screen = (bScreen *)id; + + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + BKE_screen_foreach_id_screen_area(data, area); + } + } +} + IDTypeInfo IDType_ID_SCR = { .id_code = ID_SCR, .id_filter = 0, @@ -86,6 +244,7 @@ IDTypeInfo IDType_ID_SCR = { .copy_data = NULL, .free_data = screen_free_data, .make_local = NULL, + .foreach_id = screen_foreach_id, }; /* ************ Spacetype/regiontype handling ************** */ diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index c1644e39afa..9fa43ed0a5f 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -61,6 +61,8 @@ #include "BLF_api.h" +static struct SeqEffectHandle get_sequence_effect_impl(int seq_type); + static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, @@ -3118,7 +3120,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) { - return EARLY_USE_INPUT_1; + return EARLY_DO_EFFECT; } static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float *ymin, float *ymax) @@ -3248,36 +3250,60 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for } } +/* Override cfra when rendering speed effect input. */ +float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context, + Sequence *seq, + float cfra, + int input) +{ + int nr = BKE_sequencer_give_stripelem_index(seq, cfra); + SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; + BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false); + + /* No interpolation. */ + if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) { + return seq->start + s->frameMap[nr]; + } + + /* We need to provide current and next image for interpolation. */ + if (input == 0) { /* Current frame. */ + return floor(seq->start + s->frameMap[nr]); + } + else { /* Next frame. */ + return ceil(seq->start + s->frameMap[nr]); + } +} + +static float speed_effect_interpolation_ratio_get(SpeedControlVars *s, Sequence *seq, float cfra) +{ + int nr = BKE_sequencer_give_stripelem_index(seq, cfra); + return s->frameMap[nr] - floor(s->frameMap[nr]); +} + static ImBuf *do_speed_effect(const SeqRenderData *context, - Sequence *UNUSED(seq), - float UNUSED(cfra), + Sequence *seq, + float cfra, float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) { - ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); + SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; + struct SeqEffectHandle cross_effect = get_sequence_effect_impl(SEQ_TYPE_CROSS); + ImBuf *out; - if (out->rect_float) { - do_cross_effect_float(facf0, - facf1, - context->rectx, - context->recty, - ibuf1->rect_float, - ibuf2->rect_float, - out->rect_float); + if (s->flags & SEQ_SPEED_USE_INTERPOLATION) { + out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); + facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, cfra); + /* Current frame is ibuf1, next frame is ibuf2. */ + out = BKE_sequencer_effect_execute_threaded( + &cross_effect, context, NULL, cfra, facf0, facf1, ibuf1, ibuf2, ibuf3); + return out; } - else { - do_cross_effect_byte(facf0, - facf1, - context->rectx, - context->recty, - (unsigned char *)ibuf1->rect, - (unsigned char *)ibuf2->rect, - (unsigned char *)out->rect); - } - return out; + + /* No interpolation. */ + return IMB_dupImBuf(ibuf1); } /*********************** overdrop *************************/ diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c index dd074c643ac..dc75e2b9098 100644 --- a/source/blender/blenkernel/intern/seqprefetch.c +++ b/source/blender/blenkernel/intern/seqprefetch.c @@ -435,8 +435,7 @@ static void *seq_prefetch_frames(void *job) seq_prefetch_update_depsgraph(pfjob); AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id); - BKE_animsys_evaluate_animdata(pfjob->context_cpy.scene, - &pfjob->context_cpy.scene->id, + BKE_animsys_evaluate_animdata(&pfjob->context_cpy.scene->id, adt, seq_prefetch_cfra(pfjob), ADT_RECALC_ALL, diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index d0527a2635a..954dca0f679 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1397,7 +1397,7 @@ static void multibuf(ImBuf *ibuf, const float fmul) } } -static float give_stripelem_index(Sequence *seq, float cfra) +float BKE_sequencer_give_stripelem_index(Sequence *seq, float cfra) { float nr; int sta = seq->start; @@ -1455,7 +1455,7 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra) * all other strips don't use this... */ - int nr = (int)give_stripelem_index(seq, cfra); + int nr = (int)BKE_sequencer_give_stripelem_index(seq, cfra); if (nr == -1 || se == NULL) { return NULL; @@ -1895,7 +1895,7 @@ static bool seq_proxy_get_fname(Editing *ed, frameno = 1; } else { - frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs; + frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs; BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix); } @@ -1929,7 +1929,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c } if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) { - int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs; + int frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs; if (proxy->anim == NULL) { if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) { return NULL; @@ -2894,15 +2894,15 @@ static void *render_effect_execute_do_thread(void *thread_data_v) return NULL; } -static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, - const SeqRenderData *context, - Sequence *seq, - float cfra, - float facf0, - float facf1, - ImBuf *ibuf1, - ImBuf *ibuf2, - ImBuf *ibuf3) +ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh, + const SeqRenderData *context, + Sequence *seq, + float cfra, + float facf0, + float facf1, + ImBuf *ibuf1, + ImBuf *ibuf2, + ImBuf *ibuf3) { RenderEffectInitData init_data; ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3); @@ -2976,14 +2976,21 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, break; case EARLY_DO_EFFECT: for (i = 0; i < 3; i++) { - if (input[i]) { - ibuf[i] = seq_render_strip(context, state, input[i], cfra); + /* Speed effect requires time remapping of cfra for input(s). */ + if (input[1] && seq->type == SEQ_TYPE_SPEED) { + float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i); + ibuf[i] = seq_render_strip(context, state, input[i], target_frame); + } + else { /* Other effects. */ + if (input[i]) { + ibuf[i] = seq_render_strip(context, state, input[i], cfra); + } } } if (ibuf[0] && ibuf[1]) { if (sh.multithreaded) { - out = seq_render_effect_execute_threaded( + out = BKE_sequencer_effect_execute_threaded( &sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]); } else { @@ -3337,8 +3344,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr /* anim-data */ adt = BKE_animdata_from_id(&mask->id); - BKE_animsys_evaluate_animdata( - context->scene, &mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false); + BKE_animsys_evaluate_animdata(&mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false); maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__); @@ -3672,8 +3678,7 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context, if (seqbase && !BLI_listbase_is_empty(seqbase)) { if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) { - BKE_animsys_evaluate_all_animation( - context->bmain, context->depsgraph, seq->scene, nr + offset); + BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, nr + offset); } ibuf = seq_render_strip_stack(context, @@ -3693,9 +3698,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, float cfra) { ImBuf *ibuf = NULL; - float nr = give_stripelem_index(seq, cfra); - int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : - seq->type; + float nr = BKE_sequencer_give_stripelem_index(seq, cfra); + int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type; switch (type) { case SEQ_TYPE_META: { ibuf = do_render_strip_seqbase(context, state, seq, nr); @@ -3737,21 +3741,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, break; } - case SEQ_TYPE_SPEED: { - float f_cfra; - SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; - - BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false); - - /* weeek! */ - f_cfra = seq->start + s->frameMap[(int)nr]; - ibuf = seq_render_strip(context, state, seq->seq1, f_cfra); - - break; - } - case SEQ_TYPE_EFFECT: { - ibuf = seq_render_effect_strip_impl(context, state, seq, seq->start + nr); + ibuf = seq_render_effect_strip_impl(context, state, seq, cfra); break; } @@ -3945,7 +3936,7 @@ static ImBuf *seq_render_strip_stack_apply_effect( if (swap_input) { if (sh.multithreaded) { - out = seq_render_effect_execute_threaded( + out = BKE_sequencer_effect_execute_threaded( &sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL); } else { @@ -3954,7 +3945,7 @@ static ImBuf *seq_render_strip_stack_apply_effect( } else { if (sh.multithreaded) { - out = seq_render_effect_execute_threaded( + out = BKE_sequencer_effect_execute_threaded( &sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL); } else { diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c index 8d692782413..0ad61de1ff2 100644 --- a/source/blender/blenkernel/intern/shader_fx.c +++ b/source/blender/blenkernel/intern/shader_fx.c @@ -59,7 +59,7 @@ bool BKE_shaderfx_has_gpencil(Object *ob) { ShaderFxData *fx; for (fx = ob->shader_fx.first; fx; fx = fx->next) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type); if (fxi->type == eShaderFxType_GpencilType) { return true; } @@ -75,7 +75,7 @@ void BKE_shaderfx_init(void) ShaderFxData *BKE_shaderfx_new(int type) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type); ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name); /* note, this name must be made unique later */ @@ -109,7 +109,7 @@ static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { if (fxi->foreachIDLink) { @@ -139,21 +139,21 @@ void BKE_shaderfx_free(ShaderFxData *fx) bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx) { if (shaders && fx) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type); return BLI_uniquename( shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name)); } return false; } -bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx) +bool BKE_shaderfx_depends_ontime(ShaderFxData *fx) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type); return fxi->dependsOnTime && fxi->dependsOnTime(fx); } -const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type) +const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type) { /* type unsigned, no need to check < 0 */ if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') { @@ -164,9 +164,9 @@ const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type) } } -void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst) +void BKE_shaderfx_copydata_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx_src->type); /* fx_dst may have already be fully initialized with some extra allocated data, * we need to free it now to avoid memleak. */ @@ -192,9 +192,9 @@ static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), } } -void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag) +void BKE_shaderfx_copydata_ex(ShaderFxData *fx, ShaderFxData *target, const int flag) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type); target->mode = fx->mode; target->flag = fx->flag; @@ -214,12 +214,12 @@ void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int } } -void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target) +void BKE_shaderfx_copydata(ShaderFxData *fx, ShaderFxData *target) { - BKE_shaderfx_copyData_ex(fx, target, 0); + BKE_shaderfx_copydata_ex(fx, target, 0); } -ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type) +ShaderFxData *BKE_shaderfx_findby_type(Object *ob, ShaderFxType type) { ShaderFxData *fx = ob->shader_fx.first; @@ -232,12 +232,12 @@ ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type) return fx; } -void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData) +void BKE_shaderfx_foreach_ID_link(Object *ob, ShaderFxIDWalkFunc walk, void *userData) { ShaderFxData *fx = ob->shader_fx.first; for (; fx; fx = fx->next) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type); if (fxi->foreachIDLink) { fxi->foreachIDLink(fx, ob, walk, userData); @@ -250,7 +250,7 @@ void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userD } } -ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name) +ShaderFxData *BKE_shaderfx_findby_name(Object *ob, const char *name) { return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name)); } diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 06086cdf56a..c59042bc045 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -443,7 +443,7 @@ bool BKE_shrinkwrap_project_normal(char options, BVHTreeRayHit *hit) { /* don't use this because this dist value could be incompatible - * this value used by the callback for comparing prev/new dist values. + * this value used by the callback for comparing previous/new dist values. * also, at the moment there is no need to have a corrected 'dist' value */ // #define USE_DIST_CORRECT diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc new file mode 100644 index 00000000000..50770125a18 --- /dev/null +++ b/source/blender/blenkernel/intern/simulation.cc @@ -0,0 +1,127 @@ +/* + * 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. + */ + +/** \file + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_defaults.h" +#include "DNA_scene_types.h" +#include "DNA_simulation_types.h" + +#include "BLI_compiler_compat.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_anim_data.h" +#include "BKE_animsys.h" +#include "BKE_idtype.h" +#include "BKE_lib_id.h" +#include "BKE_lib_query.h" +#include "BKE_lib_remap.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_simulation.h" + +#include "NOD_simulation.h" + +#include "BLT_translation.h" + +#include "DEG_depsgraph.h" + +static void simulation_init_data(ID *id) +{ + Simulation *simulation = (Simulation *)id; + BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(simulation, id)); + + MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id); + + bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname); + simulation->nodetree = ntree; +} + +static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag) +{ + Simulation *simulation_dst = (Simulation *)id_dst; + Simulation *simulation_src = (Simulation *)id_src; + + /* We always need allocation of our private ID data. */ + const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE; + + if (simulation_src->nodetree) { + BKE_id_copy_ex(bmain, + (ID *)simulation_src->nodetree, + (ID **)&simulation_dst->nodetree, + flag_private_id_data); + } +} + +static void simulation_free_data(ID *id) +{ + Simulation *simulation = (Simulation *)id; + + BKE_animdata_free(&simulation->id, false); + + if (simulation->nodetree) { + ntreeFreeEmbeddedTree(simulation->nodetree); + MEM_freeN(simulation->nodetree); + simulation->nodetree = nullptr; + } +} + +static void simulation_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Simulation *simulation = (Simulation *)id; + if (simulation->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree); + } +} + +IDTypeInfo IDType_ID_SIM = { + /* id_code */ ID_SIM, + /* id_filter */ FILTER_ID_SIM, + /* main_listbase_index */ INDEX_ID_SIM, + /* struct_size */ sizeof(Simulation), + /* name */ "Simulation", + /* name_plural */ "simulations", + /* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION, + /* flags */ 0, + + /* init_data */ simulation_init_data, + /* copy_data */ simulation_copy_data, + /* free_data */ simulation_free_data, + /* make_local */ nullptr, + /* foreach_id */ simulation_foreach_id, +}; + +void *BKE_simulation_add(Main *bmain, const char *name) +{ + Simulation *simulation = (Simulation *)BKE_libblock_alloc(bmain, ID_SIM, name, 0); + + simulation_init_data(&simulation->id); + + return simulation; +} + +void BKE_simulation_data_update(Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene)) +{ +} diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index c358dde449f..68d0822a223 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -285,7 +285,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob) float hull; int i; - cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); + cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Collision); /* first some paranoia checks */ if (!cmd) { @@ -371,7 +371,7 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M) float hull; int i; - cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); + cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Collision); /* first some paranoia checks */ if (!cmd) { @@ -3010,7 +3010,7 @@ static void curve_surf_to_softbody(Scene *scene, Object *ob) * (C2= continuous in second derivate -> no jump in bending ) condition. * * Not too hard to do, but needs some more code to care for; - * some one may want look at it JOW 2010/06/12. */ + * some one may want look at it (JOW 2010/06/12). */ for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++, bp += 3, curindex += 3) { if (setgoal) { bp->goal *= bezt->weight; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 64fe396d6a3..e8f31594cc0 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -127,6 +127,7 @@ IDTypeInfo IDType_ID_SO = { .copy_data = sound_copy_data, .free_data = sound_free_data, .make_local = NULL, + .foreach_id = NULL, }; #ifdef WITH_AUDASPACE @@ -751,12 +752,12 @@ static void sound_start_play_scene(Scene *scene) } } -static float get_cur_time(Scene *scene) +static double get_cur_time(Scene *scene) { /* We divide by the current framelen to take into account time remapping. * Otherwise we will get the wrong starting time which will break A/V sync. * See T74111 for further details. */ - return FRA2TIME((CFRA + SUBFRA) / scene->r.framelen); + return FRA2TIME((CFRA + SUBFRA) / (double)scene->r.framelen); } void BKE_sound_play_scene(Scene *scene) @@ -764,7 +765,7 @@ void BKE_sound_play_scene(Scene *scene) sound_verify_evaluated_id(&scene->id); AUD_Status status; - const float cur_time = get_cur_time(scene); + const double cur_time = get_cur_time(scene); AUD_Device_lock(sound_device); @@ -811,8 +812,8 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene) bScreen *screen; int animation_playing; - const float one_frame = (float)(1.0 / FPS); - const float cur_time = FRA2TIME(CFRA); + const double one_frame = 1.0 / FPS; + const double cur_time = FRA2TIME(CFRA); AUD_Device_lock(sound_device); @@ -869,7 +870,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene) AUD_Device_unlock(sound_device); } -float BKE_sound_sync_scene(Scene *scene) +double BKE_sound_sync_scene(Scene *scene) { sound_verify_evaluated_id(&scene->id); @@ -1230,7 +1231,7 @@ void BKE_sound_stop_scene(Scene *UNUSED(scene)) void BKE_sound_seek_scene(Main *UNUSED(bmain), Scene *UNUSED(scene)) { } -float BKE_sound_sync_scene(Scene *UNUSED(scene)) +double BKE_sound_sync_scene(Scene *UNUSED(scene)) { return NAN_FLT; } @@ -1341,7 +1342,7 @@ void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback) #endif } -void BKE_sound_jack_scene_update(Scene *scene, int mode, float time) +void BKE_sound_jack_scene_update(Scene *scene, int mode, double time) { sound_verify_evaluated_id(&scene->id); diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index 980cc2a59fd..1f778f5fcd6 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -30,6 +30,7 @@ #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_speaker.h" @@ -42,6 +43,13 @@ static void speaker_init_data(ID *id) MEMCPY_STRUCT_AFTER(speaker, DNA_struct_default_get(Speaker), id); } +static void speaker_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Speaker *speaker = (Speaker *)id; + + BKE_LIB_FOREACHID_PROCESS(data, speaker->sound, IDWALK_CB_USER); +} + IDTypeInfo IDType_ID_SPK = { .id_code = ID_SPK, .id_filter = FILTER_ID_SPK, @@ -56,6 +64,7 @@ IDTypeInfo IDType_ID_SPK = { .copy_data = NULL, .free_data = NULL, .make_local = NULL, + .foreach_id = speaker_foreach_id, }; void *BKE_speaker_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c index 1f7cb225fc7..fe1dd3835fd 100644 --- a/source/blender/blenkernel/intern/subdiv.c +++ b/source/blender/blenkernel/intern/subdiv.c @@ -38,6 +38,18 @@ #include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" +/* =================----====--===== MODULE ==========================------== */ + +void BKE_subdiv_init() +{ + openSubdiv_init(); +} + +void BKE_subdiv_exit() +{ + openSubdiv_cleanup(); +} + /* ========================== CONVERSION HELPERS ============================ */ eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth) diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 0ae32701cd5..d5d5530c1ce 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -40,9 +40,9 @@ #include "opensubdiv_topology_refiner_capi.h" -/* ============================================================================= - * Various forward declarations. - */ +/* -------------------------------------------------------------------- */ +/** \name Various forward declarations + * \{ */ static void subdiv_ccg_average_all_boundaries_and_corners(SubdivCCG *subdiv_ccg, CCGKey *key); @@ -50,9 +50,11 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg, CCGKey *key, SubdivCCGFace *face); -/* ============================================================================= - * Generally useful internal helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generally useful internal helpers + * \{ */ /* Number of floats in per-vertex elements. */ static int num_element_float_get(const SubdivCCG *subdiv_ccg) @@ -74,9 +76,11 @@ static int element_size_bytes_get(const SubdivCCG *subdiv_ccg) return sizeof(float) * num_element_float_get(subdiv_ccg); } -/* ============================================================================= - * Internal helpers for CCG creation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal helpers for CCG creation + * \{ */ static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, const SubdivToCCGSettings *settings) { @@ -158,9 +162,11 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv) } } -/* ============================================================================= - * Grids evaluation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Grids evaluation + * \{ */ typedef struct CCGEvalGridsData { SubdivCCG *subdiv_ccg; @@ -556,9 +562,11 @@ static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg) subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg); } -/* ============================================================================= - * Creation / evaluation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Creation / evaluation + * \{ */ SubdivCCG *BKE_subdiv_to_ccg(Subdiv *subdiv, const SubdivToCCGSettings *settings, @@ -670,9 +678,11 @@ void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg) BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level); } -/* ============================================================================= - * Normals. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Normals + * \{ */ typedef struct RecalcInnerNormalsData { SubdivCCG *subdiv_ccg; @@ -770,8 +780,8 @@ static void subdiv_ccg_recalc_inner_normal_task(void *__restrict userdata_v, subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index); } -static void subdiv_ccg_recalc_inner_normal_finalize(void *__restrict UNUSED(userdata), - void *__restrict tls_v) +static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict UNUSED(userdata), + void *__restrict tls_v) { RecalcInnerNormalsTLSData *tls = tls_v; MEM_SAFE_FREE(tls->face_normals); @@ -791,7 +801,7 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg) BLI_parallel_range_settings_defaults(¶llel_range_settings); parallel_range_settings.userdata_chunk = &tls_data; parallel_range_settings.userdata_chunk_size = sizeof(tls_data); - parallel_range_settings.func_finalize = subdiv_ccg_recalc_inner_normal_finalize; + parallel_range_settings.func_free = subdiv_ccg_recalc_inner_normal_free; BLI_task_parallel_range(0, subdiv_ccg->num_grids, &data, @@ -834,8 +844,8 @@ static void subdiv_ccg_recalc_modified_inner_normal_task(void *__restrict userda subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face); } -static void subdiv_ccg_recalc_modified_inner_normal_finalize(void *__restrict UNUSED(userdata), - void *__restrict tls_v) +static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict UNUSED(userdata), + void *__restrict tls_v) { RecalcInnerNormalsTLSData *tls = tls_v; MEM_SAFE_FREE(tls->face_normals); @@ -857,7 +867,7 @@ static void subdiv_ccg_recalc_modified_inner_grid_normals(SubdivCCG *subdiv_ccg, BLI_parallel_range_settings_defaults(¶llel_range_settings); parallel_range_settings.userdata_chunk = &tls_data; parallel_range_settings.userdata_chunk_size = sizeof(tls_data); - parallel_range_settings.func_finalize = subdiv_ccg_recalc_modified_inner_normal_finalize; + parallel_range_settings.func_free = subdiv_ccg_recalc_modified_inner_normal_free; BLI_task_parallel_range(0, num_effected_faces, &data, @@ -885,9 +895,11 @@ void BKE_subdiv_ccg_update_normals(SubdivCCG *subdiv_ccg, subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key); } -/* ============================================================================= - * Boundary averaging/stitching. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Boundary averaging/stitching + * \{ */ typedef struct AverageInnerGridsData { SubdivCCG *subdiv_ccg; @@ -1077,8 +1089,8 @@ static void subdiv_ccg_average_grids_boundaries_task(void *__restrict userdata_v subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls); } -static void subdiv_ccg_average_grids_boundaries_finalize(void *__restrict UNUSED(userdata), - void *__restrict tls_v) +static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict UNUSED(userdata), + void *__restrict tls_v) { AverageGridsBoundariesTLSData *tls = tls_v; MEM_SAFE_FREE(tls->accumulators); @@ -1136,7 +1148,7 @@ static void subdiv_ccg_average_all_boundaries(SubdivCCG *subdiv_ccg, CCGKey *key AverageGridsBoundariesTLSData tls_data = {NULL}; parallel_range_settings.userdata_chunk = &tls_data; parallel_range_settings.userdata_chunk_size = sizeof(tls_data); - parallel_range_settings.func_finalize = subdiv_ccg_average_grids_boundaries_finalize; + parallel_range_settings.func_free = subdiv_ccg_average_grids_boundaries_free; BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_edges, &boundaries_data, @@ -1244,9 +1256,11 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, *r_num_loops = *r_num_faces * 4; } -/* ============================================================================= - * Neighbors. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Neighbors + * \{ */ void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord) { @@ -1791,3 +1805,5 @@ int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int gri const int face_index = face - subdiv_ccg->faces; return face_index; } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c index db0a51c390b..f03cf4c4d21 100644 --- a/source/blender/blenkernel/intern/subdiv_deform.c +++ b/source/blender/blenkernel/intern/subdiv_deform.c @@ -39,9 +39,9 @@ #include "MEM_guardedalloc.h" -/* ================================================================================================ - * Subdivision context. - */ +/* -------------------------------------------------------------------- */ +/** \name Subdivision context + * \{ */ typedef struct SubdivDeformContext { const Mesh *coarse_mesh; @@ -77,9 +77,11 @@ static void subdiv_mesh_context_free(SubdivDeformContext *ctx) MEM_SAFE_FREE(ctx->accumulated_counters); } -/* ================================================================================================ - * Accumulation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Accumulation helpers + * \{ */ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx, const int ptex_face_index, @@ -105,9 +107,11 @@ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx, ++ctx->accumulated_counters[vertex_index]; } -/* ================================================================================================ - * Subdivision callbacks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Subdivision callbacks + * \{ */ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context, const int UNUSED(num_vertices), @@ -165,9 +169,11 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex add_v3_v3(vertex_co, D); } -/* ================================================================================================ - * Initialization. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Initialization + * \{ */ static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, SubdivForeachContext *foreach_context) @@ -182,9 +188,11 @@ static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, foreach_context->vertex_corner = subdiv_mesh_vertex_corner; } -/* ================================================================================================ - * Public entry point. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public entry point + * \{ */ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, const struct Mesh *coarse_mesh, @@ -234,3 +242,5 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, /* Free used memory. */ subdiv_mesh_context_free(&subdiv_context); } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c index b31fb2c9312..ff7f6fad5f0 100644 --- a/source/blender/blenkernel/intern/subdiv_foreach.c +++ b/source/blender/blenkernel/intern/subdiv_foreach.c @@ -40,9 +40,9 @@ #include "MEM_guardedalloc.h" -/* ============================================================================= - * General helpers. - */ +/* -------------------------------------------------------------------- */ +/** \name General helpers + * \{ */ /* Number of ptex faces for a given polygon. */ BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly) @@ -75,9 +75,11 @@ BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution) return (poly->totloop == 4) ? (resolution) : ((resolution >> 1) + 1); } -/* ============================================================================= - * Context which is passed to all threaded tasks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Context which is passed to all threaded tasks + * \{ */ typedef struct SubdivForeachTaskContext { const Mesh *coarse_mesh; @@ -122,9 +124,11 @@ typedef struct SubdivForeachTaskContext { BLI_bitmap *coarse_edges_used_map; } SubdivForeachTaskContext; -/* ============================================================================= - * Threading helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Threading helpers + * \{ */ static void *subdiv_foreach_tls_alloc(SubdivForeachTaskContext *ctx) { @@ -148,9 +152,11 @@ static void subdiv_foreach_tls_free(SubdivForeachTaskContext *ctx, void *tls) MEM_freeN(tls); } -/* ============================================================================= - * Initialization. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Initialization + * \{ */ /* NOTE: Expects edge map to be zeroed. */ static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx) @@ -294,9 +300,11 @@ static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx) MEM_freeN(ctx->subdiv_polygon_offset); } -/* ============================================================================= - * Vertex traversal process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex traversal process + * \{ */ /* Traversal of corner vertices. They are coming from coarse vertices. */ @@ -706,9 +714,11 @@ static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx, void *tls, co } } -/* ============================================================================= - * Edge traversal process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edge traversal process + * \{ */ /* TODO(sergey): Coarse edge are always NONE, consider getting rid of it. */ static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx, @@ -1022,9 +1032,11 @@ static void subdiv_foreach_boundary_edges(SubdivForeachTaskContext *ctx, ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2); } -/* ============================================================================= - * Loops traversal. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loops traversal + * \{ */ static void rotate_indices(const int rot, int *a, int *b, int *c, int *d) { @@ -1666,9 +1678,11 @@ static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx, void *tls, int p } } -/* ============================================================================= - * Polygons traverse process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Polygons traverse process + * \{ */ static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int poly_index) { @@ -1697,9 +1711,11 @@ static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int p } } -/* ============================================================================= - * Loose elements traverse process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loose elements traverse process + * \{ */ static void subdiv_foreach_loose_vertices_task(void *__restrict userdata, const int coarse_vertex_index, @@ -1754,9 +1770,11 @@ static void subdiv_foreach_vertices_of_loose_edges_task(void *__restrict userdat } } -/* ============================================================================= - * Subdivision process entry points. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Subdivision process entry points + * \{ */ static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ctx, void *tls) { @@ -1838,9 +1856,9 @@ static void subdiv_foreach_boundary_edges_task(void *__restrict userdata, subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index); } -static void subdiv_foreach_finalize(void *__restrict userdata, void *__restrict userdata_chunk) +static void subdiv_foreach_free(const void *__restrict userdata, void *__restrict userdata_chunk) { - SubdivForeachTaskContext *ctx = userdata; + const SubdivForeachTaskContext *ctx = userdata; ctx->foreach_context->user_data_tls_free(userdata_chunk); } @@ -1873,7 +1891,7 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv, parallel_range_settings.userdata_chunk_size = context->user_data_tls_size; parallel_range_settings.min_iter_per_thread = 1; if (context->user_data_tls_free != NULL) { - parallel_range_settings.func_finalize = subdiv_foreach_finalize; + parallel_range_settings.func_free = subdiv_foreach_free; } /* TODO(sergey): Possible optimization is to have a single pool and push all @@ -1908,3 +1926,5 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv, subdiv_foreach_ctx_free(&ctx); return true; } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index bd091108b11..987cc0311c7 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -41,9 +41,9 @@ #include "MEM_guardedalloc.h" -/* ============================================================================= - * Subdivision context. - */ +/* -------------------------------------------------------------------- */ +/** \name Subdivision Context + * \{ */ typedef struct SubdivMeshContext { const SubdivToMeshSettings *settings; @@ -119,9 +119,11 @@ static void subdiv_mesh_context_free(SubdivMeshContext *ctx) MEM_SAFE_FREE(ctx->accumulated_counters); } -/* ============================================================================= - * Loop custom data copy helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop custom data copy helpers + * \{ */ typedef struct LoopsOfPtex { /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */ @@ -159,9 +161,11 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx, } } -/* ============================================================================= - * Vertex custom data interpolation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex custom data interpolation helpers + * \{ */ /* TODO(sergey): Somehow de-duplicate with loops storage, without too much * exception cases all over the code. */ @@ -295,9 +299,11 @@ static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolat } } -/* ============================================================================= - * Loop custom data interpolation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop custom data interpolation helpers + * \{ */ typedef struct LoopsForInterpolation { /* This field points to a loop data which is to be used for interpolation. @@ -413,9 +419,11 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) } } -/* ============================================================================= - * TLS. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name TLS + * \{ */ typedef struct SubdivMeshTLS { bool vertex_interpolation_initialized; @@ -440,9 +448,11 @@ static void subdiv_mesh_tls_free(void *tls_v) } } -/* ============================================================================= - * Evaluation helper functions. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Evaluation helper functions + * \{ */ static void eval_final_point_and_vertex_normal(Subdiv *subdiv, const int ptex_face_index, @@ -459,9 +469,11 @@ static void eval_final_point_and_vertex_normal(Subdiv *subdiv, } } -/* ============================================================================= - * Accumulation helpers. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Accumulation helpers + * \{ */ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx, const int ptex_face_index, @@ -490,9 +502,11 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext * ++ctx->accumulated_counters[subdiv_vertex_index]; } -/* ============================================================================= - * Callbacks. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks + * \{ */ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context, const int num_vertices, @@ -513,9 +527,11 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex return true; } -/* ============================================================================= - * Vertex subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex subdivision process + * \{ */ static void subdiv_vertex_data_copy(const SubdivMeshContext *ctx, const MVert *coarse_vertex, @@ -778,9 +794,11 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v); } -/* ============================================================================= - * Edge subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edge subdivision process + * \{ */ static void subdiv_copy_edge_data(SubdivMeshContext *ctx, MEdge *subdiv_edge, @@ -827,9 +845,11 @@ static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context, subdiv_edge->v2 = subdiv_v2; } -/* ============================================================================= - * Loops creation/interpolation. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loops creation/interpolation + * \{ */ static void subdiv_interpolate_loop_data(const SubdivMeshContext *ctx, MLoop *subdiv_loop, @@ -921,9 +941,11 @@ static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context, subdiv_loop->e = subdiv_edge_index; } -/* ============================================================================= - * Polygons subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Polygons subdivision process + * \{ */ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, MPoly *subdiv_poly, @@ -955,9 +977,11 @@ static void subdiv_mesh_poly(const SubdivForeachContext *foreach_context, subdiv_poly->totloop = num_loops; } -/* ============================================================================= - * Loose elements subdivision process. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loose elements subdivision process + * \{ */ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context, void *UNUSED(tls), @@ -1127,9 +1151,11 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext * normal_float_to_short_v3(subdiv_vertex->no, no); } -/* ============================================================================= - * Initialization. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Initialization + * \{ */ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context, SubdivForeachContext *foreach_context) @@ -1157,9 +1183,11 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context, foreach_context->user_data_tls_free = subdiv_mesh_tls_free; } -/* ============================================================================= - * Public entry point. - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public entry point + * \{ */ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, const SubdivToMeshSettings *settings, @@ -1206,3 +1234,5 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, subdiv_mesh_context_free(&subdiv_context); return result; } + +/** \} */ diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index c21d640a4c1..7a0a5645b80 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -71,18 +71,13 @@ #include "CCGSubSurf.h" -#ifdef WITH_OPENSUBDIV -# include "opensubdiv_capi.h" -#endif - /* assumes MLoop's are laid out 4 for each poly, in order */ #define USE_LOOP_LAYOUT_FAST static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, - DerivedMesh *dm, - bool use_gpu_backend); + DerivedMesh *dm); /// static void *arena_alloc(CCGAllocatorHDL a, int numBytes) @@ -404,82 +399,6 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, return 1; } -#ifdef WITH_OPENSUBDIV -static void UNUSED_FUNCTION(set_subsurf_osd_ccg_uv)(CCGSubSurf *ss, - DerivedMesh *dm, - DerivedMesh *result, - int layer_index) -{ - CCGFace **faceMap; - MTFace *tf; - MLoopUV *mluv; - CCGFaceIterator fi; - int index, gridSize, gridFaces, totface, x, y, S; - MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index); - /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with - * just tface except applying the modifier then looses subsurf UV */ - MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index); - MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index); - - if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) { - return; - } - - ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index); - - /* get some info from CCGSubSurf */ - totface = ccgSubSurf_getNumFaces(ss); - gridSize = ccgSubSurf_getGridSize(ss); - gridFaces = gridSize - 1; - - /* make a map from original faces to CCGFaces */ - faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv"); - for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); - ccgFaceIterator_next(&fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(&fi); - faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f; - } - - /* load coordinates from uvss into tface */ - tf = tface; - mluv = mloopuv; - for (index = 0; index < totface; index++) { - CCGFace *f = faceMap[index]; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - const int delta[4][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; - float uv[4][2]; - int i; - for (i = 0; i < 4; i++) { - const int dx = delta[i][0], dy = delta[i][1]; - const float grid_u = ((float)(x + dx)) / (gridSize - 1), - grid_v = ((float)(y + dy)) / (gridSize - 1); - ccgSubSurf_evaluatorFVarUV(ss, index, S, grid_u, grid_v, uv[i]); - } - if (tf) { - copy_v2_v2(tf->uv[0], uv[0]); - copy_v2_v2(tf->uv[1], uv[1]); - copy_v2_v2(tf->uv[2], uv[2]); - copy_v2_v2(tf->uv[3], uv[3]); - tf++; - } - if (mluv) { - copy_v2_v2(mluv[0].uv, uv[0]); - copy_v2_v2(mluv[1].uv, uv[1]); - copy_v2_v2(mluv[2].uv, uv[2]); - copy_v2_v2(mluv[3].uv, uv[3]); - mluv += 4; - } - } - } - } - } - MEM_freeN(faceMap); -} -#endif /* WITH_OPENSUBDIV */ - static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n) { CCGSubSurf *uvss; @@ -564,16 +483,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh * static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int layer_index) { -#ifdef WITH_OPENSUBDIV - if (!ccgSubSurf_needGrids(ss)) { - /* GPU backend is used, no need to evaluate UVs on CPU. */ - /* TODO(sergey): Think of how to support edit mode of UVs. */ - } - else -#endif - { - set_subsurf_legacy_uv(ss, dm, result, layer_index); - } + set_subsurf_legacy_uv(ss, dm, result, layer_index); } /* face weighting */ @@ -763,40 +673,13 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss, #endif } -#ifdef WITH_OPENSUBDIV -static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm) -{ - ccgSubSurf_initFullSync(ss); - ccgSubSurf_prepareTopologyRefiner(ss, dm); - ccgSubSurf_processSync(ss); -} -#endif /* WITH_OPENSUBDIV */ - static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, float (*vertexCos)[3], int use_flat_subdiv, - bool use_subdiv_uvs) + bool UNUSED(use_subdiv_uvs)) { -#ifndef WITH_OPENSUBDIV - UNUSED_VARS(use_subdiv_uvs); -#endif - -#ifdef WITH_OPENSUBDIV - /* Reset all related descriptors if actual mesh topology changed or if - * other evaluation-related settings changed. - */ - if (!ccgSubSurf_needGrids(ss)) { - /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */ - ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs); - ccgSubSurf_checkTopologyChanged(ss, dm); - ss_sync_osd_from_derivedmesh(ss, dm); - } - else -#endif - { - ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv); - } + ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv); } /***/ @@ -850,13 +733,6 @@ static void UNUSED_FUNCTION(ccgDM_getMinMax)(DerivedMesh *dm, float r_min[3], fl int i, edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - ccgSubSurf_getMinMax(ccgdm->ss, r_min, r_max); - return; - } -#endif - CCG_key_top_level(&key, ss); if (!ccgSubSurf_getNumVerts(ss)) { @@ -1642,11 +1518,9 @@ static void ccgDM_release(DerivedMesh *dm) } MEM_freeN(ccgdm->edgeFlags); MEM_freeN(ccgdm->faceFlags); - if (ccgdm->useGpuBackend == false) { - MEM_freeN(ccgdm->vertMap); - MEM_freeN(ccgdm->edgeMap); - MEM_freeN(ccgdm->faceMap); - } + MEM_freeN(ccgdm->vertMap); + MEM_freeN(ccgdm->edgeMap); + MEM_freeN(ccgdm->faceMap); BLI_mutex_end(&ccgdm->loops_cache_lock); BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock); @@ -2417,76 +2291,44 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss)); } -/* Fill in only geometry arrays needed for the GPU tessellation. */ -static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm, DerivedMesh *dm) -{ - const int totface = dm->getNumPolys(dm); - MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); - int index; - DMFlagMat *faceFlags = ccgdm->faceFlags; - - for (index = 0; index < totface; index++) { - faceFlags->flag = mpoly ? mpoly[index].flag : 0; - faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0; - faceFlags++; - } - - /* TODO(sergey): Fill in edge flags. */ -} - -static CCGDerivedMesh *getCCGDerivedMesh( - CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, DerivedMesh *dm, bool use_gpu_backend) +static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, + int drawInteriorEdges, + int useSubsurfUv, + DerivedMesh *dm) { -#ifdef WITH_OPENSUBDIV - const int totedge = dm->getNumEdges(dm); - const int totface = dm->getNumPolys(dm); -#else const int totedge = ccgSubSurf_getNumEdges(ss); const int totface = ccgSubSurf_getNumFaces(ss); -#endif CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); - if (use_gpu_backend == false) { - BLI_assert(totedge == ccgSubSurf_getNumEdges(ss)); - BLI_assert(totface == ccgSubSurf_getNumFaces(ss)); - DM_from_template(&ccgdm->dm, - dm, - DM_TYPE_CCGDM, - ccgSubSurf_getNumFinalVerts(ss), - ccgSubSurf_getNumFinalEdges(ss), - 0, - ccgSubSurf_getNumFinalFaces(ss) * 4, - ccgSubSurf_getNumFinalFaces(ss)); + BLI_assert(totedge == ccgSubSurf_getNumEdges(ss)); + BLI_assert(totface == ccgSubSurf_getNumFaces(ss)); + DM_from_template(&ccgdm->dm, + dm, + DM_TYPE_CCGDM, + ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + 0, + ccgSubSurf_getNumFinalFaces(ss) * 4, + ccgSubSurf_getNumFinalFaces(ss)); - CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData); + CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData); - ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), - "reverseFaceMap"); + ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), + "reverseFaceMap"); - create_ccgdm_maps(ccgdm, ss); - } - else { - DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, 0, 0, 0, 0, dm->getNumPolys(dm)); - CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, 0, 0, dm->getNumPolys(dm)); - } + create_ccgdm_maps(ccgdm, ss); set_default_ccgdm_callbacks(ccgdm); ccgdm->ss = ss; ccgdm->drawInteriorEdges = drawInteriorEdges; ccgdm->useSubsurfUv = useSubsurfUv; - ccgdm->useGpuBackend = use_gpu_backend; /* CDDM hack. */ ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags"); ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags"); - if (use_gpu_backend == false) { - set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0); - } - else { - set_ccgdm_gpu_geometry(ccgdm, dm); - } + set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0); ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss); ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss); @@ -2502,21 +2344,6 @@ static CCGDerivedMesh *getCCGDerivedMesh( /***/ -static bool subsurf_use_gpu_backend(SubsurfFlags flags) -{ -#ifdef WITH_OPENSUBDIV - /* Use GPU backend if it's a last modifier in the stack - * and user chose to use any of the OSD compute devices, - * but also check if GPU has all needed features. - */ - return (flags & SUBSURF_USE_GPU_BACKEND) != 0 && - (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE); -#else - (void)flags; - return false; -#endif -} - struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, struct SubsurfModifierData *smd, const struct Scene *scene, @@ -2527,7 +2354,6 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0; const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE); const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); - const bool use_gpu_backend = subsurf_use_gpu_backend(flags); const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY); CCGDerivedMesh *result; @@ -2546,11 +2372,8 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS); -#ifdef WITH_OPENSUBDIV - ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend); -#endif ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); + result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm); } else if (flags & SUBSURF_USE_RENDER_PARAMS) { /* Do not use cache in render mode. */ @@ -2567,7 +2390,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, false); + result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); result->freeSS = 1; } @@ -2600,32 +2423,15 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm, false); + result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm); } else { CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS; CCGSubSurf *prevSS = NULL; if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) { -#ifdef WITH_OPENSUBDIV - /* With OpenSubdiv enabled we always tries to re-use previous - * subsurf structure in order to save computation time since - * re-creation is rather a complicated business. - * - * TODO(sergey): There was a good reason why final calculation - * used to free entirely cached subsurf structure. reason of - * this is to be investigated still to be sure we don't have - * regressions here. - */ - if (use_gpu_backend) { - prevSS = smd->mCache; - } - else -#endif - { - ccgSubSurf_free(smd->mCache); - smd->mCache = NULL; - } + ccgSubSurf_free(smd->mCache); + smd->mCache = NULL; } if (flags & SUBSURF_ALLOC_PAINT_MASK) { @@ -2633,12 +2439,9 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm, } ss = _getSubSurf(prevSS, levels, 3, ccg_flags); -#ifdef WITH_OPENSUBDIV - ccgSubSurf_setSkipGrids(ss, use_gpu_backend); -#endif ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); + result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); if (flags & SUBSURF_IS_FINAL_CALC) { smd->mCache = ss; @@ -2710,26 +2513,10 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3]) bool subsurf_has_edges(DerivedMesh *dm) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - return true; - } -#else - (void)ccgdm; -#endif return dm->getNumEdges(dm) != 0; } bool subsurf_has_faces(DerivedMesh *dm) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - return true; - } -#else - (void)ccgdm; -#endif return dm->getNumPolys(dm) != 0; } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 3cdf3b40ce3..527b54a1aa2 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -206,6 +206,7 @@ IDTypeInfo IDType_ID_TXT = { .copy_data = text_copy_data, .free_data = text_free_data, .make_local = NULL, + .foreach_id = NULL, }; /***/ diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index fe10861f96e..e2c3c20e36e 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -57,6 +57,7 @@ #include "BKE_image.h" #include "BKE_key.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_material.h" #include "BKE_node.h" #include "BKE_scene.h" @@ -112,7 +113,7 @@ static void texture_free_data(ID *id) /* is no lib link block, but texture extension */ if (texture->nodetree) { - ntreeFreeNestedTree(texture->nodetree); + ntreeFreeEmbeddedTree(texture->nodetree); MEM_freeN(texture->nodetree); texture->nodetree = NULL; } @@ -123,6 +124,16 @@ static void texture_free_data(ID *id) BKE_previewimg_free(&texture->preview); } +static void texture_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Tex *texture = (Tex *)id; + if (texture->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree); + } + BKE_LIB_FOREACHID_PROCESS(data, texture->ima, IDWALK_CB_USER); +} + IDTypeInfo IDType_ID_TE = { .id_code = ID_TE, .id_filter = FILTER_ID_TE, @@ -137,8 +148,16 @@ IDTypeInfo IDType_ID_TE = { .copy_data = texture_copy_data, .free_data = texture_free_data, .make_local = NULL, + .foreach_id = texture_foreach_id, }; +/* Utils for all IDs using those texture slots. */ +void BKE_texture_mtex_foreach_id(LibraryForeachIDData *data, MTex *mtex) +{ + BKE_LIB_FOREACHID_PROCESS(data, mtex->object, IDWALK_CB_NOP); + BKE_LIB_FOREACHID_PROCESS(data, mtex->tex, IDWALK_CB_USER); +} + /* ****************** Mapping ******************* */ TexMapping *BKE_texture_mapping_add(int type) diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 0204667b3bd..97d95cb7e46 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -2288,13 +2288,15 @@ void BKE_tracking_distortion_free(MovieDistortion *distortion) MEM_freeN(distortion); } -void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r_co[2]) +void BKE_tracking_distort_v2( + MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2]) { const MovieTrackingCamera *camera = &tracking->camera; const float aspy = 1.0f / tracking->camera.pixel_aspect; libmv_CameraIntrinsicsOptions camera_intrinsics_options; - tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options); + tracking_cameraIntrinscisOptionsFromTracking( + tracking, image_width, image_height, &camera_intrinsics_options); libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options); /* Normalize coordinates. */ @@ -2309,13 +2311,15 @@ void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r r_co[1] = y; } -void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float r_co[2]) +void BKE_tracking_undistort_v2( + MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2]) { const MovieTrackingCamera *camera = &tracking->camera; const float aspy = 1.0f / tracking->camera.pixel_aspect; libmv_CameraIntrinsicsOptions camera_intrinsics_options; - tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options); + tracking_cameraIntrinscisOptionsFromTracking( + tracking, image_width, image_height, &camera_intrinsics_options); libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options); double x = co[0], y = co[1]; @@ -2361,13 +2365,19 @@ ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking, } void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking, + int image_width, + int image_height, rcti *rect, bool undistort, float delta[2]) { float pos[2], warped_pos[2]; const int coord_delta = 5; - void (*apply_distortion)(MovieTracking * tracking, const float pos[2], float out[2]); + void (*apply_distortion)(MovieTracking * tracking, + int image_width, + int image_height, + const float pos[2], + float out[2]); if (undistort) { apply_distortion = BKE_tracking_undistort_v2; @@ -2387,7 +2397,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking, pos[0] = a; pos[1] = rect->ymin; - apply_distortion(tracking, pos, warped_pos); + apply_distortion(tracking, image_width, image_height, pos, warped_pos); delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); @@ -2396,7 +2406,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking, pos[0] = a; pos[1] = rect->ymax; - apply_distortion(tracking, pos, warped_pos); + apply_distortion(tracking, image_width, image_height, pos, warped_pos); delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); @@ -2415,7 +2425,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking, pos[0] = rect->xmin; pos[1] = a; - apply_distortion(tracking, pos, warped_pos); + apply_distortion(tracking, image_width, image_height, pos, warped_pos); delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); @@ -2424,7 +2434,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking, pos[0] = rect->xmax; pos[1] = a; - apply_distortion(tracking, pos, warped_pos); + apply_distortion(tracking, image_width, image_height, pos, warped_pos); delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 5f7452e4775..dcaa9082026 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -451,6 +451,12 @@ static void distortion_model_parameters_from_tracking( camera_intrinsics_options->division_k1 = camera->division_k1; camera_intrinsics_options->division_k2 = camera->division_k2; return; + + case TRACKING_DISTORTION_MODEL_NUKE: + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE; + camera_intrinsics_options->nuke_k1 = camera->nuke_k1; + camera_intrinsics_options->nuke_k2 = camera->nuke_k2; + return; } /* Unknown distortion model, which might be due to opening newer file in older Blender. @@ -479,6 +485,12 @@ static void distortion_model_parameters_from_options( camera->division_k1 = camera_intrinsics_options->division_k1; camera->division_k2 = camera_intrinsics_options->division_k2; return; + + case LIBMV_DISTORTION_MODEL_NUKE: + camera->distortion_model = TRACKING_DISTORTION_MODEL_NUKE; + camera->nuke_k1 = camera_intrinsics_options->nuke_k1; + camera->nuke_k2 = camera_intrinsics_options->nuke_k2; + return; } /* Libmv returned distortion model which is not known to Blender. This is a logical error in code @@ -701,7 +713,7 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf) */ const size_t size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float); grayscale->channels = 1; - if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) { + if ((grayscale->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) { grayscale->mall |= IB_rectfloat; grayscale->flags |= IB_rectfloat; @@ -729,7 +741,7 @@ static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image) ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0); size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float); ibuf->channels = float_image->channels; - if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) { + if ((ibuf->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) { ibuf->mall |= IB_rectfloat; ibuf->flags |= IB_rectfloat; diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index b0b7a60b556..26c5810aefa 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -21,6 +21,7 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_volume_types.h" @@ -442,26 +443,6 @@ static void volume_init_data(ID *id) BKE_volume_init_grids(volume); } -void BKE_volume_init_grids(Volume *volume) -{ -#ifdef WITH_OPENVDB - if (volume->runtime.grids == NULL) { - volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector); - } -#else - UNUSED_VARS(volume); -#endif -} - -void *BKE_volume_add(Main *bmain, const char *name) -{ - Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0); - - volume_init_data(&volume->id); - - return volume; -} - static void volume_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, @@ -483,18 +464,6 @@ static void volume_copy_data(Main *UNUSED(bmain), #endif } -Volume *BKE_volume_copy(Main *bmain, const Volume *volume) -{ - Volume *volume_copy; - BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy); - return volume_copy; -} - -static void volume_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - static void volume_free_data(ID *id) { Volume *volume = (Volume *)id; @@ -506,6 +475,14 @@ static void volume_free_data(ID *id) #endif } +static void volume_foreach_id(ID *id, LibraryForeachIDData *data) +{ + Volume *volume = (Volume *)id; + for (int i = 0; i < volume->totcol; i++) { + BKE_LIB_FOREACHID_PROCESS(data, volume->mat[i], IDWALK_CB_USER); + } +} + IDTypeInfo IDType_ID_VO = { /* id_code */ ID_VO, /* id_filter */ FILTER_ID_VO, @@ -519,9 +496,37 @@ IDTypeInfo IDType_ID_VO = { /* init_data */ volume_init_data, /* copy_data */ volume_copy_data, /* free_data */ volume_free_data, - /* make_local */ volume_make_local, + /* make_local */ nullptr, + /* foreach_id */ volume_foreach_id, }; +void BKE_volume_init_grids(Volume *volume) +{ +#ifdef WITH_OPENVDB + if (volume->runtime.grids == NULL) { + volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector); + } +#else + UNUSED_VARS(volume); +#endif +} + +void *BKE_volume_add(Main *bmain, const char *name) +{ + Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0); + + volume_init_data(&volume->id); + + return volume; +} + +Volume *BKE_volume_copy(Main *bmain, const Volume *volume) +{ + Volume *volume_copy; + BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy); + return volume_copy; +} + /* Sequence */ static int volume_sequence_frame(const Depsgraph *depsgraph, const Volume *volume) @@ -795,12 +800,52 @@ bool BKE_volume_is_points_only(const Volume *volume) /* Dependency Graph */ -static Volume *volume_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph), - struct Scene *UNUSED(scene), - Object *UNUSED(object), +static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph, + struct Scene *scene, + Object *object, Volume *volume_input) { - return volume_input; + Volume *volume = volume_input; + + /* Modifier evaluation modes. */ + const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE; + const ModifierEvalContext mectx = {depsgraph, object, apply_flag}; + + /* Get effective list of modifiers to execute. Some effects like shape keys + * are added as virtual modifiers before the user created modifiers. */ + VirtualModifierData virtualModifierData; + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData); + + /* Evaluate modifiers. */ + for (; md; md = md->next) { + const ModifierTypeInfo *mti = (const ModifierTypeInfo *)BKE_modifier_get_info( + (ModifierType)md->type); + + if (!BKE_modifier_is_enabled(scene, md, required_mode)) { + continue; + } + + if (mti->modifyVolume) { + /* Ensure we are not modifying the input. */ + if (volume == volume_input) { + volume = BKE_volume_copy_for_eval(volume, true); + } + + Volume *volume_next = mti->modifyVolume(md, &mectx, volume); + + if (volume_next && volume_next != volume) { + /* If the modifier returned a new volume, release the old one. */ + if (volume != volume_input) { + BKE_id_free(NULL, volume); + } + volume = volume_next; + } + } + } + + return volume; } void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume) diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index c65d55785c1..3a69b95c114 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -32,6 +32,7 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -65,6 +66,23 @@ static void workspace_free_data(ID *id) MEM_SAFE_FREE(workspace->status_text); } +static void workspace_foreach_id(ID *id, LibraryForeachIDData *data) +{ + WorkSpace *workspace = (WorkSpace *)id; + ListBase *layouts = BKE_workspace_layouts_get(workspace); + + LISTBASE_FOREACH (WorkSpaceLayout *, layout, layouts) { + bScreen *screen = BKE_workspace_layout_screen_get(layout); + + /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer. + * However we can't access layout->screen here + * since we are outside the workspace project. */ + BKE_LIB_FOREACHID_PROCESS(data, screen, IDWALK_CB_USER); + /* allow callback to set a different screen */ + BKE_workspace_layout_screen_set(layout, screen); + } +} + IDTypeInfo IDType_ID_WS = { .id_code = ID_WS, .id_filter = FILTER_ID_WS, @@ -79,6 +97,7 @@ IDTypeInfo IDType_ID_WS = { .copy_data = NULL, .free_data = workspace_free_data, .make_local = NULL, + .foreach_id = workspace_foreach_id, }; /** \name Internal Utils diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index f2219ad1cf8..e3b58e03d93 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -38,6 +38,7 @@ #include "BKE_icons.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_world.h" @@ -59,7 +60,7 @@ static void world_free_data(ID *id) /* is no lib link block, but world extension */ if (wrld->nodetree) { - ntreeFreeNestedTree(wrld->nodetree); + ntreeFreeEmbeddedTree(wrld->nodetree); MEM_freeN(wrld->nodetree); wrld->nodetree = NULL; } @@ -78,17 +79,6 @@ static void world_init_data(ID *id) MEMCPY_STRUCT_AFTER(wrld, DNA_struct_default_get(World), id); } -World *BKE_world_add(Main *bmain, const char *name) -{ - World *wrld; - - wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0); - - world_init_data(&wrld->id); - - return wrld; -} - /** * Only copy internal data of World ID from source * to already allocated/initialized destination. @@ -122,6 +112,44 @@ static void world_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int } } +static void world_foreach_id(ID *id, LibraryForeachIDData *data) +{ + World *world = (World *)id; + + if (world->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree); + } +} + +IDTypeInfo IDType_ID_WO = { + .id_code = ID_WO, + .id_filter = FILTER_ID_WO, + .main_listbase_index = INDEX_ID_WO, + .struct_size = sizeof(World), + .name = "World", + .name_plural = "worlds", + .translation_context = BLT_I18NCONTEXT_ID_WORLD, + .flags = 0, + + .init_data = world_init_data, + .copy_data = world_copy_data, + .free_data = world_free_data, + .make_local = NULL, + .foreach_id = world_foreach_id, +}; + +World *BKE_world_add(Main *bmain, const char *name) +{ + World *wrld; + + wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0); + + world_init_data(&wrld->id); + + return wrld; +} + World *BKE_world_copy(Main *bmain, const World *wrld) { World *wrld_copy; @@ -159,27 +187,6 @@ World *BKE_world_localize(World *wrld) return wrldn; } -static void world_make_local(Main *bmain, ID *id, const int flags) -{ - BKE_lib_id_make_local_generic(bmain, id, flags); -} - -IDTypeInfo IDType_ID_WO = { - .id_code = ID_WO, - .id_filter = FILTER_ID_WO, - .main_listbase_index = INDEX_ID_WO, - .struct_size = sizeof(World), - .name = "World", - .name_plural = "worlds", - .translation_context = BLT_I18NCONTEXT_ID_WORLD, - .flags = 0, - - .init_data = world_init_data, - .copy_data = world_copy_data, - .free_data = world_free_data, - .make_local = world_make_local, -}; - void BKE_world_eval(struct Depsgraph *depsgraph, World *world) { DEG_debug_print_eval(depsgraph, __func__, world->id.name, world); |