- Stephane Soppera added long missed support for edge data in Blender.NMesh + related doc;
- Michael Reimpell improved script registration (fixes bug report #2160) and the file and image selectors in Blender.Window (improved with suggestions from Yann Vernier).  They now suppport methods as callbacks;
- World.get/setMode were not registered, so could not be directly called (reported by Ken Hughes).  Still needs some work to improve things, including docs.

Scripts:
- Jean-Michel Soler updated his texture baker based on input from Appolux;
- Campbell and Jean-Michel improved the bvh importer: faster, better float units scaling (by Campbell); supports Poser 3.01 files (by jms).

Thanks guys!
This commit is contained in:
Willian Padovani Germano
2005-01-22 02:48:03 +00:00
parent 5822d4601d
commit 1da3b9f517
8 changed files with 1009 additions and 147 deletions

View File

@@ -2,30 +2,44 @@
"""
Name: 'Motion Capture (.bvh)...'
Blender: 232
Blender: 236
Group: 'Import'
Tip: 'Import a (.bvh) motion capture file'
"""
__author__ = "Campbell Barton"
__url__ = ("blender", "elysiun")
__version__ = "1.0 03/25/04"
__url__ = ("blender", "elysiun", "http://jmsoler.free.fr/util/blenderfile/py/bvh_import.py")
__version__ = "1.0.2 04/12/28"
__bpydoc__ = """\
This script imports BVH motion capture data to Blender.
Supported:<br>
Supported: Poser 3.01<br>
Missing:<br>
Known issues:<br>
Notes:<br>
Jean-Michel Soler improved importer to support Poser 3.01 files.
"""
# $Id$
#
#===============================================#
# BVH Import script 1.03 patched by Campbell #
# Small optimizations and scale input #
# 01/01/2005, #
#===============================================#
#===============================================#
# BVH Import script 1.02 patched by Jm Soler #
# to the Poser 3.01 bvh file #
# 28/12/2004, #
#===============================================#
#===============================================#
# BVH Import script 1.0 by Campbell Barton #
# 25/03/2004, euler rotation code taken from #
@@ -67,7 +81,7 @@ Notes:<br>
import string
import math
import Blender
from Blender import Window, Object, Scene, Ipo
from Blender import Window, Object, Scene, Ipo, Draw
from Blender.Scene import Render
@@ -80,14 +94,13 @@ from Blender.Scene import Render
#
# except:
# print 'psyco is not present on this system'
# Default scale
scale = 0.01
# Update as we load?
debug = 0
# Global scale facctor # sHOULD BE 1 BY DEFAULT
scale = 1
# Get the current scene.
scn = Scene.GetCurrent()
context = scn.getRenderingContext()
@@ -100,6 +113,9 @@ channelCurves = []
# Chenging there rotation to EULER rotation
objectList = []
def getScale():
return Draw.PupFloatInput('BVH Scale: ', 0.01, 0.001, 10.0, 0.1, 3)
def MAT(m):
if len(m) == 3:
return Blender.Mathutils.Matrix(m[0], m[1], m[2])
@@ -127,7 +143,6 @@ def eulerRotate(x,y,z):
for k in range(3):
for j in range(3):
mat3[i][k]=mat3[i][k]+mat1[i][j]*mat2[j][k]
mat1 = mat2 = i = k = j = None # Save memory
return mat3
@@ -162,7 +177,6 @@ def eulerRotate(x,y,z):
mat3[2][1]=t*y*z-s*x
mat3[2][2]=t*z*z+c
rot4 = s = c = t = x = y = z = None # Save some memory
return mat3
eul = [x,y,z]
@@ -202,8 +216,6 @@ def eulerRotate(x,y,z):
y =- eul[1]/-10
z =- eul[2]/-10
eul = mat = zmat = xmat = ymat = jj = None
return x, y, z # Returm euler roration values.
@@ -213,6 +225,7 @@ def eulerRotate(x,y,z):
# from the BVA file to create an empty #
#===============================================#
def makeJoint(name, parent, prefix, offset, channels):
global scale
# Make Empty, with the prefix in front of the name
ob = Object.New('Empty', prefix + name) # New object, ob is shorter and nicer to use.
scn.link(ob) # place the object in the current scene
@@ -253,8 +266,6 @@ def makeJoint(name, parent, prefix, offset, channels):
# Add to object list
objectList.append(ob)
ob = newIpo = opParent = None
# Redraw if debugging
if debug: Blender.Redraw()
@@ -280,13 +291,22 @@ def makeEnd(parent, prefix, offset):
#===============================================#
# MAIN FUNCTION - All things are done from here #
#===============================================#
def loadBVH(filename):
global scale
print ''
print 'BVH Importer 1.0 by Campbell Barton (Ideasman) - ideasman@linuxmail.org'
alpha='abcdefghijklmnopqrstuvewxyz'
ALPHA=alpha+alpha.upper()
ALPHA+=' 0123456789+-{}. '
time1 = Blender.sys.time()
tmpScale = getScale()
if tmpScale != None:
scale = tmpScale
# File loading stuff
# Open the file for importing
file = open(filename, 'r')
@@ -294,10 +314,19 @@ def loadBVH(filename):
# Make a list of lines
lines = []
for fileLine in fileData:
fileLine=fileLine.replace('..','.')
newLine = string.split(fileLine)
if newLine != []:
lines.append(string.split(fileLine))
fileData = None
t=[]
for n in newLine:
for n0 in n:
if n0 not in ALPHA:
n=n.replace(n0,'')
t.append(n)
lines.append(t)
del fileData
# End file loading code
# Call object names with this prefix, mainly for scenes with multiple BVH's - Can imagine most partr names are the same
@@ -320,18 +349,25 @@ def loadBVH(filename):
#channelList [(<objectName>, [channelType1, channelType2...]), (<objectName>, [channelType1, channelType2...)]
channelList = []
channelIndex = -1
lineIdx = 1 # An index for the file.
while lineIdx < len(lines) -1:
#...
if lines[lineIdx][0] == 'ROOT' or lines[lineIdx][0] == 'JOINT':
if lines[lineIdx][0] == 'JOINT' and len(lines[lineIdx])>2:
for j in range(2,len(lines[lineIdx])) :
lines[lineIdx][1]+='_'+lines[lineIdx][j]
# MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.??
print len(parent) * ' ' + 'node:',lines[lineIdx][1],' parent:',parent[-1]
print lineIdx
name = lines[lineIdx][1]
print name,lines[lineIdx+1],lines[lineIdx+2]
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( eval(lines[lineIdx][1]), eval(lines[lineIdx][2]), eval(lines[lineIdx][3]) )
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(lines[lineIdx][3]) )
lineIdx += 1 # Incriment to the next line (Channels)
# newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
@@ -367,7 +403,7 @@ def loadBVH(filename):
# Account for an end node
if lines[lineIdx][0] == 'End' and lines[lineIdx][1] == 'Site': # There is somtimes a name afetr 'End Site' but we will ignore it.
lineIdx += 2 # Incriment to the next line (Offset)
offset = ( eval(lines[lineIdx][1]), eval(lines[lineIdx][2]), eval(lines[lineIdx][3]) )
offset = ( float(lines[lineIdx][1]), float(lines[lineIdx][2]), float(lines[lineIdx][3]) )
makeEnd(parent, prefix, offset)
# Just so we can remove the Parents in a uniform way- End end never has kids
@@ -431,21 +467,46 @@ def loadBVH(filename):
if debug: Blender.Redraw()
while obIdx < len(objectList) -1:
if channelList[obIdx][0] != -1:
objectList[obIdx].getIpo().getCurve('LocX').addBezier((currentFrame, scale * eval(lines[lineIdx][channelList[obIdx][0]])))
VAL0=lines[lineIdx][channelList[obIdx][0]]
if VAL0.find('.')==-1:
VAL0=VAL0[:len(VAL0)-6]+'.'+VAL0[-6:]
objectList[obIdx].getIpo().getCurve('LocX').addBezier((currentFrame, scale * float(VAL0)))
if channelList[obIdx][1] != -1:
objectList[obIdx].getIpo().getCurve('LocY').addBezier((currentFrame, scale * eval(lines[lineIdx][channelList[obIdx][1]])))
VAL1=lines[lineIdx][channelList[obIdx][0]]
if VAL1.find('.')==-1:
VAL1=VAL1[:len(VAL1)-6]+'.'+VAL1[-6:]
objectList[obIdx].getIpo().getCurve('LocY').addBezier((currentFrame, scale * float(VAL1)))
if channelList[obIdx][2] != -1:
objectList[obIdx].getIpo().getCurve('LocZ').addBezier((currentFrame, scale * eval(lines[lineIdx][channelList[obIdx][2]])))
VAL2=lines[lineIdx][channelList[obIdx][0]]
if VAL2.find('.')==-1:
VAL2=VAL2[:len(VAL2)-6]+'.'+VAL2[-6:]
objectList[obIdx].getIpo().getCurve('LocZ').addBezier((currentFrame, scale * float(VAL2)))
if channelList[obIdx][3] != '-1' or channelList[obIdx][4] != '-1' or channelList[obIdx][5] != '-1':
x, y, z = eulerRotate(eval(lines[lineIdx][channelList[obIdx][3]]), eval(lines[lineIdx][channelList[obIdx][4]]), eval(lines[lineIdx][channelList[obIdx][5]]))
VAL3=lines[lineIdx][channelList[obIdx][3]]
if VAL3.find('.')==-1:
VAL3=VAL3[:len(VAL3)-6]+'.'+VAL3[-6:]
VAL4=lines[lineIdx][channelList[obIdx][4]]
if VAL4.find('.')==-1:
VAL4=VAL4[:len(VAL4)-6]+'.'+VAL4[-6:]
VAL5=lines[lineIdx][channelList[obIdx][5]]
if VAL5.find('.')==-1:
VAL5=VAL5[:len(VAL5)-6]+'.'+VAL5[-6:]
x, y, z = eulerRotate(float(VAL3), float(VAL4), float(VAL5))
objectList[obIdx].getIpo().getCurve('RotX').addBezier((currentFrame, x))
objectList[obIdx].getIpo().getCurve('RotY').addBezier((currentFrame, y))
objectList[obIdx].getIpo().getCurve('RotZ').addBezier((currentFrame, z))
obIdx += 1
# Done importing motion data #
lines[lineIdx] = None # Scrap old motion data, save some memory?
# lines[lineIdx] = None # Scrap old motion data, save some memory?
lineIdx += 1
# We have finished now
print currentFrame, 'done.'
@@ -457,5 +518,6 @@ def loadBVH(filename):
# Main file loop
lineIdx += 1
print "bvh import time: ", Blender.sys.time() - time1
Blender.Window.FileSelector(loadBVH, "Import BVH")

View File

@@ -11,7 +11,7 @@ __author__ = "Jean-Michel Soler (jms)"
__url__ = ("blender", "elysiun",
"Script online, http://jmsoler.free.fr/util/blenderfile/py/text2uvbaker.py",
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
__version__ = "0.2.2 2004/08/01"
__version__ = "0.2.3 2004/12/30"
__bpydoc__ = """\
This script "bakes" Blender procedural materials (including textures): it saves
@@ -33,7 +33,7 @@ Notes:<br>
"""
#---------------------------------------------
# Last release : 0.2.2 , 2004/08/01 , 22h13
# Last release : 0.2.3 , 2004/12/30 , 22h13
#---------------------------------------------
#---------------------------------------------
# (c) jm soler 07/2004 : 'Procedural Texture Baker'
@@ -43,12 +43,40 @@ Notes:<br>
# original mesh.
# released under Blender Artistic Licence
#
# 0.2.2 : if the uv mesh objet exists it used,
# no creation of a new one. As the lamp and
# the camera
# 0.2.1 : This script automaticaly frame and shoot the
# new uv mesh . The image file is saved ine the
# /render folder.
#
# 0.2.3 :
# Great thanks for Apollux who sees a lot of these
# problems
#
# --Everytime you run the script a new set
# of objects is created. File size and memory
# consumption can go pretty high if you are
# not aware of that .
# Now it ONLY creates 3 objects: a flattened
# mesh, a camera and a lamp.
# --all the 3 objects was placed on layer 1, but if
# that layer was not visible while you used the script
# all you will get a is an empty render.
# Now the layer is tst and activated befor the shoot
# --The flattened mesh was really flattend only after
# frame 100 (if you playbacked the animation, you can
# actually see the mesh becoming flat on the first 100
# frames). No more.
# -- When the script is run, it changes temporary to
# the new cammera, set the render output to a square
# (i.e. 1024 x 1024 or else), does the render, and then
# resets the render output and the active camera to the
# original one. But if no original camera was found
# this produce an error.
#
# 0.2.2 :
# if the uv mesh objet exists it used,
# no creation of a new one. As the lamp and
# the camera
# 0.2.1 :
# This script automaticaly frame and shoot the
# new uv mesh . The image file is saved ine the
# /render folder.
#
#---------------------------------------------
# On user-friendly side :
@@ -83,9 +111,9 @@ Basic instructions:
- Run this script and check the console.
"""
def GET_newobject (TYPE):
def GET_newobject (TYPE,NAME):
SCENE = Blender.Scene.getCurrent()
OBJECT = Blender.Object.New(TYPE)
OBJECT = Blender.Object.New(TYPE,NAME)
SCENE.link(OBJECT)
return OBJECT, SCENE
@@ -138,7 +166,7 @@ def SHOOT (XYlimit, frame, obj, name, FRAME):
except:
Cam = Blender.Camera.New()
Cam.name = 'UVCamera'
CAM, SC = GET_newobject('Camera')
CAM, SC = GET_newobject('Camera','UVCAMERA')
CAM.link(Cam)
CAM.setName('UVCAMERA')
Cam.lens = 30
@@ -151,22 +179,23 @@ def SHOOT (XYlimit, frame, obj, name, FRAME):
CAM.setEuler (0.0, 0.0, 0.0)
try:
LAMP = Blender.Object.Get('Eclairage')
LAMP = Blender.Object.Get('ECLAIRAGE')
lampe = LAMP.getData()
SC = Blender.Scene.getCurrent()
except:
lampe = Blender.Lamp.New()
lampe.name = 'lumin'
LAMP, SC = GET_newobject('Lamp')
LAMP, SC = GET_newobject('Lamp','ECLAIRAGE')
LAMP.link(lampe)
LAMP.setName('Eclairage')
LAMP.setName('ECLAIRAGE')
LAMP.setLocation(obj.getLocation())
LAMP.LocX += XYlimit[0] / 2.0
LAMP.LocY += XYlimit[1] / 2.0
LAMP.LocZ += max (XYlimit[0], XYlimit[1])
LAMP.setEuler (0.0, 0.0, 0.0)
context = SC.getRenderingContext()
Camold = SC.getCurrentCamera()
SC.setCurrentCamera(CAM)
@@ -189,16 +218,27 @@ def SHOOT (XYlimit, frame, obj, name, FRAME):
SAVE_image (context, name, FRAME)
context.imageSizeY(OLDy)
context.imageSizeX(OLDx)
SC.setCurrentCamera(Camold)
if Camold :SC.setCurrentCamera(Camold)
Blender.Set ('curframe', frame)
def Mesh2UVCoord ():
try:
if 1:#try:
MESH3D = Object.GetSelected()[0]
if MESH3D.getType() == 'Mesh':
MESH = MESH3D.getData()
MESH2 = Blender.NMesh.GetRaw()
try:
NewOBJECT=Blender.Object.Get('UVOBJECT')
CurSCENE=Blender.Scene.getCurrent()
MESH2 = NewOBJECT.getData()
MESH2.faces=[]
except:
NewOBJECT, CurSCENE = GET_newobject('Mesh','UVOBJECT')
MESH2 = Blender.NMesh.GetRaw()
for f in MESH.faces:
f1 = Blender.NMesh.Face()
@@ -218,25 +258,14 @@ def Mesh2UVCoord ():
MESH2.materials = MESH.materials[:]
try:
NewOBJECT=Blender.Object.Get('UVOBJECT')
CurSCENE=Blender.Scene.getCurrent()
except:
NewOBJECT, CurSCENE = GET_newobject('Mesh')
NewOBJECT.link(MESH2)
#NewOBJECT, CurSCENE = GET_newobject('Mesh')
#NewOBJECT.link(MESH2)
NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0)
NewOBJECT.setEuler (0.0, 0.0, 0.0)
MESH2.removeAllKeys()
MESH2.update()
MESH2.insertKey (1, 'absolute')
MESH2.update()
for f in MESH2.faces:
for v in f.v:
@@ -248,6 +277,10 @@ def Mesh2UVCoord ():
print XYLIMIT
MESH2.update()
MESH2.insertKey (1, 'absolute')
MESH2.update()
MESH2.update()
MESH2.insertKey (FRAME, 'absolute')
MESH2.update()
@@ -271,9 +304,9 @@ def Mesh2UVCoord ():
result = Draw.PupMenu(name)
print 'problem : no object selected or not mesh'
except:
name = "Error%t|Active object is not a mesh or has no UV coordinates"
result = Draw.PupMenu(name)
#except:
# name = "Error%t|Active object is not a mesh or has no UV coordinates"
# result = Draw.PupMenu(name)
print 'problem : no object selected or not mesh'
Mesh2UVCoord()

View File

@@ -647,14 +647,13 @@ static int bpymenu_CreateFromDir( char *dirname, int whichdir )
int scriptGroup;
BPyMenu *scriptMenu = NULL;
/* other */
int scanDir = 1;
int returnValue = 0;
/* open directory stream */
dir = opendir(dirname);
if (dir != NULL) {
/* directory stream opened */
while (((dirEntry = readdir(dir)) != NULL) && (scanDir == 1)) {
while ((dirEntry = readdir(dir)) != NULL) {
/* Check if filename does not start with a dot,
* ends with '.py' and is a regular file. */
BLI_make_file_string("/", fileName, dirname, dirEntry->d_name);
@@ -722,10 +721,7 @@ static int bpymenu_CreateFromDir( char *dirname, int whichdir )
if (DEBUG) {
fprintf(stderr, "BPyMenus error: Couldn't create entry for: %s\n", fileName);
}
/* abort */
parserState = 0;
scanDir = 0;
returnValue = -2;
} else {
parserState++;
}

View File

@@ -26,7 +26,7 @@
* This is a new part of Blender.
*
* Contributor(s): Willian P. Germano, Jordi Rovira i Bonet, Joseph Gilbert,
* Bala Gi, Alexander Szakaly
* Bala Gi, Alexander Szakaly, Stephane Soppera
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
@@ -46,6 +46,7 @@
#include "BIF_editmesh.h" /* vertexnormals_mesh() : still needed???*/
#include "BIF_meshtools.h" /* current loc of vertexnormals_mesh() */
#include "BIF_space.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_main.h"
#include "BKE_global.h"
@@ -86,7 +87,16 @@
static PyObject *g_nmeshmodule = NULL;
static int unlink_existingMeshData( Mesh * mesh );
static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh );
static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh, int store_edges );
/* <start> */
static PyObject *NMesh_printDebug( PyObject * self );
/* <end> */
static PyObject *NMesh_addEdge( PyObject * self, PyObject * args );
static PyObject *NMesh_findEdge( PyObject * self, PyObject * args );
static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args );
static PyObject *NMesh_addEdgesData( PyObject * self );
static PyObject *NMesh_addFace( PyObject * self, PyObject * args );
static PyObject *NMesh_removeFace( PyObject * self, PyObject * args );
static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args );
static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args );
static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args );
@@ -94,8 +104,37 @@ static PyObject *NMesh_removeVertsFromGroup( PyObject * self,
PyObject * args );
static PyObject *NMesh_getVertsFromGroup( PyObject * self, PyObject * args );
static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args );
static PyObject *NMesh_getVertGroupNames( PyObject * self, PyObject * args );
static PyObject *NMesh_getVertGroupNames( PyObject * self );
/* <start> */
static char NMesh_printDebug_doc[] =
"print debug info about the mesh.";
/* <end> */
static char NMesh_addEdge_doc[] =
"create an edge between two vertices.\n\
If an edge already exists between those vertices, it is returned. (in blender, only zero \
or one edge can link two vertices.\n\
Created edge is automatically added to edges list.";
static char NMesh_findEdge_doc[] =
"find an edge between two vertices.";
static char NMesh_removeEdge_doc[] =
"remove an edge between two vertices.\n\
All faces using this edge are removed from faces list.";
static char NMesh_addEdgesData_doc[] =
"add edges data to the mesh.";
static char NMesh_addFace_doc[] =
"add a face to face list and add to edge list (if edge data exists) necessary edges.";
static char NMesh_removeFace_doc[] =
"remove a face for face list and remove edges no more used by any other face (if \
edge data exists).";
static char NMesh_addVertGroup_doc[] =
"add a named and empty vertex(deform) Group to a mesh that has been linked\n\
@@ -202,8 +241,9 @@ specified by index. The list contains pairs with the \n\
bone name and the weight.";
static char NMesh_update_doc[] = "(recalc_normals = 0) - updates the Mesh.\n\
if recalc_normals is given and is equal to 1, normal vectors are recalculated.";
static char NMesh_update_doc[] = "(recalc_normals = 0, store_edges = 0) - updates the Mesh.\n\
if recalc_normals is given and is equal to 1, normal vectors are recalculated.\n\
if store_edges is given qnd is equal to 1, egdes data are stored.";
static char NMesh_getMode_doc[] =
"() - get the mode flags of this nmesh as an or'ed int value.";
@@ -242,10 +282,11 @@ This returns the mesh as used by the object, which\n\
means it contains all deformations and modifications.";
static char M_NMesh_PutRaw_doc[] =
"(mesh, [name, renormal]) - Return a raw mesh to Blender\n\n\
"(mesh, [name, renormal, store_edges]) - Return a raw mesh to Blender\n\n\
(mesh) The NMesh object to store\n\
[name] The mesh to replace\n\
[renormal=1] Flag to control vertex normal recalculation\n\n\
[renormal=1] Flag to control vertex normal recalculation\n\
[store_edges=0] Store edges data in the blender mesh\n\
If the name of a mesh to replace is not given a new\n\
object is created and returned.";
@@ -840,6 +881,109 @@ PyTypeObject NMVert_Type = {
&NMVert_SeqMethods, /*tp_as_sequence */
};
/*****************************
* NMEdge
*****************************/
static BPy_NMEdge *new_NMEdge( BPy_NMVert * v1, BPy_NMVert * v2, char crease, short flag)
{
BPy_NMEdge *edge=NULL;
if (!v1 || !v2) return NULL;
if (!BPy_NMVert_Check(v1) || !BPy_NMVert_Check(v2)) return NULL;
edge = PyObject_NEW( BPy_NMEdge, &NMEdge_Type );
edge->v1=EXPP_incr_ret((PyObject*)v1);
edge->v2=EXPP_incr_ret((PyObject*)v2);
edge->flag=flag;
edge->crease=crease;
return edge;
}
static void NMEdge_dealloc( PyObject * self )
{
BPy_NMEdge *edge=(BPy_NMEdge *)self;
Py_DECREF(edge->v1);
Py_DECREF(edge->v2);
PyObject_DEL(self);
}
static PyObject *NMEdge_getattr( PyObject * self, char *name )
{
BPy_NMEdge *edge=(BPy_NMEdge *)self;
if ( strcmp( name, "v1" ) == 0 )
return EXPP_incr_ret( edge->v1 );
else if ( strcmp( name, "v2" ) == 0 )
return EXPP_incr_ret( edge->v2 );
else if ( strcmp( name, "flag" ) == 0 )
return PyInt_FromLong( edge->flag );
else if ( strcmp( name, "crease" ) == 0 )
return PyInt_FromLong( edge->crease );
else if( strcmp( name, "__members__" ) == 0 )
return Py_BuildValue( "[s,s,s,s]",
"v1", "v2", "flag", "crease" );
return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
}
static int NMEdge_setattr( PyObject * self, char *name, PyObject * v )
{
BPy_NMEdge *edge=(BPy_NMEdge *)self;
if ( strcmp( name, "flag" ) == 0 )
{
short flag=0;
if( !PyInt_Check( v ) )
return EXPP_ReturnIntError( PyExc_TypeError,
"expected int argument" );
flag = ( short ) PyInt_AsLong( v );
edge->flag = flag;
return 0;
}
else if ( strcmp( name, "crease" ) == 0 )
{
char crease=0;
if( !PyInt_Check( v ) )
return EXPP_ReturnIntError( PyExc_TypeError,
"expected int argument" );
crease = ( char ) PyInt_AsLong( v );
edge->crease = crease;
return 0;
}
return EXPP_ReturnIntError( PyExc_AttributeError, name );
}
PyTypeObject NMEdge_Type = {
PyObject_HEAD_INIT( NULL )
0, /*ob_size */
"Blender NMEdge", /*tp_name */
sizeof( BPy_NMEdge ), /*tp_basicsize */
0, /*tp_itemsize */
/* methods */
( destructor ) NMEdge_dealloc, /*tp_dealloc */
( printfunc ) 0, /*tp_print */
( getattrfunc ) NMEdge_getattr, /*tp_getattr */
( setattrfunc ) NMEdge_setattr, /*tp_setattr */
};
static void NMesh_dealloc( PyObject * self )
{
BPy_NMesh *me = ( BPy_NMesh * ) self;
@@ -848,6 +992,7 @@ static void NMesh_dealloc( PyObject * self )
Py_DECREF( me->verts );
Py_DECREF( me->faces );
Py_DECREF( me->materials );
Py_XDECREF( me->edges );
PyObject_DEL( self );
}
@@ -1020,7 +1165,7 @@ static PyObject *NMesh_getSelectedFaces( PyObject * self, PyObject * args )
return l;
}
static PyObject *NMesh_getActiveFace( PyObject * self, PyObject * args )
static PyObject *NMesh_getActiveFace( PyObject * self )
{
if( ( ( BPy_NMesh * ) self )->sel_face < 0 )
return EXPP_incr_ret( Py_None );
@@ -1108,13 +1253,13 @@ static PyObject *NMesh_hasVertexColours( PyObject * self, PyObject * args )
static PyObject *NMesh_update( PyObject * self, PyObject * args )
{
int recalc_normals = 0;
int recalc_normals = 0, store_edges = 0;
BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
Mesh *mesh = nmesh->mesh;
if( !PyArg_ParseTuple( args, "|i", &recalc_normals ) )
if( !PyArg_ParseTuple( args, "|ii", &recalc_normals, &store_edges ) )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"expected nothing or an int (0 or 1) as argument" );
"expected nothing, one or two int(s) (0 or 1) as argument" );
if( recalc_normals && recalc_normals != 1 )
return EXPP_ReturnPyObjError( PyExc_ValueError,
@@ -1122,9 +1267,9 @@ static PyObject *NMesh_update( PyObject * self, PyObject * args )
if( mesh ) {
unlink_existingMeshData( mesh );
convert_NMeshToMesh( mesh, nmesh );
convert_NMeshToMesh( mesh, nmesh, store_edges );
} else {
nmesh->mesh = Mesh_fromNMesh( nmesh );
nmesh->mesh = Mesh_fromNMesh( nmesh, store_edges );
mesh = nmesh->mesh;
}
@@ -1215,7 +1360,7 @@ static PyObject *NMesh_getVertexInfluences( PyObject * self, PyObject * args )
return influence_list;
}
Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh )
Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh , int store_edges )
{
Mesh *mesh = NULL;
mesh = add_mesh( );
@@ -1226,26 +1371,11 @@ Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh )
mesh->id.us = 0; /* no user yet */
G.totmesh++;
convert_NMeshToMesh( mesh, nmesh );
convert_NMeshToMesh( mesh, nmesh, store_edges );
return mesh;
}
PyObject *NMesh_link( PyObject * self, PyObject * args )
{ /*
BPy_Object *bl_obj;
if (!PyArg_ParseTuple(args, "O!", &Object_Type, &bl_obj))
return EXPP_ReturnPyErrorObj (PyExc_TypeError,
"NMesh can only be linked to Objects");
bl_obj->data = (PyObject *)self; */
/* Better use object.link(nmesh), no need for this nmesh.link(object) */
return EXPP_incr_ret( Py_None );
}
static PyObject *NMesh_getMaxSmoothAngle( BPy_NMesh * self )
{
PyObject *attr = PyInt_FromLong( self->smoothresh );
@@ -1353,21 +1483,25 @@ static PyObject *NMesh_setMode( PyObject * self, PyObject * args )
return Py_None;
}
/* METH_VARARGS: function(PyObject *self, PyObject *args) */
#undef MethodDef
#define MethodDef(func) {#func, NMesh_##func, METH_VARARGS, NMesh_##func##_doc}
static struct PyMethodDef NMesh_methods[] = {
MethodDef( addEdge ),
MethodDef( findEdge ),
MethodDef( removeEdge ),
MethodDef( addFace ),
MethodDef( removeFace ),
MethodDef( addVertGroup ),
MethodDef( removeVertGroup ),
MethodDef( assignVertsToGroup ),
MethodDef( removeVertsFromGroup ),
MethodDef( getVertsFromGroup ),
MethodDef( renameVertGroup ),
MethodDef( getVertGroupNames ),
MethodDef( hasVertexColours ),
MethodDef( hasFaceUV ),
MethodDef( hasVertexUV ),
MethodDef( getActiveFace ),
MethodDef( getSelectedFaces ),
MethodDef( getVertexInfluences ),
MethodDef( getMaterials ),
@@ -1379,13 +1513,19 @@ static struct PyMethodDef NMesh_methods[] = {
MethodDef( setMode ),
MethodDef( setMaxSmoothAngle ),
MethodDef( setSubDivLevels ),
{"getMode", ( PyCFunction ) NMesh_getMode, METH_NOARGS,
NMesh_getMode_doc},
{"getMaxSmoothAngle", ( PyCFunction ) NMesh_getMaxSmoothAngle,
METH_NOARGS,
NMesh_getMaxSmoothAngle_doc},
{"getSubDivLevels", ( PyCFunction ) NMesh_getSubDivLevels, METH_NOARGS,
NMesh_getSubDivLevels_doc},
/* METH_NOARGS: function(PyObject *self) */
#undef MethodDef
#define MethodDef(func) {#func, (PyCFunction)NMesh_##func, METH_NOARGS,\
NMesh_##func##_doc}
MethodDef( printDebug ),
MethodDef( addEdgesData ),
MethodDef( getVertGroupNames ),
MethodDef( getActiveFace ),
MethodDef( getMode ),
MethodDef( getMaxSmoothAngle ),
MethodDef( getSubDivLevels ),
{NULL, NULL, 0, NULL}
};
@@ -1425,11 +1565,18 @@ static PyObject *NMesh_getattr( PyObject * self, char *name )
else if( strcmp( name, "faces" ) == 0 )
return EXPP_incr_ret( me->faces );
else if( strcmp( name, "edges" ) == 0 )
{
if (me->edges)
return EXPP_incr_ret( me->edges );
else
return EXPP_incr_ret( Py_None );
}
else if( strcmp( name, "__members__" ) == 0 )
return Py_BuildValue( "[s,s,s,s,s,s,s]",
return Py_BuildValue( "[s,s,s,s,s,s,s,s]",
"name", "materials", "verts", "users",
"faces", "maxSmoothAngle",
"subdivLevels" );
"subdivLevels", "edges" );
return Py_FindMethod( NMesh_methods, ( PyObject * ) self, name );
}
@@ -1529,7 +1676,20 @@ static int NMesh_setattr( PyObject * self, char *name, PyObject * v )
"couldn't retrieve subdiv values from list" );
}
}
else if( strcmp( name, "edges" ) == 0 )
{
if (me->edges)
{
if (PySequence_Check(v))
{
Py_DECREF(me->edges);
me->edges = EXPP_incr_ret( v );
}
}
else
return EXPP_ReturnIntError( PyExc_RuntimeError,
"mesh has no edge information" );
}
else
return EXPP_ReturnIntError( PyExc_AttributeError, name );
@@ -1611,9 +1771,15 @@ static BPy_NMFace *nmface_from_data( BPy_NMesh * mesh, int vidxs[4],
return newf;
}
static BPy_NMVert *nmvert_from_data( BPy_NMesh * me,
MVert * vert, MSticky * st, float *co,
int idx, char flag )
static BPy_NMEdge *nmedge_from_data( BPy_NMesh * mesh, MEdge *edge )
{
BPy_NMVert *v1=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v1 );
BPy_NMVert *v2=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v2 );
return new_NMEdge(v1, v2, edge->crease, edge->flag);
}
static BPy_NMVert *nmvert_from_data( MVert * vert, MSticky * st, float *co,
int idx, char flag )
{
BPy_NMVert *mv = PyObject_NEW( BPy_NMVert, &NMVert_Type );
@@ -1667,6 +1833,7 @@ static PyObject *new_NMesh_internal( Mesh * oldmesh,
me->subdiv[0] = NMESH_SUBDIV;
me->subdiv[1] = NMESH_SUBDIV;
me->smoothresh = NMESH_SMOOTHRESH;
me->edges = NULL; /* no edge data by default */
me->object = NULL; /* not linked to any object yet */
@@ -1682,7 +1849,8 @@ static PyObject *new_NMesh_internal( Mesh * oldmesh,
MFace *mfaces;
TFace *tfaces;
MCol *mcols;
int i, totvert, totface;
MEdge *medges;
int i, totvert, totface, totedge;
if( dlm ) {
me->name = EXPP_incr_ret( Py_None );
@@ -1694,9 +1862,11 @@ static PyObject *new_NMesh_internal( Mesh * oldmesh,
mfaces = dlm->mface;
tfaces = dlm->tface;
mcols = dlm->mcol;
medges = dlm->medge;
totvert = dlm->totvert;
totface = dlm->totface;
totedge = dlm->totedge;
} else {
me->name = PyString_FromString( oldmesh->id.name + 2 );
me->mesh = oldmesh;
@@ -1710,9 +1880,11 @@ static PyObject *new_NMesh_internal( Mesh * oldmesh,
mfaces = oldmesh->mface;
tfaces = oldmesh->tface;
mcols = oldmesh->mcol;
medges = oldmesh->medge;
totvert = oldmesh->totvert;
totface = oldmesh->totface;
totedge = oldmesh->totedge;
me->sel_face = get_active_faceindex( oldmesh );
}
@@ -1732,8 +1904,7 @@ static PyObject *new_NMesh_internal( Mesh * oldmesh,
float *vco = extverts ? &extverts[i * 3] : oldmv->co;
PyList_SetItem( me->verts, i,
( PyObject * ) nmvert_from_data( me,
oldmv,
( PyObject * ) nmvert_from_data( oldmv,
oldst,
vco,
i,
@@ -1762,6 +1933,17 @@ static PyObject *new_NMesh_internal( Mesh * oldmesh,
oldtf,
oldmc ) );
}
if (medges)
{
me->edges = PyList_New( totedge );
for( i = 0; i < totedge; i++ )
{
MEdge *edge = &medges[i];
PyList_SetItem( me->edges, i, (PyObject*)nmedge_from_data ( me, edge ) );
}
}
me->materials =
EXPP_PyList_fromMaterialList( oldmesh->mat,
oldmesh->totcol, 0 );
@@ -2170,7 +2352,93 @@ PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob )
return EXPP_incr_ret( Py_None );
}
static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh )
static void fill_medge_from_nmesh(Mesh * mesh, BPy_NMesh * nmesh)
{
int i,j;
MEdge *faces_edges=NULL;
int tot_faces_edges=0;
int tot_valid_faces_edges=0;
int nmeshtotedges=PyList_Size(nmesh->edges);
int tot_valid_nmedges=0;
BPy_NMEdge **valid_nmedges=NULL;
valid_nmedges=MEM_callocN(nmeshtotedges*sizeof(BPy_NMEdge *), "make BPy_NMEdge");
/* First compute the list of edges that exists because faces exists */
make_edges(mesh);
faces_edges=mesh->medge;
tot_faces_edges=mesh->totedge;
tot_valid_faces_edges=tot_faces_edges;
mesh->medge=NULL;
mesh->totedge = 0;
/* Flag each edge in faces_edges that is already in nmesh->edges list.
* Flaging an edge means MEdge v1=v2=0.
* Each time an edge is flagged, tot_valid_faces_edges is decremented.
*
* Also store in valid_nmedges pointers to each valid NMEdge in nmesh->edges.
* An invalid NMEdge is an edge that has a vertex that is not in the vertices
* list. Ie its index is -1.
* Each time an valid NMEdge is flagged, tot_valid_nmedges is incremented.
*/
for( i = 0; i < nmeshtotedges; ++i )
{
int v1idx,v2idx;
BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i);
BPy_NMVert *v=(BPy_NMVert *)edge->v1;
v1idx=v->index;
v=(BPy_NMVert *)edge->v2;
v2idx=v->index;
if (-1 == v1idx || -1 == v2idx) continue;
valid_nmedges[tot_valid_nmedges]=edge;
++tot_valid_nmedges;
for( j = 0; j < tot_faces_edges; j++ )
{
MEdge *me=faces_edges+j;
if ( ((int)me->v1==v1idx && (int)me->v2==v2idx) ||
((int)me->v1==v2idx && (int)me->v2==v1idx) )
{
me->v1=0; me->v2=0;
--tot_valid_faces_edges;
}
}
}
/* Now we have the total count of valid edges */
mesh->totedge=tot_valid_nmedges+tot_valid_faces_edges;
mesh->medge=MEM_callocN(mesh->totedge*sizeof(MEdge), "make mesh edges");
for ( i = 0; i < tot_valid_nmedges; ++i )
{
BPy_NMEdge *edge=valid_nmedges[i];
MEdge *medge=mesh->medge+i;
int v1=((BPy_NMVert *)edge->v1)->index;
int v2=((BPy_NMVert *)edge->v2)->index;
medge->v1=v1;
medge->v2=v2;
medge->flag=edge->flag;
medge->crease=edge->crease;
}
for ( i = 0, j = tot_valid_nmedges; i < tot_faces_edges; ++i )
{
MEdge *edge=faces_edges+i;
if (edge->v1!=0 || edge->v2!=0) // valid edge
{
MEdge *medge=mesh->medge+j;
medge->v1=edge->v1;
medge->v2=edge->v2;
medge->flag=ME_EDGEDRAW;
medge->crease=0;
++j;
}
}
MEM_freeN( valid_nmedges );
MEM_freeN( faces_edges );
}
static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh, int store_edges)
{
MFace *newmf;
TFace *newtf;
@@ -2187,6 +2455,7 @@ static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh )
mesh->msticky = NULL;
mesh->tface = NULL;
mesh->mat = NULL;
mesh->medge = NULL;
/* Minor note: we used 'mode' because 'flag' was already used internally
* by nmesh */
@@ -2257,6 +2526,19 @@ static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh )
Py_DECREF( mf );
}
/* do the same for edges if there is edge data */
if (nmesh->edges)
{
int nmeshtotedges=PyList_Size(nmesh->edges);
for( i = 0; i < nmeshtotedges; ++i )
{
BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i);
BPy_NMVert *v=(BPy_NMVert *)edge->v1;
v->index=-1;
v=(BPy_NMVert *)edge->v2;
v->index=-1;
}
}
for( i = 0; i < mesh->totvert; i++ ) {
BPy_NMVert *mv =
@@ -2317,6 +2599,15 @@ static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh )
}
}
/* After face data has been written, write edge data.
* Edge data are not stored before face ones since we need
* mesh->mface to be correctly initialized.
*/
if (nmesh->edges && store_edges)
{
fill_medge_from_nmesh(mesh, nmesh);
}
return 1;
}
@@ -2327,11 +2618,12 @@ static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args )
Object *ob = NULL;
BPy_NMesh *nmesh;
int recalc_normals = 1;
int store_edges = 0;
if( !PyArg_ParseTuple( args, "O!|si",
&NMesh_Type, &nmesh, &name, &recalc_normals ) )
if( !PyArg_ParseTuple( args, "O!|sii",
&NMesh_Type, &nmesh, &name, &recalc_normals, &store_edges ) )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"expected an NMesh object and optionally also a string and an int" );
"expected an NMesh object and optionally also a string and two ints" );
if( !PySequence_Check( nmesh->verts ) )
return EXPP_ReturnPyObjError( PyExc_AttributeError,
@@ -2376,7 +2668,7 @@ static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args )
PyString_AsString( nmesh->name ) );
unlink_existingMeshData( mesh );
convert_NMeshToMesh( mesh, nmesh );
convert_NMeshToMesh( mesh, nmesh, store_edges );
nmesh->mesh = mesh;
if( recalc_normals )
@@ -2524,6 +2816,22 @@ static PyObject *M_NMesh_FaceTranspModesDict( void )
return FTM;
}
static PyObject *M_NMesh_EdgeFlagsDict( void )
{
PyObject *EF = M_constant_New( );
if( EF ) {
BPy_constant *d = ( BPy_constant * ) EF;
constant_insert(d, "SELECT", PyInt_FromLong(1));
constant_insert(d, "EDGEDRAW", PyInt_FromLong(ME_EDGEDRAW));
constant_insert(d, "SEAM", PyInt_FromLong(ME_SEAM));
constant_insert(d, "FGON", PyInt_FromLong(ME_FGON));
}
return EF;
}
PyObject *NMesh_Init( void )
{
PyObject *submodule;
@@ -2532,6 +2840,7 @@ PyObject *NMesh_Init( void )
PyObject *FaceFlags = M_NMesh_FaceFlagsDict( );
PyObject *FaceModes = M_NMesh_FaceModesDict( );
PyObject *FaceTranspModes = M_NMesh_FaceTranspModesDict( );
PyObject *EdgeFlags = M_NMesh_EdgeFlagsDict( );
NMCol_Type.ob_type = &PyType_Type;
NMFace_Type.ob_type = &PyType_Type;
@@ -2551,6 +2860,8 @@ PyObject *NMesh_Init( void )
if( FaceTranspModes )
PyModule_AddObject( submodule, "FaceTranspModes",
FaceTranspModes );
if( EdgeFlags )
PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags );
g_nmeshmodule = submodule;
return submodule;
@@ -2581,29 +2892,376 @@ Mesh *Mesh_FromPyObject( PyObject * pyobj, Object * ob )
if( nmesh->mesh ) {
mesh = nmesh->mesh;
unlink_existingMeshData( mesh );
convert_NMeshToMesh( mesh, nmesh );
} else {
nmesh->mesh = Mesh_fromNMesh( nmesh );
nmesh->mesh = Mesh_fromNMesh( nmesh, 1 );
mesh = nmesh->mesh;
}
nmesh->object = ob; /* linking for vgrouping methods */
nmesh->object = ob; /* linking for vgrouping methods */
if( nmesh->name && nmesh->name != Py_None )
new_id( &( G.main->mesh ), &mesh->id,
PyString_AsString( nmesh->name ) );
if( nmesh->name && nmesh->name != Py_None )
new_id( &( G.main->mesh ), &mesh->id,
PyString_AsString( nmesh->name ) );
mesh_update( mesh );
nmesh_updateMaterials( nmesh );
mesh_update( mesh );
nmesh_updateMaterials( nmesh );
}
return mesh;
}
return NULL;
}
#define POINTER_CROSS_EQ(a1, a2, b1, b2) (((a1)==(b1) && (a2)==(b2)) || ((a1)==(b2) && (a2)==(b1)))
static PyObject *findEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int create)
{
int i;
for ( i = 0; i < PyList_Size(nmesh->edges); ++i )
{
BPy_NMEdge *edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i );
if (!BPy_NMEdge_Check(edge)) continue;
if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) )
{
return EXPP_incr_ret((PyObject*)edge);
}
}
/* if this line is reached, edge has not been found */
if (create)
{
PyObject *newEdge=(PyObject *)new_NMEdge(v1, v2, 0, ME_EDGEDRAW);
PyList_Append(nmesh->edges, newEdge);
return newEdge;
}
else
return EXPP_incr_ret( Py_None );
}
static void removeEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int ununsedOnly)
{
int i,j;
BPy_NMEdge *edge=NULL;
int edgeUsedByFace=0;
int totedge=PyList_Size(nmesh->edges);
/* find the edge in the edge list */
for ( i = 0; i < totedge; ++i )
{
edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i );
if (!BPy_NMEdge_Check(edge)) continue;
if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) )
{
break;
}
}
if (i==totedge || !edge) // edge not found
return;
for ( j = PyList_Size(nmesh->faces)-1; j >= 0 ; --j )
{
BPy_NMFace *face=(BPy_NMFace *)PyList_GetItem(nmesh->faces, j);
int k, del_face=0;
int totv;
if (!BPy_NMFace_Check(face)) continue;
totv=PyList_Size(face->v);
if (totv<2) continue;
for ( k = 0; k < totv && !del_face; ++k )
{
BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
if ( POINTER_CROSS_EQ(v1, v2, fe_v1, fe_v2) )
{
edgeUsedByFace=1;
del_face=1;
}
}
if (del_face && !ununsedOnly)
{
PySequence_DelItem(nmesh->faces, j);
}
}
if (!ununsedOnly || (ununsedOnly && !edgeUsedByFace) )
PySequence_DelItem(nmesh->edges, PySequence_Index(nmesh->edges, (PyObject*)edge));
}
static PyObject *NMesh_addEdge( PyObject * self, PyObject * args )
{
BPy_NMesh *bmesh=(BPy_NMesh *)self;
BPy_NMVert *v1=NULL, *v2=NULL;
if (!bmesh->edges)
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
"NMesh has no edge data." );
if (!PyArg_ParseTuple
( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected NMVert, NMVert" );
}
if (v1==v2)
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"vertices must be different" );
return findEdge(bmesh, v1, v2, 1);
}
static PyObject *NMesh_findEdge( PyObject * self, PyObject * args )
{
BPy_NMesh *bmesh=(BPy_NMesh *)self;
BPy_NMVert *v1=NULL, *v2=NULL;
if (!bmesh->edges)
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
"NMesh has no edge data." );
if (!PyArg_ParseTuple
( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected NMVert, NMVert" );
}
if (v1==v2)
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"vertices must be different" );
return findEdge(bmesh, v1, v2, 0);
}
static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args )
{
BPy_NMesh *bmesh=(BPy_NMesh *)self;
BPy_NMVert *v1=NULL, *v2=NULL;
if (!bmesh->edges)
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
"NMesh has no edge data." );
if (!PyArg_ParseTuple
( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected NMVert, NMVert" );
}
if (v1==v2)
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"vertices must be different" );
removeEdge(bmesh, v1, v2, 0);
return EXPP_incr_ret( Py_None );
}
static PyObject *NMesh_addEdgesData( PyObject * self )
{
/* Here we uses make_edges to create edges data.
* Since Mesh corresponding to NMesh may not content the same data as
* the NMesh and since maybe the NMesh has been created from scratch,
* we creates a temporary Mesh to use to call make_edges
*/
BPy_NMesh *nmesh=(BPy_NMesh *)self;
Mesh *tempMesh=NULL;
int i;
if (nmesh->edges)
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
"NMesh has already edge data." );
tempMesh=MEM_callocN(sizeof(Mesh), "temp mesh");
convert_NMeshToMesh(tempMesh, nmesh, 0);
make_edges(tempMesh);
nmesh->edges = PyList_New( tempMesh->totedge );
for( i = 0; i < tempMesh->totedge; ++i )
{
MEdge *edge = (tempMesh->medge) + i;
/* By using nmedge_from_data, an important assumption is made:
* every vertex in nmesh has been written in tempMesh in the same order
* than in nmesh->verts.
* Actually this assumption is needed since nmedge_from_data get the
* two NMVert for the newly created edge by using a PyList_GetItem with
* the indices stored in edge. Those indices are valid for nmesh only if
* nmesh->verts and tempMesh->mvert are identical (same number of vertices
* in same order).
*/
PyList_SetItem( nmesh->edges, i, (PyObject*)nmedge_from_data ( nmesh, edge ) );
}
unlink_existingMeshData(tempMesh);
MEM_freeN(tempMesh);
return EXPP_incr_ret( Py_None );
}
static PyObject *NMesh_addFace( PyObject * self, PyObject * args )
{
BPy_NMesh *nmesh=(BPy_NMesh *)self;
BPy_NMFace *face;
int totv=0;
if (!PyArg_ParseTuple
( args, "O!", &NMFace_Type, &face ) ) {
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected NMFace argument" );
}
totv=PyList_Size(face->v);
/*
* Before edges data exists, having faces with two vertices was
* the only way of storing edges not attached to any face.
*/
if (totv!=2 || !nmesh->edges)
PyList_Append(nmesh->faces, (PyObject*)face);
if (nmesh->edges)
{
if (totv>=2)
{
/* when totv==2, there is only one edge, when totv==3 there is three edges
* and when totv==4 there is four edges.
* that's why in the following line totv==2 is a special case */
PyObject *edges = PyList_New((totv==2) ? 1 : totv);
if (totv==2)
{
BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0);
BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1);
BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1);
PyList_SetItem(edges, 0, (PyObject*)edge); // PyList_SetItem steals the reference
}
else
{
int k;
for ( k = 0; k < totv; ++k )
{
BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1);
PyList_SetItem(edges, k, (PyObject*)edge); // PyList_SetItem steals the reference
}
}
return edges;
}
}
return EXPP_incr_ret( Py_None );
}
static PyObject *NMesh_removeFace( PyObject * self, PyObject * args )
{
BPy_NMesh *nmesh=(BPy_NMesh *)self;
BPy_NMFace *face;
int totv=0;
if (!PyArg_ParseTuple
( args, "O!", &NMFace_Type, &face ) ) {
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected NMFace argument" );
}
totv=PyList_Size(face->v);
{
int index=PySequence_Index(nmesh->faces, (PyObject*)face);
if (index>=0)
PySequence_DelItem(nmesh->faces, index);
}
if (nmesh->edges)
{
if (totv>=2)
{
/* when totv==2, there is only one edge, when totv==3 there is three edges
* and when totv==4 there is four edges.
* that's why in the following line totv==2 is a special case */
if (totv==2)
{
BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0);
BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1);
removeEdge(nmesh, fe_v1, fe_v2, 1);
}
else
{
int k;
for ( k = 0; k < totv; ++k )
{
BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
removeEdge(nmesh, fe_v1, fe_v2, 1);
}
}
}
}
return EXPP_incr_ret( Py_None );
}
/* <start> */
static PyObject *NMesh_printDebug( PyObject * self )
{
BPy_NMesh *bmesh=(BPy_NMesh *)self;
Mesh *mesh=bmesh->mesh;
printf("**Vertices\n");
{
int i;
for (i=0; i<mesh->totvert; ++i)
{
MVert *v=mesh->mvert+i;
double x=v->co[0];
double y=v->co[1];
double z=v->co[2];
printf(" %2d : %.3f %.3f %.3f\n", i, x, y, z);
}
}
printf("**Edges\n");
if (mesh->medge)
{
int i;
for (i=0; i<mesh->totedge; ++i)
{
MEdge *e=mesh->medge+i;
int v1 = e->v1;
int v2 = e->v2;
int flag = e->flag;
printf(" %2d : %2d %2d flag=%d\n", i, v1, v2, flag);
}
}
else
printf(" No edge informations\n");
printf("**Faces\n");
{
int i;
for (i=0; i<mesh->totface; ++i)
{
MFace *e=((MFace*)(mesh->mface))+i;
int v1 = e->v1;
int v2 = e->v2;
int v3 = e->v3;
int v4 = e->v4;
printf(" %2d : %2d %2d %2d %2d\n", i, v1, v2, v3, v4);
}
}
return EXPP_incr_ret( Py_None );
}
/* <end> */
static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args )
{
char *groupStr;
@@ -3024,7 +3682,8 @@ static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args )
return EXPP_incr_ret( Py_None );
}
static PyObject *NMesh_getVertGroupNames( PyObject * self, PyObject * args )
static PyObject *NMesh_getVertGroupNames( PyObject * self )
{
bDeformGroup *defGroup;
PyObject *list;

View File

@@ -52,6 +52,7 @@ extern PyTypeObject NMesh_Type;
extern PyTypeObject NMFace_Type;
extern PyTypeObject NMVert_Type;
extern PyTypeObject NMCol_Type;
extern PyTypeObject NMEdge_Type;
struct BPy_Object;
@@ -71,6 +72,7 @@ void remove_vert_def_nr( Object * ob, int def_nr, int vertnum );
#define BPy_NMFace_Check(v) ((v)->ob_type == &NMFace_Type)
#define BPy_NMVert_Check(v) ((v)->ob_type == &NMVert_Type)
#define BPy_NMCol_Check(v) ((v)->ob_type == &NMCol_Type)
#define BPy_NMEdge_Check(v) ((v)->ob_type == &NMEdge_Type)
/* Typedefs for the new types */
@@ -103,6 +105,14 @@ typedef struct {
} BPy_NMFace; /* an NMesh face */
typedef struct {
PyObject_HEAD /* required python macro */
PyObject *v1;
PyObject *v2;
char crease;
short flag;
} BPy_NMEdge; /* an NMesh edge */
typedef struct {
PyObject_HEAD /* required python macro */
Mesh * mesh;
@@ -111,6 +121,7 @@ typedef struct {
PyObject *materials;
PyObject *verts;
PyObject *faces;
PyObject *edges;
int sel_face; /*@ XXX remove */
short smoothresh; /* max AutoSmooth angle */
short subdiv[2]; /* SubDiv Levels: display and rendering */
@@ -134,7 +145,7 @@ int NMesh_CheckPyObject( PyObject * pyobj );
void mesh_update( Mesh * mesh );
PyObject *new_NMesh( Mesh * oldmesh );
Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh );
Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh , int store_edges );
PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob );
Material **nmesh_updateMaterials( BPy_NMesh * nmesh );
Material **newMaterialList_fromPyList( PyObject * list );

View File

@@ -25,7 +25,7 @@
*
* This is a new part of Blender.
*
* Contributor(s): Willian P. Germano, Tom Musgrove
* Contributor(s): Willian P. Germano, Tom Musgrove, Michael Reimpell, Yann Vernier
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
@@ -68,7 +68,7 @@
extern int EXPP_disable_force_draw;
/* Callback used by the file and image selector access functions */
static PyObject *( *EXPP_FS_PyCallback ) ( PyObject * arg ) = NULL;
static PyObject *EXPP_FS_PyCallback = NULL;
/*****************************************************************************/
/* Python API function prototypes for the Window module. */
@@ -452,13 +452,24 @@ static PyObject *M_Window_QRedrawAll( PyObject * self, PyObject * args )
static void getSelectedFile( char *name )
{
if( !EXPP_FS_PyCallback )
return;
PyObject_CallFunction( ( PyObject * ) EXPP_FS_PyCallback, "s", name );
EXPP_FS_PyCallback = NULL;
PyObject *callback;
PyObject *result;
callback = EXPP_FS_PyCallback;
result = PyObject_CallFunction( EXPP_FS_PyCallback, "s", name );
if ((!result) && (G.f & G_DEBUG)) {
fprintf(stderr, "BPy error: Callback call failed!\n");
}
Py_XDECREF(result);
/* Catch changes of EXPP_FS_PyCallback during the callback call
* due to calls to Blender.Window.FileSelector or
* Blender.Window.ImageSelector inside the python callback. */
if (callback == EXPP_FS_PyCallback) {
Py_DECREF(EXPP_FS_PyCallback);
EXPP_FS_PyCallback = NULL;
} else {
Py_DECREF(callback);
}
return;
}
@@ -470,12 +481,12 @@ static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args )
Script *script = G.main->script.last;
int startspace = 0;
if( !PyArg_ParseTuple( args, "O!|ss",
&PyFunction_Type, &EXPP_FS_PyCallback, &title,
&filename ) )
if( (!PyArg_ParseTuple( args, "O|ss", &EXPP_FS_PyCallback, &title, &filename ) )
|| (!PyCallable_Check(EXPP_FS_PyCallback)))
return EXPP_ReturnPyObjError( PyExc_AttributeError,
"\nexpected a callback function (and optionally one or two strings) "
"as argument(s)" );
Py_XINCREF(EXPP_FS_PyCallback);
/* trick: we move to a spacescript because then the fileselector will properly
* unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the
@@ -514,13 +525,13 @@ static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args )
Script *script = G.main->script.last;
int startspace = 0;
if( !PyArg_ParseTuple( args, "O!|ss",
&PyFunction_Type, &EXPP_FS_PyCallback, &title,
&filename ) )
if( !PyArg_ParseTuple( args, "O|ss", &EXPP_FS_PyCallback, &title, &filename )
|| (!PyCallable_Check(EXPP_FS_PyCallback)))
return ( EXPP_ReturnPyObjError
( PyExc_AttributeError,
"\nexpected a callback function (and optionally one or two strings) "
"as argument(s)" ) );
Py_XINCREF(EXPP_FS_PyCallback);
/* trick: we move to a spacescript because then the fileselector will properly
* unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the

View File

@@ -68,6 +68,8 @@ static PyObject *World_setIpo( BPy_World * self, PyObject * args );
static PyObject *World_clearIpo( BPy_World * self );
static PyObject *World_getName( BPy_World * self );
static PyObject *World_setName( BPy_World * self, PyObject * args );
static PyObject *World_getMode( BPy_World * self );
static PyObject *World_setMode( BPy_World * self, PyObject * args );
static PyObject *World_getSkytype( BPy_World * self );
static PyObject *World_setSkytype( BPy_World * self, PyObject * args );
static PyObject *World_getMistype( BPy_World * self );
@@ -162,7 +164,11 @@ static PyMethodDef BPy_World_methods[] = {
{"getName", ( PyCFunction ) World_getName, METH_NOARGS,
"() - Return World Data name"},
{"setName", ( PyCFunction ) World_setName, METH_VARARGS,
"() - Return World Data name"},
"() - Set World Data name"},
{"getMode", ( PyCFunction ) World_getMode, METH_NOARGS,
"() - Return World Data mode"},
{"setMode", ( PyCFunction ) World_setMode, METH_VARARGS,
"(i) - Set World Data mode"},
{"getSkytype", ( PyCFunction ) World_getSkytype, METH_NOARGS,
"() - Return World Data skytype"},
{"setSkytype", ( PyCFunction ) World_setSkytype, METH_VARARGS,

View File

@@ -66,6 +66,11 @@ Example::
- ADD - add to background (halo).
- ALPHA - draw with transparency.
- SUB - subtract from background.
@var EdgeFlags: The available edge flags.
- SELECT - selected.
- EDGEDRAW - edge is drawn out of edition mode.
- SEAM - edge is a seam for LSCM UV unwrapping
- FGON - edge is part of a F-Gon.
"""
def Col(col = [255, 255, 255, 255]):
@@ -139,16 +144,18 @@ def GetRawFromObject(name):
be created.
"""
def PutRaw(nmesh, name = None, recalculate_normals = 1):
def PutRaw(nmesh, name = None, recalculate_normals = 1, store_edges = 0):
"""
Put an NMesh object back in Blender.
@type nmesh: NMesh
@type name: string
@type recalculate_normals: int
@type store_edges: int
@param name: The name of the mesh data object in Blender which will receive
this nmesh data. It can be an existing mesh data object or a new one.
@param recalculate_normals: If non-zero, the vertex normals for the mesh will
be recalculated.
@param store_edges: if non-zero, the edges data are stored
@rtype: None or Object
@return: It depends on the 'name' parameter:
- I{name} refers to an existing mesh data obj already linked to an
@@ -193,6 +200,21 @@ class NMVert:
each face can be independently mapped to any part of its texture.
"""
class NMEdge:
"""
The NMEdge object
=================
This object holds mesh edge data.
@type v1: NMVert
@cvar v1: The first vertex of the edge.
@type v2: NMVert
@cvar v2: The second vertex of the edge.
@type crease: int
@cvar crease: The crease value of the edge. It is in the range [0,255].
@type flag: int
@cvar flag: The bitmask describing edge properties. See L{NMesh.EdgeFlags<EdgeFlags>}.
"""
class NMFace:
"""
The NMFace object
@@ -264,11 +286,71 @@ class NMesh:
@cvar verts: The list of NMesh vertices (NMVerts).
@cvar users: The number of Objects using (linked to) this mesh.
@cvar faces: The list of NMesh faces (NMFaces).
@cvar edges: None if mesh has no edge data, else a list of L{NMEdge} edges. Use L{addEdgesData} to create edge data if it do not exist.
@cvar mode: The mode flags for this mesh. See L{setMode}.
@cvar subDivLevels: The [display, rendering] subdivision levels in [1, 6].
@cvar maxSmoothAngle: The max angle for auto smoothing. See L{setMode}.
"""
def addEdge(v1, v2):
"""
Create an edge between two vertices.
If an edge already exists between those vertices, it is returned. (in blender, only zero or one edge can link two vertices).
Created edge is automatically added to edges list.
You can only call this method if mesh has edge data.
@type v1: NMVert
@param v1: the first vertex of the edge.
@type v2: NMVert
@param v2: the second vertex of the edge.
@rtype: NMEdge
@return: The created or already existing edge.
"""
def findEdge(v1, v2):
"""
Try to find an edge between two vertices.
If no edge exists between v1 and v2, None is returned.
You can only call this method if mesh has edge data.
@type v1: NMVert
@param v1: the first vertex of the edge.
@type v2: NMVert
@param v2: the second vertex of the edge.
@rtype: NMEdge
@return: The found edge. None if no edge was found.
"""
def removeEdge():
"""
remove an edge between two vertices.
All faces using this edge are removed from faces list.
You can only call this method if mesh has edge data.
@type v1: NMVert
@param v1: the first vertex of the edge.
@type v2: NMVert
@param v2: the second vertex of the edge.
"""
def addFace(face):
"""
Add a face to face list and add to edge list (if edge data exists) necessary edges.
@type face: NMFace
@param face: the face to add to the mesh.
@rtype: list of NMEdge
@return: If mesh has edge data, return the list of face edges.
"""
def removeFace():
"""
Remove a face for face list and remove edges no more used by any other face (if edge data exists).
@type face: NMFace
@param face: the face to add to the mesh.
"""
def addEdgesData():
"""
If edge data does not exist for the mesh (ie L{edges}==None), then create them.
"""
def addMaterial(material):
"""
Add a new material to this NMesh's list of materials. This method is the
@@ -412,7 +494,7 @@ class NMesh:
add them.
"""
def update(recalc_normals = 0):
def update(recalc_normals = 0, store_edges = 0):
"""
Update the mesh in Blender. The changes made are put back to the mesh in
Blender, if available, or put in a newly created mesh object if this NMesh
@@ -420,6 +502,8 @@ class NMesh:
@type recalc_normals: int
@param recalc_normals: If given and equal to 1, the vertex normals are
recalculated.
@type store_edges: int
@param store_edges: if not 0, then edge data are stored.
@note: if your mesh disappears after it's updated, try
L{Object.Object.makeDisplayList}. 'Subsurf' meshes (see L{getMode},
L{setMode}) need their display lists updated, too.