Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/DerivedMesh.c
| Show First 20 Lines • Show All 1,091 Lines • ▼ Show 20 Lines | static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, | ||||
| /* Some modifiers, like data-transfer, may generate those data as temp layer, | /* Some modifiers, like data-transfer, may generate those data as temp layer, | ||||
| * we do not want to keep them, as they are used by display code when available | * we do not want to keep them, as they are used by display code when available | ||||
| * (i.e. even if autosmooth is disabled). */ | * (i.e. even if autosmooth is disabled). */ | ||||
| if (!do_loop_normals && CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) { | if (!do_loop_normals && CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) { | ||||
| CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop); | CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop); | ||||
| } | } | ||||
| } | } | ||||
| /* Does final touches to the final evaluated mesh, making sure it is perfectly usable. | |||||
| * | |||||
| * This is needed because certain information is not passed along intermediate meshes allocated | |||||
| * during stack evaluation. | |||||
| */ | |||||
| static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval) | |||||
| { | |||||
| /* Make sure the name is the same. This is because mesh allocation from template does not | |||||
| * take care of naming. */ | |||||
| BLI_strncpy(mesh_eval->id.name, mesh_input->id.name, sizeof(mesh_eval->id.name)); | |||||
| /* Make sure materials are preserved from the input. */ | |||||
| if (mesh_eval->mat != NULL) { | |||||
| MEM_freeN(mesh_eval->mat); | |||||
| } | |||||
| mesh_eval->mat = MEM_dupallocN(mesh_input->mat); | |||||
| mesh_eval->totcol = mesh_input->totcol; | |||||
| /* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */ | |||||
| mesh_eval->edit_mesh = mesh_input->edit_mesh; | |||||
| /* Copy auth-smooth settings which are also not taken care about by mesh allocation from a | |||||
| * template. */ | |||||
| mesh_eval->flag |= (mesh_input->flag & ME_AUTOSMOOTH); | |||||
| mesh_eval->smoothresh = mesh_input->smoothresh; | |||||
| } | |||||
| static void mesh_calc_modifiers(struct Depsgraph *depsgraph, | static void mesh_calc_modifiers(struct Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| int useDeform, | int useDeform, | ||||
| const bool need_mapping, | const bool need_mapping, | ||||
| const CustomData_MeshMasks *dataMask, | const CustomData_MeshMasks *dataMask, | ||||
| const int index, | const int index, | ||||
| const bool use_cache, | const bool use_cache, | ||||
| ▲ Show 20 Lines • Show All 401 Lines • ▼ Show 20 Lines | static void mesh_calc_modifiers(struct Depsgraph *depsgraph, | ||||
| for (md = firstmd; md; md = md->next) { | for (md = firstmd; md; md = md->next) { | ||||
| modifier_freeTemporaryData(md); | modifier_freeTemporaryData(md); | ||||
| } | } | ||||
| /* Yay, we are done. If we have a Mesh and deformed vertices | /* Yay, we are done. If we have a Mesh and deformed vertices | ||||
| * need to apply these back onto the Mesh. If we have no | * need to apply these back onto the Mesh. If we have no | ||||
| * Mesh then we need to build one. */ | * Mesh then we need to build one. */ | ||||
| if (mesh_final == NULL) { | if (mesh_final == NULL) { | ||||
| if (deformed_verts == NULL) { | |||||
| mesh_final = mesh_input; | |||||
| } | |||||
| else { | |||||
| mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); | mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); | ||||
| } | } | ||||
| } | |||||
| if (deformed_verts) { | if (deformed_verts) { | ||||
| BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); | BKE_mesh_apply_vert_coords(mesh_final, deformed_verts); | ||||
| MEM_freeN(deformed_verts); | MEM_freeN(deformed_verts); | ||||
| deformed_verts = NULL; | deformed_verts = NULL; | ||||
| } | } | ||||
| /* Denotes whether the object which the modifier stack came from owns the mesh or whether the | |||||
| * mesh is shared across multiple objects since there are no effective modifiers. */ | |||||
| const bool is_own_mesh = (mesh_final != mesh_input); | |||||
| /* Add orco coordinates to final and deformed mesh if requested. */ | /* Add orco coordinates to final and deformed mesh if requested. */ | ||||
| if (dataMask->vmask & CD_MASK_ORCO) { | if (dataMask->vmask & CD_MASK_ORCO) { | ||||
| /* No need in ORCO layer if the mesh was not deformed or modified: undeformed mesh in this case | |||||
| * matches input mesh. */ | |||||
| if (is_own_mesh) { | |||||
| add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO); | add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO); | ||||
| } | |||||
| if (mesh_deform) { | if (mesh_deform) { | ||||
| add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO); | add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO); | ||||
| } | } | ||||
| } | } | ||||
| if (mesh_orco) { | if (mesh_orco) { | ||||
| BKE_id_free(NULL, mesh_orco); | BKE_id_free(NULL, mesh_orco); | ||||
| } | } | ||||
| if (mesh_orco_cloth) { | if (mesh_orco_cloth) { | ||||
| BKE_id_free(NULL, mesh_orco_cloth); | BKE_id_free(NULL, mesh_orco_cloth); | ||||
| } | } | ||||
| /* Compute normals. */ | /* Compute normals. */ | ||||
| if (is_own_mesh) { | |||||
| mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final); | |||||
| } | |||||
| else { | |||||
| Mesh_Runtime *runtime = &mesh_input->runtime; | |||||
| if (runtime->mesh_eval == NULL) { | |||||
| BLI_assert(runtime->eval_mutex != NULL); | |||||
| BLI_mutex_lock(runtime->eval_mutex); | |||||
| if (runtime->mesh_eval == NULL) { | |||||
| mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); | |||||
| mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final); | mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final); | ||||
| mesh_calc_finalize(mesh_input, mesh_final); | |||||
| runtime->mesh_eval = mesh_final; | |||||
| } | |||||
| BLI_mutex_unlock(runtime->eval_mutex); | |||||
| } | |||||
| mesh_final = runtime->mesh_eval; | |||||
| } | |||||
| if (is_own_mesh) { | |||||
| mesh_calc_finalize(mesh_input, mesh_final); | |||||
| } | |||||
mont29: This can be put above (in block defined by lines 1579-1581) I think? ;) | |||||
Done Inline ActionsProbably, but then it's not "Compute normals" anymore. However, the block inside of mutex is already not really just-a-normals =\ sergey: Probably, but then it's not "Compute normals" anymore. However, the block inside of mutex is… | |||||
| /* Return final mesh */ | /* Return final mesh */ | ||||
| *r_final = mesh_final; | *r_final = mesh_final; | ||||
| if (r_deform) { | if (r_deform) { | ||||
| *r_deform = mesh_deform; | *r_deform = mesh_deform; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 359 Lines • ▼ Show 20 Lines | static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, | ||||
| /* Return final mesh. */ | /* Return final mesh. */ | ||||
| *r_final = mesh_final; | *r_final = mesh_final; | ||||
| if (r_cage) { | if (r_cage) { | ||||
| *r_cage = mesh_cage; | *r_cage = mesh_cage; | ||||
| } | } | ||||
| } | } | ||||
| static void mesh_finalize_eval(Object *object) | static void assign_object_mesh_eval(Object *object) | ||||
| { | { | ||||
| BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE); | |||||
| Mesh *mesh = (Mesh *)object->data; | Mesh *mesh = (Mesh *)object->data; | ||||
| Mesh *mesh_eval = object->runtime.mesh_eval; | Mesh *mesh_eval = object->runtime.mesh_eval; | ||||
| /* Special Tweaks for cases when evaluated mesh came from | |||||
| * BKE_mesh_new_nomain_from_template(). | /* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result | ||||
| */ | * is not guaranteed to be owned by object. | ||||
| BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name)); | * | ||||
| if (mesh_eval->mat != NULL) { | * Check ownership now, since later on we can not go to a mesh owned by someone else via object's | ||||
| MEM_freeN(mesh_eval->mat); | * runtime: this could cause access freed data on depsgraph destruction (mesh who owns the final | ||||
| * result might be freed prior to object). */ | |||||
| if (mesh_eval == mesh->runtime.mesh_eval) { | |||||
| object->runtime.is_mesh_eval_owned = false; | |||||
| } | } | ||||
| /* Set flag which makes it easier to see what's going on in a debugger. */ | else { | ||||
| mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT; | mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT; | ||||
| mesh_eval->mat = MEM_dupallocN(mesh->mat); | object->runtime.is_mesh_eval_owned = true; | ||||
| mesh_eval->totcol = mesh->totcol; | } | ||||
| /* Make evaluated mesh to share same edit mesh pointer as original | |||||
| * and copied meshes. | |||||
| */ | |||||
| mesh_eval->edit_mesh = mesh->edit_mesh; | |||||
| /* Copy autosmooth settings from original mesh. | |||||
| * This is not done by BKE_mesh_new_nomain_from_template(), so need to take | |||||
| * extra care here. | |||||
| */ | |||||
| mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH); | |||||
| mesh_eval->smoothresh = mesh->smoothresh; | |||||
| /* Replace evaluated object's data with fully evaluated mesh. */ | |||||
| /* TODO(sergey): There was statement done by Sybren and Mai that this | |||||
| * caused modifiers to be applied twice. which is weirtd and shouldn't | |||||
| * really happen. But since there is no reference to the report, can not | |||||
| * do much about this. | |||||
| */ | |||||
| /* Object is sometimes not evaluated! | /* NOTE: We are not supposed to invoke evaluation for original object, but some areas are still | ||||
| * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */ | * under process of being ported, so we play safe here. */ | ||||
| if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) { | if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) { | ||||
| object->data = mesh_eval; | object->data = mesh_eval; | ||||
| } | } | ||||
| else { | else { | ||||
| /* evaluated will be available via: 'object->runtime.mesh_eval' */ | /* evaluated will be available via: 'object->runtime.mesh_eval' */ | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | #endif | ||||
| BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval); | BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval); | ||||
| /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492) | /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492) | ||||
| * did not re-enable that flag (which always get disabled for eval mesh as a start). */ | * did not re-enable that flag (which always get disabled for eval mesh as a start). */ | ||||
| if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) { | if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) { | ||||
| BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob); | BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob); | ||||
| } | } | ||||
| mesh_finalize_eval(ob); | assign_object_mesh_eval(ob); | ||||
| ob->runtime.last_data_mask = *dataMask; | ob->runtime.last_data_mask = *dataMask; | ||||
| ob->runtime.last_need_mapping = need_mapping; | ob->runtime.last_need_mapping = need_mapping; | ||||
| if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { | if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { | ||||
| /* create PBVH immediately (would be created on the fly too, | /* create PBVH immediately (would be created on the fly too, | ||||
| * but this avoids waiting on first stroke) */ | * but this avoids waiting on first stroke) */ | ||||
| /* XXX Disabled for now. | /* XXX Disabled for now. | ||||
| * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */ | * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */ | ||||
| #if 0 | #if 0 | ||||
| BKE_sculpt_update_mesh_elements( | BKE_sculpt_update_mesh_elements( | ||||
| depsgraph, scene, scene->toolsettings->sculpt, ob, false, false); | depsgraph, scene, scene->toolsettings->sculpt, ob, false, false); | ||||
| #endif | #endif | ||||
| } | } | ||||
| if (ob->runtime.mesh_eval != NULL) { | |||||
| mesh_runtime_check_normals_valid(ob->runtime.mesh_eval); | mesh_runtime_check_normals_valid(ob->runtime.mesh_eval); | ||||
| } | |||||
| mesh_build_extra_data(depsgraph, ob); | mesh_build_extra_data(depsgraph, ob); | ||||
| } | } | ||||
| static void editbmesh_build_data(struct Depsgraph *depsgraph, | static void editbmesh_build_data(struct Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *obedit, | Object *obedit, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| CustomData_MeshMasks *dataMask) | CustomData_MeshMasks *dataMask) | ||||
| ▲ Show 20 Lines • Show All 598 Lines • Show Last 20 Lines | |||||
This can be put above (in block defined by lines 1579-1581) I think? ;)