This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/object_update.c
Campbell Barton c8597a465f Object Mode: remove Scene.obedit
Add ED_screen_window_find, BKE_workspace_edit_object
2018-02-13 20:55:12 +11:00

457 lines
14 KiB
C

/*
* ***** 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) 20014 by Blender Foundation.
* All rights reserved.
*
* Contributor(s): Sergey Sharybin.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/object_update.c
* \ingroup bke
*/
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BKE_global.h"
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
#include "BKE_animsys.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_editmesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_image.h"
#include "MEM_guardedalloc.h"
#include "DEG_depsgraph.h"
#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
void BKE_object_eval_local_transform(const EvaluationContext *UNUSED(eval_ctx),
Object *ob)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
/* calculate local matrix */
BKE_object_to_mat4(ob, ob->obmat);
}
/* Evaluate parent */
/* NOTE: based on solve_parenting(), but with the cruft stripped out */
void BKE_object_eval_parent(const EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob)
{
Object *par = ob->parent;
float totmat[4][4];
float tmat[4][4];
float locmat[4][4];
DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
/* get local matrix (but don't calculate it, as that was done already!) */
// XXX: redundant?
copy_m4_m4(locmat, ob->obmat);
/* get parent effect matrix */
BKE_object_get_parent_matrix(scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
mul_m4_m4m4(ob->obmat, tmat, locmat);
/* origin, for help line */
if ((ob->partype & PARTYPE) == PARSKEL) {
copy_v3_v3(ob->orig, par->obmat[3]);
}
else {
copy_v3_v3(ob->orig, totmat[3]);
}
}
void BKE_object_eval_constraints(const EvaluationContext *eval_ctx,
Scene *scene,
Object *ob)
{
bConstraintOb *cob;
float ctime = BKE_scene_frame_get(scene);
DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
/* evaluate constraints stack */
/* TODO: split this into:
* - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e.
* - inner body of BKE_constraints_solve),
* - post (i.e. BKE_constraints_clear_evalob)
*
* Not sure why, this is from Joshua - sergey
*
*/
cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
BKE_constraints_solve(eval_ctx, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
void BKE_object_eval_done(const EvaluationContext *UNUSED(eval_ctx), Object *ob)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
/* Set negative scale flag in object. */
if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
else ob->transflag &= ~OB_NEG_SCALE;
}
void BKE_object_handle_data_update(
const EvaluationContext *eval_ctx,
Scene *scene,
Object *ob)
{
ID *data_id = (ID *)ob->data;
AnimData *adt = BKE_animdata_from_id(data_id);
Key *key;
float ctime = BKE_scene_frame_get(scene);
if (G.debug & G_DEBUG_DEPSGRAPH)
printf("recalcdata %s\n", ob->id.name + 2);
/* TODO(sergey): Only used by legacy depsgraph. */
if (adt) {
/* evaluate drivers - datalevel */
/* XXX: for mesh types, should we push this to derivedmesh instead? */
BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
}
/* TODO(sergey): Only used by legacy depsgraph. */
key = BKE_key_from_object(ob);
if (key && key->block.first) {
if (!(ob->shapeflag & OB_SHAPE_LOCK))
BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
}
/* includes all keys and modifiers */
switch (ob->type) {
case OB_MESH:
{
BMEditMesh *em = (eval_ctx->object_mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
#ifdef WITH_FREESTYLE
/* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
}
#endif
if (em) {
makeDerivedMesh(eval_ctx, scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */
}
else {
makeDerivedMesh(eval_ctx, scene, ob, NULL, data_mask, false);
}
break;
}
case OB_ARMATURE:
if (ID_IS_LINKED(ob) && ob->proxy_from) {
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
ob->id.name + 2, ob->proxy_from->id.name + 2);
}
}
else {
BKE_pose_where_is(eval_ctx, scene, ob);
}
break;
case OB_MBALL:
BKE_displist_make_mball(eval_ctx, scene, ob);
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
BKE_displist_make_curveTypes(eval_ctx, scene, ob, 0);
break;
case OB_LATTICE:
BKE_lattice_modifiers_calc(eval_ctx, scene, ob);
break;
case OB_EMPTY:
if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
if (BKE_image_is_animated(ob->data))
BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
break;
}
/* particles */
if ((ob != OBEDIT_FROM_EVAL_CTX(eval_ctx)) && ob->particlesystem.first) {
ParticleSystem *tpsys, *psys;
DerivedMesh *dm;
ob->transflag &= ~OB_DUPLIPARTS;
psys = ob->particlesystem.first;
while (psys) {
/* ensure this update always happens even if psys is disabled */
if (psys->recalc & PSYS_RECALC_TYPE) {
psys_changed_type(ob, psys);
}
if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) {
/* check use of dupli objects here */
if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
(psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
{
ob->transflag |= OB_DUPLIPARTS;
}
particle_system_update(eval_ctx, scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER));
psys = psys->next;
}
else if (psys->flag & PSYS_DELETE) {
tpsys = psys->next;
BLI_remlink(&ob->particlesystem, psys);
psys_free(ob, psys);
psys = tpsys;
}
else
psys = psys->next;
}
if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
/* this is to make sure we get render level duplis in groups:
* the derivedmesh must be created before init_render_mesh,
* since object_duplilist does dupliparticles before that */
CustomDataMask data_mask = CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL;
dm = mesh_create_derived_render(eval_ctx, scene, ob, data_mask);
dm->release(dm);
for (psys = ob->particlesystem.first; psys; psys = psys->next)
psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
}
}
/* quick cache removed */
}
bool BKE_object_eval_proxy_copy(const EvaluationContext *UNUSED(eval_ctx),
Object *object)
{
/* Handle proxy copy for target, */
if (ID_IS_LINKED(object) && object->proxy_from) {
if (object->proxy_from->proxy_group) {
/* Transform proxy into group space. */
Object *obg = object->proxy_from->proxy_group;
float imat[4][4];
invert_m4_m4(imat, obg->obmat);
mul_m4_m4m4(object->obmat, imat, object->proxy_from->obmat);
/* Should always be true. */
if (obg->dup_group) {
add_v3_v3(object->obmat[3], obg->dup_group->dupli_ofs);
}
}
else {
copy_m4_m4(object->obmat, object->proxy_from->obmat);
}
return true;
}
return false;
}
void BKE_object_eval_uber_transform(const EvaluationContext *eval_ctx, Object *object)
{
BKE_object_eval_proxy_copy(eval_ctx, object);
}
void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx,
Scene *scene,
Object *ob)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
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;
case OB_MBALL:
BKE_mball_batch_cache_dirty(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
break;
}
if (DEG_depsgraph_use_copy_on_write()) {
if (ob->type == OB_MESH) {
/* Quick hack to convert evaluated derivedMesh to Mesh. */
DerivedMesh *dm = ob->derivedFinal;
if (dm != NULL) {
Mesh *mesh = (Mesh *)ob->data;
Mesh *new_mesh = BKE_libblock_alloc_notest(ID_ME);
BKE_mesh_init(new_mesh);
/* Copy ID name so GS(new_mesh->id) works correct later on. */
BLI_strncpy(new_mesh->id.name, mesh->id.name, sizeof(new_mesh->id.name));
/* Copy materials so render engines can access them. */
new_mesh->mat = MEM_dupallocN(mesh->mat);
new_mesh->totcol = mesh->totcol;
DM_to_mesh(dm, new_mesh, ob, CD_MASK_MESH, true);
new_mesh->edit_btmesh = mesh->edit_btmesh;
/* Store result mesh as derived_mesh of object. This way we have
* explicit way to query final object evaluated data and know for sure
* who owns the newly created mesh datablock.
*/
ob->mesh_evaluated = new_mesh;
/* TODO(sergey): This is kind of compatibility thing, so all render
* engines can use object->data for mesh data for display. This is
* something what we might want to change in the future.
*/
ob->data = new_mesh;
/* Special flags to help debugging. */
new_mesh->id.tag |= LIB_TAG_COPY_ON_WRITE_EVAL;
/* Save some memory by throwing DerivedMesh away. */
/* NOTE: Watch out, some tools might need it!
* So keep around for now..
*/
/* Store original ID as a pointer in evaluated ID.
* This way we can restore original object data when we are freeing
* evaluated mesh.
*/
new_mesh->id.orig_id = &mesh->id;
}
#if 0
if (ob->derivedFinal != NULL) {
ob->derivedFinal->needsFree = 1;
ob->derivedFinal->release(ob->derivedFinal);
ob->derivedFinal = NULL;
}
if (ob->derivedDeform != NULL) {
ob->derivedDeform->needsFree = 1;
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform = NULL;
}
#endif
}
}
}
void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *object)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object);
BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
}
void BKE_object_eval_transform_all(const EvaluationContext *eval_ctx,
Scene *scene,
Object *object)
{
/* This mimics full transform update chain from new depsgraph. */
BKE_object_eval_local_transform(eval_ctx, object);
if (object->parent != NULL) {
BKE_object_eval_parent(eval_ctx, scene, object);
}
if (!BLI_listbase_is_empty(&object->constraints)) {
BKE_object_eval_constraints(eval_ctx, scene, object);
}
BKE_object_eval_uber_transform(eval_ctx, object);
BKE_object_eval_done(eval_ctx, object);
}
void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx),
Object *object)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object);
if (object->type == OB_MESH) {
BKE_mesh_batch_cache_dirty(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
}
}
void BKE_object_data_select_update(const EvaluationContext *UNUSED(eval_ctx),
struct ID *object_data)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, object_data->name, object_data);
switch (GS(object_data->name)) {
case ID_ME:
BKE_mesh_batch_cache_dirty((Mesh *)object_data,
BKE_CURVE_BATCH_DIRTY_SELECT);
break;
case ID_CU:
BKE_curve_batch_cache_dirty((Curve *)object_data,
BKE_CURVE_BATCH_DIRTY_SELECT);
break;
case ID_LT:
BKE_lattice_batch_cache_dirty((struct Lattice *)object_data,
BKE_CURVE_BATCH_DIRTY_SELECT);
break;
default:
break;
}
}
void BKE_object_eval_flush_base_flags(const EvaluationContext *UNUSED(eval_ctx),
Object *object, Base *base, bool is_from_set)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object);
/* Make sure we have the base collection settings is already populated.
* This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet.
*
* Which usually means a missing call to DEG_id_tag_update(id, DEG_TAG_BASE_FLAGS_UPDATE).
* Either of the entire scene, or of the newly added objects.*/
BLI_assert(!BLI_listbase_is_empty(&base->collection_properties->data.group));
/* Copy flags and settings from base. */
object->base_flag = base->flag;
if (is_from_set) {
object->base_flag |= BASE_FROM_SET;
object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLED);
}
object->base_collection_properties = base->collection_properties;
}