[Bf-python] PutRaw()

models at paposo.com models at paposo.com
Thu Sep 18 09:32:02 CEST 2003


Ok. This is sorta a separate post. I was looking at putRaw() and noticed the
following:

NMesh.PutRaw() handles 4 things:
1.PutRaw(nmesh) - no named 2nd parameter
    a) Create default object with default mesh called 'Mesh'
    b) if nmesh was returned from GetRaw() or GetRawFromObject() a new
datablock is created and linked to object
            else if nmesh was created new, the default object->data mesh is
used
    c) Update mesh
2.PutRaw(nmesh, 'datablock') - named datablock with users (linked to objects
in the scene)
    a) Tests to see if 'datablock' exists - YES
    b) Tests to see if linked to objects - YES
    c) Update mesh
3.PutRaw(nmesh, 'datablock') - named datablock with no users (persistent
mesh data with no linked objects)
    a) Tests to see if 'datablock' exists - YES
    b) Tests to see if linked to objects - NO
    c) Create default object with default mesh called 'Mesh'
    d) Link new object to existing datablock
    e) Update mesh
4.PutRaw(nmesh, 'datablock') - new datablock name (add nmesh as named
datablock)
    a) Tests to see if 'datablock' exists - NO
    b) Create default object with default mesh called 'Mesh'
    c) Set object's global mesh name to 'name'
    d) Update mesh

Problem #1:
One of the problems here is with 3) when the datablock exists but has no
users - the call to set_mesh leaves a default datablock hanging around:
A way to test this is the following:

Add a cube to scene from the toolbox. Hit x and delete the cube. The object
is gone but the mesh is persistant as 'Cube'.
Verify this by hiting F9 after deleting the cube, right click the default
plane and look at the meshes. There will be 'Cube' and 'Plane'.
Run the following script:

import Blender
myMesh = Blender.NMesh.GetRaw('Cube')
Blender.NMesh.PutRaw(myMesh, 'Cube')

Hit alt-P. F9 and look at the meshes again. You'll have 'Plane', 'Cube' and
'Mesh'.  Mesh was the default datablock that was created when a new object
was     created.  This is because add_object() calls add_mesh(). Calling
set_mesh on the datablock with no users (which is the only time it's called)
will decrement the user count for the default mesh and link the object to
the existing mesh with no user counts.  This leave 'Mesh' hanging around.
The default mesh created should be removed. This will do the trick:

if (mesh)
 {
       free_libblock(&(G.main->mesh),(Mesh*)ob->data);
       set_mesh(ob, mesh);
 }

Problem #2:
This one's no so obvious.
When calling PutRaw(nmesh) with no 2nd parameter the following line gets
called:

 else if (nmesh->name && nmesh->name != Py_None)
       new_id(&(G.main->mesh), &mesh->id, PyString_AsString(nmesh->name));

This executes only when the nmesh came from GetRaw() or GetRawFromObject().
This is because all other nmesh's have Py_None as a name. This will attempt
to create a new global mesh when the mesh came from an existing mesh but the
user didn't say so. (i.e. he called PutRaw() without a second parameter)
    Under situation 2 and 3 new_id() will return 0 because the Mesh ID
already exists. It's only when you don't pass a 2nd parameter and the mesh
block exists does this code actually execute and produce a new global mesh
id.
    The problem here similar to the one before but different.
1)You got a mesh from GetRaw() or GetRawFromObject(). This gives you a
nmesh->name.
2) A new object is created with a default mesh called 'Mesh'. (because no
2nd parameter)
3) new_id() determines that a new id should be created in the global list
for this mesh.
4) You now have 2 global id's for the default object->data mesh oops.

The answer here i think is that when you are calling PutRaw(nmesh) and the
nmesh was returned from GetRaw() or GetRawFromObject() you are really doing
the same thing as situation 2 or 3, where you are doing PutRaw(nmesh,
'datablock') where the datablock exists and has users or maybe not.  So I
think this will do the trick:

  if (name)
        mesh = (Mesh *)GetIdFromList(&(G.main->mesh), name);
  else if (nmesh->name && nmesh->name != Py_None)
  {
         nmeshName = PyString_AsString(nmesh->name);
         mesh = (Mesh *)GetIdFromList(&(G.main->mesh), nmeshName);
  }

...

  if (name) //renames mesh datablock
   new_id(&(G.main->mesh), &mesh->id, name);

the above else if will only execute when nmesh is derived from an existing
mesh and we are calling PutRaw().  If there are user counts (i.e. it's
linked) it will follow what normally happens in situation 2 - it will update
the mesh, else it will create a new object and link the datablock. No more
floating default meshes!! yes.

What i mean by updating the mesh is:

unlink_existingMeshData(mesh);
convert_NMeshToMesh(mesh, nmesh);
nmesh->mesh = mesh;

which is called regardless.

CONCLUSION:
The following change should do a body good:

  if (name)
        mesh = (Mesh *)GetIdFromList(&(G.main->mesh), name);
  else if (nmesh->name && nmesh->name != Py_None)
  {
         nmeshName = PyString_AsString(nmesh->name);
         mesh = (Mesh *)GetIdFromList(&(G.main->mesh), nmeshName);
  }

  if(!mesh || mesh->id.us == 0)
  {
        ob = add_object(OB_MESH);
        if (!ob)
 {
      PyErr_SetString(PyExc_RuntimeError,
                      "Fatal: could not create mesh object");
          return 0;
    }
  if (mesh)
 {
       free_libblock(&(G.main->mesh),(Mesh*)ob->data);
       set_mesh(ob, mesh);
 }
    else
          mesh = (Mesh *)ob->data;
  }

  if (name) //renames mesh datablock
       new_id(&(G.main->mesh), &mesh->id, name);

  unlink_existingMeshData(mesh);
  convert_NMeshToMesh(mesh, nmesh);
  nmesh->mesh = mesh;

P.S. There is a last problem here. GetRawFromObject() relates to displists.
However, GetRawFromObject() has the following code:
{
    Mesh *me = (Mesh*)ob->data;
    DispList *dl;

    if (mesh_uses_displist(me) && (dl = find_displist(&me->disp, DL_MESH)))
      nmesh = new_NMesh_internal(me, dl->mesh, NULL);
    else if ((dl= find_displist(&ob->disp, DL_VERTS)))
      nmesh = new_NMesh_internal(me, NULL, dl->verts);
    else
      nmesh = new_NMesh(me);
  }

This seems to imply that a mesh may not use a displist. There could be a
flag here to let PutRaw() know not to fool around with mesh using displists,
else it would proceed as planned. This coiuld also be true of using GetRaw()
with PutRaw(). There could be a test in PutRaw() for a nmesh->name named
mesh using displists.  If yes, If will create a new mesh and new object
regardless, else it would proceed as above. Maybe something like this:

if (mesh_uses_displist(mesh) && (dl = find_displist(&mesh->disp, DL_MESH)))
   mesh = NULL;

So the whole enchilda would be:

  char *nmeshName = NULL;
  DispList *dl;
....
....
if (name)
    mesh = (Mesh *)GetIdFromList(&(G.main->mesh), name);
    else if (nmesh->name && nmesh->name != Py_None)
  {
    nmeshName = PyString_AsString(nmesh->name);
    mesh = (Mesh *)GetIdFromList(&(G.main->mesh), nmeshName);
  }

  if (mesh_uses_displist(mesh) && (dl = find_displist(&mesh->disp,
DL_MESH)))
   mesh = NULL;

  if(!mesh || mesh->id.us == 0)
  {
      ob = add_object(OB_MESH);
      if (!ob)
 {
      PyErr_SetString(PyExc_RuntimeError,
                      "Fatal: could not create mesh object");
        return 0;
    }
 if (mesh)
 {
      free_libblock(&(G.main->mesh),(Mesh*)ob->data);
      set_mesh(ob, mesh);
 }
    else
        mesh = (Mesh *)ob->data;
  }

  if (name)
     new_id(&(G.main->mesh), &mesh->id, name);

  unlink_existingMeshData(mesh);
  convert_NMeshToMesh(mesh, nmesh);
  nmesh->mesh = mesh;




More information about the Bf-python mailing list