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/editors/object/object_lattice.c

977 lines
24 KiB
C
Raw Normal View History

/*
* ***** 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,
2010-02-12 13:34:04 +00:00
* 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 *****
*/
2011-02-27 20:29:51 +00:00
/** \file blender/editors/object/object_lattice.c
* \ingroup edobj
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
#include "BLI_bitmap.h"
#include "DNA_curve_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "RNA_access.h"
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_deform.h"
#include "BKE_report.h"
#include "BKE_utildefines.h"
#include "ED_lattice.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
#include "object_intern.h"
/********************** Load/Make/Free ********************/
void free_editLatt(Object *ob)
{
2012-04-28 15:42:27 +00:00
Lattice *lt = ob->data;
if (lt->editlatt) {
2012-04-28 15:42:27 +00:00
Lattice *editlt = lt->editlatt->latt;
if (editlt->def)
MEM_freeN(editlt->def);
if (editlt->dvert)
BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw);
MEM_freeN(editlt);
MEM_freeN(lt->editlatt);
2012-04-28 15:42:27 +00:00
lt->editlatt = NULL;
}
}
void make_editLatt(Object *obedit)
{
2012-04-28 15:42:27 +00:00
Lattice *lt = obedit->data;
KeyBlock *actkey;
free_editLatt(obedit);
actkey = BKE_keyblock_from_object(obedit);
if (actkey)
BKE_key_convert_to_lattice(actkey, lt);
2012-04-28 15:42:27 +00:00
lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt");
lt->editlatt->latt = MEM_dupallocN(lt);
lt->editlatt->latt->def = MEM_dupallocN(lt->def);
if (lt->dvert) {
2012-04-28 15:42:27 +00:00
int tot = lt->pntsu * lt->pntsv * lt->pntsw;
lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot);
}
2012-04-28 15:42:27 +00:00
if (lt->key) lt->editlatt->shapenr = obedit->shapenr;
}
void load_editLatt(Object *obedit)
{
Lattice *lt, *editlt;
KeyBlock *actkey;
BPoint *bp;
float *fp;
int tot;
2012-04-28 15:42:27 +00:00
lt = obedit->data;
editlt = lt->editlatt->latt;
if (lt->editlatt->shapenr) {
2012-04-28 15:42:27 +00:00
actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
/* active key: vertices */
2012-04-28 15:42:27 +00:00
tot = editlt->pntsu * editlt->pntsv * editlt->pntsw;
if (actkey->data) MEM_freeN(actkey->data);
2012-04-28 15:42:27 +00:00
fp = actkey->data = MEM_callocN(lt->key->elemsize * tot, "actkey->data");
actkey->totelem = tot;
2012-04-28 15:42:27 +00:00
bp = editlt->def;
while (tot--) {
copy_v3_v3(fp, bp->vec);
2012-04-28 15:42:27 +00:00
fp += 3;
bp++;
}
}
else {
MEM_freeN(lt->def);
2012-04-28 15:42:27 +00:00
lt->def = MEM_dupallocN(editlt->def);
2012-04-28 15:42:27 +00:00
lt->flag = editlt->flag;
2012-04-28 15:42:27 +00:00
lt->pntsu = editlt->pntsu;
lt->pntsv = editlt->pntsv;
lt->pntsw = editlt->pntsw;
2012-04-28 15:42:27 +00:00
lt->typeu = editlt->typeu;
lt->typev = editlt->typev;
lt->typew = editlt->typew;
lt->actbp = editlt->actbp;
}
if (lt->dvert) {
BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
2012-04-28 15:42:27 +00:00
lt->dvert = NULL;
}
if (editlt->dvert) {
2012-04-28 15:42:27 +00:00
tot = lt->pntsu * lt->pntsv * lt->pntsw;
lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot);
}
}
/*************************** Transform Operator ************************/
void ED_lattice_transform(Lattice *lt, float mat[4][4])
{
BPoint *bp = lt->def;
int a = lt->pntsu * lt->pntsv * lt->pntsw;
while (a--) {
mul_m4_v3(mat, bp->vec);
bp++;
}
DAG_id_tag_update(&lt->id, 0);
}
/************************** Select Random Operator **********************/
static int lattice_select_random_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
int tot;
BPoint *bp;
if (!RNA_boolean_get(op->ptr, "extend")) {
ED_setflagsLatt(obedit, !SELECT);
}
else {
lt->actbp = LT_ACTBP_NONE;
}
tot = lt->pntsu * lt->pntsv * lt->pntsw;
bp = lt->def;
while (tot--) {
if (!bp->hide) {
if (BLI_frand() < randfac) {
bp->f1 |= SELECT;
}
}
bp++;
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
void LATTICE_OT_select_random(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Random";
ot->description = "Randomly select UVW control points";
ot->idname = "LATTICE_OT_select_random";
/* api callbacks */
ot->exec = lattice_select_random_exec;
ot->poll = ED_operator_editlattice;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
"Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
/* -------------------------------------------------------------------- */
/* Select Mirror Operator */
static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
const bool extend = RNA_boolean_get(op->ptr, "extend");
const int axis = RNA_enum_get(op->ptr, "axis");
bool flip_uvw[3] = {false};
int tot, i;
BPoint *bp;
BLI_bitmap *selpoints;
tot = lt->pntsu * lt->pntsv * lt->pntsw;
flip_uvw[axis] = true;
if (!extend) {
lt->actbp = LT_ACTBP_NONE;
}
/* store "original" selection */
selpoints = BLI_BITMAP_NEW(tot, __func__);
BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
/* actual (de)selection */
for (i = 0; i < tot; i++) {
const int i_flip = BKE_lattice_index_flip(lt, i, flip_uvw[0], flip_uvw[1], flip_uvw[2]);
bp = &lt->def[i];
if (!bp->hide) {
if (BLI_BITMAP_GET(selpoints, i_flip)) {
bp->f1 |= SELECT;
}
else {
if (!extend) {
bp->f1 &= ~SELECT;
}
}
}
}
MEM_freeN(selpoints);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
void LATTICE_OT_select_mirror(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Mirror";
ot->description = "Select mirrored lattice points";
ot->idname = "LATTICE_OT_select_mirror";
/* api callbacks */
ot->exec = lattice_select_mirror_exec;
ot->poll = ED_operator_editlattice;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
RNA_def_enum(ot->srna, "axis", object_axis_unsigned_items, 0, "Axis", "");
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
/************************** Select More/Less Operator *************************/
static bool lattice_test_bitmap_uvw(Lattice *lt, BLI_bitmap *selpoints, int u, int v, int w, const bool selected)
{
if ((u < 0 || u >= lt->pntsu) ||
(v < 0 || v >= lt->pntsv) ||
(w < 0 || w >= lt->pntsw))
{
return false;
}
else {
int i = BKE_lattice_index_from_uvw(lt, u, v, w);
if (lt->def[i].hide == 0) {
return (BLI_BITMAP_GET(selpoints, i) != 0) == selected;
}
return false;
}
}
static int lattice_select_more_less(bContext *C, const bool select)
{
Object *obedit = CTX_data_edit_object(C);
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
BPoint *bp;
const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
int u, v, w;
BLI_bitmap *selpoints;
lt->actbp = LT_ACTBP_NONE;
selpoints = BLI_BITMAP_NEW(tot, __func__);
BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
bp = lt->def;
for (w = 0; w < lt->pntsw; w++) {
for (v = 0; v < lt->pntsv; v++) {
for (u = 0; u < lt->pntsu; u++) {
if ((bp->hide == 0) && (((bp->f1 & SELECT) == 0) == select)) {
if (lattice_test_bitmap_uvw(lt, selpoints, u + 1, v, w, select) ||
lattice_test_bitmap_uvw(lt, selpoints, u - 1, v, w, select) ||
lattice_test_bitmap_uvw(lt, selpoints, u, v + 1, w, select) ||
lattice_test_bitmap_uvw(lt, selpoints, u, v - 1, w, select) ||
lattice_test_bitmap_uvw(lt, selpoints, u, v, w + 1, select) ||
lattice_test_bitmap_uvw(lt, selpoints, u, v, w - 1, select))
{
BKE_BIT_TEST_SET(bp->f1, select, SELECT);
}
}
bp++;
}
}
}
MEM_freeN(selpoints);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
static int lattice_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
return lattice_select_more_less(C, true);
}
static int lattice_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
return lattice_select_more_less(C, false);
}
void LATTICE_OT_select_more(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select More";
ot->description = "Select vertex directly linked to already selected ones";
ot->idname = "LATTICE_OT_select_more";
/* api callbacks */
ot->exec = lattice_select_more_exec;
ot->poll = ED_operator_editlattice;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
void LATTICE_OT_select_less(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Less";
ot->description = "Deselect vertices at the boundary of each selection region";
ot->idname = "LATTICE_OT_select_less";
/* api callbacks */
ot->exec = lattice_select_less_exec;
ot->poll = ED_operator_editlattice;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
/************************** Select All Operator *************************/
void ED_setflagsLatt(Object *obedit, int flag)
{
2012-04-28 15:42:27 +00:00
Lattice *lt = obedit->data;
BPoint *bp;
int a;
2012-04-28 15:42:27 +00:00
bp = lt->editlatt->latt->def;
2012-04-28 15:42:27 +00:00
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
lt->editlatt->latt->actbp = LT_ACTBP_NONE;
while (a--) {
2012-04-28 15:42:27 +00:00
if (bp->hide == 0) {
bp->f1 = flag;
}
bp++;
}
}
static int lattice_select_all_exec(bContext *C, wmOperator *op)
{
2012-04-28 15:42:27 +00:00
Object *obedit = CTX_data_edit_object(C);
Lattice *lt = obedit->data;
BPoint *bp;
int a;
int action = RNA_enum_get(op->ptr, "action");
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
2012-04-28 15:42:27 +00:00
bp = lt->editlatt->latt->def;
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
while (a--) {
2012-04-28 15:42:27 +00:00
if (bp->hide == 0) {
2012-07-19 11:40:25 +00:00
if (bp->f1 & SELECT) {
action = SEL_DESELECT;
break;
}
}
bp++;
}
}
switch (action) {
2012-04-28 15:42:27 +00:00
case SEL_SELECT:
ED_setflagsLatt(obedit, 1);
break;
case SEL_DESELECT:
ED_setflagsLatt(obedit, 0);
break;
case SEL_INVERT:
bp = lt->editlatt->latt->def;
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
lt->editlatt->latt->actbp = LT_ACTBP_NONE;
2012-04-28 15:42:27 +00:00
while (a--) {
if (bp->hide == 0) {
2012-07-19 11:40:25 +00:00
bp->f1 ^= SELECT;
2012-04-28 15:42:27 +00:00
}
bp++;
}
2012-04-28 15:42:27 +00:00
break;
}
2012-04-28 15:42:27 +00:00
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
void LATTICE_OT_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "(De)select All";
ot->description = "Change selection of all UVW control points";
ot->idname = "LATTICE_OT_select_all";
/* api callbacks */
ot->exec = lattice_select_all_exec;
ot->poll = ED_operator_editlattice;
/* flags */
2012-04-28 15:42:27 +00:00
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
/************************** Select Ungrouped Verts Operator *************************/
static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
MDeformVert *dv;
BPoint *bp;
int a, tot;
if (obedit->defbase.first == NULL || lt->dvert == NULL) {
BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
return OPERATOR_CANCELLED;
}
if (!RNA_boolean_get(op->ptr, "extend")) {
ED_setflagsLatt(obedit, 0);
}
dv = lt->dvert;
tot = lt->pntsu * lt->pntsv * lt->pntsw;
for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
if (bp->hide == 0) {
if (dv->dw == NULL) {
bp->f1 |= SELECT;
}
}
}
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
void LATTICE_OT_select_ungrouped(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Ungrouped";
ot->idname = "LATTICE_OT_select_ungrouped";
ot->description = "Select vertices without a group";
/* api callbacks */
ot->exec = lattice_select_ungrouped_exec;
ot->poll = ED_operator_editlattice;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
/************************** Make Regular Operator *************************/
static int make_regular_poll(bContext *C)
{
Object *ob;
if (ED_operator_editlattice(C)) return 1;
2012-04-28 15:42:27 +00:00
ob = CTX_data_active_object(C);
return (ob && ob->type == OB_LATTICE);
}
static int make_regular_exec(bContext *C, wmOperator *UNUSED(op))
{
2012-04-28 15:42:27 +00:00
Object *ob = CTX_data_edit_object(C);
Lattice *lt;
if (ob) {
2012-04-28 15:42:27 +00:00
lt = ob->data;
BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
}
else {
2012-04-28 15:42:27 +00:00
ob = CTX_data_active_object(C);
lt = ob->data;
BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2012-04-28 15:42:27 +00:00
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
}
void LATTICE_OT_make_regular(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Make Regular";
ot->description = "Set UVW control points a uniform distance apart";
ot->idname = "LATTICE_OT_make_regular";
/* api callbacks */
ot->exec = make_regular_exec;
ot->poll = make_regular_poll;
/* flags */
2012-04-28 15:42:27 +00:00
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
/************************** Flip Verts Operator *************************/
/* flipping options */
typedef enum eLattice_FlipAxes {
LATTICE_FLIP_U = 0,
LATTICE_FLIP_V = 1,
LATTICE_FLIP_W = 2
} eLattice_FlipAxes;
2013-10-31 14:10:01 +00:00
/* Flip midpoint value so that relative distances between midpoint and neighbor-pair is maintained
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
* ! Assumes that uvw <=> xyz (i.e. axis-aligned index-axes with coordinate-axes)
* - Helper for lattice_flip_exec()
*/
static void lattice_flip_point_value(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
{
BPoint *bp;
float diff;
/* just the point in the middle (unpaired) */
bp = &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
/* flip over axis */
diff = mid - bp->vec[axis];
bp->vec[axis] = mid + diff;
}
/* Swap pairs of lattice points along a specified axis
* - Helper for lattice_flip_exec()
*/
static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid, eLattice_FlipAxes axis)
{
BPoint *bpA, *bpB;
int numU = lt->pntsu;
int numV = lt->pntsv;
int numW = lt->pntsw;
int u0 = u, u1 = u;
int v0 = v, v1 = v;
int w0 = w, w1 = w;
/* get pair index by just overriding the relevant pair-value
* - "-1" else buffer overflow
*/
switch (axis) {
case LATTICE_FLIP_U:
u1 = numU - u - 1;
break;
case LATTICE_FLIP_V:
v1 = numV - v - 1;
break;
case LATTICE_FLIP_W:
w1 = numW - w - 1;
break;
}
/* get points to operate on */
bpA = &lt->def[BKE_lattice_index_from_uvw(lt, u0, v0, w0)];
bpB = &lt->def[BKE_lattice_index_from_uvw(lt, u1, v1, w1)];
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
/* Swap all coordinates, so that flipped coordinates belong to
* the indices on the correct side of the lattice.
*
* Coords: (-2 4) |0| (3 4) --> (3 4) |0| (-2 4)
* Indices: (0,L) (1,R) --> (0,L) (1,R)
*/
swap_v3_v3(bpA->vec, bpB->vec);
/* However, we need to mirror the coordinate values on the axis we're dealing with,
* otherwise we'd have effectively only rotated the points around. If we don't do this,
* we'd just be reimplementing the naive mirroring algorithm, which causes unwanted deforms
* such as flipped normals, etc.
*
* Coords: (3 4) |0| (-2 4) --\
* \-> (-3 4) |0| (2 4)
* Indices: (0,L) (1,R) --> (0,L) (1,R)
*/
lattice_flip_point_value(lt, u0, v0, w0, mid, axis);
lattice_flip_point_value(lt, u1, v1, w1, mid, axis);
}
static int lattice_flip_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Lattice *lt;
eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis");
int numU, numV, numW;
int totP;
float mid = 0.0f;
short isOdd = 0;
/* get lattice - we need the "edit lattice" from the lattice... confusing... */
lt = (Lattice *)obedit->data;
lt = lt->editlatt->latt;
numU = lt->pntsu;
numV = lt->pntsv;
numW = lt->pntsw;
totP = numU * numV * numW;
/* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */
switch (axis) {
case LATTICE_FLIP_U:
isOdd = numU & 1;
break;
case LATTICE_FLIP_V:
isOdd = numV & 1;
break;
case LATTICE_FLIP_W:
isOdd = numW & 1;
break;
default:
printf("lattice_flip(): Unknown flipping axis (%d)\n", axis);
return OPERATOR_CANCELLED;
}
if (isOdd) {
BPoint *bp;
float avgInv = 1.0f / (float)totP;
int i;
/* midpoint calculation - assuming that u/v/w are axis-aligned */
for (i = 0, bp = lt->def; i < totP; i++, bp++) {
mid += bp->vec[axis] * avgInv;
}
}
/* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */
switch (axis) {
case LATTICE_FLIP_U:
{
int u, v, w;
/* v/w strips - front to back, top to bottom */
for (w = 0; w < numW; w++) {
for (v = 0; v < numV; v++) {
/* swap coordinates of pairs of vertices on u */
for (u = 0; u < (numU / 2); u++) {
lattice_swap_point_pairs(lt, u, v, w, mid, axis);
}
/* flip u-coordinate of midpoint (i.e. unpaired point on u) */
if (isOdd) {
u = (numU / 2);
lattice_flip_point_value(lt, u, v, w, mid, axis);
}
}
}
break;
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
}
case LATTICE_FLIP_V:
{
int u, v, w;
/* u/w strips - front to back, left to right */
for (w = 0; w < numW; w++) {
for (u = 0; u < numU; u++) {
/* swap coordinates of pairs of vertices on v */
for (v = 0; v < (numV / 2); v++) {
lattice_swap_point_pairs(lt, u, v, w, mid, axis);
}
/* flip v-coordinate of midpoint (i.e. unpaired point on v) */
if (isOdd) {
v = (numV / 2);
lattice_flip_point_value(lt, u, v, w, mid, axis);
}
}
}
break;
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
}
case LATTICE_FLIP_W:
{
int u, v, w;
for (v = 0; v < numV; v++) {
for (u = 0; u < numU; u++) {
/* swap coordinates of pairs of vertices on w */
for (w = 0; w < (numW / 2); w++) {
lattice_swap_point_pairs(lt, u, v, w, mid, axis);
}
/* flip w-coordinate of midpoint (i.e. unpaired point on w) */
if (isOdd) {
w = (numW / 2);
lattice_flip_point_value(lt, u, v, w, mid, axis);
}
}
}
break;
Lattice Editing: Distortion-Free "Flip" Operator This operator (Ctrl-F) allows you to flip the lattice coordinates without inverting the normals of meshes deformed by the lattice (or the lattice's deformation space for that matter). Unlike the traditional mirror tool, this tool is aware of the fact that the vertex order for lattice control points matters, and that simply mirroring the coordinates will only cause the lattice to have an inverted deform along a particular axis (i.e. it will be scaling by a negative scaling factor along that axis). The problems (as I discovered the other day) with having such an inverted deformation space are that: - the normals of meshes/objects inside that will be incorrect/flipped (and will disappear in GLSL shading mode for instance) - transforming objects deformed by the lattices will become really tricky and counter-intuitive (e.g. rotate in opposite direction by asymmetric amounts to get desired result) - it is not always immediately obvious that problems have occurred Specific use cases this operator is meant to solve: 1) You've created a lattice-based deformer for one cartoonish eye. Now you want to make the second eye, but want to save some time crafting that basic shape again but mirrored. 2) You've got an even more finely crafted setup for stretchy-rigs, and now need to apply it to other parts of the rig. Notes: * I've implemented a separate operator for this vs extending/patching mirror transform tool as it's easier to implement this way, but also because there are still some cases where the old mirroring seems valid (i.e. you explicitly want these sort of distortion effects). * Currently this doesn't take selections into account, as it doesn't seem useful to do so.
2012-10-13 10:42:38 +00:00
}
default: /* shouldn't happen, but just in case */
break;
}
/* updates */
DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
}
void LATTICE_OT_flip(wmOperatorType *ot)
{
static EnumPropertyItem flip_items[] = {
{LATTICE_FLIP_U, "U", 0, "U (X) Axis", ""},
{LATTICE_FLIP_V, "V", 0, "V (Y) Axis", ""},
{LATTICE_FLIP_W, "W", 0, "W (Z) Axis", ""},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
ot->name = "Flip (Distortion Free)";
ot->description = "Mirror all control points without inverting the lattice deform";
ot->idname = "LATTICE_OT_flip";
/* api callbacks */
ot->poll = ED_operator_editlattice;
ot->invoke = WM_menu_invoke;
ot->exec = lattice_flip_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
ot->prop = RNA_def_enum(ot->srna, "axis", flip_items, LATTICE_FLIP_U, "Flip Axis", "Coordinates along this axis get flipped");
}
/****************************** Mouse Selection *************************/
static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const float screen_co[2])
{
struct { BPoint *bp; float dist; int select; float mval_fl[2]; } *data = userData;
float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
if ((bp->f1 & SELECT) && data->select)
dist_test += 5.0f;
if (dist_test < data->dist) {
data->dist = dist_test;
data->bp = bp;
}
}
static BPoint *findnearestLattvert(ViewContext *vc, const int mval[2], int sel)
{
/* (sel == 1): selected gets a disadvantage */
2012-04-28 15:42:27 +00:00
/* in nurb and bezt or bp the nearest is written */
/* return 0 1 2: handlepunt */
struct { BPoint *bp; float dist; int select; float mval_fl[2]; } data = {NULL};
data.dist = 100;
data.select = sel;
data.mval_fl[0] = mval[0];
data.mval_fl[1] = mval[1];
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
lattice_foreachScreenVert(vc, findnearestLattvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
return data.bp;
}
bool mouse_lattice(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
ViewContext vc;
2012-04-28 15:42:27 +00:00
BPoint *bp = NULL;
Lattice *lt;
view3d_set_viewcontext(C, &vc);
lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
bp = findnearestLattvert(&vc, mval, TRUE);
if (bp) {
2012-06-05 21:54:21 +00:00
if (extend) {
bp->f1 |= SELECT;
}
else if (deselect) {
bp->f1 &= ~SELECT;
}
else if (toggle) {
bp->f1 ^= SELECT; /* swap */
}
2012-06-05 21:54:21 +00:00
else {
ED_setflagsLatt(vc.obedit, 0);
bp->f1 |= SELECT;
}
if (bp->f1 & SELECT) {
lt->actbp = bp - lt->def;
}
else {
lt->actbp = LT_ACTBP_NONE;
}
2012-04-28 15:42:27 +00:00
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
return true;
}
return false;
}
/******************************** Undo *************************/
typedef struct UndoLattice {
BPoint *def;
int pntsu, pntsv, pntsw, actbp;
} UndoLattice;
static void undoLatt_to_editLatt(void *data, void *edata, void *UNUSED(obdata))
{
2012-04-28 15:42:27 +00:00
UndoLattice *ult = (UndoLattice *)data;
EditLatt *editlatt = (EditLatt *)edata;
int a = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw;
2012-04-28 15:42:27 +00:00
memcpy(editlatt->latt->def, ult->def, a * sizeof(BPoint));
editlatt->latt->actbp = ult->actbp;
}
static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata))
{
2012-04-28 15:42:27 +00:00
UndoLattice *ult = MEM_callocN(sizeof(UndoLattice), "UndoLattice");
EditLatt *editlatt = (EditLatt *)edata;
2012-04-28 15:42:27 +00:00
ult->def = MEM_dupallocN(editlatt->latt->def);
ult->pntsu = editlatt->latt->pntsu;
ult->pntsv = editlatt->latt->pntsv;
ult->pntsw = editlatt->latt->pntsw;
ult->actbp = editlatt->latt->actbp;
return ult;
}
static void free_undoLatt(void *data)
{
2012-04-28 15:42:27 +00:00
UndoLattice *ult = (UndoLattice *)data;
if (ult->def) MEM_freeN(ult->def);
MEM_freeN(ult);
}
static int validate_undoLatt(void *data, void *edata)
{
2012-04-28 15:42:27 +00:00
UndoLattice *ult = (UndoLattice *)data;
EditLatt *editlatt = (EditLatt *)edata;
return (ult->pntsu == editlatt->latt->pntsu &&
2012-04-28 15:42:27 +00:00
ult->pntsv == editlatt->latt->pntsv &&
ult->pntsw == editlatt->latt->pntsw);
}
static void *get_editlatt(bContext *C)
{
2012-04-28 15:42:27 +00:00
Object *obedit = CTX_data_edit_object(C);
2012-04-28 15:42:27 +00:00
if (obedit && obedit->type == OB_LATTICE) {
Lattice *lt = obedit->data;
return lt->editlatt;
}
return NULL;
}
/* and this is all the undo system needs to know */
void undo_push_lattice(bContext *C, const char *name)
{
undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt);
}