Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/object.c
| Show First 20 Lines • Show All 357 Lines • ▼ Show 20 Lines | static void object_update_from_subsurf_ccg(Object *object) | ||||
| /* Currently CCG is only created for Mesh objects. */ | /* Currently CCG is only created for Mesh objects. */ | ||||
| if (object->type != OB_MESH) { | if (object->type != OB_MESH) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* If object does not own evaluated mesh we can not access it since it might be freed already | /* If object does not own evaluated mesh we can not access it since it might be freed already | ||||
| * (happens on dependency graph free where order of CoW-ed IDs free is undefined). | * (happens on dependency graph free where order of CoW-ed IDs free is undefined). | ||||
| * | * | ||||
| * Good news is: such mesh does not have modifiers applied, so no need to worry about CCG. */ | * Good news is: such mesh does not have modifiers applied, so no need to worry about CCG. */ | ||||
| if (!object->runtime.is_mesh_eval_owned) { | if (!object->runtime.is_data_eval_owned) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Object was never evaluated, so can not have CCG subdivision surface. */ | /* Object was never evaluated, so can not have CCG subdivision surface. */ | ||||
| Mesh *mesh_eval = object->runtime.mesh_eval; | Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object); | ||||
| if (mesh_eval == NULL) { | if (mesh_eval == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; | SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; | ||||
| if (subdiv_ccg == NULL) { | if (subdiv_ccg == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Check whether there is anything to be reshaped. */ | /* Check whether there is anything to be reshaped. */ | ||||
| Show All 26 Lines | static void object_update_from_subsurf_ccg(Object *object) | ||||
| * current sculpt//evaluated mesh design. This is also how we've survived | * current sculpt//evaluated mesh design. This is also how we've survived | ||||
| * with old DerivedMesh based solutions. So, while this is all wrong and | * with old DerivedMesh based solutions. So, while this is all wrong and | ||||
| * needs reconsideration, doesn't seem to be a big stopper for real | * needs reconsideration, doesn't seem to be a big stopper for real | ||||
| * production artists. | * production artists. | ||||
| */ | */ | ||||
| /* TODO(sergey): Solve this somehow, to be fully stable for threaded | /* TODO(sergey): Solve this somehow, to be fully stable for threaded | ||||
| * evaluation environment. | * evaluation environment. | ||||
| */ | */ | ||||
| /* NOTE: runtime.mesh_orig is what was before assigning mesh_eval, | /* NOTE: runtime.data_orig is what was before assigning mesh_eval, | ||||
| * it is orig as in what was in object_eval->data before evaluating | * it is orig as in what was in object_eval->data before evaluating | ||||
| * modifier stack. | * modifier stack. | ||||
| * | * | ||||
| * mesh_cow is a copy-on-written version od object_orig->data. | * mesh_cow is a copy-on-written version od object_orig->data. | ||||
| */ | */ | ||||
| Mesh *mesh_cow = object->runtime.mesh_orig; | Mesh *mesh_cow = (Mesh *)object->runtime.data_orig; | ||||
| copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS); | copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS); | ||||
| copy_ccg_data(mesh_cow, mesh_orig, CD_GRID_PAINT_MASK); | copy_ccg_data(mesh_cow, mesh_orig, CD_GRID_PAINT_MASK); | ||||
| /* Everything is now up-to-date. */ | /* Everything is now up-to-date. */ | ||||
| subdiv_ccg->dirty.coords = false; | subdiv_ccg->dirty.coords = false; | ||||
| subdiv_ccg->dirty.hidden = false; | subdiv_ccg->dirty.hidden = false; | ||||
| } | } | ||||
| /* Assign data after modifier stack evaluation. */ | |||||
| void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_owned) | |||||
| { | |||||
| BLI_assert(object_eval->id.tag & LIB_TAG_COPIED_ON_WRITE); | |||||
| BLI_assert(object_eval->runtime.data_eval == NULL); | |||||
| BLI_assert(data_eval->tag & LIB_TAG_NO_MAIN); | |||||
| if (is_owned) { | |||||
| /* Set flag for debugging. */ | |||||
| data_eval->tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT; | |||||
| } | |||||
| /* Assigned evaluated data. */ | |||||
| object_eval->runtime.data_eval = data_eval; | |||||
| object_eval->runtime.is_data_eval_owned = is_owned; | |||||
| /* Overwrite data of evaluated object, if the datablock types match. */ | |||||
| ID *data = object_eval->data; | |||||
| if (GS(data->name) == GS(data_eval->name)) { | |||||
| /* NOTE: we are not supposed to invoke evaluation for original objects, | |||||
| * but some areas are still being ported, so we play safe here. */ | |||||
| if (object_eval->id.tag & LIB_TAG_COPIED_ON_WRITE) { | |||||
| object_eval->data = data_eval; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* free data derived from mesh, called when mesh changes or is freed */ | /* free data derived from mesh, called when mesh changes or is freed */ | ||||
| void BKE_object_free_derived_caches(Object *ob) | void BKE_object_free_derived_caches(Object *ob) | ||||
| { | { | ||||
| MEM_SAFE_FREE(ob->runtime.bb); | MEM_SAFE_FREE(ob->runtime.bb); | ||||
| object_update_from_subsurf_ccg(ob); | object_update_from_subsurf_ccg(ob); | ||||
| /* Restore initial pointer. */ | if (ob->runtime.data_eval != NULL) { | ||||
| if (ob->runtime.mesh_orig != NULL) { | if (ob->runtime.is_data_eval_owned) { | ||||
| ob->data = ob->runtime.mesh_orig; | ID *data_eval = ob->runtime.data_eval; | ||||
| if (GS(data_eval->name) == ID_ME) { | |||||
| /* TODO: why exception? */ | |||||
| BKE_mesh_eval_delete((Mesh *)data_eval); | |||||
| } | |||||
| else { | |||||
| BKE_libblock_free_datablock(data_eval, 0); | |||||
| MEM_freeN(data_eval); | |||||
| } | } | ||||
| if (ob->runtime.mesh_eval != NULL) { | |||||
| if (ob->runtime.is_mesh_eval_owned) { | |||||
| Mesh *mesh_eval = ob->runtime.mesh_eval; | |||||
| BKE_mesh_eval_delete(mesh_eval); | |||||
| } | } | ||||
| ob->runtime.mesh_eval = NULL; | ob->runtime.data_eval = NULL; | ||||
| } | } | ||||
| if (ob->runtime.mesh_deform_eval != NULL) { | if (ob->runtime.mesh_deform_eval != NULL) { | ||||
| Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval; | Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval; | ||||
| BKE_mesh_eval_delete(mesh_deform_eval); | BKE_mesh_eval_delete(mesh_deform_eval); | ||||
| ob->runtime.mesh_deform_eval = NULL; | ob->runtime.mesh_deform_eval = NULL; | ||||
| } | } | ||||
| /* Restore initial pointer for copy-on-write datablocks, object->data | |||||
| * might be pointing to an evaluated datablock data was just freed above. */ | |||||
| if (ob->runtime.data_orig != NULL) { | |||||
| ob->data = ob->runtime.data_orig; | |||||
| } | |||||
| BKE_object_to_mesh_clear(ob); | BKE_object_to_mesh_clear(ob); | ||||
| BKE_object_free_curve_cache(ob); | BKE_object_free_curve_cache(ob); | ||||
| /* clear grease pencil data */ | /* clear grease pencil data */ | ||||
| DRW_gpencil_freecache(ob); | DRW_gpencil_freecache(ob); | ||||
| } | } | ||||
| void BKE_object_free_caches(Object *object) | void BKE_object_free_caches(Object *object) | ||||
| ▲ Show 20 Lines • Show All 1,843 Lines • ▼ Show 20 Lines | |||||
| static void give_parvert(Object *par, int nr, float vec[3]) | static void give_parvert(Object *par, int nr, float vec[3]) | ||||
| { | { | ||||
| zero_v3(vec); | zero_v3(vec); | ||||
| if (par->type == OB_MESH) { | if (par->type == OB_MESH) { | ||||
| Mesh *me = par->data; | Mesh *me = par->data; | ||||
| BMEditMesh *em = me->edit_mesh; | BMEditMesh *em = me->edit_mesh; | ||||
| Mesh *me_eval = (em) ? em->mesh_eval_final : par->runtime.mesh_eval; | Mesh *me_eval = (em) ? em->mesh_eval_final : BKE_object_get_evaluated_mesh(par); | ||||
| if (me_eval) { | if (me_eval) { | ||||
| int count = 0; | int count = 0; | ||||
| const int numVerts = me_eval->totvert; | const int numVerts = me_eval->totvert; | ||||
| if (em && me_eval->runtime.is_original) { | if (em && me_eval->runtime.is_original) { | ||||
| if (em->bm->elem_table_dirty & BM_VERT) { | if (em->bm->elem_table_dirty & BM_VERT) { | ||||
| #ifdef VPARENT_THREADING_HACK | #ifdef VPARENT_THREADING_HACK | ||||
| ▲ Show 20 Lines • Show All 742 Lines • ▼ Show 20 Lines | bool BKE_object_minmax_dupli(Depsgraph *depsgraph, | ||||
| return ok; | return ok; | ||||
| } | } | ||||
| void BKE_object_foreach_display_point(Object *ob, | void BKE_object_foreach_display_point(Object *ob, | ||||
| float obmat[4][4], | float obmat[4][4], | ||||
| void (*func_cb)(const float[3], void *), | void (*func_cb)(const float[3], void *), | ||||
| void *user_data) | void *user_data) | ||||
| { | { | ||||
| Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); | |||||
| float co[3]; | float co[3]; | ||||
| if (ob->runtime.mesh_eval) { | if (mesh_eval != NULL) { | ||||
| const Mesh *me = ob->runtime.mesh_eval; | const MVert *mv = mesh_eval->mvert; | ||||
| const MVert *mv = me->mvert; | const int totvert = mesh_eval->totvert; | ||||
| const int totvert = me->totvert; | |||||
| for (int i = 0; i < totvert; i++, mv++) { | for (int i = 0; i < totvert; i++, mv++) { | ||||
| mul_v3_m4v3(co, obmat, mv->co); | mul_v3_m4v3(co, obmat, mv->co); | ||||
| func_cb(co, user_data); | func_cb(co, user_data); | ||||
| } | } | ||||
| } | } | ||||
| else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) { | else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) { | ||||
| DispList *dl; | DispList *dl; | ||||
| ▲ Show 20 Lines • Show All 253 Lines • ▼ Show 20 Lines | case ID_MB: { | ||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| /** Get evaluated mesh for given (main, original) object and depsgraph. */ | /** Get evaluated mesh for given object. */ | ||||
| Mesh *BKE_object_get_evaluated_mesh(const Depsgraph *depsgraph, Object *ob) | Mesh *BKE_object_get_evaluated_mesh(Object *object) | ||||
| { | |||||
| Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); | |||||
| return ob_eval->runtime.mesh_eval; | |||||
| } | |||||
| /* Get object's mesh with all modifiers applied. */ | |||||
| Mesh *BKE_object_get_final_mesh(Object *object) | |||||
| { | { | ||||
| if (object->runtime.mesh_eval != NULL) { | ID *data_eval = object->runtime.data_eval; | ||||
| BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); | return (data_eval && GS(data_eval->name) == ID_ME) ? (Mesh *)data_eval : NULL; | ||||
| BLI_assert(object->runtime.mesh_eval == object->data); | |||||
| BLI_assert((object->runtime.mesh_eval->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) != 0); | |||||
| return object->runtime.mesh_eval; | |||||
| } | |||||
| /* Wasn't evaluated yet. */ | |||||
| return object->data; | |||||
| } | } | ||||
| /* Get mesh which is not affected by modifiers: | /* Get mesh which is not affected by modifiers: | ||||
| * - For original objects it will be same as object->data, and it is a mesh | * - For original objects it will be same as object->data, and it is a mesh | ||||
| * which is in the corresponding bmain. | * which is in the corresponding bmain. | ||||
| * - For copied-on-write objects it will give pointer to a copied-on-write | * - For copied-on-write objects it will give pointer to a copied-on-write | ||||
| * mesh which corresponds to original object's mesh. | * mesh which corresponds to original object's mesh. | ||||
| */ | */ | ||||
| Mesh *BKE_object_get_pre_modified_mesh(Object *object) | Mesh *BKE_object_get_pre_modified_mesh(Object *object) | ||||
| { | { | ||||
| if (object->runtime.mesh_orig != NULL) { | if (object->type == OB_MESH && object->runtime.data_orig != NULL) { | ||||
| BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE); | BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE); | ||||
| BLI_assert(object->id.orig_id != NULL); | BLI_assert(object->id.orig_id != NULL); | ||||
| BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data); | BLI_assert(object->runtime.data_orig->orig_id == ((Object *)object->id.orig_id)->data); | ||||
| Mesh *result = object->runtime.mesh_orig; | Mesh *result = (Mesh *)object->runtime.data_orig; | ||||
| BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); | BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); | ||||
| BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); | BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); | ||||
| return result; | return result; | ||||
| } | } | ||||
| BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0); | BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0); | ||||
| return object->data; | return object->data; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 534 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| memset(&object->runtime, 0, sizeof(object->runtime)); | memset(&object->runtime, 0, sizeof(object->runtime)); | ||||
| } | } | ||||
| /* Reset all pointers which we don't want to be shared when copying the object. */ | /* Reset all pointers which we don't want to be shared when copying the object. */ | ||||
| void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag)) | void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag)) | ||||
| { | { | ||||
| Object_Runtime *runtime = &object->runtime; | Object_Runtime *runtime = &object->runtime; | ||||
| runtime->mesh_eval = NULL; | runtime->data_eval = NULL; | ||||
| runtime->mesh_deform_eval = NULL; | runtime->mesh_deform_eval = NULL; | ||||
| runtime->curve_cache = NULL; | runtime->curve_cache = NULL; | ||||
| runtime->gpencil_cache = NULL; | runtime->gpencil_cache = NULL; | ||||
| } | } | ||||
| /* | /* | ||||
| * Find an associated Armature object | * Find an associated Armature object | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 534 Lines • Show Last 20 Lines | |||||