diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
70 files changed, 5908 insertions, 7422 deletions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 792e9195f12..68bcfa878ac 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -42,7 +42,7 @@ # include "opensubdiv_converter_capi.h" #endif -#include "GL/glew.h" +#include "GPU_glew.h" /***/ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index 65cf899b42b..9c86a22a1f8 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -43,7 +43,7 @@ #include "opensubdiv_capi.h" #include "opensubdiv_converter_capi.h" -#include "GL/glew.h" +#include "GPU_glew.h" #include "GPU_extensions.h" #define OSD_LOG if (false) printf @@ -993,7 +993,7 @@ void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs) void BKE_subsurf_osd_init(void) { - openSubdiv_init(GPU_legacy_support()); + openSubdiv_init(); BLI_spin_init(&delete_spin); } diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index eba5814d897..874637896cd 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -54,11 +54,13 @@ #include "BKE_cdderivedmesh.h" #include "BKE_editmesh.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_tangent.h" #include "BKE_object.h" #include "BKE_object_deform.h" #include "BKE_paint.h" @@ -76,11 +78,12 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); #include "BLI_sys_types.h" /* for intptr_t support */ #include "GPU_buffers.h" -#include "GPU_glew.h" #include "GPU_shader.h" +#include "GPU_immediate.h" #ifdef WITH_OPENSUBDIV -# include "BKE_depsgraph.h" +# include "DEG_depsgraph.h" +# include "DEG_depsgraph_query.h" # include "DNA_userdef_types.h" #endif @@ -317,7 +320,7 @@ void DM_init( dm->numPolyData = numPolys; DM_init_funcs(dm); - + dm->needsFree = 1; dm->auto_bump_scale = -1.0f; dm->dirty = 0; @@ -377,6 +380,7 @@ int DM_release(DerivedMesh *dm) if (dm->needsFree) { bvhcache_free(&dm->bvhCache); GPU_drawobject_free(dm); + CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numTessFaceData); @@ -529,7 +533,6 @@ void DM_update_tessface_data(DerivedMesh *dm) MLoop *ml = dm->getLoopArray(dm); CustomData *fdata = dm->getTessFaceDataLayout(dm); - CustomData *pdata = dm->getPolyDataLayout(dm); CustomData *ldata = dm->getLoopDataLayout(dm); const int totface = dm->getNumTessFaces(dm); @@ -542,7 +545,7 @@ void DM_update_tessface_data(DerivedMesh *dm) if (!polyindex) return; - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + CustomData_from_bmeshpoly(fdata, ldata, totface); if (CustomData_has_layer(fdata, CD_MTFACE) || CustomData_has_layer(fdata, CD_MCOL) || @@ -574,7 +577,7 @@ void DM_update_tessface_data(DerivedMesh *dm) * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code). * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test. */ - BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface, polyindex, loopindex, totface); + BKE_mesh_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface); MEM_freeN(loopindex); } @@ -592,7 +595,6 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate) MLoop *ml = dm->getLoopArray(dm); CustomData *fdata = dm->getTessFaceDataLayout(dm); - CustomData *pdata = dm->getPolyDataLayout(dm); CustomData *ldata = dm->getLoopDataLayout(dm); const int totface = dm->getNumTessFaces(dm); @@ -609,7 +611,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate) for (int j = 0; j < ldata->totlayer; j++) { if (ldata->layers[j].type == CD_TANGENT) { CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name); - CustomData_bmesh_update_active_layers(fdata, pdata, ldata); + CustomData_bmesh_update_active_layers(fdata, ldata); if (!loopindex) { loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__); @@ -639,7 +641,7 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate) } if (loopindex) MEM_freeN(loopindex); - BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true)); + BLI_assert(CustomData_from_bmeshpoly_test(fdata, ldata, true)); } if (G.debug & G_DEBUG) @@ -2603,7 +2605,7 @@ static bool calc_modifiers_skip_orco(Scene *scene, else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) { return false; } - else if ((DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CPU) != 0) { + else if ((DEG_get_eval_flags_for_id(scene->depsgraph, &ob->id) & DAG_EVAL_NEED_CPU) != 0) { return false; } SubsurfModifierData *smd = (SubsurfModifierData *)last_md; @@ -2679,7 +2681,9 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *r_need_mapping) { - Object *actob = scene->basact ? scene->basact->object : NULL; + /* TODO(sergey): Avoid this linear list lookup. */ + SceneLayer *sl = BKE_scene_layer_context_active(scene); + Object *actob = sl->basact ? sl->basact->object : NULL; CustomDataMask mask = ob->customdata_mask; if (r_need_mapping) { @@ -3037,234 +3041,6 @@ void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int /* ******************* GLSL ******************** */ -/** \name Tangent Space Calculation - * \{ */ - -/* Necessary complexity to handle looptri's as quads for correct tangents */ -#define USE_LOOPTRI_DETECT_QUADS - -typedef struct { - float (*precomputedFaceNormals)[3]; - float (*precomputedLoopNormals)[3]; - const MLoopTri *looptri; - MLoopUV *mloopuv; /* texture coordinates */ - MPoly *mpoly; /* indices */ - MLoop *mloop; /* indices */ - MVert *mvert; /* vertices & normals */ - float (*orco)[3]; - float (*tangent)[4]; /* destination */ - int numTessFaces; - -#ifdef USE_LOOPTRI_DETECT_QUADS - /* map from 'fake' face index to looptri, - * quads will point to the first looptri of the quad */ - const int *face_as_quad_map; - int num_face_as_quad_map; -#endif - -} SGLSLMeshToTangent; - -/* interface */ -#include "mikktspace.h" - -static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) -{ - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - -#ifdef USE_LOOPTRI_DETECT_QUADS - return pMesh->num_face_as_quad_map; -#else - return pMesh->numTessFaces; -#endif -} - -static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) -{ -#ifdef USE_LOOPTRI_DETECT_QUADS - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - if (pMesh->face_as_quad_map) { - const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - return 4; - } - } - return 3; -#else - UNUSED_VARS(pContext, face_num); - return 3; -#endif -} - -static void dm_ts_GetPosition( - const SMikkTSpaceContext *pContext, float r_co[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - const float *co; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - -finally: - co = pMesh->mvert[pMesh->mloop[loop_index].v].co; - copy_v3_v3(r_co, co); -} - -static void dm_ts_GetTextureCoordinate( - const SMikkTSpaceContext *pContext, float r_uv[2], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - -finally: - if (pMesh->mloopuv != NULL) { - const float *uv = pMesh->mloopuv[loop_index].uv; - copy_v2_v2(r_uv, uv); - } - else { - const float *orco = pMesh->orco[pMesh->mloop[loop_index].v]; - map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); - } -} - -static void dm_ts_GetNormal( - const SMikkTSpaceContext *pContext, float r_no[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - -finally: - if (pMesh->precomputedLoopNormals) { - copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]); - } - else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */ - if (pMesh->precomputedFaceNormals) { - copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]); - } - else { -#ifdef USE_LOOPTRI_DETECT_QUADS - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - normal_quad_v3( - r_no, - pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co, - pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co, - pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co, - pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co); - } - else -#endif - { - normal_tri_v3( - r_no, - pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co, - pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co, - pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co); - } - } - } - else { - const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no; - normal_short_to_float_v3(r_no, no); - } -} - -static void dm_ts_SetTSpace( - const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - - float *pRes; - -finally: - pRes = pMesh->tangent[loop_index]; - copy_v3_v3(pRes, fvTangent); - pRes[3] = fSign; -} - void DM_calc_tangents_names_from_gpu( const GPUVertexAttribs *gattribs, char (*tangent_names)[MAX_NAME], int *r_tangent_names_count) @@ -3278,241 +3054,29 @@ void DM_calc_tangents_names_from_gpu( *r_tangent_names_count = count; } -static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) -{ - struct SGLSLMeshToTangent *mesh2tangent = taskdata; - /* new computation method */ - { - SMikkTSpaceContext sContext = {NULL}; - SMikkTSpaceInterface sInterface = {NULL}; - - sContext.m_pUserData = mesh2tangent; - sContext.m_pInterface = &sInterface; - sInterface.m_getNumFaces = dm_ts_GetNumFaces; - sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace; - sInterface.m_getPosition = dm_ts_GetPosition; - sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate; - sInterface.m_getNormal = dm_ts_GetNormal; - sInterface.m_setTSpaceBasic = dm_ts_SetTSpace; - - /* 0 if failed */ - genTangSpaceDefault(&sContext); - } -} - -void DM_add_named_tangent_layer_for_uv( - CustomData *uv_data, CustomData *tan_data, int numLoopData, - const char *layer_name) -{ - if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && - CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) - { - CustomData_add_layer_named( - tan_data, CD_TANGENT, CD_CALLOC, NULL, - numLoopData, layer_name); - } -} - -/** - * Here we get some useful information such as active uv layer name and search if it is already in tangent_names. - * Also, we calculate tangent_mask that works as a descriptor of tangents state. - * If tangent_mask has changed, then recalculate tangents. - */ -void DM_calc_loop_tangents_step_0( - const CustomData *loopData, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count, - bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, - char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) -{ - /* Active uv in viewport */ - int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV); - *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV); - ract_uv_name[0] = 0; - if (*ract_uv_n != -1) { - strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name); - } - - /* Active tangent in render */ - *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV); - rren_uv_name[0] = 0; - if (*rren_uv_n != -1) { - strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name); - } - - /* If active tangent not in tangent_names we take it into account */ - *rcalc_act = false; - *rcalc_ren = false; - for (int i = 0; i < tangent_names_count; i++) { - if (tangent_names[i][0] == 0) { - calc_active_tangent = true; - } - } - if (calc_active_tangent) { - *rcalc_act = true; - *rcalc_ren = true; - for (int i = 0; i < tangent_names_count; i++) { - if (STREQ(ract_uv_name, tangent_names[i])) - *rcalc_act = false; - if (STREQ(rren_uv_name, tangent_names[i])) - *rcalc_ren = false; - } - } - *rtangent_mask = 0; - - const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV); - for (int n = 0; n < uv_layer_num; n++) { - const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n); - bool add = false; - for (int i = 0; i < tangent_names_count; i++) { - if (tangent_names[i][0] && STREQ(tangent_names[i], name)) { - add = true; - break; - } - } - if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) || - (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))) - { - add = true; - } - if (add) - *rtangent_mask |= 1 << n; - } -} - void DM_calc_loop_tangents( DerivedMesh *dm, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count) + const char (*tangent_names)[MAX_NAME], int tangent_names_len) { - if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0) + if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0) { return; - int act_uv_n = -1; - int ren_uv_n = -1; - bool calc_act = false; - bool calc_ren = false; - char act_uv_name[MAX_NAME]; - char ren_uv_name[MAX_NAME]; - char tangent_mask = 0; - DM_calc_loop_tangents_step_0( - &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count, - &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); - if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) { - /* Check we have all the needed layers */ - MPoly *mpoly = dm->getPolyArray(dm); - const MLoopTri *looptri = dm->getLoopTriArray(dm); - int totface = dm->getNumLoopTri(dm); - /* Allocate needed tangent layers */ - for (int i = 0; i < tangent_names_count; i++) - if (tangent_names[i][0]) - DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]); - if (calc_act && act_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name); - if (calc_ren && ren_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name); - -#ifdef USE_LOOPTRI_DETECT_QUADS - int num_face_as_quad_map; - int *face_as_quad_map = NULL; - - /* map faces to quads */ - if (totface != dm->getNumPolys(dm)) { - /* over alloc, since we dont know how many ngon or quads we have */ - - /* map fake face index to looptri */ - face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__); - int k, j; - for (k = 0, j = 0; j < totface; k++, j++) { - face_as_quad_map[k] = j; - /* step over all quads */ - if (mpoly[looptri[j].poly].totloop == 4) { - j++; /* skips the nest looptri */ - } - } - num_face_as_quad_map = k; - } - else { - num_face_as_quad_map = totface; - } -#endif - - /* Calculation */ - { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL); - - dm->tangent_mask = 0; - /* Calculate tangent layers */ - SGLSLMeshToTangent data_array[MAX_MTFACE]; - const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT); - for (int n = 0; n < tangent_layer_num; n++) { - int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n); - BLI_assert(n < MAX_MTFACE); - SGLSLMeshToTangent *mesh2tangent = &data_array[n]; - mesh2tangent->numTessFaces = totface; -#ifdef USE_LOOPTRI_DETECT_QUADS - mesh2tangent->face_as_quad_map = face_as_quad_map; - mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; -#endif - mesh2tangent->mvert = dm->getVertArray(dm); - mesh2tangent->mpoly = dm->getPolyArray(dm); - mesh2tangent->mloop = dm->getLoopArray(dm); - mesh2tangent->looptri = dm->getLoopTriArray(dm); - /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), - * have to check this is valid... - */ - mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL); - mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL); - - mesh2tangent->orco = NULL; - mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name); - if (!mesh2tangent->mloopuv) { - mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO); - if (!mesh2tangent->orco) - continue; - } - mesh2tangent->tangent = dm->loopData.layers[index].data; - - /* Fill the resulting tangent_mask */ - int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name); - int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV); - BLI_assert(uv_ind != -1 && uv_start != -1); - BLI_assert(uv_ind - uv_start < MAX_MTFACE); - dm->tangent_mask |= 1 << (uv_ind - uv_start); - BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); - } - - BLI_assert(dm->tangent_mask == tangent_mask); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - } -#ifdef USE_LOOPTRI_DETECT_QUADS - if (face_as_quad_map) { - MEM_freeN(face_as_quad_map); - } -#undef USE_LOOPTRI_DETECT_QUADS - -#endif - - int uv_index, tan_index; - - /* Update active layer index */ - uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n); - if (uv_index != -1) { - tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name); - CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index); - } - - /* Update render layer index */ - uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n); - if (uv_index != -1) { - tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name); - CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index); - } } -} - -/** \} */ + BKE_mesh_calc_loop_tangent_ex( + dm->getVertArray(dm), + dm->getPolyArray(dm), dm->getNumPolys(dm), + dm->getLoopArray(dm), + dm->getLoopTriArray(dm), dm->getNumLoopTri(dm), + &dm->loopData, + calc_active_tangent, + tangent_names, tangent_names_len, + CustomData_get_layer(&dm->polyData, CD_NORMAL), + dm->getLoopDataArray(dm, CD_NORMAL), + dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */ + /* result */ + &dm->loopData, dm->getNumLoops(dm), + &dm->tangent_mask); +} void DM_calc_auto_bump_scale(DerivedMesh *dm) { @@ -3942,7 +3506,6 @@ BLI_INLINE void navmesh_intToCol(int i, float col[3]) static void navmesh_drawColored(DerivedMesh *dm) { - int a, glmode; MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT); MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE); int *polygonIdx = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST); @@ -3957,43 +3520,42 @@ static void navmesh_drawColored(DerivedMesh *dm) dm->drawEdges(dm, 0, 1); #endif - /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */ - { - DEBUG_VBO("Using legacy code. drawNavMeshColored\n"); - glBegin(glmode = GL_QUADS); - for (a = 0; a < dm->numTessFaceData; a++, mface++) { - int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES; - int pi = polygonIdx[a]; - if (pi <= 0) { - zero_v3(col); - } - else { - navmesh_intToCol(pi, col); - } + VertexFormat *format = immVertexFormat(); + unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + unsigned int color = VertexFormat_add_attrib(format, "color", COMP_F32, 3, KEEP_FLOAT); - if (new_glmode != glmode) { - glEnd(); - glBegin(glmode = new_glmode); - } - glColor3fv(col); - glVertex3fv(mvert[mface->v1].co); - glVertex3fv(mvert[mface->v2].co); - glVertex3fv(mvert[mface->v3].co); - if (mface->v4) { - glVertex3fv(mvert[mface->v4].co); - } + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + + /* Note: batch drawing API would let us share vertices */ + immBeginAtMost(PRIM_TRIANGLES, dm->numTessFaceData * 6); + for (int a = 0; a < dm->numTessFaceData; a++, mface++) { + int pi = polygonIdx[a]; + if (pi <= 0) { + zero_v3(col); + } + else { + navmesh_intToCol(pi, col); } - glEnd(); - } -} -static void navmesh_DM_drawFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsTex UNUSED(setDrawOptions), - DMCompareDrawOptions UNUSED(compareDrawOptions), - void *UNUSED(userData), DMDrawFlag UNUSED(flag)) -{ - navmesh_drawColored(dm); + immSkipAttrib(color); + immVertex3fv(pos, mvert[mface->v1].co); + immSkipAttrib(color); + immVertex3fv(pos, mvert[mface->v2].co); + immAttrib3fv(color, col); + immVertex3fv(pos, mvert[mface->v3].co); + + if (mface->v4) { + /* this tess face is a quad, so draw the other triangle */ + immSkipAttrib(color); + immVertex3fv(pos, mvert[mface->v1].co); + immSkipAttrib(color); + immVertex3fv(pos, mvert[mface->v3].co); + immAttrib3fv(color, col); + immVertex3fv(pos, mvert[mface->v4].co); + } + } + immEnd(); + immUnbindProgram(); } static void navmesh_DM_drawFacesSolid( @@ -4029,7 +3591,6 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm) recastData = (int *)CustomData_get_layer(&result->polyData, CD_RECAST); /* note: This is not good design! - really should not be doing this */ - result->drawFacesTex = navmesh_DM_drawFacesTex; result->drawFacesSolid = navmesh_DM_drawFacesSolid; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 1e33fe4ab46..30097a98b40 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -55,7 +55,6 @@ #include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idprop.h" @@ -65,6 +64,8 @@ #include "BKE_main.h" #include "BKE_object.h" +#include "DEG_depsgraph_build.h" + #include "BIK_api.h" #include "RNA_access.h" @@ -578,6 +579,8 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints) if (pchan->prop) { pchan->prop = IDP_CopyProperty(pchan->prop); } + + pchan->draw_data = NULL; /* Drawing cache, no need to copy. */ } /* for now, duplicate Bone Groups too when doing this */ @@ -766,6 +769,9 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) IDP_FreeProperty(pchan->prop); MEM_freeN(pchan->prop); } + + /* Cached data, for new draw manager rendering code. */ + MEM_SAFE_FREE(pchan->draw_data); } void BKE_pose_channel_free(bPoseChannel *pchan) @@ -1403,7 +1409,7 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose) /* Depsgraph components depends on actual pose state, * if pose was changed depsgraph is to be updated as well. */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } /* For the calculation of the effects of an Action at the given frame on an object diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 2f65e71c6d2..59484724aee 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -44,7 +44,6 @@ #include "DNA_scene_types.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_key.h" #include "BKE_main.h" @@ -54,6 +53,8 @@ #include "BKE_anim.h" #include "BKE_report.h" +#include "DEG_depsgraph_build.h" + // XXX bad level call... /* --------------------- */ @@ -283,7 +284,7 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets) /* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets) { - Base *base, *baseNext; + BaseLegacy *base, *baseNext; MPathTarget *mpt; /* make sure our temp-tag isn't already in use */ @@ -308,53 +309,21 @@ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets) } /* "brew me a list that's sorted a bit faster now depsy" */ - DAG_scene_relations_rebuild(G.main, scene); + DEG_scene_relations_rebuild(G.main, scene); } /* update scene for current frame */ static void motionpaths_calc_update_scene(Scene *scene) { -#if 1 // 'production' optimizations always on - /* rigid body simulation needs complete update to work correctly for now */ - /* RB_TODO investigate if we could avoid updating everything */ - if (BKE_scene_check_rigidbody_active(scene)) { - BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); - } - else { /* otherwise we can optimize by restricting updates */ - Base *base, *last = NULL; - - /* only stuff that moves or needs display still */ - DAG_scene_update_flags(G.main, scene, scene->lay, true, false); - - /* find the last object with the tag - * - all those afterwards are assumed to not be relevant for our calculations - */ - /* optimize further by moving out... */ - for (base = scene->base.first; base; base = base->next) { - if (base->object->flag & BA_TEMP_TAG) - last = base; - } - - /* perform updates for tagged objects */ - /* XXX: this will break if rigs depend on scene or other data that - * is animated but not attached to/updatable from objects */ - for (base = scene->base.first; base; base = base->next) { - /* update this object */ - BKE_object_handle_update(G.main->eval_ctx, scene, base->object); - - /* if this is the last one we need to update, let's stop to save some time */ - if (base == last) - break; - } - } -#else // original, 'always correct' version - /* do all updates + /* Do all updates * - if this is too slow, resort to using a more efficient way * that doesn't force complete update, but for now, this is the * most accurate way! + * + * TODO(segey): Bring back partial updates, which became impossible + * with the new depsgraph due to unsorted nature of bases. */ - BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */ -#endif + BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene); } /* ........ */ diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index bcc0d1aeacb..6475e5c8acd 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -60,7 +60,6 @@ #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_nla.h" #include "BKE_global.h" @@ -70,6 +69,8 @@ #include "BKE_report.h" #include "BKE_texture.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "nla_private.h" @@ -93,6 +94,7 @@ bool id_type_can_have_animdata(const short id_type) case ID_MA: case ID_TE: case ID_NT: case ID_LA: case ID_CA: case ID_WO: case ID_LS: + case ID_LP: case ID_SPK: case ID_SCE: case ID_MC: @@ -1594,7 +1596,7 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val * notify anyone of updates */ if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) { BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC); - DAG_id_type_tag(G.main, GS(id->name)); + DEG_id_type_tag(G.main, GS(id->name)); } } @@ -2549,7 +2551,7 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData ID *id = ptr->id.data; if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) { id->tag |= LIB_TAG_ID_RECALC; - DAG_id_type_tag(G.main, GS(id->name)); + DEG_id_type_tag(G.main, GS(id->name)); } } } diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index d7ea534068d..6f04be653d1 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -60,7 +60,6 @@ #include "BKE_anim.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_deform.h" #include "BKE_displist.h" @@ -1935,7 +1934,7 @@ void BKE_pose_clear_pointers(bPose *pose) /* only after leave editmode, duplicating, validating older files, library syncing */ /* NOTE: pose->flag is set for it */ -void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) +void BKE_pose_rebuild(Object *ob, bArmature *arm) { Bone *bone; bPose *pose; @@ -1979,27 +1978,12 @@ void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */ -#ifdef WITH_LEGACY_DEPSGRAPH - /* the sorting */ - /* Sorting for new dependnecy graph is done on the scene graph level. */ - if (counter > 1 && sort_bones) { - DAG_pose_sort(ob); - } -#else - UNUSED_VARS(sort_bones); -#endif - ob->pose->flag &= ~POSE_RECALC; ob->pose->flag |= POSE_WAS_REBUILT; BKE_pose_channels_hash_make(ob->pose); } -void BKE_pose_rebuild(Object *ob, bArmature *arm) -{ - BKE_pose_rebuild_ex(ob, arm, true); -} - /* ********************** THE POSE SOLVER ******************* */ /* loc/rot/size to given mat4 */ diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index a4714041edf..73e9f5d0774 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -41,7 +41,6 @@ #include "BKE_anim.h" #include "BKE_armature.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_fcurve.h" #include "BKE_scene.h" @@ -51,13 +50,7 @@ #include "BKE_global.h" #include "BKE_main.h" -#include "DEG_depsgraph.h" - -#ifdef WITH_LEGACY_DEPSGRAPH -# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf -#else -# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf -#endif +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf /* ********************** SPLINE IK SOLVER ******************* */ @@ -558,7 +551,7 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo /* *************** Depsgraph evaluation callbacks ************ */ -void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_eval_init(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, bPose *pose) @@ -592,7 +585,7 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), BKE_pose_splineik_init_tree(scene, ob, ctime); } -void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_eval_bone(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, bPoseChannel *pchan) @@ -627,7 +620,7 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), } } -void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_constraints_evaluate(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, bPoseChannel *pchan) @@ -648,7 +641,7 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), } } -void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_bone_done(struct EvaluationContext *UNUSED(eval_ctx), bPoseChannel *pchan) { float imat[4][4]; @@ -659,7 +652,7 @@ void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx), } } -void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_iktree_evaluate(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, bPoseChannel *rootchan) @@ -669,7 +662,7 @@ void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx), BIK_execute_tree(scene, ob, rootchan, ctime); } -void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_splineik_evaluate(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, bPoseChannel *rootchan) @@ -679,7 +672,7 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), BKE_splineik_execute_tree(scene, ob, rootchan, ctime); } -void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_eval_flush(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, bPose *UNUSED(pose)) @@ -694,7 +687,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), ob->recalc &= ~OB_RECALC_ALL; } -void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) +void BKE_pose_eval_proxy_copy(struct EvaluationContext *UNUSED(eval_ctx), Object *ob) { BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL); DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index ceb641073e0..ebb10c02683 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -51,10 +51,10 @@ #include "BKE_brush.h" #include "BKE_cachefile.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_node.h" #include "BKE_report.h" @@ -62,6 +62,8 @@ #include "BKE_screen.h" #include "BKE_sequencer.h" +#include "DEG_depsgraph.h" + #include "RE_pipeline.h" #include "RE_render_ext.h" @@ -87,7 +89,7 @@ void BKE_blender_free(void) IMB_exit(); BKE_cachefiles_exit(); BKE_images_exit(); - DAG_exit(); + DEG_free_node_types(); BKE_brush_system_exit(); RE_texture_rng_exit(); @@ -96,6 +98,8 @@ void BKE_blender_free(void) BKE_sequencer_cache_destruct(); IMB_moviecache_destruct(); + + BKE_layer_exit(); free_nodesystem(); } diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index e57524af546..206b0f2a8cc 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -44,12 +44,13 @@ #include "BKE_blender_copybuffer.h" /* own include */ #include "BKE_blendfile.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "DEG_depsgraph_build.h" + #include "BLO_readfile.h" #include "BLO_writefile.h" @@ -117,7 +118,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); + SceneLayer *sl = CTX_data_scene_layer(C); Main *mainl = NULL; Library *lib; BlendHandle *bh; @@ -142,7 +143,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re BLO_library_link_copypaste(mainl, bh); - BLO_library_link_end(mainl, &bh, flag, scene, v3d); + BLO_library_link_end(mainl, &bh, flag, scene, sl); /* mark all library linked objects to be updated */ BKE_main_lib_objects_recalc_all(bmain); @@ -157,7 +158,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); /* recreate dependency graph to include new objects */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); BLO_blendhandle_close(bh); /* remove library... */ diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index e3a5edb2049..b8f46756445 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -56,7 +56,6 @@ #include "BKE_appdir.h" #include "BKE_brush.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" @@ -66,6 +65,8 @@ #include "BLO_readfile.h" #include "BLO_writefile.h" +#include "DEG_depsgraph.h" + /* -------------------------------------------------------------------- */ /** \name Global Undo @@ -118,7 +119,7 @@ static int read_undosave(bContext *C, UndoElem *uel) if (success) { /* important not to update time here, else non keyed tranforms are lost */ - DAG_on_visible_update(G.main, false); + DEG_on_visible_update(G.main, false); } return success; diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index a521d671ea4..9e244246e16 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -32,6 +32,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_workspace_types.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -48,11 +49,13 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_ipo.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "BLO_readfile.h" #include "BLO_writefile.h" @@ -93,7 +96,7 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene) { wmWindow *win; for (win = wm->windows.first; win; win = win->next) { - if (win->screen->scene == scene) { + if (win->scene == scene) { return true; } } @@ -162,17 +165,22 @@ static void setup_app_data( * (otherwise we'd be undoing on an off-screen scene which isn't acceptable). * see: T43424 */ + wmWindow *win; bScreen *curscreen = NULL; + SceneLayer *cur_render_layer; bool track_undo_scene; /* comes from readfile.c */ SWAP(ListBase, G.main->wm, bfd->main->wm); + SWAP(ListBase, G.main->workspaces, bfd->main->workspaces); SWAP(ListBase, G.main->screen, bfd->main->screen); - /* we re-use current screen */ + /* we re-use current window and screen */ + win = CTX_wm_window(C); curscreen = CTX_wm_screen(C); - /* but use new Scene pointer */ + /* but use Scene pointer from new file */ curscene = bfd->curscene; + cur_render_layer = bfd->cur_render_layer; track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first); @@ -183,32 +191,31 @@ static void setup_app_data( if (curscene == NULL) { curscene = BKE_scene_add(bfd->main, "Empty"); } + if (cur_render_layer == NULL) { + /* fallback to scene layer */ + cur_render_layer = BKE_scene_layer_render_active(curscene); + } if (track_undo_scene) { /* keep the old (free'd) scene, let 'blo_lib_link_screen_restore' * replace it with 'curscene' if its needed */ } - else { - /* and we enforce curscene to be in current screen */ - if (curscreen) { - /* can run in bgmode */ - curscreen->scene = curscene; - } + /* and we enforce curscene to be in current screen */ + else if (win) { /* can run in bgmode */ + win->scene = curscene; } /* BKE_blender_globals_clear will free G.main, here we can still restore pointers */ - blo_lib_link_screen_restore(bfd->main, curscreen, curscene); - /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */ - if (curscreen) { - curscene = curscreen->scene; + blo_lib_link_restore(bfd->main, CTX_wm_manager(C), curscene, cur_render_layer); + if (win) { + curscene = win->scene; } if (track_undo_scene) { wmWindowManager *wm = bfd->main->wm.first; if (wm_scene_is_visible(wm, bfd->curscene) == false) { curscene = bfd->curscene; - curscreen->scene = curscene; - BKE_screen_view3d_scene_sync(curscreen); + BKE_screen_view3d_scene_sync(curscreen, curscene); } } } @@ -262,12 +269,14 @@ static void setup_app_data( /* this can happen when active scene was lib-linked, and doesn't exist anymore */ if (CTX_data_scene(C) == NULL) { + wmWindow *win = CTX_wm_window(C); + /* in case we don't even have a local scene, add one */ if (!G.main->scene.first) BKE_scene_add(G.main, "Empty"); CTX_data_scene_set(C, G.main->scene.first); - CTX_wm_screen(C)->scene = CTX_data_scene(C); + win->scene = CTX_data_scene(C); curscene = CTX_data_scene(C); } @@ -316,12 +325,10 @@ static void setup_app_data( wmWindowManager *wm = G.main->wm.first; if (wm) { - wmWindow *win; - - for (win = wm->windows.first; win; win = win->next) { - if (win->screen && win->screen->scene) /* zealous check... */ - if (win->screen->scene != curscene) - BKE_scene_set_background(G.main, win->screen->scene); + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (win->scene && win->scene != curscene) { + BKE_scene_set_background(G.main, win->scene); + } } } } @@ -509,6 +516,49 @@ int BKE_blendfile_userdef_write(const char *filepath, ReportList *reports) return retval; } +WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, ReportList *reports) +{ + BlendFileData *bfd; + WorkspaceConfigFileData *workspace_config = NULL; + + bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_USERDEF); + if (bfd) { + workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__); + workspace_config->main = bfd->main; + workspace_config->workspaces = bfd->main->workspaces; + + MEM_freeN(bfd); + } + + return workspace_config; +} + +bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports) +{ + int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_AUTOPLAY | G_FILE_HISTORY); + bool retval = false; + + BKE_blendfile_write_partial_begin(bmain); + + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + BKE_blendfile_write_partial_tag_ID(&workspace->id, true); + } + + if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) { + retval = true; + } + + BKE_blendfile_write_partial_end(bmain); + + return retval; +} + +void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config) +{ + BKE_main_free(workspace_config->main); + MEM_freeN(workspace_config); +} + /** \} */ diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 67c66d4e40b..859aa628781 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -204,11 +204,9 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f } /* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */ -void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) +void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file) { - for (Base *base = scene->base.first; base; base = base->next) { - Object *ob = base->object; - + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); if (md) { diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 9cb553aa27b..be75048492c 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -633,7 +633,7 @@ static bool camera_frame_fit_calc_from_data( /* don't move the camera, just yield the fit location */ /* r_scale only valid/useful for ortho cameras */ bool BKE_camera_view_frame_fit_to_scene( - Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale) + Scene *scene, SceneLayer *sl, Object *camera_ob, float r_co[3], float *r_scale) { CameraParams params; CameraViewFrameData data_cb; @@ -644,7 +644,7 @@ bool BKE_camera_view_frame_fit_to_scene( camera_frame_fit_data_init(scene, camera_ob, ¶ms, &data_cb); /* run callback on all visible points */ - BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb); + BKE_scene_foreach_display_point(scene, sl, camera_to_frame_view_cb, &data_cb); return camera_frame_fit_calc_from_data(¶ms, &data_cb, r_co, r_scale); } @@ -853,7 +853,7 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha } if (name[0] != '\0') { - Base *base = BKE_scene_base_find_by_name(scene, name); + BaseLegacy *base = BKE_scene_base_find_by_name(scene, name); if (base) { return base->object; } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 46a067ea0bc..c743d1f7e11 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -58,6 +58,7 @@ #include "GPU_buffers.h" #include "GPU_draw.h" #include "GPU_glew.h" +#include "GPU_immediate.h" #include "GPU_shader.h" #include "GPU_basic_shader.h" @@ -372,40 +373,10 @@ static void cdDM_drawVerts(DerivedMesh *dm) GPU_buffers_unbind(); } -static void cdDM_drawUVEdges(DerivedMesh *dm) +static void cdDM_drawEdges(DerivedMesh *dm, bool UNUSED(drawLooseEdges), bool UNUSED(drawAllEdges)) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - const MPoly *mpoly = cddm->mpoly; - int totpoly = dm->getNumPolys(dm); - int prevstart = 0; - bool prevdraw = true; - int curpos = 0; - int i; - - GPU_uvedge_setup(dm); - for (i = 0; i < totpoly; i++, mpoly++) { - const bool draw = (mpoly->flag & ME_HIDE) == 0; - - if (prevdraw != draw) { - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - prevstart = curpos; - } - curpos += 2 * mpoly->totloop; - prevdraw = draw; - } - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - GPU_buffers_unbind(); -} - -static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - GPUDrawObject *gdo; if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) { @@ -413,22 +384,37 @@ static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdg return; } - - GPU_edge_setup(dm); - gdo = dm->drawObject; - if (gdo->edges && gdo->points) { - if (drawAllEdges && drawLooseEdges) { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->totedge * 2); - } - else if (drawAllEdges) { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2); - } - else { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2); - GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, dm->drawObject->tot_loose_edge_drawn * 2); + + MVert *vert = cddm->mvert; + MEdge *edge = cddm->medge; + + VertexFormat *format = immVertexFormat(); + unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + + /* NOTE: This is active object color, which is not really perfect. + * But we can't query color set by glColor() :( + */ + float color[4] = {1.0f, 0.667f, 0.251f, 1.0f}; + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(color); + + const int chunk_size = 1024; + const int num_chunks = (dm->numEdgeData + chunk_size - 1) / chunk_size; + + for (int chunk = 0; chunk < num_chunks; ++chunk) { + const int num_current_edges = (chunk < num_chunks - 1) + ? chunk_size + : dm->numEdgeData - chunk_size * (num_chunks - 1); + immBeginAtMost(PRIM_LINES, num_current_edges * 2); + for (int i = 0; i < num_current_edges; i++, edge++) { + immVertex3fv(pos, vert[edge->v1].co); + immVertex3fv(pos, vert[edge->v2].co); } + immEnd(); } - GPU_buffers_unbind(); + + immUnbindProgram(); } static void cdDM_drawLooseEdges(DerivedMesh *dm) @@ -451,8 +437,9 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm) static void cdDM_drawFacesSolid( DerivedMesh *dm, float (*partial_redraw_planes)[4], - bool UNUSED(fast), DMSetMaterial setMaterial) + bool fast, DMSetMaterial setMaterial) { + UNUSED_VARS(partial_redraw_planes, fast, setMaterial); CDDerivedMesh *cddm = (CDDerivedMesh *) dm; int a; @@ -465,177 +452,79 @@ static void cdDM_drawFacesSolid( return; } } - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - for (a = 0; a < dm->drawObject->totmaterial; a++) { - if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) { - GPU_buffer_draw_elements( - dm->drawObject->triangles, GL_TRIANGLES, - dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); - } - } - GPU_buffers_unbind(); -} -static void cdDM_drawFacesTex_common( - DerivedMesh *dm, - DMSetDrawOptionsTex drawParams, - DMSetDrawOptionsMappedTex drawParamsMapped, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; + const MVert *mvert = cddm->mvert; + const MLoop *mloop = cddm->mloop; const MPoly *mpoly = cddm->mpoly; - MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); - const MLoopCol *mloopcol = NULL; - int i; - int colType, start_element, tot_drawn; - const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0; - const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0; - const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0; - int totpoly; - int next_actualFace; - int mat_index; - int tot_element; - - /* double lookup */ - const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - - /* TODO: not entirely correct, but currently dynamic topology will - * destroy UVs anyway, so textured display wouldn't work anyway - * - * this will do more like solid view with lights set up for - * textured view, but object itself will be displayed gray - * (the same as it'll display without UV maps in textured view) - */ - if (cddm->pbvh) { - if (cddm->pbvh_draw && - BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH && - BKE_pbvh_has_faces(cddm->pbvh)) - { - GPU_set_tpage(NULL, false, false); - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false); - return; - } - else { - cdDM_update_normals_from_pbvh(dm); - } - } + const int num_looptris = dm->getNumLoopTri(dm); + const MLoopTri *looptri = dm->getLoopTriArray(dm); + const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL); + const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - if (use_colors) { - colType = CD_TEXTURE_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - if (!mloopcol) { - colType = CD_PREVIEW_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - if (!mloopcol) { - colType = CD_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - } + VertexFormat *format = immVertexFormat(); + unsigned int pos = VertexFormat_add_attrib(format, "pos", COMP_F32, 3, KEEP_FLOAT); + unsigned int nor = VertexFormat_add_attrib(format, "nor", COMP_F32, 3, KEEP_FLOAT); - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - if (flag & DM_DRAW_USE_TEXPAINT_UV) - GPU_texpaint_uv_setup(dm); - else - GPU_uv_setup(dm); - if (mloopcol) { - GPU_color_setup(dm, colType); - } + float color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; + const float light_vec[3] = {0.0f, 0.0f, 1.0f}; - /* lastFlag = 0; */ /* UNUSED */ - for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { - GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index; - next_actualFace = bufmat->polys[0]; - totpoly = bufmat->totpolys; + immBindBuiltinProgram(GPU_SHADER_SIMPLE_LIGHTING); + immUniformColor4fv(color); + immUniform3fv("light", light_vec); - tot_element = 0; - tot_drawn = 0; - start_element = 0; + const int chunk_size = 1024; + const int num_chunks = (num_looptris + chunk_size - 1) / chunk_size; - for (i = 0; i < totpoly; i++) { - int actualFace = bufmat->polys[i]; - DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - int flush = 0; - int tot_tri_verts; + for (int chunk = 0; chunk < num_chunks; ++chunk) { + const int num_current_looptris = (chunk < num_chunks - 1) + ? chunk_size + : num_looptris - chunk_size * (num_chunks - 1); - if (i != totpoly - 1) - next_actualFace = bufmat->polys[i + 1]; + immBeginAtMost(PRIM_TRIANGLES, num_current_looptris * 3); - if (use_hide && (mpoly[actualFace].flag & ME_HIDE)) { - draw_option = DM_DRAW_OPTION_SKIP; - } - else if (drawParams) { - MTexPoly *tp = use_tface && mtexpoly ? &mtexpoly[actualFace] : NULL; - draw_option = drawParams(tp, (mloopcol != NULL), mpoly[actualFace].mat_nr); - } - else { - if (index_mp_to_orig) { - const int orig = index_mp_to_orig[actualFace]; - if (orig == ORIGINDEX_NONE) { - /* XXX, this is not really correct - * it will draw the previous faces context for this one when we don't know its settings. - * but better then skipping it altogether. - campbell */ - draw_option = DM_DRAW_OPTION_NORMAL; - } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, orig, mpoly[actualFace].mat_nr); - } + for (a = 0; a < num_current_looptris; a++, looptri++) { + const MPoly *mp = &mpoly[looptri->poly]; + const bool smoothnormal = (lnors != NULL) || (mp->flag & ME_SMOOTH); + const unsigned int vtri[3] = {mloop[looptri->tri[0]].v, + mloop[looptri->tri[1]].v, + mloop[looptri->tri[2]].v}; + const unsigned int *ltri = looptri->tri; + float normals[3][3]; + if (!smoothnormal) { + if (nors != NULL) { + copy_v3_v3(normals[0], nors[looptri->poly]); } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, actualFace, mpoly[actualFace].mat_nr); + else { + normal_tri_v3(normals[0], + mvert[vtri[0]].co, + mvert[vtri[1]].co, + mvert[vtri[2]].co); } + copy_v3_v3(normals[1], normals[0]); + copy_v3_v3(normals[2], normals[0]); } - - /* flush buffer if current triangle isn't drawable or it's last triangle */ - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1); - - if (!flush && compareDrawOptions) { - /* also compare draw options and flush buffer if they're different - * need for face selection highlight in edit mode */ - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3; - tot_element += tot_tri_verts; - - if (flush) { - if (draw_option != DM_DRAW_OPTION_SKIP) - tot_drawn += tot_tri_verts; - - if (tot_drawn) { - if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL) - GPU_color_switch(1); - else - GPU_color_switch(0); - - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn); - tot_drawn = 0; - } - start_element = tot_element; + else if (lnors != NULL) { + copy_v3_v3(normals[0], lnors[ltri[0]]); + copy_v3_v3(normals[1], lnors[ltri[1]]); + copy_v3_v3(normals[2], lnors[ltri[2]]); } else { - tot_drawn += tot_tri_verts; + normal_short_to_float_v3(normals[0], mvert[vtri[0]].no); + normal_short_to_float_v3(normals[1], mvert[vtri[1]].no); + normal_short_to_float_v3(normals[2], mvert[vtri[2]].no); } + + immAttrib3fv(nor, normals[0]); + immVertex3fv(pos, mvert[vtri[0]].co); + immAttrib3fv(nor, normals[1]); + immVertex3fv(pos, mvert[vtri[1]].co); + immAttrib3fv(nor, normals[2]); + immVertex3fv(pos, mvert[vtri[2]].co); } + immEnd(); } - GPU_buffers_unbind(); - -} - -static void cdDM_drawFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag); + immUnbindProgram(); } static void cdDM_drawMappedFaces( @@ -842,15 +731,6 @@ static void cdDM_drawMappedFaces( } -static void cdDM_drawMappedFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsMappedTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); -} - static void cddm_draw_attrib_vertex( DMVertexAttribs *attribs, const MVert *mvert, int a, int index, int loop, int vert, const float *lnor, const bool smoothnormal) @@ -1904,7 +1784,7 @@ void CDDM_recalc_tessellation_ex(DerivedMesh *dm, const bool do_face_nor_cpy) /* Tessellation recreated faceData, and the active layer indices need to get re-propagated * from loops and polys to faces */ - CustomData_bmesh_update_active_layers(&dm->faceData, &dm->polyData, &dm->loopData); + CustomData_bmesh_update_active_layers(&dm->faceData, &dm->loopData); } void CDDM_recalc_tessellation(DerivedMesh *dm) @@ -2008,16 +1888,13 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->drawVerts = cdDM_drawVerts; - dm->drawUVEdges = cdDM_drawUVEdges; dm->drawEdges = cdDM_drawEdges; dm->drawLooseEdges = cdDM_drawLooseEdges; dm->drawMappedEdges = cdDM_drawMappedEdges; dm->drawFacesSolid = cdDM_drawFacesSolid; - dm->drawFacesTex = cdDM_drawFacesTex; dm->drawFacesGLSL = cdDM_drawFacesGLSL; dm->drawMappedFaces = cdDM_drawMappedFaces; - dm->drawMappedFacesTex = cdDM_drawMappedFacesTex; dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL; dm->drawMappedFacesMat = cdDM_drawMappedFacesMat; @@ -2154,7 +2031,6 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase) if (alluv) { const char *uvname = "Orco"; - CustomData_add_layer_named(&cddm->dm.polyData, CD_MTEXPOLY, CD_DEFAULT, NULL, totpoly, uvname); CustomData_add_layer_named(&cddm->dm.loopData, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname); } @@ -2169,22 +2045,18 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase) static void loops_to_customdata_corners( BMesh *bm, CustomData *facedata, int cdindex, const BMLoop *l3[3], - int numCol, int numTex) + int numCol, int numUV) { const BMLoop *l; - BMFace *f = l3[0]->f; +// BMFace *f = l3[0]->f; MTFace *texface; - MTexPoly *texpoly; MCol *mcol; MLoopCol *mloopcol; MLoopUV *mloopuv; int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL); - for (i = 0; i < numTex; i++) { + for (i = 0; i < numUV; i++) { texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i); - texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i); - - ME_MTEXFACE_CPY(texface, texpoly); for (j = 0; j < 3; j++) { l = l3[j]; @@ -2238,7 +2110,7 @@ static DerivedMesh *cddm_from_bmesh_ex( MLoop *mloop = cddm->mloop; MPoly *mpoly = cddm->mpoly; int numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); - int numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + int numUV = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV); int *index, add_orig; CustomDataMask mask; unsigned int i, j; @@ -2268,7 +2140,7 @@ static DerivedMesh *cddm_from_bmesh_ex( /* add tessellation mface layers */ if (use_tessface) { - CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em_tottri); + CustomData_from_bmeshpoly(&dm->faceData, &dm->loopData, em_tottri); } index = dm->getVertDataArray(dm, CD_ORIGINDEX); @@ -2340,7 +2212,7 @@ static DerivedMesh *cddm_from_bmesh_ex( /* map mfaces to polygons in the same cddm intentionally */ *index++ = BM_elem_index_get(efa); - loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex); + loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numUV); test_index_face(mf, &dm->faceData, i, 3); } } diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index ee0fde1ea61..8190a7c2a8b 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -478,7 +478,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived return; } - if (!can_simulate) return; /* if on second frame, write cache for first frame */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c new file mode 100644 index 00000000000..f0ae3d8be1c --- /dev/null +++ b/source/blender/blenkernel/intern/collection.c @@ -0,0 +1,636 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/collection.c + * \ingroup bke + */ + +#include <string.h> + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_iterator.h" +#include "BLI_listbase.h" +#include "BLT_translation.h" +#include "BLI_string_utils.h" + +#include "BKE_collection.h" +#include "BKE_layer.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + + +/** + * Add a collection to a collection ListBase and syncronize all render layers + * The ListBase is NULL when the collection is to be added to the master collection + */ +SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, const char *name) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); + + if (!name) { + name = DATA_("New Collection"); + } + + if (!sc_parent) { + sc_parent = sc_master; + } + + BKE_collection_rename(scene, sc, name); + BLI_addtail(&sc_parent->scene_collections, sc); + + BKE_layer_sync_new_scene_collection(scene, sc_parent, sc); + return sc; +} + +/** + * Free the collection items recursively + */ +static void collection_free(SceneCollection *sc) +{ + for (LinkData *link = sc->objects.first; link; link = link->next) { + id_us_min(link->data); + } + BLI_freelistN(&sc->objects); + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + id_us_min(link->data); + } + BLI_freelistN(&sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + collection_free(nsc); + } + BLI_freelistN(&sc->scene_collections); +} + +/** + * Unlink the collection recursively + * \return true if unlinked. + */ +static bool collection_remlink(SceneCollection *sc_parent, SceneCollection *sc_gone) +{ + for (SceneCollection *sc = sc_parent->scene_collections.first; sc; sc = sc->next) { + if (sc == sc_gone) { + BLI_remlink(&sc_parent->scene_collections, sc_gone); + return true; + } + + if (collection_remlink(sc, sc_gone)) { + return true; + } + } + return false; +} + +/** + * Recursively remove any instance of this SceneCollection + */ +static void layer_collection_remove(SceneLayer *sl, ListBase *lb, const SceneCollection *sc) +{ + LayerCollection *lc = lb->first; + while (lc) { + if (lc->scene_collection == sc) { + BKE_layer_collection_free(sl, lc); + BLI_remlink(lb, lc); + + LayerCollection *lc_next = lc->next; + MEM_freeN(lc); + lc = lc_next; + + /* only the "top-level" layer collections may have the + * same SceneCollection in a sibling tree. + */ + if (lb != &sl->layer_collections) { + return; + } + } + + else { + layer_collection_remove(sl, &lc->layer_collections, sc); + lc = lc->next; + } + } +} + +/** + * Remove a collection from the scene, and syncronize all render layers + */ +bool BKE_collection_remove(Scene *scene, SceneCollection *sc) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + + /* the master collection cannot be removed */ + if (sc == sc_master) { + return false; + } + + /* unlink from the respective collection tree */ + if (!collection_remlink(sc_master, sc)) { + BLI_assert(false); + } + + /* clear the collection items */ + collection_free(sc); + + /* check all layers that use this collection and clear them */ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + layer_collection_remove(sl, &sl->layer_collections, sc); + sl->active_collection = 0; + } + + MEM_freeN(sc); + return true; +} + +/** + * Returns the master collection + */ +SceneCollection *BKE_collection_master(const Scene *scene) +{ + return scene->collection; +} + +struct UniqueNameCheckData { + ListBase *lb; + SceneCollection *lookup_sc; +}; + +static bool collection_unique_name_check(void *arg, const char *name) +{ + struct UniqueNameCheckData *data = arg; + + for (SceneCollection *sc = data->lb->first; sc; sc = sc->next) { + struct UniqueNameCheckData child_data = {.lb = &sc->scene_collections, .lookup_sc = data->lookup_sc}; + + if (sc != data->lookup_sc) { + if (STREQ(sc->name, name)) { + return true; + } + } + if (collection_unique_name_check(&child_data, name)) { + return true; + } + } + + return false; +} + +void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc}; + + BLI_strncpy(sc->name, name, sizeof(sc->name)); + BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name)); +} + +/** + * Free (or release) any data used by the master collection (does not free the master collection itself). + * Used only to clear the entire scene data since it's not doing re-syncing of the LayerCollection tree + */ +void BKE_collection_master_free(Scene *scene) +{ + collection_free(BKE_collection_master(scene)); +} + +static void collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob) +{ + BLI_addtail(&sc->objects, BLI_genericNodeN(ob)); + id_us_plus((ID *)ob); + BKE_layer_sync_object_link(scene, sc, ob); +} + +/** + * Add object to collection + */ +void BKE_collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob) +{ + if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) { + /* don't add the same object twice */ + return; + } + collection_object_add(scene, sc, ob); +} + +/** + * Add object to all collections that reference objects is in + * (used to copy objects) + */ +void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst) +{ + FOREACH_SCENE_COLLECTION(scene, sc) + { + if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) { + collection_object_add(scene, sc, ob_dst); + } + } + FOREACH_SCENE_COLLECTION_END +} + +/** + * Remove object from collection. + * \param bmain: Can be NULL if free_us is false. + */ +void BKE_collection_object_remove(Main *bmain, const Scene *scene, SceneCollection *sc, Object *ob, const bool free_us) +{ + + LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data)); + + if (link == NULL) { + return; + } + + BLI_remlink(&sc->objects, link); + MEM_freeN(link); + + TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */ + BKE_layer_sync_object_unlink(scene, sc, ob); + + if (free_us) { + BKE_libblock_free_us(bmain, ob); + } + else { + id_us_min(&ob->id); + } +} + +/** + * Move object from a collection into another + */ +void BKE_collection_object_move(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob) +{ + BKE_collection_object_add(scene, sc_dst, ob); + BKE_collection_object_remove(NULL, scene, sc_src, ob, false); +} + +/** + * Remove object from all collections of scene + */ +void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us) +{ + BKE_scene_remove_rigidbody_object(scene, ob); + + FOREACH_SCENE_COLLECTION(scene, sc) + { + BKE_collection_object_remove(bmain, scene, sc, ob, free_us); + } + FOREACH_SCENE_COLLECTION_END +} + +/* ---------------------------------------------------------------------- */ +/* Outliner drag and drop */ + +/** + * Find and return the SceneCollection that has \a sc_child as one of its directly + * nested SceneCollection. + * + * \param sc_parent Initial SceneCollection to look into recursively, usually the master collection + */ +static SceneCollection *find_collection_parent(const SceneCollection *sc_child, SceneCollection *sc_parent) +{ + for (SceneCollection *sc_nested = sc_parent->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { + if (sc_nested == sc_child) { + return sc_parent; + } + + SceneCollection *found = find_collection_parent(sc_child, sc_nested); + if (found) { + return found; + } + } + + return NULL; +} + +/** + * Check if \a sc_reference is nested to \a sc_parent SceneCollection + */ +static bool is_collection_in_tree(const SceneCollection *sc_reference, SceneCollection *sc_parent) +{ + return find_collection_parent(sc_reference, sc_parent) != NULL; +} + +bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) +{ + /* Find the SceneCollection the sc_src belongs to */ + SceneCollection *sc_master = BKE_collection_master(scene); + + /* Master Layer can't be moved around*/ + if (ELEM(sc_master, sc_src, sc_dst)) { + return false; + } + + /* collection is already where we wanted it to be */ + if (sc_dst->prev == sc_src) { + return false; + } + + /* We can't move a collection fs the destiny collection + * is nested to the source collection */ + if (is_collection_in_tree(sc_dst, sc_src)) { + return false; + } + + SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); + SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master); + BLI_assert(sc_src_parent); + BLI_assert(sc_dst_parent); + + /* Remove sc_src from its parent */ + BLI_remlink(&sc_src_parent->scene_collections, sc_src); + + /* Re-insert it where it belongs */ + BLI_insertlinkbefore(&sc_dst_parent->scene_collections, sc_dst, sc_src); + + /* Update the tree */ + BKE_layer_collection_resync(scene, sc_src_parent); + BKE_layer_collection_resync(scene, sc_dst_parent); + + return true; +} + +bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) +{ + /* Find the SceneCollection the sc_src belongs to */ + SceneCollection *sc_master = BKE_collection_master(scene); + + /* Master Layer can't be moved around*/ + if (ELEM(sc_master, sc_src, sc_dst)) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (sc_dst->next == sc_src) { + return false; + } + + /* We can't move a collection if the destiny collection + * is nested to the source collection */ + if (is_collection_in_tree(sc_dst, sc_src)) { + return false; + } + + SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); + SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master); + BLI_assert(sc_src_parent); + BLI_assert(sc_dst_parent); + + /* Remove sc_src from its parent */ + BLI_remlink(&sc_src_parent->scene_collections, sc_src); + + /* Re-insert it where it belongs */ + BLI_insertlinkafter(&sc_dst_parent->scene_collections, sc_dst, sc_src); + + /* Update the tree */ + BKE_layer_collection_resync(scene, sc_src_parent); + BKE_layer_collection_resync(scene, sc_dst_parent); + + return true; +} + +bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) +{ + /* Find the SceneCollection the sc_src belongs to */ + SceneCollection *sc_master = BKE_collection_master(scene); + if (sc_src == sc_master) { + return false; + } + + /* We can't move a collection if the destiny collection + * is nested to the source collection */ + if (is_collection_in_tree(sc_dst, sc_src)) { + return false; + } + + SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); + BLI_assert(sc_src_parent); + + /* collection is already where we wanted it to be */ + if (sc_dst->scene_collections.last == sc_src) { + return false; + } + + /* Remove sc_src from it */ + BLI_remlink(&sc_src_parent->scene_collections, sc_src); + + /* Insert sc_src into sc_dst */ + BLI_addtail(&sc_dst->scene_collections, sc_src); + + /* Update the tree */ + BKE_layer_collection_resync(scene, sc_src_parent); + BKE_layer_collection_resync(scene, sc_dst); + + return true; +} + +/* ---------------------------------------------------------------------- */ +/* Iteractors */ +/* scene collection iteractor */ + +typedef struct SceneCollectionsIteratorData { + Scene *scene; + void **array; + int tot, cur; +} SceneCollectionsIteratorData; + +static void scene_collection_callback(SceneCollection *sc, BKE_scene_collections_Cb callback, void *data) +{ + callback(sc, data); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + scene_collection_callback(nsc, callback, data); + } +} + +static void scene_collections_count(SceneCollection *UNUSED(sc), void *data) +{ + int *tot = data; + (*tot)++; +} + +static void scene_collections_build_array(SceneCollection *sc, void *data) +{ + SceneCollection ***array = data; + **array = sc; + (*array)++; +} + +static void scene_collections_array(Scene *scene, SceneCollection ***collections_array, int *tot) +{ + SceneCollection *sc = BKE_collection_master(scene); + SceneCollection **array; + + *collections_array = NULL; + *tot = 0; + + if (scene == NULL) + return; + + scene_collection_callback(sc, scene_collections_count, tot); + + if (*tot == 0) + return; + + *collections_array = array = MEM_mallocN(sizeof(SceneCollection *) * (*tot), "SceneCollectionArray"); + scene_collection_callback(sc, scene_collections_build_array, &array); +} + +/** + * Only use this in non-performance critical situations + * (it iterates over all scene collections twice) + */ +void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + SceneCollectionsIteratorData *data = MEM_callocN(sizeof(SceneCollectionsIteratorData), __func__); + + data->scene = scene; + iter->data = data; + + scene_collections_array(scene, (SceneCollection ***)&data->array, &data->tot); + BLI_assert(data->tot != 0); + + data->cur = 0; + iter->current = data->array[data->cur]; + iter->valid = true; +} + +void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter) +{ + SceneCollectionsIteratorData *data = iter->data; + + if (++data->cur < data->tot) { + iter->current = data->array[data->cur]; + } + else { + iter->valid = false; + } +} + +void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter) +{ + SceneCollectionsIteratorData *data = iter->data; + + if (data) { + if (data->array) { + MEM_freeN(data->array); + } + MEM_freeN(data); + } + iter->valid = false; +} + + +/* scene objects iteractor */ + +typedef struct SceneObjectsIteratorData { + GSet *visited; + LinkData *link; + BLI_Iterator scene_collection_iter; +} SceneObjectsIteratorData; + +void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__); + iter->data = data; + + /* lookup list ot make sure each object is object called once */ + data->visited = BLI_gset_ptr_new(__func__); + + /* we wrap the scenecollection iterator here to go over the scene collections */ + BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene); + + SceneCollection *sc = data->scene_collection_iter.current; + iter->current = sc->objects.first ? ((LinkData *)sc->objects.first)->data : NULL; + iter->valid = true; + + if (iter->current == NULL) { + BKE_scene_objects_iterator_next(iter); + } +} + +/** + * Gets the first unique object in the sequence + */ +static LinkData *object_base_unique(GSet *gs, LinkData *link) +{ + for (; link != NULL; link = link->next) { + Object *ob = link->data; + if (!BLI_gset_haskey(gs, ob)) { + BLI_gset_add(gs, ob); + return link; + } + } + return NULL; +} + +void BKE_scene_objects_iterator_next(BLI_Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + LinkData *link = data->link ? object_base_unique(data->visited, data->link->next) : NULL; + + if (link) { + data->link = link; + iter->current = link->data; + } + else { + /* if this is the last object of this ListBase look at the next SceneCollection */ + SceneCollection *sc; + BKE_scene_collections_iterator_next(&data->scene_collection_iter); + do { + sc = data->scene_collection_iter.current; + /* get the first unique object of this collection */ + LinkData *new_link = object_base_unique(data->visited, sc->objects.first); + if (new_link) { + data->link = new_link; + iter->current = data->link->data; + return; + } + BKE_scene_collections_iterator_next(&data->scene_collection_iter); + } while (data->scene_collection_iter.valid); + + if (!data->scene_collection_iter.valid) { + iter->valid = false; + } + } +} + +void BKE_scene_objects_iterator_end(BLI_Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + if (data) { + BKE_scene_collections_iterator_end(&data->scene_collection_iter); + BLI_gset_free(data->visited, NULL); + MEM_freeN(data); + } +} diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index ee25be36855..acb48a9646f 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -512,7 +512,7 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned // return all collision objects in scene // collision object will exclude self -Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) +Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) { Base *base; Object **objs; @@ -532,9 +532,9 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int Scene *sce_iter; /* add objects in same layer in scene */ for (SETLOOPER(scene, sce_iter, base)) { - if ( base->lay & layer ) + if ((base->flag & BASE_VISIBLED) != 0) { add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type); - + } } } @@ -547,7 +547,7 @@ Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned { /* Need to check for active layers, too. Otherwise this check fails if the objects are not on the same layer - DG */ - return get_collisionobjects_ext(scene, self, group, self->lay | scene->lay, numcollobj, modifier_type, true); + return get_collisionobjects_ext(scene, self, group, numcollobj, modifier_type, true); } static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level) @@ -600,7 +600,7 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group) /* add objects in same layer in scene */ for (SETLOOPER(scene, sce_iter, base)) { - if (!self || (base->lay & self->lay)) + if (!self || ((base->flag & BASE_VISIBLED) != 0)) add_collider_cache_object(&objs, base->object, self, 0); } diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 4c01bfd35f2..7f24f1c2e5e 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -39,6 +39,8 @@ #include "DNA_linestyle_types.h" #include "DNA_gpencil_types.h" +#include "DEG_depsgraph.h" + #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_threads.h" @@ -47,9 +49,11 @@ #include "BLT_translation.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_screen.h" #include "BKE_sound.h" +#include "BKE_workspace.h" #include "RNA_access.h" @@ -66,6 +70,7 @@ struct bContext { struct { struct wmWindowManager *manager; struct wmWindow *window; + struct WorkSpace *workspace; struct bScreen *screen; struct ScrArea *area; struct ARegion *region; @@ -627,6 +632,11 @@ wmWindow *CTX_wm_window(const bContext *C) return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window); } +WorkSpace *CTX_wm_workspace(const bContext *C) +{ + return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace); +} + bScreen *CTX_wm_screen(const bContext *C) { return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen); @@ -826,9 +836,11 @@ void CTX_wm_manager_set(bContext *C, wmWindowManager *wm) void CTX_wm_window_set(bContext *C, wmWindow *win) { C->wm.window = win; - C->wm.screen = (win) ? win->screen : NULL; - if (C->wm.screen) - C->data.scene = C->wm.screen->scene; + if (win) { + C->data.scene = win->scene; + } + C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL; + C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL; C->wm.area = NULL; C->wm.region = NULL; } @@ -836,8 +848,6 @@ void CTX_wm_window_set(bContext *C, wmWindow *win) void CTX_wm_screen_set(bContext *C, bScreen *screen) { C->wm.screen = screen; - if (C->wm.screen) - C->data.scene = C->wm.screen->scene; C->wm.area = NULL; C->wm.region = NULL; } @@ -896,10 +906,62 @@ Scene *CTX_data_scene(const bContext *C) return C->data.scene; } -int CTX_data_mode_enum(const bContext *C) +SceneLayer *CTX_data_scene_layer(const bContext *C) { - Object *obedit = CTX_data_edit_object(C); + SceneLayer *sl; + + if (ctx_data_pointer_verify(C, "render_layer", (void *)&sl)) { + return sl; + } + else { + return BKE_scene_layer_context_active(CTX_data_scene(C)); + } +} + +/** + * This is tricky. Sometimes the user overrides the render_layer + * but not the scene_collection. In this case what to do? + * + * If the scene_collection is linked to the SceneLayer we use it. + * Otherwise we fallback to the active one of the SceneLayer. + */ +LayerCollection *CTX_data_layer_collection(const bContext *C) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + LayerCollection *lc; + + if (ctx_data_pointer_verify(C, "layer_collection", (void *)&lc)) { + if (BKE_scene_layer_has_collection(sl, lc->scene_collection)) { + return lc; + } + } + /* fallback */ + return BKE_layer_collection_get_active(sl); +} + +SceneCollection *CTX_data_scene_collection(const bContext *C) +{ + SceneCollection *sc; + if (ctx_data_pointer_verify(C, "scene_collection", (void *)&sc)) { + if (BKE_scene_layer_has_collection(CTX_data_scene_layer(C), sc)) { + return sc; + } + } + + LayerCollection *lc = CTX_data_layer_collection(C); + if (lc) { + return lc->scene_collection; + } + + /* fallback */ + Scene *scene = CTX_data_scene(C); + return BKE_collection_master(scene); +} + +int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob) +{ + // Object *obedit = CTX_data_edit_object(C); if (obedit) { switch (obedit->type) { case OB_MESH: @@ -919,8 +981,7 @@ int CTX_data_mode_enum(const bContext *C) } } else { - Object *ob = CTX_data_active_object(C); - + // Object *ob = CTX_data_active_object(C); if (ob) { if (ob->mode & OB_MODE_POSE) return CTX_MODE_POSE; else if (ob->mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT; @@ -934,6 +995,12 @@ int CTX_data_mode_enum(const bContext *C) return CTX_MODE_OBJECT; } +int CTX_data_mode_enum(const bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + Object *obact = obedit ? NULL : CTX_data_active_object(C); + return CTX_data_mode_enum_ex(obedit, obact); +} /* would prefer if we can use the enum version below over this one - Campbell */ /* must be aligned with above enum */ @@ -1154,3 +1221,8 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list) return ctx_data_collection_get(C, "editable_gpencil_strokes", list); } +Depsgraph *CTX_data_depsgraph(const bContext *C) +{ + Scene *scene = CTX_data_scene(C); + return scene->depsgraph; +} diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 439abb1d593..0cfc4a99eb2 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -52,7 +52,6 @@ #include "BKE_animsys.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" @@ -64,6 +63,8 @@ #include "BKE_object.h" #include "BKE_material.h" +#include "DEG_depsgraph.h" + /* globals */ /* local */ @@ -126,6 +127,8 @@ void BKE_curve_free(Curve *cu) { BKE_animdata_free((ID *)cu, false); + BKE_curve_batch_cache_free(cu); + BKE_nurbList_free(&cu->nurb); BKE_curve_editfont_free(cu); @@ -206,6 +209,7 @@ Curve *BKE_curve_copy(Main *bmain, Curve *cu) cun->strinfo = MEM_dupallocN(cu->strinfo); cun->tb = MEM_dupallocN(cu->tb); cun->bb = MEM_dupallocN(cu->bb); + cun->batch_cache = NULL; if (cu->key) { cun->key = BKE_key_copy(bmain, cu->key); @@ -4568,7 +4572,7 @@ int BKE_curve_material_index_validate(Curve *cu) } if (!is_valid) { - DAG_id_tag_update(&cu->id, OB_RECALC_DATA); + DEG_id_tag_update(&cu->id, OB_RECALC_DATA); return true; } else { @@ -4656,3 +4660,20 @@ void BKE_curve_eval_path(EvaluationContext *UNUSED(eval_ctx), printf("%s on %s\n", __func__, curve->id.name); } } + +/* Draw Engine */ +void (*BKE_curve_batch_cache_dirty_cb)(Curve *cu, int mode) = NULL; +void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL; + +void BKE_curve_batch_cache_dirty(Curve *cu, int mode) +{ + if (cu->batch_cache) { + BKE_curve_batch_cache_dirty_cb(cu, mode); + } +} +void BKE_curve_batch_cache_free(Curve *cu) +{ + if (cu->batch_cache) { + BKE_curve_batch_cache_free_cb(cu); + } +}
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 0939d35ed8d..3ccf619fd11 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -390,37 +390,19 @@ static void layerSwap_tface(void *data, const int *corner_indices) { MTFace *tf = data; float uv[4][2]; - static const short pin_flags[4] = { TF_PIN1, TF_PIN2, TF_PIN3, TF_PIN4 }; - static const char sel_flags[4] = { TF_SEL1, TF_SEL2, TF_SEL3, TF_SEL4 }; - short unwrap = tf->unwrap & ~(TF_PIN1 | TF_PIN2 | TF_PIN3 | TF_PIN4); - char flag = tf->flag & ~(TF_SEL1 | TF_SEL2 | TF_SEL3 | TF_SEL4); int j; for (j = 0; j < 4; ++j) { const int source_index = corner_indices[j]; - copy_v2_v2(uv[j], tf->uv[source_index]); - - /* swap pinning flags around */ - if (tf->unwrap & pin_flags[source_index]) { - unwrap |= pin_flags[j]; - } - - /* swap selection flags around */ - if (tf->flag & sel_flags[source_index]) { - flag |= sel_flags[j]; - } } memcpy(tf->uv, uv, sizeof(tf->uv)); - tf->unwrap = unwrap; - tf->flag = flag; } static void layerDefault_tface(void *data, int count) { - static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, NULL, - 0, 0, TF_DYNAMIC | TF_CONVERTED, 0, 0}; + static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}}; MTFace *tf = (MTFace *)data; int i; @@ -1190,6 +1172,15 @@ static void layerSwap_flnor(void *data, const int *corner_indices) memcpy(flnors, nors, sizeof(nors)); } +static void layerDefault_fmap(void *data, int count) +{ + int *fmap_num = (int *)data; + int i; + for (i = 0; i < count; i++) { + *fmap_num = -1; + } +} + static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 0: CD_MVERT */ {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL}, @@ -1215,8 +1206,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 3 floats per normal vector */ {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal}, - /* 9: CD_POLYINDEX */ /* DEPRECATED */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 9: CD_FACEMAP */ + {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL}, /* 10: CD_PROP_FLT */ {sizeof(MFloatProperty), "MFloatProperty", 1, N_("Float"), layerCopy_propFloat, NULL, NULL, NULL}, /* 11: CD_PROP_INT */ @@ -1228,10 +1219,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face}, /* 14: CD_ORCO */ {sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, - /* 15: CD_MTEXPOLY */ + /* 15: CD_MTEXPOLY */ /* DEPRECATED */ /* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */ - {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface}, + {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, /* 16: CD_MLOOPUV */ {sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL, layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv, @@ -1310,7 +1300,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { static const char *LAYERTYPENAMES[CD_NUMTYPES] = { /* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", - /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags", + /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFaceMap", /* 10-14 */ "CDMFloatProperty", "CDMIntProperty", "CDMStringProperty", "CDOrigSpace", "CDOrco", /* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps", /* 20-24 */ "CDPreviewMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast", @@ -1325,41 +1315,41 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { const CustomDataMask CD_MASK_BAREMESH = - CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT; + CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_MESH = CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP | - CD_MASK_MTEXPOLY | CD_MASK_RECAST | CD_MASK_PAINT_MASK | + CD_MASK_RECAST | CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_EDITMESH = CD_MASK_MDEFORMVERT | CD_MASK_MLOOPUV | - CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX | + CD_MASK_MLOOPCOL | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_PAINT_MASK | - CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_DERIVEDMESH = CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO | - CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL | + CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_PREVIEW_MCOL | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_BMESH = - CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | + CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS | CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; /** * cover values copied by #BKE_mesh_loops_to_tessdata */ const CustomDataMask CD_MASK_FACECORNERS = - CD_MASK_MTFACE | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | + CD_MASK_MTFACE | CD_MASK_MLOOPUV | CD_MASK_MCOL | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | @@ -1368,7 +1358,7 @@ const CustomDataMask CD_MASK_FACECORNERS = const CustomDataMask CD_MASK_EVERYTHING = CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT | - CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | + CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_TANGENT | CD_MASK_MDISPS | CD_MASK_PREVIEW_MCOL | CD_MASK_CLOTH_ORCO | CD_MASK_RECAST | /* BMESH ONLY START */ CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_SHAPE_KEYINDEX | CD_MASK_SHAPEKEY | CD_MASK_BWEIGHT | CD_MASK_CREASE | @@ -1376,7 +1366,7 @@ const CustomDataMask CD_MASK_EVERYTHING = /* BMESH ONLY END */ CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; static const LayerTypeInfo *layerType_getInfo(int type) { @@ -2502,13 +2492,10 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou /* BMesh functions */ /* needed to convert to/from different face reps */ -void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, - int totloop, int totpoly) +void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop) { - int i; - for (i = 0; i < fdata->totlayer; i++) { + for (int i = 0; i < fdata->totlayer; i++) { if (fdata->layers[i].type == CD_MTFACE) { - CustomData_add_layer_named(pdata, CD_MTEXPOLY, CD_CALLOC, NULL, totpoly, fdata->layers[i].name); CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MCOL) { @@ -2523,19 +2510,18 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *l } } -void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total) +void CustomData_from_bmeshpoly( + CustomData *fdata, CustomData *ldata, int total) { int i; /* avoid accumulating extra layers */ - BLI_assert(!CustomData_from_bmeshpoly_test(fdata, pdata, ldata, false)); + BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false)); - for (i = 0; i < pdata->totlayer; i++) { - if (pdata->layers[i].type == CD_MTEXPOLY) { - CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name); - } - } for (i = 0; i < ldata->totlayer; i++) { + if (ldata->layers[i].type == CD_MLOOPUV) { + CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name); + } if (ldata->layers[i].type == CD_MLOOPCOL) { CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name); } @@ -2553,7 +2539,7 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData } } - CustomData_bmesh_update_active_layers(fdata, pdata, ldata); + CustomData_bmesh_update_active_layers(fdata, ldata); } #ifndef NDEBUG @@ -2563,13 +2549,13 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData * \param fallback: Use when there are no layers to handle, * since callers may expect success or failure. */ -bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback) +bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback) { int a_num = 0, b_num = 0; #define LAYER_CMP(l_a, t_a, l_b, t_b) \ ((a_num += CustomData_number_of_layers(l_a, t_a)) == (b_num += CustomData_number_of_layers(l_b, t_b))) - if (!LAYER_CMP(pdata, CD_MTEXPOLY, fdata, CD_MTFACE)) + if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE)) return false; if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL)) return false; @@ -2591,25 +2577,21 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom #endif -void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata) +void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata) { int act; - if (CustomData_has_layer(pdata, CD_MTEXPOLY)) { - act = CustomData_get_active_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_active(ldata, CD_MLOOPUV, act); + if (CustomData_has_layer(ldata, CD_MLOOPUV)) { + act = CustomData_get_active_layer(ldata, CD_MLOOPUV); CustomData_set_layer_active(fdata, CD_MTFACE, act); - act = CustomData_get_render_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_render(ldata, CD_MLOOPUV, act); + act = CustomData_get_render_layer(ldata, CD_MLOOPUV); CustomData_set_layer_render(fdata, CD_MTFACE, act); - act = CustomData_get_clone_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_clone(ldata, CD_MLOOPUV, act); + act = CustomData_get_clone_layer(ldata, CD_MLOOPUV); CustomData_set_layer_clone(fdata, CD_MTFACE, act); - act = CustomData_get_stencil_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act); + act = CustomData_get_stencil_layer(ldata, CD_MLOOPUV); CustomData_set_layer_stencil(fdata, CD_MTFACE, act); } @@ -2633,25 +2615,21 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, * used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files */ -void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata) +void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata) { int act; if (CustomData_has_layer(fdata, CD_MTFACE)) { act = CustomData_get_active_layer(fdata, CD_MTFACE); - CustomData_set_layer_active(pdata, CD_MTEXPOLY, act); CustomData_set_layer_active(ldata, CD_MLOOPUV, act); act = CustomData_get_render_layer(fdata, CD_MTFACE); - CustomData_set_layer_render(pdata, CD_MTEXPOLY, act); CustomData_set_layer_render(ldata, CD_MLOOPUV, act); act = CustomData_get_clone_layer(fdata, CD_MTFACE); - CustomData_set_layer_clone(pdata, CD_MTEXPOLY, act); CustomData_set_layer_clone(ldata, CD_MLOOPUV, act); act = CustomData_get_stencil_layer(fdata, CD_MTFACE); - CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, act); CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act); } diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 3bc09c0173b..a83ec8f0486 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -79,7 +79,7 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types cddata_mask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */ } else if (cddata_type == CD_FAKE_UV) { - cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV; + cddata_mask |= CD_MASK_MLOOPUV; } else if (cddata_type == CD_FAKE_LNOR) { cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; @@ -962,7 +962,7 @@ static bool data_transfer_layersmapping_generate( } else if (elem_type == ME_POLY) { if (cddata_type == CD_FAKE_UV) { - cddata_type = CD_MTEXPOLY; + cddata_type = CD_MLOOPUV; } if (!(cddata_type & CD_FAKE)) { diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 13b1aab5e1c..3b91534e321 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -54,6 +54,7 @@ #include "BKE_customdata.h" #include "BKE_data_transfer.h" #include "BKE_deform.h" /* own include */ +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_object_deform.h" @@ -73,6 +74,8 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name) BLI_addtail(&ob->defbase, defgroup); defgroup_unique_name(defgroup, ob); + BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_PAINT); + return defgroup; } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c deleted file mode 100644 index 019e0df1623..00000000000 --- a/source/blender/blenkernel/intern/depsgraph.c +++ /dev/null @@ -1,3700 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/depsgraph.c - * \ingroup bke - */ - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#ifdef WIN32 -# include "BLI_winstuff.h" -#endif - -#include "BLI_utildefines.h" -#include "BLI_listbase.h" -#include "BLI_ghash.h" -#include "BLI_threads.h" - -#include "DNA_anim_types.h" -#include "DNA_camera_types.h" -#include "DNA_cachefile_types.h" -#include "DNA_group_types.h" -#include "DNA_lamp_types.h" -#include "DNA_lattice_types.h" -#include "DNA_key_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_node_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_windowmanager_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_mask_types.h" -#include "DNA_modifier_types.h" -#include "DNA_rigidbody_types.h" - -#include "BKE_anim.h" -#include "BKE_animsys.h" -#include "BKE_action.h" -#include "BKE_DerivedMesh.h" -#include "BKE_collision.h" -#include "BKE_effect.h" -#include "BKE_fcurve.h" -#include "BKE_global.h" -#include "BKE_idcode.h" -#include "BKE_image.h" -#include "BKE_key.h" -#include "BKE_library.h" -#include "BKE_main.h" -#include "BKE_node.h" -#include "BKE_material.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" -#include "BKE_pointcache.h" -#include "BKE_scene.h" -#include "BKE_screen.h" -#include "BKE_tracking.h" - -#include "GPU_buffers.h" - -#include "atomic_ops.h" - -#include "depsgraph_private.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_build.h" -#include "DEG_depsgraph_debug.h" -#include "DEG_depsgraph_query.h" - -#ifdef WITH_LEGACY_DEPSGRAPH - -static SpinLock threaded_update_lock; - -void DAG_init(void) -{ - BLI_spin_init(&threaded_update_lock); - DEG_register_node_types(); -} - -void DAG_exit(void) -{ - BLI_spin_end(&threaded_update_lock); - DEG_free_node_types(); -} - -/* Queue and stack operations for dag traversal - * - * the queue store a list of freenodes to avoid successive alloc/dealloc - */ - -DagNodeQueue *queue_create(int slots) -{ - DagNodeQueue *queue; - DagNodeQueueElem *elem; - int i; - - queue = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue"); - queue->freenodes = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue"); - queue->count = 0; - queue->maxlevel = 0; - queue->first = queue->last = NULL; - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem3"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < slots; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem4"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = slots; - return queue; -} - -void queue_raz(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - - elem = queue->first; - if (queue->freenodes->last) - queue->freenodes->last->next = elem; - else - queue->freenodes->first = queue->freenodes->last = elem; - - elem->node = NULL; - queue->freenodes->count++; - while (elem->next) { - elem = elem->next; - elem->node = NULL; - queue->freenodes->count++; - } - queue->freenodes->last = elem; - queue->count = 0; -} - -void queue_delete(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - DagNodeQueueElem *temp; - - elem = queue->first; - while (elem) { - temp = elem; - elem = elem->next; - MEM_freeN(temp); - } - - elem = queue->freenodes->first; - while (elem) { - temp = elem; - elem = elem->next; - MEM_freeN(temp); - } - - MEM_freeN(queue->freenodes); - MEM_freeN(queue); -} - -/* insert in queue, remove in front */ -void push_queue(DagNodeQueue *queue, DagNode *node) -{ - DagNodeQueueElem *elem; - int i; - - if (node == NULL) { - fprintf(stderr, "pushing null node\n"); - return; - } - /*fprintf(stderr, "BFS push : %s %d\n", ((ID *) node->ob)->name, queue->count);*/ - - elem = queue->freenodes->first; - if (elem != NULL) { - queue->freenodes->first = elem->next; - if (queue->freenodes->last == elem) { - queue->freenodes->last = NULL; - queue->freenodes->first = NULL; - } - queue->freenodes->count--; - } - else { /* alllocating more */ - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < DAGQUEUEALLOC; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = DAGQUEUEALLOC; - - elem = queue->freenodes->first; - queue->freenodes->first = elem->next; - } - elem->next = NULL; - elem->node = node; - if (queue->last != NULL) - queue->last->next = elem; - queue->last = elem; - if (queue->first == NULL) { - queue->first = elem; - } - queue->count++; -} - - -/* insert in front, remove in front */ -void push_stack(DagNodeQueue *queue, DagNode *node) -{ - DagNodeQueueElem *elem; - int i; - - elem = queue->freenodes->first; - if (elem != NULL) { - queue->freenodes->first = elem->next; - if (queue->freenodes->last == elem) { - queue->freenodes->last = NULL; - queue->freenodes->first = NULL; - } - queue->freenodes->count--; - } - else { /* alllocating more */ - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < DAGQUEUEALLOC; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = DAGQUEUEALLOC; - - elem = queue->freenodes->first; - queue->freenodes->first = elem->next; - } - elem->next = queue->first; - elem->node = node; - queue->first = elem; - if (queue->last == NULL) - queue->last = elem; - queue->count++; -} - - -DagNode *pop_queue(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - DagNode *node; - - elem = queue->first; - if (elem) { - queue->first = elem->next; - if (queue->last == elem) { - queue->last = NULL; - queue->first = NULL; - } - queue->count--; - if (queue->freenodes->last) - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - if (queue->freenodes->first == NULL) - queue->freenodes->first = elem; - node = elem->node; - elem->node = NULL; - elem->next = NULL; - queue->freenodes->count++; - return node; - } - else { - fprintf(stderr, "return null\n"); - return NULL; - } -} - -DagNode *get_top_node_queue(DagNodeQueue *queue) -{ - return queue->first->node; -} - -DagForest *dag_init(void) -{ - DagForest *forest; - /* use callocN to init all zero */ - forest = MEM_callocN(sizeof(DagForest), "DAG root"); - forest->ugly_hack_sorry = true; - return forest; -} - -/* isdata = object data... */ -/* XXX this needs to be extended to be more flexible (so that not only objects are evaluated via depsgraph)... */ -static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node, int isdata) -{ - FCurve *fcu; - DagNode *node1; - - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - int isdata_fcu = (isdata) || (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")); - - /* loop over variables to get the target relationships */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* only used targets */ - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id) { - /* FIXME: other data types need to be added here so that they can work! */ - if (GS(dtar->id->name) == ID_OB) { - Object *ob = (Object *)dtar->id; - - /* normal channel-drives-channel */ - node1 = dag_get_node(dag, dtar->id); - - /* check if bone... */ - if ((ob->type == OB_ARMATURE) && - ( ((dtar->rna_path) && strstr(dtar->rna_path, "pose.bones[")) || - ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) )) - { - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver"); - } - /* check if ob data */ - else if (dtar->rna_path && strstr(dtar->rna_path, "data.")) - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver"); - /* normal */ - else - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_OB_DATA : DAG_RL_OB_OB, "Driver"); - } - } - } - DRIVER_TARGETS_LOOPER_END - } - } -} - -/* XXX: forward def for material driver handling... */ -static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma); - -/* recursive handling for shader nodetree drivers */ -static void dag_add_shader_nodetree_driver_relations(DagForest *dag, DagNode *node, bNodeTree *ntree) -{ - bNode *n; - - /* nodetree itself */ - if (ntree->adt) { - dag_add_driver_relation(ntree->adt, dag, node, 1); - } - - /* nodetree's nodes... */ - for (n = ntree->nodes.first; n; n = n->next) { - if (n->id) { - if (GS(n->id->name) == ID_MA) { - dag_add_material_driver_relations(dag, node, (Material *)n->id); - } - else if (n->type == NODE_GROUP) { - dag_add_shader_nodetree_driver_relations(dag, node, (bNodeTree *)n->id); - } - } - } -} - -/* recursive handling for material drivers */ -static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma) -{ - /* Prevent infinite recursion by checking (and tagging the material) as having been visited - * already (see build_dag()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (ma->id.tag & LIB_TAG_DOIT) - return; - - ma->id.tag |= LIB_TAG_DOIT; - - /* material itself */ - if (ma->adt) - dag_add_driver_relation(ma->adt, dag, node, 1); - - /* textures */ - // TODO... - //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); - - /* material's nodetree */ - if (ma->nodetree) - dag_add_shader_nodetree_driver_relations(dag, node, ma->nodetree); - - ma->id.tag &= ~LIB_TAG_DOIT; -} - -/* recursive handling for lamp drivers */ -static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *la) -{ - /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited - * already (see build_dag()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (la->id.tag & LIB_TAG_DOIT) - return; - - la->id.tag |= LIB_TAG_DOIT; - - /* lamp itself */ - if (la->adt) - dag_add_driver_relation(la->adt, dag, node, 1); - - /* textures */ - // TODO... - //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); - - /* lamp's nodetree */ - if (la->nodetree) - dag_add_shader_nodetree_driver_relations(dag, node, la->nodetree); - - la->id.tag &= ~LIB_TAG_DOIT; -} - -static void create_collision_relation(DagForest *dag, DagNode *node, Object *ob1, const char *name) -{ - DagNode *node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, name); -} - -void dag_add_collision_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name) -{ - unsigned int numcollobj; - Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli); - - for (unsigned int i = 0; i < numcollobj; i++) { - Object *ob1 = collobjs[i]; - - if (!fn || fn(ob1, modifiers_findByType(ob1, modifier_type))) { - create_collision_relation(dag, node, ob1, name); - } - } - - if (collobjs) - MEM_freeN(collobjs); -} - -void dag_add_forcefield_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name) -{ - ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false); - - if (effectors) { - for (EffectorCache *eff = effectors->first; eff; eff = eff->next) { - if (eff->ob != ob && eff->pd->forcefield != skip_forcefield) { - create_collision_relation(dag, node, eff->ob, name); - - if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) { - create_collision_relation(dag, node, eff->pd->f_source, "Smoke Force Domain"); - } - - if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) { - /* Actual code uses get_collider_cache */ - dag_add_collision_relations(dag, scene, ob, node, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption"); - } - } - } - } - - pdEndEffectors(&effectors); -} - -static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Object *ob, int mask) -{ - bConstraint *con; - DagNode *node; - DagNode *node2; - DagNode *node3; - Key *key; - ParticleSystem *psys; - int addtoroot = 1; - - node = dag_get_node(dag, ob); - - if ((ob->data) && (mask & DAG_RL_DATA)) { - node2 = dag_get_node(dag, ob->data); - dag_add_relation(dag, node, node2, DAG_RL_DATA, "Object-Data Relation"); - node2->first_ancestor = ob; - node2->ancestor_count += 1; - } - - /* also build a custom data mask for dependencies that need certain layers */ - - if (ob->type == OB_ARMATURE) { - if (ob->pose) { - bPoseChannel *pchan; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar && ct->tar != ob) { - // fprintf(stderr, "armature %s target :%s\n", ob->id.name, target->id.name); - node3 = dag_get_node(dag, ct->tar); - - if (ct->subtarget[0]) { - dag_add_relation(dag, node3, node, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, cti->name); - if (ct->tar->type == OB_MESH) - node3->customdata_mask |= CD_MASK_MDEFORMVERT; - } - else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, - CONSTRAINT_TYPE_CLAMPTO, - CONSTRAINT_TYPE_SPLINEIK, - CONSTRAINT_TYPE_SHRINKWRAP)) - { - dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name); - } - else { - dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name); - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - - } - } - } - } - - /* driver dependencies, nla modifiers */ -#if 0 // XXX old animation system - if (ob->nlastrips.first) { - bActionStrip *strip; - bActionChannel *chan; - for (strip = ob->nlastrips.first; strip; strip = strip->next) { - if (strip->modifiers.first) { - bActionModifier *amod; - for (amod = strip->modifiers.first; amod; amod = amod->next) { - if (amod->ob) { - node2 = dag_get_node(dag, amod->ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "NLA Strip Modifier"); - } - } - } - } - } -#endif // XXX old animation system - if (ob->adt) - dag_add_driver_relation(ob->adt, dag, node, (ob->type == OB_ARMATURE)); // XXX isdata arg here doesn't give an accurate picture of situation - - key = BKE_key_from_object(ob); - if (key && key->adt) - dag_add_driver_relation(key->adt, dag, node, 1); - - if (ob->modifiers.first) { - ModifierData *md; - - for (md = ob->modifiers.first; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - - if (mti->updateDepgraph) mti->updateDepgraph(md, dag, bmain, scene, ob, node); - } - } - if (ob->parent) { - node2 = dag_get_node(dag, ob->parent); - - switch (ob->partype) { - case PARSKEL: - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Parent"); - break; - case PARVERT1: case PARVERT3: - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Vertex Parent"); - node2->customdata_mask |= CD_MASK_ORIGINDEX; - break; - case PARBONE: - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Bone Parent"); - break; - default: - if (ob->parent->type == OB_LATTICE) - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Lattice Parent"); - else if (ob->parent->type == OB_CURVE) { - Curve *cu = ob->parent->data; - if (cu->flag & CU_PATH) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Curve Parent"); - else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Curve Parent"); - } - else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Parent"); - break; - } - /* exception case: parent is duplivert */ - if (ob->type == OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert"); - } - - addtoroot = 0; - } - if (ob->proxy) { - node2 = dag_get_node(dag, ob->proxy); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Proxy"); - /* inverted relation, so addtoroot shouldn't be set to zero */ - } - - if (ob->transflag & OB_DUPLI) { - if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { - GroupObject *go; - for (go = ob->dup_group->gobject.first; go; go = go->next) { - if (go->ob) { - node2 = dag_get_node(dag, go->ob); - /* node2 changes node1, this keeps animations updated in groups?? not logical? */ - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Dupligroup"); - } - } - } - } - - /* rigidbody force fields */ - if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) { - if (ob->rigidbody_object && scene->rigidbody_world) { - dag_add_forcefield_relations(dag, scene, ob, node, scene->rigidbody_world->effector_weights, true, 0, "Force Field"); - } - } - - /* object data drivers */ - if (ob->data) { - AnimData *adt = BKE_animdata_from_id((ID *)ob->data); - if (adt) - dag_add_driver_relation(adt, dag, node, 1); - } - - /* object type/data relationships */ - switch (ob->type) { - case OB_CAMERA: - { - Camera *cam = (Camera *)ob->data; - - if (cam->dof_ob) { - node2 = dag_get_node(dag, cam->dof_ob); - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Camera DoF"); - } - break; - } - case OB_MBALL: - { - Object *mom = BKE_mball_basis_find(scene, ob); - - if (mom != ob) { - node2 = dag_get_node(dag, mom); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Metaball"); /* mom depends on children! */ - } - break; - } - case OB_CURVE: - case OB_FONT: - { - Curve *cu = ob->data; - - if (cu->bevobj) { - node2 = dag_get_node(dag, cu->bevobj); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Bevel"); - } - if (cu->taperobj) { - node2 = dag_get_node(dag, cu->taperobj); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper"); - } - if (ob->type == OB_FONT) { - /* Really rather dirty hack. needs to support font family to work - * reliably on render export. - * - * This totally mimics behavior of regular verts duplication with - * parenting. The only tricky thing here is to get list of objects - * used for the custom "font". - * - * This shouldn't harm so much because this code only runs on DAG - * rebuild and this feature is not that commonly used. - * - * - sergey - - */ - if (cu->family[0] != '\n') { - ListBase *duplilist; - DupliObject *dob; - duplilist = object_duplilist(G.main->eval_ctx, scene, ob); - for (dob = duplilist->first; dob; dob = dob->next) { - node2 = dag_get_node(dag, dob->ob); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font"); - } - free_object_duplilist(duplilist); - } - - if (cu->textoncurve) { - node2 = dag_get_node(dag, cu->textoncurve); - /* Text on curve requires path to be evaluated for the target curve. */ - node2->eval_flags |= DAG_EVAL_NEED_CURVE_PATH; - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Texture On Curve"); - } - } - break; - } - } - - /* material drivers */ - if (ob->totcol) { - int a; - - for (a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - - if (ma) { - /* recursively figure out if there are drivers, and hook these up to this object */ - dag_add_material_driver_relations(dag, node, ma); - } - } - } - else if (ob->type == OB_LAMP) { - dag_add_lamp_driver_relations(dag, node, ob->data); - } - - /* particles */ - psys = ob->particlesystem.first; - if (psys) { - GroupObject *go; - - for (; psys; psys = psys->next) { - BoidRule *rule = NULL; - BoidState *state = NULL; - ParticleSettings *part = psys->part; - - if (part->adt) { - dag_add_driver_relation(part->adt, dag, node, 1); - } - - dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); - - if (!psys_check_enabled(ob, psys, G.is_rendering)) - continue; - - if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) { - ParticleTarget *pt = psys->targets.first; - - for (; pt; pt = pt->next) { - if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) { - node2 = dag_get_node(dag, pt->ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets"); - } - } - } - - if (part->ren_as == PART_DRAW_OB && part->dup_ob) { - node2 = dag_get_node(dag, part->dup_ob); - /* note that this relation actually runs in the wrong direction, the problem - * is that dupli system all have this (due to parenting), and the render - * engine instancing assumes particular ordering of objects in list */ - dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization"); - if (part->dup_ob->type == OB_MBALL) - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization"); - } - - if (part->ren_as == PART_DRAW_GR && part->dup_group) { - for (go = part->dup_group->gobject.first; go; go = go->next) { - node2 = dag_get_node(dag, go->ob); - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization"); - } - } - - if (part->type != PART_HAIR) { - /* Actual code uses get_collider_cache */ - dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision"); - } - else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) { - /* Hair uses cloth simulation, i.e. get_collision_objects */ - dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision"); - } - - dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field"); - - if (part->boids) { - for (state = part->boids->states.first; state; state = state->next) { - for (rule = state->rules.first; rule; rule = rule->next) { - Object *ruleob = NULL; - if (rule->type == eBoidRuleType_Avoid) - ruleob = ((BoidRuleGoalAvoid *)rule)->ob; - else if (rule->type == eBoidRuleType_FollowLeader) - ruleob = ((BoidRuleFollowLeader *)rule)->ob; - - if (ruleob) { - node2 = dag_get_node(dag, ruleob); - dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule"); - } - } - } - } - } - } - - /* object constraints */ - for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (!cti) - continue; - - /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { - int depends_on_camera = 0; - - if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; - - if ((data->clip || data->flag & FOLLOWTRACK_ACTIVECLIP) && data->track[0]) - depends_on_camera = 1; - - if (data->depth_ob) { - node2 = dag_get_node(dag, data->depth_ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - } - } - else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) - depends_on_camera = 1; - - if (depends_on_camera && scene->camera) { - node2 = dag_get_node(dag, scene->camera); - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - } - - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); - addtoroot = 0; - } - else if (cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - Object *obt; - - if (ct->tar) - obt = ct->tar; - else - continue; - - node2 = dag_get_node(dag, obt); - if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - else { - if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - if (obt->type == OB_MESH) - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - else if (cti->type == CONSTRAINT_TYPE_SHRINKWRAP) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name); - } - else { - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name); - } - } - addtoroot = 0; - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - } - - if (addtoroot == 1) - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); -} - -static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Group *group, short mask) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - build_dag_object(dag, scenenode, bmain, scene, go->ob, mask); - if (go->ob->dup_group) - build_dag_group(dag, scenenode, bmain, scene, go->ob->dup_group, mask); - } -} - -DagForest *build_dag(Main *bmain, Scene *sce, short mask) -{ - Base *base; - Object *ob; - DagNode *node; - DagNode *scenenode; - DagForest *dag; - DagAdjList *itA; - - dag = sce->theDag; - if (dag) - free_forest(dag); - else { - dag = dag_init(); - sce->theDag = dag; - } - dag->need_update = false; - - BKE_main_id_tag_idcode(bmain, ID_OB, LIB_TAG_DOIT, false); - - /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */ - BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* add base node for scene. scene is always the first node in DAG */ - scenenode = dag_add_node(dag, sce); - - /* add current scene objects */ - for (base = sce->base.first; base; base = base->next) { - ob = base->object; - ob->id.tag |= LIB_TAG_DOIT; - build_dag_object(dag, scenenode, bmain, sce, ob, mask); - if (ob->proxy) - build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask); - if (ob->dup_group) - build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask); - } - - /* There might be situations when object from current scene depends on - * objects form other scene AND objects from other scene has own - * dependencies on objects from other scene. - * - * This is really important to include such indirect dependencies in order - * to keep threaded update safe but since we don't really know if object is - * coming from current scene or another scene we do rather stupid tag-based - * check here: all the objects for which build_dag_object() was called are - * getting tagged with LIB_TAG_DOIT. This way if some node has untagged - * object we know it's an object from other scene. - * - * It should be enough to to it once, because if there's longer chain of - * indirect dependencies, all the new nodes will be added to the end of the - * list, meaning we'll keep covering them in this for loop. - */ - for (node = sce->theDag->DagNode.first; node != NULL; node = node->next) { - if (node->type == ID_OB) { - ob = node->ob; - if ((ob->id.tag & LIB_TAG_DOIT) == 0) { - ob->id.tag |= LIB_TAG_DOIT; - build_dag_object(dag, scenenode, bmain, sce, ob, mask); - if (ob->proxy) - build_dag_object(dag, scenenode, bmain, sce, ob->proxy, mask); - if (ob->dup_group) - build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask); - } - } - } - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* Now all relations were built, but we need to solve 1 exceptional case; - * When objects have multiple "parents" (for example parent + constraint working on same object) - * the relation type has to be synced. One of the parents can change, and should give same event to child */ - - /* nodes were callocced, so we can use node->color for temporal storage */ - for (node = sce->theDag->DagNode.first; node; node = node->next) { - if (node->type == ID_OB) { - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - itA->node->color |= itA->type; - } - } - - /* also flush custom data mask */ - ((Object *)node->ob)->customdata_mask = node->customdata_mask; - - if (node->parent == NULL) { - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); - } - } - } - /* now set relations equal, so that when only one parent changes, the correct recalcs are found */ - for (node = sce->theDag->DagNode.first; node; node = node->next) { - if (node->type == ID_OB) { - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - itA->type |= itA->node->color; - } - } - } - } - - /* cycle detection and solving */ - // solve_cycles(dag); - - return dag; -} - - -void free_forest(DagForest *Dag) -{ /* remove all nodes and deps */ - DagNode *tempN; - DagAdjList *tempA; - DagAdjList *itA; - DagNode *itN = Dag->DagNode.first; - - while (itN) { - itA = itN->child; - while (itA) { - tempA = itA; - itA = itA->next; - MEM_freeN(tempA); - } - - itA = itN->parent; - while (itA) { - tempA = itA; - itA = itA->next; - MEM_freeN(tempA); - } - - tempN = itN; - itN = itN->next; - MEM_freeN(tempN); - } - - BLI_ghash_free(Dag->nodeHash, NULL, NULL); - Dag->nodeHash = NULL; - Dag->DagNode.first = NULL; - Dag->DagNode.last = NULL; - Dag->numNodes = 0; - -} - -DagNode *dag_find_node(DagForest *forest, void *fob) -{ - if (forest->nodeHash) - return BLI_ghash_lookup(forest->nodeHash, fob); - - return NULL; -} - -static int dag_print_dependencies = 0; /* debugging */ - -/* no checking of existence, use dag_find_node first or dag_get_node */ -DagNode *dag_add_node(DagForest *forest, void *fob) -{ - DagNode *node; - - node = MEM_callocN(sizeof(DagNode), "DAG node"); - if (node) { - node->ob = fob; - node->color = DAG_WHITE; - - if (forest->ugly_hack_sorry) node->type = GS(((ID *) fob)->name); /* sorry, done for pose sorting */ - if (forest->numNodes) { - ((DagNode *) forest->DagNode.last)->next = node; - forest->DagNode.last = node; - forest->numNodes++; - } - else { - forest->DagNode.last = node; - forest->DagNode.first = node; - forest->numNodes = 1; - } - - if (!forest->nodeHash) - forest->nodeHash = BLI_ghash_ptr_new("dag_add_node gh"); - BLI_ghash_insert(forest->nodeHash, fob, node); - } - - return node; -} - -DagNode *dag_get_node(DagForest *forest, void *fob) -{ - DagNode *node; - - node = dag_find_node(forest, fob); - if (!node) - node = dag_add_node(forest, fob); - return node; -} - - - -DagNode *dag_get_sub_node(DagForest *forest, void *fob) -{ - DagNode *node; - DagAdjList *mainchild, *prev = NULL; - - mainchild = ((DagNode *) forest->DagNode.first)->child; - /* remove from first node (scene) adj list if present */ - while (mainchild) { - if (mainchild->node == fob) { - if (prev) { - prev->next = mainchild->next; - MEM_freeN(mainchild); - break; - } - else { - ((DagNode *) forest->DagNode.first)->child = mainchild->next; - MEM_freeN(mainchild); - break; - } - } - prev = mainchild; - mainchild = mainchild->next; - } - node = dag_find_node(forest, fob); - if (!node) - node = dag_add_node(forest, fob); - return node; -} - -static void dag_add_parent_relation(DagForest *UNUSED(forest), DagNode *fob1, DagNode *fob2, short rel, const char *name) -{ - DagAdjList *itA = fob2->parent; - - while (itA) { /* search if relation exist already */ - if (itA->node == fob1) { - itA->type |= rel; - itA->count += 1; - return; - } - itA = itA->next; - } - /* create new relation and insert at head. MALLOC alert! */ - itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list"); - itA->node = fob1; - itA->type = rel; - itA->count = 1; - itA->next = fob2->parent; - itA->name = name; - fob2->parent = itA; -} - -void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name) -{ - DagAdjList *itA = fob1->child; - - /* parent relation is for cycle checking */ - dag_add_parent_relation(forest, fob1, fob2, rel, name); - - /* TODO(sergey): Find a better place for this. */ -#ifdef WITH_OPENSUBDIV - if ((rel & (DAG_RL_DATA_DATA | DAG_RL_DATA_OB)) != 0) { - if (fob1->type == ID_OB) { - if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) { - Object *ob2 = fob2->ob; - if (ob2->recalc & OB_RECALC_ALL) { - /* Make sure object has all the data on CPU. */ - Object *ob1 = fob1->ob; - ob1->recalc |= OB_RECALC_DATA; - } - fob1->eval_flags |= DAG_EVAL_NEED_CPU; - } - } - } -#endif - - while (itA) { /* search if relation exist already */ - if (itA->node == fob2) { - itA->type |= rel; - itA->count += 1; - return; - } - itA = itA->next; - } - /* create new relation and insert at head. MALLOC alert! */ - itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list"); - itA->node = fob2; - itA->type = rel; - itA->count = 1; - itA->next = fob1->child; - itA->name = name; - fob1->child = itA; -} - -static const char *dag_node_name(DagForest *dag, DagNode *node) -{ - if (node->ob == NULL) - return "null"; - else if (dag->ugly_hack_sorry) - return ((ID *)(node->ob))->name + 2; - else - return ((bPoseChannel *)(node->ob))->name; -} - -static void dag_node_print_dependencies(DagForest *dag, DagNode *node) -{ - DagAdjList *itA; - - printf("%s depends on:\n", dag_node_name(dag, node)); - - for (itA = node->parent; itA; itA = itA->next) - printf(" %s through %s\n", dag_node_name(dag, itA->node), itA->name); - printf("\n"); -} - -static int dag_node_print_dependency_recurs(DagForest *dag, DagNode *node, DagNode *endnode) -{ - DagAdjList *itA; - - if (node->color == DAG_BLACK) - return 0; - - node->color = DAG_BLACK; - - if (node == endnode) - return 1; - - for (itA = node->parent; itA; itA = itA->next) { - if (dag_node_print_dependency_recurs(dag, itA->node, endnode)) { - printf(" %s depends on %s through %s.\n", dag_node_name(dag, node), dag_node_name(dag, itA->node), itA->name); - return 1; - } - } - - return 0; -} - -static void dag_node_print_dependency_cycle(DagForest *dag, DagNode *startnode, DagNode *endnode, const char *name) -{ - DagNode *node; - - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - printf(" %s depends on %s through %s.\n", dag_node_name(dag, endnode), dag_node_name(dag, startnode), name); - dag_node_print_dependency_recurs(dag, startnode, endnode); - printf("\n"); -} - -static int dag_node_recurs_level(DagNode *node, int level) -{ - DagAdjList *itA; - int newlevel; - - node->color = DAG_BLACK; /* done */ - newlevel = ++level; - - for (itA = node->parent; itA; itA = itA->next) { - if (itA->node->color == DAG_WHITE) { - itA->node->ancestor_count = dag_node_recurs_level(itA->node, level); - newlevel = MAX2(newlevel, level + itA->node->ancestor_count); - } - else - newlevel = MAX2(newlevel, level + itA->node->ancestor_count); - } - - return newlevel; -} - -static void dag_check_cycle(DagForest *dag) -{ - DagNode *node; - DagAdjList *itA; - - dag->is_acyclic = true; - - /* debugging print */ - if (dag_print_dependencies) - for (node = dag->DagNode.first; node; node = node->next) - dag_node_print_dependencies(dag, node); - - /* tag nodes unchecked */ - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - for (node = dag->DagNode.first; node; node = node->next) { - if (node->color == DAG_WHITE) { - node->ancestor_count = dag_node_recurs_level(node, 0); - } - } - - /* check relations, and print errors */ - for (node = dag->DagNode.first; node; node = node->next) { - for (itA = node->parent; itA; itA = itA->next) { - if (itA->node->ancestor_count > node->ancestor_count) { - if (node->ob && itA->node->ob) { - dag->is_acyclic = false; - printf("Dependency cycle detected:\n"); - dag_node_print_dependency_cycle(dag, itA->node, node, itA->name); - } - } - } - } - - /* parent relations are only needed for cycle checking, so free now */ - for (node = dag->DagNode.first; node; node = node->next) { - while (node->parent) { - itA = node->parent->next; - MEM_freeN(node->parent); - node->parent = itA; - } - } -} - -/* debug test functions */ - -void graph_print_queue(DagNodeQueue *nqueue) -{ - DagNodeQueueElem *queueElem; - - queueElem = nqueue->first; - while (queueElem) { - fprintf(stderr, "** %s %i %i-%i ", ((ID *) queueElem->node->ob)->name, queueElem->node->color, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm); - queueElem = queueElem->next; - } - fprintf(stderr, "\n"); -} - -void graph_print_queue_dist(DagNodeQueue *nqueue) -{ - DagNodeQueueElem *queueElem; - int count; - - queueElem = nqueue->first; - count = 0; - while (queueElem) { - fprintf(stderr, "** %25s %2.2i-%2.2i ", ((ID *) queueElem->node->ob)->name, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm); - while (count < queueElem->node->DFS_dvtm - 1) { fputc(' ', stderr); count++; } - fputc('|', stderr); - while (count < queueElem->node->DFS_fntm - 2) { fputc('-', stderr); count++; } - fputc('|', stderr); - fputc('\n', stderr); - count = 0; - queueElem = queueElem->next; - } - fprintf(stderr, "\n"); -} - -void graph_print_adj_list(DagForest *dag) -{ - DagNode *node; - DagAdjList *itA; - - node = dag->DagNode.first; - while (node) { - fprintf(stderr, "node : %s col: %i", ((ID *) node->ob)->name, node->color); - itA = node->child; - while (itA) { - fprintf(stderr, "-- %s ", ((ID *) itA->node->ob)->name); - - itA = itA->next; - } - fprintf(stderr, "\n"); - node = node->next; - } -} - -/* ************************ API *********************** */ - -/* mechanism to allow editors to be informed of depsgraph updates, - * to do their own updates based on changes... */ -static void (*EditorsUpdateIDCb)(Main *bmain, ID *id) = NULL; -static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NULL; -static void (*EditorsUpdateScenePreCb)(Main *bmain, Scene *scene, bool time) = NULL; - -void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), - void (*scene_func)(Main *bmain, Scene *scene, int updated), - void (*scene_pre_func)(Main *bmain, Scene *scene, bool time)) -{ - if (DEG_depsgraph_use_legacy()) { - EditorsUpdateIDCb = id_func; - EditorsUpdateSceneCb = scene_func; - EditorsUpdateScenePreCb = scene_pre_func; - } - else { - /* New dependency graph. */ - DEG_editors_set_update_cb(id_func, scene_func, scene_pre_func); - } -} - -void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time) -{ - if (DEG_depsgraph_use_legacy()) { - if (EditorsUpdateScenePreCb != NULL) { - EditorsUpdateScenePreCb(bmain, scene, time); - } - } - else { - DEG_editors_update_pre(bmain, scene, time); - } -} - -static void dag_editors_id_update(Main *bmain, ID *id) -{ - if (EditorsUpdateIDCb) - EditorsUpdateIDCb(bmain, id); -} - -static void dag_editors_scene_update(Main *bmain, Scene *scene, int updated) -{ - if (EditorsUpdateSceneCb) - EditorsUpdateSceneCb(bmain, scene, updated); -} - -/* groups with objects in this scene need to be put in the right order as well */ -static void scene_sort_groups(Main *bmain, Scene *sce) -{ - Base *base; - Group *group; - GroupObject *go; - Object *ob; - - /* test; are group objects all in this scene? */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - ob->id.tag &= ~LIB_TAG_DOIT; - } - for (base = sce->base.first; base; base = base->next) - base->object->id.tag |= LIB_TAG_DOIT; - - for (group = bmain->group.first; group; group = group->id.next) { - for (go = group->gobject.first; go; go = go->next) { - if ((go->ob->id.tag & LIB_TAG_DOIT) == 0) - break; - } - /* this group is entirely in this scene */ - if (go == NULL) { - ListBase listb = {NULL, NULL}; - - for (go = group->gobject.first; go; go = go->next) - go->ob->id.newid = (ID *)go; - - /* in order of sorted bases we reinsert group objects */ - for (base = sce->base.first; base; base = base->next) { - - if (base->object->id.newid) { - go = (GroupObject *)base->object->id.newid; - base->object->id.newid = NULL; - BLI_remlink(&group->gobject, go); - BLI_addtail(&listb, go); - } - } - /* copy the newly sorted listbase */ - group->gobject = listb; - } - } - - /* newid abused for GroupObject, cleanup. */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - ob->id.newid = NULL; - } -} - -static void dag_scene_tag_rebuild(Scene *sce) -{ - if (sce->theDag) { - sce->theDag->need_update = true; - } -} - -/* free the depency graph */ -static void dag_scene_free(Scene *sce) -{ - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; - } -} - -/* Check whether object data needs to be evaluated before it - * might be used by others. - * - * Means that mesh object needs to have proper derivedFinal, - * curves-typed objects are to have proper curve cache. - * - * Other objects or objects which are tagged for data update are - * not considered to be in need of evaluation. - */ -static bool check_object_needs_evaluation(Object *object) -{ - if (object->recalc & OB_RECALC_ALL) { - /* Object is tagged for update anyway, no need to re-tag it. */ - return false; - } - - if (object->type == OB_MESH) { - return object->derivedFinal == NULL; - } - else if (ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - return object->curve_cache == NULL; - } - - return false; -} - -/* Check whether object data is tagged for update. */ -static bool check_object_tagged_for_update(Object *object) -{ - if (object->recalc & OB_RECALC_ALL) { - return true; - } - - if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - ID *data_id = object->data; - return (data_id->tag & (LIB_TAG_ID_RECALC_DATA | LIB_TAG_ID_RECALC)) != 0; - } - - return false; -} - -/* Flush changes from tagged objects in the scene to their - * dependencies which are not evaluated yet. - * - * This is needed to ensure all the dependencies are met - * before objects gets handled by object_handle_update(), - * - * This is needed when visible layers are changed or changing - * scene graph layout which involved usage of objects which - * aren't in the scene or weren't visible yet. - */ -static void dag_invisible_dependencies_flush(Scene *scene) -{ - DagNode *root_node = scene->theDag->DagNode.first, *node; - DagNodeQueue *queue; - - for (node = root_node; node != NULL; node = node->next) { - node->color = DAG_WHITE; - } - - queue = queue_create(DAGQUEUEALLOC); - - for (node = root_node; node != NULL; node = node->next) { - if (node->color == DAG_WHITE) { - push_stack(queue, node); - node->color = DAG_GRAY; - - while (queue->count) { - DagNode *current_node = get_top_node_queue(queue); - DagAdjList *itA; - bool skip = false; - - for (itA = current_node->child; itA; itA = itA->next) { - if (itA->node->color == DAG_WHITE) { - itA->node->color = DAG_GRAY; - push_stack(queue, itA->node); - skip = true; - break; - } - } - - if (!skip) { - current_node = pop_queue(queue); - - if (current_node->type == ID_OB) { - Object *current_object = current_node->ob; - if (check_object_needs_evaluation(current_object)) { - for (itA = current_node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - Object *object = itA->node->ob; - if (check_object_tagged_for_update(object)) { - current_object->recalc |= OB_RECALC_OB | OB_RECALC_DATA; - } - } - } - } - } - node->color = DAG_BLACK; - } - } - } - } - - queue_delete(queue); -} - -static void dag_invisible_dependencies_check_flush(Main *bmain, Scene *scene) -{ - if (DAG_id_type_tagged(bmain, ID_OB) || - DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */ - DAG_id_type_tagged(bmain, ID_CU) || /* Curve */ - DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */ - DAG_id_type_tagged(bmain, ID_LT)) /* Lattice */ - { - dag_invisible_dependencies_flush(scene); - } -} - -/* sort the base list on dependency order */ -static void dag_scene_build(Main *bmain, Scene *sce) -{ - DagNode *node, *rootnode; - DagNodeQueue *nqueue; - DagAdjList *itA; - int time; - int skip = 0; - ListBase tempbase; - Base *base; - - BLI_listbase_clear(&tempbase); - - build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA); - - dag_check_cycle(sce->theDag); - - nqueue = queue_create(DAGQUEUEALLOC); - - for (node = sce->theDag->DagNode.first; node; node = node->next) { - node->color = DAG_WHITE; - } - - time = 1; - - rootnode = sce->theDag->DagNode.first; - rootnode->color = DAG_GRAY; - time++; - push_stack(nqueue, rootnode); - - while (nqueue->count) { - - skip = 0; - node = get_top_node_queue(nqueue); - - itA = node->child; - while (itA != NULL) { - if (itA->node->color == DAG_WHITE) { - itA->node->DFS_dvtm = time; - itA->node->color = DAG_GRAY; - - time++; - push_stack(nqueue, itA->node); - skip = 1; - break; - } - itA = itA->next; - } - - if (!skip) { - if (node) { - node = pop_queue(nqueue); - if (node->ob == sce) /* we are done */ - break; - node->color = DAG_BLACK; - - time++; - base = sce->base.first; - while (base && base->object != node->ob) - base = base->next; - if (base) { - BLI_remlink(&sce->base, base); - BLI_addhead(&tempbase, base); - } - } - } - } - - /* temporal correction for circular dependencies */ - base = sce->base.first; - while (base) { - BLI_remlink(&sce->base, base); - BLI_addhead(&tempbase, base); - //if (G.debug & G_DEBUG) - printf("cyclic %s\n", base->object->id.name); - base = sce->base.first; - } - - sce->base = tempbase; - queue_delete(nqueue); - - /* all groups with objects in this scene gets resorted too */ - scene_sort_groups(bmain, sce); - - if (G.debug & G_DEBUG) { - printf("\nordered\n"); - for (base = sce->base.first; base; base = base->next) { - printf(" %s\n", base->object->id.name); - } - } - - /* Make sure that new dependencies which came from invisible layers - * are tagged for update (if they're needed for objects which were - * tagged for update). - */ - dag_invisible_dependencies_check_flush(bmain, sce); -} - -/* clear all dependency graphs */ -void DAG_relations_tag_update(Main *bmain) -{ - if (DEG_depsgraph_use_legacy()) { - Scene *sce; - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - dag_scene_tag_rebuild(sce); - } - } - else { - /* New dependency graph. */ - DEG_relations_tag_update(bmain); - } -} - -/* rebuild dependency graph only for a given scene */ -void DAG_scene_relations_rebuild(Main *bmain, Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - dag_scene_free(sce); - DAG_scene_relations_update(bmain, sce); - } - else { - /* New dependency graph. */ - DEG_scene_relations_rebuild(bmain, sce); - } -} - -/* create dependency graph if it was cleared or didn't exist yet */ -void DAG_scene_relations_update(Main *bmain, Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - if (!sce->theDag || sce->theDag->need_update) - dag_scene_build(bmain, sce); - } - else { - /* New dependency graph. */ - DEG_scene_relations_update(bmain, sce); - } -} - -void DAG_scene_relations_validate(Main *bmain, Scene *sce) -{ - if (!DEG_depsgraph_use_legacy()) { - DEG_debug_scene_relations_validate(bmain, sce); - } -} - -void DAG_scene_free(Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; - } - } - else { - if (sce->depsgraph) { - DEG_graph_free(sce->depsgraph); - sce->depsgraph = NULL; - } - } -} - -static void lib_id_recalc_tag(Main *bmain, ID *id) -{ - id->tag |= LIB_TAG_ID_RECALC; - DAG_id_type_tag(bmain, GS(id->name)); -} - -static void lib_id_recalc_data_tag(Main *bmain, ID *id) -{ - id->tag |= LIB_TAG_ID_RECALC_DATA; - DAG_id_type_tag(bmain, GS(id->name)); -} - -/* node was checked to have lasttime != curtime and is if type ID_OB */ -static void flush_update_node(Main *bmain, DagNode *node, unsigned int layer, int curtime) -{ - DagAdjList *itA; - Object *ob, *obc; - int oldflag; - bool changed = false; - unsigned int all_layer; - - node->lasttime = curtime; - - ob = node->ob; - if (ob && (ob->recalc & OB_RECALC_ALL)) { - all_layer = node->scelay; - - /* got an object node that changes, now check relations */ - for (itA = node->child; itA; itA = itA->next) { - all_layer |= itA->lay; - /* the relationship is visible */ - if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) - if (itA->node->type == ID_OB) { - obc = itA->node->ob; - oldflag = obc->recalc; - - /* got a ob->obc relation, now check if flag needs flush */ - if (ob->recalc & OB_RECALC_OB) { - if (itA->type & DAG_RL_OB_OB) { - //printf("ob %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obc->id); - } - if (itA->type & DAG_RL_OB_DATA) { - //printf("ob %s changes obdata %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - if (ob->recalc & OB_RECALC_DATA) { - if (itA->type & DAG_RL_DATA_OB) { - //printf("obdata %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obc->id); - } - if (itA->type & DAG_RL_DATA_DATA) { - //printf("obdata %s changes obdata %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - if (oldflag != obc->recalc) changed = 1; - } - } - } - /* even nicer, we can clear recalc flags... */ - if ((all_layer & layer) == 0) { // XXX && (ob != obedit)) { - /* but existing displaylists or derivedmesh should be freed */ - if (ob->recalc & OB_RECALC_DATA) - BKE_object_free_derived_caches(ob); - - ob->recalc &= ~OB_RECALC_ALL; - } - } - - /* check case where child changes and parent forcing obdata to change */ - /* should be done regardless if this ob has recalc set */ - /* could merge this in with loop above...? (ton) */ - for (itA = node->child; itA; itA = itA->next) { - /* the relationship is visible */ - if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) - if (itA->node->type == ID_OB) { - obc = itA->node->ob; - /* child moves */ - if ((obc->recalc & OB_RECALC_ALL) == OB_RECALC_OB) { - /* parent has deforming info */ - if (itA->type & (DAG_RL_OB_DATA | DAG_RL_DATA_DATA)) { - // printf("parent %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - } - } - } - - /* we only go deeper if node not checked or something changed */ - for (itA = node->child; itA; itA = itA->next) { - if (changed || itA->node->lasttime != curtime) - flush_update_node(bmain, itA->node, layer, curtime); - } - -} - -/* node was checked to have lasttime != curtime, and is of type ID_OB */ -static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) -{ - DagAdjList *itA; - - node->lasttime = curtime; - node->lay = node->scelay; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - if (itA->node->lasttime != curtime) { - itA->lay = flush_layer_node(sce, itA->node, curtime); /* lay is only set once for each relation */ - } - else { - itA->lay = itA->node->lay; - } - - node->lay |= itA->lay; - } - } - - return node->lay; -} - -/* node was checked to have lasttime != curtime, and is of type ID_OB */ -static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, - int curtime, unsigned int lay, bool reset) -{ - DagAdjList *itA; - Object *ob; - - node->lasttime = curtime; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - if (itA->node->lasttime != curtime) { - ob = (Object *)(itA->node->ob); - - if (reset || (ob->recalc & OB_RECALC_ALL)) { - if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) { - /* Don't tag nodes which are on invisible layer. */ - if (itA->node->lay & lay) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &ob->id); - } - } - - flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, true); - } - else - flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, false); - } - } - } -} - -/* flush layer flags to dependencies */ -static void dag_scene_flush_layers(Scene *sce, int lay) -{ - DagNode *node, *firstnode; - DagAdjList *itA; - Base *base; - int lasttime; - - firstnode = sce->theDag->DagNode.first; /* always scene node */ - - for (itA = firstnode->child; itA; itA = itA->next) - itA->lay = 0; - - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - - /* update layer flags in nodes */ - for (base = sce->base.first; base; base = base->next) { - node = dag_get_node(sce->theDag, base->object); - node->scelay = base->object->lay; - } - - /* ensure cameras are set as if they are on a visible layer, because - * they ared still used for rendering or setting the camera view - * - * XXX, this wont work for local view / unlocked camera's */ - if (sce->camera) { - node = dag_get_node(sce->theDag, sce->camera); - node->scelay |= lay; - } - -#ifdef DURIAN_CAMERA_SWITCH - { - TimeMarker *m; - - for (m = sce->markers.first; m; m = m->next) { - if (m->camera) { - node = dag_get_node(sce->theDag, m->camera); - node->scelay |= lay; - } - } - } -#endif - - /* flush layer nodes to dependencies */ - for (itA = firstnode->child; itA; itA = itA->next) - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) - flush_layer_node(sce, itA->node, lasttime); -} - -static void dag_tag_renderlayers(Scene *sce, unsigned int lay) -{ - if (sce->nodetree) { - bNode *node; - Base *base; - unsigned int lay_changed = 0; - - for (base = sce->base.first; base; base = base->next) - if (base->lay & lay) - if (base->object->recalc) - lay_changed |= base->lay; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == (ID *)sce) { - SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1); - if (srl && (srl->lay & lay_changed)) - nodeUpdate(sce->nodetree, node); - } - } - } -} - -/* flushes all recalc flags in objects down the dependency tree */ -void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const short time) -{ - DagNode *firstnode; - DagAdjList *itA; - Object *ob; - int lasttime; - - if (!DEG_depsgraph_use_legacy()) { - return; - } - - if (sce->theDag == NULL || sce->theDag->need_update) { - printf("DAG zero... not allowed to happen!\n"); - DAG_scene_relations_update(bmain, sce); - } - - firstnode = sce->theDag->DagNode.first; /* always scene node */ - - /* first we flush the layer flags */ - dag_scene_flush_layers(sce, lay); - - /* then we use the relationships + layer info to flush update events */ - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - for (itA = firstnode->child; itA; itA = itA->next) - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) - flush_update_node(bmain, itA->node, lay, lasttime); - - /* if update is not due to time change, do pointcache clears */ - if (!time) { - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - for (itA = firstnode->child; itA; itA = itA->next) { - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) { - ob = (Object *)(itA->node->ob); - - if (ob->recalc & OB_RECALC_ALL) { - if (BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH)) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &ob->id); - } - - flush_pointcache_reset(bmain, sce, itA->node, lasttime, - lay, true); - } - else - flush_pointcache_reset(bmain, sce, itA->node, lasttime, - lay, false); - } - } - } - - dag_tag_renderlayers(sce, lay); -} - -static bool modifier_nlastrips_use_time(ListBase *strips) -{ - NlaStrip *strip; - - if (strips) { - for (strip = strips->first; strip; strip = strip->next) { - if (modifier_nlastrips_use_time(&strip->strips)) { - return true; - } - else if (strip->act) { - FCurve *fcu; - - for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - } - } - } - - return false; -} - -static bool object_modifiers_use_time(Object *ob) -{ - ModifierData *md; - - /* check if a modifier in modifier stack needs time input */ - for (md = ob->modifiers.first; md; md = md->next) { - if (modifier_dependsOnTime(md)) - return true; - } - - /* check whether any modifiers are animated */ - if (ob->adt) { - AnimData *adt = ob->adt; - NlaTrack *nlt; - FCurve *fcu; - - /* action - check for F-Curves with paths containing 'modifiers[' */ - if (adt->action) { - for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - } - - /* This here allows modifier properties to get driven and still update properly - * - * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven) - * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused - * by the RNA updates cache introduced in r.38649 - */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - - /* Also check NLA Strips... [#T45938] */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - if (modifier_nlastrips_use_time(&nlt->strips)) - return true; - } - } - - return false; -} - -static short animdata_use_time(AnimData *adt) -{ - NlaTrack *nlt; - - if (adt == NULL) return 0; - - /* check action - only if assigned, and it has anim curves */ - if (adt->action && adt->action->curves.first) - return 1; - - /* check NLA tracks + strips */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - if (nlt->strips.first) - return 1; - } - - /* If we have drivers, more likely than not, on a frame change - * they'll need updating because their owner changed - * - * This is kindof a hack to get around a whole host of problems - * involving drivers using non-object datablock data (which the - * depsgraph currently has no way of representing let alone correctly - * dependency sort+tagging). By doing this, at least we ensure that - * some commonly attempted drivers (such as scene -> current frame; - * see "Driver updates fail" thread on Bf-committers dated July 2) - * will work correctly, and that other non-object datablocks will have - * their drivers update at least on frame change. - * - * -- Aligorith, July 4 2011 - */ - if (adt->drivers.first) - return 1; - - return 0; -} - -static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) -{ - if (ob->constraints.first) { - bConstraint *con; - for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti) { - /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM(cti->type, - CONSTRAINT_TYPE_FOLLOWTRACK, - CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER, - CONSTRAINT_TYPE_TRANSFORM_CACHE)) - { - ob->recalc |= OB_RECALC_OB; - } - else if (cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar) { - ob->recalc |= OB_RECALC_OB; - break; - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - - } - } - } - - if (ob->parent) { - /* motion path or bone child */ - if (ob->parent->type == OB_CURVE || ob->parent->type == OB_ARMATURE) ob->recalc |= OB_RECALC_OB; - } - -#if 0 // XXX old animation system - if (ob->nlastrips.first) { - if (ob->dup_group) { - bActionStrip *strip; - /* this case is for groups with nla, whilst nla target has no action or nla */ - for (strip = ob->nlastrips.first; strip; strip = strip->next) { - if (strip->object) - strip->object->recalc |= OB_RECALC_ALL; - } - } - } -#endif // XXX old animation system - - if (animdata_use_time(ob->adt)) { - ob->recalc |= OB_RECALC_OB; - ob->adt->recalc |= ADT_RECALC_ANIM; - } - - if ((ob->adt) && (ob->type == OB_ARMATURE)) ob->recalc |= OB_RECALC_DATA; - - if (object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA; - if ((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA; - - // XXX: scene here may not be the scene that contains the rigidbody world affecting this! - if (ob->rigidbody_object && BKE_scene_check_rigidbody_active(scene)) - ob->recalc |= OB_RECALC_OB; - - { - AnimData *adt = BKE_animdata_from_id((ID *)ob->data); - Mesh *me; - Curve *cu; - Lattice *lt; - - switch (ob->type) { - case OB_MESH: - me = ob->data; - if (me->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - if (ob->particlesystem.first) - ob->recalc |= OB_RECALC_DATA; - break; - case OB_CURVE: - case OB_SURF: - cu = ob->data; - if (cu->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - break; - case OB_FONT: - cu = ob->data; - if (BLI_listbase_is_empty(&cu->nurb) && cu->str && cu->vfont) - ob->recalc |= OB_RECALC_DATA; - break; - case OB_LATTICE: - lt = ob->data; - if (lt->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - break; - case OB_MBALL: - if (ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA; - break; - case OB_EMPTY: - /* update animated images */ - if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) - if (BKE_image_is_animated(ob->data)) - ob->recalc |= OB_RECALC_DATA; - break; - } - - if (animdata_use_time(adt)) { - ob->recalc |= OB_RECALC_DATA; - adt->recalc |= ADT_RECALC_ANIM; - } - - if (ob->particlesystem.first) { - ParticleSystem *psys = ob->particlesystem.first; - - for (; psys; psys = psys->next) { - if (psys_check_enabled(ob, psys, G.is_rendering)) { - ob->recalc |= OB_RECALC_DATA; - break; - } - } - } - } - - if (ob->recalc & OB_RECALC_OB) - lib_id_recalc_tag(bmain, &ob->id); - if (ob->recalc & OB_RECALC_DATA) - lib_id_recalc_data_tag(bmain, &ob->id); - -} - -/* recursively update objects in groups, each group is done at most once */ -static void dag_group_update_flags(Main *bmain, Scene *scene, Group *group, const bool do_time) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - if (do_time) - dag_object_time_update_flags(bmain, scene, go->ob); - if (go->ob->dup_group) - dag_group_update_flags(bmain, scene, go->ob->dup_group, do_time); - } -} - -/* flag all objects that need recalc, for changes in time for example */ -/* do_time: make this optional because undo resets objects to their animated locations without this */ -void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const bool do_time, const bool do_invisible_flush) -{ - Base *base; - Object *ob; - Group *group; - GroupObject *go; - Scene *sce_iter; - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* set ob flags where animated systems are */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - - if (do_time) { - /* now if DagNode were part of base, the node->lay could be checked... */ - /* we do all now, since the scene_flush checks layers and clears recalc flags even */ - - /* NOTE: "sce_iter" not "scene" so that rigidbodies in background scenes work - * (i.e. muting + rbw availability can be checked and tagged properly) [#33970] - */ - dag_object_time_update_flags(bmain, sce_iter, ob); - } - - /* recursively tag groups with LIB_TAG_DOIT, and update flags for objects */ - if (ob->dup_group) - dag_group_update_flags(bmain, scene, ob->dup_group, do_time); - } - - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) - DAG_scene_flush_update(bmain, sce_iter, lay, 1); - - if (do_time) { - /* test: set time flag, to disable baked systems to update */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - if (ob->recalc & OB_RECALC_ALL) - ob->recalc |= OB_RECALC_TIME; - } - - /* hrmf... an exception to look at once, for invisible camera object we do it over */ - if (scene->camera) - dag_object_time_update_flags(bmain, scene, scene->camera); - } - - /* and store the info in groupobject */ - for (group = bmain->group.first; group; group = group->id.next) { - if (group->id.tag & LIB_TAG_DOIT) { - for (go = group->gobject.first; go; go = go->next) { - go->recalc = go->ob->recalc; - // printf("ob %s recalc %d\n", go->ob->id.name, go->recalc); - } - group->id.tag &= ~LIB_TAG_DOIT; - } - } - - if (do_invisible_flush) { - dag_invisible_dependencies_check_flush(bmain, scene); - } -} - -/* struct returned by DagSceneLayer */ -typedef struct DagSceneLayer { - struct DagSceneLayer *next, *prev; - Scene *scene; - unsigned int layer; -} DagSceneLayer; - -/* returns visible scenes with valid DAG */ -static void dag_current_scene_layers(Main *bmain, ListBase *lb) -{ - wmWindowManager *wm; - wmWindow *win; - - BLI_listbase_clear(lb); - - /* if we have a windowmanager, look into windows */ - if ((wm = bmain->wm.first)) { - - BKE_main_id_flag_listbase(&bmain->scene, LIB_TAG_DOIT, 1); - - for (win = wm->windows.first; win; win = win->next) { - if (win->screen && win->screen->scene->theDag) { - Scene *scene = win->screen->scene; - DagSceneLayer *dsl; - - if (scene->id.tag & LIB_TAG_DOIT) { - dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); - - BLI_addtail(lb, dsl); - - dsl->scene = scene; - dsl->layer = BKE_screen_visible_layers(win->screen, scene); - - scene->id.tag &= ~LIB_TAG_DOIT; - } - else { - /* It is possible that multiple windows shares the same scene - * and have different layers visible. - * - * Here we deal with such cases by squashing layers bits from - * multiple windoew to the DagSceneLayer. - * - * TODO(sergey): Such a lookup could be optimized perhaps, - * however should be fine for now since we usually have only - * few open windows. - */ - for (dsl = lb->first; dsl; dsl = dsl->next) { - if (dsl->scene == scene) { - dsl->layer |= BKE_screen_visible_layers(win->screen, scene); - break; - } - } - } - } - } - } - else { - /* if not, use the first sce */ - DagSceneLayer *dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); - - BLI_addtail(lb, dsl); - - dsl->scene = bmain->scene.first; - dsl->layer = dsl->scene->lay; - - /* XXX for background mode, we should get the scene - * from somewhere, for the -S option, but it's in - * the context, how to get it here? */ - } -} - -static void dag_group_on_visible_update(Scene *scene, Group *group) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - go->ob->recalc |= OB_RECALC_DATA; - go->ob->id.tag |= LIB_TAG_DOIT; - lib_id_recalc_tag(G.main, &go->ob->id); - } - if (go->ob->proxy_from) { - go->ob->recalc |= OB_RECALC_OB; - go->ob->id.tag |= LIB_TAG_DOIT; - lib_id_recalc_tag(G.main, &go->ob->id); - } - - if (go->ob->dup_group) - dag_group_on_visible_update(scene, go->ob->dup_group); - } -} - -void DAG_on_visible_update(Main *bmain, const bool do_time) -{ - ListBase listbase; - DagSceneLayer *dsl; - - if (!DEG_depsgraph_use_legacy()) { - /* Inform new dependnecy graphs about visibility changes. */ - DEG_on_visible_update(bmain, do_time); - return; - } - - /* get list of visible scenes and layers */ - dag_current_scene_layers(bmain, &listbase); - - for (dsl = listbase.first; dsl; dsl = dsl->next) { - Scene *scene = dsl->scene; - Scene *sce_iter; - Base *base; - Object *ob; - DagNode *node; - unsigned int lay = dsl->layer, oblay; - - /* derivedmeshes and displists are not saved to file so need to be - * remade, tag them so they get remade in the scene update loop, - * note armature poses or object matrices are preserved and do not - * require updates, so we skip those */ - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) - dag_scene_flush_layers(sce_iter, lay); - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - node = (sce_iter->theDag) ? dag_get_node(sce_iter->theDag, ob) : NULL; - oblay = (node) ? node->lay : ob->lay; - - if ((oblay & lay) & ~scene->lay_updated) { - /* TODO(sergey): Why do we need armature here now but didn't need before? */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_tag(bmain, &ob->id); - } - /* This should not be needed here, but in some cases, like after a redo, we can end up with - * a wrong final matrix (see T42472). - * Quoting Sergey, this comes from BKE_object_handle_update_ex, which is calling - * BKE_object_where_is_calc_ex when it shouldn't, but that issue is not easily fixable. - */ - else { - ob->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &ob->id); - } - if (ob->proxy && (ob->proxy_group == NULL)) { - ob->proxy->recalc |= OB_RECALC_DATA; - lib_id_recalc_tag(bmain, &ob->id); - } - if (ob->dup_group) - dag_group_on_visible_update(scene, ob->dup_group); - } - } - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* now tag update flags, to ensure deformers get calculated on redraw */ - DAG_scene_update_flags(bmain, scene, lay, do_time, true); - scene->lay_updated |= lay; - } - - BLI_freelistN(&listbase); - - /* hack to get objects updating on layer changes */ - DAG_id_type_tag(bmain, ID_OB); - - /* so masks update on load */ - if (bmain->mask.first) { - Mask *mask; - - for (mask = bmain->mask.first; mask; mask = mask->id.next) { - DAG_id_tag_update(&mask->id, 0); - } - } -} - -static void dag_id_flush_update__isDependentTexture( - void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag)) -{ - struct { ID *id; bool is_dependent; } *data = userData; - - if (*idpoin && GS((*idpoin)->name) == ID_TE) { - if (data->id == (*idpoin)) - data->is_dependent = 1; - } -} - -static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) -{ - Object *obt, *ob = NULL; - short idtype; - - /* here we flush a few things before actual scene wide flush, mostly - * due to only objects and not other datablocks being in the depsgraph */ - - /* set flags & pointcache for object */ - if (GS(id->name) == ID_OB) { - ob = (Object *)id; - BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH); - - /* So if someone tagged object recalc directly, - * id_tag_update bit-field stays relevant - */ - if (ob->recalc & OB_RECALC_ALL) { - DAG_id_type_tag(bmain, GS(id->name)); - } - - if (ob->recalc & OB_RECALC_DATA) { - /* all users of this ob->data should be checked */ - id = ob->data; - - /* no point in trying in this cases */ - if (id && id->us <= 1) { - dag_editors_id_update(bmain, id); - id = NULL; - } - } - } - - /* set flags & pointcache for object data */ - if (id) { - idtype = GS(id->name); - - - if (OB_DATA_SUPPORT_ID(idtype)) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - if (!(ob && obt == ob) && obt->data == id) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - else if (idtype == ID_VF) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - if (obt->type == OB_FONT) { - Curve *cu = obt->data; - if (ELEM((struct VFont *)id, CURVE_VFONT_ANY(cu))) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - } - } - } - } - - /* set flags based on textures - can influence depgraph via modifiers */ - if (idtype == ID_TE) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - struct { ID *id; bool is_dependent; } data; - data.id = id; - data.is_dependent = 0; - - modifiers_foreachIDLink(obt, dag_id_flush_update__isDependentTexture, &data); - if (data.is_dependent) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - } - - /* particle settings can use the texture as well */ - if (obt->particlesystem.first) { - ParticleSystem *psys = obt->particlesystem.first; - MTex **mtexp, *mtex; - int a; - for (; psys; psys = psys->next) { - mtexp = psys->part->mtex; - for (a = 0; a < MAX_MTEX; a++, mtexp++) { - mtex = *mtexp; - if (mtex && mtex->tex == (Tex *)id) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - - if (mtex->mapto & PAMAP_INIT) - psys->recalc |= PSYS_RECALC_RESET; - if (mtex->mapto & PAMAP_CHILD) - psys->recalc |= PSYS_RECALC_CHILD; - - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - } - } - } - - /* set flags based on ShapeKey */ - if (idtype == ID_KE) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - Key *key = BKE_key_from_object(obt); - if (!(ob && obt == ob) && ((ID *)key == id)) { - obt->flag |= (OB_RECALC_OB | OB_RECALC_DATA); - lib_id_recalc_tag(bmain, &obt->id); - lib_id_recalc_data_tag(bmain, &obt->id); - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - - /* set flags based on particle settings */ - if (idtype == ID_PA) { - ParticleSystem *psys; - for (obt = bmain->object.first; obt; obt = obt->id.next) - for (psys = obt->particlesystem.first; psys; psys = psys->next) - if (&psys->part->id == id) - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - - if (ELEM(idtype, ID_MA, ID_TE)) { - obt = sce->basact ? sce->basact->object : NULL; - if (obt && obt->mode & OB_MODE_TEXTURE_PAINT) { - BKE_texpaint_slots_refresh_object(sce, obt); - BKE_paint_proj_mesh_data_check(sce, obt, NULL, NULL, NULL, NULL); - GPU_drawobject_free(obt->derivedFinal); - } - } - - if (idtype == ID_MC) { - MovieClip *clip = (MovieClip *) id; - - BKE_tracking_dopesheet_tag_update(&clip->tracking); - - for (obt = bmain->object.first; obt; obt = obt->id.next) { - bConstraint *con; - for (con = obt->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER)) - { - obt->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obt->id); - break; - } - } - } - - if (sce->nodetree) { - bNode *node; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == id) { - nodeUpdate(sce->nodetree, node); - } - } - } - } - - /* Not pretty to iterate all the nodes here, but it's as good as it - * could be with the current depsgraph design/ - */ - if (idtype == ID_IM) { - FOREACH_NODETREE(bmain, ntree, parent_id) { - if (ntree->type == NTREE_SHADER) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == id) { - lib_id_recalc_tag(bmain, &ntree->id); - break; - } - } - } - } FOREACH_NODETREE_END - } - - if (idtype == ID_MSK) { - if (sce->nodetree) { - bNode *node; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == id) { - nodeUpdate(sce->nodetree, node); - } - } - } - } - - /* camera's matrix is used to orient reconstructed stuff, - * so it should happen tracking-related constraints recalculation - * when camera is changing (sergey) */ - if (sce->camera && &sce->camera->id == id) { - MovieClip *clip = BKE_object_movieclip_get(sce, sce->camera, true); - - if (clip) - dag_id_flush_update(bmain, sce, &clip->id); - } - - /* update editors */ - dag_editors_id_update(bmain, id); - } -} - -void DAG_ids_flush_tagged(Main *bmain) -{ - ListBase listbase; - DagSceneLayer *dsl; - ListBase *lbarray[MAX_LIBARRAY]; - int a; - bool do_flush = false; - - if (!DEG_depsgraph_use_legacy()) { - DEG_ids_flush_tagged(bmain); - return; - } - - /* get list of visible scenes and layers */ - dag_current_scene_layers(bmain, &listbase); - - if (BLI_listbase_is_empty(&listbase)) - return; - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - for (; id; id = id->next) { - if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) { - - for (dsl = listbase.first; dsl; dsl = dsl->next) - dag_id_flush_update(bmain, dsl->scene, id); - - do_flush = true; - } - } - } - } - - /* flush changes to other objects */ - if (do_flush) { - for (dsl = listbase.first; dsl; dsl = dsl->next) - DAG_scene_flush_update(bmain, dsl->scene, dsl->layer, 0); - } - - BLI_freelistN(&listbase); -} - -void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) -{ - ListBase *lbarray[MAX_LIBARRAY]; - int a; - bool updated = false; - - if (!DEG_depsgraph_use_legacy()) { - DEG_ids_check_recalc(bmain, scene, time); - return; - } - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - updated = true; - break; - } - } - - dag_editors_scene_update(bmain, scene, (updated || time)); -} - -/* It is possible that scene_update_post and frame_update_post handlers - * will modify objects. The issue is that DAG_ids_clear_recalc is called - * just after callbacks, which leaves objects with recalc flags but no - * corresponding bit in ID recalc bitfield. This leads to some kind of - * regression when using ID type tag fields to check whether there objects - * to be updated internally comparing threaded DAG with legacy one. - * - * For now let's have a workaround which will preserve tag for ID_OB - * if there're objects with OB_RECALC_ALL bits. This keeps behavior - * unchanged comparing with 2.69 release. - * - * TODO(sergey): Need to get rid of such a workaround. - * - * - sergey - - */ - -#define POST_UPDATE_HANDLER_WORKAROUND - -void DAG_ids_clear_recalc(Main *bmain) -{ - ListBase *lbarray[MAX_LIBARRAY]; - bNodeTree *ntree; - int a; - -#ifdef POST_UPDATE_HANDLER_WORKAROUND - bool have_updated_objects = false; - - if (DAG_id_type_tagged(bmain, ID_OB)) { - ListBase listbase; - DagSceneLayer *dsl; - - /* We need to check all visible scenes, otherwise resetting - * OB_ID changed flag will only work fine for first scene of - * multiple visible and all the rest will skip update. - * - * This could also lead to wrong behavior scene update handlers - * because of missing ID datablock changed flags. - * - * This is a bit of a bummer to allocate list here, but likely - * it wouldn't become too much bad because it only happens when - * objects were actually changed. - */ - dag_current_scene_layers(bmain, &listbase); - - for (dsl = listbase.first; dsl; dsl = dsl->next) { - Scene *scene = dsl->scene; - DagNode *node; - for (node = scene->theDag->DagNode.first; - node != NULL && have_updated_objects == false; - node = node->next) - { - if (node->type == ID_OB) { - Object *object = (Object *) node->ob; - if (object->recalc & OB_RECALC_ALL) { - have_updated_objects = true; - break; - } - } - } - } - - BLI_freelistN(&listbase); - } -#endif - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - for (; id; id = id->next) { - if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) - id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA); - - /* some ID's contain semi-datablock nodetree */ - ntree = ntreeFromID(id); - if (ntree && (ntree->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA))) - ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA); - } - } - } - - memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update)); - -#ifdef POST_UPDATE_HANDLER_WORKAROUND - if (have_updated_objects) { - DAG_id_type_tag(bmain, ID_OB); - } -#endif -} - -void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) -{ - if (!DEG_depsgraph_use_legacy()) { - DEG_id_tag_update_ex(bmain, id, flag); - return; - } - - if (id == NULL) return; - - if (G.debug & G_DEBUG_DEPSGRAPH) { - printf("%s: id=%s flag=%d\n", __func__, id->name, flag); - } - - /* tag ID for update */ - if (flag) { - if (flag & OB_RECALC_OB) - lib_id_recalc_tag(bmain, id); - if (flag & (OB_RECALC_DATA | PSYS_RECALC)) - lib_id_recalc_data_tag(bmain, id); - } - else - lib_id_recalc_tag(bmain, id); - - /* flag is for objects and particle systems */ - if (flag) { - Object *ob; - short idtype = GS(id->name); - - if (idtype == ID_OB) { - /* only quick tag */ - ob = (Object *)id; - ob->recalc |= (flag & OB_RECALC_ALL); - } - else if (idtype == ID_PA) { - ParticleSystem *psys; - /* this is weak still, should be done delayed as well */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (&psys->part->id == id) { - ob->recalc |= (flag & OB_RECALC_ALL); - psys->recalc |= (flag & PSYS_RECALC); - lib_id_recalc_tag(bmain, &ob->id); - lib_id_recalc_data_tag(bmain, &ob->id); - } - } - } - } - else { - /* disable because this is called on various ID types automatically. - * where printing warning is not useful. for now just ignore */ - /* BLI_assert(!"invalid flag for this 'idtype'"); */ - } - } - else if (GS(id->name) == ID_CF) { - for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { - ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); - - if (md) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - - if (mcmd->cache_file && (&mcmd->cache_file->id == id)) { - ob->recalc |= OB_RECALC_ALL; - continue; - } - } - - for (bConstraint *con = ob->constraints.first; con; con = con->next) { - if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { - continue; - } - - bTransformCacheConstraint *data = con->data; - - if (data->cache_file && (&data->cache_file->id == id)) { - ob->recalc |= OB_RECALC_ALL; - break; - } - } - } - } -} - -void DAG_id_tag_update(ID *id, short flag) -{ - DAG_id_tag_update_ex(G.main, id, flag); -} - -void DAG_id_type_tag(Main *bmain, short idtype) -{ - if (idtype == ID_NT) { - /* stupid workaround so parent datablocks of nested nodetree get looped - * over when we loop over tagged datablock types */ - DAG_id_type_tag(bmain, ID_MA); - DAG_id_type_tag(bmain, ID_TE); - DAG_id_type_tag(bmain, ID_LA); - DAG_id_type_tag(bmain, ID_WO); - DAG_id_type_tag(bmain, ID_SCE); - } - - atomic_fetch_and_or_uint8((uint8_t *)&bmain->id_tag_update[BKE_idcode_to_index(idtype)], 1); -} - -int DAG_id_type_tagged(Main *bmain, short idtype) -{ - return bmain->id_tag_update[BKE_idcode_to_index(idtype)]; -} - -#if 0 // UNUSED -/* recursively descends tree, each node only checked once */ -/* node is checked to be of type object */ -static int parent_check_node(DagNode *node, int curtime) -{ - DagAdjList *itA; - - node->lasttime = curtime; - - if (node->color == DAG_GRAY) - return DAG_GRAY; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - - if (itA->node->color == DAG_GRAY) - return DAG_GRAY; - - /* descend if not done */ - if (itA->node->lasttime != curtime) { - itA->node->color = parent_check_node(itA->node, curtime); - - if (itA->node->color == DAG_GRAY) - return DAG_GRAY; - } - } - } - - return DAG_WHITE; -} -#endif - -/* ******************* DAG FOR ARMATURE POSE ***************** */ - -/* we assume its an armature with pose */ -void DAG_pose_sort(Object *ob) -{ - bPose *pose = ob->pose; - bPoseChannel *pchan; - bConstraint *con; - DagNode *node; - DagNode *node2, *node3; - DagNode *rootnode; - DagForest *dag; - DagNodeQueue *nqueue; - DagAdjList *itA; - ListBase tempbase; - int skip = 0; - - dag = dag_init(); - dag->ugly_hack_sorry = false; /* no ID structs */ - - rootnode = dag_add_node(dag, NULL); /* node->ob becomes NULL */ - - /* we add the hierarchy and the constraints */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - int addtoroot = 1; - - node = dag_get_node(dag, pchan); - - if (pchan->parent) { - node2 = dag_get_node(dag, pchan->parent); - dag_add_relation(dag, node2, node, 0, "Parent Relation"); - addtoroot = 0; - } - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob && ct->subtarget[0]) { - bPoseChannel *target = BKE_pose_channel_find_name(ob->pose, ct->subtarget); - if (target) { - node2 = dag_get_node(dag, target); - dag_add_relation(dag, node2, node, 0, "Pose Constraint"); - - if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - bPoseChannel *parchan; - int segcount = 0; - - /* exclude tip from chain? */ - if (!(data->flag & CONSTRAINT_IK_TIP)) - parchan = pchan->parent; - else - parchan = pchan; - - /* Walk to the chain's root */ - while (parchan) { - node3 = dag_get_node(dag, parchan); - dag_add_relation(dag, node2, node3, 0, "IK Constraint"); - - segcount++; - if (segcount == data->rootbone || segcount > 255) break; /* 255 is weak */ - parchan = parchan->parent; - } - } - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - } - if (addtoroot == 1) { - dag_add_relation(dag, rootnode, node, 0, "Root Bone Relation"); - } - } - - dag_check_cycle(dag); - - /* now we try to sort... */ - BLI_listbase_clear(&tempbase); - - nqueue = queue_create(DAGQUEUEALLOC); - - /* tag nodes unchecked */ - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - rootnode->color = DAG_GRAY; - push_stack(nqueue, rootnode); - - while (nqueue->count) { - - skip = 0; - node = get_top_node_queue(nqueue); - - itA = node->child; - while (itA != NULL) { - if (itA->node->color == DAG_WHITE) { - itA->node->color = DAG_GRAY; - push_stack(nqueue, itA->node); - skip = 1; - break; - } - itA = itA->next; - } - - if (!skip) { - if (node) { - node = pop_queue(nqueue); - if (node->ob == NULL) /* we are done */ - break; - node->color = DAG_BLACK; - - /* put node in new list */ - BLI_remlink(&pose->chanbase, node->ob); - BLI_addhead(&tempbase, node->ob); - } - } - } - - /* temporal correction for circular dependencies */ - while (pose->chanbase.first) { - pchan = pose->chanbase.first; - BLI_remlink(&pose->chanbase, pchan); - BLI_addhead(&tempbase, pchan); - - printf("cyclic %s\n", pchan->name); - } - - pose->chanbase = tempbase; - queue_delete(nqueue); - -// printf("\nordered\n"); -// for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { -// printf(" %s\n", pchan->name); -// } - - free_forest(dag); - MEM_freeN(dag); -} - -/* ************************ DAG FOR THREADED UPDATE ********************* */ - -/* Initialize run-time data in the graph needed for traversing it - * from multiple threads and start threaded tree traversal by adding - * the root node to the queue. - * - * This will mark DAG nodes as object/non-object and will calculate - * num_pending_parents of nodes (which is how many non-updated parents node - * have, which helps a lot checking whether node could be scheduled - * already or not). - */ -void DAG_threaded_update_begin(Scene *scene, - void (*func)(void *node, void *user_data), - void *user_data) -{ - DagNode *node; - - /* We reset num_pending_parents to zero first and tag node as not scheduled yet... */ - for (node = scene->theDag->DagNode.first; node; node = node->next) { - node->num_pending_parents = 0; - node->scheduled = false; - } - - /* ... and then iterate over all the nodes and - * increase num_pending_parents for node childs. - */ - for (node = scene->theDag->DagNode.first; node; node = node->next) { - DagAdjList *itA; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node != node) { - itA->node->num_pending_parents++; - } - } - } - - /* Add root nodes to the queue. */ - BLI_spin_lock(&threaded_update_lock); - for (node = scene->theDag->DagNode.first; node; node = node->next) { - if (node->num_pending_parents == 0) { - node->scheduled = true; - func(node, user_data); - } - } - BLI_spin_unlock(&threaded_update_lock); -} - -/* This function is called when handling node is done. - * - * This function updates num_pending_parents for all childs and - * schedules them if they're ready. - */ -void DAG_threaded_update_handle_node_updated(void *node_v, - void (*func)(void *node, void *user_data), - void *user_data) -{ - DagNode *node = node_v; - DagAdjList *itA; - - for (itA = node->child; itA; itA = itA->next) { - DagNode *child_node = itA->node; - if (child_node != node) { - atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1); - - if (child_node->num_pending_parents == 0) { - bool need_schedule; - - BLI_spin_lock(&threaded_update_lock); - need_schedule = child_node->scheduled == false; - child_node->scheduled = true; - BLI_spin_unlock(&threaded_update_lock); - - if (need_schedule) { - func(child_node, user_data); - } - } - } - } -} - -/* ************************ DAG DEBUGGING ********************* */ - -void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob) -{ - /* utility for debugging dependencies */ - dag_print_dependencies = 1; - - if (ob && (ob->mode & OB_MODE_POSE)) { - printf("\nDEPENDENCY RELATIONS for %s\n\n", ob->id.name + 2); - DAG_pose_sort(ob); - } - else { - printf("\nDEPENDENCY RELATIONS for %s\n\n", scene->id.name + 2); - DAG_scene_relations_rebuild(bmain, scene); - } - - dag_print_dependencies = 0; -} - -/* ************************ DAG querying ********************* */ - -/* Will return Object ID if node represents Object, - * and will return NULL otherwise. - */ -Object *DAG_get_node_object(void *node_v) -{ - DagNode *node = node_v; - - if (node->type == ID_OB) { - return node->ob; - } - - return NULL; -} - -/* Returns node name, used for debug output only, atm. */ -const char *DAG_get_node_name(Scene *scene, void *node_v) -{ - DagNode *node = node_v; - - return dag_node_name(scene->theDag, node); -} - -short DAG_get_eval_flags_for_object(Scene *scene, void *object) -{ - DagNode *node; - - if (!DEG_depsgraph_use_legacy()) { - return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); - } - - if (scene->theDag == NULL) { - /* Happens when converting objects to mesh from a python script - * after modifying scene graph. - * - * Currently harmless because it's only called for temporary - * objects which are out of the DAG anyway. - */ - return 0; - } - - node = dag_find_node(scene->theDag, object); - - if (node) { - return node->eval_flags; - } - else { - /* Happens when external render engine exports temporary objects - * which are not in the DAG. - */ - - /* TODO(sergey): Doublecheck objects with Curve Deform exports all fine. */ - - /* TODO(sergey): Weak but currently we can't really access proper DAG from - * the modifiers stack. This is because in most cases modifier is to use - * the foreground scene, but to access evaluation flags we need to know - * active background scene, which we don't know. - */ - if (scene->set) { - return DAG_get_eval_flags_for_object(scene->set, object); - } - return 0; - } -} - -bool DAG_is_acyclic(Scene *scene) -{ - return scene->theDag->is_acyclic; -} - -#else - -/* ********************************************************************* - * Stubs to avoid linking issues and make sure legacy crap is not used * - * ********************************************************************* - */ - -DagNodeQueue *queue_create(int UNUSED(slots)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -void queue_raz(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void queue_delete(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -DagNode *pop_queue(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagForest *dag_init(void) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagForest *build_dag(Main *UNUSED(bmain), - Scene *UNUSED(sce), - short UNUSED(mask)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -void free_forest(DagForest *UNUSED(Dag)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -void dag_add_relation(DagForest *UNUSED(forest), - DagNode *UNUSED(fob1), - DagNode *UNUSED(fob2), - short UNUSED(rel), - const char *UNUSED(name)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -/* debug test functions */ - -void graph_print_queue(DagNodeQueue *UNUSED(nqueue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void graph_print_adj_list(DagForest *UNUSED(dag)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void DAG_scene_flush_update(Main *UNUSED(bmain), - Scene *UNUSED(sce), - unsigned int UNUSED(lay), - const short UNUSED(time)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void DAG_scene_update_flags(Main *UNUSED(bmain), - Scene *UNUSED(scene), - unsigned int UNUSED(lay), - const bool UNUSED(do_time), - const bool UNUSED(do_invisible_flush)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -/* ******************* DAG FOR ARMATURE POSE ***************** */ - -void DAG_pose_sort(Object *UNUSED(ob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -/* ************************ DAG FOR THREADED UPDATE ********************* */ - -void DAG_threaded_update_begin(Scene *UNUSED(scene), - void (*func)(void *node, void *user_data), - void *UNUSED(user_data)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - (void)func; -} - -void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v), - void (*func)(void *node, void *user_data), - void *UNUSED(user_data)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - (void)func; -} - -/* ************************ DAG querying ********************* */ - -Object *DAG_get_node_object(void *UNUSED(node_v)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return "INVALID"; -} - -bool DAG_is_acyclic(Scene *UNUSED(scene)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return false; -} - -/* ************************************ - * This functions are to be supported * - * ************************************ - */ - -void DAG_init(void) -{ - DEG_register_node_types(); -} - -void DAG_exit(void) -{ - DEG_free_node_types(); -} - -/* ************************ API *********************** */ - -void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func, - DEG_EditorUpdateScenePreCb scene_func_pre) -{ - DEG_editors_set_update_cb(id_func, scene_func, scene_func_pre); -} - -void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time) -{ - DEG_editors_update_pre(bmain, scene, time); -} - -/* Tag all relations for update. */ -void DAG_relations_tag_update(Main *bmain) -{ - DEG_relations_tag_update(bmain); -} - -/* Rebuild dependency graph only for a given scene. */ -void DAG_scene_relations_rebuild(Main *bmain, Scene *scene) -{ - DEG_scene_relations_rebuild(bmain, scene); -} - -/* Create dependency graph if it was cleared or didn't exist yet. */ -void DAG_scene_relations_update(Main *bmain, Scene *scene) -{ - DEG_scene_relations_update(bmain, scene); -} - -void DAG_scene_relations_validate(Main *bmain, Scene *scene) -{ - DEG_debug_scene_relations_validate(bmain, scene); -} - -void DAG_scene_free(Scene *scene) -{ - DEG_scene_graph_free(scene); -} - -void DAG_on_visible_update(Main *bmain, const bool do_time) -{ - DEG_on_visible_update(bmain, do_time); -} - -void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) -{ - DEG_ids_check_recalc(bmain, scene, time); -} - -void DAG_id_tag_update(ID *id, short flag) -{ - DEG_id_tag_update_ex(G.main, id, flag); -} - -void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) -{ - DEG_id_tag_update_ex(bmain, id, flag); -} - -void DAG_id_type_tag(Main *bmain, short idtype) -{ - DEG_id_type_tag(bmain, idtype); -} - -int DAG_id_type_tagged(Main *bmain, short idtype) -{ - return DEG_id_type_tagged(bmain, idtype); -} - -void DAG_ids_clear_recalc(Main *bmain) -{ - DEG_ids_clear_recalc(bmain); -} - -short DAG_get_eval_flags_for_object(Scene *scene, void *object) -{ - return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); -} - -void DAG_ids_flush_tagged(Main *bmain) -{ - DEG_ids_flush_tagged(bmain); -} - -/* ************************ DAG DEBUGGING ********************* */ - -void DAG_print_dependencies(Main *UNUSED(bmain), - Scene *scene, - Object *UNUSED(ob)) -{ - DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false); -} - -#endif diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 2a300cbe47b..44f284d043e 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -48,7 +48,6 @@ #include "BLI_utildefines.h" #include "BKE_global.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_cdderivedmesh.h" #include "BKE_object.h" @@ -63,6 +62,9 @@ #include "BLI_sys_types.h" // for intptr_t support +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + static void boundbox_displist_object(Object *ob); void BKE_displist_elem_free(DispList *dl) @@ -1739,7 +1741,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba if (!for_orco) { if ((cu->flag & CU_PATH) || - DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CURVE_PATH) + DEG_get_eval_flags_for_id(scene->depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH) { calc_curvepath(ob, &nubase); } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 1db69d23607..fb5ef403218 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -486,7 +486,7 @@ static void scene_setSubframe(Scene *scene, float subframe) scene->r.subframe = subframe; } -static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene) +static int surface_getBrushFlags(DynamicPaintSurface *surface, const SceneLayer *sl) { Base *base = NULL; GroupObject *go = NULL; @@ -498,7 +498,7 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen if (surface->brush_group) go = surface->brush_group->gobject.first; else - base = scene->base.first; + base = FIRSTBASE_NEW; while (base || go) { brushObj = NULL; @@ -1973,7 +1973,7 @@ static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMe /* * Updates derived mesh copy and processes dynamic paint step / caches. */ -static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm) +static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm) { if (pmd->canvas) { DynamicPaintCanvasSettings *canvas = pmd->canvas; @@ -2036,7 +2036,7 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene else if (can_simulate) { /* calculate surface frame */ canvas->flags |= MOD_DPAINT_BAKING; - dynamicPaint_calculateFrame(surface, scene, ob, current_frame); + dynamicPaint_calculateFrame(surface, scene, sl, ob, current_frame); canvas->flags &= ~MOD_DPAINT_BAKING; /* restore canvas derivedmesh if required */ @@ -2055,7 +2055,7 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene } /* Modifier call. Processes dynamic paint modifier step. */ -DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm) +DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm) { if (pmd->canvas) { DerivedMesh *ret; @@ -2064,7 +2064,7 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen DM_ensure_looptri(dm); /* Update canvas data for a new frame */ - dynamicPaint_frameUpdate(pmd, scene, ob, dm); + dynamicPaint_frameUpdate(pmd, scene, sl, ob, dm); /* Return output mesh */ ret = dynamicPaint_Modifier_apply(pmd, ob, dm); @@ -2076,7 +2076,7 @@ DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scen DM_ensure_looptri(dm); /* Update canvas data for a new frame */ - dynamicPaint_frameUpdate(pmd, scene, ob, dm); + dynamicPaint_frameUpdate(pmd, scene, sl, ob, dm); /* Return output mesh */ return dynamicPaint_Modifier_apply(pmd, ob, dm); @@ -5638,7 +5638,7 @@ static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index) } } -static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob) +static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const SceneLayer *sl, Object *ob) { PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; @@ -5646,7 +5646,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce int index; bool new_bdata = false; const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) || - (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY)); + (surface_getBrushFlags(surface, sl) & BRUSH_USES_VELOCITY)); const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0; int canvasNumOfVerts = dm->getNumVerts(dm); @@ -5758,7 +5758,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce /* * Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface. */ -static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe) +static int dynamicPaint_doStep(Scene *scene, SceneLayer *sl, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe) { PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; @@ -5791,7 +5791,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su if (surface->brush_group) go = surface->brush_group->gobject.first; else - base = scene->base.first; + base = FIRSTBASE_NEW; while (base || go) { brushObj = NULL; @@ -5844,8 +5844,6 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats); /* Apply brush on the surface depending on it's collision type */ - /* Particle brush: */ - if (brush->collision == MOD_DPAINT_COL_PSYS) { if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && psys_check_enabled(brushObj, brush->psys, G.is_rendering)) @@ -5855,9 +5853,8 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su BKE_scene_frame_get(scene), ADT_RECALC_ANIM); dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); } - } /* Object center distance: */ - else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { + if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { dynamicPaint_paintSinglePoint(surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale); } /* Mesh volume/proximity: */ @@ -5931,7 +5928,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su /* * Calculate a single frame and included subframes for surface */ -int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame) +int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, SceneLayer *sl, Object *cObject, int frame) { float timescale = 1.0f; @@ -5940,7 +5937,7 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm); /* update bake data */ - dynamicPaint_generateBakeData(surface, scene, cObject); + dynamicPaint_generateBakeData(surface, sl, cObject); /* don't do substeps for first frame */ if (surface->substeps && (frame != surface->start_frame)) { @@ -5949,10 +5946,10 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje for (st = 1; st <= surface->substeps; st++) { float subframe = ((float) st) / (surface->substeps + 1); - if (!dynamicPaint_doStep(scene, cObject, surface, timescale, subframe)) + if (!dynamicPaint_doStep(scene, sl, cObject, surface, timescale, subframe)) return 0; } } - return dynamicPaint_doStep(scene, cObject, surface, timescale, 0.0f); + return dynamicPaint_doStep(scene, sl, cObject, surface, timescale, 0.0f); } diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 4a45bf1534c..c8ae3598097 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -50,6 +50,7 @@ #include "BKE_mesh.h" #include "BKE_editmesh.h" #include "BKE_editmesh_bvh.h" +#include "BKE_editmesh_tangent.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -240,383 +241,29 @@ static void emDM_calcLoopNormalsSpaceArray( #endif } - -/** \name Tangent Space Calculation - * \{ */ - -/* Necessary complexity to handle looptri's as quads for correct tangents */ -#define USE_LOOPTRI_DETECT_QUADS - -typedef struct { - const float (*precomputedFaceNormals)[3]; - const float (*precomputedLoopNormals)[3]; - const BMLoop *(*looptris)[3]; - int cd_loop_uv_offset; /* texture coordinates */ - const float (*orco)[3]; - float (*tangent)[4]; /* destination */ - int numTessFaces; - -#ifdef USE_LOOPTRI_DETECT_QUADS - /* map from 'fake' face index to looptri, - * quads will point to the first looptri of the quad */ - const int *face_as_quad_map; - int num_face_as_quad_map; -#endif - -} SGLSLEditMeshToTangent; - -#ifdef USE_LOOPTRI_DETECT_QUADS -/* seems weak but only used on quads */ -static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index) -{ - const BMLoop *l = BM_FACE_FIRST_LOOP(f); - while (vert_index--) { - l = l->next; - } - return l; -} -#endif - -/* interface */ -#include "mikktspace.h" - -static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) -{ - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - -#ifdef USE_LOOPTRI_DETECT_QUADS - return pMesh->num_face_as_quad_map; -#else - return pMesh->numTessFaces; -#endif -} - -static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) -{ -#ifdef USE_LOOPTRI_DETECT_QUADS - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - if (pMesh->face_as_quad_map) { - const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - return 4; - } - } - return 3; -#else - UNUSED_VARS(pContext, face_num); - return 3; -#endif -} - -static void emdm_ts_GetPosition( - const SMikkTSpaceContext *pContext, float r_co[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - - const float *co; - -finally: - co = l->v->co; - copy_v3_v3(r_co, co); -} - -static void emdm_ts_GetTextureCoordinate( - const SMikkTSpaceContext *pContext, float r_uv[2], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - -finally: - if (pMesh->cd_loop_uv_offset != -1) { - const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset); - copy_v2_v2(r_uv, uv); - } - else { - const float *orco = pMesh->orco[BM_elem_index_get(l->v)]; - map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); - } -} - -static void emdm_ts_GetNormal( - const SMikkTSpaceContext *pContext, float r_no[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - -finally: - if (pMesh->precomputedLoopNormals) { - copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]); - } - else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */ - if (pMesh->precomputedFaceNormals) { - copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]); - } - else { - copy_v3_v3(r_no, l->f->no); - } - } - else { - copy_v3_v3(r_no, l->v->no); - } -} - -static void emdm_ts_SetTSpace( - const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - - float *pRes; - -finally: - pRes = pMesh->tangent[BM_elem_index_get(l)]; - copy_v3_v3(pRes, fvTangent); - pRes[3] = fSign; -} - -static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) -{ - struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; - /* new computation method */ - { - SMikkTSpaceContext sContext = {NULL}; - SMikkTSpaceInterface sInterface = {NULL}; - sContext.m_pUserData = mesh2tangent; - sContext.m_pInterface = &sInterface; - sInterface.m_getNumFaces = emdm_ts_GetNumFaces; - sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace; - sInterface.m_getPosition = emdm_ts_GetPosition; - sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate; - sInterface.m_getNormal = emdm_ts_GetNormal; - sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace; - /* 0 if failed */ - genTangSpaceDefault(&sContext); - } -} - -/** - * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data. - * - * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`. - * This is done because #CD_TANGENT is cache data used only for drawing. - */ - static void emDM_calc_loop_tangents( DerivedMesh *dm, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count) + const char (*tangent_names)[MAX_NAME], int tangent_names_len) { EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; BMEditMesh *em = bmdm->em; - BMesh *bm = bmdm->em->bm; - if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0) - return; - - int act_uv_n = -1; - int ren_uv_n = -1; - bool calc_act = false; - bool calc_ren = false; - char act_uv_name[MAX_NAME]; - char ren_uv_name[MAX_NAME]; - char tangent_mask = 0; - - DM_calc_loop_tangents_step_0( - &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count, - &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); - - if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) { - for (int i = 0; i < tangent_names_count; i++) - if (tangent_names[i][0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]); - if (calc_act && act_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name); - if (calc_ren && ren_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name); - int totface = em->tottri; -#ifdef USE_LOOPTRI_DETECT_QUADS - int num_face_as_quad_map; - int *face_as_quad_map = NULL; - - /* map faces to quads */ - if (bmdm->em->tottri != bm->totface) { - /* over alloc, since we dont know how many ngon or quads we have */ - - /* map fake face index to looptri */ - face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__); - int i, j; - for (i = 0, j = 0; j < totface; i++, j++) { - face_as_quad_map[i] = j; - /* step over all quads */ - if (em->looptris[j][0]->f->len == 4) { - j++; /* skips the nest looptri */ - } - } - num_face_as_quad_map = i; - } - else { - num_face_as_quad_map = totface; - } -#endif - /* Calculation */ - { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL); - - dm->tangent_mask = 0; - /* Calculate tangent layers */ - SGLSLEditMeshToTangent data_array[MAX_MTFACE]; - int index = 0; - int n = 0; - CustomData_update_typemap(&dm->loopData); - const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT); - for (n = 0; n < tangent_layer_num; n++) { - index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n); - BLI_assert(n < MAX_MTFACE); - SGLSLEditMeshToTangent *mesh2tangent = &data_array[n]; - mesh2tangent->numTessFaces = em->tottri; -#ifdef USE_LOOPTRI_DETECT_QUADS - mesh2tangent->face_as_quad_map = face_as_quad_map; - mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; -#endif - mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */ - /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), - * have to check this is valid... - */ - mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL); - mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n); - - /* needed for indexing loop-tangents */ - int htype_index = BM_LOOP; - if (mesh2tangent->cd_loop_uv_offset == -1) { - mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO); - if (!mesh2tangent->orco) - continue; - /* needed for orco lookups */ - htype_index |= BM_VERT; - } - if (mesh2tangent->precomputedFaceNormals) { - /* needed for face normal lookups */ - htype_index |= BM_FACE; - } - BM_mesh_elem_index_ensure(bm, htype_index); - - mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris; - mesh2tangent->tangent = dm->loopData.layers[index].data; - - /* Fill the resulting tangent_mask */ - int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name); - int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV); - BLI_assert(uv_ind != -1 && uv_start != -1); - BLI_assert(uv_ind - uv_start < MAX_MTFACE); - dm->tangent_mask |= 1 << (uv_ind - uv_start); - BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); - } - BLI_assert(dm->tangent_mask == tangent_mask); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - } -#ifdef USE_LOOPTRI_DETECT_QUADS - if (face_as_quad_map) { - MEM_freeN(face_as_quad_map); - } -#undef USE_LOOPTRI_DETECT_QUADS -#endif + if (CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV) == 0) { + return; } - /* Update active layer index */ - int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n); - int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name); - CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index); - /* Update render layer index */ - uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n); - tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name); - CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index); + const float (*poly_normals)[3] = bmdm->polyNos; + const float (*loop_normals)[3] = CustomData_get_layer(&dm->loopData, CD_NORMAL); + const float (*vert_orco)[3] = dm->getVertDataArray(dm, CD_ORCO); /* can be NULL */ + BKE_editmesh_loop_tangent_calc( + em, calc_active_tangent, + tangent_names, tangent_names_len, + poly_normals, loop_normals, + vert_orco, + &dm->loopData, dm->numLoopData, + &dm->tangent_mask); } -/** \} */ - static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm)) { @@ -812,39 +459,6 @@ static void emDM_drawMappedEdgesInterp( } } -static void emDM_drawUVEdges(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMFace *efa; - BMIter iter; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - if (UNLIKELY(cd_loop_uv_offset == -1)) { - return; - } - - glBegin(GL_LINES); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - const float *uv, *uv_prev; - - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) - continue; - - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter->prev, cd_loop_uv_offset))->uv; - do { - uv = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; - glVertex2fv(uv); - glVertex2fv(uv_prev); - uv_prev = uv; - } while ((l_iter = l_iter->next) != l_first); - } - glEnd(); -} - static void emDM_foreachMappedLoop( DerivedMesh *dm, void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]), @@ -1193,20 +807,6 @@ static void emDM_drawMappedFaces( } } -static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset) -{ - luv[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_uv_offset); - luv[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_uv_offset); - luv[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_uv_offset); -} - -static void bmdm_get_tri_col(BMLoop *ltri[3], MLoopCol *lcol[3], const int cd_loop_color_offset) -{ - lcol[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_color_offset); - lcol[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_color_offset); - lcol[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_color_offset); -} - static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4]) { lcol[0] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[0]->v)]; @@ -1214,204 +814,6 @@ static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned c lcol[2] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[2]->v)]; } -static void emDM_drawFacesTex_common( - DerivedMesh *dm, - DMSetDrawOptionsTex drawParams, - DMSetDrawOptionsMappedTex drawParamsMapped, - DMCompareDrawOptions compareDrawOptions, - void *userData) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMEditMesh *em = bmdm->em; - BMesh *bm = em->bm; - struct BMLoop *(*looptris)[3] = em->looptris; - BMFace *efa; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - MLoopUV *luv[3], dummyluv = {{0}}; - MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); - unsigned char(*color_vert_array)[4] = em->derivedVertColor; - bool has_uv = (cd_loop_uv_offset != -1); - bool has_vcol_preview = (color_vert_array != NULL); - bool has_vcol = (cd_loop_color_offset != -1) && (has_vcol_preview == false); - bool has_vcol_any = (has_vcol_preview || has_vcol); - int i; - - (void) compareDrawOptions; - - luv[0] = luv[1] = luv[2] = &dummyluv; - - // dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */ - - /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ - BM_mesh_elem_index_ensure(bm, BM_FACE); - - /* call again below is ok */ - if (has_vcol_preview) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - - if (bmdm->vertexCos) { - /* add direct access */ - const float (*vertexCos)[3] = bmdm->vertexCos; - const float (*vertexNos)[3]; - const float (*polyNos)[3]; - - emDM_ensureVertNormals(bmdm); - emDM_ensurePolyNormals(bmdm); - vertexNos = bmdm->vertexNos; - polyNos = bmdm->polyNos; - - BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT); - - for (i = 0; i < em->tottri; i++) { - BMLoop **ltri = looptris[i]; - MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL; - /*unsigned char *cp = NULL;*/ /*UNUSED*/ - int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH); - DMDrawOption draw_option; - - efa = ltri[0]->f; - - if (drawParams) { - draw_option = drawParams(tp, has_vcol, efa->mat_nr); - } - else if (drawParamsMapped) - draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr); - else - draw_option = DM_DRAW_OPTION_NORMAL; - - if (draw_option != DM_DRAW_OPTION_SKIP) { - - if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset); - if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset); - else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array); - - glBegin(GL_TRIANGLES); - if (!drawSmooth) { - glNormal3fv(polyNos[BM_elem_index_get(efa)]); - - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]); - } - else { - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]); - } - glEnd(); - } - } - } - else { - BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT); - - for (i = 0; i < em->tottri; i++) { - BMLoop **ltri = looptris[i]; - MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL; - /*unsigned char *cp = NULL;*/ /*UNUSED*/ - int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH); - DMDrawOption draw_option; - - efa = ltri[0]->f; - - if (drawParams) - draw_option = drawParams(tp, has_vcol, efa->mat_nr); - else if (drawParamsMapped) - draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr); - else - draw_option = DM_DRAW_OPTION_NORMAL; - - if (draw_option != DM_DRAW_OPTION_SKIP) { - - if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset); - if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset); - else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array); - - glBegin(GL_TRIANGLES); - if (!drawSmooth) { - glNormal3fv(efa->no); - - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(ltri[0]->v->co); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(ltri[1]->v->co); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(ltri[2]->v->co); - } - else { - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[0]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]); - else glNormal3fv(ltri[0]->v->no); - glVertex3fv(ltri[0]->v->co); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[1]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]); - else glNormal3fv(ltri[1]->v->no); - glVertex3fv(ltri[1]->v->co); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor3ubv((const GLubyte *)&(lcol[2]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]); - else glNormal3fv(ltri[2]->v->no); - glVertex3fv(ltri[2]->v->co); - } - glEnd(); - } - } - } -} - -static void emDM_drawFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag UNUSED(flag)) -{ - emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); -} - -static void emDM_drawMappedFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsMappedTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag UNUSED(flag)) -{ - emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); -} - /** * \note * @@ -2057,14 +1459,8 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type) if (type == CD_MTFACE || type == CD_MCOL) { const char *bmdata; char *data; - bool has_type_source = false; - if (type == CD_MTFACE) { - has_type_source = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY); - } - else { - has_type_source = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL); - } + bool has_type_source = CustomData_has_layer(&bm->ldata, (type == CD_MTFACE) ? CD_MLOOPUV : CD_MLOOPCOL); if (has_type_source) { /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */ @@ -2080,15 +1476,8 @@ static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type) if (type == CD_MTFACE) { const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); for (i = 0; i < bmdm->em->tottri; i++, data += size) { - BMFace *efa = looptris[i][0]->f; - - // bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); - bmdata = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - ME_MTEXFACE_CPY(((MTFace *)data), ((const MTexPoly *)bmdata)); for (j = 0; j < 3; j++) { // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPUV); bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_uv_offset); @@ -2282,12 +1671,9 @@ DerivedMesh *getEditDerivedBMesh( bmdm->dm.drawMappedEdges = emDM_drawMappedEdges; bmdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp; bmdm->dm.drawMappedFaces = emDM_drawMappedFaces; - bmdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex; bmdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL; bmdm->dm.drawMappedFacesMat = emDM_drawMappedFacesMat; - bmdm->dm.drawFacesTex = emDM_drawFacesTex; bmdm->dm.drawFacesGLSL = emDM_drawFacesGLSL; - bmdm->dm.drawUVEdges = emDM_drawUVEdges; bmdm->dm.release = emDM_release; diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index fea3c24d322..c95da3b2569 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -165,26 +165,6 @@ void BKE_editmesh_tessface_calc(BMEditMesh *em) #endif } -void BKE_editmesh_update_linked_customdata(BMEditMesh *em) -{ - BMesh *bm = em->bm; - int act; - - if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) { - act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act); - - act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act); - - act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act); - - act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act); - } -} - void BKE_editmesh_free_derivedmesh(BMEditMesh *em) { if (em->derivedCage) { diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c new file mode 100644 index 00000000000..b04fc753f7a --- /dev/null +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -0,0 +1,420 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/editmesh_tangent.c + * \ingroup bke + */ + +#include "BLI_math.h" +#include "BLI_task.h" + +#include "BKE_DerivedMesh.h" + +#include "BKE_mesh.h" +#include "BKE_mesh_tangent.h" /* for utility functions */ +#include "BKE_editmesh.h" +#include "BKE_editmesh_tangent.h" + +#include "MEM_guardedalloc.h" + +/* interface */ +#include "mikktspace.h" + +/** \name Tangent Space Calculation + * \{ */ + +/* Necessary complexity to handle looptri's as quads for correct tangents */ +#define USE_LOOPTRI_DETECT_QUADS + +typedef struct { + const float (*precomputedFaceNormals)[3]; + const float (*precomputedLoopNormals)[3]; + const BMLoop *(*looptris)[3]; + int cd_loop_uv_offset; /* texture coordinates */ + const float (*orco)[3]; + float (*tangent)[4]; /* destination */ + int numTessFaces; + +#ifdef USE_LOOPTRI_DETECT_QUADS + /* map from 'fake' face index to looptri, + * quads will point to the first looptri of the quad */ + const int *face_as_quad_map; + int num_face_as_quad_map; +#endif + +} SGLSLEditMeshToTangent; + +#ifdef USE_LOOPTRI_DETECT_QUADS +/* seems weak but only used on quads */ +static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index) +{ + const BMLoop *l = BM_FACE_FIRST_LOOP(f); + while (vert_index--) { + l = l->next; + } + return l; +} +#endif + +static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + +#ifdef USE_LOOPTRI_DETECT_QUADS + return pMesh->num_face_as_quad_map; +#else + return pMesh->numTessFaces; +#endif +} + +static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ +#ifdef USE_LOOPTRI_DETECT_QUADS + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + if (pMesh->face_as_quad_map) { + const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + return 4; + } + } + return 3; +#else + UNUSED_VARS(pContext, face_num); + return 3; +#endif +} + +static void emdm_ts_GetPosition( + const SMikkTSpaceContext *pContext, float r_co[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + + const float *co; + +finally: + co = l->v->co; + copy_v3_v3(r_co, co); +} + +static void emdm_ts_GetTextureCoordinate( + const SMikkTSpaceContext *pContext, float r_uv[2], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + +finally: + if (pMesh->cd_loop_uv_offset != -1) { + const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset); + copy_v2_v2(r_uv, uv); + } + else { + const float *orco = pMesh->orco[BM_elem_index_get(l->v)]; + map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); + } +} + +static void emdm_ts_GetNormal( + const SMikkTSpaceContext *pContext, float r_no[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + +finally: + if (pMesh->precomputedLoopNormals) { + copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]); + } + else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */ + if (pMesh->precomputedFaceNormals) { + copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]); + } + else { + copy_v3_v3(r_no, l->f->no); + } + } + else { + copy_v3_v3(r_no, l->v->no); + } +} + +static void emdm_ts_SetTSpace( + const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + + float *pRes; + +finally: + pRes = pMesh->tangent[BM_elem_index_get(l)]; + copy_v3_v3(pRes, fvTangent); + pRes[3] = fSign; +} + +static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +{ + struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; + /* new computation method */ + { + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + sContext.m_pUserData = mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = emdm_ts_GetNumFaces; + sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace; + sInterface.m_getPosition = emdm_ts_GetPosition; + sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate; + sInterface.m_getNormal = emdm_ts_GetNormal; + sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace; + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } +} + +/** + * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data. + * + * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`. + * This is done because #CD_TANGENT is cache data used only for drawing. + */ +void BKE_editmesh_loop_tangent_calc( + BMEditMesh *em, bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_len, + const float (*poly_normals)[3], + const float (*loop_normals)[3], + const float (*vert_orco)[3], + /* result */ + CustomData *loopdata_out, + const uint loopdata_out_len, + char *tangent_mask_curr_p) +{ + BMesh *bm = em->bm; + + BLI_assert(CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) != 0); + + int act_uv_n = -1; + int ren_uv_n = -1; + bool calc_act = false; + bool calc_ren = false; + char act_uv_name[MAX_NAME]; + char ren_uv_name[MAX_NAME]; + char tangent_mask = 0; + char tangent_mask_curr = *tangent_mask_curr_p; + + BKE_mesh_calc_loop_tangent_step_0( + &bm->ldata, calc_active_tangent, tangent_names, tangent_names_len, + &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); + + if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) { + for (int i = 0; i < tangent_names_len; i++) + if (tangent_names[i][0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, tangent_names[i]); + if (calc_act && act_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, act_uv_name); + if (calc_ren && ren_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, loopdata_out_len, ren_uv_name); + int totface = em->tottri; +#ifdef USE_LOOPTRI_DETECT_QUADS + int num_face_as_quad_map; + int *face_as_quad_map = NULL; + + /* map faces to quads */ + if (em->tottri != bm->totface) { + /* over alloc, since we dont know how many ngon or quads we have */ + + /* map fake face index to looptri */ + face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__); + int i, j; + for (i = 0, j = 0; j < totface; i++, j++) { + face_as_quad_map[i] = j; + /* step over all quads */ + if (em->looptris[j][0]->f->len == 4) { + j++; /* skips the nest looptri */ + } + } + num_face_as_quad_map = i; + } + else { + num_face_as_quad_map = totface; + } +#endif + /* Calculation */ + { + TaskScheduler *scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + task_pool = BLI_task_pool_create(scheduler, NULL); + + tangent_mask_curr = 0; + /* Calculate tangent layers */ + SGLSLEditMeshToTangent data_array[MAX_MTFACE]; + int index = 0; + int n = 0; + CustomData_update_typemap(loopdata_out); + const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT); + for (n = 0; n < tangent_layer_num; n++) { + index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n); + BLI_assert(n < MAX_MTFACE); + SGLSLEditMeshToTangent *mesh2tangent = &data_array[n]; + mesh2tangent->numTessFaces = em->tottri; +#ifdef USE_LOOPTRI_DETECT_QUADS + mesh2tangent->face_as_quad_map = face_as_quad_map; + mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; +#endif + mesh2tangent->precomputedFaceNormals = poly_normals; /* dm->getPolyDataArray(dm, CD_NORMAL) */ + /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), + * have to check this is valid... + */ + mesh2tangent->precomputedLoopNormals = loop_normals; + mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n); + + /* needed for indexing loop-tangents */ + int htype_index = BM_LOOP; + if (mesh2tangent->cd_loop_uv_offset == -1) { + mesh2tangent->orco = vert_orco; + if (!mesh2tangent->orco) + continue; + /* needed for orco lookups */ + htype_index |= BM_VERT; + } + if (mesh2tangent->precomputedFaceNormals) { + /* needed for face normal lookups */ + htype_index |= BM_FACE; + } + BM_mesh_elem_index_ensure(bm, htype_index); + + mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris; + mesh2tangent->tangent = loopdata_out->layers[index].data; + + /* Fill the resulting tangent_mask */ + int uv_ind = CustomData_get_named_layer_index( + &bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name); + int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV); + BLI_assert(uv_ind != -1 && uv_start != -1); + BLI_assert(uv_ind - uv_start < MAX_MTFACE); + tangent_mask_curr |= 1 << (uv_ind - uv_start); + BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); + } + + BLI_assert(tangent_mask_curr == tangent_mask); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + } +#ifdef USE_LOOPTRI_DETECT_QUADS + if (face_as_quad_map) { + MEM_freeN(face_as_quad_map); + } +#undef USE_LOOPTRI_DETECT_QUADS +#endif + } + + *tangent_mask_curr_p = tangent_mask_curr; + + /* Update active layer index */ + int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n); + int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[uv_index].name); + CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index); + + /* Update render layer index */ + uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n); + tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[uv_index].name); + CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index); +} + +/** \} */
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 38f5c00941c..2213094cd0b 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -64,6 +64,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -209,6 +210,7 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src, EffectorWeights *weights, bool for_simulation) { + SceneLayer *sl = BKE_scene_layer_context_active(scene); /* Can't get sl from the calling modifiers yet */ Base *base; unsigned int layer= ob_src->lay; ListBase *effectors = NULL; @@ -231,17 +233,15 @@ ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src } } else { - for (base = scene->base.first; base; base= base->next) { - if ( (base->lay & layer) ) { - if ( base->object->pd && base->object->pd->forcefield ) - add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation); + for (base = FIRSTBASE_NEW; base; base = base->next) { + if ( base->object->pd && base->object->pd->forcefield ) + add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation); - if ( base->object->particlesystem.first ) { - ParticleSystem *psys= base->object->particlesystem.first; + if ( base->object->particlesystem.first ) { + ParticleSystem *psys= base->object->particlesystem.first; - for ( ; psys; psys=psys->next ) - add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation); - } + for ( ; psys; psys=psys->next ) + add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation); } } } diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 414802dd250..f969c932333 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -45,8 +45,6 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" - -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_group.h" #include "BKE_icons.h" @@ -132,18 +130,11 @@ static bool group_object_add_internal(Group *group, Object *ob) return true; } -bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base) +bool BKE_group_object_add(Group *group, Object *object) { if (group_object_add_internal(group, object)) { if ((object->flag & OB_FROMGROUP) == 0) { - - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - object->flag |= OB_FROMGROUP; - - if (base) - base->flag |= OB_FROMGROUP; } return true; } @@ -210,18 +201,12 @@ bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group) return group_object_cyclic_check_internal(object, group); } -bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base) +bool BKE_group_object_unlink(Group *group, Object *object) { if (group_object_unlink_internal(group, object)) { /* object can be NULL */ if (object && BKE_group_object_find(NULL, object) == NULL) { - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - object->flag &= ~OB_FROMGROUP; - - if (base) - base->flag &= ~OB_FROMGROUP; } return true; } @@ -329,7 +314,7 @@ static void group_replaces_nla(Object *parent, Object *target, char mode) * you can draw everything, leaves tags in objects to signal it needs further updating */ /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ -void BKE_group_handle_recalc_and_update(EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group) +void BKE_group_handle_recalc_and_update(struct EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group) { GroupObject *go; diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 7669c4ba112..70cf0d5a445 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -42,6 +42,7 @@ #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" #include "DNA_brush_types.h" @@ -252,6 +253,7 @@ PreviewImage **BKE_previewimg_id_get_p(ID *id) ID_PRV_CASE(ID_OB, Object); ID_PRV_CASE(ID_GR, Group); ID_PRV_CASE(ID_SCE, Scene); + ID_PRV_CASE(ID_SCR, bScreen); #undef ID_PRV_CASE } diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 70d037d85f3..487635f06ad 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -81,8 +81,9 @@ static IDType idtypes[] = { { ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE }, { ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE }, { ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE }, + { ID_LP, "LightProbe", "light_probes", BLT_I18NCONTEXT_ID_LIGHTPROBE, IDTYPE_FLAGS_ISLINKABLE }, { ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, 0 }, + { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE }, { ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */ { ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE }, { ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE }, @@ -91,6 +92,7 @@ static IDType idtypes[] = { { ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE }, { ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE }, { ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 }, + { ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE }, /** Keep last, not an ID exactly, only include for completeness */ { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */ @@ -203,6 +205,7 @@ int BKE_idcode_to_idfilter(const short idcode) CASE_IDFILTER(PA); CASE_IDFILTER(PAL); CASE_IDFILTER(PC); + CASE_IDFILTER(LP); CASE_IDFILTER(SCE); CASE_IDFILTER(SPK); CASE_IDFILTER(SO); @@ -210,6 +213,7 @@ int BKE_idcode_to_idfilter(const short idcode) CASE_IDFILTER(TXT); CASE_IDFILTER(VF); CASE_IDFILTER(WO); + CASE_IDFILTER(WS); default: return 0; } @@ -247,6 +251,7 @@ short BKE_idcode_from_idfilter(const int idfilter) CASE_IDFILTER(PA); CASE_IDFILTER(PAL); CASE_IDFILTER(PC); + CASE_IDFILTER(LP); CASE_IDFILTER(SCE); CASE_IDFILTER(SPK); CASE_IDFILTER(SO); @@ -294,6 +299,7 @@ int BKE_idcode_to_index(const short idcode) CASE_IDINDEX(PA); CASE_IDINDEX(PAL); CASE_IDINDEX(PC); + CASE_IDINDEX(LP); CASE_IDINDEX(SCE); CASE_IDINDEX(SCR); CASE_IDINDEX(SPK); @@ -303,6 +309,7 @@ int BKE_idcode_to_index(const short idcode) CASE_IDINDEX(VF); CASE_IDINDEX(WM); CASE_IDINDEX(WO); + CASE_IDINDEX(WS); } BLI_assert(0); diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index e98181be444..a3bd15252cb 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -474,6 +474,7 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop) BLI_assert(prop->type == IDP_GROUP); newp = idp_generic_copy(prop); newp->len = prop->len; + newp->subtype = prop->subtype; for (link = prop->data.group.first; link; link = link->next) { BLI_addtail(&newp->data.group, IDP_CopyProperty(link)); @@ -600,6 +601,7 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop) /** * If a property is missing in \a dest, add it. + * Do it recursively. */ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite) { @@ -610,13 +612,29 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw if (do_overwrite) { for (prop = src->data.group.first; prop; prop = prop->next) { + if (prop->type == IDP_GROUP) { + IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); + + if (prop_exist != NULL) { + IDP_MergeGroup(prop_exist, prop, do_overwrite); + continue; + } + } + IDProperty *copy = IDP_CopyProperty(prop); IDP_ReplaceInGroup(dest, copy); } } else { for (prop = src->data.group.first; prop; prop = prop->next) { - if (IDP_GetPropertyFromGroup(dest, prop->name) == NULL) { + IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); + if (prop_exist != NULL) { + if (prop->type == IDP_GROUP) { + IDP_MergeGroup(prop_exist, prop, do_overwrite); + continue; + } + } + else { IDProperty *copy = IDP_CopyProperty(prop); dest->len++; BLI_addtail(&dest->data.group, copy); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 92c796ad321..4d3e2bbc3c8 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -81,6 +81,7 @@ #include "BKE_scene.h" #include "BKE_node.h" #include "BKE_sequencer.h" /* seq_foreground_frame_get() */ +#include "BKE_workspace.h" #include "BLF_api.h" @@ -2544,8 +2545,9 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata, /* image window, compo node users */ for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */ for (win = wm->windows.first; win; win = win->next) { - ScrArea *sa; - for (sa = win->screen->areabase.first; sa; sa = sa->next) { + const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { if (sa->spacetype == SPACE_VIEW3D) { View3D *v3d = sa->spacedata.first; BGpic *bgpic; diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 69a2067f4e6..bf4b1b6a680 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -69,6 +69,7 @@ void BKE_lamp_init(Lamp *la) la->bufsize = 512; la->clipsta = 0.5f; la->clipend = 40.0f; + la->bleedexp = 120.0f; la->samp = 3; la->bias = 1.0f; la->soft = 3.0f; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 54cfae620a1..c03aa0cd155 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -53,7 +53,6 @@ #include "BKE_anim.h" #include "BKE_cdderivedmesh.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_key.h" @@ -307,6 +306,8 @@ void BKE_lattice_free(Lattice *lt) { BKE_animdata_free(<->id, false); + BKE_lattice_batch_cache_free(lt); + MEM_SAFE_FREE(lt->def); if (lt->dvert) { BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); @@ -1227,8 +1228,24 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys) /* **** Depsgraph evaluation **** */ -void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx), +void BKE_lattice_eval_geometry(struct EvaluationContext *UNUSED(eval_ctx), Lattice *UNUSED(latt)) { } +/* Draw Engine */ +void (*BKE_lattice_batch_cache_dirty_cb)(Lattice *lt, int mode) = NULL; +void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL; + +void BKE_lattice_batch_cache_dirty(Lattice *lt, int mode) +{ + if (lt->batch_cache) { + BKE_lattice_batch_cache_dirty_cb(lt, mode); + } +} +void BKE_lattice_batch_cache_free(Lattice *lt) +{ + if (lt->batch_cache) { + BKE_lattice_batch_cache_free_cb(lt); + } +}
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c new file mode 100644 index 00000000000..d600f753d75 --- /dev/null +++ b/source/blender/blenkernel/intern/layer.c @@ -0,0 +1,1821 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/layer.c + * \ingroup bke + */ + +#include <string.h> + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_string_utils.h" +#include "BLT_translation.h" + +#include "BKE_collection.h" +#include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_workspace.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_node_types.h" +#include "DNA_scene_types.h" +#include "DNA_windowmanager_types.h" + +#include "DRW_engine.h" + +#include "MEM_guardedalloc.h" + +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf + +/* prototype */ +struct EngineSettingsCB_Type; +static void layer_collection_free(SceneLayer *sl, LayerCollection *lc); +static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc); +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc); +static IDProperty *collection_engine_settings_create(struct EngineSettingsCB_Type *ces_type, const bool populate); +static IDProperty *collection_engine_get(IDProperty *root, const int type, const char *engine_name); +static void collection_engine_settings_init(IDProperty *root, const bool populate); +static void layer_engine_settings_init(IDProperty *root, const bool populate); +static void object_bases_Iterator_next(BLI_Iterator *iter, const int flag); + +/* RenderLayer */ + +/** + * Returns the SceneLayer to be used for rendering + * Most of the time BKE_scene_layer_context_active should be used instead + */ +SceneLayer *BKE_scene_layer_render_active(const Scene *scene) +{ + SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer); + BLI_assert(sl); + return sl; +} + +/** + * Returns the SceneLayer to be used for drawing, outliner, and other context related areas. + */ +SceneLayer *BKE_scene_layer_context_active_ex(const Main *bmain, const Scene *UNUSED(scene)) +{ + /* XXX We should really pass the workspace as argument, but would require + * some bigger changes since it's often not available where we call this. + * Just working around this by getting active window from WM for now */ + for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { + /* Called on startup, so 'winactive' may not be set, in that case fall back to first window. */ + wmWindow *win = wm->winactive ? wm->winactive : wm->windows.first; + const WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + return BKE_workspace_render_layer_get(workspace); + } + + return NULL; +} +SceneLayer *BKE_scene_layer_context_active(const Scene *scene) +{ + return BKE_scene_layer_context_active_ex(G.main, scene); +} + +/** + * Add a new renderlayer + * by default, a renderlayer has the master collection + */ +SceneLayer *BKE_scene_layer_add(Scene *scene, const char *name) +{ + if (!name) { + name = DATA_("Render Layer"); + } + + IDPropertyTemplate val = {0}; + SceneLayer *sl = MEM_callocN(sizeof(SceneLayer), "Scene Layer"); + sl->flag |= SCENE_LAYER_RENDER; + + sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + layer_engine_settings_init(sl->properties, false); + + BLI_addtail(&scene->render_layers, sl); + + /* unique name */ + BLI_strncpy_utf8(sl->name, name, sizeof(sl->name)); + BLI_uniquename(&scene->render_layers, sl, DATA_("SceneLayer"), '.', offsetof(SceneLayer, name), sizeof(sl->name)); + + SceneCollection *sc = BKE_collection_master(scene); + layer_collection_add(sl, NULL, sc); + + return sl; +} + +/** + * Free (or release) any data used by this SceneLayer. + */ +void BKE_scene_layer_free(SceneLayer *sl) +{ + sl->basact = NULL; + + for (Base *base = sl->object_bases.first; base; base = base->next) { + if (base->collection_properties) { + IDP_FreeProperty(base->collection_properties); + MEM_freeN(base->collection_properties); + } + } + BLI_freelistN(&sl->object_bases); + + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_free(NULL, lc); + } + BLI_freelistN(&sl->layer_collections); + + if (sl->properties) { + IDP_FreeProperty(sl->properties); + MEM_freeN(sl->properties); + } + + if (sl->properties_evaluated) { + IDP_FreeProperty(sl->properties_evaluated); + MEM_freeN(sl->properties_evaluated); + } + + for (SceneLayerEngineData *sled = sl->drawdata.first; sled; sled = sled->next) { + if (sled->storage) { + if (sled->free) { + sled->free(sled->storage); + } + MEM_freeN(sled->storage); + } + } + BLI_freelistN(&sl->drawdata); + + MEM_SAFE_FREE(sl->stats); + + MEM_freeN(sl); +} + +/** + * Set the render engine of a renderlayer + */ +void BKE_scene_layer_engine_set(SceneLayer *sl, const char *engine) +{ + BLI_strncpy_utf8(sl->engine, engine, sizeof(sl->engine)); +} + +/** + * Tag all the selected objects of a renderlayer + */ +void BKE_scene_layer_selected_objects_tag(SceneLayer *sl, const int tag) +{ + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + base->object->flag |= tag; + } + else { + base->object->flag &= ~tag; + } + } +} + +static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc) +{ + for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) { + if (lcn == lc) { + return true; + } + if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) { + return true; + } + } + return false; +} + +/** + * Find the SceneLayer a LayerCollection belongs to + */ +SceneLayer *BKE_scene_layer_find_from_collection(const Scene *scene, LayerCollection *lc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + if (find_scene_collection_in_scene_collections(&sl->layer_collections, lc)) { + return sl; + } + } + return NULL; +} + +/* Base */ + +Base *BKE_scene_layer_base_find(SceneLayer *sl, Object *ob) +{ + return BLI_findptr(&sl->object_bases, ob, offsetof(Base, object)); +} + +void BKE_scene_layer_base_deselect_all(SceneLayer *sl) +{ + Base *base; + + for (base = sl->object_bases.first; base; base = base->next) { + base->flag &= ~BASE_SELECTED; + } +} + +void BKE_scene_layer_base_select(struct SceneLayer *sl, Base *selbase) +{ + sl->basact = selbase; + if ((selbase->flag & BASE_SELECTABLED) != 0) { + selbase->flag |= BASE_SELECTED; + } +} + +static void scene_layer_object_base_unref(SceneLayer *sl, Base *base) +{ + base->refcount--; + + /* It only exists in the RenderLayer */ + if (base->refcount == 0) { + if (sl->basact == base) { + sl->basact = NULL; + } + + if (base->collection_properties) { + IDP_FreeProperty(base->collection_properties); + MEM_freeN(base->collection_properties); + } + + BLI_remlink(&sl->object_bases, base); + MEM_freeN(base); + } +} + +/** + * Return the base if existent, or create it if necessary + * Always bump the refcount + */ +static Base *object_base_add(SceneLayer *sl, Object *ob) +{ + Base *base; + base = BKE_scene_layer_base_find(sl, ob); + + if (base == NULL) { + base = MEM_callocN(sizeof(Base), "Object Base"); + + /* Do not bump user count, leave it for SceneCollections. */ + base->object = ob; + BLI_addtail(&sl->object_bases, base); + + IDPropertyTemplate val = {0}; + base->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + } + + base->refcount++; + return base; +} + +/* LayerCollection */ + +/** + * When freeing the entire SceneLayer at once we don't bother with unref + * otherwise SceneLayer is passed to keep the syncing of the LayerCollection tree + */ +static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) +{ + if (sl) { + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + scene_layer_object_base_unref(sl, link->data); + } + } + + BLI_freelistN(&lc->object_bases); + BLI_freelistN(&lc->overrides); + + if (lc->properties) { + IDP_FreeProperty(lc->properties); + MEM_freeN(lc->properties); + } + + if (lc->properties_evaluated) { + IDP_FreeProperty(lc->properties_evaluated); + MEM_freeN(lc->properties_evaluated); + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_free(sl, nlc); + } + + BLI_freelistN(&lc->layer_collections); +} + +/** + * Free (or release) LayerCollection from SceneLayer + * (does not free the LayerCollection itself). + */ +void BKE_layer_collection_free(SceneLayer *sl, LayerCollection *lc) +{ + layer_collection_free(sl, lc); +} + +/* LayerCollection */ + +/** + * Recursively get the collection for a given index + */ +static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + if (*i == number) { + return lc; + } + + (*i)++; + + LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i); + if (lc_nested) { + return lc_nested; + } + } + return NULL; +} + +/** + * Get the active collection + */ +LayerCollection *BKE_layer_collection_get_active(SceneLayer *sl) +{ + int i = 0; + return collection_from_index(&sl->layer_collections, sl->active_collection, &i); +} + + +/** + * Return layer collection to add new object(s). + * Create one if none exists. + */ +LayerCollection *BKE_layer_collection_get_active_ensure(Scene *scene, SceneLayer *sl) +{ + LayerCollection *lc = BKE_layer_collection_get_active(sl); + + if (lc == NULL) { + BLI_assert(BLI_listbase_is_empty(&sl->layer_collections)); + /* When there is no collection linked to this SceneLayer, create one. */ + SceneCollection *sc = BKE_collection_add(scene, NULL, NULL); + lc = BKE_collection_link(sl, sc); + } + + return lc; +} + +/** + * Recursively get the count of collections + */ +static int collection_count(ListBase *lb) +{ + int i = 0; + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + i += collection_count(&lc->layer_collections) + 1; + } + return i; +} + +/** + * Get the total number of collections + * (including all the nested collections) + */ +int BKE_layer_collection_count(SceneLayer *sl) +{ + return collection_count(&sl->layer_collections); +} + +/** + * Recursively get the index for a given collection + */ +static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i) +{ + for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) { + if (lcol == lc) { + return *i; + } + + (*i)++; + + int i_nested = index_from_collection(&lcol->layer_collections, lc, i); + if (i_nested != -1) { + return i_nested; + } + } + return -1; +} + +/** + * Return -1 if not found + */ +int BKE_layer_collection_findindex(SceneLayer *sl, const LayerCollection *lc) +{ + int i = 0; + return index_from_collection(&sl->layer_collections, lc, &i); +} + +/** + * Lookup the listbase that contains \a lc. + */ +static ListBase *layer_collection_listbase_find(ListBase *lb, LayerCollection *lc) +{ + for (LayerCollection *lc_iter = lb->first; lc_iter; lc_iter = lc_iter->next) { + if (lc_iter == lc) { + return lb; + } + + ListBase *lb_child_result; + if ((lb_child_result = layer_collection_listbase_find(&lc_iter->layer_collections, lc))) { + return lb_child_result; + } + } + + return NULL; +} + +#if 0 +/** + * Lookup the listbase that contains \a sc. + */ +static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *sc) +{ + for (SceneCollection *sc_iter = lb->first; sc_iter; sc_iter = sc_iter->next) { + if (sc_iter == sc) { + return lb; + } + + ListBase *lb_child_result; + if ((lb_child_result = scene_collection_listbase_find(&sc_iter->scene_collections, sc))) { + return lb_child_result; + } + } + + return NULL; +} +#endif + +/* ---------------------------------------------------------------------- */ +/* Outliner drag and drop */ + +/** + * Nest a LayerCollection into another one + * Both collections must be from the same SceneLayer, return true if succeded. + * + * The LayerCollection will effectively be moved into the + * new (nested) position. So all the settings, overrides, ... go with it, and + * if the collection was directly linked to the SceneLayer it's then unlinked. + * + * For the other SceneLayers we simply resync the tree, without changing directly + * linked collections (even if they link to the same SceneCollection) + * + * \param lc_src LayerCollection to nest into \a lc_dst + * \param lc_dst LayerCollection to have \a lc_src inserted into + */ + +static void layer_collection_swap( + SceneLayer *sl, ListBase *lb_a, ListBase *lb_b, + LayerCollection *lc_a, LayerCollection *lc_b) +{ + if (lb_a == NULL) { + lb_a = layer_collection_listbase_find(&sl->layer_collections, lc_a); + } + + if (lb_b == NULL) { + lb_b = layer_collection_listbase_find(&sl->layer_collections, lc_b); + } + + BLI_assert(lb_a); + BLI_assert(lb_b); + + BLI_listbases_swaplinks(lb_a, lb_b, lc_a, lc_b); +} + +/** + * Move \a lc_src into \a lc_dst. Both have to be stored in \a sl. + * If \a lc_src is directly linked to the SceneLayer it's unlinked + */ +bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src); + bool is_directly_linked = false; + + if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) { + return false; + } + + /* We can't nest the collection into itself */ + if (lc_src->scene_collection == lc_dst->scene_collection) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (lc_dst->layer_collections.last == lc_src) { + return false; + } + + /* Collection is already where we want it to be in the scene tree + * but we want to swap it in the layer tree still */ + if (lc_dst->scene_collection->scene_collections.last == lc_src->scene_collection) { + LayerCollection *lc_swap = lc_dst->layer_collections.last; + layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_dst->layer_collections.last, lc_src); + + if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) { + BKE_collection_unlink(sl, lc_swap); + } + return true; + } + else { + LayerCollection *lc_temp; + is_directly_linked = BLI_findindex(&sl->layer_collections, lc_src) != -1; + + if (!is_directly_linked) { + /* lc_src will be invalid after BKE_collection_move_into! + * so we swap it with lc_temp to preserve its settings */ + lc_temp = BKE_collection_link(sl, lc_src->scene_collection); + layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src); + } + + if (!BKE_collection_move_into(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!is_directly_linked) { + /* Swap back and remove */ + layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src); + BKE_collection_unlink(sl, lc_temp); + } + return false; + } + } + + LayerCollection *lc_new = BLI_findptr(&lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection)); + BLI_assert(lc_new); + layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_new, lc_src); + + /* If it's directly linked, unlink it after the swap */ + if (BLI_findindex(&sl->layer_collections, lc_new) != -1) { + BKE_collection_unlink(sl, lc_new); + } + + return true; +} + +/** + * Move \a lc_src above \a lc_dst. Both have to be stored in \a sl. + * If \a lc_src is directly linked to the SceneLayer it's unlinked + */ +bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src); + const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1; + const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1; + + if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (lc_dst->prev == lc_src) { + return false; + } + + /* Collection is already where we want it to be in the scene tree + * but we want to swap it in the layer tree still */ + if (lc_dst->prev && lc_dst->prev->scene_collection == lc_src->scene_collection) { + LayerCollection *lc_swap = lc_dst->prev; + layer_collection_swap(sl, NULL, NULL, lc_dst->prev, lc_src); + + if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) { + BKE_collection_unlink(sl, lc_swap); + } + return true; + } + /* We don't allow to move above/below a directly linked collection + * unless the source collection is also directly linked */ + else if (is_directly_linked_dst) { + /* Both directly linked to the SceneLayer, just need to swap */ + if (is_directly_linked_src) { + BLI_remlink(&sl->layer_collections, lc_src); + BLI_insertlinkbefore(&sl->layer_collections, lc_dst, lc_src); + return true; + } + else { + return false; + } + } + else { + LayerCollection *lc_temp; + + if (!is_directly_linked_src) { + /* lc_src will be invalid after BKE_collection_move_into! + * so we swap it with lc_temp to preserve its settings */ + lc_temp = BKE_collection_link(sl, lc_src->scene_collection); + layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src); + } + + if (!BKE_collection_move_above(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!is_directly_linked_src) { + /* Swap back and remove */ + layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src); + BKE_collection_unlink(sl, lc_temp); + } + return false; + } + } + + LayerCollection *lc_new = lc_dst->prev; + BLI_assert(lc_new); + layer_collection_swap(sl, NULL, NULL, lc_new, lc_src); + + /* If it's directly linked, unlink it after the swap */ + if (BLI_findindex(&sl->layer_collections, lc_new) != -1) { + BKE_collection_unlink(sl, lc_new); + } + + return true; +} + +/** + * Move \a lc_src below \a lc_dst. Both have to be stored in \a sl. + * If \a lc_src is directly linked to the SceneLayer it's unlinked + */ +bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src); + const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1; + const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1; + + if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (lc_dst->next == lc_src) { + return false; + } + + /* Collection is already where we want it to be in the scene tree + * but we want to swap it in the layer tree still */ + if (lc_dst->next && lc_dst->next->scene_collection == lc_src->scene_collection) { + LayerCollection *lc_swap = lc_dst->next; + layer_collection_swap(sl, NULL, NULL, lc_dst->next, lc_src); + + if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) { + BKE_collection_unlink(sl, lc_swap); + } + return true; + } + /* We don't allow to move above/below a directly linked collection + * unless the source collection is also directly linked */ + else if (is_directly_linked_dst) { + /* Both directly linked to the SceneLayer, just need to swap */ + if (is_directly_linked_src) { + BLI_remlink(&sl->layer_collections, lc_src); + BLI_insertlinkafter(&sl->layer_collections, lc_dst, lc_src); + return true; + } + else { + return false; + } + } + else { + LayerCollection *lc_temp; + + if (!is_directly_linked_src) { + /* lc_src will be invalid after BKE_collection_move_into! + * so we swap it with lc_temp to preserve its settings */ + lc_temp = BKE_collection_link(sl, lc_src->scene_collection); + layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src); + } + + if (!BKE_collection_move_below(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!is_directly_linked_src) { + /* Swap back and remove */ + layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src); + BKE_collection_unlink(sl, lc_temp); + } + return false; + } + } + + LayerCollection *lc_new = lc_dst->next; + BLI_assert(lc_new); + layer_collection_swap(sl, NULL, NULL, lc_new, lc_src); + + /* If it's directly linked, unlink it after the swap */ + if (BLI_findindex(&sl->layer_collections, lc_new) != -1) { + BKE_collection_unlink(sl, lc_new); + } + + return true; +} + +static bool layer_collection_resync(SceneLayer *sl, LayerCollection *lc, const SceneCollection *sc) +{ + if (lc->scene_collection == sc) { + ListBase collections = {NULL}; + BLI_movelisttolist(&collections, &lc->layer_collections); + + for (SceneCollection *sc_nested = sc->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { + LayerCollection *lc_nested = BLI_findptr(&collections, sc_nested, offsetof(LayerCollection, scene_collection)); + if (lc_nested) { + BLI_remlink(&collections, lc_nested); + BLI_addtail(&lc->layer_collections, lc_nested); + } + else { + layer_collection_add(sl, lc, sc_nested); + } + } + + for (LayerCollection *lc_nested = collections.first; lc_nested; lc_nested = lc_nested->next) { + layer_collection_free(sl, lc_nested); + } + BLI_freelistN(&collections); + + BLI_assert(BLI_listbase_count(&lc->layer_collections) == + BLI_listbase_count(&sc->scene_collections)); + + return true; + } + + for (LayerCollection *lc_nested = lc->layer_collections.first; lc_nested; lc_nested = lc_nested->next) { + if (layer_collection_resync(sl, lc_nested, sc)) { + return true; + } + } + + return false; +} + +/** + * Update the scene layers so that any LayerCollection that points + * to \a sc is re-synced again + */ +void BKE_layer_collection_resync(const Scene *scene, const SceneCollection *sc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_resync(sl, lc, sc); + } + } +} + +/* ---------------------------------------------------------------------- */ + +/** + * Link a collection to a renderlayer + * The collection needs to be created separately + */ +LayerCollection *BKE_collection_link(SceneLayer *sl, SceneCollection *sc) +{ + LayerCollection *lc = layer_collection_add(sl, NULL, sc); + sl->active_collection = BKE_layer_collection_findindex(sl, lc); + return lc; +} + +/** + * Unlink a collection base from a renderlayer + * The corresponding collection is not removed from the master collection + */ +void BKE_collection_unlink(SceneLayer *sl, LayerCollection *lc) +{ + BKE_layer_collection_free(sl, lc); + BLI_remlink(&sl->layer_collections, lc); + MEM_freeN(lc); + sl->active_collection = 0; +} + +static void layer_collection_object_add(SceneLayer *sl, LayerCollection *lc, Object *ob) +{ + Base *base = object_base_add(sl, ob); + + /* Only add an object once - prevent SceneCollection->objects and + * SceneCollection->filter_objects to add the same object. */ + + if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) { + return; + } + + bool is_visible = (lc->flag & COLLECTION_VISIBLE) != 0; + bool is_selectable = is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0); + + if (is_visible) { + base->flag |= BASE_VISIBLED; + } + + if (is_selectable) { + base->flag |= BASE_SELECTABLED; + } + + BLI_addtail(&lc->object_bases, BLI_genericNodeN(base)); +} + +static void layer_collection_object_remove(SceneLayer *sl, LayerCollection *lc, Object *ob) +{ + Base *base; + base = BKE_scene_layer_base_find(sl, ob); + + LinkData *link = BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)); + BLI_remlink(&lc->object_bases, link); + MEM_freeN(link); + + scene_layer_object_base_unref(sl, base); +} + +static void layer_collection_objects_populate(SceneLayer *sl, LayerCollection *lc, ListBase *objects) +{ + for (LinkData *link = objects->first; link; link = link->next) { + layer_collection_object_add(sl, lc, link->data); + } +} + +static void layer_collection_populate(SceneLayer *sl, LayerCollection *lc, SceneCollection *sc) +{ + layer_collection_objects_populate(sl, lc, &sc->objects); + layer_collection_objects_populate(sl, lc, &sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + layer_collection_add(sl, lc, nsc); + } +} + +static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc) +{ + IDPropertyTemplate val = {0}; + LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); + + lc->scene_collection = sc; + lc->flag = COLLECTION_VISIBLE | COLLECTION_SELECTABLE; + + lc->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + collection_engine_settings_init(lc->properties, false); + + if (parent != NULL) { + BLI_addtail(&parent->layer_collections, lc); + } + else { + BLI_addtail(&sl->layer_collections, lc); + } + + layer_collection_populate(sl, lc, sc); + + return lc; +} + +/* ---------------------------------------------------------------------- */ + +/** + * See if render layer has the scene collection linked directly, or indirectly (nested) + */ +bool BKE_scene_layer_has_collection(SceneLayer *sl, const SceneCollection *sc) +{ + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + if (find_layer_collection_by_scene_collection(lc, sc) != NULL) { + return true; + } + } + return false; +} + +/** + * See if the object is in any of the scene layers of the scene + */ +bool BKE_scene_has_object(Scene *scene, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + Base *base = BKE_scene_layer_base_find(sl, ob); + if (base) { + return true; + } + } + return false; +} + + +/* ---------------------------------------------------------------------- */ +/* Syncing */ + +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc) +{ + if (lc->scene_collection == sc) { + return lc; + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(nlc, sc); + if (found) { + return found; + } + } + return NULL; +} + +/** + * Add a new LayerCollection for all the SceneLayers that have sc_parent + */ +void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc_parent, SceneCollection *sc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent); + if (lc_parent) { + layer_collection_add(sl, lc_parent, sc); + } + } + } +} + +/** + * Add a corresponding ObjectBase to all the equivalent LayerCollection + */ +void BKE_layer_sync_object_link(const Scene *scene, SceneCollection *sc, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); + if (found) { + layer_collection_object_add(sl, found, ob); + } + } + } +} + +/** + * Remove the equivalent object base to all layers that have this collection + * also remove all reference to ob in the filter_objects + */ +void BKE_layer_sync_object_unlink(const Scene *scene, SceneCollection *sc, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); + if (found) { + layer_collection_object_remove(sl, found, ob); + } + } + } +} + +/* ---------------------------------------------------------------------- */ +/* Override */ + +/** + * Add a new datablock override + */ +void BKE_collection_override_datablock_add(LayerCollection *UNUSED(lc), const char *UNUSED(data_path), ID *UNUSED(id)) +{ + TODO_LAYER_OVERRIDE; +} + +/* ---------------------------------------------------------------------- */ +/* Engine Settings */ + +ListBase R_layer_collection_engines_settings_callbacks = {NULL, NULL}; +ListBase R_scene_layer_engines_settings_callbacks = {NULL, NULL}; + +typedef struct EngineSettingsCB_Type { + struct EngineSettingsCB_Type *next, *prev; + + char name[MAX_NAME]; /* engine name */ + + EngineSettingsCB callback; + +} EngineSettingsCB_Type; + +static void create_engine_settings_scene(IDProperty *root, EngineSettingsCB_Type *es_type) +{ + if (collection_engine_get(root, COLLECTION_MODE_NONE, es_type->name)) { + return; + } + + IDProperty *props = collection_engine_settings_create(es_type, true); + IDP_AddToGroup(root, props); +} + +static void create_layer_collection_engine_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type) +{ + create_engine_settings_scene(scene->collection_properties, es_type); +} + +static void create_scene_layer_engine_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type) +{ + create_engine_settings_scene(scene->layer_properties, es_type); +} + +static void create_layer_collection_engine_settings_collection(LayerCollection *lc, EngineSettingsCB_Type *es_type) +{ + if (BKE_layer_collection_engine_collection_get(lc, COLLECTION_MODE_NONE, es_type->name)) { + return; + } + + IDProperty *props = collection_engine_settings_create(es_type, false); + IDP_AddToGroup(lc->properties, props); + + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + create_layer_collection_engine_settings_collection(lcn, es_type); + } +} + +static void create_layer_collection_engines_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type) +{ + /* Populate the scene with the new settings. */ + create_layer_collection_engine_settings_scene(scene, es_type); + + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + create_layer_collection_engine_settings_collection(lc, es_type); + } + } +} + +static void create_scene_layer_engines_settings_scene(Scene *scene, EngineSettingsCB_Type *es_type) +{ + /* Populate the scene with the new settings. */ + create_scene_layer_engine_settings_scene(scene, es_type); +} + +static void create_scene_layer_engines_settings_layer(SceneLayer *sl, EngineSettingsCB_Type *es_type) +{ + if (BKE_scene_layer_engine_layer_get(sl, COLLECTION_MODE_NONE, es_type->name)) { + return; + } + + IDProperty *props = collection_engine_settings_create(es_type, false); + IDP_AddToGroup(sl->properties, props); +} + +static EngineSettingsCB_Type *engine_settings_callback_register(const char *engine_name, EngineSettingsCB func, ListBase *lb) +{ + EngineSettingsCB_Type *es_type; + + /* Cleanup in case it existed. */ + es_type = BLI_findstring(lb, engine_name, offsetof(EngineSettingsCB_Type, name)); + + if (es_type) { + BLI_remlink(lb, es_type); + MEM_freeN(es_type); + } + + es_type = MEM_callocN(sizeof(EngineSettingsCB_Type), __func__); + BLI_strncpy_utf8(es_type->name, engine_name, sizeof(es_type->name)); + es_type->callback = func; + BLI_addtail(lb, es_type); + + return es_type; +} + +void BKE_layer_collection_engine_settings_callback_register( + Main *bmain, const char *engine_name, EngineSettingsCB func) +{ + EngineSettingsCB_Type *es_type = + engine_settings_callback_register(engine_name, func, &R_layer_collection_engines_settings_callbacks); + + if (bmain) { + /* Populate all of the collections of the scene with those settings. */ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + create_layer_collection_engines_settings_scene(scene, es_type); + } + } +} + +void BKE_scene_layer_engine_settings_callback_register( + Main *bmain, const char *engine_name, EngineSettingsCB func) +{ + EngineSettingsCB_Type *es_type = + engine_settings_callback_register(engine_name, func, &R_scene_layer_engines_settings_callbacks); + + if (bmain) { + /* Populate all of the collections of the scene with those settings. */ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + create_scene_layer_engines_settings_scene(scene, es_type); + + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + create_scene_layer_engines_settings_layer(sl, es_type); + } + } + } +} + +void BKE_layer_collection_engine_settings_callback_free(void) +{ + BLI_freelistN(&R_layer_collection_engines_settings_callbacks); +} + +void BKE_scene_layer_engine_settings_callback_free(void) +{ + BLI_freelistN(&R_scene_layer_engines_settings_callbacks); +} + +/** + * Create a root IDProperty for this engine + * + * \param populate whether we want to pre-fill the collection with the default properties + */ +static IDProperty *collection_engine_settings_create(EngineSettingsCB_Type *es_type, const bool populate) +{ + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, es_type->name); + props->subtype = IDP_GROUP_SUB_ENGINE_RENDER; + + /* properties */ + if (populate) { + es_type->callback(NULL, props); + } + + return props; +} + +static void layer_collection_create_mode_settings_object(IDProperty *root, const bool populate) +{ + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, "ObjectMode"); + props->subtype = IDP_GROUP_SUB_MODE_OBJECT; + + /* properties */ + if (populate) { + OBJECT_collection_settings_create(props); + } + + IDP_AddToGroup(root, props); +} + +static void layer_collection_create_mode_settings_edit(IDProperty *root, const bool populate) +{ + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, "EditMode"); + props->subtype = IDP_GROUP_SUB_MODE_EDIT; + + /* properties */ + if (populate) { + EDIT_MESH_collection_settings_create(props); + } + + IDP_AddToGroup(root, props); +} + +static void layer_collection_create_mode_settings_paint_weight(IDProperty *root, const bool populate) +{ + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, "WeightPaintMode"); + props->subtype = IDP_GROUP_SUB_MODE_PAINT_WEIGHT; + + /* properties */ + if (populate) { + PAINT_WEIGHT_collection_settings_create(props); + } + + IDP_AddToGroup(root, props); +} + +static void layer_collection_create_mode_settings_paint_vertex(IDProperty *root, const bool populate) +{ + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, "VertexPaintMode"); + props->subtype = IDP_GROUP_SUB_MODE_PAINT_VERTEX; + + /* properties */ + if (populate) { + PAINT_VERTEX_collection_settings_create(props); + } + + IDP_AddToGroup(root, props); +} + +static void layer_collection_create_render_settings(IDProperty *root, const bool populate) +{ + EngineSettingsCB_Type *es_type; + for (es_type = R_layer_collection_engines_settings_callbacks.first; es_type; es_type = es_type->next) { + IDProperty *props = collection_engine_settings_create(es_type, populate); + IDP_AddToGroup(root, props); + } +} + +static void scene_layer_create_render_settings(IDProperty *root, const bool populate) +{ + EngineSettingsCB_Type *es_type; + for (es_type = R_scene_layer_engines_settings_callbacks.first; es_type; es_type = es_type->next) { + IDProperty *props = collection_engine_settings_create(es_type, populate); + IDP_AddToGroup(root, props); + } +} + +static void collection_create_mode_settings(IDProperty *root, const bool populate) +{ + /* XXX TODO: put all those engines in the R_engines_settings_callbacks + * and have IDP_AddToGroup outside the callbacks */ + layer_collection_create_mode_settings_object(root, populate); + layer_collection_create_mode_settings_edit(root, populate); + layer_collection_create_mode_settings_paint_weight(root, populate); + layer_collection_create_mode_settings_paint_vertex(root, populate); +} + +static void layer_create_mode_settings(IDProperty *root, const bool populate) +{ + TODO_LAYER; /* XXX like collection_create_mode_settings */ + UNUSED_VARS(root, populate); +} + +static int idproperty_group_subtype(const int mode_type) +{ + int idgroup_type; + + switch (mode_type) { + case COLLECTION_MODE_OBJECT: + idgroup_type = IDP_GROUP_SUB_MODE_OBJECT; + break; + case COLLECTION_MODE_EDIT: + idgroup_type = IDP_GROUP_SUB_MODE_EDIT; + break; + case COLLECTION_MODE_PAINT_WEIGHT: + idgroup_type = IDP_GROUP_SUB_MODE_PAINT_WEIGHT; + break; + case COLLECTION_MODE_PAINT_VERTEX: + idgroup_type = IDP_GROUP_SUB_MODE_PAINT_VERTEX; + break; + default: + case COLLECTION_MODE_NONE: + return IDP_GROUP_SUB_ENGINE_RENDER; + break; + } + + return idgroup_type; +} + +/** + * Return collection enginne settings for either Object s of LayerCollection s + */ +static IDProperty *collection_engine_get( + IDProperty *root, const int type, const char *engine_name) +{ + const int subtype = idproperty_group_subtype(type); + + if (subtype == IDP_GROUP_SUB_ENGINE_RENDER) { + return IDP_GetPropertyFromGroup(root, engine_name); + } + else { + IDProperty *prop; + for (prop = root->data.group.first; prop; prop = prop->next) { + if (prop->subtype == subtype) { + return prop; + } + } + } + + BLI_assert(false); + return NULL; +} + +/** + * Return collection engine settings from Object for specified engine of mode + */ +IDProperty *BKE_layer_collection_engine_evaluated_get(Object *ob, const int type, const char *engine_name) +{ + return collection_engine_get(ob->base_collection_properties, type, engine_name); +} +/** + * Return layer collection engine settings for specified engine + */ +IDProperty *BKE_layer_collection_engine_collection_get(LayerCollection *lc, const int type, const char *engine_name) +{ + return collection_engine_get(lc->properties, type, engine_name); +} + +/** + * Return layer collection engine settings for specified engine in the scene + */ +IDProperty *BKE_layer_collection_engine_scene_get(Scene *scene, const int type, const char *engine_name) +{ + return collection_engine_get(scene->collection_properties, type, engine_name); +} + +/** + * Return scene layer engine settings for specified engine in the scene + */ +IDProperty *BKE_scene_layer_engine_scene_get(Scene *scene, const int type, const char *engine_name) +{ + return collection_engine_get(scene->layer_properties, type, engine_name); +} + +/** + * Return scene layer engine settings for specified engine + */ +IDProperty *BKE_scene_layer_engine_layer_get(SceneLayer *sl, const int type, const char *engine_name) +{ + return collection_engine_get(sl->properties, type, engine_name); +} + +/** + * Return scene layer evaluated engine settings for specified engine + */ +IDProperty *BKE_scene_layer_engine_evaluated_get(SceneLayer *sl, const int type, const char *engine_name) +{ + return collection_engine_get(sl->properties_evaluated, type, engine_name); +} + +/* ---------------------------------------------------------------------- */ +/* Engine Settings Properties */ + +void BKE_collection_engine_property_add_float(IDProperty *props, const char *name, float value) +{ + IDPropertyTemplate val = {0}; + val.f = value; + IDP_AddToGroup(props, IDP_New(IDP_FLOAT, &val, name)); +} + +void BKE_collection_engine_property_add_float_array( + IDProperty *props, const char *name, const float *values, const int array_length) +{ + IDPropertyTemplate val = {0}; + val.array.len = array_length; + val.array.type = IDP_FLOAT; + + IDProperty *idprop= IDP_New(IDP_ARRAY, &val, name); + memcpy(IDP_Array(idprop), values, sizeof(float) * idprop->len); + IDP_AddToGroup(props, idprop); +} + +void BKE_collection_engine_property_add_int(IDProperty *props, const char *name, int value) +{ + IDPropertyTemplate val = {0}; + val.i = value; + IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name)); +} + +void BKE_collection_engine_property_add_bool(IDProperty *props, const char *name, bool value) +{ + IDPropertyTemplate val = {0}; + val.i = value; + IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name)); +} + +int BKE_collection_engine_property_value_get_int(IDProperty *props, const char *name) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + return idprop ? IDP_Int(idprop) : 0; +} + +float BKE_collection_engine_property_value_get_float(IDProperty *props, const char *name) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + return idprop ? IDP_Float(idprop) : 0.0f; +} + +const float *BKE_collection_engine_property_value_get_float_array(IDProperty *props, const char *name) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + return idprop ? IDP_Array(idprop) : NULL; +} + +bool BKE_collection_engine_property_value_get_bool(IDProperty *props, const char *name) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + return idprop ? IDP_Int(idprop) : 0; +} + +void BKE_collection_engine_property_value_set_int(IDProperty *props, const char *name, int value) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + IDP_Int(idprop) = value; +} + +void BKE_collection_engine_property_value_set_float(IDProperty *props, const char *name, float value) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + IDP_Float(idprop) = value; +} + +void BKE_collection_engine_property_value_set_float_array(IDProperty *props, const char *name, const float *values) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + memcpy(IDP_Array(idprop), values, sizeof(float) * idprop->len); +} + +void BKE_collection_engine_property_value_set_bool(IDProperty *props, const char *name, bool value) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + IDP_Int(idprop) = value; +} + +/* Engine Settings recalculate */ + +/* get all the default settings defined in scene and merge them here */ +static void collection_engine_settings_init(IDProperty *root, const bool populate) +{ + /* render engines */ + layer_collection_create_render_settings(root, populate); + + /* mode engines */ + collection_create_mode_settings(root, populate); +} + +/* get all the default settings defined in scene and merge them here */ +static void layer_engine_settings_init(IDProperty *root, const bool populate) +{ + /* render engines */ + scene_layer_create_render_settings(root, populate); + + /* mode engines */ + layer_create_mode_settings(root, populate); +} + +/** + * Initialize the layer collection render setings + * It's used mainly for scenes + */ +void BKE_layer_collection_engine_settings_create(IDProperty *root) +{ + collection_engine_settings_init(root, true); +} + +/** + * Initialize the render setings + * It's used mainly for scenes + */ +void BKE_scene_layer_engine_settings_create(IDProperty *root) +{ + layer_engine_settings_init(root, true); +} + +/** + * Reference of IDProperty group scene collection settings + * Used when reading blendfiles, to see if there is any missing settings. + */ +static struct { + struct { + IDProperty *collection_properties; + IDProperty *render_settings; + } scene; + IDProperty *scene_layer; + IDProperty *layer_collection; +} root_reference = { + .scene = {NULL, NULL}, + .scene_layer = NULL, + .layer_collection = NULL, +}; + +/** + * Free the reference scene collection settings IDProperty group. + */ +static void engine_settings_validate_init(void) +{ + IDPropertyTemplate val = {0}; + + /* LayerCollection engine settings. */ + if (root_reference.scene.collection_properties == NULL) { + root_reference.scene.collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + collection_engine_settings_init(root_reference.scene.collection_properties, true); + } + + if (root_reference.layer_collection == NULL) { + root_reference.layer_collection = IDP_New(IDP_GROUP, &val, ROOT_PROP); + collection_engine_settings_init(root_reference.layer_collection, false); + } + + /* Render engine setting. */ + if (root_reference.scene.render_settings == NULL) { + root_reference.scene.render_settings = IDP_New(IDP_GROUP, &val, ROOT_PROP); + layer_engine_settings_init(root_reference.scene.render_settings, true); + } + + if (root_reference.scene_layer == NULL) { + root_reference.scene_layer = IDP_New(IDP_GROUP, &val, ROOT_PROP); + layer_engine_settings_init(root_reference.scene_layer, false); + } +} + +/** + * Free the reference scene collection settings IDProperty group. + */ +static void layer_collection_engine_settings_validate_free(void) +{ + IDProperty *idprops[] = { + root_reference.scene.render_settings, + root_reference.scene.collection_properties, + root_reference.scene_layer, + root_reference.layer_collection, + NULL, + }; + + IDProperty **idprop = &idprops[0]; + while (*idprop) { + if (*idprop) { + IDP_FreeProperty(*idprop); + MEM_freeN(*idprop); + *idprop = NULL; + idprop++; + } + } +} + +/** + * Make sure Scene has all required collection settings. + */ +void BKE_layer_collection_engine_settings_validate_scene(Scene *scene) +{ + if (root_reference.scene.collection_properties == NULL) { + engine_settings_validate_init(); + } + + if (scene->collection_properties == NULL) { + IDPropertyTemplate val = {0}; + scene->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + BKE_layer_collection_engine_settings_create(scene->collection_properties); + } + else { + IDP_MergeGroup(scene->collection_properties, root_reference.scene.collection_properties, false); + } +} + +/** + * Maker sure LayerCollection has all required collection settings. + */ +void BKE_layer_collection_engine_settings_validate_collection(LayerCollection *lc) +{ + if (root_reference.layer_collection == NULL) { + engine_settings_validate_init(); + } + + BLI_assert(lc->properties != NULL); + IDP_MergeGroup(lc->properties, root_reference.layer_collection, false); +} + +/** + * Make sure Scene has all required collection settings. + */ +void BKE_scene_layer_engine_settings_validate_scene(Scene *scene) +{ + if (root_reference.scene.render_settings == NULL) { + engine_settings_validate_init(); + } + + if (scene->layer_properties == NULL) { + IDPropertyTemplate val = {0}; + scene->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + BKE_scene_layer_engine_settings_create(scene->layer_properties); + } + else { + IDP_MergeGroup(scene->layer_properties, root_reference.scene.render_settings, false); + } +} + +/** + * Make sure Scene has all required collection settings. + */ +void BKE_scene_layer_engine_settings_validate_layer(SceneLayer *sl) +{ + if (root_reference.scene_layer == NULL) { + engine_settings_validate_init(); + } + + IDP_MergeGroup(sl->properties, root_reference.scene_layer, false); +} + +/* ---------------------------------------------------------------------- */ +/* Iterators */ + +static void object_bases_Iterator_begin(BLI_Iterator *iter, void *data_in, const int flag) +{ + SceneLayer *sl = data_in; + Base *base = sl->object_bases.first; + + /* when there are no objects */ + if (base == NULL) { + iter->valid = false; + return; + } + + iter->valid = true; + iter->data = base; + + if ((base->flag & flag) == 0) { + object_bases_Iterator_next(iter, flag); + } + else { + iter->current = base; + } +} + +static void object_bases_Iterator_next(BLI_Iterator *iter, const int flag) +{ + Base *base = ((Base *)iter->data)->next; + + while (base) { + if ((base->flag & flag) != 0) { + iter->current = base; + iter->data = base; + return; + } + base = base->next; + } + + iter->current = NULL; + iter->valid = false; +} + +static void objects_Iterator_begin(BLI_Iterator *iter, void *data_in, const int flag) +{ + object_bases_Iterator_begin(iter, data_in, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +static void objects_Iterator_next(BLI_Iterator *iter, const int flag) +{ + object_bases_Iterator_next(iter, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +void BKE_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + objects_Iterator_begin(iter, data_in, BASE_SELECTED); +} + +void BKE_selected_objects_iterator_next(BLI_Iterator *iter) +{ + objects_Iterator_next(iter, BASE_SELECTED); +} + +void BKE_selected_objects_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +void BKE_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + objects_Iterator_begin(iter, data_in, BASE_VISIBLED); +} + +void BKE_visible_objects_iterator_next(BLI_Iterator *iter) +{ + objects_Iterator_next(iter, BASE_VISIBLED); +} + +void BKE_visible_objects_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +void BKE_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + object_bases_Iterator_begin(iter, data_in, BASE_SELECTED); +} + +void BKE_selected_bases_iterator_next(BLI_Iterator *iter) +{ + object_bases_Iterator_next(iter, BASE_SELECTED); +} + +void BKE_selected_bases_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +void BKE_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + object_bases_Iterator_begin(iter, data_in, BASE_VISIBLED); +} + +void BKE_visible_bases_iterator_next(BLI_Iterator *iter) +{ + object_bases_Iterator_next(iter, BASE_VISIBLED); +} + +void BKE_visible_bases_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +/* Evaluation */ + +/** + * Reset props + * + * If props_ref is pasted, copy props from it + */ +static void idproperty_reset(IDProperty **props, IDProperty *props_ref) +{ + IDPropertyTemplate val = {0}; + + if (*props) { + IDP_FreeProperty(*props); + MEM_freeN(*props); + } + *props = IDP_New(IDP_GROUP, &val, ROOT_PROP); + + if (props_ref) { + IDP_MergeGroup(*props, props_ref, true); + } +} + +void BKE_layer_eval_layer_collection_pre(struct EvaluationContext *UNUSED(eval_ctx), + Scene *scene, SceneLayer *scene_layer) +{ + DEBUG_PRINT("%s on %s\n", __func__, scene_layer->name); + for (Base *base = scene_layer->object_bases.first; base != NULL; base = base->next) { + base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED); + idproperty_reset(&base->collection_properties, scene->collection_properties); + } + + /* Sync properties from scene to scene layer. */ + idproperty_reset(&scene_layer->properties_evaluated, scene->layer_properties); + IDP_MergeGroup(scene_layer->properties_evaluated, scene_layer->properties, true); + + /* TODO(sergey): Is it always required? */ + scene_layer->flag |= SCENE_LAYER_ENGINE_DIRTY; +} + +void BKE_layer_eval_layer_collection(struct EvaluationContext *UNUSED(eval_ctx), + LayerCollection *layer_collection, + LayerCollection *parent_layer_collection) +{ + DEBUG_PRINT("%s on %s, parent %s\n", + __func__, + layer_collection->scene_collection->name, + (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE"); + + /* visibility */ + layer_collection->flag_evaluated = layer_collection->flag; + bool is_visible = (layer_collection->flag & COLLECTION_VISIBLE) != 0; + bool is_selectable = is_visible && ((layer_collection->flag & COLLECTION_SELECTABLE) != 0); + + if (parent_layer_collection != NULL) { + is_visible &= (parent_layer_collection->flag_evaluated & COLLECTION_VISIBLE) != 0; + is_selectable &= (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0; + layer_collection->flag_evaluated &= parent_layer_collection->flag_evaluated; + } + + /* overrides */ + if (is_visible) { + if (parent_layer_collection == NULL) { + idproperty_reset(&layer_collection->properties_evaluated, layer_collection->properties); + } + else { + idproperty_reset(&layer_collection->properties_evaluated, parent_layer_collection->properties_evaluated); + IDP_MergeGroup(layer_collection->properties_evaluated, layer_collection->properties, true); + } + } + + for (LinkData *link = layer_collection->object_bases.first; link != NULL; link = link->next) { + Base *base = link->data; + + if (is_visible) { + IDP_MergeGroup(base->collection_properties, layer_collection->properties_evaluated, true); + base->flag |= BASE_VISIBLED; + } + + if (is_selectable) { + base->flag |= BASE_SELECTABLED; + } + } +} + +void BKE_layer_eval_layer_collection_post(struct EvaluationContext *UNUSED(eval_ctx), + SceneLayer *scene_layer) +{ + DEBUG_PRINT("%s on %s\n", __func__, scene_layer->name); + /* if base is not selectabled, clear select */ + for (Base *base = scene_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLED) == 0) { + base->flag &= ~BASE_SELECTED; + } + } +} + +/** + * Free any static allocated memory. + */ +void BKE_layer_exit(void) +{ + layer_collection_engine_settings_validate_free(); +} diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index c249577686e..04cd557e68a 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -62,6 +62,7 @@ #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" @@ -70,6 +71,7 @@ #include "DNA_vfont_types.h" #include "DNA_windowmanager_types.h" #include "DNA_world_types.h" +#include "DNA_workspace_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -91,7 +93,6 @@ #include "BKE_cachefile.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_group.h" @@ -117,6 +118,7 @@ #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" +#include "BKE_lightprobe.h" #include "BKE_sound.h" #include "BKE_speaker.h" #include "BKE_scene.h" @@ -419,6 +421,9 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) case ID_SPK: if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local); return true; + case ID_LP: + if (!test) BKE_lightprobe_make_local(bmain, (LightProbe *)id, lib_local); + return true; case ID_WO: if (!test) BKE_world_make_local(bmain, (World *)id, lib_local); return true; @@ -472,7 +477,11 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) case ID_CF: if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local); return true; + case ID_WS: case ID_SCR: + /* A bit special: can be appended but not linked. Return false + * since supporting make-local doesn't make much sense. */ + return false; case ID_LI: case ID_KE: case ID_WM: @@ -528,6 +537,9 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test) case ID_SPK: if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id); return true; + case ID_LP: + if (!test) *newid = (ID *)BKE_lightprobe_copy(bmain, (LightProbe *)id); + return true; case ID_CA: if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id); return true; @@ -579,6 +591,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test) case ID_CF: if (!test) *newid = (ID *)BKE_cachefile_copy(bmain, (CacheFile *)id); return true; + case ID_WS: case ID_SCE: case ID_LI: case ID_SCR: @@ -664,6 +677,8 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->text); case ID_SPK: return &(mainlib->speaker); + case ID_LP: + return &(mainlib->lightprobe); case ID_SO: return &(mainlib->sound); case ID_GR: @@ -694,6 +709,8 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->paintcurves); case ID_CF: return &(mainlib->cachefiles); + case ID_WS: + return &(mainlib->workspaces); } return NULL; } @@ -779,11 +796,11 @@ void BKE_main_lib_objects_recalc_all(Main *bmain) /* flag for full recalc */ for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ID_IS_LINKED_DATABLOCK(ob)) { - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } } - DAG_id_type_tag(bmain, ID_OB); + DEG_id_type_tag(bmain, ID_OB); } /** @@ -832,6 +849,7 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[INDEX_ID_BR] = &(main->brush); lb[INDEX_ID_PA] = &(main->particle); lb[INDEX_ID_SPK] = &(main->speaker); + lb[INDEX_ID_LP] = &(main->lightprobe); lb[INDEX_ID_WO] = &(main->world); lb[INDEX_ID_MC] = &(main->movieclip); @@ -839,6 +857,7 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[INDEX_ID_OB] = &(main->object); lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */ lb[INDEX_ID_SCE] = &(main->scene); + lb[INDEX_ID_WS] = &(main->workspaces); /* before wm, so it's freed after it! */ lb[INDEX_ID_WM] = &(main->wm); lb[INDEX_ID_MSK] = &(main->mask); @@ -923,6 +942,9 @@ void *BKE_libblock_alloc_notest(short type) case ID_SPK: id = MEM_callocN(sizeof(Speaker), "speaker"); break; + case ID_LP: + id = MEM_callocN(sizeof(LightProbe), "probe"); + break; case ID_SO: id = MEM_callocN(sizeof(bSound), "sound"); break; @@ -968,6 +990,9 @@ void *BKE_libblock_alloc_notest(short type) case ID_CF: id = MEM_callocN(sizeof(CacheFile), "Cache File"); break; + case ID_WS: + id = MEM_callocN(sizeof(WorkSpace), "Workspace"); + break; } return id; } @@ -994,7 +1019,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name) /* alphabetic insertion: is in new_id */ BKE_main_unlock(bmain); } - DAG_id_type_tag(bmain, type); + DEG_id_type_tag(bmain, type); return id; } @@ -1046,6 +1071,9 @@ void BKE_libblock_init_empty(ID *id) case ID_SPK: BKE_speaker_init((Speaker *)id); break; + case ID_LP: + BKE_lightprobe_init((LightProbe *)id); + break; case ID_CA: BKE_camera_init((Camera *)id); break; @@ -1220,41 +1248,41 @@ void BKE_main_free(Main *mainvar) /* errors freeing ID's can be hard to track down, * enable this so valgrind will give the line number in its error log */ switch (a) { - case 0: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 1: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 2: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 3: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 4: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 5: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 6: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 7: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 8: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 9: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 10: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 11: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 12: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 13: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 14: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 15: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 16: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 17: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 18: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 19: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 20: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 21: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 22: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 23: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 24: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 25: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 26: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 27: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 28: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 29: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 30: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 31: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 32: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 33: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 34: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 0: BKE_libblock_free_ex(mainvar, id, false); break; + case 1: BKE_libblock_free_ex(mainvar, id, false); break; + case 2: BKE_libblock_free_ex(mainvar, id, false); break; + case 3: BKE_libblock_free_ex(mainvar, id, false); break; + case 4: BKE_libblock_free_ex(mainvar, id, false); break; + case 5: BKE_libblock_free_ex(mainvar, id, false); break; + case 6: BKE_libblock_free_ex(mainvar, id, false); break; + case 7: BKE_libblock_free_ex(mainvar, id, false); break; + case 8: BKE_libblock_free_ex(mainvar, id, false); break; + case 9: BKE_libblock_free_ex(mainvar, id, false); break; + case 10: BKE_libblock_free_ex(mainvar, id, false); break; + case 11: BKE_libblock_free_ex(mainvar, id, false); break; + case 12: BKE_libblock_free_ex(mainvar, id, false); break; + case 13: BKE_libblock_free_ex(mainvar, id, false); break; + case 14: BKE_libblock_free_ex(mainvar, id, false); break; + case 15: BKE_libblock_free_ex(mainvar, id, false); break; + case 16: BKE_libblock_free_ex(mainvar, id, false); break; + case 17: BKE_libblock_free_ex(mainvar, id, false); break; + case 18: BKE_libblock_free_ex(mainvar, id, false); break; + case 19: BKE_libblock_free_ex(mainvar, id, false); break; + case 20: BKE_libblock_free_ex(mainvar, id, false); break; + case 21: BKE_libblock_free_ex(mainvar, id, false); break; + case 22: BKE_libblock_free_ex(mainvar, id, false); break; + case 23: BKE_libblock_free_ex(mainvar, id, false); break; + case 24: BKE_libblock_free_ex(mainvar, id, false); break; + case 25: BKE_libblock_free_ex(mainvar, id, false); break; + case 26: BKE_libblock_free_ex(mainvar, id, false); break; + case 27: BKE_libblock_free_ex(mainvar, id, false); break; + case 28: BKE_libblock_free_ex(mainvar, id, false); break; + case 29: BKE_libblock_free_ex(mainvar, id, false); break; + case 30: BKE_libblock_free_ex(mainvar, id, false); break; + case 31: BKE_libblock_free_ex(mainvar, id, false); break; + case 32: BKE_libblock_free_ex(mainvar, id, false); break; + case 33: BKE_libblock_free_ex(mainvar, id, false); break; + case 34: BKE_libblock_free_ex(mainvar, id, false); break; default: BLI_assert(0); break; diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 931002e6bbc..8a42a3334bd 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -52,6 +52,7 @@ #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_force.h" +#include "DNA_lightprobe_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_sensor_types.h" @@ -61,6 +62,8 @@ #include "DNA_sound_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 "BLI_utildefines.h" @@ -69,6 +72,7 @@ #include "BLI_linklist_stack.h" #include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" #include "BKE_idprop.h" @@ -82,6 +86,7 @@ #include "BKE_sca.h" #include "BKE_sequencer.h" #include "BKE_tracking.h" +#include "BKE_workspace.h" #define FOREACH_FINALIZE _finalize @@ -403,7 +408,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call Scene *scene = (Scene *) id; ToolSettings *toolsett = scene->toolsettings; SceneRenderLayer *srl; - Base *base; + BaseLegacy *legacy_base; CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP); CALLBACK_INVOKE(scene->world, IDWALK_CB_USER); @@ -461,8 +466,27 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); - for (base = scene->base.first; base; base = base->next) { - CALLBACK_INVOKE(base->object, IDWALK_CB_USER); + for (legacy_base = scene->base.first; legacy_base; legacy_base = legacy_base->next) { + CALLBACK_INVOKE(legacy_base->object, IDWALK_CB_USER); + } + + FOREACH_SCENE_COLLECTION(scene, sc) + { + for (LinkData *link = sc->objects.first; link; link = link->next) { + CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); + } + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); + } + } + FOREACH_SCENE_COLLECTION_END + + SceneLayer *sl; + for (sl = scene->render_layers.first; sl; sl = sl->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + CALLBACK_INVOKE(base->object, IDWALK_NOP); + } } for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) { @@ -623,31 +647,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call for (i = 0; i < mesh->totcol; i++) { CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER); } - - /* XXX Really not happy with this - probably texface should rather use some kind of - * 'texture slots' and just set indices in each poly/face item - would also save some memory. - * Maybe a nice TODO for blender2.8? */ - if (mesh->mtface || mesh->mtpoly) { - for (i = 0; i < mesh->pdata.totlayer; i++) { - if (mesh->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data; - - for (int j = 0; j < mesh->totpoly; j++, txface++) { - CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE); - } - } - } - - for (i = 0; i < mesh->fdata.totlayer; i++) { - if (mesh->fdata.layers[i].type == CD_MTFACE) { - MTFace *tface = (MTFace *)mesh->fdata.layers[i].data; - - for (int j = 0; j < mesh->totface; j++, tface++) { - CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE); - } - } - } - } break; } @@ -690,6 +689,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data); } CALLBACK_INVOKE(material->group, IDWALK_CB_USER); + CALLBACK_INVOKE(material->edit_image, IDWALK_CB_USER); break; } @@ -750,13 +750,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call break; } - case ID_SCR: - { - bScreen *screen = (bScreen *) id; - CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE); - break; - } - case ID_WO: { World *world = (World *) id; @@ -779,6 +772,13 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call break; } + case ID_LP: + { + LightProbe *probe = (LightProbe *) id; + CALLBACK_INVOKE(probe->image, IDWALK_CB_USER); + break; + } + case ID_GR: { Group *group = (Group *) id; @@ -967,6 +967,38 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call } break; } + + case ID_WM: + { + wmWindowManager *wm = (wmWindowManager *)id; + + for (wmWindow *win = wm->windows.first; win; win = win->next) { + ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); + + CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE); + + CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP); + /* allow callback to set a different workspace */ + BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); + } + break; + } + + case ID_WS: + { + WorkSpace *workspace = (WorkSpace *)id; + ListBase *layouts = BKE_workspace_layouts_get(workspace); + + for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) { + bScreen *screen = BKE_workspace_layout_screen_get(layout); + + CALLBACK_INVOKE(screen, IDWALK_CB_NOP); + /* allow callback to set a different screen */ + BKE_workspace_layout_screen_set(layout, screen); + } + + break; + } case ID_GD: { bGPdata *gpencil = (bGPdata *) id; @@ -978,11 +1010,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call } /* Nothing needed for those... */ + case ID_SCR: case ID_IM: case ID_VF: case ID_TXT: case ID_SO: - case ID_WM: case ID_PAL: case ID_PC: case ID_CF: @@ -1110,6 +1142,9 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */ case ID_LS: return (ELEM(id_type_used, ID_TE, ID_OB)); + case ID_LP: + return ELEM(id_type_used, ID_IM); + case ID_WS: case ID_IM: case ID_VF: case ID_TXT: diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 24626c6ead7..42dc1230586 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -53,6 +53,7 @@ #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" @@ -71,8 +72,8 @@ #include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_font.h" #include "BKE_group.h" @@ -99,6 +100,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" +#include "BKE_lightprobe.h" #include "BKE_sca.h" #include "BKE_speaker.h" #include "BKE_sound.h" @@ -106,8 +108,12 @@ #include "BKE_scene.h" #include "BKE_text.h" #include "BKE_texture.h" +#include "BKE_workspace.h" #include "BKE_world.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -219,7 +225,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id else { if (!is_never_null) { *id_p = new_id; - DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } if (cb_flag & IDWALK_CB_USER) { id_us_min(old_id); @@ -243,7 +249,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id /* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */ static void libblock_remap_data_preprocess_scene_base_unlink( - IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect) + IDRemap *r_id_remap_data, Scene *sce, BaseLegacy *base, const bool skip_indirect, const bool is_indirect) { if (skip_indirect && is_indirect) { r_id_remap_data->skipped_indirect++; @@ -259,6 +265,22 @@ static void libblock_remap_data_preprocess_scene_base_unlink( } } +/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */ +static void libblock_remap_data_preprocess_scene_object_unlink( + IDRemap *r_id_remap_data, Scene *sce, Object *ob, const bool skip_indirect, const bool is_indirect) +{ + if (skip_indirect && is_indirect) { + r_id_remap_data->skipped_indirect++; + r_id_remap_data->skipped_refcounted++; + } + else { + BKE_collections_object_remove(r_id_remap_data->bmain, sce, ob, false); + if (!is_indirect) { + r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } +} + static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) { switch (GS(r_id_remap_data->id->name)) { @@ -273,7 +295,15 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) /* In case we are unlinking... */ if (!r_id_remap_data->old_id) { /* ... everything from scene. */ - Base *base, *base_next; + FOREACH_SCENE_OBJECT(sce, ob_iter) + { + libblock_remap_data_preprocess_scene_object_unlink( + r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect); + } + FOREACH_SCENE_OBJECT_END + + + BaseLegacy *base, *base_next; for (base = sce->base.first; base; base = base_next) { base_next = base->next; libblock_remap_data_preprocess_scene_base_unlink( @@ -283,8 +313,11 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) else if (GS(r_id_remap_data->old_id->name) == ID_OB) { /* ... a specific object from scene. */ Object *old_ob = (Object *)r_id_remap_data->old_id; - Base *base = BKE_scene_base_find(sce, old_ob); + libblock_remap_data_preprocess_scene_object_unlink( + r_id_remap_data, sce, old_ob, skip_indirect, is_indirect); + + BaseLegacy *base = BKE_scene_base_find(sce, old_ob); if (base) { libblock_remap_data_preprocess_scene_base_unlink( r_id_remap_data, sce, base, skip_indirect, is_indirect); @@ -330,7 +363,7 @@ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, } if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ for (Group *group = bmain->group.first; group; group = group->id.next) { - BKE_group_object_unlink(group, NULL, NULL, NULL); + BKE_group_object_unlink(group, NULL); } } else { @@ -343,23 +376,17 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai { /* Note that here we assume no object has no base (i.e. all objects are assumed instanced * in one scene...). */ - for (Base *base = sce->base.first; base; base = base->next) { - if (base->flag & OB_FROMGROUP) { - Object *ob = base->object; - - if (ob->flag & OB_FROMGROUP) { - Group *grp = BKE_group_object_find(NULL, ob); - - /* Unlinked group (old_id) is still in bmain... */ - if (grp && (&grp->id == old_id || grp->id.us == 0)) { - grp = BKE_group_object_find(grp, ob); - } - if (!grp) { - ob->flag &= ~OB_FROMGROUP; - } + for (BaseLegacy *base = sce->base.first; base; base = base->next) { + Object *ob = base->object; + if (ob->flag & OB_FROMGROUP) { + Group *grp = BKE_group_object_find(NULL, ob); + + /* Unlinked group (old_id) is still in bmain... */ + if (grp && (&grp->id == old_id || grp->id.us == 0)) { + grp = BKE_group_object_find(grp, ob); } - if (!(ob->flag & OB_FROMGROUP)) { - base->flag &= ~OB_FROMGROUP; + if (!grp) { + ob->flag &= ~OB_FROMGROUP; } } } @@ -577,7 +604,7 @@ void BKE_libblock_remap_locked( BKE_main_lock(bmain); /* Full rebuild of DAG! */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags) @@ -745,7 +772,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b short type = GS(id->name); ListBase *lb = which_libbase(bmain, type); - DAG_id_type_tag(bmain, type); + DEG_id_type_tag(bmain, type); #ifdef WITH_PYTHON BPY_id_release(id); @@ -813,6 +840,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b case ID_SPK: BKE_speaker_free((Speaker *)id); break; + case ID_LP: + BKE_lightprobe_free((LightProbe *)id); + break; case ID_SO: BKE_sound_free((bSound *)id); break; @@ -859,6 +889,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b case ID_CF: BKE_cachefile_free((CacheFile *)id); break; + case ID_WS: + BKE_workspace_free((WorkSpace *)id); + break; } /* avoid notifying on removed data */ diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c new file mode 100644 index 00000000000..e0e778725fc --- /dev/null +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -0,0 +1,84 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/probe.c + * \ingroup bke + */ + +#include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_animsys.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_lightprobe.h" + +void BKE_lightprobe_init(LightProbe *probe) +{ + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(probe, id)); + + probe->distinf = 5.0f; + probe->distpar = 5.0f; + probe->falloff = 0.2f; + probe->clipsta = 1.0f; + probe->clipend = 40.0f; +} + +void *BKE_lightprobe_add(Main *bmain, const char *name) +{ + LightProbe *probe; + + probe = BKE_libblock_alloc(bmain, ID_LP, name); + + BKE_lightprobe_init(probe); + + return probe; +} + +LightProbe *BKE_lightprobe_copy(Main *bmain, LightProbe *probe) +{ + LightProbe *probe_new; + + probe_new = BKE_libblock_copy(bmain, &probe->id); + + BKE_id_copy_ensure_local(bmain, &probe->id, &probe_new->id); + + return probe_new; +} + +void BKE_lightprobe_make_local(Main *bmain, LightProbe *probe, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &probe->id, true, lib_local); +} + +void BKE_lightprobe_free(LightProbe *probe) +{ + BKE_animdata_free((ID *)probe, false); +} diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 54945242fe4..61e3ede3e8a 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -58,7 +58,6 @@ #include "BKE_animsys.h" #include "BKE_displist.h" #include "BKE_global.h" -#include "BKE_depsgraph.h" #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_library.h" @@ -73,6 +72,8 @@ #include "BKE_editmesh.h" #include "BKE_font.h" +#include "DEG_depsgraph_build.h" + #include "GPU_material.h" /* used in UI and render */ @@ -228,6 +229,7 @@ Material *BKE_material_copy(Main *bmain, Material *ma) man = BKE_libblock_copy(bmain, &ma->id); id_lib_extern((ID *)man->group); + id_lib_extern((ID *)man->edit_image); for (a = 0; a < MAX_MTEX; a++) { if (ma->mtex[a]) { @@ -248,6 +250,8 @@ Material *BKE_material_copy(Main *bmain, Material *ma) BLI_listbase_clear(&man->gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ + BKE_id_copy_ensure_local(bmain, &ma->id, &man->id); return man; @@ -279,6 +283,8 @@ Material *localize_material(Material *ma) man->nodetree = ntreeLocalize(ma->nodetree); BLI_listbase_clear(&man->gpumaterial); + + /* TODO Duplicate Engine Settings and set runtime to NULL */ return man; } @@ -426,7 +432,7 @@ void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user) } *totcolp = totcol; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } void BKE_material_append_id(Main *bmain, ID *id, Material *ma) @@ -443,7 +449,7 @@ void BKE_material_append_id(Main *bmain, ID *id, Material *ma) id_us_plus((ID *)ma); test_all_objects_materials(bmain, id); - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } } @@ -477,7 +483,7 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data material_data_index_remove_id(id, index); } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } } @@ -504,7 +510,7 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data) material_data_index_clear_id(id); } - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } } @@ -599,7 +605,7 @@ void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, boo if (ob->totcol && ob->actcol == 0) ob->actcol = 1; if (ob->actcol > ob->totcol) ob->actcol = ob->totcol; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } void test_object_materials(Object *ob, ID *id) @@ -939,7 +945,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) if (needtang) ma->mode |= MA_NORMAP_TANG; else ma->mode &= ~MA_NORMAP_TANG; - if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) { + if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) { needuv = 1; if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */ } @@ -1300,6 +1306,14 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) bool use_nodes = BKE_scene_use_new_shading_nodes(scene); bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene); + + /* XXX, for 2.8 testing & development its useful to have non Cycles/BI engines use material nodes + * In the future we may have some way to check this which each engine can define. + * For now use material slots for Clay/Eevee. + * - Campbell */ + if (!(use_nodes || is_bi)) { + is_bi = true; + } if (!ma) return; @@ -1698,6 +1712,7 @@ void copy_matcopybuf(Material *ma) matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, G.main, false); matcopybuf.preview = NULL; BLI_listbase_clear(&matcopybuf.gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ matcopied = 1; } @@ -1753,501 +1768,30 @@ void paste_matcopybuf(Material *ma) ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, G.main, false); } - -/*********************** texface to material convert functions **********************/ -/* encode all the TF information into a single int */ -static int encode_tfaceflag(MTFace *tf, int convertall) -{ - /* calculate the flag */ - int flag = tf->mode; - - /* options that change the material offline render */ - if (!convertall) { - flag &= ~TF_OBCOL; - } - - /* clean flags that are not being converted */ - flag &= ~TF_TEX; - flag &= ~TF_SHAREDVERT; - flag &= ~TF_SHAREDCOL; - flag &= ~TF_CONVERTED; - - /* light tface flag is ignored in GLSL mode */ - flag &= ~TF_LIGHT; - - /* 15 is how big the flag can be - hardcoded here and in decode_tfaceflag() */ - flag |= tf->transp << 15; - - /* increase 1 so flag 0 is different than no flag yet */ - return flag + 1; -} - -/* set the material options based in the tface flag */ -static void decode_tfaceflag(Material *ma, int flag, int convertall) -{ - int alphablend; - GameSettings *game = &ma->game; - - /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */ - flag -= 1; - - alphablend = flag >> 15; /* encoded in the encode_tfaceflag function */ - (*game).flag = 0; - - /* General Material Options */ - if ((flag & TF_DYNAMIC) == 0) (*game).flag |= GEMAT_NOPHYSICS; - - /* Material Offline Rendering Properties */ - if (convertall) { - if (flag & TF_OBCOL) ma->shade_flag |= MA_OBCOLOR; - } - - /* Special Face Properties */ - if ((flag & TF_TWOSIDE) == 0) (*game).flag |= GEMAT_BACKCULL; - if (flag & TF_INVISIBLE) (*game).flag |= GEMAT_INVISIBLE; - if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT; - - /* Face Orientation */ - if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO; - else if (flag & TF_BILLBOARD2) (*game).face_orientation |= GEMAT_BILLBOARD; - else if (flag & TF_SHADOW) (*game).face_orientation |= GEMAT_SHADOW; - - /* Alpha Blend */ - if (flag & TF_ALPHASORT && ELEM(alphablend, TF_ALPHA, TF_ADD)) (*game).alpha_blend = GEMAT_ALPHA_SORT; - else if (alphablend & TF_ALPHA) (*game).alpha_blend = GEMAT_ALPHA; - else if (alphablend & TF_ADD) (*game).alpha_blend = GEMAT_ADD; - else if (alphablend & TF_CLIP) (*game).alpha_blend = GEMAT_CLIP; -} - -/* boolean check to see if the mesh needs a material */ -static int check_tfaceneedmaterial(int flag) -{ - /* check if the flags we have are not deprecated != than default material options - * also if only flags are visible and collision see if all objects using this mesh have this option in physics */ - - /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */ - flag -= 1; - - /* deprecated flags */ - flag &= ~TF_OBCOL; - flag &= ~TF_SHAREDVERT; - flag &= ~TF_SHAREDCOL; - - /* light tface flag is ignored in GLSL mode */ - flag &= ~TF_LIGHT; - - /* automatic detected if tex image has alpha */ - flag &= ~(TF_ALPHA << 15); - /* automatic detected if using texture */ - flag &= ~TF_TEX; - - /* settings for the default NoMaterial */ - if (flag == TF_DYNAMIC) - return 0; - - else - return 1; -} - -/* return number of digits of an integer */ -/* XXX to be optmized or replaced by an equivalent blender internal function */ -static int integer_getdigits(int number) -{ - int i = 0; - if (number == 0) return 1; - - while (number != 0) { - number = (int)(number / 10); - i++; - } - return i; -} - -static void calculate_tface_materialname(char *matname, char *newname, int flag) -{ - /* if flag has only light and collision and material matches those values - * you can do strcpy(name, mat_name); - * otherwise do: */ - int digits = integer_getdigits(flag); - /* clamp the old name, remove the MA prefix and add the .TF.flag suffix - * e.g. matname = "MALoooooooooooooongName"; newname = "Loooooooooooooon.TF.2" */ - BLI_snprintf(newname, MAX_ID_NAME, "%.*s.TF.%0*d", MAX_ID_NAME - (digits + 5), matname, digits, flag); -} - -/* returns -1 if no match */ -static short mesh_getmaterialnumber(Mesh *me, Material *ma) -{ - short a; - - for (a = 0; a < me->totcol; a++) { - if (me->mat[a] == ma) { - return a; - } - } - - return -1; -} - -/* append material */ -static short mesh_addmaterial(Mesh *me, Material *ma) -{ - BKE_material_append_id(G.main, &me->id, NULL); - me->mat[me->totcol - 1] = ma; - - id_us_plus(&ma->id); - - return me->totcol - 1; -} - -static void set_facetexture_flags(Material *ma, Image *image) +struct Image *BKE_object_material_edit_image_get(Object *ob, short mat_nr) { - if (image) { - ma->mode |= MA_FACETEXTURE; - /* we could check if the texture has alpha, but then more meshes sharing the same - * material may need it. Let's make it simple. */ - if (BKE_image_has_alpha(image)) - ma->mode |= MA_FACETEXTURE_ALPHA; - } + Material *ma = give_current_material(ob, mat_nr + 1); + return ma ? ma->edit_image : NULL; } -/* returns material number */ -static short convert_tfacenomaterial(Main *main, Mesh *me, MTFace *tf, int flag) +struct Image **BKE_object_material_edit_image_get_array(Object *ob) { - Material *ma; - char idname[MAX_ID_NAME]; - short mat_nr = -1; - - /* new material, the name uses the flag*/ - BLI_snprintf(idname, sizeof(idname), "MAMaterial.TF.%0*d", integer_getdigits(flag), flag); - - if ((ma = BLI_findstring(&main->mat, idname + 2, offsetof(ID, name) + 2))) { - mat_nr = mesh_getmaterialnumber(me, ma); - /* assign the material to the mesh */ - if (mat_nr == -1) mat_nr = mesh_addmaterial(me, ma); - - /* if needed set "Face Textures [Alpha]" Material options */ - set_facetexture_flags(ma, tf->tpage); - } - /* create a new material */ - else { - ma = BKE_material_add(main, idname + 2); - - if (ma) { - printf("TexFace Convert: Material \"%s\" created.\n", idname + 2); - mat_nr = mesh_addmaterial(me, ma); - - /* if needed set "Face Textures [Alpha]" Material options */ - set_facetexture_flags(ma, tf->tpage); - - decode_tfaceflag(ma, flag, 1); - /* the final decoding will happen after, outside the main loop - * for now store the flag into the material and change light/tex/collision - * store the flag as a negative number */ - ma->game.flag = -flag; - id_us_min((ID *)ma); - } - else { - printf("Error: Unable to create Material \"%s\" for Mesh \"%s\".", idname + 2, me->id.name + 2); - } + Image **image_array = MEM_mallocN(sizeof(Material *) * ob->totcol, __func__); + for (int i = 0; i < ob->totcol; i++) { + image_array[i] = BKE_object_material_edit_image_get(ob, i); } - - /* set as converted, no need to go bad to this face */ - tf->mode |= TF_CONVERTED; - return mat_nr; + return image_array; } -/* Function to fully convert materials */ -static void convert_tfacematerial(Main *main, Material *ma) +bool BKE_object_material_edit_image_set(Object *ob, short mat_nr, Image *image) { - Mesh *me; - Material *mat_new; - MFace *mf; - MTFace *tf; - int flag, index; - int a; - short mat_nr; - CustomDataLayer *cdl; - char idname[MAX_ID_NAME]; - - for (me = main->mesh.first; me; me = me->id.next) { - /* check if this mesh uses this material */ - for (a = 0; a < me->totcol; a++) - if (me->mat[a] == ma) break; - - /* no material found */ - if (a == me->totcol) continue; - - /* get the active tface layer */ - index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); - cdl = (index == -1) ? NULL : &me->fdata.layers[index]; - if (!cdl) continue; - - /* loop over all the faces and stop at the ones that use the material*/ - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - if (me->mat[mf->mat_nr] != ma) continue; - - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - flag = encode_tfaceflag(tf, 1); - - /* the name of the new material */ - calculate_tface_materialname(ma->id.name, (char *)&idname, flag); - - if ((mat_new = BLI_findstring(&main->mat, idname + 2, offsetof(ID, name) + 2))) { - /* material already existent, see if the mesh has it */ - mat_nr = mesh_getmaterialnumber(me, mat_new); - /* material is not in the mesh, add it */ - if (mat_nr == -1) mat_nr = mesh_addmaterial(me, mat_new); - } - /* create a new material */ - else { - mat_new = BKE_material_copy(main, ma); - if (mat_new) { - /* rename the material*/ - BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name)); - id_us_min((ID *)mat_new); - - mat_nr = mesh_addmaterial(me, mat_new); - decode_tfaceflag(mat_new, flag, 1); - } - else { - printf("Error: Unable to create Material \"%s\" for Mesh \"%s.", idname + 2, me->id.name + 2); - mat_nr = mf->mat_nr; - continue; - } - } - - /* if the material has a texture but no texture channel - * set "Face Textures [Alpha]" Material options - * actually we need to run it always, because of old behavior - * of using face texture if any texture channel was present (multitex) */ - //if ((!mat_new->mtex[0]) && (!mat_new->mtex[0]->tex)) - set_facetexture_flags(mat_new, tf->tpage); - - /* set the material number to the face*/ - mf->mat_nr = mat_nr; - } - /* remove material from mesh */ - for (a = 0; a < me->totcol; ) { - if (me->mat[a] == ma) { - BKE_material_pop_id(main, &me->id, a, true); - } - else { - a++; - } - } - } -} - - -#define MAT_BGE_DISPUTED -99999 - -int do_version_tface(Main *main) -{ - Mesh *me; - Material *ma; - MFace *mf; - MTFace *tf; - CustomDataLayer *cdl; - int a; - int flag; - int index; - - /* Operator in help menu has been removed for 2.7x */ - int fileload = 1; - - /* sometimes mesh has no materials but will need a new one. In those - * cases we need to ignore the mf->mat_nr and only look at the face - * mode because it can be zero as uninitialized or the 1st created material - */ - int nomaterialslots; - - /* alert to user to check the console */ - int nowarning = 1; - - /* mark all the materials to conversion with a flag - * if there is tface create a complete flag for that storing in flag - * if there is tface and flag > 0: creates a new flag based on this face - * if flags are different set flag to -1 - */ - - /* 1st part: marking mesh materials to update */ - for (me = main->mesh.first; me; me = me->id.next) { - if (ID_IS_LINKED_DATABLOCK(me)) continue; - - /* get the active tface layer */ - index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); - cdl = (index == -1) ? NULL : &me->fdata.layers[index]; - if (!cdl) continue; - - nomaterialslots = (me->totcol == 0 ? 1 : 0); - - /* loop over all the faces*/ - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - - /* conversion should happen only once */ - if (fileload) - tf->mode &= ~TF_CONVERTED; - else { - if ((tf->mode & TF_CONVERTED)) continue; - else tf->mode |= TF_CONVERTED; - } - - /* no material slots */ - if (nomaterialslots) { - flag = encode_tfaceflag(tf, 1); - - /* create/find a new material and assign to the face */ - if (check_tfaceneedmaterial(flag)) { - mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag); - } - /* else mark them as no-material to be reverted to 0 later */ - else { - mf->mat_nr = -1; - } - } - else if (mf->mat_nr < me->totcol) { - ma = me->mat[mf->mat_nr]; - - /* no material create one if necessary */ - if (!ma) { - /* find a new material and assign to the face */ - flag = encode_tfaceflag(tf, 1); - - /* create/find a new material and assign to the face */ - if (check_tfaceneedmaterial(flag)) - mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag); - - continue; - } - - /* we can't read from this if it comes from a library, - * at doversion time: direct_link might not have happened on it, - * so ma->mtex is not pointing to valid memory yet. - * later we could, but it's better not */ - else if (ID_IS_LINKED_DATABLOCK(ma)) - continue; - - /* material already marked as disputed */ - else if (ma->game.flag == MAT_BGE_DISPUTED) - continue; - - /* found a material */ - else { - flag = encode_tfaceflag(tf, ((fileload) ? 0 : 1)); - - /* first time changing this material */ - if (ma->game.flag == 0) - ma->game.flag = -flag; - - /* mark material as disputed */ - else if (ma->game.flag != -flag) { - ma->game.flag = MAT_BGE_DISPUTED; - continue; - } - - /* material ok so far */ - else { - ma->game.flag = -flag; - - /* some people uses multitexture with TexFace by creating a texture - * channel which not necessarily the tf->tpage image. But the game engine - * was enabling it. Now it's required to set "Face Texture [Alpha] in the - * material settings. */ - if (!fileload) - set_facetexture_flags(ma, tf->tpage); - } - } - } - else { - continue; - } - } - - /* if we didn't have material slot and now we do, we need to - * make sure the materials are correct */ - if (nomaterialslots) { - if (me->totcol > 0) { - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - if (mf->mat_nr == -1) { - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - mf->mat_nr = convert_tfacenomaterial(main, me, tf, encode_tfaceflag(tf, 1)); - } - } - } - else { - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - mf->mat_nr = 0; - } - } - } - - } - - /* 2nd part - conversion */ - /* skip library files */ - - /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */ - for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) { - if (ID_IS_LINKED_DATABLOCK(ma)) continue; - - /* disputed material */ - if (ma->game.flag == MAT_BGE_DISPUTED) { - ma->game.flag = 0; - if (fileload) { - printf("Warning: material \"%s\" skipped.\n", ma->id.name + 2); - nowarning = 0; - } - else { - convert_tfacematerial(main, ma); - } - continue; - } - - /* no conflicts in this material - 90% of cases - * convert from tface system to material */ - else if (ma->game.flag < 0) { - decode_tfaceflag(ma, -(ma->game.flag), 1); - - /* material is good make sure all faces using - * this material are set to converted */ - if (fileload) { - for (me = main->mesh.first; me; me = me->id.next) { - /* check if this mesh uses this material */ - for (a = 0; a < me->totcol; a++) - if (me->mat[a] == ma) break; - - /* no material found */ - if (a == me->totcol) continue; - - /* get the active tface layer */ - index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); - cdl = (index == -1) ? NULL : &me->fdata.layers[index]; - if (!cdl) continue; - - /* loop over all the faces and stop at the ones that use the material*/ - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - if (me->mat[mf->mat_nr] == ma) { - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - tf->mode |= TF_CONVERTED; - } - } - } - } - } - /* material is not used by faces with texface - * set the default flag - do it only once */ - else { - if (fileload) { - ma->game.flag = GEMAT_BACKCULL; - } - } + Material *ma = give_current_material(ob, mat_nr + 1); + if (ma) { + /* both may be NULL */ + id_us_min((ID *)ma->edit_image); + ma->edit_image = image; + id_us_plus((ID *)ma->edit_image); + return true; } - - return nowarning; + return false; } - diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 97033a9555d..4bfdb7fbc61 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -57,7 +57,6 @@ #include "BKE_animsys.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_scene.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -67,6 +66,8 @@ #include "BKE_object.h" #include "BKE_material.h" +//#include "DEG_depsgraph.h" + /* Functions */ /** Free (or release) any data used by this mball (does not free the mball itself). */ @@ -316,13 +317,13 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2) void BKE_mball_properties_copy(Scene *scene, Object *active_object) { Scene *sce_iter = scene; - Base *base; + BaseLegacy *base; Object *ob; MetaBall *active_mball = (MetaBall *)active_object->data; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; SceneBaseIter iter; - EvaluationContext *eval_ctx = G.main->eval_ctx; + struct EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); @@ -359,27 +360,25 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) */ Object *BKE_mball_basis_find(Scene *scene, Object *basis) { - Scene *sce_iter = scene; - Base *base; - Object *ob, *bob = basis; + Object *bob = basis; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; - SceneBaseIter iter; - EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); - BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { - if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { - if (ob != bob) { - BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - - /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ - if (STREQ(obname, basisname)) { - if (obnr < basisnr) { - basis = ob; - basisnr = obnr; + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + Object *ob = base->object; + if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { + if (ob != bob) { + BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); + + /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ + if (STREQ(obname, basisname)) { + if (obnr < basisnr) { + basis = ob; + basisnr = obnr; + } } } } @@ -533,7 +532,7 @@ void BKE_mball_select_swap(struct MetaBall *mb) /* **** Depsgraph evaluation **** */ -void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx), +void BKE_mball_eval_geometry(struct EvaluationContext *UNUSED(eval_ctx), MetaBall *UNUSED(mball)) { } diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 76965176be8..d897213d362 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -48,11 +48,12 @@ #include "BKE_global.h" -#include "BKE_depsgraph.h" #include "BKE_scene.h" #include "BKE_displist.h" #include "BKE_mball_tessellate.h" /* own include */ +#include "DEG_depsgraph.h" + #include "BLI_strict_flags.h" /* experimental (faster) normal calculation */ @@ -1081,7 +1082,7 @@ static void polygonize(PROCESS *process) static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) { Scene *sce_iter = scene; - Base *base; + BaseLegacy *base; Object *bob; MetaBall *mb; const MetaElem *ml; @@ -1103,7 +1104,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen zero_size = 0; ml = NULL; - if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { + if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) { mb = ob->data; if (mb->editelems) ml = mb->editelems->first; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index c12890a354e..3c3943cb062 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -59,7 +59,6 @@ #include "BKE_multires.h" #include "BKE_key.h" #include "BKE_mball.h" -#include "BKE_depsgraph.h" /* these 2 are only used by conversion functions */ #include "BKE_curve.h" /* -- */ @@ -127,7 +126,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 for (i = 0; i < c1->totlayer; i++) { if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i1++; } @@ -135,7 +134,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 for (i = 0; i < c2->totlayer; i++) { if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i2++; } @@ -149,14 +148,14 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 i1 = 0; i2 = 0; for (i = 0; i < tot; i++) { while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i1++; l1++; } while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i2++; l2++; @@ -324,7 +323,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) * Callers could also check but safer to do here - campbell */ } else { - const int tottex_original = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE); @@ -335,7 +334,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) { BKE_mesh_tessface_clear(me); - CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface); + CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface); /* TODO - add some --debug-mesh option */ if (G.debug & G_DEBUG) { @@ -344,7 +343,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) * and check if there was any data to begin with, for now just print the warning with * some info to help troubleshoot whats going on - campbell */ printf("%s: warning! Tessellation uvs or vcol data got out of sync, " - "had to reset!\n CD_MTFACE: %d != CD_MTEXPOLY: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n", + "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n", __func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original); } } @@ -396,14 +395,11 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) * versions of the mesh. - campbell*/ static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd) { - if (me->edit_btmesh) - BKE_editmesh_update_linked_customdata(me->edit_btmesh); - if (do_ensure_tess_cd) { mesh_ensure_tessellation_customdata(me); } - CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata); + CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata); } void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) @@ -422,7 +418,6 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); - me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY); me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); } @@ -442,6 +437,8 @@ void BKE_mesh_free(Mesh *me) { BKE_animdata_free(&me->id, false); + BKE_mesh_batch_cache_free(me); + CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); @@ -529,6 +526,7 @@ Mesh *BKE_mesh_copy(Main *bmain, Mesh *me) BKE_mesh_update_customdata_pointers(men, do_tessface); men->edit_btmesh = NULL; + men->batch_cache = NULL; men->mselect = MEM_dupallocN(men->mselect); men->bb = MEM_dupallocN(men->bb); @@ -583,24 +581,34 @@ bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int ldata = &me->ldata; fdata = &me->fdata; } - cdlp = &pdata->layers[poly_index]; + cdlp = (poly_index != -1) ? &pdata->layers[poly_index] : NULL; cdlu = &ldata->layers[loop_index]; cdlf = fdata && do_tessface ? &fdata->layers[face_index] : NULL; - if (cdlp->name != new_name) { + if (cdlp == NULL && cdlf == NULL) { + return false; + } + + if (cdlu->name != new_name) { /* Mesh validate passes a name from the CD layer as the new name, * Avoid memcpy from self to self in this case. */ - BLI_strncpy(cdlp->name, new_name, sizeof(cdlp->name)); - CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers); + BLI_strncpy(cdlu->name, new_name, sizeof(cdlu->name)); + CustomData_set_layer_unique_name(pdata, cdlu - pdata->layers); } /* Loop until we do have exactly the same name for all layers! */ - for (i = 1; !STREQ(cdlp->name, cdlu->name) || (cdlf && !STREQ(cdlp->name, cdlf->name)); i++) { + for (i = 1; + (cdlp && !STREQ(cdlp->name, cdlu->name)) || + (cdlf && !STREQ(cdlp->name, cdlf->name)); + i++) + { switch (i % step) { case 0: - BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name)); - CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers); + if (cdlp) { + BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name)); + CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers); + } break; case 1: BLI_strncpy(cdlu->name, cdlp->name, sizeof(cdlu->name)); @@ -608,7 +616,7 @@ bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int break; case 2: if (cdlf) { - BLI_strncpy(cdlf->name, cdlp->name, sizeof(cdlf->name)); + BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name)); CustomData_set_layer_unique_name(fdata, cdlf - fdata->layers); } break; @@ -620,66 +628,44 @@ bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface) { - CustomData *pdata, *ldata, *fdata; + CustomData *ldata, *fdata; if (me->edit_btmesh) { - pdata = &me->edit_btmesh->bm->pdata; ldata = &me->edit_btmesh->bm->ldata; /* No tessellated data in BMesh! */ fdata = NULL; do_tessface = false; } else { - pdata = &me->pdata; ldata = &me->ldata; fdata = &me->fdata; do_tessface = (do_tessface && fdata->totlayer); } { - const int pidx_start = CustomData_get_layer_index(pdata, CD_MTEXPOLY); const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV); const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1; - int pidx = CustomData_get_named_layer(pdata, CD_MTEXPOLY, old_name); int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name); int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1; /* None of those cases should happen, in theory! * Note this assume we have the same number of mtexpoly, mloopuv and mtface layers! */ - if (pidx == -1) { - if (lidx == -1) { - if (fidx == -1) { - /* No layer found with this name! */ - return false; - } - else { - lidx = fidx; - } - } - pidx = lidx; - } - else { - if (lidx == -1) { - lidx = pidx; + if (lidx == -1) { + if (fidx == -1) { + /* No layer found with this name! */ + return false; } - if (fidx == -1 && do_tessface) { - fidx = pidx; + else { + lidx = fidx; } } -#if 0 - /* For now, we do not consider mismatch in indices (i.e. same name leading to (relative) different indices). */ - else if (pidx != lidx) { - lidx = pidx; - } -#endif /* Go back to absolute indices! */ - pidx += pidx_start; lidx += lidx_start; if (fidx != -1) fidx += fidx_start; - return BKE_mesh_uv_cdlayer_rename_index(me, pidx, lidx, fidx, new_name, do_tessface); + return BKE_mesh_uv_cdlayer_rename_index(me, -1, lidx, fidx, new_name, do_tessface); } } @@ -757,6 +743,18 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_siz if (r_size) copy_v3_v3(r_size, me->size); } +void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size) +{ + if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { + BKE_mesh_texspace_calc(me); + } + + if (r_texflag != NULL) *r_texflag = &me->texflag; + if (r_loc != NULL) *r_loc = me->loc; + if (r_rot != NULL) *r_rot = me->rot; + if (r_size != NULL) *r_size = me->size; +} + void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) { float *texloc, *texrot, *texsize; @@ -1379,7 +1377,6 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use if (alluv) { const char *uvname = "Orco"; - me->mtpoly = CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname); me->mloopuv = CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname); } @@ -2676,3 +2673,20 @@ void BKE_mesh_eval_geometry(EvaluationContext *UNUSED(eval_ctx), BKE_mesh_texspace_calc(mesh); } } + +/* Draw Engine */ +void (*BKE_mesh_batch_cache_dirty_cb)(Mesh *me, int mode) = NULL; +void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL; + +void BKE_mesh_batch_cache_dirty(Mesh *me, int mode) +{ + if (me->batch_cache) { + BKE_mesh_batch_cache_dirty_cb(me, mode); + } +} +void BKE_mesh_batch_cache_free(Mesh *me) +{ + if (me->batch_cache) { + BKE_mesh_batch_cache_free_cb(me); + } +}
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 37f4477febf..2c769c3ce03 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -1665,152 +1665,6 @@ void BKE_mesh_normals_loop_to_vertex( /* -------------------------------------------------------------------- */ -/** \name Mesh Tangent Calculations - * \{ */ - -/* Tangent space utils. */ - -/* User data. */ -typedef struct { - const MPoly *mpolys; /* faces */ - const MLoop *mloops; /* faces's vertices */ - const MVert *mverts; /* vertices */ - const MLoopUV *luvs; /* texture coordinates */ - float (*lnors)[3]; /* loops' normals */ - float (*tangents)[4]; /* output tangents */ - int num_polys; /* number of polygons */ -} BKEMeshToTangent; - -/* Mikktspace's API */ -static int get_num_faces(const SMikkTSpaceContext *pContext) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - return p_mesh->num_polys; -} - -static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - return p_mesh->mpolys[face_idx].totloop; -} - -static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx; - copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co); -} - -static void get_texture_coordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx, - const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv); -} - -static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]); -} - -static void set_tspace(const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign, - const int face_idx, const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx]; - copy_v3_v3(p_res, fv_tangent); - p_res[3] = face_sign; -} - -/** - * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with - * split normals can be used to recreate the full tangent space. - * Note: * The mesh should be made of only tris and quads! - */ -void BKE_mesh_loop_tangents_ex( - const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops, - float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs, - const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys, - ReportList *reports) -{ - BKEMeshToTangent mesh_to_tangent = {NULL}; - SMikkTSpaceContext s_context = {NULL}; - SMikkTSpaceInterface s_interface = {NULL}; - - const MPoly *mp; - int mp_index; - - /* First check we do have a tris/quads only mesh. */ - for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { - if (mp->totloop > 4) { - BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting"); - return; - } - } - - /* Compute Mikktspace's tangent normals. */ - mesh_to_tangent.mpolys = mpolys; - mesh_to_tangent.mloops = mloops; - mesh_to_tangent.mverts = mverts; - mesh_to_tangent.luvs = loopuvs; - mesh_to_tangent.lnors = loopnors; - mesh_to_tangent.tangents = r_looptangent; - mesh_to_tangent.num_polys = numPolys; - - s_context.m_pUserData = &mesh_to_tangent; - s_context.m_pInterface = &s_interface; - s_interface.m_getNumFaces = get_num_faces; - s_interface.m_getNumVerticesOfFace = get_num_verts_of_face; - s_interface.m_getPosition = get_position; - s_interface.m_getTexCoord = get_texture_coordinate; - s_interface.m_getNormal = get_normal; - s_interface.m_setTSpaceBasic = set_tspace; - - /* 0 if failed */ - if (genTangSpaceDefault(&s_context) == false) { - BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!"); - } -} - -/** - * Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code. - * \note - * - There must be a valid loop's CD_NORMALS available. - * - The mesh should be made of only tris and quads! - */ -void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports) -{ - MLoopUV *loopuvs; - float (*loopnors)[3]; - - /* Check we have valid texture coordinates first! */ - if (uvmap) { - loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap); - } - else { - loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV); - } - if (!loopuvs) { - BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap); - return; - } - - loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); - if (!loopnors) { - BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting"); - return; - } - - BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents, - loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - /** \name Polygon Calculations * \{ */ @@ -2307,12 +2161,12 @@ void BKE_mesh_calc_volume( */ void BKE_mesh_loops_to_mface_corners( CustomData *fdata, CustomData *ldata, - CustomData *pdata, unsigned int lindex[4], int findex, - const int polyindex, + CustomData *UNUSED(pdata), unsigned int lindex[4], int findex, + const int UNUSED(polyindex), const int mf_len, /* 3 or 4 */ /* cache values to avoid lookups every time */ - const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */ + const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */ const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */ const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */ const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */ @@ -2320,17 +2174,13 @@ void BKE_mesh_loops_to_mface_corners( ) { MTFace *texface; - MTexPoly *texpoly; MCol *mcol; MLoopCol *mloopcol; MLoopUV *mloopuv; int i, j; - for (i = 0; i < numTex; i++) { + for (i = 0; i < numUV; i++) { texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); - texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i); - - ME_MTEXFACE_CPY(texface, texpoly); for (j = 0; j < mf_len; j++) { mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i); @@ -2382,14 +2232,14 @@ void BKE_mesh_loops_to_mface_corners( * * \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used. */ -void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData *pdata, MFace *mface, +void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, MFace *mface, int *polyindices, unsigned int (*loopindices)[4], const int num_faces) { /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code... * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve * this. Better imho to live with it for now. :/ --mont29 */ - const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV); const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); @@ -2399,17 +2249,14 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData const int *pidx; unsigned int (*lidx)[4]; - for (i = 0; i < numTex; i++) { + for (i = 0; i < numUV; i++) { MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i); - MTexPoly *texpoly = CustomData_get_layer_n(pdata, CD_MTEXPOLY, i); MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i); for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces; pidx++, lidx++, findex++, texface++) { - ME_MTEXFACE_CPY(texface, &texpoly[*pidx]); - for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv); } @@ -2732,7 +2579,7 @@ int BKE_mesh_recalc_tessellation( /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons * they are directly tessellated from */ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + CustomData_from_bmeshpoly(fdata, ldata, totface); if (do_face_nor_copy) { /* If polys have a normals layer, copying that to faces can help @@ -2753,7 +2600,7 @@ int BKE_mesh_recalc_tessellation( * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test. * ... */ - BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, mface_to_poly_map, lindices, totface); + BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface); /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad. @@ -2932,7 +2779,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, MPoly *mp, *mpoly; MFace *mface, *mf; - const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV); const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); @@ -2972,7 +2819,7 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + CustomData_from_bmeshpoly(fdata, ldata, totface); mp = mpoly; k = 0; @@ -2994,9 +2841,10 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, mf->v2 = mloop[mf->v2].v; mf->v3 = mloop[mf->v3].v; - BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, - lindex, k, i, 3, - numTex, numCol, hasPCol, hasOrigSpace, hasLNor); + BKE_mesh_loops_to_mface_corners( + fdata, ldata, pdata, + lindex, k, i, 3, + numUV, numCol, hasPCol, hasOrigSpace, hasLNor); test_index_face(mf, fdata, k, 3); } else { @@ -3014,9 +2862,10 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, mf->v3 = mloop[mf->v3].v; mf->v4 = mloop[mf->v4].v; - BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, - lindex, k, i, 4, - numTex, numCol, hasPCol, hasOrigSpace, hasLNor); + BKE_mesh_loops_to_mface_corners( + fdata, ldata, pdata, + lindex, k, i, 4, + numUV, numCol, hasPCol, hasOrigSpace, hasLNor); test_index_face(mf, fdata, k, 4); } @@ -3031,11 +2880,11 @@ int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, #endif /* USE_BMESH_SAVE_AS_COMPAT */ -static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, - MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol) +static void bm_corners_to_loops_ex( + ID *id, CustomData *fdata, CustomData *ldata, + MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol) { MTFace *texface; - MTexPoly *texpoly; MCol *mcol; MLoopCol *mloopcol; MLoopUV *mloopuv; @@ -3046,9 +2895,6 @@ static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, for (i = 0; i < numTex; i++) { texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); - texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i); - - ME_MTEXFACE_CPY(texpoly, texface); mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i); copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++; @@ -3156,7 +3002,7 @@ void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) mesh->medge, mesh->mface, &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly); - CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata); + CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata); BKE_mesh_update_customdata_pointers(mesh, true); } @@ -3199,7 +3045,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); - CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly); + CustomData_to_bmeshpoly(fdata, ldata, totloop); if (id) { /* ensure external data is transferred */ @@ -3249,7 +3095,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData # undef ML - bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol); + bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol); if (polyindex) { *polyindex = i; diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c new file mode 100644 index 00000000000..b9d1025d7b1 --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -0,0 +1,684 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_tangent.c + * \ingroup bke + * + * Functions to evaluate mesh tangents. + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_stack.h" +#include "BLI_task.h" + +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_mesh_tangent.h" +#include "BKE_report.h" + +#include "BLI_strict_flags.h" + +#include "atomic_ops.h" +#include "mikktspace.h" + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Tangent Calculations (Single Layer) + * \{ */ + +/* Tangent space utils. */ + +/* User data. */ +typedef struct { + const MPoly *mpolys; /* faces */ + const MLoop *mloops; /* faces's vertices */ + const MVert *mverts; /* vertices */ + const MLoopUV *luvs; /* texture coordinates */ + float (*lnors)[3]; /* loops' normals */ + float (*tangents)[4]; /* output tangents */ + int num_polys; /* number of polygons */ +} BKEMeshToTangent; + +/* Mikktspace's API */ +static int get_num_faces(const SMikkTSpaceContext *pContext) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + return p_mesh->num_polys; +} + +static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + return p_mesh->mpolys[face_idx].totloop; +} + +static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx; + copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co); +} + +static void get_texture_coordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx, + const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv); +} + +static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]); +} + +static void set_tspace(const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign, + const int face_idx, const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx]; + copy_v3_v3(p_res, fv_tangent); + p_res[3] = face_sign; +} + +/** + * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with + * split normals can be used to recreate the full tangent space. + * Note: * The mesh should be made of only tris and quads! + */ +void BKE_mesh_calc_loop_tangent_single_ex( + const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops, + float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs, + const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys, + ReportList *reports) +{ + BKEMeshToTangent mesh_to_tangent = {NULL}; + SMikkTSpaceContext s_context = {NULL}; + SMikkTSpaceInterface s_interface = {NULL}; + + const MPoly *mp; + int mp_index; + + /* First check we do have a tris/quads only mesh. */ + for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { + if (mp->totloop > 4) { + BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting"); + return; + } + } + + /* Compute Mikktspace's tangent normals. */ + mesh_to_tangent.mpolys = mpolys; + mesh_to_tangent.mloops = mloops; + mesh_to_tangent.mverts = mverts; + mesh_to_tangent.luvs = loopuvs; + mesh_to_tangent.lnors = loopnors; + mesh_to_tangent.tangents = r_looptangent; + mesh_to_tangent.num_polys = numPolys; + + s_context.m_pUserData = &mesh_to_tangent; + s_context.m_pInterface = &s_interface; + s_interface.m_getNumFaces = get_num_faces; + s_interface.m_getNumVerticesOfFace = get_num_verts_of_face; + s_interface.m_getPosition = get_position; + s_interface.m_getTexCoord = get_texture_coordinate; + s_interface.m_getNormal = get_normal; + s_interface.m_setTSpaceBasic = set_tspace; + + /* 0 if failed */ + if (genTangSpaceDefault(&s_context) == false) { + BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!"); + } +} + +/** + * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code. + * \note + * - There must be a valid loop's CD_NORMALS available. + * - The mesh should be made of only tris and quads! + */ +void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports) +{ + MLoopUV *loopuvs; + float (*loopnors)[3]; + + /* Check we have valid texture coordinates first! */ + if (uvmap) { + loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap); + } + else { + loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV); + } + if (!loopuvs) { + BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap); + return; + } + + loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + if (!loopnors) { + BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting"); + return; + } + + BKE_mesh_calc_loop_tangent_single_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents, + loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Tangent Calculations (All Layers) + * \{ */ + + +/* Necessary complexity to handle looptri's as quads for correct tangents */ +#define USE_LOOPTRI_DETECT_QUADS + +typedef struct { + const float (*precomputedFaceNormals)[3]; + const float (*precomputedLoopNormals)[3]; + const MLoopTri *looptri; + MLoopUV *mloopuv; /* texture coordinates */ + const MPoly *mpoly; /* indices */ + const MLoop *mloop; /* indices */ + const MVert *mvert; /* vertices & normals */ + const float (*orco)[3]; + float (*tangent)[4]; /* destination */ + int numTessFaces; + +#ifdef USE_LOOPTRI_DETECT_QUADS + /* map from 'fake' face index to looptri, + * quads will point to the first looptri of the quad */ + const int *face_as_quad_map; + int num_face_as_quad_map; +#endif + +} SGLSLMeshToTangent; + +/* interface */ +#include "mikktspace.h" + +static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + +#ifdef USE_LOOPTRI_DETECT_QUADS + return pMesh->num_face_as_quad_map; +#else + return pMesh->numTessFaces; +#endif +} + +static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ +#ifdef USE_LOOPTRI_DETECT_QUADS + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + if (pMesh->face_as_quad_map) { + const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + return 4; + } + } + return 3; +#else + UNUSED_VARS(pContext, face_num); + return 3; +#endif +} + +static void dm_ts_GetPosition( + const SMikkTSpaceContext *pContext, float r_co[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + const float *co; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + +finally: + co = pMesh->mvert[pMesh->mloop[loop_index].v].co; + copy_v3_v3(r_co, co); +} + +static void dm_ts_GetTextureCoordinate( + const SMikkTSpaceContext *pContext, float r_uv[2], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + +finally: + if (pMesh->mloopuv != NULL) { + const float *uv = pMesh->mloopuv[loop_index].uv; + copy_v2_v2(r_uv, uv); + } + else { + const float *orco = pMesh->orco[pMesh->mloop[loop_index].v]; + map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); + } +} + +static void dm_ts_GetNormal( + const SMikkTSpaceContext *pContext, float r_no[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + +finally: + if (pMesh->precomputedLoopNormals) { + copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]); + } + else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */ + if (pMesh->precomputedFaceNormals) { + copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]); + } + else { +#ifdef USE_LOOPTRI_DETECT_QUADS + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + normal_quad_v3( + r_no, + pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co, + pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co, + pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co, + pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co); + } + else +#endif + { + normal_tri_v3( + r_no, + pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co, + pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co, + pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co); + } + } + } + else { + const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no; + normal_short_to_float_v3(r_no, no); + } +} + +static void dm_ts_SetTSpace( + const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + + float *pRes; + +finally: + pRes = pMesh->tangent[loop_index]; + copy_v3_v3(pRes, fvTangent); + pRes[3] = fSign; +} + +static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +{ + struct SGLSLMeshToTangent *mesh2tangent = taskdata; + /* new computation method */ + { + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + + sContext.m_pUserData = mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = dm_ts_GetNumFaces; + sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace; + sInterface.m_getPosition = dm_ts_GetPosition; + sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate; + sInterface.m_getNormal = dm_ts_GetNormal; + sInterface.m_setTSpaceBasic = dm_ts_SetTSpace; + + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } +} + +void BKE_mesh_add_loop_tangent_named_layer_for_uv( + CustomData *uv_data, CustomData *tan_data, int numLoopData, + const char *layer_name) +{ + if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && + CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) + { + CustomData_add_layer_named( + tan_data, CD_TANGENT, CD_CALLOC, NULL, + numLoopData, layer_name); + } +} + +/** + * Here we get some useful information such as active uv layer name and search if it is already in tangent_names. + * Also, we calculate tangent_mask that works as a descriptor of tangents state. + * If tangent_mask has changed, then recalculate tangents. + */ +void BKE_mesh_calc_loop_tangent_step_0( + const CustomData *loopData, bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_count, + bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, + char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) { + /* Active uv in viewport */ + int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV); + *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV); + ract_uv_name[0] = 0; + if (*ract_uv_n != -1) { + strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name); + } + + /* Active tangent in render */ + *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV); + rren_uv_name[0] = 0; + if (*rren_uv_n != -1) { + strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name); + } + + /* If active tangent not in tangent_names we take it into account */ + *rcalc_act = false; + *rcalc_ren = false; + for (int i = 0; i < tangent_names_count; i++) { + if (tangent_names[i][0] == 0) { + calc_active_tangent = true; + } + } + if (calc_active_tangent) { + *rcalc_act = true; + *rcalc_ren = true; + for (int i = 0; i < tangent_names_count; i++) { + if (STREQ(ract_uv_name, tangent_names[i])) + *rcalc_act = false; + if (STREQ(rren_uv_name, tangent_names[i])) + *rcalc_ren = false; + } + } + *rtangent_mask = 0; + + const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV); + for (int n = 0; n < uv_layer_num; n++) { + const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n); + bool add = false; + for (int i = 0; i < tangent_names_count; i++) { + if (tangent_names[i][0] && STREQ(tangent_names[i], name)) { + add = true; + break; + } + } + if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) || + (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))) + { + add = true; + } + if (add) + *rtangent_mask |= (char)(1 << n); + } +} + +/** + * See: #BKE_editmesh_loop_tangent_calc (matching logic). + */ +void BKE_mesh_calc_loop_tangent_ex( + const MVert *mvert, + const MPoly *mpoly, const uint mpoly_len, + const MLoop *mloop, + const MLoopTri *looptri, + const uint looptri_len, + + CustomData *loopdata, + bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_len, + const float (*poly_normals)[3], + const float (*loop_normals)[3], + const float (*vert_orco)[3], + /* result */ + CustomData *loopdata_out, + const uint loopdata_out_len, + char *tangent_mask_curr_p) +{ + BLI_assert(CustomData_number_of_layers(loopdata, CD_MLOOPUV) != 0); + + int act_uv_n = -1; + int ren_uv_n = -1; + bool calc_act = false; + bool calc_ren = false; + char act_uv_name[MAX_NAME]; + char ren_uv_name[MAX_NAME]; + char tangent_mask = 0; + char tangent_mask_curr = *tangent_mask_curr_p; + + BKE_mesh_calc_loop_tangent_step_0( + loopdata, calc_active_tangent, tangent_names, tangent_names_len, + &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); + if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) { + /* Check we have all the needed layers */ + /* Allocate needed tangent layers */ + for (int i = 0; i < tangent_names_len; i++) + if (tangent_names[i][0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]); + if (calc_act && act_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name); + if (calc_ren && ren_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name); + +#ifdef USE_LOOPTRI_DETECT_QUADS + int num_face_as_quad_map; + int *face_as_quad_map = NULL; + + /* map faces to quads */ + if (looptri_len != mpoly_len) { + /* over alloc, since we dont know how many ngon or quads we have */ + + /* map fake face index to looptri */ + face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__); + int k, j; + for (k = 0, j = 0; j < (int)looptri_len; k++, j++) { + face_as_quad_map[k] = j; + /* step over all quads */ + if (mpoly[looptri[j].poly].totloop == 4) { + j++; /* skips the nest looptri */ + } + } + num_face_as_quad_map = k; + } + else { + num_face_as_quad_map = (int)looptri_len; + } +#endif + + /* Calculation */ + { + TaskScheduler *scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + task_pool = BLI_task_pool_create(scheduler, NULL); + + tangent_mask_curr = 0; + /* Calculate tangent layers */ + SGLSLMeshToTangent data_array[MAX_MTFACE]; + const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT); + for (int n = 0; n < tangent_layer_num; n++) { + int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n); + BLI_assert(n < MAX_MTFACE); + SGLSLMeshToTangent *mesh2tangent = &data_array[n]; + mesh2tangent->numTessFaces = (int)looptri_len; +#ifdef USE_LOOPTRI_DETECT_QUADS + mesh2tangent->face_as_quad_map = face_as_quad_map; + mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; +#endif + mesh2tangent->mvert = mvert; + mesh2tangent->mpoly = mpoly; + mesh2tangent->mloop = mloop; + mesh2tangent->looptri = looptri; + /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), + * have to check this is valid... + */ + mesh2tangent->precomputedLoopNormals = loop_normals; + mesh2tangent->precomputedFaceNormals = poly_normals; + + mesh2tangent->orco = NULL; + mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata->layers[index].name); + if (!mesh2tangent->mloopuv) { + mesh2tangent->orco = vert_orco; + if (!mesh2tangent->orco) + continue; + } + mesh2tangent->tangent = loopdata_out->layers[index].data; + + /* Fill the resulting tangent_mask */ + int uv_ind = CustomData_get_named_layer_index( + loopdata, CD_MLOOPUV, loopdata_out->layers[index].name); + int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV); + BLI_assert(uv_ind != -1 && uv_start != -1); + BLI_assert(uv_ind - uv_start < MAX_MTFACE); + tangent_mask_curr |= (char)(1 << (uv_ind - uv_start)); + BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); + } + + BLI_assert(tangent_mask_curr == tangent_mask); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + } +#ifdef USE_LOOPTRI_DETECT_QUADS + if (face_as_quad_map) { + MEM_freeN(face_as_quad_map); + } +#undef USE_LOOPTRI_DETECT_QUADS + +#endif + + *tangent_mask_curr_p = tangent_mask_curr; + + int uv_index, tan_index; + + /* Update active layer index */ + uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n); + if (uv_index != -1) { + tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, loopdata->layers[uv_index].name); + CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index); + } + + /* Update render layer index */ + uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n); + if (uv_index != -1) { + tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, loopdata->layers[uv_index].name); + CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index); + } + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 4aeddbb4c45..54de843bc64 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -43,10 +43,11 @@ #include "BLI_math_vector.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_mesh.h" +#include "DEG_depsgraph.h" + #include "MEM_guardedalloc.h" /* loop v/e are unsigned, so using max uint_32 value as invalid marker... */ @@ -936,7 +937,7 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, { bool is_valid = true; bool is_change_v, is_change_e, is_change_l, is_change_p; - int tot_texpoly, tot_uvloop, tot_vcolloop; + int tot_uvloop, tot_vcolloop; CustomDataMask mask = check_meshmask ? CD_MASK_MESH : 0; is_valid &= mesh_validate_customdata(vdata, mask, do_verbose, do_fixes, &is_change_v); @@ -944,17 +945,8 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, is_valid &= mesh_validate_customdata(ldata, mask, do_verbose, do_fixes, &is_change_l); is_valid &= mesh_validate_customdata(pdata, mask, do_verbose, do_fixes, &is_change_p); - tot_texpoly = CustomData_number_of_layers(pdata, CD_MTEXPOLY); tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV); tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL); - if (tot_texpoly != tot_uvloop) { - PRINT_ERR("\tCustomDataLayer mismatch, tot_texpoly(%d), tot_uvloop(%d)\n", - tot_texpoly, tot_uvloop); - } - if (tot_texpoly > MAX_MTFACE) { - PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MTFACE, tot_texpoly - MAX_MTFACE); - } if (tot_uvloop > MAX_MTFACE) { PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", MAX_MTFACE, tot_uvloop - MAX_MTFACE); @@ -965,18 +957,10 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, } /* check indices of clone/stencil */ - if (do_fixes && CustomData_get_clone_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) { - CustomData_set_layer_clone(pdata, CD_MTEXPOLY, 0); - is_change_p = true; - } if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) { CustomData_set_layer_clone(ldata, CD_MLOOPUV, 0); is_change_l = true; } - if (do_fixes && CustomData_get_stencil_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) { - CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, 0); - is_change_p = true; - } if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) { CustomData_set_layer_stencil(ldata, CD_MLOOPUV, 0); is_change_l = true; @@ -1019,7 +1003,7 @@ int BKE_mesh_validate(Mesh *me, const int do_verbose, const int cddata_check_mas &changed); if (changed) { - DAG_id_tag_update(&me->id, OB_RECALC_DATA); + DEG_id_tag_update(&me->id, OB_RECALC_DATA); return true; } else { @@ -1028,64 +1012,6 @@ int BKE_mesh_validate(Mesh *me, const int do_verbose, const int cddata_check_mas } /** - * Duplicate of BM_mesh_cd_validate() for Mesh data. - */ -void BKE_mesh_cd_validate(Mesh *me) -{ - int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); - int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); - int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); - int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY); - int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV); - int i; - - /* XXX For now, do not delete those, just warn they are not really usable. */ - if (UNLIKELY(totlayer_mtex > MAX_MTFACE)) { - printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MTFACE, totlayer_mtex - MAX_MTFACE); - } - if (UNLIKELY(totlayer_uv > MAX_MTFACE)) { - printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MTFACE, totlayer_uv - MAX_MTFACE); - } - if (UNLIKELY(totlayer_mcol > MAX_MCOL)) { - printf("WARNING! More VCol layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MCOL, totlayer_mcol - MAX_MCOL); - } - - if (LIKELY(totlayer_mtex == totlayer_uv)) { - /* pass */ - } - else if (totlayer_mtex < totlayer_uv) { - do { - const char *from_name = me->ldata.layers[uv_index + totlayer_mtex].name; - CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name); - CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex); - } while (totlayer_uv != ++totlayer_mtex); - mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY); - } - else if (totlayer_uv < totlayer_mtex) { - do { - const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name; - CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name); - CustomData_set_layer_unique_name(&me->ldata, totlayer_uv); - } while (totlayer_mtex != ++totlayer_uv); - uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV); - } - - BLI_assert(totlayer_mtex == totlayer_uv); - - /* Check uv/tex names match as well!!! */ - for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) { - const char *name_src = me->pdata.layers[mtex_index].name; - const char *name_dst = me->ldata.layers[uv_index].name; - if (!STREQ(name_src, name_dst)) { - BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false); - } - } -} - -/** * Check all material indices of polygons are valid, invalid ones are set to 0. * \returns is_valid. */ @@ -1105,7 +1031,7 @@ int BKE_mesh_validate_material_indices(Mesh *me) } if (!is_valid) { - DAG_id_tag_update(&me->id, OB_RECALC_DATA); + DEG_id_tag_update(&me->id, OB_RECALC_DATA); return true; } else { diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 63da1b5f9e7..7c382bccfc9 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3588,6 +3588,8 @@ static void registerShaderNodes(void) register_node_type_sh_output_lamp(); register_node_type_sh_output_material(); + register_node_type_sh_output_metallic(); + register_node_type_sh_output_specular(); register_node_type_sh_output_world(); register_node_type_sh_output_linestyle(); @@ -3777,3 +3779,20 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, return true; } + +/* -------------------------------------------------------------------- */ +/* NodeTree kernel functions */ + +void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index) +{ + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { + if (node->custom1 == layer_index) { + node->custom1 = 0; + } + else if (node->custom1 > layer_index) { + node->custom1--; + } + } + } +} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index b65cc408ae5..b1d2573f0e8 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -58,6 +58,7 @@ #include "DNA_view3d_types.h" #include "DNA_world_types.h" #include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_property_types.h" #include "DNA_rigidbody_types.h" @@ -78,7 +79,6 @@ #include "BKE_action.h" #include "BKE_bullet.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_animsys.h" #include "BKE_anim.h" @@ -91,6 +91,7 @@ #include "BKE_icons.h" #include "BKE_key.h" #include "BKE_lamp.h" +#include "BKE_layer.h" #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -103,9 +104,11 @@ #include "BKE_multires.h" #include "BKE_node.h" #include "BKE_object.h" +#include "BKE_object_facemap.h" #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_lightprobe.h" #include "BKE_property.h" #include "BKE_rigidbody.h" #include "BKE_sca.h" @@ -118,6 +121,10 @@ #include "BKE_camera.h" #include "BKE_image.h" +#include "DEG_depsgraph.h" + +#include "DRW_engine.h" + #ifdef WITH_MOD_FLUID #include "LBM_fluidsim.h" #endif @@ -129,7 +136,7 @@ #include "CCGSubSurf.h" #include "atomic_ops.h" -#include "GPU_material.h" +#include "GPU_lamp.h" /* Vertex parent modifies original BMesh which is not safe for threading. * Ideally such a modification should be handled as a separate DAG update @@ -154,7 +161,7 @@ void BKE_object_workob_clear(Object *workob) void BKE_object_update_base_layer(struct Scene *scene, Object *ob) { - Base *base = scene->base.first; + BaseLegacy *base = scene->base.first; while (base) { if (base->object == ob) base->lay = ob->lay; @@ -401,7 +408,7 @@ void BKE_object_free_caches(Object *object) * guaranteed to be in a known state. */ if (update_flag != 0) { - DAG_id_tag_update(&object->id, update_flag); + DEG_id_tag_update(&object->id, update_flag); } } @@ -418,6 +425,7 @@ void BKE_object_free(Object *ob) MEM_SAFE_FREE(ob->bb); BLI_freelistN(&ob->defbase); + BLI_freelistN(&ob->fmaps); if (ob->pose) { BKE_pose_free_ex(ob->pose, false); ob->pose = NULL; @@ -448,6 +456,18 @@ void BKE_object_free(Object *ob) } GPU_lamp_free(ob); + for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { + if (oed->storage) { + if (oed->free) { + oed->free(oed->storage); + } + MEM_freeN(oed->storage); + } + } + BLI_freelistN(&ob->drawdata); + + ob->deg_update_flag = 0; + BKE_sculptsession_free(ob); BLI_freelistN(&ob->pc_ids); @@ -464,6 +484,9 @@ void BKE_object_free(Object *ob) } BKE_previewimg_free(&ob->preview); + + /* don't free, let the base free it */ + ob->base_collection_properties = NULL; } /* actual check for internal data, not context or flags */ @@ -581,6 +604,7 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) case OB_LATTICE: return BKE_lattice_add(bmain, name); case OB_ARMATURE: return BKE_armature_add(bmain, name); case OB_SPEAKER: return BKE_speaker_add(bmain, name); + case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name); case OB_EMPTY: return NULL; default: printf("%s: Internal error, bad type: %d\n", __func__, type); @@ -683,23 +707,26 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) /* general add: to scene, with layer from area and default name */ /* creates minimum required data, but without vertices etc. */ Object *BKE_object_add( - Main *bmain, Scene *scene, + Main *bmain, Scene *scene, SceneLayer *sl, int type, const char *name) { Object *ob; Base *base; + LayerCollection *lc; ob = BKE_object_add_only_object(bmain, type, name); ob->data = BKE_object_obdata_add_from_type(bmain, type, name); - ob->lay = scene->lay; - - base = BKE_scene_base_add(scene, ob); - BKE_scene_base_deselect_all(scene); - BKE_scene_base_select(scene, base); - DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + lc = BKE_layer_collection_get_active_ensure(scene, sl); + + BKE_collection_object_add(scene, lc->scene_collection, ob); + base = BKE_scene_layer_base_find(sl, ob); + BKE_scene_layer_base_deselect_all(sl); + BKE_scene_layer_base_select(sl, base); + + DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); return ob; } @@ -794,9 +821,9 @@ static LodLevel *lod_level_select(Object *ob, const float camera_position[3]) return current; } -bool BKE_object_lod_is_usable(Object *ob, Scene *scene) +bool BKE_object_lod_is_usable(Object *ob, SceneLayer *sl) { - bool active = (scene) ? ob == OBACT : false; + bool active = (sl) ? ob == OBACT_NEW : false; return (ob->mode == OB_MODE_OBJECT || !active); } @@ -810,11 +837,11 @@ void BKE_object_lod_update(Object *ob, const float camera_position[3]) } } -static Object *lod_ob_get(Object *ob, Scene *scene, int flag) +static Object *lod_ob_get(Object *ob, SceneLayer *sl, int flag) { LodLevel *current = ob->currentlod; - if (!current || !BKE_object_lod_is_usable(ob, scene)) + if (!current || !BKE_object_lod_is_usable(ob, sl)) return ob; while (current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) { @@ -824,14 +851,14 @@ static Object *lod_ob_get(Object *ob, Scene *scene, int flag) return current->source; } -struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene) +struct Object *BKE_object_lod_meshob_get(Object *ob, SceneLayer *sl) { - return lod_ob_get(ob, scene, OB_LOD_USE_MESH); + return lod_ob_get(ob, sl, OB_LOD_USE_MESH); } -struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene) +struct Object *BKE_object_lod_matob_get(Object *ob, SceneLayer *sl) { - return lod_ob_get(ob, scene, OB_LOD_USE_MAT); + return lod_ob_get(ob, sl, OB_LOD_USE_MAT); } #endif /* WITH_GAMEENGINE */ @@ -943,6 +970,7 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys) psysn->effectors = NULL; psysn->tree = NULL; psysn->bvhtree = NULL; + psysn->batch_cache = NULL; BLI_listbase_clear(&psysn->pathcachebufs); BLI_listbase_clear(&psysn->childcachebufs); @@ -1138,6 +1166,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) BKE_pose_rebuild(obn, obn->data); } defgroup_copy_list(&obn->defbase, &ob->defbase); + BKE_object_facemap_copy_list(&obn->fmaps, &ob->fmaps); BKE_constraints_copy(&obn->constraints, &ob->constraints, true); obn->mode = OB_MODE_OBJECT; @@ -1170,6 +1199,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) BLI_listbase_clear(&obn->gpulamp); BLI_listbase_clear(&obn->pc_ids); + BLI_listbase_clear(&obn->drawdata); obn->mpath = NULL; @@ -1265,10 +1295,10 @@ static void armature_set_id_extern(Object *ob) unsigned int lay = arm->layer_protected; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (!(pchan->bone->layer & lay)) + if (!(pchan->bone->layer & lay)) { id_lib_extern((ID *)pchan->custom); + } } - } void BKE_object_copy_proxy_drivers(Object *ob, Object *target) @@ -1326,8 +1356,8 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) ob->proxy_group = gob; id_lib_extern(&target->id); - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - DAG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* copy transform * - gob means this proxy comes from a group, just apply the matrix @@ -2486,14 +2516,14 @@ void BKE_object_foreach_display_point( } void BKE_scene_foreach_display_point( - Scene *scene, View3D *v3d, const short flag, + Scene *scene, SceneLayer *sl, void (*func_cb)(const float[3], void *), void *user_data) { Base *base; Object *ob; - for (base = FIRSTBASE; base; base = base->next) { - if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag & flag) == flag) { + for (base = FIRSTBASE_NEW; base; base = base->next) { + if (((base->flag & BASE_VISIBLED) != 0) && ((base->flag & BASE_SELECTED) != 0)) { ob = base->object; if ((ob->transflag & OB_DUPLI) == 0) { @@ -2714,14 +2744,7 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, switch (GS(((ID *)ob->data)->name)) { case ID_ME: { - Mesh *me = ob->data; - if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(me); - } - if (r_texflag) *r_texflag = &me->texflag; - if (r_loc) *r_loc = me->loc; - if (r_size) *r_size = me->size; - if (r_rot) *r_rot = me->rot; + BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size); break; } case ID_CU: @@ -3288,33 +3311,33 @@ static void obrel_list_add(LinkNode **links, Object *ob) } /* - * Iterates over all objects of the given scene. + * Iterates over all objects of the given scene layer. * Depending on the eObjectSet flag: * collect either OB_SET_ALL, OB_SET_VISIBLE or OB_SET_SELECTED objects. * If OB_SET_VISIBLE or OB_SET_SELECTED are collected, * then also add related objects according to the given includeFilters. */ -LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter) +LinkNode *BKE_object_relational_superset(struct SceneLayer *scene_layer, eObjectSet objectSet, eObRelationTypes includeFilter) { LinkNode *links = NULL; Base *base; /* Remove markers from all objects */ - for (base = scene->base.first; base; base = base->next) { + for (base = scene_layer->object_bases.first; base; base = base->next) { base->object->id.tag &= ~LIB_TAG_DOIT; } /* iterate over all selected and visible objects */ - for (base = scene->base.first; base; base = base->next) { + for (base = scene_layer->object_bases.first; base; base = base->next) { if (objectSet == OB_SET_ALL) { /* as we get all anyways just add it */ Object *ob = base->object; obrel_list_add(&links, ob); } else { - if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), scene, base)) || - (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, base))) + if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE_NEW(base)) || + (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE_NEW(base))) { Object *ob = base->object; @@ -3343,8 +3366,8 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS /* child relationship */ if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) { Base *local_base; - for (local_base = scene->base.first; local_base; local_base = local_base->next) { - if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) { + for (local_base = scene_layer->object_bases.first; local_base; local_base = local_base->next) { + if (BASE_EDITABLE_BGMODE_NEW(local_base)) { Object *child = local_base->object; if (obrel_list_test(child)) { @@ -3388,18 +3411,11 @@ struct LinkNode *BKE_object_groups(Object *ob) return group_linknode; } -void BKE_object_groups_clear(Scene *scene, Base *base, Object *object) +void BKE_object_groups_clear(Object *ob) { Group *group = NULL; - - BLI_assert((base == NULL) || (base->object == object)); - - if (scene && base == NULL) { - base = BKE_scene_base_find(scene, object); - } - - while ((group = BKE_group_object_find(group, base->object))) { - BKE_group_object_unlink(group, object, scene, base); + while ((group = BKE_group_object_find(group, ob))) { + BKE_group_object_unlink(group, ob); } } diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index ccf2aec5c7a..455c4b6352d 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -51,6 +51,7 @@ #include "BKE_editmesh.h" #include "BKE_object_deform.h" /* own include */ #include "BKE_object.h" +#include "BKE_mesh.h" #include "BKE_modifier.h" /** \name Misc helpers @@ -405,6 +406,8 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) object_defgroup_remove_edit_mode(ob, defgroup); else object_defgroup_remove_object_mode(ob, defgroup); + + BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_PAINT); } /** diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index e9ebd397df0..774ddca061d 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -49,7 +49,6 @@ #include "BKE_animsys.h" #include "BKE_DerivedMesh.h" -#include "BKE_depsgraph.h" #include "BKE_font.h" #include "BKE_group.h" #include "BKE_global.h" @@ -62,6 +61,7 @@ #include "BKE_editmesh.h" #include "BKE_anim.h" +#include "DEG_depsgraph.h" #include "BLI_strict_flags.h" #include "BLI_hash.h" @@ -77,7 +77,6 @@ typedef struct DupliContext { Scene *scene; Object *object; float space_mat[4][4]; - unsigned int lay; int persistent_id[MAX_DUPLI_RECUR]; int level; @@ -110,7 +109,6 @@ static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene copy_m4_m4(r_ctx->space_mat, space_mat); else unit_m4(r_ctx->space_mat); - r_ctx->lay = ob->lay; r_ctx->level = 0; r_ctx->gen = get_dupli_generator(r_ctx); @@ -259,7 +257,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild else { unsigned int lay = ctx->scene->lay; int baseid = 0; - Base *base; + BaseLegacy *base; for (base = ctx->scene->base.first; base; base = base->next, baseid++) { Object *ob = base->object; diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c new file mode 100644 index 00000000000..0e1e29f7bf3 --- /dev/null +++ b/source/blender/blenkernel/intern/object_facemap.c @@ -0,0 +1,257 @@ + +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/object_facemap.c + * \ingroup bke + */ + +#include <string.h> + +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_object.h" +#include "BKE_object_facemap.h" /* own include */ +#include "BKE_object_deform.h" + +#include "BLI_utildefines.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" +#include "BLI_listbase.h" + +#include "BLT_translation.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +static bool fmap_unique_check(void *arg, const char *name) +{ + struct {Object *ob; void *fm; } *data = arg; + + bFaceMap *fmap; + + for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) { + if (data->fm != fmap) { + if (!strcmp(fmap->name, name)) { + return true; + } + } + } + + return false; +} + +static bFaceMap *fmap_duplicate(bFaceMap *infmap) +{ + bFaceMap *outfmap; + + if (!infmap) + return NULL; + + outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap"); + + /* For now, just copy everything over. */ + memcpy(outfmap, infmap, sizeof(bFaceMap)); + + outfmap->next = outfmap->prev = NULL; + + return outfmap; +} + +void BKE_object_facemap_copy_list(ListBase *outbase, ListBase *inbase) +{ + bFaceMap *fmap, *fmapn; + + BLI_listbase_clear(outbase); + + for (fmap = inbase->first; fmap; fmap = fmap->next) { + fmapn = fmap_duplicate(fmap); + BLI_addtail(outbase, fmapn); + } +} + +void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap) +{ + struct {Object *ob; void *fmap; } data; + data.ob = ob; + data.fmap = fmap; + + BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name)); +} + +bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name) +{ + bFaceMap *fmap; + + if (!ob || ob->type != OB_MESH) + return NULL; + + fmap = MEM_callocN(sizeof(bFaceMap), __func__); + + BLI_strncpy(fmap->name, name, sizeof(fmap->name)); + + BLI_addtail(&ob->fmaps, fmap); + + ob->actfmap = BLI_listbase_count(&ob->fmaps); + + BKE_object_facemap_unique_name(ob, fmap); + + return fmap; +} + +bFaceMap *BKE_object_facemap_add(Object *ob) +{ + return BKE_object_facemap_add_name(ob, DATA_("FaceMap")); +} + + +static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge) +{ + const int fmap_nr = BLI_findindex(&ob->fmaps, fmap); + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); + + if (cd_fmap_offset != -1) { + BMFace *efa; + BMIter iter; + int *map; + + if (purge) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (map) { + if (*map == fmap_nr) + *map = -1; + else if (*map > fmap_nr) + *map -= 1; + } + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (map && *map == fmap_nr && (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) { + *map = -1; + } + } + } + } + + if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) + ob->actfmap--; + + BLI_remlink(&ob->fmaps, fmap); + MEM_freeN(fmap); + } + } +} + +static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge) +{ + const int fmap_nr = BLI_findindex(&ob->fmaps, fmap); + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) { + int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP); + int i; + + if (map) { + for (i = 0; i < me->totpoly; i++) { + if (map[i] == fmap_nr) + map[i] = -1; + else if (purge && map[i] > fmap_nr) + map[i]--; + } + } + } + + if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) + ob->actfmap--; + + BLI_remlink(&ob->fmaps, fmap); + MEM_freeN(fmap); + } +} + +static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge) +{ + if (is_edit_mode) + object_fmap_remove_edit_mode(ob, fmap, false, purge); + else + object_fmap_remove_object_mode(ob, fmap, purge); +} + +void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap) +{ + fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true); +} + +void BKE_object_facemap_clear(Object *ob) +{ + bFaceMap *fmap = (bFaceMap *)ob->fmaps.first; + + if (fmap) { + const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob); + + while (fmap) { + bFaceMap *next_fmap = fmap->next; + fmap_remove_exec(ob, fmap, edit_mode, false); + fmap = next_fmap; + } + } + /* remove all face-maps */ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0); + } + ob->actfmap = 0; +} + +int BKE_object_facemap_name_index(Object *ob, const char *name) +{ + return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1; +} + +bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name) +{ + return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name)); +} diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index e03af585cf2..0c53ee8818a 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -43,7 +43,7 @@ #include "BKE_armature.h" #include "BKE_action.h" #include "BKE_constraint.h" -#include "BKE_depsgraph.h" +#include "BKE_curve.h" #include "BKE_DerivedMesh.h" #include "BKE_animsys.h" #include "BKE_displist.h" @@ -57,15 +57,12 @@ #include "BKE_pointcache.h" #include "BKE_scene.h" #include "BKE_material.h" +#include "BKE_mesh.h" #include "BKE_image.h" #include "DEG_depsgraph.h" -#ifdef WITH_LEGACY_DEPSGRAPH -# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf -#else -# define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf -#endif +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER; @@ -334,6 +331,20 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, BLI_assert(ob->type != OB_ARMATURE); BKE_object_handle_data_update(eval_ctx, scene, ob); + switch (ob->type) { + case OB_MESH: + BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + break; + case OB_LATTICE: + BKE_lattice_batch_cache_dirty(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL); + break; + case OB_CURVE: + case OB_FONT: + case OB_SURF: + BKE_curve_batch_cache_dirty(ob->data, BKE_CURVE_BATCH_DIRTY_ALL); + break; + } + ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); } diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index f31ba34a984..3e99dbe37ca 100644 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -27,6 +27,7 @@ */ #include <stdlib.h> +#include <string.h> #include "BKE_outliner_treehash.h" @@ -56,7 +57,7 @@ static TseGroup *tse_group_create(void) return tse_group; } -static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem) +static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem) { if (UNLIKELY(tse_group->size == tse_group->allocated)) { tse_group->allocated *= 2; @@ -66,6 +67,26 @@ static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem) tse_group->size++; } +static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem) +{ + int min_allocated = MAX2(1, tse_group->allocated / 2); + BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0); + + tse_group->size--; + BLI_assert(tse_group->size >= 0); + for (int i = 0; i < tse_group->size; i++) { + if (tse_group->elems[i] == elem) { + memcpy(tse_group->elems[i], tse_group->elems[i + 1], (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *)); + break; + } + } + + if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) { + tse_group->allocated = min_allocated; + tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated); + } +} + static void tse_group_free(TseGroup *tse_group) { MEM_freeN(tse_group->elems); @@ -140,7 +161,21 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem) *val_p = tse_group_create(); } group = *val_p; - tse_group_add(group, elem); + tse_group_add_element(group, elem); +} + +void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem) +{ + TseGroup *group = BLI_ghash_lookup(treehash, elem); + + BLI_assert(group != NULL); + if (group->size <= 1) { + /* one element -> remove group completely */ + BLI_ghash_remove(treehash, elem, NULL, free_treehash_group); + } + else { + tse_group_remove_element(group, elem); + } } static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id) diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 6b954f060d3..5a85637755d 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -52,7 +52,6 @@ #include "BKE_main.h" #include "BKE_context.h" #include "BKE_crazyspace.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_key.h" @@ -64,6 +63,8 @@ #include "BKE_pbvh.h" #include "BKE_subsurf.h" +#include "DEG_depsgraph.h" + #include "bmesh.h" const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; @@ -73,9 +74,9 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; static OverlayControlFlags overlay_flags = 0; -void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex) +void BKE_paint_invalidate_overlay_tex(Scene *scene, SceneLayer *sl, const Tex *tex) { - Paint *p = BKE_paint_get_active(scene); + Paint *p = BKE_paint_get_active(scene, sl); Brush *br = p->brush; if (!br) @@ -87,9 +88,9 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex) overlay_flags |= PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY; } -void BKE_paint_invalidate_cursor_overlay(Scene *scene, CurveMapping *curve) +void BKE_paint_invalidate_cursor_overlay(Scene *scene, SceneLayer *sl, CurveMapping *curve) { - Paint *p = BKE_paint_get_active(scene); + Paint *p = BKE_paint_get_active(scene, sl); Brush *br = p->brush; if (br && br->curve == curve) @@ -155,13 +156,13 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode) return NULL; } -Paint *BKE_paint_get_active(Scene *sce) +Paint *BKE_paint_get_active(Scene *sce, SceneLayer *sl) { - if (sce) { + if (sce && sl) { ToolSettings *ts = sce->toolsettings; - if (sce->basact && sce->basact->object) { - switch (sce->basact->object->mode) { + if (sl->basact && sl->basact->object) { + switch (sl->basact->object->mode) { case OB_MODE_SCULPT: return &ts->sculpt->paint; case OB_MODE_VERTEX_PAINT: @@ -187,14 +188,15 @@ Paint *BKE_paint_get_active(Scene *sce) Paint *BKE_paint_get_active_from_context(const bContext *C) { Scene *sce = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); SpaceImage *sima; - if (sce) { + if (sce && sl) { ToolSettings *ts = sce->toolsettings; Object *obact = NULL; - if (sce->basact && sce->basact->object) - obact = sce->basact->object; + if (sl->basact && sl->basact->object) + obact = sl->basact->object; if ((sima = CTX_wm_space_image(C)) != NULL) { if (obact && obact->mode == OB_MODE_EDIT) { @@ -237,14 +239,15 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) PaintMode BKE_paintmode_get_active_from_context(const bContext *C) { Scene *sce = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); SpaceImage *sima; - if (sce) { + if (sce && sl) { ToolSettings *ts = sce->toolsettings; Object *obact = NULL; - if (sce->basact && sce->basact->object) - obact = sce->basact->object; + if (sl->basact && sl->basact->object) + obact = sl->basact->object; if ((sima = CTX_wm_space_image(C)) != NULL) { if (obact && obact->mode == OB_MODE_EDIT) { @@ -681,7 +684,7 @@ void BKE_sculptsession_bm_to_me(Object *ob, bool reorder) sculptsession_bm_to_me_update_data_only(ob, reorder); /* ensure the objects DerivedMesh mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 021e9b4339d..df48c319064 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -78,7 +78,6 @@ #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" -#include "BKE_depsgraph.h" #include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_cdderivedmesh.h" @@ -86,6 +85,9 @@ #include "BKE_scene.h" #include "BKE_deform.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "RE_render_ext.h" unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT]; @@ -601,6 +603,8 @@ void psys_free(Object *ob, ParticleSystem *psys) MEM_freeN(psys->pdd); } + BKE_particle_batch_cache_free(psys); + MEM_freeN(psys); } } @@ -3153,8 +3157,8 @@ ModifierData *object_add_particle_system(Scene *scene, Object *ob, const char *n psys->flag = PSYS_CURRENT; psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1); - DAG_relations_tag_update(G.main); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(G.main); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); return md; } @@ -3199,8 +3203,8 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob) else ob->mode &= ~OB_MODE_PARTICLE_EDIT; - DAG_relations_tag_update(G.main); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(G.main); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } static void default_particle_settings(ParticleSettings *part) @@ -3285,6 +3289,7 @@ static void default_particle_settings(ParticleSettings *part) part->omat = 1; part->use_modifier_stack = false; + part->draw_size = 0.1f; } @@ -4305,3 +4310,22 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) psys->flag |= PSYS_EDITED; } } + + + +/* Draw Engine */ +void (*BKE_particle_batch_cache_dirty_cb)(ParticleSystem *psys, int mode) = NULL; +void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL; + +void BKE_particle_batch_cache_dirty(ParticleSystem *psys, int mode) +{ + if (psys->batch_cache) { + BKE_particle_batch_cache_dirty_cb(psys, mode); + } +} +void BKE_particle_batch_cache_free(ParticleSystem *psys) +{ + if (psys->batch_cache) { + BKE_particle_batch_cache_free_cb(psys); + } +} diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 3f9a92a5577..a6ed50fd0e9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -78,6 +78,7 @@ #include "BKE_particle.h" #include "BKE_global.h" +#include "BKE_collection.h" #include "BKE_DerivedMesh.h" #include "BKE_object.h" #include "BKE_material.h" @@ -88,7 +89,6 @@ #include "BKE_modifier.h" #include "BKE_scene.h" #include "BKE_bvhutils.h" -#include "BKE_depsgraph.h" #include "PIL_time.h" @@ -2896,7 +2896,6 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; ParticleEditSettings *pset = &sim->scene->toolsettings->particle; - Base *base; int distr=0, alloc=0, skip=0; if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) @@ -2941,8 +2940,9 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons /* particle instance modifier with "path" option need cached paths even if particle system doesn't */ - for (base = sim->scene->base.first; base; base= base->next) { - ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance); + FOREACH_SCENE_OBJECT(sim->scene, ob) + { + ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance); if (md) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) { @@ -2951,6 +2951,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons } } } + FOREACH_SCENE_OBJECT_END if (!skip) { psys_cache_paths(sim, cfra, use_render_params); @@ -4320,6 +4321,8 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys, cons /* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */ if (psys->renderdata==0) invert_m4_m4(psys->imat, ob->obmat); + + BKE_particle_batch_cache_dirty(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); } /* ID looper */ @@ -4350,7 +4353,7 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, /* **** Depsgraph evaluation **** */ -void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx), +void BKE_particle_system_eval(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob, ParticleSystem *psys) diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 53dfffe2b97..336d4fae1b8 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -40,6 +40,7 @@ #include "BKE_paint.h" #include "GPU_buffers.h" +#include "GPU_immediate.h" #include "bmesh.h" @@ -1158,15 +1159,16 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) static void pbvh_draw_BB(PBVH *bvh) { - GPU_pbvh_BB_draw_init(); + unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 3, KEEP_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); for (int a = 0; a < bvh->totnode; a++) { PBVHNode *node = &bvh->nodes[a]; - GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0)); + GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0), pos); } - GPU_pbvh_BB_draw_end(); + immUnbindProgram(); } static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) @@ -1739,24 +1741,6 @@ void BKE_pbvh_node_draw(PBVHNode *node, void *data_v) { PBVHNodeDrawData *data = data_v; -#if 0 - /* XXX: Just some quick code to show leaf nodes in different colors */ - float col[3]; - float spec[3] = {0.0f, 0.0f, 0.0f}; - - if (0) { //is_partial) { - col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6; - } - else { - srand((long long)node); - for (int i = 0; i < 3; ++i) - col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7; - } - - GPU_basic_shader_colors(col, spec, 0, 1.0f); - glColor3f(1, 0, 0); -#endif - if (!(node->flag & PBVH_FullyHidden)) { GPU_pbvh_buffers_draw(node->draw_buffers, data->setMaterial, @@ -1863,6 +1847,67 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], pbvh_draw_BB(bvh); } +struct PBVHNodeDrawCallbackData { + + void (*draw_fn)(void *user_data, Batch *batch); + void *user_data; + bool fast; +}; + +static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) +{ + struct PBVHNodeDrawCallbackData *data = data_v; + + if (!(node->flag & PBVH_FullyHidden)) { + Batch *triangles = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast); + if (triangles != NULL) { + data->draw_fn(data->user_data, triangles); + } + } +} + +/** + * Version of #BKE_pbvh_draw that runs a callback. + */ +void BKE_pbvh_draw_cb( + PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, + void (*draw_fn)(void *user_data, Batch *batch), void *user_data) +{ + struct PBVHNodeDrawCallbackData draw_data = { + .fast = fast, + .draw_fn = draw_fn, + .user_data = user_data, + }; + PBVHNode **nodes; + int totnode; + + for (int a = 0; a < bvh->totnode; a++) + pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); + + BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), + &nodes, &totnode); + + pbvh_update_normals(bvh, nodes, totnode, fnors); + pbvh_update_draw_buffers(bvh, nodes, totnode); + + if (nodes) MEM_freeN(nodes); + + if (planes) { + BKE_pbvh_search_callback( + bvh, BKE_pbvh_node_planes_contain_AABB, + planes, pbvh_node_draw_cb, &draw_data); + } + else { + BKE_pbvh_search_callback( + bvh, NULL, + NULL, pbvh_node_draw_cb, &draw_data); + } +#if 0 + if (G.debug_value == 14) + pbvh_draw_BB(bvh); +#endif +} + void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { @@ -2072,22 +2117,22 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK); } -void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color) +bool pbvh_has_mask(PBVH *bvh) { - bool has_mask = false; - switch (bvh->type) { case PBVH_GRIDS: - has_mask = (bvh->gridkey.has_mask != 0); - break; + return (bvh->gridkey.has_mask != 0); case PBVH_FACES: - has_mask = (bvh->vdata && CustomData_get_layer(bvh->vdata, - CD_PAINT_MASK)); - break; + return (bvh->vdata && CustomData_get_layer(bvh->vdata, + CD_PAINT_MASK)); case PBVH_BMESH: - has_mask = (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1)); - break; + return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1)); } - bvh->show_diffuse_color = !has_mask || show_diffuse_color; + return false; +} + +void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color) +{ + bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color; } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index a7e00a8103a..0b152534dcb 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3652,7 +3652,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) stime = ptime = PIL_check_seconds_timer(); for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) { - BKE_scene_update_for_newframe(G.main->eval_ctx, bmain, scene, scene->lay); + BKE_scene_update_for_newframe(G.main->eval_ctx, bmain, scene); if (baker->update_progress) { float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe)); @@ -3738,7 +3738,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) CFRA = cfrao; if (bake) { /* already on cfra unless baking */ - BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); + BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene); } /* TODO: call redraw all windows somehow */ diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index b3a36bfb089..aec635feffa 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -55,7 +55,6 @@ #include "DNA_scene_types.h" #include "BKE_cdderivedmesh.h" -#include "BKE_depsgraph.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_library.h" @@ -1589,7 +1588,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) } /* advance simulation, we can only step one frame forward */ - if (can_simulate) { + if (ctime == rbw->ltime + 1) { /* write cache for first frame when on second frame */ if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { BKE_ptcache_write(&pid, startframe); @@ -1652,7 +1651,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {} /* -------------------- */ /* Depsgraph evaluation */ -void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx), +void BKE_rigidbody_rebuild_sim(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene) { float ctime = BKE_scene_frame_get(scene); @@ -1667,7 +1666,7 @@ void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx), } } -void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx), +void BKE_rigidbody_eval_simulation(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene) { float ctime = BKE_scene_frame_get(scene); @@ -1682,7 +1681,7 @@ void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx), } } -void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx), +void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *ob) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 44b71416bf0..fbb24a8ccb5 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -67,8 +67,8 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_colortools.h" -#include "BKE_depsgraph.h" #include "BKE_editmesh.h" #include "BKE_fcurve.h" #include "BKE_freestyle.h" @@ -78,6 +78,7 @@ #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -92,9 +93,12 @@ #include "BKE_sequencer.h" #include "BKE_sound.h" #include "BKE_unit.h" +#include "BKE_workspace.h" #include "BKE_world.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "RE_engine.h" @@ -107,6 +111,8 @@ const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER"; const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME"; +const char *RE_engine_id_BLENDER_CLAY = "BLENDER_CLAY"; +const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE"; const char *RE_engine_id_CYCLES = "CYCLES"; void free_avicodecdata(AviCodecData *acd) @@ -154,13 +160,66 @@ static void remove_sequencer_fcurves(Scene *sce) } } +/* copy SceneCollection tree but keep pointing to the same objects */ +static void scene_collection_copy(SceneCollection *scn, SceneCollection *sc) +{ + BLI_duplicatelist(&scn->objects, &sc->objects); + for (LinkData *link = scn->objects.first; link; link = link->next) { + id_us_plus(link->data); + } + + BLI_duplicatelist(&scn->filter_objects, &sc->filter_objects); + for (LinkData *link = scn->filter_objects.first; link; link = link->next) { + id_us_plus(link->data); + } + + BLI_duplicatelist(&scn->scene_collections, &sc->scene_collections); + SceneCollection *nscn = scn->scene_collections.first; /* nested SceneCollection new */ + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + scene_collection_copy(nscn, nsc); + nscn = nscn->next; + } +} + +/* Find the equivalent SceneCollection in the new tree */ +static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_reference, SceneCollection *scn, SceneCollection *sc) +{ + if (sc == sc_reference) { + return scn; + } + + SceneCollection *nscn = scn->scene_collections.first; /* nested master collection new */ + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + + SceneCollection *found = scene_collection_from_new_tree(sc_reference, nscn, nsc); + if (found) { + return found; + } + nscn = nscn->next; + } + return NULL; +} + +/* recreate the LayerCollection tree */ +static void layer_collections_recreate(SceneLayer *sl, ListBase *lb, SceneCollection *mcn, SceneCollection *mc) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + + SceneCollection *sc = scene_collection_from_new_tree(lc->scene_collection, mcn, mc); + BLI_assert(sc); + + /* instead of syncronizing both trees we simply re-create it */ + BKE_collection_link(sl, sc); + } +} + Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) { Scene *scen; SceneRenderLayer *srl, *new_srl; FreestyleLineSet *lineset; ToolSettings *ts; - Base *base, *obase; + BaseLegacy *legacy_base, *olegacy_base; if (type == SCE_COPY_EMPTY) { ListBase rl, rv; @@ -196,14 +255,12 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) scen->theDag = NULL; scen->depsgraph = NULL; scen->obedit = NULL; - scen->stats = NULL; scen->fps_info = NULL; if (sce->rigidbody_world) scen->rigidbody_world = BKE_rigidbody_world_copy(sce->rigidbody_world); BLI_duplicatelist(&(scen->markers), &(sce->markers)); - BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces)); BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers)); BLI_duplicatelist(&(scen->r.views), &(sce->r.views)); BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets)); @@ -214,14 +271,14 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false); } - obase = sce->base.first; - base = scen->base.first; - while (base) { - id_us_plus(&base->object->id); - if (obase == sce->basact) scen->basact = base; + olegacy_base = sce->base.first; + legacy_base = scen->base.first; + while (legacy_base) { + id_us_plus(&legacy_base->object->id); + if (olegacy_base == sce->basact) scen->basact = legacy_base; - obase = obase->next; - base = base->next; + olegacy_base = olegacy_base->next; + legacy_base = legacy_base->next; } /* copy action and remove animation used by sequencer */ @@ -247,6 +304,44 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) } new_srl = new_srl->next; } + + /* layers and collections */ + scen->collection = MEM_dupallocN(sce->collection); + SceneCollection *mcn = BKE_collection_master(scen); + SceneCollection *mc = BKE_collection_master(sce); + + /* recursively creates a new SceneCollection tree */ + scene_collection_copy(mcn, mc); + + IDPropertyTemplate val = {0}; + BLI_duplicatelist(&scen->render_layers, &sce->render_layers); + SceneLayer *new_sl = scen->render_layers.first; + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + new_sl->stats = NULL; + new_sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + new_sl->properties_evaluated = NULL; + + /* we start fresh with no overrides and no visibility flags set + * instead of syncing both trees we simply unlink and relink the scene collection */ + BLI_listbase_clear(&new_sl->layer_collections); + BLI_listbase_clear(&new_sl->object_bases); + layer_collections_recreate(new_sl, &sl->layer_collections, mcn, mc); + + + if (sl->basact) { + Object *active_ob = sl->basact->object; + for (Base *base = new_sl->object_bases.first; base; base = base->next) { + if (base->object == active_ob) { + new_sl->basact = base; + break; + } + } + } + new_sl = new_sl->next; + } + + scen->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + scen->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); } /* copy color management settings */ @@ -360,6 +455,15 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) BKE_previewimg_id_copy(&scen->id, &sce->id); + if (type != SCE_COPY_NEW) { + if (sce->collection_properties) { + IDP_MergeGroup(scen->collection_properties, sce->collection_properties, true); + } + if (sce->layer_properties) { + IDP_MergeGroup(scen->layer_properties, sce->layer_properties, true); + } + } + return scen; } @@ -429,10 +533,9 @@ void BKE_scene_free(Scene *sce) } BLI_freelistN(&sce->markers); - BLI_freelistN(&sce->transform_spaces); BLI_freelistN(&sce->r.layers); BLI_freelistN(&sce->r.views); - + if (sce->toolsettings) { if (sce->toolsettings->vpaint) { BKE_paint_free(&sce->toolsettings->vpaint->paint); @@ -465,11 +568,10 @@ void BKE_scene_free(Scene *sce) sce->toolsettings = NULL; } - DAG_scene_free(sce); + DEG_scene_graph_free(sce); if (sce->depsgraph) DEG_graph_free(sce->depsgraph); - - MEM_SAFE_FREE(sce->stats); + MEM_SAFE_FREE(sce->fps_info); BKE_sound_destroy_scene(sce); @@ -478,6 +580,32 @@ void BKE_scene_free(Scene *sce) BKE_previewimg_free(&sce->preview); curvemapping_free_data(&sce->r.mblur_shutter_curve); + + for (SceneLayer *sl = sce->render_layers.first, *sl_next; sl; sl = sl_next) { + sl_next = sl->next; + + BLI_remlink(&sce->render_layers, sl); + BKE_scene_layer_free(sl); + } + + /* Master Collection */ + BKE_collection_master_free(sce); + MEM_freeN(sce->collection); + sce->collection = NULL; + + /* LayerCollection engine settings. */ + if (sce->collection_properties) { + IDP_FreeProperty(sce->collection_properties); + MEM_freeN(sce->collection_properties); + sce->collection_properties = NULL; + } + + /* Render engine setting. */ + if (sce->layer_properties) { + IDP_FreeProperty(sce->layer_properties); + MEM_freeN(sce->layer_properties); + sce->layer_properties = NULL; + } } void BKE_scene_init(Scene *sce) @@ -733,7 +861,7 @@ void BKE_scene_init(Scene *sce) sce->gm.angulardeactthreshold = 1.0f; sce->gm.deactivationtime = 0.0f; - sce->gm.flag = GAME_DISPLAY_LISTS; + sce->gm.flag = 0; sce->gm.matmode = GAME_MAT_MULTITEX; sce->gm.obstacleSimulation = OBSTSIMULATION_NONE; @@ -827,6 +955,20 @@ void BKE_scene_init(Scene *sce) sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE; + + /* Master Collection */ + sce->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection"); + BLI_strncpy(sce->collection->name, "Master Collection", sizeof(sce->collection->name)); + + /* Engine settings */ + IDPropertyTemplate val = {0}; + sce->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + BKE_layer_collection_engine_settings_create(sce->collection_properties); + + sce->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + BKE_scene_layer_engine_settings_create(sce->layer_properties); + + BKE_scene_layer_add(sce, "Render Layer"); } Scene *BKE_scene_add(Main *bmain, const char *name) @@ -842,9 +984,9 @@ Scene *BKE_scene_add(Main *bmain, const char *name) return sce; } -Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) +BaseLegacy *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) { - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { if (STREQ(base->object->id.name + 2, name)) { @@ -855,24 +997,23 @@ Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) return base; } -Base *BKE_scene_base_find(Scene *scene, Object *ob) +BaseLegacy *BKE_scene_base_find(Scene *scene, Object *ob) { - return BLI_findptr(&scene->base, ob, offsetof(Base, object)); + return BLI_findptr(&scene->base, ob, offsetof(BaseLegacy, object)); } /** * Sets the active scene, mainly used when running in background mode (``--scene`` command line argument). * This is also called to set the scene directly, bypassing windowing code. - * Otherwise #ED_screen_set_scene is used when changing scenes by the user. + * Otherwise #WM_window_change_active_scene is used when changing scenes by the user. */ void BKE_scene_set_background(Main *bmain, Scene *scene) { Scene *sce; - Base *base; + BaseLegacy *base; Object *ob; Group *group; GroupObject *go; - int flag; /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); @@ -896,7 +1037,7 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) /* sort baselist for scene and sets */ for (sce = scene; sce; sce = sce->set) - DAG_scene_relations_rebuild(bmain, sce); + DEG_scene_relations_rebuild(bmain, sce); /* copy layers and flags from bases to objects */ for (base = scene->base.first; base; base = base->next) { @@ -904,13 +1045,7 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) ob->lay = base->lay; /* group patch... */ - base->flag &= ~(OB_FROMGROUP); - flag = ob->flag & (OB_FROMGROUP); - base->flag |= flag; - - /* not too nice... for recovering objects with lost data */ - //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE; - ob->flag = base->flag; + BKE_scene_base_flag_sync_from_base(base); } /* no full animation update, this to enable render code to work (render code calls own animation updates) */ } @@ -931,7 +1066,7 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, - Scene **scene, int val, Base **base, Object **ob) + Scene **scene, int val, BaseLegacy **base, Object **ob) { bool run_again = true; @@ -1013,7 +1148,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, } /* handle dupli's */ if (iter->dupob) { - (*base)->flag |= OB_FROMDUPLI; + (*base)->flag_legacy |= OB_FROMDUPLI; *ob = iter->dupob->ob; iter->phase = F_DUPLI; @@ -1032,7 +1167,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, } else if (iter->phase == F_DUPLI) { iter->phase = F_SCENE; - (*base)->flag &= ~OB_FROMDUPLI; + (*base)->flag_legacy &= ~OB_FROMDUPLI; if (iter->dupli_refob) { /* Restore last object's real matrix. */ @@ -1057,9 +1192,22 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, return iter->phase; } +Scene *BKE_scene_find_from_collection(const Main *bmain, const SceneCollection *scene_collection) +{ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + for (SceneLayer *layer = scene->render_layers.first; layer; layer = layer->next) { + if (BKE_scene_layer_has_collection(layer, scene_collection)) { + return scene; + } + } + } + + return NULL; +} + Object *BKE_scene_camera_find(Scene *sc) { - Base *base; + BaseLegacy *base; for (base = sc->base.first; base; base = base->next) if (base->object->type == OB_CAMERA) @@ -1161,47 +1309,54 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame) return best_marker ? best_marker->name : NULL; } +void BKE_scene_remove_rigidbody_object(Scene *scene, Object *ob) +{ + /* remove rigid body constraint from world before removing object */ + if (ob->rigidbody_constraint) + BKE_rigidbody_remove_constraint(scene, ob); + /* remove rigid body object from world before removing object */ + if (ob->rigidbody_object) + BKE_rigidbody_remove_object(scene, ob); +} -Base *BKE_scene_base_add(Scene *sce, Object *ob) +BaseLegacy *BKE_scene_base_add(Scene *sce, Object *ob) { - Base *b = MEM_callocN(sizeof(*b), __func__); + BaseLegacy *b = MEM_callocN(sizeof(*b), __func__); BLI_addhead(&sce->base, b); b->object = ob; - b->flag = ob->flag; + b->flag_legacy = ob->flag; b->lay = ob->lay; return b; } -void BKE_scene_base_unlink(Scene *sce, Base *base) +void BKE_scene_base_unlink(Scene *sce, BaseLegacy *base) { - /* remove rigid body constraint from world before removing object */ - if (base->object->rigidbody_constraint) - BKE_rigidbody_remove_constraint(sce, base->object); - /* remove rigid body object from world before removing object */ - if (base->object->rigidbody_object) - BKE_rigidbody_remove_object(sce, base->object); - + BKE_scene_remove_rigidbody_object(sce, base->object); + BLI_remlink(&sce->base, base); if (sce->basact == base) sce->basact = NULL; } +/* deprecated, use BKE_scene_layer_base_deselect_all */ void BKE_scene_base_deselect_all(Scene *sce) { - Base *b; + BaseLegacy *b; for (b = sce->base.first; b; b = b->next) { - b->flag &= ~SELECT; - b->object->flag = b->flag; + b->flag_legacy &= ~SELECT; + int flag = b->object->flag & (OB_FROMGROUP); + b->object->flag = b->flag_legacy; + b->object->flag |= flag; } } -void BKE_scene_base_select(Scene *sce, Base *selbase) +void BKE_scene_base_select(Scene *sce, BaseLegacy *selbase) { - selbase->flag |= SELECT; - selbase->object->flag = selbase->flag; + selbase->flag_legacy |= SELECT; + selbase->object->flag = selbase->flag_legacy; sce->basact = selbase; } @@ -1255,109 +1410,6 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra) scene->r.cfra = (int)intpart; } -#ifdef WITH_LEGACY_DEPSGRAPH -/* drivers support/hacks - * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render - * - these are always run since the depsgraph can't handle non-object data - * - these happen after objects are all done so that we can read in their final transform values, - * though this means that objects can't refer to scene info for guidance... - */ -static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) -{ - SceneRenderLayer *srl; - float ctime = BKE_scene_frame_get(scene); - - /* scene itself */ - if (scene->adt && scene->adt->drivers.first) { - BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* world */ - /* TODO: what about world textures? but then those have nodes too... */ - if (scene->world) { - ID *wid = (ID *)scene->world; - AnimData *adt = BKE_animdata_from_id(wid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* nodes */ - if (scene->nodetree) { - ID *nid = (ID *)scene->nodetree; - AnimData *adt = BKE_animdata_from_id(nid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* world nodes */ - if (scene->world && scene->world->nodetree) { - ID *nid = (ID *)scene->world->nodetree; - AnimData *adt = BKE_animdata_from_id(nid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* freestyle */ - for (srl = scene->r.layers.first; srl; srl = srl->next) { - FreestyleConfig *config = &srl->freestyleConfig; - FreestyleLineSet *lineset; - - for (lineset = config->linesets.first; lineset; lineset = lineset->next) { - if (lineset->linestyle) { - ID *lid = &lineset->linestyle->id; - AnimData *adt = BKE_animdata_from_id(lid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS); - } - } - } -} - -/* deps hack - do extra recalcs at end */ -static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) -{ - Base *base; - - scene->customdata_mask = scene_parent->customdata_mask; - - /* sets first, we allow per definition current scene to have - * dependencies on sets, but not the other way around. */ - if (scene->set) - scene_depsgraph_hack(eval_ctx, scene->set, scene_parent); - - for (base = scene->base.first; base; base = base->next) { - Object *ob = base->object; - - if (ob->depsflag) { - int recalc = 0; - // printf("depshack %s\n", ob->id.name + 2); - - if (ob->depsflag & OB_DEPS_EXTRA_OB_RECALC) - recalc |= OB_RECALC_OB; - if (ob->depsflag & OB_DEPS_EXTRA_DATA_RECALC) - recalc |= OB_RECALC_DATA; - - ob->recalc |= recalc; - BKE_object_handle_update(eval_ctx, scene_parent, ob); - - if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) { - GroupObject *go; - - for (go = ob->dup_group->gobject.first; go; go = go->next) { - if (go->ob) - go->ob->recalc |= recalc; - } - BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, ob, ob->dup_group); - } - } - } -} -#endif /* WITH_LEGACY_DEPSGRAPH */ - /* 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 @@ -1373,7 +1425,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen static void scene_armature_depsgraph_workaround(Main *bmain) { Object *ob; - if (BLI_listbase_is_empty(&bmain->armature) || !DAG_id_type_tagged(bmain, ID_OB)) { + if (BLI_listbase_is_empty(&bmain->armature) || !DEG_id_type_tagged(bmain, ID_OB)) { return; } for (ob = bmain->object.first; ob; ob = ob->id.next) { @@ -1386,372 +1438,25 @@ static void scene_armature_depsgraph_workaround(Main *bmain) } #endif -#ifdef WITH_LEGACY_DEPSGRAPH -static void scene_rebuild_rbw_recursive(Scene *scene, float ctime) -{ - if (scene->set) - scene_rebuild_rbw_recursive(scene->set, ctime); - - if (BKE_scene_check_rigidbody_active(scene)) - BKE_rigidbody_rebuild_world(scene, ctime); -} - -static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) -{ - if (scene->set) - scene_do_rb_simulation_recursive(scene->set, ctime); - - if (BKE_scene_check_rigidbody_active(scene)) - BKE_rigidbody_do_simulation(scene, ctime); -} -#endif - -/* Used to visualize CPU threads activity during threaded object update, - * would pollute STDERR with whole bunch of timing information which then - * could be parsed and nicely visualized. - */ -#ifdef WITH_LEGACY_DEPSGRAPH -# undef DETAILED_ANALYSIS_OUTPUT -#else -/* ALWAYS KEEY DISABLED! */ -# undef DETAILED_ANALYSIS_OUTPUT -#endif - -/* Mballs evaluation uses BKE_scene_base_iter_next which calls - * duplilist for all objects in the scene. This leads to conflict - * accessing and writing same data from multiple threads. - * - * Ideally Mballs shouldn't do such an iteration and use DAG - * queries instead. For the time being we've got new DAG - * let's keep it simple and update mballs in a single thread. - */ -#define MBALL_SINGLETHREAD_HACK - -#ifdef WITH_LEGACY_DEPSGRAPH -typedef struct StatisicsEntry { - struct StatisicsEntry *next, *prev; - Object *object; - double start_time; - double duration; -} StatisicsEntry; - -typedef struct ThreadedObjectUpdateState { - /* TODO(sergey): We might want this to be per-thread object. */ - EvaluationContext *eval_ctx; - Scene *scene; - Scene *scene_parent; - double base_time; - -#ifdef MBALL_SINGLETHREAD_HACK - bool has_mballs; -#endif - - /* Execution statistics */ - bool has_updated_objects; - ListBase *statistics; -} ThreadedObjectUpdateState; - -static void scene_update_object_add_task(void *node, void *user_data); - -static void scene_update_all_bases(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) -{ - Base *base; - - for (base = scene->base.first; base; base = base->next) { - Object *object = base->object; - - BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, true); - - if (object->dup_group && (object->transflag & OB_DUPLIGROUP)) - BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, object, object->dup_group); - - /* always update layer, so that animating layers works (joshua july 2010) */ - /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes - * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */ - // base->lay = ob->lay; - } -} - -static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid) -{ -/* Disable print for now in favor of summary statistics at the end of update. */ -#define PRINT if (false) printf - - ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool); - void *node = taskdata; - Object *object = DAG_get_node_object(node); - EvaluationContext *eval_ctx = state->eval_ctx; - Scene *scene = state->scene; - Scene *scene_parent = state->scene_parent; - -#ifdef MBALL_SINGLETHREAD_HACK - if (object && object->type == OB_MBALL) { - state->has_mballs = true; - } - else -#endif - if (object) { - double start_time = 0.0; - bool add_to_stats = false; - - if (G.debug & G_DEBUG_DEPSGRAPH) { - if (object->recalc & OB_RECALC_ALL) { - printf("Thread %d: update object %s\n", threadid, object->id.name); - } - - start_time = PIL_check_seconds_timer(); - - if (object->recalc & OB_RECALC_ALL) { - state->has_updated_objects = true; - add_to_stats = true; - } - } - - /* We only update object itself here, dupli-group will be updated - * separately from main thread because of we've got no idea about - * dependencies inside the group. - */ - BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, false); - - /* Calculate statistics. */ - if (add_to_stats) { - StatisicsEntry *entry; - - entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics"); - entry->object = object; - entry->start_time = start_time; - entry->duration = PIL_check_seconds_timer() - start_time; - - BLI_addtail(&state->statistics[threadid], entry); - } - } - else { - PRINT("Threda %d: update node %s\n", threadid, - DAG_get_node_name(scene, node)); - } - - /* Update will decrease child's valency and schedule child with zero valency. */ - DAG_threaded_update_handle_node_updated(node, scene_update_object_add_task, pool); - -#undef PRINT -} - -static void scene_update_object_add_task(void *node, void *user_data) -{ - TaskPool *task_pool = user_data; - - BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW); -} - -static void print_threads_statistics(ThreadedObjectUpdateState *state) -{ - int i, tot_thread; - double finish_time; - - if ((G.debug & G_DEBUG_DEPSGRAPH) == 0) { - return; - } - -#ifdef DETAILED_ANALYSIS_OUTPUT - if (state->has_updated_objects) { - tot_thread = BLI_system_thread_count(); - - fprintf(stderr, "objects update base time %f\n", state->base_time); - - for (i = 0; i < tot_thread; i++) { - StatisicsEntry *entry; - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - fprintf(stderr, "thread %d object %s start_time %f duration %f\n", - i, entry->object->id.name + 2, - entry->start_time, entry->duration); - } - BLI_freelistN(&state->statistics[i]); - } - } -#else - finish_time = PIL_check_seconds_timer(); - tot_thread = BLI_system_thread_count(); - int total_objects = 0; - - for (i = 0; i < tot_thread; i++) { - int thread_total_objects = 0; - double thread_total_time = 0.0; - StatisicsEntry *entry; - - if (state->has_updated_objects) { - /* Don't pollute output if no objects were updated. */ - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - thread_total_objects++; - thread_total_time += entry->duration; - } - - printf("Thread %d: total %d objects in %f sec.\n", - i, - thread_total_objects, - thread_total_time); - - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration); - } - - total_objects += thread_total_objects; - } - - BLI_freelistN(&state->statistics[i]); - } - if (state->has_updated_objects) { - printf("Scene updated %d objects in %f sec\n", - total_objects, - finish_time - state->base_time); - } -#endif -} - -static bool scene_need_update_objects(Main *bmain) -{ - return - /* Object datablocks themselves (for OB_RECALC_OB) */ - DAG_id_type_tagged(bmain, ID_OB) || - - /* Objects data datablocks (for OB_RECALC_DATA) */ - DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */ - DAG_id_type_tagged(bmain, ID_CU) || /* Curve */ - DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */ - DAG_id_type_tagged(bmain, ID_LA) || /* Lamp */ - DAG_id_type_tagged(bmain, ID_LT) || /* Lattice */ - DAG_id_type_tagged(bmain, ID_CA) || /* Camera */ - DAG_id_type_tagged(bmain, ID_KE) || /* KE */ - DAG_id_type_tagged(bmain, ID_SPK) || /* Speaker */ - DAG_id_type_tagged(bmain, ID_AR); /* Armature */ -} - -static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent) -{ - TaskScheduler *task_scheduler; - TaskPool *task_pool; - ThreadedObjectUpdateState state; - bool need_singlethread_pass; - bool need_free_scheduler; - - /* Early check for whether we need to invoke all the task-based - * things (spawn new ppol, traverse dependency graph and so on). - * - * Basically if there's no ID datablocks tagged for update which - * corresponds to object->recalc flags (which are checked in - * BKE_object_handle_update() then we do nothing here. - */ - if (!scene_need_update_objects(bmain)) { - return; - } - - state.eval_ctx = eval_ctx; - state.scene = scene; - state.scene_parent = scene_parent; - - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { - task_scheduler = BLI_task_scheduler_create(1); - need_free_scheduler = true; - } - else { - task_scheduler = BLI_task_scheduler_get(); - need_free_scheduler = false; - } - - /* Those are only needed when blender is run with --debug argument. */ - if (G.debug & G_DEBUG_DEPSGRAPH) { - const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler); - state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics), - "scene update objects stats"); - state.has_updated_objects = false; - state.base_time = PIL_check_seconds_timer(); - } - -#ifdef MBALL_SINGLETHREAD_HACK - state.has_mballs = false; -#endif - - task_pool = BLI_task_pool_create(task_scheduler, &state); - - DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - - if (G.debug & G_DEBUG_DEPSGRAPH) { - print_threads_statistics(&state); - MEM_freeN(state.statistics); - } - - /* We do single thread pass to update all the objects which are in cyclic dependency. - * Such objects can not be handled by a generic DAG traverse and it's really tricky - * to detect whether cycle could be solved or not. - * - * In this situation we simply update all remaining objects in a single thread and - * it'll happen in the same exact order as it was in single-threaded DAG. - * - * We couldn't use threaded update for objects which are in cycle because they might - * access data of each other which is being re-evaluated. - * - * Also, as was explained above, for now we also update all the mballs in single thread. - * - * - sergey - - */ - need_singlethread_pass = DAG_is_acyclic(scene) == false; -#ifdef MBALL_SINGLETHREAD_HACK - need_singlethread_pass |= state.has_mballs; -#endif - - if (need_singlethread_pass) { - scene_update_all_bases(eval_ctx, scene, scene_parent); - } - - if (need_free_scheduler) { - BLI_task_scheduler_free(task_scheduler); - } -} - -static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent) -{ - scene->customdata_mask = scene_parent->customdata_mask; - - /* sets first, we allow per definition current scene to have - * dependencies on sets, but not the other way around. */ - if (scene->set) - scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent); - - /* scene objects */ - scene_update_objects(eval_ctx, bmain, scene, scene_parent); - - /* scene drivers... */ - scene_update_drivers(bmain, scene); - - /* update masking curves */ - BKE_mask_update_scene(bmain, scene); - -} -#endif /* WITH_LEGACY_DEPSGRAPH */ - static bool check_rendered_viewport_visible(Main *bmain) { wmWindowManager *wm = bmain->wm.first; wmWindow *window; for (window = wm->windows.first; window != NULL; window = window->next) { - bScreen *screen = window->screen; + const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + Scene *scene = window->scene; ScrArea *area; + RenderEngineType *type = RE_engines_find(scene->r.engine); + if ((type->draw_engine != NULL) || (type->render_to_view == NULL)) { + continue; + } + const bool use_legacy = (type->flag & RE_USE_LEGACY_PIPELINE) != 0; for (area = screen->areabase.first; area != NULL; area = area->next) { View3D *v3d = area->spacedata.first; if (area->spacetype != SPACE_VIEW3D) { continue; } - if (v3d->drawtype == OB_RENDER) { + if (v3d->drawtype == OB_RENDER || !use_legacy) { return true; } } @@ -1780,7 +1485,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) if (check_rendered_viewport_visible(bmain)) { BMesh *bm = mesh->edit_btmesh->bm; BM_mesh_bm_to_me(bm, mesh, (&(struct BMeshToMeshParams){0})); - DAG_id_tag_update(&mesh->id, 0); + DEG_id_tag_update(&mesh->id, 0); } } } @@ -1789,24 +1494,13 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) { Scene *sce_iter; -#ifdef WITH_LEGACY_DEPSGRAPH - bool use_new_eval = !DEG_depsgraph_use_legacy(); -#endif - - /* keep this first */ - BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE); /* (re-)build dependency graph if needed */ for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) { - DAG_scene_relations_update(bmain, sce_iter); + DEG_scene_relations_update(bmain, sce_iter); /* Uncomment this to check if graph was properly tagged for update. */ #if 0 -#ifdef WITH_LEGACY_DEPSGRAPH - if (use_new_eval) -#endif - { - DAG_scene_relations_validate(bmain, sce_iter); - } + DEG_scene_relations_validate(bmain, sce_iter); #endif } @@ -1814,7 +1508,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc prepare_mesh_for_viewport_render(bmain, scene); /* flush recalc flags to dependencies */ - DAG_ids_flush_tagged(bmain); + DEG_ids_flush_tagged(bmain); /* removed calls to quick_cache, see pointcache.c */ @@ -1829,17 +1523,9 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc * * in the future this should handle updates for all datablocks, not * only objects and scenes. - brecht */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); - } - else -#endif - { - DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); - /* TODO(sergey): This is to beocme a node in new depsgraph. */ - BKE_mask_update_scene(bmain, scene); - } + DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); + /* TODO(sergey): This is to beocme a node in new depsgraph. */ + BKE_mask_update_scene(bmain, scene); /* update sound system animation (TODO, move to depsgraph) */ BKE_sound_update_scene(bmain, scene); @@ -1853,110 +1539,35 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0); } - /* Extra call here to recalc material animation. - * - * Need to do this so changing material settings from the graph/dopesheet - * will update stuff in the viewport. - */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) { - Material *material; - float ctime = BKE_scene_frame_get(scene); - - for (material = bmain->mat.first; - material; - material = material->id.next) - { - AnimData *adt = BKE_animdata_from_id(&material->id); - if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0); - } - } - - /* Also do the same for node trees. */ - if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) { - float ctime = BKE_scene_frame_get(scene); - - FOREACH_NODETREE(bmain, ntree, id) - { - AnimData *adt = BKE_animdata_from_id(&ntree->id); - if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(scene, &ntree->id, adt, ctime, 0); - } - FOREACH_NODETREE_END - } -#endif - - /* notify editors and python about recalc */ - BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST); - /* Inform editors about possible changes. */ - DAG_ids_check_recalc(bmain, scene, false); + DEG_ids_check_recalc(bmain, scene, false); /* clear recalc flags */ - DAG_ids_clear_recalc(bmain); + DEG_ids_clear_recalc(bmain); } /* applies changes right away, does all sets too */ -void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay) -{ - BKE_scene_update_for_newframe_ex(eval_ctx, bmain, sce, lay, false); -} - -void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool do_invisible_flush) +void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce) { float ctime = BKE_scene_frame_get(sce); Scene *sce_iter; -#ifdef DETAILED_ANALYSIS_OUTPUT - double start_time = PIL_check_seconds_timer(); -#endif -#ifdef WITH_LEGACY_DEPSGRAPH - bool use_new_eval = !DEG_depsgraph_use_legacy(); -#else - /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */ - (void) do_invisible_flush; -#endif - DAG_editors_update_pre(bmain, sce, true); + DEG_editors_update_pre(bmain, sce, true); /* keep this first */ BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE); - BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_PRE); /* update animated image textures for particles, modifiers, gpu, etc, * call this at the start so modifiers with textures don't lag 1 frame */ BKE_image_update_frame(bmain, sce->r.cfra); - -#ifdef WITH_LEGACY_DEPSGRAPH - /* rebuild rigid body worlds before doing the actual frame update - * this needs to be done on start frame but animation playback usually starts one frame later - * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive - */ - if (!use_new_eval) { - scene_rebuild_rbw_recursive(sce, ctime); - } -#endif - + BKE_sound_set_cfra(sce->r.cfra); - + /* clear animation overrides */ /* XXX TODO... */ for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set) - DAG_scene_relations_update(bmain, sce_iter); - -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - /* flush recalc flags to dependencies, if we were only changing a frame - * this would not be necessary, but if a user or a script has modified - * some datablock before BKE_scene_update_tagged was called, we need the flush */ - DAG_ids_flush_tagged(bmain); - - /* Following 2 functions are recursive - * so don't call within 'scene_update_tagged_recursive' */ - DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still - } -#endif + DEG_scene_relations_update(bmain, sce_iter); BKE_mask_evaluate_all_masks(bmain, ctime, true); @@ -1967,67 +1578,26 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, scene_armature_depsgraph_workaround(bmain); #endif - /* All 'standard' (i.e. without any dependencies) animation is handled here, - * with an 'local' to 'macro' order of evaluation. This should ensure that - * settings stored nestled within a hierarchy (i.e. settings in a Texture block - * can be overridden by settings from Scene, which owns the Texture through a hierarchy - * such as Scene->World->MTex/Texture) can still get correctly overridden. - */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - BKE_animsys_evaluate_all_animation(bmain, sce, ctime); - /*...done with recursive funcs */ - } -#endif - /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later * when trying to find materials with drivers that need evaluating [#32017] */ BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false); BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false); - /* run rigidbody sim */ - /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_do_rb_simulation_recursive(sce, ctime); - } -#endif - /* BKE_object_handle_update() on all objects, groups and sets */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (use_new_eval) { - DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); - } - else { - scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); - } -#else - DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); -#endif + DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime); /* update sound system animation (TODO, move to depsgraph) */ BKE_sound_update_scene(bmain, sce); -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_depsgraph_hack(eval_ctx, sce, sce); - } -#endif - /* notify editors and python about recalc */ - BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST); BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST); /* Inform editors about possible changes. */ - DAG_ids_check_recalc(bmain, sce, true); + DEG_ids_check_recalc(bmain, sce, true); /* clear recalc flags */ - DAG_ids_clear_recalc(bmain); - -#ifdef DETAILED_ANALYSIS_OUTPUT - fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time); -#endif + DEG_ids_clear_recalc(bmain); } /* return default layer, also used to patch old files */ @@ -2082,15 +1652,7 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer * for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) { - bNode *node; - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { - if (node->custom1 == act) - node->custom1 = 0; - else if (node->custom1 > act) - node->custom1--; - } - } + BKE_nodetree_remove_layer_n(sce->nodetree, scene, act); } } @@ -2177,21 +1739,40 @@ float get_render_aosss_error(const RenderData *r, float error) return error; } -/* helper function for the SETLOOPER macro */ +/** + * Helper function for the SETLOOPER macro + * + * It iterates over the bases of the active layer and then the bases + * of the active layer of the background (set) scenes recursively. + */ Base *_setlooper_base_step(Scene **sce_iter, Base *base) { if (base && base->next) { /* common case, step to the next */ return base->next; } - else if (base == NULL && (*sce_iter)->base.first) { + else if (base == NULL) { /* first time looping, return the scenes first base */ - return (Base *)(*sce_iter)->base.first; + + /* for the first loop we should get the layer from context */ + SceneLayer *sl = BKE_scene_layer_context_active((*sce_iter)); + /* TODO For first scene (non-background set), we should pass the render layer as argument. + * In some cases we want it to be the workspace one, in other the scene one. */ + TODO_LAYER; + + if (sl->object_bases.first) { + return (Base *)sl->object_bases.first; + } + /* no base on this scene layer */ + goto next_set; } else { +next_set: /* reached the end, get the next base in the set */ while ((*sce_iter = (*sce_iter)->set)) { - base = (Base *)(*sce_iter)->base.first; + SceneLayer *sl = BKE_scene_layer_render_active((*sce_iter)); + base = (Base *)sl->object_bases.first; + if (base) { return base; } @@ -2236,23 +1817,60 @@ bool BKE_scene_uses_blender_game(const Scene *scene) return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME); } -void BKE_scene_base_flag_to_objects(struct Scene *scene) +bool BKE_scene_uses_blender_eevee(const Scene *scene) +{ + return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE); +} + +void BKE_scene_base_flag_to_objects(SceneLayer *sl) { - Base *base = scene->base.first; + Base *base = sl->object_bases.first; while (base) { - base->object->flag = base->flag; + BKE_scene_object_base_flag_sync_from_base(base); base = base->next; } } -void BKE_scene_base_flag_from_objects(struct Scene *scene) +void BKE_scene_base_flag_sync_from_base(BaseLegacy *base) { - Base *base = scene->base.first; + BKE_scene_object_base_flag_sync_from_base(base); +} - while (base) { - base->flag = base->object->flag; - base = base->next; +void BKE_scene_base_flag_sync_from_object(BaseLegacy *base) +{ + BKE_scene_object_base_flag_sync_from_object(base); +} + +void BKE_scene_object_base_flag_sync_from_base(Base *base) +{ + Object *ob = base->object; + + /* keep the object only flags untouched */ + int flag = ob->flag & OB_FROMGROUP; + + ob->flag = base->flag; + ob->flag |= flag; + + if ((base->flag & BASE_SELECTED) != 0) { + ob->flag |= SELECT; + } + else { + ob->flag &= ~SELECT; + } +} + +void BKE_scene_object_base_flag_sync_from_object(Base *base) +{ + Object *ob = base->object; + base->flag = ob->flag; + + if ((ob->flag & SELECT) != 0) { + base->flag |= BASE_SELECTED; + BLI_assert((base->flag & BASE_SELECTABLED) != 0); + } + else { + base->flag &= ~BASE_SELECTED; } } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 857bd5447c8..91d675535f3 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -50,8 +50,10 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_screen.h" +#include "BKE_workspace.h" /* ************ Spacetype/regiontype handling ************** */ @@ -180,6 +182,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) BLI_listbase_clear(&newar->panels_category_active); BLI_listbase_clear(&newar->ui_lists); newar->swinid = 0; + newar->manipulator_map = NULL; newar->regiontimer = NULL; /* use optional regiondata callback */ @@ -288,6 +291,17 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID } } + +/** + * Avoid bad-level calls to #WM_manipulatormap_delete. + */ +static void (*region_free_manipulatormap_callback)(struct wmManipulatorMap *) = NULL; + +void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *)) +{ + region_free_manipulatormap_callback = callback; +} + /* not region itself */ void BKE_area_region_free(SpaceType *st, ARegion *ar) { @@ -337,6 +351,8 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) MEM_freeN(uilst->properties); } } + + region_free_manipulatormap_callback(ar->manipulator_map); BLI_freelistN(&ar->ui_lists); BLI_freelistN(&ar->ui_previews); BLI_freelistN(&ar->panels_category); @@ -380,6 +396,8 @@ void BKE_screen_free(bScreen *sc) BLI_freelistN(&sc->vertbase); BLI_freelistN(&sc->edgebase); BLI_freelistN(&sc->areabase); + + BKE_previewimg_free(&sc->preview); } /* for depsgraph */ @@ -579,7 +597,7 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) } } -void BKE_screen_view3d_scene_sync(bScreen *sc) +void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene) { /* are there cameras in the views that are not in the scene? */ ScrArea *sa; @@ -588,55 +606,26 @@ void BKE_screen_view3d_scene_sync(bScreen *sc) for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *) sl; - BKE_screen_view3d_sync(v3d, sc->scene); + BKE_screen_view3d_sync(v3d, scene); } } } } -void BKE_screen_view3d_main_sync(ListBase *screen_lb, Scene *scene) -{ - bScreen *sc; - ScrArea *sa; - SpaceLink *sl; - - /* from scene copy to the other views */ - for (sc = screen_lb->first; sc; sc = sc->id.next) { - if (sc->scene != scene) - continue; - - for (sa = sc->areabase.first; sa; sa = sa->next) - for (sl = sa->spacedata.first; sl; sl = sl->next) - if (sl->spacetype == SPACE_VIEW3D) - BKE_screen_view3d_sync((View3D *)sl, scene); - } -} - -void BKE_screen_view3d_twmode_remove(View3D *v3d, const int i) +void BKE_screen_transform_orientation_remove( + const bScreen *screen, const WorkSpace *workspace, const TransformOrientation *orientation) { - const int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM); - if (selected_index == i) { - v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */ - } - else if (selected_index > i) { - v3d->twmode--; - } -} + const int orientation_index = BKE_workspace_transform_orientation_get_index(workspace, orientation); -void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, Scene *scene, const int i) -{ - bScreen *sc; + for (ScrArea *area = screen->areabase.first; area; area = area->next) { + for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; - for (sc = screen_lb->first; sc; sc = sc->id.next) { - if (sc->scene == scene) { - ScrArea *sa; - for (sa = sc->areabase.first; sa; sa = sa->next) { - SpaceLink *sl; - for (sl = sa->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *)sl; - BKE_screen_view3d_twmode_remove(v3d, i); - } + if (v3d->custom_orientation_index == orientation_index) { + /* could also use orientation_index-- */ + v3d->twmode = V3D_MANIP_GLOBAL; + v3d->custom_orientation_index = -1; } } } @@ -683,3 +672,13 @@ void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings) GPU_fx_compositor_init_ssao_settings(fx_ssao); } } + +bool BKE_screen_is_fullscreen_area(const bScreen *screen) +{ + return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL); +} + +bool BKE_screen_is_used(const bScreen *screen) +{ + return (screen->winid != 0); +} diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 757f639775b..0d7a374a446 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -63,9 +63,9 @@ #include "BLT_translation.h" #include "BKE_animsys.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_sequencer.h" #include "BKE_movieclip.h" @@ -75,6 +75,8 @@ #include "BKE_library.h" #include "BKE_idprop.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "RE_pipeline.h" @@ -3301,10 +3303,10 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq context->scene->r.seq_prev_type = 3 /* == OB_SOLID */; /* opengl offscreen render */ - BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); + BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene); ibuf = sequencer_view3d_cb( /* set for OpenGL render (NULL when scrubbing) */ - scene, camera, width, height, IB_rect, + scene, BKE_scene_layer_render_active(scene), camera, width, height, IB_rect, context->scene->r.seq_prev_type, (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0, use_gpencil, use_background, scene->r.alphamode, @@ -3334,7 +3336,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq if (re == NULL) re = RE_NewRender(scene->id.name); - BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); + BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene); RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false); /* restore previous state after it was toggled on & off by RE_BlenderFrame */ @@ -3394,7 +3396,7 @@ finally: scene->r.subframe = orig_data.subframe; if (is_frame_update) { - BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); + BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene); } #ifdef DURIAN_CAMERA_SWITCH diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index d0ef5cfc092..667f8d1e8c7 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -126,7 +126,7 @@ void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(s void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color), float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {} -struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; } +struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), SceneLayer *UNUSED(sl), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; } float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; } #endif /* WITH_SMOKE */ @@ -693,16 +693,16 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData #ifdef WITH_SMOKE // forward decleration -static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene); +static void smoke_calc_transparency(SmokeDomainSettings *sds, SceneLayer *sl); static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); -static int get_lamp(Scene *scene, float *light) +static int get_lamp(SceneLayer *sl, float *light) { Base *base_tmp = NULL; int found_lamp = 0; // try to find a lamp, preferably local - for (base_tmp = scene->base.first; base_tmp; base_tmp = base_tmp->next) { + for (base_tmp = FIRSTBASE_NEW; base_tmp; base_tmp = base_tmp->next) { if (base_tmp->object->type == OB_LAMP) { Lamp *la = base_tmp->object->data; @@ -2683,7 +2683,7 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) return result; } -static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) +static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm) { if ((smd->type & MOD_SMOKE_TYPE_FLOW)) { @@ -2810,7 +2810,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * } // create shadows before writing cache so they get stored - smoke_calc_transparency(sds, scene); + smoke_calc_transparency(sds, sl); if (sds->wt && sds->total_cells > 1) { smoke_turbulence_step(sds->wt, sds->fluid); @@ -2827,13 +2827,13 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object * } } -struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) +struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, SceneLayer *sl, Object *ob, DerivedMesh *dm) { /* lock so preview render does not read smoke data while it gets modified */ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); - smokeModifier_process(smd, scene, ob, dm); + smokeModifier_process(smd, scene, sl, ob, dm); if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) BLI_rw_mutex_unlock(smd->domain->fluid_mutex); @@ -2948,7 +2948,7 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f cb(result, input, res, pixel, tRay, correct); } -static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene) +static void smoke_calc_transparency(SmokeDomainSettings *sds, SceneLayer *sl) { float bv[6] = {0}; float light[3]; @@ -2956,7 +2956,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene) float *density = smoke_get_density(sds->fluid); float correct = -7.0f * sds->dx; - if (!get_lamp(scene, light)) return; + if (!get_lamp(sl, light)) return; /* convert light pos to sim cell space */ mul_m4_v3(sds->imat, light); diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 600bc3f453d..0b8c11f6dc8 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -512,7 +512,7 @@ static void ccd_build_deflector_hash_single(GHash *hash, Object *ob) /** * \note group overrides scene when not NULL. */ -static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash) +static void ccd_build_deflector_hash(SceneLayer *sl, Group *group, Object *vertexowner, GHash *hash) { Object *ob; @@ -530,10 +530,10 @@ static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexo } } else { - for (Base *base = scene->base.first; base; base = base->next) { + for (Base *base = FIRSTBASE_NEW; base; base = base->next) { /*Only proceed for mesh object in same layer */ - if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { - ob= base->object; + if (base->object->type == OB_MESH) { + ob = base->object; if ((vertexowner) && (ob == vertexowner)) { /* if vertexowner is given we don't want to check collision with owner object */ continue; @@ -558,7 +558,7 @@ static void ccd_update_deflector_hash_single(GHash *hash, Object *ob) /** * \note group overrides scene when not NULL. */ -static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash) +static void ccd_update_deflector_hash(SceneLayer *sl, Group *group, Object *vertexowner, GHash *hash) { Object *ob; @@ -576,10 +576,10 @@ static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertex } } else { - for (Base *base = scene->base.first; base; base = base->next) { + for (Base *base = FIRSTBASE_NEW; base; base = base->next) { /*Only proceed for mesh object in same layer */ - if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { - ob= base->object; + if (base->object->type == OB_MESH) { + ob = base->object; if (ob == vertexowner) { /* if vertexowner is given we don't want to check collision with owner object */ continue; @@ -977,7 +977,7 @@ static void free_softbody_intern(SoftBody *sb) /** * \note group overrides scene when not NULL. */ -static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer) +static bool are_there_deflectors(SceneLayer *sl, Group *group) { if (group) { for (GroupObject *go = group->gobject.first; go; go = go->next) { @@ -986,8 +986,8 @@ static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer) } } else { - for (Base *base = scene->base.first; base; base= base->next) { - if ( (base->lay & layer) && base->object->pd) { + for (Base *base = FIRSTBASE_NEW; base; base = base->next) { + if (base->object->pd) { if (base->object->pd->deflect) return 1; } @@ -997,9 +997,9 @@ static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer) return 0; } -static int query_external_colliders(Scene *scene, Group *group, Object *me) +static int query_external_colliders(SceneLayer *sl, Group *group) { - return(are_there_deflectors(scene, group, me->lay)); + return(are_there_deflectors(sl, group)); } /* --- dependency information functions*/ @@ -2233,7 +2233,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t MEM_freeN(sb_threads); } -static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow) +static void softbody_calc_forcesEx(Scene *scene, SceneLayer *sl, Object *ob, float forcetime, float timenow) { /* rule we never alter free variables :bp->vec bp->pos in here ! * this will ruin adaptive stepsize AKA heun! (BM) @@ -2249,7 +2249,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl /* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */ /* check conditions for various options */ - do_deflector= query_external_colliders(scene, sb->collision_group, ob); + do_deflector= query_external_colliders(sl, sb->collision_group); /* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */ do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -2278,11 +2278,11 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl } -static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow) +static void softbody_calc_forces(Scene *scene, SceneLayer *sl, Object *ob, float forcetime, float timenow) { /* redirection to the new threaded Version */ if (!(G.debug_value & 0x10)) { // 16 - softbody_calc_forcesEx(scene, ob, forcetime, timenow); + softbody_calc_forcesEx(scene, sl, ob, forcetime, timenow); return; } else { @@ -2313,7 +2313,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa } /* check conditions for various options */ - do_deflector= query_external_colliders(scene, sb->collision_group, ob); + do_deflector= query_external_colliders(sl, sb->collision_group); do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -3510,7 +3510,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int } } -static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) +static void softbody_step(Scene *scene, SceneLayer *sl, Object *ob, SoftBody *sb, float dtime) { /* the simulator */ float forcetime; @@ -3524,11 +3524,11 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) */ if (dtime < 0 || dtime > 10.5f) return; - ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash); + ccd_update_deflector_hash(sl, sb->collision_group, ob, sb->scratch->colliderhash); if (sb->scratch->needstobuildcollider) { - if (query_external_colliders(scene, sb->collision_group, ob)) { - ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash); + if (query_external_colliders(sl, sb->collision_group)) { + ccd_build_deflector_hash(sl, sb->collision_group, ob, sb->scratch->colliderhash); } sb->scratch->needstobuildcollider=0; } @@ -3558,12 +3558,12 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) sb->scratch->flag &= ~SBF_DOFUZZY; /* do predictive euler step */ - softbody_calc_forces(scene, ob, forcetime, timedone/dtime); + softbody_calc_forces(scene, sl, ob, forcetime, timedone/dtime); softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags); /* crop new slope values to do averaged slope step */ - softbody_calc_forces(scene, ob, forcetime, timedone/dtime); + softbody_calc_forces(scene, sl, ob, forcetime, timedone/dtime); softbody_apply_forces(ob, forcetime, 2, &err, mid_flags); softbody_apply_goalsnap(ob); @@ -3644,7 +3644,7 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) } /* simulates one step. framenr is in frames */ -void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts) +void sbObjectStep(Scene *scene, SceneLayer *sl, Object *ob, float cfra, float (*vertexCos)[3], int numVerts) { SoftBody *sb= ob->soft; PointCache *cache; @@ -3652,7 +3652,6 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i float dtime, timescale; int framedelta, framenr, startframe, endframe; int cache_result; - cache= sb->pointcache; framenr= (int)cfra; @@ -3721,7 +3720,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i } /* try to read from cache */ - bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED); + bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED); cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate); @@ -3760,7 +3759,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i dtime = framedelta*timescale; /* do simulation */ - softbody_step(scene, ob, sb, dtime); + softbody_step(scene, sl, ob, sb, dtime); softbody_to_object(ob, vertexCos, numVerts, 0); diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index c4665c40ec4..1f72744bdee 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1901,7 +1901,8 @@ static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d) no[1] = b_dZ * a_cX - b_dX * a_cZ; no[2] = b_dX * a_cY - b_dY * a_cX; - /* don't normalize, GL_NORMALIZE is enabled */ + normalize_v3(no); /* we no longer rely on GL_NORMALIZE */ + glNormal3fv(no); } @@ -3409,261 +3410,6 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm, #undef PASSATTRIB } -static void ccgDM_drawFacesTex_common(DerivedMesh *dm, - DMSetDrawOptionsTex drawParams, - DMSetDrawOptionsMappedTex drawParamsMapped, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - int colType; - const MLoopCol *mloopcol = NULL; - MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); - DMFlagMat *faceFlags = ccgdm->faceFlags; - DMDrawOption draw_option; - int i, totpoly; - bool flush; - const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0; - const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0; - unsigned int next_actualFace; - unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1; - int mat_index; - int tot_element, start_element, tot_drawn; - - if (use_colors) { - colType = CD_TEXTURE_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - if (!mloopcol) { - colType = CD_PREVIEW_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - if (!mloopcol) { - colType = CD_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - } - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV); - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) { - return; - } - if (drawParams == NULL) { - ccgSubSurf_drawGLMesh(ss, true, -1, -1); - return; - } - const int level = ccgSubSurf_getSubdivisionLevels(ss); - const int face_side = 1 << level; - const int grid_side = 1 << (level - 1); - const int face_patches = face_side * face_side; - const int grid_patches = grid_side * grid_side; - const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); - int current_patch = 0; - int mat_nr = -1; - int start_draw_patch = 0, num_draw_patches = 0; - bool draw_smooth = false; - for (i = 0; i < num_base_faces; ++i) { - const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); - const int num_patches = (num_face_verts == 4) ? face_patches - : num_face_verts * grid_patches; - if (faceFlags) { - mat_nr = faceFlags[i].mat_nr; - draw_smooth = (faceFlags[i].flag & ME_SMOOTH); - } - else { - mat_nr = 0; - draw_smooth = false; - } - - if (drawParams != NULL) { - MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL; - draw_option = drawParams(tp, (mloopcol != NULL), mat_nr); - } - else { - draw_option = (drawParamsMapped) - ? drawParamsMapped(userData, i, mat_nr) - : DM_DRAW_OPTION_NORMAL; - } - - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1); - - const int next_face = min_ii(i + 1, num_base_faces - 1); - if (!flush && compareDrawOptions) { - flush |= compareDrawOptions(userData, i, next_face) == 0; - } - if (!flush && faceFlags) { - bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH); - flush |= (new_draw_smooth != draw_smooth); - } - - current_patch += num_patches; - - if (flush) { - if (draw_option != DM_DRAW_OPTION_SKIP) { - num_draw_patches += num_patches; - } - if (num_draw_patches != 0) { - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - start_draw_patch = current_patch; - num_draw_patches = 0; - } - else { - num_draw_patches += num_patches; - } - } - glShadeModel(GL_SMOOTH); - return; - } -#endif - - CCG_key_top_level(&key, ss); - ccgdm_pbvh_update(ccgdm); - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - if (flag & DM_DRAW_USE_TEXPAINT_UV) - GPU_texpaint_uv_setup(dm); - else - GPU_uv_setup(dm); - if (mloopcol) { - GPU_color_setup(dm, colType); - } - - next_actualFace = 0; - - /* lastFlag = 0; */ /* UNUSED */ - for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { - GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index; - next_actualFace = bufmat->polys[0]; - totpoly = bufmat->totpolys; - - tot_element = 0; - tot_drawn = 0; - start_element = 0; - - for (i = 0; i < totpoly; i++) { - int polyindex = bufmat->polys[i]; - CCGFace *f = ccgdm->faceMap[polyindex].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - int index = ccgDM_getFaceMapIndex(ss, f); - int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); - int mat_nr; - int facequads = numVerts * gridFaces * gridFaces; - int actualFace = ccgdm->faceMap[polyindex].startFace; - - if (i != totpoly - 1) { - polyindex = bufmat->polys[i + 1]; - next_actualFace = ccgdm->faceMap[polyindex].startFace; - } - - if (faceFlags) { - mat_nr = faceFlags[orig_index].mat_nr; - } - else { - mat_nr = 0; - } - - if (drawParams) { - MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL; - draw_option = drawParams(tp, (mloopcol != NULL), mat_nr); - } - else if (index != ORIGINDEX_NONE) - draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL; - else - draw_option = DM_DRAW_OPTION_NORMAL; - - /* flush buffer if current triangle isn't drawable or it's last triangle */ - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1); - - if (!flush && compareDrawOptions) { - /* also compare draw options and flush buffer if they're different - * need for face selection highlight in edit mode */ - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - tot_element += facequads * 6; - - if (flush) { - if (draw_option != DM_DRAW_OPTION_SKIP) - tot_drawn += facequads * 6; - - if (tot_drawn) { - if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL) - GPU_color_switch(1); - else - GPU_color_switch(0); - - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn); - tot_drawn = 0; - } - - start_element = tot_element; - } - else { - tot_drawn += facequads * 6; - } - } - } - - - GPU_buffers_unbind(); -} - -static void ccgDM_drawFacesTex(DerivedMesh *dm, - DMSetDrawOptionsTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag); -} - -static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, - DMSetDrawOptionsMappedTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); -} - -/* same as cdDM_drawUVEdges */ -static void ccgDM_drawUVEdges(DerivedMesh *dm) -{ - MPoly *mpoly = dm->getPolyArray(dm); - int totpoly = dm->getNumPolys(dm); - int prevstart = 0; - bool prevdraw = true; - int curpos = 0; - int i; - - GPU_uvedge_setup(dm); - for (i = 0; i < totpoly; i++, mpoly++) { - const bool draw = (mpoly->flag & ME_HIDE) == 0; - - if (prevdraw != draw) { - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - prevstart = curpos; - } - - curpos += 2 * mpoly->totloop; - prevdraw = draw; - } - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - GPU_buffers_unbind(); -} - static void ccgDM_drawMappedFaces(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMSetMaterial setMaterial, @@ -4583,13 +4329,10 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) ccgdm->dm.drawEdges = ccgDM_drawEdges; ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges; ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid; - ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex; ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL; ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces; - ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex; ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL; ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat; - ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges; ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp; ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges; @@ -5044,8 +4787,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags) */ return (flags & SUBSURF_USE_GPU_BACKEND) != 0 && - (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) && - (openSubdiv_supportGPUDisplay()); + (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE); #else (void)flags; return false; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 298790a9e9b..9a6db855694 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -58,7 +58,6 @@ #include "DNA_node_types.h" #include "DNA_material_types.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c new file mode 100644 index 00000000000..82fface7d06 --- /dev/null +++ b/source/blender/blenkernel/intern/workspace.c @@ -0,0 +1,432 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/workspace.c + * \ingroup bke + */ + +/* allow accessing private members of DNA_workspace_types.h */ +#define DNA_PRIVATE_WORKSPACE_ALLOW + +#include <stdlib.h> + +#include "BLI_utildefines.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" +#include "BLI_listbase.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_workspace.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_workspace_types.h" + +#include "MEM_guardedalloc.h" + + +/* -------------------------------------------------------------------- */ +/* Internal utils */ + +static void workspace_layout_name_set( + WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name) +{ + BLI_strncpy(layout->name, new_name, sizeof(layout->name)); + BLI_uniquename(&workspace->layouts, layout, "Layout", '.', offsetof(WorkSpaceLayout, name), sizeof(layout->name)); +} + +/** + * This should only be used directly when it is to be expected that there isn't + * a layout within \a workspace that wraps \a screen. Usually - especially outside + * of BKE_workspace - #BKE_workspace_layout_find should be used! + */ +static WorkSpaceLayout *workspace_layout_find_exec( + const WorkSpace *workspace, const bScreen *screen) +{ + return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen)); +} + +static void workspace_relation_add( + ListBase *relation_list, void *parent, void *data) +{ + WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__); + relation->parent = parent; + relation->value = data; + /* add to head, if we switch back to it soon we find it faster. */ + BLI_addhead(relation_list, relation); +} +static void workspace_relation_remove( + ListBase *relation_list, WorkSpaceDataRelation *relation) +{ + BLI_remlink(relation_list, relation); + MEM_freeN(relation); +} + +static void workspace_relation_ensure_updated( + ListBase *relation_list, void *parent, void *data) +{ + WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent)); + if (relation != NULL) { + relation->value = data; + /* reinsert at the head of the list, so that more commonly used relations are found faster. */ + BLI_remlink(relation_list, relation); + BLI_addhead(relation_list, relation); + } + else { + /* no matching relation found, add new one */ + workspace_relation_add(relation_list, parent, data); + } +} + +static void *workspace_relation_get_data_matching_parent( + const ListBase *relation_list, const void *parent) +{ + WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent)); + if (relation != NULL) { + return relation->value; + } + else { + return NULL; + } +} + +/** + * Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple + * WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks. + * Hence, this should only be used as assert check before assigining a screen to a workspace. + */ +#ifndef NDEBUG +static bool workspaces_is_screen_used( +#else +static bool UNUSED_FUNCTION(workspaces_is_screen_used)( +#endif + const Main *bmain, bScreen *screen) +{ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + if (workspace_layout_find_exec(workspace, screen)) { + return true; + } + } + + return false; +} + +/* -------------------------------------------------------------------- */ +/* Create, delete, init */ + +WorkSpace *BKE_workspace_add(Main *bmain, const char *name) +{ + WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name); + return new_workspace; +} + +void BKE_workspace_free(WorkSpace *workspace) +{ + for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next; + relation; + relation = relation_next) + { + relation_next = relation->next; + workspace_relation_remove(&workspace->hook_layout_relations, relation); + } + BLI_freelistN(&workspace->layouts); + BLI_freelistN(&workspace->transform_orientations); +} + +void BKE_workspace_remove(Main *bmain, WorkSpace *workspace) +{ + for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout; layout = layout_next) { + layout_next = layout->next; + BKE_workspace_layout_remove(bmain, workspace, layout); + } + + BKE_libblock_free(bmain, workspace); +} + +WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain) +{ + WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__); + + /* set an active screen-layout for each possible window/workspace combination */ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first); + } + + return hook; +} +void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook) +{ + /* workspaces should never be freed before wm (during which we call this function) */ + BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces)); + + /* Free relations for this hook */ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next; + relation; + relation = relation_next) + { + relation_next = relation->next; + if (relation->parent == hook) { + workspace_relation_remove(&workspace->hook_layout_relations, relation); + } + } + } + + MEM_freeN(hook); +} + +/** + * Add a new layout to \a workspace for \a screen. + */ +WorkSpaceLayout *BKE_workspace_layout_add( + WorkSpace *workspace, + bScreen *screen, + const char *name) +{ + WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__); + + BLI_assert(!workspaces_is_screen_used(G.main, screen)); + layout->screen = screen; + workspace_layout_name_set(workspace, layout, name); + BLI_addtail(&workspace->layouts, layout); + + return layout; +} + +void BKE_workspace_layout_remove( + Main *bmain, + WorkSpace *workspace, WorkSpaceLayout *layout) +{ + BKE_libblock_free(bmain, BKE_workspace_layout_screen_get(layout)); + BLI_freelinkN(&workspace->layouts, layout); +} + +/* -------------------------------------------------------------------- */ +/* General Utils */ + +void BKE_workspace_transform_orientation_remove( + WorkSpace *workspace, TransformOrientation *orientation) +{ + for (WorkSpaceLayout *layout = workspace->layouts.first; layout; layout = layout->next) { + BKE_screen_transform_orientation_remove(BKE_workspace_layout_screen_get(layout), workspace, orientation); + } + + BLI_freelinkN(&workspace->transform_orientations, orientation); +} + +TransformOrientation *BKE_workspace_transform_orientation_find( + const WorkSpace *workspace, const int index) +{ + return BLI_findlink(&workspace->transform_orientations, index); +} + +/** + * \return the index that \a orientation has within \a workspace's transform-orientation list or -1 if not found. + */ +int BKE_workspace_transform_orientation_get_index( + const WorkSpace *workspace, const TransformOrientation *orientation) +{ + return BLI_findindex(&workspace->transform_orientations, orientation); +} + +WorkSpaceLayout *BKE_workspace_layout_find( + const WorkSpace *workspace, const bScreen *screen) +{ + WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen); + if (layout) { + return layout; + } + + printf("%s: Couldn't find layout in this workspace: '%s' screen: '%s'. " + "This should not happen!\n", + __func__, workspace->id.name + 2, screen->id.name + 2); + + return NULL; +} + +/** + * Find the layout for \a screen without knowing which workspace to look in. + * Can also be used to find the workspace that contains \a screen. + * + * \param r_workspace: Optionally return the workspace that contains the looked up layout (if found). + */ +WorkSpaceLayout *BKE_workspace_layout_find_global( + const Main *bmain, const bScreen *screen, + WorkSpace **r_workspace) +{ + WorkSpaceLayout *layout; + + if (r_workspace) { + *r_workspace = NULL; + } + + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + if ((layout = workspace_layout_find_exec(workspace, screen))) { + if (r_workspace) { + *r_workspace = workspace; + } + + return layout; + } + } + + return NULL; +} + +/** + * Circular workspace layout iterator. + * + * \param callback: Custom function which gets executed for each layout. Can return false to stop iterating. + * \param arg: Custom data passed to each \a callback call. + * + * \return the layout at which \a callback returned false. + */ +WorkSpaceLayout *BKE_workspace_layout_iter_circular( + const WorkSpace *workspace, WorkSpaceLayout *start, + bool (*callback)(const WorkSpaceLayout *layout, void *arg), + void *arg, const bool iter_backward) +{ + WorkSpaceLayout *iter_layout; + + if (iter_backward) { + BLI_LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start) + { + if (!callback(iter_layout, arg)) { + return iter_layout; + } + } + BLI_LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start); + } + else { + BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start) + { + if (!callback(iter_layout, arg)) { + return iter_layout; + } + } + BLI_LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start) + } + + return NULL; +} + + +/* -------------------------------------------------------------------- */ +/* Getters/Setters */ + +WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook) +{ + return hook->active; +} +void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) +{ + hook->active = workspace; + if (workspace) { + WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook); + if (layout) { + hook->act_layout = layout; + } + } +} + +WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) +{ + return hook->act_layout; +} +void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout) +{ + hook->act_layout = layout; +} + +bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) +{ + return hook->act_layout->screen; +} +void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace, bScreen *screen) +{ + /* we need to find the WorkspaceLayout that wraps this screen */ + WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen); + BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout); +} + +#ifdef USE_WORKSPACE_MODE +ObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace) +{ + return workspace->object_mode; +} +void BKE_workspace_object_mode_set(WorkSpace *workspace, const ObjectMode mode) +{ + workspace->object_mode = mode; +} +#endif + +ListBase *BKE_workspace_transform_orientations_get(WorkSpace *workspace) +{ + return &workspace->transform_orientations; +} + +SceneLayer *BKE_workspace_render_layer_get(const WorkSpace *workspace) +{ + return workspace->render_layer; +} +void BKE_workspace_render_layer_set(WorkSpace *workspace, SceneLayer *layer) +{ + workspace->render_layer = layer; +} + +ListBase *BKE_workspace_layouts_get(WorkSpace *workspace) +{ + return &workspace->layouts; +} + + +const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout) +{ + return layout->name; +} +void BKE_workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name) +{ + workspace_layout_name_set(workspace, layout, new_name); +} + +bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout) +{ + return layout->screen; +} +void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen) +{ + layout->screen = screen; +} + +WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get( + const WorkSpaceInstanceHook *hook, const WorkSpace *workspace) +{ + return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook); +} +void BKE_workspace_hook_layout_for_workspace_set( + WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout) +{ + hook->act_layout = layout; + workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout); +} |