root/trunk/RBRapier/RBRapier/Formats/Lightwave/MeshedObject.py

Revision 702, 13.3 kB (checked in by sholloway, 5 years ago)

Added GL prefix to Execute/Select/Deselect

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 """Uses Loader and Renderer to describe a meshed object"""
23
24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 #~ Imports
26 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27
28 import Loader
29 import Numeric
30
31 from RBRapier.Tools.Geometry.Analysis import TriangleLister
32 from RBRapier.Tools.Geometry.Analysis import TriangleStripifier
33 from RBRapier.Tools.Geometry.Analysis import TriangleMesh
34 from RBRapier.Tools.Geometry.Analysis import LocalityRemapper
35 from RBRapier.Tools.Geometry.Synthesis import VertexNormals
36
37 from RBRapier.Tools.Geometry.ConvexPolygonTesselation import TesselateConvexPolygon
38 #from RBRapier.Tools.Geometry.PolygonTesselation import PolygonTesselation
39
40 from RBRapier.Renderer.Geometry import VertexArrays
41 from RBRapier.Renderer.Geometry import ArrayTraversal
42 from RBRapier.Renderer.Appearance import Materials
43
44 from RBRapier.Formats import GeoObject
45
46 from RBFoundation import TaskProgress
47
48 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
49 #~ Constants / Variables / Etc.
50 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51
52 _NumericType = VertexArrays._DefautNumericType
53
54 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
55 #~ Definitions
56 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
57
58 class PrintOnTaskProgress(TaskProgress.TaskProgress):
59     Indent = 0
60     def __init__(self, Name, Start, Stop, Step=20):
61         TaskProgress.TaskProgress.__init__(self, Name, Start, Stop, Step)
62         self.OnProgress.Add(self._OnProgress)
63         self.OnAddSubtask.Add(self._OnAddSubtask)
64         self._OnProgress(self, self.Progress)
65
66     def __del__(self):
67         def _printAllDone(next):
68             print "%s[%3.0f%%] %s" % ("  " * next.Indent, 100*next.Percent, next.Name)
69             try: map(_printAllDone, next.Subtasks)
70             except AttributeError: pass
71         print
72         print "All Done!"
73         print "========="
74         _printAllDone(self)
75
76     def _OnProgress(self, task, progress):
77         if not hasattr(task, 'Subtasks'):
78             print '%s[%3.0f%%]%s%-40s (%s)' % ('  '*task.Indent, 100*task.Percent, '  '*(5 - task.Indent), task.Name, id(task))
79
80     def _OnAddSubtask(self, parent, child):
81         child.Indent = parent.Indent + 1
82         child.OnAddSubtask.Add(self._OnAddSubtask)
83         child.OnProgress.Add(self._OnProgress)
84         self._OnProgress(child, child.Progress)
85
86 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87
88 class MeshedObjectBuilder(object):
89     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
90     #~ Constants / Variables / Etc.
91     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92
93     GeoObjectFactory = GeoObject.GeoObject
94     IndexedTraversal = ArrayTraversal.IndexedCollectionTraversal
95     TaskProgressFactory = PrintOnTaskProgress
96
97     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98     #~ Public Methods
99     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100
101     def Build(self, FileInFormat, optimizetraversal=1, optimizemesh=3):
102         if self.TaskProgressFactory:
103             self.TaskProgress = self.TaskProgressFactory('Lightwave Meshed Object', 0., 3.)
104         else: self.TaskProgress = None
105         self.Load(FileInFormat)
106         self.Process(optimizetraversal, optimizemesh)
107
108         result = self.GeoObjectFactory()
109         result.SetVertices(self.Vertices)
110         result.SetNormals(self.Normals)
111
112         if self.SurfaceGroups:
113             for Group in self.SurfaceGroups:
114                 resultgroup = result.AddGroup(Group.Name)
115                 resultgroup.AddMaterial(Group.Material)
116                 for each in Group.Traversals.itervalues():
117                     resultgroup.AddTraversal(each)
118                 resultgroup.LoadFinalized()
119         result.LoadFinalized()
120         del self.TaskProgress
121         return result
122
123     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124     #~ Public Utilities
125     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126
127     def Process(self, optimizetraversal=1, optimizemesh=3):
128         if optimizemesh > 0:
129             self.OptimizeMesh(optimizemesh)
130         elif optimizemesh == 0:
131             self.SimpleMesh()
132
133         self.ProcessSurfaces()
134
135         if optimizetraversal > 0:
136             self.OptimizeTraversals(optimizetraversal)
137         elif optimizetraversal == 0:
138             self.SimpleTraversals()
139
140     def ProcessSurfaces(self):
141         for Group in self.SurfaceGroups:
142             Group.Material = Materials.Material()
143
144             try:
145                 BaseColor = Numeric.asarray(getattr(Group, 'BaseColor'), _NumericType)
146                 BaseColor /= Numeric.asarray([255.], _NumericType)
147                 try: # Convert Transparency to alpha
148                     scale = getattr(Group, 'Transparency', None)
149                     if scale is None:
150                         scale = getattr(Group, 'iTransparency') / 256.
151                     BaseColor[3] = 1. - scale
152                 except AttributeError: pass
153
154                 # Set the ambient color
155                 Group.Material.Ambient = BaseColor
156
157                 try: # Try to get the diffuse color
158                     scale = getattr(Group, 'Diffuse', None)
159                     if scale is None:
160                         scale = getattr(Group, 'iDiffuse') / 256.
161                     Group.Material.Diffuse = BaseColor * scale
162                 except AttributeError: pass
163
164                 try: # Try to get the Specular color
165                     scale = getattr(Group, 'Specular', None)
166                     if scale is None:
167                         scale = getattr(Group, 'iSpecular') / 256.
168                     Group.Material.Specular = BaseColor * scale
169
170                     shininess = getattr(Group, 'Shininess', None)
171                     if shininess is not None:
172                         Group.Material.Shininess = shininess
173                 except AttributeError: pass
174
175                 try: # Try to get the Luminous color -- Emissive I'm guessing
176                     scale = getattr(Group, 'Luminous', None)
177                     if scale is None:
178                         scale = getattr(Group, 'iLuminous') / 256.
179                     Group.Material.Emission = BaseColor * scale
180                 except AttributeError: pass
181             except AttributeError:
182                 pass
183
184     def Load(self, FileInFormat):
185         obj = Loader.LightwaveLWOBLoader()
186         obj.ReadFormat(FileInFormat, TaskProgress=self.TaskProgress)
187
188         self.Name = FileInFormat.name
189         self.Vertices = obj.Vertices
190         self.SurfaceGroups = obj.Surfaces.values()
191
192         if self.TaskProgress:
193             SurfaceSubtasks = self.TaskProgress.NewSubtask('Surfaces', 0, len(self.SurfaceGroups))
194             self.TaskProgress.SurfaceSubtasks = SurfaceSubtasks
195             for each in self.SurfaceGroups:
196                 each.SurfaceTask = SurfaceSubtasks.NewSubtask('Surface %s'%each.Name, 0., 3.)
197         else:
198             for each in self.SurfaceGroups:
199                 each.SurfaceTask = None
200
201     def SimpleMesh(self):
202         TriLister = TriangleLister.TriangleLister()
203         self.TraverseMesh(TriangleMesh.FaceMesh, TriLister, 'SimpleList')
204
205     def OptimizeMesh(self, level):
206         TriStripifier = TriangleStripifier.TriangleStripifier()
207         TriStripifier.GLSelector = TriangleStripifier.ExperimentGLSelector(level, 3)
208         self.TraverseMesh(TriangleMesh.FaceEdgeMesh, TriStripifier, 'TriStrip')
209
210     def TraverseMesh(self, MeshFactory, TraversalMaker, TraverseMethodName):
211         #PolyTesselator = PolygonTesselation()
212         VNSythesisMgr = VertexNormals.VertexNormalSynthesisMgr(self.Vertices)
213         for Group in self.SurfaceGroups:
214             if Group.Smoothing:
215                 VNSythesisMgr.SetTolerance(getattr(Group, 'SmoothingAngle', None))
216             else:
217                 VNSythesisMgr.SetTolerance(None)
218
219             if Group.SurfaceTask:
220                 Subtask = Group.SurfaceTask.NewSubtask('Meshing and tesselation', 0, len(Group.Faces))
221             else: Subtask = 0
222
223             mesh = MeshFactory()
224             for FaceTraversal in Group.Faces:
225                 count = len(FaceTraversal.IndexList)
226                 if count > 3:
227                     # Yuck.  Polygons.  We should tesselate them, but that's not too easy
228                     FaceTraversal = TesselateConvexPolygon(FaceTraversal.IndexList)
229                     #FaceTraversal = PolyTesselator.TesselatePolygon(FaceTraversal.IndexList, self.Vertices)
230                     for each in FaceTraversal:
231                         each = VNSythesisMgr.VisitTriangle(*each)
232                         if each: face = mesh.AddFace(*each)
233                 elif count == 3:
234                     # Triangles are easy =) wish they were all triangles...
235                     each = VNSythesisMgr.VisitTriangle(*FaceTraversal.IndexList)
236                     if each: face = mesh.AddFace(*each)
237                 # Update our progress
238                 Subtask += 1
239
240             if not mesh.Faces:
241                 Group.Traversals = {}
242             else:
243                 if Group.SurfaceTask: Subtask = Group.SurfaceTask
244                 else: Subtask = None
245                 Group.Traversals = dict(TraversalMaker(mesh, TaskProgress=Subtask))
246
247         Vertices, Normals = VNSythesisMgr.GetResultantArrays()
248         self.Vertices = VertexArrays.VertexArray(Vertices)
249         self.Normals = VertexArrays.NormalArray(Normals)
250
251     def SimpleTraversals(self):
252         if self.TaskProgress:
253             IndexTraversalSubtask = self.TaskProgress.NewSubtask('Index traversal', 0, len(self.SurfaceGroups))
254         else: IndexTraversalSubtask = 0
255
256         for Group in self.SurfaceGroups:
257             if Group.SurfaceTask:
258                 Subtask = Group.SurfaceTask.NewSubtask('Simple index traversal', 0, 3)
259             else: Subtask = 0
260
261             listdata = Group.Traversals.get('list')
262             if listdata:
263                 Group.Traversals['list'] = self.IndexedTraversal('trilist', [listdata])
264             elif listdata is not None:
265                 del Group.Traversals['list']
266             Subtask += 1
267
268             fandatacollection = Group.Traversals.get('fan')
269             if fandatacollection:
270                 Group.Traversals['fan'] = self.IndexedTraversal('tristrip', fandatacollection)
271             elif fandatacollection is not None:
272                 del Group.Traversals['fan']
273             Subtask += 1
274
275             stripdatacollection = Group.Traversals.get('strip')
276             if stripdatacollection:
277                 Group.Traversals['strip'] = self.IndexedTraversal('tristrip', stripdatacollection)
278             elif stripdatacollection is not None:
279                 del Group.Traversals['strip']
280             Subtask += 1
281
282             IndexTraversalSubtask += 1
283
284     def OptimizeTraversals(self, level):
285         if self.TaskProgress:
286             OptimizingSubtask = self.TaskProgress.NewSubtask('Index locality optimized traversal', 0, 2+len(self.SurfaceGroups))
287         else: OptimizingSubtask = 0
288
289         optimizer = LocalityRemapper.LocalityRemapper(len(self.Vertices.data))
290
291         for Group in self.SurfaceGroups:
292             if Group.SurfaceTask:
293                 Subtask = Group.SurfaceTask.NewSubtask('Locality optimizing index traversal', 0, 3)
294             else: Subtask = 0
295
296             listdata = Group.Traversals.get('list')
297             if listdata:
298                 optimizer.Visit(listdata)
299                 Group.Traversals['list'] = self.IndexedTraversal('trilist', [listdata])
300             elif listdata is not None:
301                 del Group.Traversals['list']
302             Subtask += 1
303
304             fandatacollection = Group.Traversals.get('fan')
305             if fandatacollection:
306                 for fandata in fandatacollection:
307                     optimizer.Visit(fandata)
308                 Group.Traversals['fan'] = self.IndexedTraversal('tristrip', fandatacollection)
309             elif fandatacollection is not None:
310                 del Group.Traversals['fan']
311             Subtask += 1
312
313             stripdatacollection = Group.Traversals.get('strip')
314             if stripdatacollection:
315                 for stripdata in stripdatacollection:
316                     optimizer.Visit(stripdata)
317                 Group.Traversals['strip'] = self.IndexedTraversal('tristrip', stripdatacollection)
318             elif stripdatacollection is not None:
319                 del Group.Traversals['strip']
320             Subtask += 1
321
322             OptimizingSubtask += 1
323
324         optimizer.RemapIndices(self.Vertices.data)
325         OptimizingSubtask += 1
326         optimizer.RemapIndices(self.Normals.data)
327         OptimizingSubtask += 1
328
329 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
330 #~ Testing
331 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
332
333 if __name__=='__main__':
334     print "Testing..."
335     import doctest
336     test = MeshedObjectBuilder()
337     obj = test.Build(open('data/ki162a.lwo', 'rb'), 1, 0)
338     print "Test complete."
339
340
Note: See TracBrowser for help on using the browser.