2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2009-01-13 15:18:41 +00:00
|
|
|
* 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-01-13 15:18:41 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup edobj
|
2011-02-27 20:29:51 +00:00
|
|
|
*/
|
|
|
|
|
2009-01-13 15:18:41 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#ifndef WIN32
|
2019-04-17 06:17:24 +02:00
|
|
|
# include <unistd.h>
|
2009-01-13 15:18:41 +00:00
|
|
|
#else
|
2019-04-17 06:17:24 +02:00
|
|
|
# include <io.h>
|
2018-06-04 09:31:30 +02:00
|
|
|
#endif
|
2009-01-13 15:18:41 +00:00
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2009-01-13 15:18:41 +00:00
|
|
|
|
|
|
|
#include "DNA_key_types.h"
|
|
|
|
#include "DNA_lattice_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
2010-08-04 04:01:27 +00:00
|
|
|
#include "DNA_object_types.h"
|
2009-01-13 15:18:41 +00:00
|
|
|
|
2009-07-01 22:25:49 +00:00
|
|
|
#include "BKE_context.h"
|
2009-01-13 15:18:41 +00:00
|
|
|
#include "BKE_key.h"
|
2018-11-07 18:00:24 +01:00
|
|
|
#include "BKE_lattice.h"
|
2009-01-13 15:18:41 +00:00
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_object.h"
|
|
|
|
|
2017-06-08 10:14:53 +02:00
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
#include "DEG_depsgraph_build.h"
|
|
|
|
|
2020-10-10 18:19:55 +11:00
|
|
|
#include "BLI_sys_types.h" /* for intptr_t support */
|
2009-01-13 15:18:41 +00:00
|
|
|
|
2009-10-16 13:04:59 +00:00
|
|
|
#include "ED_mesh.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "ED_object.h"
|
2009-01-13 15:18:41 +00:00
|
|
|
|
2009-07-01 22:25:49 +00:00
|
|
|
#include "RNA_access.h"
|
2009-10-16 10:29:41 +00:00
|
|
|
#include "RNA_define.h"
|
2009-07-01 22:25:49 +00:00
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
2009-01-13 15:18:41 +00:00
|
|
|
#include "object_intern.h"
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Add Shape Key Function
|
|
|
|
* \{ */
|
2009-07-03 15:23:33 +00:00
|
|
|
|
2015-01-07 02:02:55 +11:00
|
|
|
static void ED_object_shape_key_add(bContext *C, Object *ob, const bool from_mix)
|
2009-07-03 15:23:33 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
KeyBlock *kb;
|
|
|
|
if ((kb = BKE_object_shapekey_insert(bmain, ob, NULL, from_mix))) {
|
|
|
|
Key *key = BKE_key_from_object(ob);
|
|
|
|
/* for absolute shape keys, new keys may not be added last */
|
|
|
|
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
}
|
2009-07-03 15:23:33 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Remove Shape Key Function
|
|
|
|
* \{ */
|
2009-07-03 15:23:33 +00:00
|
|
|
|
2015-06-08 19:49:01 +10:00
|
|
|
static bool object_shapekey_remove(Main *bmain, Object *ob)
|
2013-06-05 06:34:18 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
KeyBlock *kb;
|
|
|
|
Key *key = BKE_key_from_object(ob);
|
2013-06-05 06:34:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (key == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-05 06:34:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
kb = BLI_findlink(&key->block, ob->shapenr - 1);
|
|
|
|
if (kb) {
|
|
|
|
return BKE_object_shapekey_remove(bmain, ob, kb);
|
|
|
|
}
|
2009-07-03 15:23:33 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return false;
|
2009-01-13 15:18:41 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static bool object_shape_key_mirror(
|
|
|
|
bContext *C, Object *ob, int *r_totmirr, int *r_totfail, bool use_topology)
|
2009-10-16 13:04:59 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
KeyBlock *kb;
|
|
|
|
Key *key;
|
|
|
|
int totmirr = 0, totfail = 0;
|
|
|
|
|
|
|
|
*r_totmirr = *r_totfail = 0;
|
|
|
|
|
|
|
|
key = BKE_key_from_object(ob);
|
2019-04-22 09:19:45 +10:00
|
|
|
if (key == NULL) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
kb = BLI_findlink(&key->block, ob->shapenr - 1);
|
|
|
|
|
|
|
|
if (kb) {
|
|
|
|
char *tag_elem = MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror");
|
|
|
|
|
|
|
|
if (ob->type == OB_MESH) {
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
MVert *mv;
|
|
|
|
int i1, i2;
|
|
|
|
float *fp1, *fp2;
|
|
|
|
float tvec[3];
|
|
|
|
|
2020-04-03 21:47:56 +11:00
|
|
|
ED_mesh_mirror_spatial_table_begin(ob, NULL, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) {
|
|
|
|
i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology);
|
|
|
|
if (i2 == i1) {
|
|
|
|
fp1 = ((float *)kb->data) + i1 * 3;
|
|
|
|
fp1[0] = -fp1[0];
|
|
|
|
tag_elem[i1] = 1;
|
|
|
|
totmirr++;
|
|
|
|
}
|
|
|
|
else if (i2 != -1) {
|
|
|
|
if (tag_elem[i1] == 0 && tag_elem[i2] == 0) {
|
|
|
|
fp1 = ((float *)kb->data) + i1 * 3;
|
|
|
|
fp2 = ((float *)kb->data) + i2 * 3;
|
|
|
|
|
|
|
|
copy_v3_v3(tvec, fp1);
|
|
|
|
copy_v3_v3(fp1, fp2);
|
|
|
|
copy_v3_v3(fp2, tvec);
|
|
|
|
|
|
|
|
/* flip x axis */
|
|
|
|
fp1[0] = -fp1[0];
|
|
|
|
fp2[0] = -fp2[0];
|
|
|
|
totmirr++;
|
|
|
|
}
|
|
|
|
tag_elem[i1] = tag_elem[i2] = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
totfail++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 21:47:56 +11:00
|
|
|
ED_mesh_mirror_spatial_table_end(ob);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else if (ob->type == OB_LATTICE) {
|
|
|
|
Lattice *lt = ob->data;
|
|
|
|
int i1, i2;
|
|
|
|
float *fp1, *fp2;
|
|
|
|
int u, v, w;
|
|
|
|
/* half but found up odd value */
|
|
|
|
const int pntsu_half = (lt->pntsu / 2) + (lt->pntsu % 2);
|
|
|
|
|
|
|
|
/* currently editmode isn't supported by mesh so
|
|
|
|
* ignore here for now too */
|
|
|
|
|
|
|
|
/* if (lt->editlatt) lt = lt->editlatt->latt; */
|
|
|
|
|
|
|
|
for (w = 0; w < lt->pntsw; w++) {
|
|
|
|
for (v = 0; v < lt->pntsv; v++) {
|
|
|
|
for (u = 0; u < pntsu_half; u++) {
|
|
|
|
int u_inv = (lt->pntsu - 1) - u;
|
|
|
|
float tvec[3];
|
|
|
|
if (u == u_inv) {
|
|
|
|
i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
|
|
|
|
fp1 = ((float *)kb->data) + i1 * 3;
|
|
|
|
fp1[0] = -fp1[0];
|
|
|
|
totmirr++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
i1 = BKE_lattice_index_from_uvw(lt, u, v, w);
|
|
|
|
i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w);
|
|
|
|
|
|
|
|
fp1 = ((float *)kb->data) + i1 * 3;
|
|
|
|
fp2 = ((float *)kb->data) + i2 * 3;
|
|
|
|
|
|
|
|
copy_v3_v3(tvec, fp1);
|
|
|
|
copy_v3_v3(fp1, fp2);
|
|
|
|
copy_v3_v3(fp2, tvec);
|
|
|
|
fp1[0] = -fp1[0];
|
|
|
|
fp2[0] = -fp2[0];
|
|
|
|
totmirr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(tag_elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
*r_totmirr = totmirr;
|
|
|
|
*r_totfail = totfail;
|
|
|
|
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
|
|
|
|
return 1;
|
2009-10-16 13:04:59 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shared Poll Functions
|
|
|
|
* \{ */
|
2009-07-01 22:25:49 +00:00
|
|
|
|
2020-06-30 17:51:41 +02:00
|
|
|
static bool shape_key_poll(bContext *C)
|
2009-10-22 16:35:51 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
ID *data = (ob) ? ob->data : NULL;
|
2020-06-30 17:51:41 +02:00
|
|
|
|
|
|
|
return (ob != NULL && !ID_IS_LINKED(ob) && !ID_IS_OVERRIDE_LIBRARY(ob) && data != NULL &&
|
|
|
|
!ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data));
|
2009-10-22 16:35:51 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 17:51:41 +02:00
|
|
|
static bool shape_key_mode_poll(bContext *C)
|
2013-10-14 21:03:18 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
2013-10-14 21:03:18 +00:00
|
|
|
|
2020-06-30 17:51:41 +02:00
|
|
|
return (shape_key_poll(C) && ob->mode != OB_MODE_EDIT);
|
2013-10-14 21:03:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-30 17:51:41 +02:00
|
|
|
static bool shape_key_mode_exists_poll(bContext *C)
|
2014-10-21 11:59:14 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
2014-10-21 11:59:14 +02:00
|
|
|
|
2020-06-30 17:51:41 +02:00
|
|
|
return (shape_key_mode_poll(C) &&
|
|
|
|
/* check a keyblock exists */
|
|
|
|
(BKE_keyblock_from_object(ob) != NULL));
|
2014-10-21 11:59:14 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 17:51:41 +02:00
|
|
|
static bool shape_key_move_poll(bContext *C)
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
{
|
2020-06-30 17:51:41 +02:00
|
|
|
/* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
2020-06-30 17:51:41 +02:00
|
|
|
Key *key = BKE_key_from_object(ob);
|
|
|
|
|
|
|
|
return (shape_key_mode_poll(C) && key != NULL && key->totkey > 1);
|
2.5
Notifiers
---------
Various fixes for wrong use of notifiers, and some new notifiers
to make things a bit more clear and consistent, with two notable
changes:
* Geometry changes are now done with NC_GEOM, rather than
NC_OBJECT|ND_GEOM_, so an object does need to be available.
* Space data now use NC_SPACE|ND_SPACE_*, instead of data
notifiers or even NC_WINDOW in some cases. Note that NC_SPACE
should only be used for notifying about changes in space data,
we don't want to go back to allqueue(REDRAW..).
Depsgraph
---------
The dependency graph now has a different flush call:
DAG_object_flush_update(scene, ob, flag)
is replaced by:
DAG_id_flush_update(id, flag)
It still works basically the same, one difference is that it now
also accepts object data (e.g. Mesh), again to avoid requiring an
Object to be available. Other ID types will simply do nothing at
the moment.
Docs
----
I made some guidelines for how/when to do which kinds of updates
and notifiers. I can't specify totally exact how to make these
decisions, but these are basically the guidelines I use. So, new
and updated docs are here:
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/NotifiersUpdates
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/DataNotifiers
2009-09-04 20:51:09 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shape Key Add Operator
|
|
|
|
* \{ */
|
|
|
|
|
2009-07-01 22:25:49 +00:00
|
|
|
static int shape_key_add_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
const bool from_mix = RNA_boolean_get(op->ptr, "from_mix");
|
2009-07-01 22:25:49 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_object_shape_key_add(C, ob, from_mix);
|
2009-12-28 18:03:04 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
|
|
DEG_relations_tag_update(CTX_data_main(C));
|
2015-03-20 15:50:56 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-07-01 22:25:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_shape_key_add(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Add Shape Key";
|
|
|
|
ot->idname = "OBJECT_OT_shape_key_add";
|
|
|
|
ot->description = "Add shape key to the object";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->poll = shape_key_mode_poll;
|
|
|
|
ot->exec = shape_key_add_exec;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_boolean(ot->srna,
|
|
|
|
"from_mix",
|
|
|
|
true,
|
|
|
|
"From Mix",
|
|
|
|
"Create the new shape key from the existing mix of keys");
|
2009-07-01 22:25:49 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shape Key Remove Operator
|
|
|
|
* \{ */
|
|
|
|
|
2013-06-05 06:34:18 +00:00
|
|
|
static int shape_key_remove_exec(bContext *C, wmOperator *op)
|
2009-07-01 22:25:49 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
if (RNA_boolean_get(op->ptr, "all")) {
|
|
|
|
changed = BKE_object_shapekey_free(bmain, ob);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
changed = object_shapekey_remove(bmain, ob);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
|
|
DEG_relations_tag_update(CTX_data_main(C));
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
2020-07-03 15:42:22 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2009-07-01 22:25:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_shape_key_remove(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Remove Shape Key";
|
|
|
|
ot->idname = "OBJECT_OT_shape_key_remove";
|
|
|
|
ot->description = "Remove shape key from the object";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->poll = shape_key_mode_exists_poll;
|
|
|
|
ot->exec = shape_key_remove_exec;
|
2009-07-01 22:25:49 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2013-06-05 06:34:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
|
|
|
RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all shape keys");
|
2009-07-01 22:25:49 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shape Key Clear Operator
|
|
|
|
* \{ */
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-10-16 10:29:41 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
Key *key = BKE_key_from_object(ob);
|
|
|
|
KeyBlock *kb = BKE_keyblock_from_object(ob);
|
2009-10-16 10:29:41 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!key || !kb) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
for (kb = key->block.first; kb; kb = kb->next) {
|
2019-04-17 06:17:24 +02:00
|
|
|
kb->curval = 0.0f;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-10-16 10:29:41 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-10-16 10:29:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_shape_key_clear(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Clear Shape Keys";
|
|
|
|
ot->description = "Clear weights for all shape keys";
|
|
|
|
ot->idname = "OBJECT_OT_shape_key_clear";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->poll = shape_key_poll;
|
|
|
|
ot->exec = shape_key_clear_exec;
|
2009-10-16 10:29:41 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-10-16 10:29:41 +00:00
|
|
|
}
|
|
|
|
|
2012-04-05 06:10:15 +00:00
|
|
|
/* starting point and step size could be optional */
|
|
|
|
static int shape_key_retime_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
Key *key = BKE_key_from_object(ob);
|
|
|
|
KeyBlock *kb = BKE_keyblock_from_object(ob);
|
|
|
|
float cfra = 0.0f;
|
2012-04-05 06:10:15 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!key || !kb) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-04-05 06:10:15 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (kb = key->block.first; kb; kb = kb->next) {
|
|
|
|
kb->pos = cfra;
|
|
|
|
cfra += 0.1f;
|
|
|
|
}
|
2012-04-05 06:10:15 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
2012-04-05 06:10:15 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2012-04-05 06:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_shape_key_retime(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Re-Time Shape Keys";
|
|
|
|
ot->description = "Resets the timing for absolute shape keys";
|
|
|
|
ot->idname = "OBJECT_OT_shape_key_retime";
|
2012-04-05 06:10:15 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->poll = shape_key_poll;
|
|
|
|
ot->exec = shape_key_retime_exec;
|
2012-04-05 06:10:15 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2012-04-05 06:10:15 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shape Key Mirror Operator
|
|
|
|
* \{ */
|
|
|
|
|
2013-06-05 05:58:51 +00:00
|
|
|
static int shape_key_mirror_exec(bContext *C, wmOperator *op)
|
2009-10-16 13:04:59 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
int totmirr = 0, totfail = 0;
|
|
|
|
bool use_topology = RNA_boolean_get(op->ptr, "use_topology");
|
2009-10-16 13:04:59 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!object_shape_key_mirror(C, ob, &totmirr, &totfail, use_topology)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-10-16 13:04:59 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_mesh_report_mirror(op, totmirr, totfail);
|
2013-06-05 05:58:51 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-10-16 13:04:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_shape_key_mirror(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Mirror Shape Key";
|
|
|
|
ot->idname = "OBJECT_OT_shape_key_mirror";
|
|
|
|
ot->description = "Mirror the current shape key along the local X axis";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->poll = shape_key_mode_poll;
|
|
|
|
ot->exec = shape_key_mirror_exec;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_boolean(
|
|
|
|
ot->srna,
|
|
|
|
"use_topology",
|
|
|
|
0,
|
|
|
|
"Topology Mirror",
|
|
|
|
"Use topology based mirroring (for when both sides of mesh have matching, unique topology)");
|
2009-10-16 13:04:59 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:50:38 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shape Key Move (Re-Order) Operator
|
|
|
|
* \{ */
|
|
|
|
|
2014-10-21 11:59:14 +02:00
|
|
|
enum {
|
2019-04-17 06:17:24 +02:00
|
|
|
KB_MOVE_TOP = -2,
|
|
|
|
KB_MOVE_UP = -1,
|
|
|
|
KB_MOVE_DOWN = 1,
|
|
|
|
KB_MOVE_BOTTOM = 2,
|
2014-10-21 11:59:14 +02:00
|
|
|
};
|
|
|
|
|
2009-10-21 14:33:52 +00:00
|
|
|
static int shape_key_move_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
|
|
|
|
Key *key = BKE_key_from_object(ob);
|
|
|
|
const int type = RNA_enum_get(op->ptr, "type");
|
|
|
|
const int totkey = key->totkey;
|
|
|
|
const int act_index = ob->shapenr - 1;
|
|
|
|
int new_index;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case KB_MOVE_TOP:
|
|
|
|
/* Replace the ref key only if we're at the top already (only for relative keys) */
|
|
|
|
new_index = (ELEM(act_index, 0, 1) || key->type == KEY_NORMAL) ? 0 : 1;
|
|
|
|
break;
|
|
|
|
case KB_MOVE_BOTTOM:
|
|
|
|
new_index = totkey - 1;
|
|
|
|
break;
|
|
|
|
case KB_MOVE_UP:
|
|
|
|
case KB_MOVE_DOWN:
|
|
|
|
default:
|
|
|
|
new_index = (totkey + act_index + type) % totkey;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!BKE_keyblock_move(ob, act_index, new_index)) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-10-21 14:33:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OBJECT_OT_shape_key_move(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static const EnumPropertyItem slot_move[] = {
|
|
|
|
{KB_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
|
|
|
|
{KB_MOVE_UP, "UP", 0, "Up", ""},
|
|
|
|
{KB_MOVE_DOWN, "DOWN", 0, "Down", ""},
|
|
|
|
{KB_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
|
|
|
|
{0, NULL, 0, NULL, NULL}};
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Move Shape Key";
|
|
|
|
ot->idname = "OBJECT_OT_shape_key_move";
|
|
|
|
ot->description = "Move the active shape key up/down in the list";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->poll = shape_key_move_poll;
|
|
|
|
ot->exec = shape_key_move_exec;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
|
2009-10-21 14:33:52 +00:00
|
|
|
}
|
2020-09-15 15:50:38 +10:00
|
|
|
|
|
|
|
/** \} */
|