BPython bug fixes:
- bug #2033 reported by Ken Hughes: Vertices of mesh parented to lattice is scaled incorrectly: https://projects.blender.org/tracker/?func=detail&aid=2033&group_id=9&atid=125 - bug #2211 reported by German Alonso Tamayo (servivo): Add a vertex to a mesh with groups using a script and then edit that mesh hangs blender: https://projects.blender.org/tracker/index.php?func=detail&aid=2211&group_id=9&atid=125 (#2211's hang was already fixed with previous commit, but this way should work better) - doc updates (Ken reported missing info about Render slinks, thanks).
This commit is contained in:
@@ -96,7 +96,7 @@ static PyObject *Lattice_setMode( BPy_Lattice * self, PyObject * args );
|
||||
static PyObject *Lattice_getMode( BPy_Lattice * self, PyObject * args );
|
||||
static PyObject *Lattice_setPoint( BPy_Lattice * self, PyObject * args );
|
||||
static PyObject *Lattice_getPoint( BPy_Lattice * self, PyObject * args );
|
||||
static PyObject *Lattice_applyDeform( BPy_Lattice * self );
|
||||
static PyObject *Lattice_applyDeform( BPy_Lattice * self, PyObject *args );
|
||||
static PyObject *Lattice_insertKey( BPy_Lattice * self, PyObject * args );
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -132,7 +132,12 @@ static char Lattice_getPoint_doc[] =
|
||||
"(str) - Get the coordinates of a point on the lattice";
|
||||
|
||||
static char Lattice_applyDeform_doc[] =
|
||||
"(str) - Apply the new lattice deformation to children";
|
||||
"(force = False) - Apply the new lattice deformation to children\n\n\
|
||||
(force = False) - if given and True, children of mesh type are not ignored.\n\
|
||||
Meshes are treated differently in Blender, deformation is stored directly in\n\
|
||||
their vertices when first redrawn (ex: with Blender.Redraw) after getting a\n\
|
||||
Lattice parent, without needing this method (except for command line bg\n\
|
||||
mode). If forced, the deformation will be applied over any previous one(s).";
|
||||
|
||||
static char Lattice_insertKey_doc[] =
|
||||
"(str) - Set a new key for the lattice at specified frame";
|
||||
@@ -162,7 +167,7 @@ static PyMethodDef BPy_Lattice_methods[] = {
|
||||
Lattice_setPoint_doc},
|
||||
{"getPoint", ( PyCFunction ) Lattice_getPoint, METH_VARARGS,
|
||||
Lattice_getPoint_doc},
|
||||
{"applyDeform", ( PyCFunction ) Lattice_applyDeform, METH_NOARGS,
|
||||
{"applyDeform", ( PyCFunction ) Lattice_applyDeform, METH_VARARGS,
|
||||
Lattice_applyDeform_doc},
|
||||
{"insertKey", ( PyCFunction ) Lattice_insertKey, METH_VARARGS,
|
||||
Lattice_insertKey_doc},
|
||||
@@ -675,22 +680,35 @@ static PyObject *Lattice_getPoint( BPy_Lattice * self, PyObject * args )
|
||||
}
|
||||
|
||||
//This function will not do anything if there are no children
|
||||
static PyObject *Lattice_applyDeform( BPy_Lattice * self )
|
||||
static PyObject *Lattice_applyDeform( BPy_Lattice * self, PyObject *args )
|
||||
{
|
||||
//Object* ob; unused
|
||||
Base *base;
|
||||
Object *par;
|
||||
int forced = 0;
|
||||
|
||||
if( !Lattice_IsLinkedToObject( self ) )
|
||||
return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"Lattice must be linked to an object to apply it's deformation!" ) );
|
||||
|
||||
if( !PyArg_ParseTuple( args, "|i", &forced ) )
|
||||
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"expected nothing or True or False argument" ) );
|
||||
|
||||
/* deform children */
|
||||
base = FIRSTBASE;
|
||||
while( base ) {
|
||||
if( ( par = base->object->parent ) ) { /* checking if object has a parent, assigning if so */
|
||||
if((par->type == OB_LATTICE) && (self->Lattice == par->data)) {
|
||||
object_deform( base->object );
|
||||
if( ( par = base->object->parent ) ) { /* check/assign if ob has parent */
|
||||
/* meshes have their mverts deformed, others ob types use displist,
|
||||
* so we're not doing meshes here (unless forced), or else they get
|
||||
* deformed twice, since parenting a Lattice to an object and redrawing
|
||||
* already applies lattice deformation. 'forced' is useful for
|
||||
* command line background mode, when no redraws occur and so this
|
||||
* method is needed. Or for users who actually want to apply the
|
||||
* deformation n times. */
|
||||
if((self->Lattice == par->data)) {
|
||||
if ((base->object->type != OB_MESH) || forced)
|
||||
object_deform( base->object );
|
||||
}
|
||||
}
|
||||
base = base->next;
|
||||
|
||||
@@ -93,6 +93,7 @@ static PyObject *g_nmeshmodule = NULL;
|
||||
|
||||
static int unlink_existingMeshData( Mesh * mesh );
|
||||
static int convert_NMeshToMesh( Mesh *mesh, BPy_NMesh *nmesh, int store_edges );
|
||||
static void check_dverts(Mesh *me, int old_totverts);
|
||||
static PyObject *NMesh_printDebug( PyObject * self );
|
||||
static PyObject *NMesh_addEdge( PyObject * self, PyObject * args );
|
||||
static PyObject *NMesh_findEdge( PyObject * self, PyObject * args );
|
||||
@@ -1292,6 +1293,7 @@ static PyObject *NMesh_update( PyObject *self, PyObject *a, PyObject *kwd )
|
||||
static char *kwlist[] = {"recalc_normals", "store_edges",
|
||||
"vertex_shade", NULL};
|
||||
int needs_redraw = 1;
|
||||
int old_totvert = 0;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(a, kwd, "|iii", kwlist, &recalc_normals,
|
||||
&store_edges, &vertex_shade ) )
|
||||
@@ -1299,8 +1301,10 @@ static PyObject *NMesh_update( PyObject *self, PyObject *a, PyObject *kwd )
|
||||
"expected nothing or one to three bool(s) (0 or 1) as argument" );
|
||||
|
||||
if( mesh ) {
|
||||
old_totvert = mesh->totvert;
|
||||
unlink_existingMeshData( mesh );
|
||||
convert_NMeshToMesh( mesh, nmesh, store_edges );
|
||||
if (mesh->dvert) check_dverts(mesh, old_totvert);
|
||||
} else {
|
||||
nmesh->mesh = Mesh_fromNMesh( nmesh, store_edges );
|
||||
mesh = nmesh->mesh;
|
||||
@@ -2411,8 +2415,6 @@ static int unlink_existingMeshData( Mesh * mesh )
|
||||
{
|
||||
freedisplist( &mesh->disp );
|
||||
EXPP_unlink_mesh( mesh );
|
||||
if( mesh->dvert )
|
||||
free_dverts( mesh->dvert, mesh->totvert );
|
||||
if( mesh->mvert )
|
||||
MEM_freeN( mesh->mvert );
|
||||
if( mesh->medge ) {
|
||||
@@ -2601,6 +2603,39 @@ static void fill_medge_from_nmesh(Mesh * mesh, BPy_NMesh * nmesh)
|
||||
MEM_freeN( faces_edges );
|
||||
}
|
||||
|
||||
/* this should ensure meshes don't end up with wrongly sized
|
||||
* me->dvert arrays, which can cause hangs; it's not ideal,
|
||||
* it's better to wrap dverts in NMesh, but it should do for now
|
||||
* since there are also methods in NMesh to edit dverts in the actual
|
||||
* mesh in Blender and anyway this is memory friendly */
|
||||
static void check_dverts(Mesh *me, int old_totvert)
|
||||
{
|
||||
int totvert = me->totvert;
|
||||
|
||||
/* if vert count didn't change or there are no dverts, all is fine */
|
||||
if ((totvert == old_totvert) || (!me->dvert)) return;
|
||||
/* if all verts have been deleted, free old dverts */
|
||||
else if (totvert == 0) free_dverts(me->dvert, old_totvert);
|
||||
/* if verts have been added, expand me->dvert */
|
||||
else if (totvert > old_totvert) {
|
||||
MDeformVert *mdv = me->dvert;
|
||||
me->dvert = NULL;
|
||||
create_dverts(me);
|
||||
copy_dverts(me->dvert, mdv, old_totvert);
|
||||
free_dverts(mdv, old_totvert);
|
||||
}
|
||||
/* if verts have been deleted, shrink me->dvert */
|
||||
else {
|
||||
MDeformVert *mdv = me->dvert;
|
||||
me->dvert = NULL;
|
||||
create_dverts(me);
|
||||
copy_dverts(me->dvert, mdv, totvert);
|
||||
free_dverts(mdv, old_totvert);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh, int store_edges)
|
||||
{
|
||||
MFace *newmf;
|
||||
@@ -2782,6 +2817,7 @@ static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args )
|
||||
BPy_NMesh *nmesh;
|
||||
int recalc_normals = 1;
|
||||
int store_edges = 0;
|
||||
int old_totvert = 0;
|
||||
|
||||
if( !PyArg_ParseTuple( args, "O!|sii",
|
||||
&NMesh_Type, &nmesh, &name, &recalc_normals, &store_edges ) )
|
||||
@@ -2830,10 +2866,14 @@ static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args )
|
||||
new_id( &( G.main->mesh ), &mesh->id,
|
||||
PyString_AsString( nmesh->name ) );
|
||||
|
||||
old_totvert = mesh->totvert;
|
||||
|
||||
unlink_existingMeshData( mesh );
|
||||
convert_NMeshToMesh( mesh, nmesh, store_edges );
|
||||
nmesh->mesh = mesh;
|
||||
|
||||
if (mesh->dvert) check_dverts(mesh, old_totvert);
|
||||
|
||||
if( recalc_normals )
|
||||
vertexnormals_mesh( mesh, 0 );
|
||||
|
||||
|
||||
@@ -1553,6 +1553,12 @@ static PyObject *Object_makeParent( BPy_Object * self, PyObject * args )
|
||||
"expected a list of objects" ) );
|
||||
}
|
||||
|
||||
parent = ( Object * ) self->object;
|
||||
|
||||
if (parent->id.us == 0)
|
||||
return EXPP_ReturnPyObjError (PyExc_RuntimeError,
|
||||
"object must be linked to a scene before it can become a parent");
|
||||
|
||||
/* Check if the PyObject passed in list is a Blender object. */
|
||||
for( i = 0; i < PySequence_Length( list ); i++ ) {
|
||||
child = NULL;
|
||||
@@ -1561,12 +1567,13 @@ static PyObject *Object_makeParent( BPy_Object * self, PyObject * args )
|
||||
child = ( Object * ) Object_FromPyObject( py_child );
|
||||
|
||||
if( child == NULL ) {
|
||||
Py_DECREF (py_child);
|
||||
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"Object Type expected" ) );
|
||||
}
|
||||
|
||||
parent = ( Object * ) self->object;
|
||||
if( test_parent_loop( parent, child ) ) {
|
||||
Py_DECREF (py_child);
|
||||
return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"parenting loop detected - parenting failed" ) );
|
||||
}
|
||||
@@ -1587,7 +1594,7 @@ static PyObject *Object_makeParent( BPy_Object * self, PyObject * args )
|
||||
sort_baselist( G.scene );
|
||||
}
|
||||
// We don't need the child object anymore.
|
||||
//Py_DECREF ((PyObject *) child);
|
||||
Py_DECREF (py_child);
|
||||
}
|
||||
return EXPP_incr_ret( Py_None );
|
||||
}
|
||||
|
||||
@@ -752,7 +752,7 @@ static PyObject *Scene_link( BPy_Scene * self, PyObject * args )
|
||||
|
||||
/* not linked, go get mem for a new base object */
|
||||
|
||||
base = MEM_callocN( sizeof( Base ), "newbase" );
|
||||
base = MEM_callocN( sizeof( Base ), "pynewbase" );
|
||||
|
||||
if( !base )
|
||||
return EXPP_ReturnPyObjError( PyExc_MemoryError,
|
||||
|
||||
@@ -205,7 +205,7 @@ class Camera:
|
||||
"""
|
||||
Get a list with this Camera's script links of type 'event'.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw" or "Render".
|
||||
@rtype: list
|
||||
@return: a list with Blender L{Text} names (the script links of the given
|
||||
'event' type) or None if there are no script links at all.
|
||||
@@ -225,7 +225,7 @@ class Camera:
|
||||
@type text: string
|
||||
@param text: the name of an existing Blender L{Text}.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw" or "Render".
|
||||
"""
|
||||
|
||||
def insertIpoKey(keytype):
|
||||
|
||||
@@ -329,7 +329,7 @@ class Lamp:
|
||||
"""
|
||||
Get a list with this Lamp's script links of type 'event'.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw" or "Render".
|
||||
@rtype: list
|
||||
@return: a list with Blender L{Text} names (the script links of the given
|
||||
'event' type) or None if there are no script links at all.
|
||||
@@ -349,7 +349,7 @@ class Lamp:
|
||||
@type text: string
|
||||
@param text: the name of an existing Blender L{Text}.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw" or "Render".
|
||||
"""
|
||||
|
||||
def getIpo():
|
||||
|
||||
@@ -171,10 +171,22 @@ class Lattice:
|
||||
@param position: The x,y,z coordinates that you want the point to be: [x,y,z]
|
||||
"""
|
||||
|
||||
def applyDeform():
|
||||
def applyDeform(force = False):
|
||||
"""
|
||||
@type force: bool
|
||||
@param force: if True, meshes are not ignored.
|
||||
Applies the current Lattice deformation to any child objects that have this
|
||||
Lattice as the parent.
|
||||
@note: simply parenting to a Lattice and redrawing the screen is enough to
|
||||
get the deformation done, this applyDeform method is useful when the
|
||||
script won't call a redraw, like in command line background (GUI-less)
|
||||
mode.
|
||||
@note: by default, this method doesn't apply deformations to meshes. This
|
||||
is because unlike other kinds of objects, meshes store lattice
|
||||
deformation directly in their vertices and calling this applyDeform
|
||||
method will apply the deformation a second time, giving double
|
||||
deformation, which can be a feature (set force = True if you want it) or
|
||||
much probably an undesired effect.
|
||||
"""
|
||||
|
||||
def insertKey(frame):
|
||||
|
||||
@@ -443,6 +443,9 @@ class Object:
|
||||
0 - update scene hierarchy automatically
|
||||
1 - don't update scene hierarchy (faster). In this case, you must
|
||||
explicitely update the Scene hierarchy.
|
||||
@warn: objects must first be linked to a scene before they can become
|
||||
parents of other objects. Calling this makeParent method for an
|
||||
unlinked object will result in an error.
|
||||
"""
|
||||
|
||||
def setDeltaLocation(delta_location):
|
||||
@@ -595,7 +598,7 @@ class Object:
|
||||
"""
|
||||
Get a list with this Object's script links of type 'event'.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw" or "Render".
|
||||
@rtype: list
|
||||
@return: a list with Blender L{Text} names (the script links of the given
|
||||
'event' type) or None if there are no script links at all.
|
||||
@@ -615,7 +618,7 @@ class Object:
|
||||
@type text: string
|
||||
@param text: the name of an existing Blender L{Text}.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw" or "Render".
|
||||
"""
|
||||
|
||||
def makeTrack (tracked, fast = 0):
|
||||
|
||||
@@ -236,7 +236,7 @@ class Scene:
|
||||
"""
|
||||
Get a list with this Scene's script links of type 'event'.
|
||||
@type event: string
|
||||
@param event: "FrameChanged", "OnLoad", "OnSave" or "Redraw".
|
||||
@param event: "FrameChanged", "OnLoad", "OnSave", "Redraw" or "Render".
|
||||
@rtype: list
|
||||
@return: a list with Blender L{Text} names (the script links of the given
|
||||
'event' type) or None if there are no script links at all.
|
||||
@@ -256,7 +256,7 @@ class Scene:
|
||||
@type text: string
|
||||
@param text: the name of an existing Blender L{Text}.
|
||||
@type event: string
|
||||
@param event: "FrameChanged", "OnLoad", "OnSave" or "Redraw".
|
||||
@param event: "FrameChanged", "OnLoad", "OnSave", "Redraw" or "Render".
|
||||
"""
|
||||
|
||||
def play (mode = 0, win = '<VIEW3D>'):
|
||||
|
||||
@@ -293,7 +293,7 @@ class World:
|
||||
"""
|
||||
Get a list with this World's script links of type 'event'.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw", "Render".
|
||||
@rtype: list
|
||||
@return: a list with Blender L{Text} names (the script links of the given
|
||||
'event' type) or None if there are no script links at all.
|
||||
@@ -313,7 +313,7 @@ class World:
|
||||
@type text: string
|
||||
@param text: the name of an existing Blender L{Text}.
|
||||
@type event: string
|
||||
@param event: "FrameChanged" or "Redraw".
|
||||
@param event: "FrameChanged", "Redraw" or "Render".
|
||||
"""
|
||||
|
||||
def setCurrent ():
|
||||
|
||||
Reference in New Issue
Block a user