Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillian Padovani Germano <wpgermano@gmail.com>2005-01-22 05:48:03 +0300
committerWillian Padovani Germano <wpgermano@gmail.com>2005-01-22 05:48:03 +0300
commit1da3b9f517103f6e04312faf08ca7c71edf7d0dd (patch)
tree62fe0e630b657710eff98a11499d1a61ef77fb5e
parent5822d4601d7cf93155442ab653b54d3e3c03cae5 (diff)
BPython:
- 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!
-rw-r--r--release/scripts/bvh_import.py114
-rw-r--r--release/scripts/tex2uvbaker.py97
-rw-r--r--source/blender/python/BPY_menus.c6
-rw-r--r--source/blender/python/api2_2x/NMesh.c789
-rw-r--r--source/blender/python/api2_2x/NMesh.h13
-rw-r--r--source/blender/python/api2_2x/Window.c41
-rw-r--r--source/blender/python/api2_2x/World.c8
-rw-r--r--source/blender/python/api2_2x/doc/NMesh.py88
8 files changed, 1009 insertions, 147 deletions
diff --git a/release/scripts/bvh_import.py b/release/scripts/bvh_import.py
index 3d29dc926c8..8c39d32eb8f 100644
--- a/release/scripts/bvh_import.py
+++ b/release/scripts/bvh_import.py
@@ -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")
diff --git a/release/scripts/tex2uvbaker.py b/release/scripts/tex2uvbaker.py
index 7a172ee5868..1e46e06475c 100644
--- a/release/scripts/tex2uvbaker.py
+++ b/release/scripts/tex2uvbaker.py
@@ -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:
@@ -249,6 +278,10 @@ def Mesh2UVCoord ():
print XYLIMIT
MESH2.update()
+ MESH2.insertKey (1, 'absolute')
+ MESH2.update()
+
+ MESH2.update()
MESH2.insertKey (FRAME, 'absolute')
MESH2.update()
imagename = 'uvtext'
@@ -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()
diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c
index 6bae8fdf3e0..a67ada0cfee 100644
--- a/source/blender/python/BPY_menus.c
+++ b/source/blender/python/BPY_menus.c
@@ -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++;
}
diff --git a/source/blender/python/api2_2x/NMesh.c b/source/blender/python/api2_2x/NMesh.c
index c2d4656cfbc..70bc9150a28 100644
--- a/source/blender/python/api2_2x/NMesh.c
+++ b/source/blender/python/api2_2x/NMesh.c
@@ -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;
diff --git a/source/blender/python/api2_2x/NMesh.h b/source/blender/python/api2_2x/NMesh.h
index 6602e9a251c..a139deb2647 100644
--- a/source/blender/python/api2_2x/NMesh.h
+++ b/source/blender/python/api2_2x/NMesh.h
@@ -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 */
@@ -104,6 +106,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;
Object *object; /* for vertex grouping info, since it's stored on the object */
@@ -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 );
diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c
index 28a17d08936..750f7ef30b3 100644
--- a/source/blender/python/api2_2x/Window.c
+++ b/source/blender/python/api2_2x/Window.c
@@ -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
diff --git a/source/blender/python/api2_2x/World.c b/source/blender/python/api2_2x/World.c
index 88f8576cde8..c6e4dae4efa 100644
--- a/source/blender/python/api2_2x/World.c
+++ b/source/blender/python/api2_2x/World.c
@@ -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,
diff --git a/source/blender/python/api2_2x/doc/NMesh.py b/source/blender/python/api2_2x/doc/NMesh.py
index ca2e42ccdbf..ed016880c24 100644
--- a/source/blender/python/api2_2x/doc/NMesh.py
+++ b/source/blender/python/api2_2x/doc/NMesh.py
@@ -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.