Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/Tools/Wings3DExporter/mesh.py @ 20

Last change on this file since 20 was 6, checked in by anonymous, 17 years ago

=…

File size: 10.3 KB
Line 
1
2from __future__ import nested_scopes
3
4from vector import Vector
5import pgon
6
7import pprint
8
9def sum(seq):
10        return reduce(lambda a, b: a + b, seq)
11
12# color property of a vertex
13class ColorProp:
14
15        color = None
16        uv = None
17
18        def __init__(self, data):
19                if len(data) == 2:
20                        self.color = None
21                        self.uv = data
22                else:
23                        self.color = data
24                        self.uv = None
25
26        def __repr__(self):
27                r = []
28                if self.uv:
29                        u, v = self.uv
30                        r.append("uv %.3f %.3f" % (u, v))
31                if self.color:
32                        r, g, b, a = self.color
33                        r.append("color %.3f %.3f %.3f %.3f" % (r, g, b, a))
34                if r: return " ".join(r)
35                else: return "none"
36
37
38# object material
39class Material:
40
41        """Material class:
42        class members:
43                name
44                diffuse: diffuse color
45                ambient: ambient color
46                specular: specular color
47                shininess
48                opacity
49                textures: list of texture layers
50        """
51       
52        def __init__(self, name):
53                self.name = name
54                self.diffuse = (1,1,1,1)
55                self.ambient = (0,0,0,1)
56                self.specular = (0,0,0,1)
57                self.shininess = 0
58                self.textures = []
59
60        def __repr__(self):
61                return 'Material("' + self.name + '")'
62       
63
64class GLVertex:
65
66        pos = None
67        normal = None
68        uv = None
69        color = None
70        material = None
71
72        def __eq__(self, other):
73                return self.pos == other.pos \
74                                and self.normal == other.normal \
75                                and self.uv == other.uv \
76                                and self.color == other.color \
77                                and self.material == other.material
78       
79        def __repr__(self):
80                seq = []
81                seq.append("pos:" + str(self.pos))
82                seq.append("normal:" + str(self.normal))
83                if self.uv != None: 
84                        u, v = self.uv
85                        seq.append("uv: (%.3f,%.3f)" % (u, v))
86                if self.color != None: 
87                        r, g, b, a = self.color
88                        seq.append("color: (%.3f,%.3f,%.3f,%.3f)" % (r, g, b, a))
89                if self.material != None: seq.append("material:" + repr(self.material))
90                return " ".join(seq)
91
92class SubMesh:
93
94        """SubMesh class:
95                a set of triangles using the same material
96       
97        submesh data:
98                material: material index in parent's materials table
99                gltris: vertex indices to parent's glverts table
100        """
101
102        def __init__(self):
103                self.material = None
104                self.mat_data = None
105                self.gltris = []
106                self.glverts = []
107
108# object which describes a mesh
109class Mesh:
110
111        """Mesh class
112        class members:
113                verts: three dimensional coordinates of vertices in this mesh
114                faces: sequences containing the vertex indices of the polygons
115                hard_edges: contains face index tuples for hard edges
116                face_materials: material data for faces
117
118        calculated data:
119                face_normals: normal vectors of faces
120
121        data associated with (face, vertex) tuples:
122                face_vert_normals: vertex normals
123                face_vert_colors: color or uv information
124       
125        processed vertex data:
126                glverts
127                glfaces: faces
128                gltris: triangulated glfaces
129        """
130
131        def __init__(self):
132                self.verts = []
133                self.faces = []
134                self.edges = []
135                self.hard_edges = []
136                self.face_materials = []
137
138                self.materials = []
139
140                self.face_normals = []
141                self.face_vert_normals = {}
142                self.face_vert_colors = {}
143
144                self.glverts = []
145                self.glfaces = []
146                self.gltris = []
147                self.tri_materials = []
148
149                self.shared_geometry = 0
150
151        def faces_containing_vertex(self, vertex):
152                return filter(lambda face: vertex in self.faces[face],
153                                range(len(self.faces)))
154
155        def face_material(self):
156                return None
157
158        def make_face_normals(self):
159                "Calculate face normals"
160
161                self.face_normals = []
162                for face in self.faces:
163                        n = pgon.pgon_normal(map(lambda v: self.verts[v], face))
164                        self.face_normals.append(n)
165
166        def face_vert_shareable(self, face1, face2, vertex):
167
168                # returns true if the vertex has the same gl data for the two vertices
169                glvert1 = self.make_gl_vert(face1, vertex)
170                glvert2 = self.make_gl_vert(face2, vertex)
171
172                return glvert1 == glvert2
173
174        def faces_same_smoothing_simple(self, face1, face2, vertex):
175
176                minf, maxf = min(face1, face2), max(face1, face2)
177
178                # check if the edge is hard between the faces
179                return (minf, maxf) not in self.hard_edges
180
181        def faces_same_smoothing_full(self, face1, face2, vertex):
182
183                myedges = []
184                for e in self.edges:
185                        f1, f2, v1, v2 = e
186                        if vertex in [v1, v2]:
187                                myedges.append(e)
188
189                same_smooth = []
190                buf = [face1]
191                while len(buf) > 0:
192                        face = buf.pop()
193                        same_smooth.append(face)
194                        for e in myedges:
195                                f1, f2, v1, v2 = e
196                                if face in [f1, f2] and vertex in [v1, v2]:
197                                        if face == f1:
198                                                otherface = f2
199                                        else:
200                                                otherface = f1
201                                        if otherface not in same_smooth:
202                                                if (f1, f2) not in self.hard_edges:
203                                                        buf.append(otherface)
204                #print same_smooth
205
206                return face2 in same_smooth
207
208        def partition_verts(self, pred):
209                "Partition vertices using the given predicate"
210
211                result = []
212                for vertex in range(len(self.verts)):
213                        buckets = []
214                        for face in self.faces_containing_vertex(vertex):
215                                found_bucket = None
216
217                                # find a bucket for this face
218                                for bucket in buckets:
219
220                                        # find faces which are compatible with current
221                                        flags = map(lambda f: pred(face, f, vertex), bucket)
222
223                                        # check if this is ok
224                                        if 0 not in flags:
225                                                found_bucket = bucket
226
227                                # add face to correct bucket or create new bucket
228                                if found_bucket:
229                                        found_bucket.append(face)
230                                else:
231                                        buckets.append([face])
232                        result.append(buckets)
233
234                return result
235
236
237        def make_vert_normals(self, full_test):
238
239                print "smoothing..."
240                if full_test:
241                        self.faces_same_smoothing = self.faces_same_smoothing_full
242                else:
243                        self.faces_same_smoothing = self.faces_same_smoothing_simple
244
245                # find faces which are compatible with current
246                all_buckets = self.partition_verts(self.faces_same_smoothing)
247
248                #pp = pprint.PrettyPrinter(indent=4,width=78)
249                #pp.pprint(self.hard_edges)
250                #pp.pprint(all_buckets)
251
252                self.face_vert_normals = {}
253                for vertex in range(len(self.verts)):
254                        buckets = all_buckets[vertex]
255
256                        for bucket in buckets:
257                                bucket_normals = map(lambda x: self.face_normals[x], bucket)
258                                try:
259                                        normal = sum(bucket_normals).unit()
260                                        for face in bucket:
261                                                self.face_vert_normals[(face, vertex)] = normal
262                                except ValueError, x:
263                                        print bucket_normals
264                                        raise x
265       
266        def make_gl_vert(self, face, vertex):
267
268                glvert = GLVertex()
269
270                # these are mandatory
271                glvert.pos = self.verts[vertex]
272                glvert.normal = self.face_vert_normals[(face, vertex)]
273
274                # check if there is color data
275                if self.face_vert_colors.has_key((face, vertex)):
276                        data = self.face_vert_colors[(face, vertex)]
277                        uv = data.uv
278                        color = data.color
279                else:
280                        uv, color = None, None
281                #glvert.uv, glvert.color = uv, color
282                # Sinbad: flip v texcoord for 0.13
283                if uv:
284                        newu, newv = uv
285                        newv = 1 - newv
286                        glvert.uv = newu, newv
287                else:
288                        glvert.uv = uv
289                glvert.color = color
290        # End Sinbad
291                glvert.material = self.face_materials[face]
292
293                return glvert
294
295        def flatten(self):
296                "generate gl vertices"
297
298                # create buckets for shareable vertices
299                all_buckets = self.partition_verts(self.face_vert_shareable)
300
301                # calculate number of total verts
302                ntotal = sum(map(len, all_buckets))
303
304                # create duplicate vertices and vertex indices
305                cur_vert_idx = 0
306                gl_indices = []
307                self.glverts = []
308                for vertex in range(len(self.verts)):
309                        nsubverts = len(all_buckets[vertex])
310                        gl_indices.append(range(cur_vert_idx, cur_vert_idx + nsubverts))
311                        for bucket in all_buckets[vertex]:
312                                face = bucket[0]
313                                self.glverts.append(self.make_gl_vert(face, vertex))
314                        cur_vert_idx += nsubverts
315
316                # create reindexed faces
317                self.glfaces = []
318                for face in range(len(self.faces)):
319                        vertices = self.faces[face]
320                        glface = []
321                        for vi in vertices:
322
323                                def sublistindexelem(seq, val):
324                                        for i in range(len(seq)):
325                                                if val in seq[i]: return i
326                                        return None
327
328                                group = sublistindexelem(all_buckets[vi], face)
329                                glface.append(gl_indices[vi][group])
330                        self.glfaces.append(glface)
331
332        def triangulate(self):
333                "triangulate polygons"
334
335                print "tesselating..."
336
337                self.gltris = []
338                self.tri_materials = []
339                for i in range(len(self.glfaces)):
340                        face = self.glfaces[i]
341                        mat = self.face_materials[i]
342                        if len(face) == 3:
343                                self.gltris.append(face)
344                                self.tri_materials.append(mat)
345                        else:
346                                verts = map(lambda vindex: Vector(self.glverts[vindex].pos), face)
347
348                                # triangulate using ear clipping method
349                                tris = pgon.triangulate(verts)
350
351                                for tri in tris:
352                                        A, B, C = map(lambda pindex: face[pindex], tri)
353                                        self.gltris.append([A, B, C])
354                                        self.tri_materials.append(mat)
355       
356        def submeshize(self):
357                "create submeshes"
358
359                print "creating submeshes..."
360
361                temp = {}
362                for t in self.tri_materials:
363                        temp[t] = 1
364                trimats = temp.keys()
365
366                self.subs = []
367                for mat in trimats:
368                        submesh = SubMesh()
369                        submesh.material = mat
370                        submesh.mat_data = self.materials[mat]
371                        if self.shared_geometry:
372                                # use shared geometry
373                                for i in range(len(self.tri_materials)):
374                                        if self.tri_materials[i] == mat:
375                                                submesh.gltris.append(self.gltris[i])
376                        else:
377                                verts = {}
378                                for i in range(len(self.tri_materials)):
379                                        if self.tri_materials[i] == mat:
380                                                for vert in self.gltris[i]:
381                                                        verts[vert] = 1
382                                verts = verts.keys()
383                                verts.sort()
384                                for i in verts:
385                                        submesh.glverts.append(self.glverts[i])
386                                for i in range(len(self.tri_materials)):
387                                        if self.tri_materials[i] == mat:
388                                                tri = []
389                                                for vert in self.gltris[i]:
390                                                        tri.append(verts.index(vert))
391                                                submesh.gltris.append(tri)
392                        self.subs.append(submesh)
393
394        def dump(self):
395                "show data"
396
397                print "Mesh '%s':" % self.name
398
399                print "%d vertices:" % len(self.glverts)
400                for vert in self.glverts: print "   ", vert
401
402                ntris = sum(map(lambda submesh: len(submesh.gltris), self.subs))
403                print "%d submeshes, %d tris total:" % (len(self.subs), ntris)
404                for sub in self.subs:
405                        print "   material %d (%s), %d tris" % (sub.material, sub.mat_data.name, len(sub.gltris))
406                        for tri in sub.gltris:
407                                A, B, C = tri
408                                print "      ", A, B, C
409
410        def merge(self, other):
411                "add all mesh data from another mesh to self"
412
413                nv = len(self.verts)
414                nf = len(self.faces)
415
416                self.verts += other.verts
417                self.faces += map(lambda face: map(lambda x: x + nv, face), other.faces)
418                self.hard_edges += map(lambda (x, y): (x + nf, y + nf), other.hard_edges)
419                self.face_materials += other.face_materials
420
421                for fv in other.face_vert_colors.keys():
422                        face, vert = fv
423                        value = other.face_vert_colors[fv]
424                        self.face_vert_colors[(face + nf, vert + nv)] = value
425
426                for e in other.edges:
427                        f1, f2, v1, v2 = e
428                        self.edges.append((f1 + nf, f2 + nf, v1 + nv, v2 + nv))
429
430        def scale(self, value):
431                for v in self.glverts:
432                        v.pos = Vector(v.pos) * value
433
434        def find_material(self, mat_name):
435                for m in range(len(self.materials)):
436                        if self.materials[m].name == mat_name:
437                                return m
438                return None
439
440
Note: See TracBrowser for help on using the repository browser.