|
9 | 9 | class ObjParser(Parser): |
10 | 10 | """This parser parses lines from .obj files.""" |
11 | 11 |
|
12 | | - def __init__(self, wavefront, file_name, strict=False, encoding="utf-8", parse=True): |
| 12 | + def __init__(self, wavefront, file_name, strict=False, encoding="utf-8", create_materials=False, parse=True): |
13 | 13 | """ |
14 | 14 | Create a new obj parser |
15 | 15 | :param wavefront: The wavefront object |
16 | 16 | :param file_name: file name and path of obj file to read |
17 | 17 | :param strict: Enable strict mode |
18 | 18 | :param encoding: Encoding to read the text files |
| 19 | + :param create_materials: Create materials if they don't exist |
19 | 20 | :param parse: Should parse be called immediately or manually called later? |
20 | 21 | """ |
21 | 22 | super(ObjParser, self).__init__(file_name, strict=strict, encoding=encoding) |
22 | 23 | self.wavefront = wavefront |
23 | 24 |
|
24 | 25 | self.mesh = None |
25 | 26 | self.material = None |
| 27 | + self.create_materials = create_materials |
26 | 28 |
|
27 | 29 | # Stores ALL vertices, normals and texcoords for the entire file |
28 | 30 | self.vertices = [] |
@@ -122,17 +124,28 @@ def consume_texture_coordinates(self): |
122 | 124 | @auto_consume |
123 | 125 | def parse_mtllib(self): |
124 | 126 | mtllib = os.path.join(self.dir, " ".join(self.values[1:])) |
125 | | - materials = MaterialParser(mtllib, encoding=self.encoding, strict=self.strict).materials |
| 127 | + try: |
| 128 | + materials = MaterialParser(mtllib, encoding=self.encoding, strict=self.strict).materials |
| 129 | + except IOError: |
| 130 | + if self.create_materials: |
| 131 | + return |
| 132 | + raise |
126 | 133 |
|
127 | 134 | for name, material in materials.items(): |
128 | 135 | self.wavefront.materials[name] = material |
129 | 136 |
|
130 | 137 | @auto_consume |
131 | 138 | def parse_usemtl(self): |
132 | | - self.material = self.wavefront.materials.get(self.values[1], None) |
| 139 | + name = " ".join(self.values[1:]) |
| 140 | + self.material = self.wavefront.materials.get(name, None) |
133 | 141 |
|
134 | 142 | if self.material is None: |
135 | | - raise PywavefrontException('Unknown material: %s' % self.values[1]) |
| 143 | + if not self.create_materials: |
| 144 | + raise PywavefrontException('Unknown material: %s' % name) |
| 145 | + |
| 146 | + # Create a new default material if configured to resolve missing ones |
| 147 | + self.material = Material(name=name, is_default=True) |
| 148 | + self.wavefront.materials[name] = self.material |
136 | 149 |
|
137 | 150 | if self.mesh is not None: |
138 | 151 | self.mesh.add_material(self.material) |
@@ -213,7 +226,10 @@ def consume_faces(self): |
213 | 226 |
|
214 | 227 | # If the material already have vertex data, ensure the same format is used |
215 | 228 | if self.material.vertex_format and self.material.vertex_format != vertex_format: |
216 | | - raise ValueError("Trying to merge vertex data with different formats") |
| 229 | + raise ValueError(( |
| 230 | + "Trying to merge vertex data with different format: {}. " |
| 231 | + "Material {} has vertex format {}" |
| 232 | + ).format(vertex_format, self.material.name, self.material.vertex_format)) |
217 | 233 |
|
218 | 234 | self.material.vertex_format = vertex_format |
219 | 235 |
|
|
0 commit comments