root/trunk/RBRapier/RBRapier/Formats/Wavefront/Loader.py

Revision 355, 6.7 kB (checked in by sholloway, 6 years ago)

*** empty log message ***

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 #~ Imports
24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
26 import os
27
28 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 #~ Definitions
30 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31
32 class WavefrontOBJLoader(object):
33     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
34     #~ Constants / Variables / Etc.
35     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36
37     RaiseMissingElements = 0
38     WarnMissingElements = 0
39
40     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41     #~ Public Methods
42     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43
44     def ReadFormat(self, WavefrontOBJFile):
45         self.Name = None
46         self.Vertices = []
47         self.Normals = []
48         self.TexCoords = []
49         self.Groups = []
50
51         self._FilePath = os.path.split(WavefrontOBJFile.name)[0]
52         self._strGroupName(['default'])
53
54         CommandTable = {
55             'o': self._strSetObjectName,
56
57             'v': self._strAddVertex,
58             'vn': self._strAddNormal,
59             'vt': self._strAddTextureCoord,
60
61             'p': self._strAddPoint,
62             'l': self._strAddLine,
63             'f': self._strAddFace,
64
65             'g': self._strGroupName,
66             'group': self._strGroupName,
67             #'s': self._strGroupSmoothing,
68             #'mg': self._strGroupMerge,
69
70             #'mtllib': self._strMaterialLibrary,
71             #'usemtl': self._strUseMaterial,
72
73             #'usemap': self._strUseTextureMap,
74             }
75
76         Line, LineNumber = '', 0
77         for PartialLine in WavefrontOBJFile:
78             LineNumber += 1
79             Line += PartialLine.strip()
80             if not Line or Line[0] == '#':
81                 Line = ''
82                 continue # Comment -- move on
83             if Line[-1] == '\\':
84                 Line = Line[:-1]
85                 continue # line continuation -- get the rest of it
86             Line = Line.split()
87             Command, Args = Line[0], Line[1:]
88             try:
89                 ex = CommandTable[Command]
90             except KeyError:
91                 if self.RaiseMissingElements:
92                     raise NotImplemented, "Unknown Wavefront command %r (%s<%d>)" % (' '.join(Line), WavefrontOBJFile.name, LineNumber)
93                 elif self.WarnMissingElements:
94                     print "%s<%d>: Wavefront command not supported: %r" % (WavefrontOBJFile.name, LineNumber, ' '.join(Line))
95             else:
96                 ex(Args)
97             Line = ''
98
99     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100     #~ Protected Methods
101     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102
103     OffsetIndicesDetected = 0
104     def _DetectOffsetIndices(self, indices):
105         if not self.OffsetIndicesDetected:
106             i0 = indices[0]
107             for i in [x for x in indices[1:] if x is not None]:
108                 if i != i0:
109                     self._ffsetIndicesDetected = 1
110
111     def _ConvertWavefrontIndex(self, x):
112         if x: return int(x) - 1
113         else: return None
114
115     def _strSetObjectName(self, Args):
116         self.Name = ' '.join(Args)
117
118     def _strGroupName(self, Args):
119         class GroupObject(object): pass
120         self.CurrentGroup = GroupObject()
121         self.CurrentGroup.Names = Args
122         self.CurrentGroup.Points = []
123         self.CurrentGroup.Lines = []
124         self.CurrentGroup.Faces = []
125         self.Groups.append(self.CurrentGroup)
126     def _strGroupSmoothing(self, Args):
127         self.CurrentGroup.Smoothing = Args
128     #def _strGroupMerge(self, Args):
129     #    print "Group Merge:", Args
130
131     def _strAddVertex(self, Args):
132         self.Vertices.append(map(float, Args))
133     def _strAddTextureCoord(self, Args):
134         self.TexCoords.append(map(float, Args))
135     def _strAddNormal(self, Args):
136         self.Normals.append(map(float, Args))
137
138     def _strAddPoint(self, Args):
139         VertexIndices = [self._ConvertWavefrontIndex(x) for x in Args]
140         self.CurrentGroup.Points.extend(VertexIndices)
141
142     def _strAddLine(self, Args):
143         LineEntry = []
144         for VT in Args:
145             VT = [self._ConvertWavefrontIndex(x) for x in VT.split('/')]
146             self._DetectOffsetIndices(VT)
147             if LineEntry and (len(VT) != len(LineEntry[-1])):
148                 raise ValueError, "All line points must have the same number of components"
149             LineEntry.append(VT)
150         self.CurrentGroup.Lines.append(LineEntry)
151
152     def _strAddFace(self, Args):
153         FaceEntry = []
154         for VTN in Args:
155             VTN = [self._ConvertWavefrontIndex(x) for x in VTN.split('/')]
156             self._DetectOffsetIndices(VTN)
157             if FaceEntry and (len(VTN) != len(FaceEntry[-1])):
158                 raise ValueError, "All face points must have the same number of components"
159             FaceEntry.append(tuple(VTN))
160         self.CurrentGroup.Faces.append(FaceEntry)
161
162     #def _strMaterialLibrary(self, Args):
163     #    for MaterialFileName in Args:
164     #        MaterialFile = file(os.path.join(self._FilePath, MaterialFileName), 'r')
165     #        Material = WavefrontMaterialFile(self.RaiseMissingElements, self.WarnMissingElements)
166     #        self._Object.MaterialLibrary.update(Material.ReadFormat(MaterialFile))
167
168     #def _strUseMaterial(self, Args):
169     #    for MaterialName in Args:
170     #        material =  self._Object.MaterialLibrary.get(MaterialName, None)
171     #        if material:
172     #            self._Group.Materials.append(material)
173
174     #def _strUseTextureMap(self, Args):
175     #    print "Use Texture Map:", Args
176
177
178 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179 #~ Testing
180 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
181
182 if __name__=='__main__':
183     print "Testing..."
184     test = WavefrontOBJLoader()
185     obj = test.ReadFormat(open('data/shuttle.obj', 'r'))
186     obj = test.ReadFormat(open('data/cessna.obj', 'r'))
187     obj = test.ReadFormat(open('data/oldtree.obj', 'r'))
188     obj = test.ReadFormat(open('data/porsche.obj', 'r'))
189     obj = test.ReadFormat(open('data/soccerball.obj', 'r'))
190     obj = test.ReadFormat(open('data/sword.obj', 'r'))
191     print "Test complete."
192
193
Note: See TracBrowser for help on using the browser.