Update of /cvsroot/cgkit/cgkit2/cgkit
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14795/cgkit
Modified Files:
objimport.py
Log Message:
Read MTL files and add the materials to the objects.
Index: objimport.py
===================================================================
RCS file: /cvsroot/cgkit/cgkit2/cgkit/objimport.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** objimport.py 28 Mar 2005 17:32:09 -0000 1.3
--- objimport.py 31 Mar 2005 06:26:11 -0000 1.4
***************
*** 21,25 ****
# $Id$
! import os.path
from cgtypes import *
from worldobject import WorldObject
--- 21,25 ----
# $Id$
! import os.path, sys
from cgtypes import *
from worldobject import WorldObject
***************
*** 29,40 ****
from polyhedrongeom import PolyhedronGeom
import pluginmanager
! from cgkit import VARYING, FACEVARYING, NORMAL, FLOAT
import cmds
! # OBJReader
! class OBJReader:
! """Wavefront OBJ reader.
! This class can be used as base class to read an OBJ file.
"""
--- 29,40 ----
from polyhedrongeom import PolyhedronGeom
import pluginmanager
! from cgkit import UNIFORM, VARYING, FACEVARYING, NORMAL, FLOAT, INT, OBJMaterial
import cmds
! # WavefrontReaderBase
! class WavefrontReaderBase:
! """Wavefront OBJ/MTL reader base class.
! This is the base class for the OBJ and the MTL reader.
"""
***************
*** 44,51 ****
self.linenr = 0
self.line = ""
- self.v_count = 0
- self.vp_count = 0
- self.vt_count = 0
- self.vn_count = 0
# read
--- 44,47 ----
***************
*** 57,71 ****
The file is read and for each keyword a handle_<keyword>() method
is called with the data as argument (the number of arguments depends
! on the keyword). A syntax error is generated if such a handler
! method is not available.
! The task of these handler methods is to preprocess the data and
! invoke the final handler methods which are just called after the
! keyword.
"""
- self.v_count = 0
- self.vp_count = 0
- self.vt_count = 0
- self.vn_count = 0
self.linenr = 0
self.begin()
--- 53,65 ----
The file is read and for each keyword a handle_<keyword>() method
is called with the data as argument (the number of arguments depends
! on the keyword). Each argument is of type str.
! A syntax error is generated if such a handler method is not available.
! The task of these handler methods is to preprocess the data, check
! for errors and invoke the final handler methods which are just called
! after the keyword.
! Before the file is read, the begin() method is called. At the end,
! the end() method is called.
"""
self.linenr = 0
self.begin()
***************
*** 84,91 ****
handler(*args)
else:
! raise SyntaxError, "Unknown statement in line %d: %s"%(self.linenr, self.line)
self.end()
# Pre handler methods (they must be called "handle_<keyword>")
--- 78,291 ----
handler(*args)
else:
! self.handleUnknown(cmd, args)
self.end()
+ # begin
+ def begin(self):
+ """Begin reading a file.
+
+ This method is called before the file is read.
+ """
+ pass
+
+ # end
+ def end(self):
+ """End of reading.
+
+ This method is called after the file was read.
+ """
+ pass
+
+ # handleUnknown
+ def handleUnknown(self, cmd, arglist):
+ """Handle unknown keywords.
+
+ cmd is the command keyword (the 1st argument in the current line)
+ and arglist is the data (the remaining arguments).
+
+ The default implementation raises a SyntaxError exception.
+ """
+ raise SyntaxError, "Unknown statement in line %d: %s"%(self.linenr, self.line)
+
+
+ # MTLReader
+ class MTLReader(WavefrontReaderBase):
+ """Wavefront MTL reader.
+
+ This class can be used as base class to read a MTL file.
+ """
+
+ def __init__(self):
+ """Constructor.
+ """
+ WavefrontReaderBase.__init__(self)
+
+ def handleUnknown(self, cmd, arglist):
+ pass
+ print "Unknown:",cmd,arglist
+
+ # Pre handler methods (they must be called "handle_<keyword>")
+
+ def handle_newmtl(self, name):
+ """New material command.
+
+ name is the name of the material.
+ """
+ self.newmtl(name)
+
+ def handle_illum(self, model):
+ """Illumination model."""
+ self.illum(int(model))
+
+ def handle_Ns(self, shininess):
+ """Shininess coefficient.
+ """
+ self.Ns(float(shininess))
+
+ def handle_Ka(self, r, g, b):
+ """Ambient color.
+ """
+ self.Ka(vec3(float(r), float(g), float(b)))
+
+ def handle_Kd(self, r, g, b):
+ """Diffuse color.
+ """
+ self.Kd(vec3(float(r), float(g), float(b)))
+
+ def handle_Ks(self, r, g, b):
+ """Specular color.
+ """
+ self.Ks(vec3(float(r), float(g), float(b)))
+
+ def handle_Tr(self, alpha):
+ """Transparency."""
+ self.Tr(float(alpha))
+
+ def handle_d(self, alpha):
+ """Dissolve factor (transparency)."""
+ self.d(float(alpha))
+
+ def handle_Tf(self, r, g, b):
+ """What's this? It gets exported from Maya..."""
+ self.Tf(vec3(float(r), float(g), float(b)))
+
+ def handle_Ni(self, ref):
+ """Refraction index."""
+ self.Ni(float(ref))
+
+ def handle_map_Ka(self, mapname):
+ """Ambient texture file."""
+ self.map_Ka(mapname)
+
+ def handle_map_Kd(self, mapname):
+ """Diffuse texture file."""
+ self.map_Kd(mapname)
+
+ def handle_map_Ks(self, mapname):
+ """Specular texture file."""
+ self.map_Ks(mapname)
+
+ def handle_map_d(self, mapname):
+ """Opacity texture file."""
+ self.map_d(mapname)
+
+ def handle_map_Bump(self, mapname):
+ """Bump map texture file."""
+ self.map_Bump(mapname)
+
+ # Handler methods
+
+ def newmtl(self, name):
+ pass
+
+ def illum(self, model):
+ """Illumination model."""
+ pass
+
+ def Ns(self, shininess):
+ """Shininess."""
+ pass
+
+ def Ka(self, c):
+ """Ambient color.
+
+ c is a vec3 containing the color.
+ """
+ pass
+
+ def Kd(self, c):
+ """Diffuse color.
+
+ c is a vec3 containing the color.
+ """
+ pass
+
+ def Ks(self, c):
+ """Specular color.
+
+ c is a vec3 containing the color.
+ """
+ pass
+
+ def Tr(self, alpha):
+ """Transparency."""
+ pass
+
+ def d(self, alpha):
+ """Dissolve factor (transparency)."""
+ pass
+
+ def Tf(self, c):
+ """???
+
+ c is a vec3 containing some color...
+ """
+ pass
+
+ def Ni(self, ref):
+ """Refraction index."""
+ pass
+
+ def map_Ka(self, mapname):
+ pass
+
+ def map_Kd(self, mapname):
+ pass
+
+ def map_Ks(self, mapname):
+ pass
+
+ def map_d(self, mapname):
+ pass
+
+ def map_Bump(self, mapname):
+ pass
+
+
+ # OBJReader
+ class OBJReader(WavefrontReaderBase):
+ """Wavefront OBJ reader.
+
+ This class can be used as base class to read an OBJ file.
+ """
+
+ def __init__(self):
+ """Constructor.
+ """
+ WavefrontReaderBase.__init__(self)
+ self.v_count = 0
+ self.vp_count = 0
+ self.vt_count = 0
+ self.vn_count = 0
+
+ # read
+ def read(self, f):
+ self.v_count = 0
+ self.vp_count = 0
+ self.vt_count = 0
+ self.vn_count = 0
+ WavefrontReaderBase.read(self, f)
+
# Pre handler methods (they must be called "handle_<keyword>")
***************
*** 219,236 ****
# Handler methods
- def begin(self):
- """Begin reading a file.
-
- This method is called before the file is read.
- """
- pass
-
- def end(self):
- """End of reading.
-
- This method is called after the file was read.
- """
- pass
-
def call(self, filename, *args):
pass
--- 419,422 ----
***************
*** 341,351 ****
######################################################################
!
! class _OBJReader(OBJReader):
"""
! TODO: - Material IDs (if there's more than 1 material per object)
! - Create materials
! - Recreate the hierarchy
"""
--- 527,618 ----
######################################################################
!
! class _MTLReader(MTLReader):
! """Read MTL files and create a list of materials.
!
! Reads an MTL file and stores the materials as OBJMaterial objects
! in the list self.material.
"""
!
! def __init__(self):
! MTLReader.__init__(self)
! self.materials = []
! self.currentmat = None
!
! def begin(self):
! self.materials = []
! self.currentmat = None
!
! def end(self):
! pass
!
! def newmtl(self, name):
! mat = OBJMaterial(name=name)
! self.materials.append(mat)
! self.currentmat = mat
!
! def illum(self, model):
! if self.currentmat!=None:
! self.currentmat.illum = model
!
! def Ka(self, c):
! if self.currentmat!=None:
! self.currentmat.Ka = c
!
! def Kd(self, c):
! if self.currentmat!=None:
! self.currentmat.Kd = c
!
! def Ks(self, c):
! if self.currentmat!=None:
! self.currentmat.Ks = c
!
! def Ks(self, c):
! if self.currentmat!=None:
! self.currentmat.Ks = c
!
! def Ns(self, shininess):
! if self.currentmat!=None:
! self.currentmat.Ns = shininess
!
! def Ni(self, refl):
! if self.currentmat!=None:
! self.currentmat.Ni = refl
+ def d(self, alpha):
+ if self.currentmat!=None:
+ self.currentmat.d = alpha
+
+ def Tr(self, alpha):
+ if self.currentmat!=None:
+ self.currentmat.Tr = alpha
+
+ def Tf(self, c):
+ if self.currentmat!=None:
+ self.currentmat.Tf = c
+
+ def map_Ka(self, name):
+ if self.currentmat!=None:
+ self.currentmat.map_Ka = name
+
+ def map_Kd(self, name):
+ if self.currentmat!=None:
+ self.currentmat.map_Kd = name
+
+ def map_Ks(self, name):
+ if self.currentmat!=None:
+ self.currentmat.map_Ks = name
+
+ def map_d(self, name):
+ if self.currentmat!=None:
+ self.currentmat.map_d = name
+
+ def map_Bump(self, name):
+ if self.currentmat!=None:
+ self.currentmat.map_Bump = name
+
+
+ class _OBJReader(OBJReader):
+ """Read an OBJ file.
"""
***************
*** 367,370 ****
--- 634,647 ----
self.groupnames = []
+ # A dictionary with OBJMaterial objects read from the MTL files
+ # Key is the material name
+ self.materials = {}
+ # Material stack. Contains 2-tuples (offset, OBJMaterial) where
+ # offset is the face index of the first face (since the last 'g'
+ # command that uses this material)
+ # The stack is cleared (the last element remains) whenever the 'g'
+ # command occurs.
+ self.materialstack = [(0, OBJMaterial())]
+
# The collected faces
self.faces = []
***************
*** 376,379 ****
--- 653,686 ----
self.g("default")
+ # mtllib
+ def mtllib(self, *files):
+ mtlreader = _MTLReader()
+ # Iterate over all MTL file names
+ for fname in files:
+ # Read the MTL file...
+ f = file(fname)
+ mtlreader.read(f)
+ f.close()
+ # ...and keep the materials that don't exist yet
+ for mat in mtlreader.materials:
+ if mat.name not in self.materials:
+ self.materials[mat.name] = mat
+
+ # usemtl
+ def usemtl(self, name):
+ if name not in self.materials:
+ print >>sys.stderr, 'WARNING: No definition found for material "%s"'%name
+ # Store None so that the warning message will only get printed
+ # once for each missing material name
+ self.materials[name] = None
+
+ # Put the material on the stack (replace the top material if it has
+ # the same offset (i.e. it is unused))
+ offset = len(self.faces)
+ mat = self.materials[name]
+ if self.materialstack[-1][0]==offset:
+ self.materialstack.pop()
+ self.materialstack.append((len(self.faces), self.materials[name]))
+
# v
def v(self, vert):
***************
*** 425,428 ****
--- 732,737 ----
self.trimesh_flag = True
self.groupnames = groups
+ # Clear the stack (the last material remains)
+ self.materialstack = [(0, self.materialstack[-1][1])]
# createTriMesh
***************
*** 496,499 ****
--- 805,810 ----
obj = TriMesh(name=name, parent=parent)
obj.geom = tm
+ # Set the materials
+ self.initMaterial(obj)
return obj
***************
*** 566,636 ****
obj = Polyhedron(name=name, parent=parent)
obj.geom = pg
return obj
- def createPolyhedron_old(self, parent=None, name=None):
- """Create a polyhedron from the current set of faces.
-
- *** splits vertices ***
! Returns the Polyhedron object.
"""
! # Build lookup tables (so that only the verts, normals and tverts
! # that are really required are stored in the Polyhedron)
! #
! # Key: Original indices (v,tv,n) - Value: New vertex index
! vert_lut = {}
! has_normals = True
! has_tverts = True
! iv = 0
! for f in self.faces:
! for v,tv,n in f:
! if (v,tv,n) not in vert_lut:
! vert_lut[(v,tv,n)] = iv
! iv+=1
! if tv==None:
! has_tverts = False
! if n==None:
! has_normals = False
!
! numpolys = len(self.faces)
! numverts = len(vert_lut)
!
! pg = PolyhedronGeom()
! pg.verts.resize(numverts)
! pg.setNumPolys(numpolys)
!
! # Set vertices
! for v,tv,n in vert_lut:
! newidx = vert_lut[(v,tv,n)]
! pg.verts[newidx] = self.verts[v]
!
! # Set normals
! if has_normals:
! pg.newVariable("N", VARYING, NORMAL)
! N = pg.slot("N")
! for v,tv,n in vert_lut:
! newidx = vert_lut[(v,tv,n)]
! N[newidx] = self.normals[n]
!
! # Set texture vertices
! if has_tverts:
! pg.newVariable("st", VARYING, FLOAT, 2)
! st = pg.slot("st")
! for v,tv,n in vert_lut:
! newidx = vert_lut[(v,tv,n)]
! st[newidx] = self.tverts[tv]
!
! # Set polys
! idx = 0
! for i,f in enumerate(self.faces):
! loop = []
! for indices in f:
! loop.append(vert_lut[indices])
! pg.setPoly(i,[loop])
- obj = Polyhedron(name=name, parent=parent)
- obj.geom = pg
- return obj
# findParent
--- 877,908 ----
obj = Polyhedron(name=name, parent=parent)
obj.geom = pg
+ # Set the materials
+ self.initMaterial(obj)
return obj
! # initMaterial
! def initMaterial(self, obj):
! """Set the material(s) and the matid primitive variable.
"""
+ # Set the materials
+ nummats = len(self.materialstack)
+ obj.setNumMaterials(nummats)
+ for i, (offset, mat) in enumerate(self.materialstack):
+ obj.setMaterial(mat, i)
! # Create a variable "matid" if there's more than 1 material...
! if nummats>1:
! obj.geom.newVariable("matid", UNIFORM, INT)
! matid = obj.geom.slot("matid")
! for id in range(len(self.materialstack)):
! begin = self.materialstack[id][0]
! if id+1<len(self.materialstack):
! end = self.materialstack[id+1][0]
! else:
! end = matid.size()
! for j in range(begin, end):
! matid[j] = id
# findParent
|