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/python/api2_2x/Key.c
Joseph Eagar 8aa152df93 =Python Bugfix=
The python wrapper code for shape keys was really bad; whoever wrote it
(mis)read the wrong section of blender's codebase and got the totally wrong
idea.  The code was definitely broken to the point where either it had to be
fixed for 2.45, or else the entire keyblock wrapper would have to be removed
from the stable branch.  The fact that it didn't crash is just sheer luck;
the code assume mesh keys were MVerts, when in fact mesh keys are just
arrays of three-float vectors.

So shapekey data can now be editing directly, and is exposed as Mathutils.Vectors.
Also I updated the epydocs to explain how it all works now.
2007-09-08 00:04:32 +00:00

683 lines
20 KiB
C

/*
* $Id$
*
* ***** BEGIN GPL/BL DUAL 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. The Blender
* Foundation also sells licenses for use in proprietary software under
* the Blender License. See http://www.blender.org/BL/ for information
* about this.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* This is a new part of Blender.
*
* Contributor(s): Pontus Lidman, Johnny Matthews, Ken Hughes,
* Michael Reimpell
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#include "Key.h" /*This must come first*/
#include "DNA_scene_types.h"
#include <BLI_blenlib.h>
#include <BKE_global.h>
#include <BKE_main.h>
#include <BKE_curve.h>
#include <BKE_library.h>
#include "BIF_space.h"
#include "Ipocurve.h"
#include "NMesh.h" /* we create NMesh.NMVert objects */
#include "Ipo.h"
#include "BezTriple.h"
#include "BSE_editipo.h"
#include "mydevice.h"
#include "BKE_depsgraph.h"
#include "blendef.h"
#include "constant.h"
#include "gen_utils.h"
#include "gen_library.h"
#define KEY_TYPE_MESH 0
#define KEY_TYPE_CURVE 1
#define KEY_TYPE_LATTICE 2
/* macro from blenkernel/intern/key.c:98 */
#define GS(a) (*((short *)(a)))
static int Key_compare( BPy_Key * a, BPy_Key * b );
static PyObject *Key_repr( BPy_Key * self );
static void Key_dealloc( BPy_Key * self );
static PyObject *Key_getBlocks( BPy_Key * self );
static PyObject *Key_getType( BPy_Key * self );
static PyObject *Key_getRelative( BPy_Key * self );
static PyObject *Key_getIpo( BPy_Key * self );
static int Key_setIpo( BPy_Key * self, PyObject * args );
static PyObject *Key_getValue( BPy_Key * self );
static int Key_setRelative( BPy_Key * self, PyObject * value );
static struct PyMethodDef Key_methods[] = {
{ "getBlocks", (PyCFunction) Key_getBlocks, METH_NOARGS, "Get key blocks" },
{ "getIpo", (PyCFunction) Key_getIpo, METH_NOARGS, "Get key Ipo" },
{ 0, 0, 0, 0 }
};
static PyGetSetDef BPy_Key_getsetters[] = {
{"type",(getter)Key_getType, (setter)NULL,
"Key Type",NULL},
{"value",(getter)Key_getValue, (setter)NULL,
"Key value",NULL},
{"ipo",(getter)Key_getIpo, (setter)Key_setIpo,
"Ipo linked to key",NULL},
{"blocks",(getter)Key_getBlocks, (setter)NULL,
"Blocks linked to the key",NULL},
{"relative",(getter)Key_getRelative, (setter)Key_setRelative,
"Non-zero is key is relative",NULL},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
static PyObject *KeyBlock_getData( PyObject * self );
static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self );
static PyObject *KeyBlock_getName( BPy_KeyBlock * self );
static PyObject *KeyBlock_getPos( BPy_KeyBlock * self );
static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self );
static PyObject *KeyBlock_getSlidermax( BPy_KeyBlock * self );
static PyObject *KeyBlock_getVgroup( BPy_KeyBlock * self );
static int KeyBlock_setName( BPy_KeyBlock *, PyObject * args );
static int KeyBlock_setVgroup( BPy_KeyBlock *, PyObject * args );
static int KeyBlock_setSlidermin( BPy_KeyBlock *, PyObject * args );
static int KeyBlock_setSlidermax( BPy_KeyBlock *, PyObject * args );
static void KeyBlock_dealloc( BPy_KeyBlock * self );
static int KeyBlock_compare( BPy_KeyBlock * a, BPy_KeyBlock * b );
static PyObject *KeyBlock_repr( BPy_KeyBlock * self );
static struct PyMethodDef KeyBlock_methods[] = {
{ "getData", (PyCFunction) KeyBlock_getData, METH_NOARGS,
"Get keyblock data" },
{ 0, 0, 0, 0 }
};
static PyGetSetDef BPy_KeyBlock_getsetters[] = {
{"curval",(getter)KeyBlock_getCurval, (setter)NULL,
"Current value of the corresponding IpoCurve",NULL},
{"name",(getter)KeyBlock_getName, (setter)KeyBlock_setName,
"Keyblock Name",NULL},
{"pos",(getter)KeyBlock_getPos, (setter)NULL,
"Keyblock Pos",NULL},
{"slidermin",(getter)KeyBlock_getSlidermin, (setter)KeyBlock_setSlidermin,
"Keyblock Slider Minimum",NULL},
{"slidermax",(getter)KeyBlock_getSlidermax, (setter)KeyBlock_setSlidermax,
"Keyblock Slider Maximum",NULL},
{"vgroup",(getter)KeyBlock_getVgroup, (setter)KeyBlock_setVgroup,
"Keyblock VGroup",NULL},
{"data",(getter)KeyBlock_getData, (setter)NULL,
"Keyblock VGroup",NULL},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
PyTypeObject Key_Type = {
PyObject_HEAD_INIT( NULL ) 0, /*ob_size */
"Blender Key", /*tp_name */
sizeof( BPy_Key ), /*tp_basicsize */
0, /*tp_itemsize */
/* methods */
( destructor ) Key_dealloc,/* destructor tp_dealloc; */
( printfunc ) 0, /*tp_print */
( getattrfunc ) 0, /*tp_getattr */
( setattrfunc ) 0, /*tp_setattr */
( cmpfunc) Key_compare, /*tp_compare*/
( reprfunc ) Key_repr, /* tp_repr */
/* Method suites for standard classes */
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
NULL, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
NULL, /* ternaryfunc tp_call; */
NULL, /* reprfunc tp_str; */
NULL, /* getattrofunc tp_getattro; */
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT, /* long tp_flags; */
NULL, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
/* call function for all accessible objects */
NULL, /* traverseproc tp_traverse; */
/* delete references to contained objects */
NULL, /* inquiry tp_clear; */
/*** Assigned meaning in release 2.1 ***/
/*** rich comparisons ***/
NULL, /* richcmpfunc tp_richcompare; */
/*** weak reference enabler ***/
0, /* long tp_weaklistoffset; */
/*** Added in release 2.2 ***/
/* Iterators */
NULL, /* getiterfunc tp_iter; */
NULL, /* iternextfunc tp_iternext; */
/*** Attribute descriptor and subclassing stuff ***/
Key_methods, /* struct PyMethodDef *tp_methods; */
NULL, /* struct PyMemberDef *tp_members; */
BPy_Key_getsetters, /* struct PyGetSetDef *tp_getset; */
NULL, /* struct _typeobject *tp_base; */
NULL, /* PyObject *tp_dict; */
NULL, /* descrgetfunc tp_descr_get; */
NULL, /* descrsetfunc tp_descr_set; */
0, /* long tp_dictoffset; */
NULL, /* initproc tp_init; */
NULL, /* allocfunc tp_alloc; */
NULL, /* newfunc tp_new; */
/* Low-level free-memory routine */
NULL, /* freefunc tp_free; */
/* For PyObject_IS_GC */
NULL, /* inquiry tp_is_gc; */
NULL, /* PyObject *tp_bases; */
/* method resolution order */
NULL, /* PyObject *tp_mro; */
NULL, /* PyObject *tp_cache; */
NULL, /* PyObject *tp_subclasses; */
NULL, /* PyObject *tp_weaklist; */
NULL
};
PyTypeObject KeyBlock_Type = {
PyObject_HEAD_INIT( NULL ) 0, /*ob_size */
"Blender KeyBlock", /*tp_name */
sizeof( BPy_KeyBlock ), /*tp_basicsize */
0, /*tp_itemsize */
/* methods */
( destructor ) KeyBlock_dealloc,/* destructor tp_dealloc; */
( printfunc ) 0, /*tp_print */
( getattrfunc ) 0, /*tp_getattr */
( setattrfunc ) 0, /*tp_setattr */
( cmpfunc) KeyBlock_compare, /*tp_compare*/
( reprfunc ) KeyBlock_repr, /* tp_repr */
/* Method suites for standard classes */
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
NULL, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
NULL, /* hashfunc tp_hash; */
NULL, /* ternaryfunc tp_call; */
NULL, /* reprfunc tp_str; */
NULL, /* getattrofunc tp_getattro; */
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT, /* long tp_flags; */
NULL, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
/* call function for all accessible objects */
NULL, /* traverseproc tp_traverse; */
/* delete references to contained objects */
NULL, /* inquiry tp_clear; */
/*** Assigned meaning in release 2.1 ***/
/*** rich comparisons ***/
NULL, /* richcmpfunc tp_richcompare; */
/*** weak reference enabler ***/
0, /* long tp_weaklistoffset; */
/*** Added in release 2.2 ***/
/* Iterators */
NULL, /* getiterfunc tp_iter; */
NULL, /* iternextfunc tp_iternext; */
/*** Attribute descriptor and subclassing stuff ***/
KeyBlock_methods, /* struct PyMethodDef *tp_methods; */
NULL, /* struct PyMemberDef *tp_members; */
BPy_KeyBlock_getsetters, /* struct PyGetSetDef *tp_getset; */
NULL, /* struct _typeobject *tp_base; */
NULL, /* PyObject *tp_dict; */
NULL, /* descrgetfunc tp_descr_get; */
NULL, /* descrsetfunc tp_descr_set; */
0, /* long tp_dictoffset; */
NULL, /* initproc tp_init; */
NULL, /* allocfunc tp_alloc; */
NULL, /* newfunc tp_new; */
/* Low-level free-memory routine */
NULL, /* freefunc tp_free; */
/* For PyObject_IS_GC */
NULL, /* inquiry tp_is_gc; */
NULL, /* PyObject *tp_bases; */
/* method resolution order */
NULL, /* PyObject *tp_mro; */
NULL, /* PyObject *tp_cache; */
NULL, /* PyObject *tp_subclasses; */
NULL, /* PyObject *tp_weaklist; */
NULL
};
PyObject *Key_CreatePyObject( Key * blenkey )
{
BPy_Key *bpykey = PyObject_NEW( BPy_Key, &Key_Type );
/* blenkey may be NULL so be careful */
bpykey->key = blenkey;
return ( PyObject * ) bpykey;
}
static void Key_dealloc( BPy_Key * self )
{
PyObject_DEL( self );
}
static int Key_compare( BPy_Key * a, BPy_Key * b )
{
return ( a->key == b->key ) ? 0 : -1;
}
static PyObject *Key_repr( BPy_Key * self )
{
return PyString_FromFormat( "[Key \"%s\"]", self->key->id.name + 2 );
}
static PyObject *Key_getIpo( BPy_Key * self )
{
if (self->key->ipo)
return Ipo_CreatePyObject( self->key->ipo );
Py_RETURN_NONE;
}
static int Key_setIpo( BPy_Key * self, PyObject * value )
{
return GenericLib_assignData(value, (void **) &self->key->ipo, 0, 1, ID_IP, ID_KE);
}
static PyObject *Key_getRelative( BPy_Key * self )
{
if( self->key->type == KEY_RELATIVE )
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
static int Key_setRelative( BPy_Key * self, PyObject * value )
{
int param = PyObject_IsTrue( value );
if( param == -1 )
return EXPP_ReturnIntError( PyExc_TypeError,
"expected True/False or 0/1" );
if( param )
self->key->type = KEY_RELATIVE;
else
self->key->type = KEY_NORMAL;
allqueue(REDRAWIPO, 0);
allspace(REMAKEIPO, 0);
return 0;
}
static PyObject *Key_getType( BPy_Key * self )
{
int idcode;
int type = -1;
idcode = GS( self->key->from->name );
switch( idcode ) {
case ID_ME:
type = KEY_TYPE_MESH;
break;
case ID_CU:
type = KEY_TYPE_CURVE;
break;
case ID_LT:
type = KEY_TYPE_LATTICE;
break;
}
return PyInt_FromLong( type );
}
static PyObject *Key_getBlocks( BPy_Key * self )
{
Key *key = self->key;
KeyBlock *kb;
int i=0;
PyObject *l = PyList_New( BLI_countlist( &(key->block)) );
for (kb = key->block.first; kb; kb = kb->next, i++)
PyList_SET_ITEM( l, i, KeyBlock_CreatePyObject( kb, key ) );
return l;
}
static PyObject *Key_getValue( BPy_Key * self )
{
BPy_Key *k = ( BPy_Key * ) self;
return PyFloat_FromDouble( k->key->curval );
}
/* ------------ Key Block Functions -------------- */
PyObject *KeyBlock_CreatePyObject( KeyBlock * keyblock, Key *parentKey )
{
BPy_KeyBlock *bpykb = PyObject_NEW( BPy_KeyBlock, &KeyBlock_Type );
bpykb->key = parentKey;
bpykb->keyblock = keyblock; /* keyblock maye be NULL, thats ok */
return ( PyObject * ) bpykb;
}
static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self ) {
return PyFloat_FromDouble( self->keyblock->curval );
}
static PyObject *KeyBlock_getName( BPy_KeyBlock * self ) {
return PyString_FromString(self->keyblock->name);
}
static PyObject *KeyBlock_getPos( BPy_KeyBlock * self ){
return PyFloat_FromDouble( self->keyblock->pos );
}
static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self ){
return PyFloat_FromDouble( self->keyblock->slidermin );
}
static PyObject *KeyBlock_getSlidermax( BPy_KeyBlock * self ){
return PyFloat_FromDouble( self->keyblock->slidermax );
}
static PyObject *KeyBlock_getVgroup( BPy_KeyBlock * self ){
return PyString_FromString(self->keyblock->vgroup);
}
static int KeyBlock_setName( BPy_KeyBlock * self, PyObject * args ){
char* text = NULL;
text = PyString_AsString ( args );
if( !text )
return EXPP_ReturnIntError( PyExc_TypeError,
"expected string argument" );
strncpy( self->keyblock->name, text , 32);
return 0;
}
static int KeyBlock_setVgroup( BPy_KeyBlock * self, PyObject * args ){
char* text = NULL;
text = PyString_AsString ( args );
if( !text )
return EXPP_ReturnIntError( PyExc_TypeError,
"expected string argument" );
strncpy( self->keyblock->vgroup, text , 32);
return 0;
}
static int KeyBlock_setSlidermin( BPy_KeyBlock * self, PyObject * args ){
return EXPP_setFloatClamped ( args, &self->keyblock->slidermin,
-10.0f,
10.0f );
}
static int KeyBlock_setSlidermax( BPy_KeyBlock * self, PyObject * args ){
return EXPP_setFloatClamped ( args, &self->keyblock->slidermax,
-10.0f,
10.0f );
}
static void KeyBlock_dealloc( BPy_KeyBlock * self )
{
PyObject_DEL( self );
}
static int KeyBlock_compare( BPy_KeyBlock * a, BPy_KeyBlock * b )
{
return ( a->keyblock == b->keyblock ) ? 0 : -1;
}
static PyObject *KeyBlock_repr( BPy_KeyBlock * self )
{
return PyString_FromFormat( "[KeyBlock \"%s\"]", self->keyblock->name );
}
static Curve *find_curve( Key *key )
{
Curve *cu;
if( !key )
return NULL;
for( cu = G.main->curve.first; cu; cu = cu->id.next ) {
if( cu->key == key )
break;
}
return cu;
}
static PyObject *KeyBlock_getData( PyObject * self )
{
/* If this is a mesh key, data is an array of MVert coords.
If lattice, data is an array of BPoint coords
If curve, data is an array of BezTriple or BPoint */
char *datap;
int datasize;
int idcode;
int i;
Curve *cu;
Nurb* nu;
PyObject *l;
BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self;
Key *key = kb->key;
if( !kb->keyblock->data ) {
Py_RETURN_NONE;
}
l = PyList_New( kb->keyblock->totelem );
if( !l )
return EXPP_ReturnPyObjError( PyExc_MemoryError,
"PyList_New() failed" );
idcode = GS( key->from->name );
switch(idcode) {
case ID_ME:
for (i=0, datap = kb->keyblock->data; i<kb->keyblock->totelem; i++) {
PyObject *vec = newVectorObject((float*)datap, 3, Py_WRAP);
if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"could not allocate memory for Blender.Mathutils.Vector wrapper!" );
PyList_SetItem(l, i, vec);
datap += kb->key->elemsize;
}
break;
case ID_CU:
cu = find_curve ( key );
if( !cu )
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
"key is no linked to any curve!" );
datasize = count_curveverts(&cu->nurb);
nu = cu->nurb.first;
if( nu->bezt ) {
datasize /= 3;
Py_DECREF (l);
l = PyList_New( datasize );
for( i = 0, datap = kb->keyblock->data; i < datasize;
i++, datap += sizeof(float)*3*4) {
PyObject *tuple = PyTuple_New(4), *vec;
float *vecs = (float*)datap;
if (!tuple) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"PyTuple_New() failed!" );
vec = newVectorObject(vecs, 3, Py_WRAP);
if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
PyTuple_SET_ITEM( tuple, 0, vec);
vecs += 3;
vec = newVectorObject(vecs, 3, Py_WRAP);
if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
PyTuple_SET_ITEM( tuple, 1, vec);
vecs += 3;
vec = newVectorObject(vecs, 3, Py_WRAP);
if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
PyTuple_SET_ITEM( tuple, 2, vec);
/*tilts*/
vecs += 3;
vec = newVectorObject(vecs, 3, Py_WRAP);
if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
PyTuple_SET_ITEM( tuple, 3, vec);
PyList_SetItem( l, i, tuple );
}
} else {
for( i = 0, datap = kb->keyblock->data; i < datasize;
i++, datap += kb->key->elemsize ) {
PyObject *vec = newVectorObject((float*)datap, 4, Py_WRAP);
if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"could not allocate memory for Blender.Mathutils.Vector wrapper!" );
PyList_SetItem( l, i, vec );
}
}
break;
case ID_LT:
for( i = 0, datap = kb->keyblock->data; i < kb->keyblock->totelem;
i++, datap += kb->key->elemsize ) {
PyObject *vec = newVectorObject((float*)datap, 3, Py_WRAP);
if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
"Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
PyList_SetItem( l, i, vec );
}
break;
}
return l;
}
static PyObject *M_Key_Get( PyObject * self, PyObject * args )
{
char *name = NULL;
Key *key_iter;
char error_msg[64];
int i;
if( !PyArg_ParseTuple( args, "|s", &name ) )
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
"expected string argument (or nothing)" ) );
if ( name ) {
for (key_iter = G.main->key.first; key_iter;
key_iter=key_iter->id.next) {
if (strcmp ( key_iter->id.name + 2, name ) == 0 ) {
return Key_CreatePyObject( key_iter );
}
}
PyOS_snprintf( error_msg, sizeof( error_msg ),
"Key \"%s\" not found", name );
return EXPP_ReturnPyObjError ( PyExc_NameError, error_msg );
} else {
PyObject *keylist;
keylist = PyList_New( BLI_countlist( &( G.main->key ) ) );
for ( i=0, key_iter = G.main->key.first; key_iter;
key_iter=key_iter->id.next, i++ ) {
PyList_SetItem(keylist, i, Key_CreatePyObject(key_iter));
}
return keylist;
}
}
struct PyMethodDef M_Key_methods[] = {
{"Get", M_Key_Get, METH_VARARGS, "Get a key or all key names"},
{NULL, NULL, 0, NULL}
};
static PyObject *M_Key_TypesDict( void )
{
PyObject *T = PyConstant_New( );
if( T ) {
BPy_constant *d = ( BPy_constant * ) T;
PyConstant_Insert( d, "MESH", PyInt_FromLong( KEY_TYPE_MESH ) );
PyConstant_Insert( d, "CURVE", PyInt_FromLong( KEY_TYPE_CURVE ) );
PyConstant_Insert( d, "LATTICE", PyInt_FromLong( KEY_TYPE_LATTICE ) );
}
return T;
}
PyObject *Key_Init( void )
{
PyObject *submodule;
PyObject *Types = NULL;
if( PyType_Ready( &Key_Type ) < 0 || PyType_Ready( &KeyBlock_Type ) < 0 )
return NULL;
submodule =
Py_InitModule3( "Blender.Key", M_Key_methods, "Key module" );
Types = M_Key_TypesDict( );
if( Types )
PyModule_AddObject( submodule, "Types", Types );
return submodule;
}