1 | #!BPY |
---|
2 | |
---|
3 | """ |
---|
4 | Name: 'Ogre XML' |
---|
5 | Blender: 240 |
---|
6 | Group: 'Export' |
---|
7 | Tooltip: 'Exports selected meshes with armature animations to Ogre3D' |
---|
8 | """ |
---|
9 | |
---|
10 | __author__ = ['Michael Reimpell', 'Jeff Doyle (nfz)', 'Jens Hoffmann', 'et al.'] |
---|
11 | __version__ = '' |
---|
12 | __url__ = ['OGRE website, http://www.ogre3d.org', |
---|
13 | 'OGRE forum, http://www.ogre3d.org/phpBB2/'] |
---|
14 | __bpydoc__ = """\ |
---|
15 | Exports selected meshes with armature animations to Ogre3D. |
---|
16 | |
---|
17 | Read the script manual for further information. |
---|
18 | """ |
---|
19 | |
---|
20 | # Blender to Ogre Mesh and Skeleton Exporter |
---|
21 | # url: http://www.ogre3d.org |
---|
22 | |
---|
23 | # Ogre exporter written by Jens Hoffmann and Michael Reimpell |
---|
24 | # based on the Cal3D exporter v0.5 written by Jean-Baptiste LAMY |
---|
25 | # modified by Jeff Doyle (nfz) to work with Blender 2.4 |
---|
26 | |
---|
27 | # Copyright (C) 2004-2005 Michael Reimpell -- <M.Reimpell@tu-bs.de> |
---|
28 | # Copyright (C) 2003 Jens Hoffmann -- <hoffmajs@gmx.de> |
---|
29 | # Copyright (C) 2003 Jean-Baptiste LAMY -- jiba@tuxfamily.org |
---|
30 | # |
---|
31 | # This program is free software; you can redistribute it and/or modify |
---|
32 | # it under the terms of the GNU General Public License as published by |
---|
33 | # the Free Software Foundation; either version 2 of the License, or |
---|
34 | # (at your option) any later version. |
---|
35 | # |
---|
36 | # This program is distributed in the hope that it will be useful, |
---|
37 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
38 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
39 | # GNU General Public License for more details. |
---|
40 | # |
---|
41 | # You should have received a copy of the GNU General Public License |
---|
42 | # along with this program; if not, write to the Free Software |
---|
43 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
44 | |
---|
45 | # this export script is assumed to be used with the latest blender version. |
---|
46 | |
---|
47 | # KEEP_SETTINGS (enable = 1, disable = 0) |
---|
48 | # transparently load and save settings to the text 'ogreexport.cfg' |
---|
49 | # inside the current .blend file. |
---|
50 | KEEP_SETTINGS = 1 |
---|
51 | |
---|
52 | # OGRE_XML_CONVERTER |
---|
53 | # the command line used to run the OgreXMLConverter tool. |
---|
54 | # Set to '' to disable automatical conversion of XML files. |
---|
55 | OGRE_XML_CONVERTER = '' |
---|
56 | |
---|
57 | # OGRE_VERTEXCOLOUR_BGRA |
---|
58 | # workaround for Ogre's vertex colour conversion bug. |
---|
59 | # Set to 0 for RGBA, 1 for BGRA. |
---|
60 | OGRE_OPENGL_VERTEXCOLOUR = 0 |
---|
61 | |
---|
62 | ####################################################################################### |
---|
63 | ## Code starts here. |
---|
64 | |
---|
65 | # epydoc doc format |
---|
66 | __docformat__ = "javadoc en" |
---|
67 | |
---|
68 | ###### |
---|
69 | # imports |
---|
70 | ###### |
---|
71 | import Blender, sys, os, math, string |
---|
72 | if KEEP_SETTINGS: |
---|
73 | try: |
---|
74 | import pickle |
---|
75 | except ImportError: |
---|
76 | Blender.Draw.PupMenu("Can't import pickle module!%t|Permanent settings disabled.") |
---|
77 | KEEP_SETTINGS = 0 |
---|
78 | |
---|
79 | ###### |
---|
80 | # namespaces |
---|
81 | ###### |
---|
82 | from Blender import Draw |
---|
83 | from Blender import Mathutils |
---|
84 | from Blender.BGL import * |
---|
85 | |
---|
86 | ###### |
---|
87 | # Classes |
---|
88 | ###### |
---|
89 | class ReplacementScrollbar: |
---|
90 | """Scrollbar replacement for Draw.Scrollbar |
---|
91 | <ul> |
---|
92 | <li> import Blender |
---|
93 | <li> call eventFilter and buttonFilter in registered callbacks |
---|
94 | </ul> |
---|
95 | |
---|
96 | @author Michael Reimpell |
---|
97 | """ |
---|
98 | def __init__(self, initialValue, minValue, maxValue, buttonUpEvent, buttonDownEvent): |
---|
99 | """Constructor |
---|
100 | |
---|
101 | @param initialValue inital value |
---|
102 | @param minValue minimum value |
---|
103 | @param maxValue maxium value |
---|
104 | @param buttonUpEvent unique event number |
---|
105 | @param buttonDownEvent unique event number |
---|
106 | """ |
---|
107 | self.currentValue = initialValue |
---|
108 | self.minValue = minValue |
---|
109 | if maxValue > minValue: |
---|
110 | self.maxValue = maxValue |
---|
111 | else: |
---|
112 | self.maxValue = self.minValue |
---|
113 | self.minValue = maxValue |
---|
114 | self.buttonUpEvent = buttonUpEvent |
---|
115 | self.buttonDownEvent = buttonDownEvent |
---|
116 | # private |
---|
117 | self.guiRect = [0,0,0,0] |
---|
118 | self.positionRect = [0,0,0,0] |
---|
119 | self.markerRect = [0,0,0,0] |
---|
120 | self.mousePressed = 0 |
---|
121 | self.mouseFocusX = 0 |
---|
122 | self.mouseFocusY = 0 |
---|
123 | self.markerFocusY = 0 |
---|
124 | self.mousePositionY = 0 |
---|
125 | return |
---|
126 | |
---|
127 | def getCurrentValue(self): |
---|
128 | """current marker position |
---|
129 | """ |
---|
130 | return self.currentValue |
---|
131 | |
---|
132 | def up(self, steps=1): |
---|
133 | """move scrollbar up |
---|
134 | """ |
---|
135 | if (steps > 0): |
---|
136 | if ((self.currentValue - steps) > self.minValue): |
---|
137 | self.currentValue -= steps |
---|
138 | else: |
---|
139 | self.currentValue = self.minValue |
---|
140 | return |
---|
141 | |
---|
142 | def down(self, steps=1): |
---|
143 | """move scrollbar down |
---|
144 | """ |
---|
145 | if (steps > 0): |
---|
146 | if ((self.currentValue + steps) < self.maxValue): |
---|
147 | self.currentValue += steps |
---|
148 | else: |
---|
149 | self.currentValue = self.maxValue |
---|
150 | return |
---|
151 | |
---|
152 | def draw(self, x, y, width, height): |
---|
153 | """draw scrollbar |
---|
154 | """ |
---|
155 | # get size of the GUI window to translate MOUSEX and MOUSEY events |
---|
156 | guiRectBuffer = Blender.BGL.Buffer(GL_FLOAT, 4) |
---|
157 | Blender.BGL.glGetFloatv(Blender.BGL.GL_SCISSOR_BOX, guiRectBuffer) |
---|
158 | self.guiRect = [int(guiRectBuffer.list[0]), int(guiRectBuffer.list[1]), \ |
---|
159 | int(guiRectBuffer.list[2]), int(guiRectBuffer.list[3])] |
---|
160 | # relative position |
---|
161 | self.positionRect = [ x, y, x + width, y + height] |
---|
162 | # check minimal size: |
---|
163 | # 2 square buttons,4 pixel borders and 1 pixel inside for inner and marker rectangles |
---|
164 | if ((height > (2*(width+5))) and (width > 2*5)): |
---|
165 | # keep track of remaining area |
---|
166 | remainRect = self.positionRect[:] |
---|
167 | # draw square buttons |
---|
168 | Blender.Draw.Button("/\\", self.buttonUpEvent, x, y + (height-width), width, width, "scroll up") |
---|
169 | remainRect[3] -= width + 2 |
---|
170 | Blender.Draw.Button("\\/", self.buttonDownEvent, x, y, width, width, "scroll down") |
---|
171 | remainRect[1] += width + 1 |
---|
172 | # draw inner rectangle |
---|
173 | Blender.BGL.glColor3f(0.13,0.13,0.13) # dark grey |
---|
174 | Blender.BGL.glRectf(remainRect[0], remainRect[1], remainRect[2], remainRect[3]) |
---|
175 | remainRect[0] += 1 |
---|
176 | remainRect[3] -= 1 |
---|
177 | Blender.BGL.glColor3f(0.78,0.78,0.78) # light grey |
---|
178 | Blender.BGL.glRectf(remainRect[0], remainRect[1], remainRect[2], remainRect[3]) |
---|
179 | remainRect[1] += 1 |
---|
180 | remainRect[2] -= 1 |
---|
181 | Blender.BGL.glColor3f(0.48,0.48,0.48) # grey |
---|
182 | Blender.BGL.glRectf(remainRect[0], remainRect[1], remainRect[2], remainRect[3]) |
---|
183 | # draw marker rectangle |
---|
184 | # calculate marker rectangle |
---|
185 | innerHeight = remainRect[3]-remainRect[1] |
---|
186 | markerHeight = innerHeight/(self.maxValue-self.minValue+1.0) |
---|
187 | # markerRect |
---|
188 | self.markerRect[0] = remainRect[0] |
---|
189 | self.markerRect[1] = remainRect[1] + (self.maxValue - self.currentValue)*markerHeight |
---|
190 | self.markerRect[2] = remainRect[2] |
---|
191 | self.markerRect[3] = self.markerRect[1] + markerHeight |
---|
192 | # clip markerRect to innerRect (catch all missed by one errors) |
---|
193 | if self.markerRect[1] > remainRect[3]: |
---|
194 | self.markerRect[1] = remainRect[3] |
---|
195 | if self.markerRect[3] > remainRect[3]: |
---|
196 | self.markerRect[3] = remainRect[3] |
---|
197 | # draw markerRect |
---|
198 | remainRect = self.markerRect |
---|
199 | Blender.BGL.glColor3f(0.78,0.78,0.78) # light grey |
---|
200 | Blender.BGL.glRectf(remainRect[0], remainRect[1], remainRect[2], remainRect[3]) |
---|
201 | remainRect[0] += 1 |
---|
202 | remainRect[3] -= 1 |
---|
203 | Blender.BGL.glColor3f(0.13,0.13,0.13) # dark grey |
---|
204 | Blender.BGL.glRectf(remainRect[0], remainRect[1], remainRect[2], remainRect[3]) |
---|
205 | remainRect[1] += 1 |
---|
206 | remainRect[2] -= 1 |
---|
207 | # check if marker has foucs |
---|
208 | if (self.mouseFocusX and self.mouseFocusY and (self.mousePositionY > self.markerRect[1]) and (self.mousePositionY < self.markerRect[3])): |
---|
209 | Blender.BGL.glColor3f(0.64,0.64,0.64) # marker focus grey |
---|
210 | else: |
---|
211 | Blender.BGL.glColor3f(0.60,0.60,0.60) # marker grey |
---|
212 | Blender.BGL.glRectf(remainRect[0], remainRect[1], remainRect[2], remainRect[3]) |
---|
213 | else: |
---|
214 | print "scrollbar draw size too small!" |
---|
215 | return |
---|
216 | |
---|
217 | def eventFilter(self, event, value): |
---|
218 | """event filter for keyboard and mouse input events |
---|
219 | call it inside the registered event function |
---|
220 | """ |
---|
221 | if (value != 0): |
---|
222 | # Buttons |
---|
223 | if (event == Blender.Draw.PAGEUPKEY): |
---|
224 | self.up(3) |
---|
225 | Blender.Draw.Redraw(1) |
---|
226 | elif (event == Blender.Draw.PAGEDOWNKEY): |
---|
227 | self.down(3) |
---|
228 | Blender.Draw.Redraw(1) |
---|
229 | elif (event == Blender.Draw.UPARROWKEY): |
---|
230 | self.up(1) |
---|
231 | Blender.Draw.Redraw(1) |
---|
232 | elif (event == Blender.Draw.DOWNARROWKEY): |
---|
233 | self.down(1) |
---|
234 | Blender.Draw.Redraw(1) |
---|
235 | # Mouse |
---|
236 | elif (event == Blender.Draw.MOUSEX): |
---|
237 | # check if mouse is inside positionRect |
---|
238 | if (value >= (self.guiRect[0] + self.positionRect[0])) and (value <= (self.guiRect[0] + self.positionRect[2])): |
---|
239 | # redraw if marker got focus |
---|
240 | if (not self.mouseFocusX) and self.mouseFocusY: |
---|
241 | Blender.Draw.Redraw(1) |
---|
242 | self.mouseFocusX = 1 |
---|
243 | else: |
---|
244 | # redraw if marker lost focus |
---|
245 | if self.mouseFocusX and self.mouseFocusY: |
---|
246 | Blender.Draw.Redraw(1) |
---|
247 | self.mouseFocusX = 0 |
---|
248 | elif (event == Blender.Draw.MOUSEY): |
---|
249 | # check if mouse is inside positionRect |
---|
250 | if (value >= (self.guiRect[1] + self.positionRect[1])) and (value <= (self.guiRect[1] + self.positionRect[3])): |
---|
251 | self.mouseFocusY = 1 |
---|
252 | # relative mouse position |
---|
253 | self.mousePositionY = value - self.guiRect[1] |
---|
254 | if ((self.mousePositionY > self.markerRect[1]) and (self.mousePositionY < self.markerRect[3])): |
---|
255 | # redraw if marker got focus |
---|
256 | if self.mouseFocusX and (not self.markerFocusY): |
---|
257 | Blender.Draw.Redraw(1) |
---|
258 | self.markerFocusY = 1 |
---|
259 | else: |
---|
260 | # redraw if marker lost focus |
---|
261 | if self.mouseFocusX and self.markerFocusY: |
---|
262 | Blender.Draw.Redraw(1) |
---|
263 | self.markerFocusY = 0 |
---|
264 | # move marker |
---|
265 | if (self.mousePressed == 1): |
---|
266 | # calculate step from distance to marker |
---|
267 | if (self.mousePositionY > self.markerRect[3]): |
---|
268 | # up |
---|
269 | self.up(1) |
---|
270 | Blender.Draw.Draw() |
---|
271 | elif (self.mousePositionY < self.markerRect[1]): |
---|
272 | # down |
---|
273 | self.down(1) |
---|
274 | Blender.Draw.Draw() |
---|
275 | # redraw if marker lost focus |
---|
276 | if self.mouseFocusX and self.mouseFocusY: |
---|
277 | Blender.Draw.Redraw(1) |
---|
278 | else: |
---|
279 | # redraw if marker lost focus |
---|
280 | if self.mouseFocusX and self.markerFocusY: |
---|
281 | Blender.Draw.Redraw(1) |
---|
282 | self.markerFocusY = 0 |
---|
283 | self.mouseFocusY = 0 |
---|
284 | elif ((event == Blender.Draw.LEFTMOUSE) and (self.mouseFocusX == 1) and (self.mouseFocusY == 1)): |
---|
285 | self.mousePressed = 1 |
---|
286 | # move marker |
---|
287 | if (self.mousePositionY > self.markerRect[3]): |
---|
288 | # up |
---|
289 | self.up(1) |
---|
290 | Blender.Draw.Redraw(1) |
---|
291 | elif (self.mousePositionY < self.markerRect[1]): |
---|
292 | # down |
---|
293 | self.down(1) |
---|
294 | Blender.Draw.Redraw(1) |
---|
295 | elif (Blender.Get("version") >= 234): |
---|
296 | if (event == Blender.Draw.WHEELUPMOUSE): |
---|
297 | self.up(1) |
---|
298 | Blender.Draw.Redraw(1) |
---|
299 | elif (event == Blender.Draw.WHEELDOWNMOUSE): |
---|
300 | self.down(1) |
---|
301 | Blender.Draw.Redraw(1) |
---|
302 | else: # released keys and buttons |
---|
303 | if (event == Blender.Draw.LEFTMOUSE): |
---|
304 | self.mousePressed = 0 |
---|
305 | |
---|
306 | return |
---|
307 | |
---|
308 | def buttonFilter(self, event): |
---|
309 | """button filter for Draw Button events |
---|
310 | call it inside the registered button function |
---|
311 | """ |
---|
312 | if (event == self.buttonUpEvent): |
---|
313 | self.up() |
---|
314 | Blender.Draw.Redraw(1) |
---|
315 | elif (event == self.buttonDownEvent): |
---|
316 | self.down() |
---|
317 | Blender.Draw.Redraw(1) |
---|
318 | return |
---|
319 | |
---|
320 | class ArmatureAction: |
---|
321 | """Resembles Blender's actions |
---|
322 | <ul> |
---|
323 | <li> import Blender, string |
---|
324 | </ul> |
---|
325 | |
---|
326 | @author Michael Reimpell |
---|
327 | """ |
---|
328 | def __init__(self, name="", ipoDict=None): |
---|
329 | """Constructor |
---|
330 | |
---|
331 | @param name the action name |
---|
332 | @param ipoDict a dictionary with bone names as keys and action Ipos as values |
---|
333 | """ |
---|
334 | self.firstKeyFrame = None |
---|
335 | self.lastKeyFrame = None |
---|
336 | self.name = name |
---|
337 | # ipoDict[boneName] = Blender.Ipo |
---|
338 | if ipoDict is None: |
---|
339 | self.ipoDict = {} |
---|
340 | else: |
---|
341 | self.ipoDict = ipoDict |
---|
342 | self._updateKeyFrameRange() |
---|
343 | return |
---|
344 | |
---|
345 | # private method |
---|
346 | def _updateKeyFrameRange(self): |
---|
347 | """Updates firstKeyFrame and lastKeyFrame considering the current IpoCurves. |
---|
348 | """ |
---|
349 | self.firstKeyFrame = None |
---|
350 | self.lastKeyFrame = None |
---|
351 | if self.ipoDict is not None: |
---|
352 | # check all bone Ipos |
---|
353 | for ipo in self.ipoDict.values(): |
---|
354 | # check all IpoCurves |
---|
355 | for ipoCurve in ipo.getCurves(): |
---|
356 | # check first and last keyframe |
---|
357 | for bezTriple in ipoCurve.getPoints(): |
---|
358 | iFrame = bezTriple.getPoints()[0] |
---|
359 | if ((iFrame < self.firstKeyFrame) or (self.firstKeyFrame is None)): |
---|
360 | self.firstKeyFrame = iFrame |
---|
361 | if ((iFrame > self.lastKeyFrame) or (self.lastKeyFrame is None)): |
---|
362 | self.lastKeyFrame = iFrame |
---|
363 | if self.firstKeyFrame == None: |
---|
364 | self.firstKeyFrame = 1 |
---|
365 | if self.lastKeyFrame == None: |
---|
366 | self.lastKeyFrame = 1 |
---|
367 | return |
---|
368 | |
---|
369 | # static method |
---|
370 | def createArmatureActionDict(object): |
---|
371 | """Creates a dictionary of possible actions belonging to an armature. |
---|
372 | Static call with: ArmatureAction.createArmatureActionDict(object) |
---|
373 | |
---|
374 | @param object a Blender.Object of type Armature |
---|
375 | @return a dictionary of ArmatureAction objects with name as key and ArmatureAction as value |
---|
376 | """ |
---|
377 | # create bone dict |
---|
378 | #boneQueue = object.getData().bones |
---|
379 | boneDict = object.getData().bones |
---|
380 | |
---|
381 | boneNameList = boneDict.keys() |
---|
382 | # check for available actions |
---|
383 | armatureActionDict = {} |
---|
384 | ## get linked action first |
---|
385 | linkedAction = object.getAction() |
---|
386 | if linkedAction is not None: |
---|
387 | # check all bones |
---|
388 | linkedActionIpoDict = linkedAction.getAllChannelIpos() |
---|
389 | hasValidChannel = 0 # false |
---|
390 | iBone = 0 |
---|
391 | while ((not hasValidChannel) and (iBone < len(boneNameList))): |
---|
392 | if (linkedActionIpoDict.keys().count(boneNameList[iBone]) == 1): |
---|
393 | if linkedActionIpoDict[boneNameList[iBone]].getNcurves(): |
---|
394 | hasValidChannel = 1 # true |
---|
395 | else: |
---|
396 | iBone += 1 |
---|
397 | else: |
---|
398 | iBone += 1 |
---|
399 | if hasValidChannel: |
---|
400 | # add action |
---|
401 | armatureActionDict[linkedAction.getName()] = ArmatureAction(linkedAction.getName(), linkedActionIpoDict) |
---|
402 | ## get other actions != linked action |
---|
403 | actionDict = Blender.Armature.NLA.GetActions() |
---|
404 | for actionName in actionDict.keys(): |
---|
405 | # check if action is not linked action |
---|
406 | if actionDict[actionName] is not linkedAction: |
---|
407 | # check all bones |
---|
408 | actionIpoDict = actionDict[actionName].getAllChannelIpos() |
---|
409 | hasValidChannel = 0 # false |
---|
410 | iBone = 0 |
---|
411 | while ((not hasValidChannel) and (iBone < len(boneNameList))): |
---|
412 | if (actionIpoDict.keys().count(boneNameList[iBone]) == 1): |
---|
413 | if actionIpoDict[boneNameList[iBone]].getNcurves(): |
---|
414 | hasValidChannel = 1 # true |
---|
415 | else: |
---|
416 | iBone += 1 |
---|
417 | else: |
---|
418 | iBone += 1 |
---|
419 | if hasValidChannel: |
---|
420 | |
---|
421 | # add action |
---|
422 | armatureActionDict[actionName] = ArmatureAction(actionName, actionIpoDict) |
---|
423 | return armatureActionDict |
---|
424 | createArmatureActionDict = staticmethod(createArmatureActionDict) |
---|
425 | |
---|
426 | class ArmatureActionActuator: |
---|
427 | """Resembles Blender's action actuators. |
---|
428 | |
---|
429 | @author Michael Reimpell |
---|
430 | """ |
---|
431 | def __init__(self, name, startFrame, endFrame, armatureAction): |
---|
432 | """Constructor |
---|
433 | |
---|
434 | @param name Animation name |
---|
435 | @param startFrame first frame of the animation |
---|
436 | @param endFrame last frame of the animation |
---|
437 | @param armatureAction ArmatureAction object of the animation |
---|
438 | """ |
---|
439 | self.name = name |
---|
440 | self.startFrame = startFrame |
---|
441 | self.endFrame = endFrame |
---|
442 | self.armatureAction = armatureAction |
---|
443 | return |
---|
444 | |
---|
445 | class ArmatureActionActuatorListView: |
---|
446 | """Mangages a list of ArmatureActionActuators. |
---|
447 | <ul> |
---|
448 | <li> import Blender |
---|
449 | <li> call eventFilter and buttonFilter in registered callbacks |
---|
450 | </ul> |
---|
451 | |
---|
452 | @author Michael Reimpell |
---|
453 | """ |
---|
454 | def __init__(self, armatureActionDict, maxActuators, buttonEventRangeStart, armatureAnimationDictList=None): |
---|
455 | """Constructor. |
---|
456 | |
---|
457 | @param armatureActionDict possible armature actuator actions |
---|
458 | @param maxActuators maximal number of actuator list elements |
---|
459 | @param buttonEventRangeStart first button event number. |
---|
460 | The number of used event numbers is (3 + maxActuators*5) |
---|
461 | @param armatureAnimationDictList list of armature animations (see getArmatureAnimationDictList()) |
---|
462 | """ |
---|
463 | self.armatureActionDict = armatureActionDict |
---|
464 | self.maxActuators = maxActuators |
---|
465 | self.buttonEventRangeStart = buttonEventRangeStart |
---|
466 | self.armatureActionActuatorList = [] |
---|
467 | self.armatureActionMenuList = [] |
---|
468 | self.startFrameNumberButtonList = [] |
---|
469 | self.endFrameNumberButtonList = [] |
---|
470 | self.animationNameStringButtonList = [] |
---|
471 | # scrollbar values: |
---|
472 | # 0:(len(self.armatureActionActuatorList)-1) = listIndex |
---|
473 | # len(self.armatureActionActuatorList) = addbuttonline |
---|
474 | self.scrollbar = ReplacementScrollbar(0,0,0, self.buttonEventRangeStart+1, self.buttonEventRangeStart+2) |
---|
475 | if armatureAnimationDictList is not None: |
---|
476 | # rebuild ArmatureActionActuators for animationList animations |
---|
477 | for animationDict in armatureAnimationDictList: |
---|
478 | # check if Action is available |
---|
479 | if self.armatureActionDict.has_key(animationDict['actionKey']): |
---|
480 | armatureActionActuator = ArmatureActionActuator(animationDict['name'], \ |
---|
481 | animationDict['startFrame'], \ |
---|
482 | animationDict['endFrame'], \ |
---|
483 | self.armatureActionDict[animationDict['actionKey']]) |
---|
484 | self._addArmatureActionActuator(armatureActionActuator) |
---|
485 | else: |
---|
486 | # create default ArmatureActionActuators |
---|
487 | for armatureAction in self.armatureActionDict.values(): |
---|
488 | # add default action |
---|
489 | armatureActionActuator = ArmatureActionActuator(armatureAction.name, armatureAction.firstKeyFrame, armatureAction.lastKeyFrame, armatureAction) |
---|
490 | self._addArmatureActionActuator(armatureActionActuator) |
---|
491 | return |
---|
492 | |
---|
493 | def refresh(self, armatureActionDict): |
---|
494 | """Delete ArmatureActionActuators for removed Actions. |
---|
495 | |
---|
496 | @param armatureActionDict possible ArmatureActuator actions |
---|
497 | """ |
---|
498 | self.armatureActionDict = armatureActionDict |
---|
499 | # delete ArmatureActionActuators for removed Actions |
---|
500 | for armatureActionActuator in self.armatureActionActuatorList[:]: |
---|
501 | # check if action is still available |
---|
502 | if not self.armatureActionDict.has_key(armatureActionActuator.armatureAction.name): |
---|
503 | # remove armatureActionActuator from lists |
---|
504 | listIndex = self.armatureActionActuatorList.index(armatureActionActuator) |
---|
505 | self._deleteArmatureActionActuator(listIndex) |
---|
506 | Blender.Draw.Redraw(1) |
---|
507 | return |
---|
508 | |
---|
509 | def draw(self, x, y, width, height): |
---|
510 | """draw actuatorList |
---|
511 | use scrollbar if needed |
---|
512 | """ |
---|
513 | # black border |
---|
514 | minX = x |
---|
515 | minY = y |
---|
516 | maxX = x + width |
---|
517 | maxY = y + height |
---|
518 | minWidth = 441 |
---|
519 | if ((width - 5) > minWidth): |
---|
520 | glColor3f(0.0,0.0,0.0) |
---|
521 | glRectf(minX, minY, maxX - 22, maxY) |
---|
522 | glColor3f(0.6,0.6,0.6) # Background: grey |
---|
523 | glRectf(minX + 1, minY + 1, maxX - 23, maxY - 1) |
---|
524 | x += 3 |
---|
525 | y += 3 |
---|
526 | width -= 5 |
---|
527 | height -= 6 |
---|
528 | else: |
---|
529 | print "ArmatureActionActuatorListView draw size to small!" |
---|
530 | glColor3f(0.0,0.0,0.0) |
---|
531 | glRectf(minX, minY, maxX, maxY) |
---|
532 | glColor3f(0.6,0.6,0.6) # Background: grey |
---|
533 | glRectf(minX + 1, minY + 1, maxX, maxY - 1) |
---|
534 | x += 3 |
---|
535 | y += 3 |
---|
536 | width -= 5 |
---|
537 | height -= 6 |
---|
538 | # Layout: |
---|
539 | # |---- 105 ---|2|----80---|2|---80---|2|---- >80 ----|2|---60---|2|----20---| |
---|
540 | # actionName | startFrame | endFrame | animationName | [delete] | scrollbar |
---|
541 | # [ add ] | scrollbar |
---|
542 | if (len(self.armatureActionDict.keys()) > 0): |
---|
543 | # construct actionMenu name |
---|
544 | menuValue = 0 |
---|
545 | menuName = "" |
---|
546 | for key in self.armatureActionDict.keys(): |
---|
547 | menuName += key + " %x" + ("%d" % menuValue) + "|" |
---|
548 | menuValue +=1 |
---|
549 | # first line |
---|
550 | lineY = y + height - 20 |
---|
551 | lineX = x |
---|
552 | listIndex = self.scrollbar.getCurrentValue() |
---|
553 | while ((listIndex < len(self.armatureActionActuatorList)) and (lineY >= y)): |
---|
554 | # still armatureActionActuators left to draw |
---|
555 | lineX = x |
---|
556 | armatureActionActuator = self.armatureActionActuatorList[listIndex] |
---|
557 | # draw actionMenu |
---|
558 | event = self.buttonEventRangeStart + 3 + listIndex |
---|
559 | menuValue = self.armatureActionDict.keys().index(armatureActionActuator.armatureAction.name) |
---|
560 | self.armatureActionMenuList[listIndex] = Blender.Draw.Menu(menuName,event, x, lineY, 105, 20, menuValue, "Action name") |
---|
561 | lineX += 107 |
---|
562 | # draw startFrameNumberButton |
---|
563 | event = self.buttonEventRangeStart + 3 + self.maxActuators + listIndex |
---|
564 | self.startFrameNumberButtonList[listIndex] = Blender.Draw.Number("Sta: ", event, lineX, lineY, 80, 20, \ |
---|
565 | armatureActionActuator.startFrame, -18000, 18000, "Start frame") |
---|
566 | lineX += 82 |
---|
567 | # draw endFrameNumberButton |
---|
568 | event = self.buttonEventRangeStart + 3 + 2*self.maxActuators + listIndex |
---|
569 | self.endFrameNumberButtonList[listIndex] = Blender.Draw.Number("End: ", event, lineX, lineY, 80, 20, \ |
---|
570 | armatureActionActuator.endFrame, -18000, 18000, "End frame") |
---|
571 | lineX += 82 |
---|
572 | # compute animationNameWidht |
---|
573 | animationNameWidth = width - 271 - 85 |
---|
574 | if (animationNameWidth < 80): |
---|
575 | animationNameWidth = 80 |
---|
576 | # draw animationNameStringButton |
---|
577 | event = self.buttonEventRangeStart + 3 + 3*self.maxActuators + listIndex |
---|
578 | self.animationNameStringButtonList[listIndex] = Blender.Draw.String("",event, lineX, lineY, animationNameWidth, 20, \ |
---|
579 | armatureActionActuator.name, 1000, "Animation export name") |
---|
580 | lineX += animationNameWidth + 2 |
---|
581 | # draw deleteButton |
---|
582 | event = self.buttonEventRangeStart + 3 + 4*self.maxActuators + listIndex |
---|
583 | Draw.Button("Delete", event, lineX, lineY, 60, 20, "Delete export animation") |
---|
584 | lineX += 62 |
---|
585 | # inc line |
---|
586 | lineY -= 22 |
---|
587 | listIndex += 1 |
---|
588 | # draw add button |
---|
589 | if (lineY >= y): |
---|
590 | Draw.Button("Add", self.buttonEventRangeStart, x, lineY, 60, 20, "Add new export animation") |
---|
591 | # draw scrollbar |
---|
592 | if (width > minWidth): |
---|
593 | # align left |
---|
594 | self.scrollbar.draw(maxX - 20, minY, 20, (maxY - minY)) |
---|
595 | return |
---|
596 | |
---|
597 | def eventFilter(self, event, value): |
---|
598 | """event filter for keyboard and mouse input events |
---|
599 | call it inside the registered event function |
---|
600 | """ |
---|
601 | self.scrollbar.eventFilter(event,value) |
---|
602 | return |
---|
603 | |
---|
604 | def buttonFilter(self, event): |
---|
605 | """button filter for Draw Button events |
---|
606 | call it inside the registered button function |
---|
607 | """ |
---|
608 | # button numbers = self.buttonEventRangeStart + buttonNumberOffset |
---|
609 | # buttonNumberOffsets: |
---|
610 | # addButton: 0 |
---|
611 | # scrollbar: 1 and 2 |
---|
612 | # actionMenu range: 3 <= event < 3 + maxActuators |
---|
613 | # startFrameNumberButton range: 3 + maxActuators <= event < 3 + 2*maxActuators |
---|
614 | # endFrameNumberButton range: 3 + 2*maxActuators <= event < 3 + 3*maxActuators |
---|
615 | # animationNameStringButton range: 3 + 3*maxActuators <= event < 3 + 4*maxActuators |
---|
616 | # deleteButton range: 3 + 4*maxActuators <= event < 3 + 5*maxActuators |
---|
617 | self.scrollbar.buttonFilter(event) |
---|
618 | relativeEvent = event - self.buttonEventRangeStart |
---|
619 | if (relativeEvent == 0): |
---|
620 | # add button pressed |
---|
621 | if (len(self.armatureActionDict.keys()) > 0): |
---|
622 | # add default ArmatureActionActuator |
---|
623 | armatureAction = self.armatureActionDict[self.armatureActionDict.keys()[0]] |
---|
624 | armatureActionActuator = ArmatureActionActuator(armatureAction.name, armatureAction.firstKeyFrame, armatureAction.lastKeyFrame, armatureAction) |
---|
625 | self._addArmatureActionActuator(armatureActionActuator) |
---|
626 | Blender.Draw.Redraw(1) |
---|
627 | elif ((3 <= relativeEvent) and (relativeEvent < (3 + self.maxActuators))): |
---|
628 | # actionMenu |
---|
629 | listIndex = relativeEvent - 3 |
---|
630 | armatureActionActuator = self.armatureActionActuatorList[listIndex] |
---|
631 | # button value is self.actionDict.keys().index |
---|
632 | keyIndex = self.armatureActionMenuList[listIndex].val |
---|
633 | key = self.armatureActionDict.keys()[keyIndex] |
---|
634 | armatureActionActuator.armatureAction = self.armatureActionDict[key] |
---|
635 | armatureActionActuator.startFrame = self.armatureActionDict[key].firstKeyFrame |
---|
636 | armatureActionActuator.endFrame = self.armatureActionDict[key].lastKeyFrame |
---|
637 | armatureActionActuator.name = self.armatureActionDict[key].name |
---|
638 | self.armatureActionActuatorList[listIndex] = armatureActionActuator |
---|
639 | Blender.Draw.Redraw(1) |
---|
640 | elif (((3 + self.maxActuators) <= relativeEvent) and (relativeEvent < (3 + 2*self.maxActuators))): |
---|
641 | # startFrameNumberButton |
---|
642 | listIndex = relativeEvent - (3 + self.maxActuators) |
---|
643 | armatureActionActuator = self.armatureActionActuatorList[listIndex] |
---|
644 | armatureActionActuator.startFrame = self.startFrameNumberButtonList[listIndex].val |
---|
645 | self.armatureActionActuatorList[listIndex] = armatureActionActuator |
---|
646 | elif (((3 + 2*self.maxActuators) <= relativeEvent) and (relativeEvent < (3 + 3*self.maxActuators))): |
---|
647 | # endFrameNumberButton |
---|
648 | listIndex = relativeEvent - (3 + 2*self.maxActuators) |
---|
649 | armatureActionActuator = self.armatureActionActuatorList[listIndex] |
---|
650 | armatureActionActuator.endFrame = self.endFrameNumberButtonList[listIndex].val |
---|
651 | self.armatureActionActuatorList[listIndex] = armatureActionActuator |
---|
652 | elif (((3 + 3*self.maxActuators) <= relativeEvent) and (relativeEvent < (3 + 4*self.maxActuators))): |
---|
653 | # animationNameStringButton |
---|
654 | listIndex = relativeEvent - (3 + 3*self.maxActuators) |
---|
655 | armatureActionActuator = self.armatureActionActuatorList[listIndex] |
---|
656 | armatureActionActuator.name = self.animationNameStringButtonList[listIndex].val |
---|
657 | self.armatureActionActuatorList[listIndex] = armatureActionActuator |
---|
658 | elif (((3 + 4*self.maxActuators) <= relativeEvent) and (relativeEvent < (3 + 5*self.maxActuators))): |
---|
659 | # deleteButton |
---|
660 | listIndex = relativeEvent - (3 + 4*self.maxActuators) |
---|
661 | self._deleteArmatureActionActuator(listIndex) |
---|
662 | Blender.Draw.Redraw(1) |
---|
663 | return |
---|
664 | |
---|
665 | def getArmatureAnimationDictList(self): |
---|
666 | """serialize the armatureActionActuatorList into a pickle storable list |
---|
667 | Each item of the returned list is a dictionary with key-value pairs: |
---|
668 | <ul> |
---|
669 | <li> name - ArmatureActionActuator.name |
---|
670 | <li> startFrame - ArmatureActionActuator.startFrame |
---|
671 | <li> endFrame - ArmatureActionActuator.endFrame |
---|
672 | <li> armatureActionKey - ArmatureActionActuator.armatureAction.name |
---|
673 | </ul> |
---|
674 | |
---|
675 | @return serialized actionActuatorList |
---|
676 | """ |
---|
677 | animationDictList = [] |
---|
678 | for armatureActionActuator in self.armatureActionActuatorList: |
---|
679 | # create animationDict |
---|
680 | animationDict = {} |
---|
681 | animationDict['name'] = armatureActionActuator.name |
---|
682 | animationDict['startFrame'] = armatureActionActuator.startFrame |
---|
683 | animationDict['endFrame'] = armatureActionActuator.endFrame |
---|
684 | animationDict['actionKey'] = armatureActionActuator.armatureAction.name |
---|
685 | animationDictList.append(animationDict) |
---|
686 | return animationDictList |
---|
687 | |
---|
688 | def setAnimationDictList(self, animationDictList): |
---|
689 | """loads old AnimationDictList with actionKey = (ipoPrefix, ipoPostfix) |
---|
690 | |
---|
691 | @see #getArmatureAnimationDictList() |
---|
692 | """ |
---|
693 | # rebuild ArmatureActionActuators for animationList animations |
---|
694 | for animationDict in animationDictList: |
---|
695 | # check if Action is available |
---|
696 | prefix, postfix = animationDict['actionKey'] |
---|
697 | armatureActionName = prefix+postfix |
---|
698 | if self.armatureActionDict.has_key(armatureActionName): |
---|
699 | armatureActionActuator = ArmatureActionActuator(animationDict['name'], \ |
---|
700 | animationDict['startFrame'], \ |
---|
701 | animationDict['endFrame'], \ |
---|
702 | self.armatureActionDict[armatureActionName]) |
---|
703 | self._addArmatureActionActuator(armatureActionActuator) |
---|
704 | return |
---|
705 | |
---|
706 | # private methods |
---|
707 | def _addArmatureActionActuator(self, armatureActionActuator): |
---|
708 | """adds an ArmatureActionActuator to the list |
---|
709 | <ul> |
---|
710 | <li> call Blender.Draw.Redraw(1) afterwards |
---|
711 | </ul> |
---|
712 | """ |
---|
713 | if (len(self.armatureActionActuatorList) < self.maxActuators): |
---|
714 | # check if armatureActionActuator.action is available |
---|
715 | if armatureActionActuator.armatureAction.name in self.armatureActionDict.keys(): |
---|
716 | # create armatureActionMenu |
---|
717 | # get ArmatureAction index in armatureActionDict.keys() list |
---|
718 | armatureActionMenu = Draw.Create(self.armatureActionDict.keys().index(armatureActionActuator.armatureAction.name)) |
---|
719 | self.armatureActionMenuList.append(armatureActionMenu) |
---|
720 | # create startFrameNumberButton |
---|
721 | startFrameNumberButton = Draw.Create(int(armatureActionActuator.startFrame)) |
---|
722 | self.startFrameNumberButtonList.append(startFrameNumberButton) |
---|
723 | # create endFrameNumberButton |
---|
724 | endFrameNumberButton = Draw.Create(int(armatureActionActuator.endFrame)) |
---|
725 | self.endFrameNumberButtonList.append(endFrameNumberButton) |
---|
726 | # create animationNameStringButton |
---|
727 | animationNameStringButton = Draw.Create(armatureActionActuator.name) |
---|
728 | self.animationNameStringButtonList.append(animationNameStringButton) |
---|
729 | # append to armatureActionActuatorList |
---|
730 | self.armatureActionActuatorList.append(armatureActionActuator) |
---|
731 | # adjust scrollbar |
---|
732 | scrollbarPosition = self.scrollbar.getCurrentValue() |
---|
733 | self.scrollbar = ReplacementScrollbar(scrollbarPosition,0,len(self.armatureActionActuatorList), self.buttonEventRangeStart+1, self.buttonEventRangeStart+2) |
---|
734 | # TODO: change scrollbarPosition in a way, such that the new actuator is visible |
---|
735 | else: |
---|
736 | print "Error: Could not add ArmatureActionActuator because ArmatureAction is not available!" |
---|
737 | return |
---|
738 | |
---|
739 | def _deleteArmatureActionActuator(self, listIndex): |
---|
740 | """removes an ArmatureActionActuator from the list |
---|
741 | <ul> |
---|
742 | <li> call Blender.Draw.Redraw(1) afterwards |
---|
743 | </ul> |
---|
744 | """ |
---|
745 | # check listIndex |
---|
746 | if ((len(self.armatureActionActuatorList) > 0) and (listIndex >= 0) and (listIndex < len(self.armatureActionActuatorList))): |
---|
747 | # remove armatureActionMenu |
---|
748 | self.armatureActionMenuList.pop(listIndex) |
---|
749 | # remove startFrameNumberButton |
---|
750 | self.startFrameNumberButtonList.pop(listIndex) |
---|
751 | # remove endFrameNumberButton |
---|
752 | self.endFrameNumberButtonList.pop(listIndex) |
---|
753 | # remove animationNameStringButton |
---|
754 | self.animationNameStringButtonList.pop(listIndex) |
---|
755 | # remove armatureActionActuator |
---|
756 | self.armatureActionActuatorList.pop(listIndex) |
---|
757 | # adjust scrollbar |
---|
758 | scrollbarPosition = self.scrollbar.getCurrentValue() |
---|
759 | if (scrollbarPosition > len(self.armatureActionActuatorList)): |
---|
760 | scrollbarPosition = len(self.armatureActionActuatorList) |
---|
761 | self.scrollbar = ReplacementScrollbar(scrollbarPosition,0,len(self.armatureActionActuatorList), self.buttonEventRangeStart+1, self.buttonEventRangeStart+2) |
---|
762 | return |
---|
763 | |
---|
764 | class Logger: |
---|
765 | """Logs messages and status. |
---|
766 | |
---|
767 | Logs messages as a list of strings and keeps track of the status. |
---|
768 | Possible status values are info, warning and error. |
---|
769 | |
---|
770 | @cvar INFO info status |
---|
771 | @cvar WARNING warning status |
---|
772 | @cvar ERROR error status |
---|
773 | """ |
---|
774 | INFO, WARNING, ERROR = range(3) |
---|
775 | def __init__(self): |
---|
776 | """Constructor. |
---|
777 | """ |
---|
778 | self.messageList = [] |
---|
779 | self.status = Logger.INFO |
---|
780 | return |
---|
781 | def logInfo(self, message): |
---|
782 | """Logs an info message. |
---|
783 | |
---|
784 | @param message message string |
---|
785 | """ |
---|
786 | self.messageList.append((Logger.INFO, message)) |
---|
787 | return |
---|
788 | def logWarning(self, message): |
---|
789 | """Logs a warning message. |
---|
790 | |
---|
791 | The status is set to <code>Logger.WARNING</code> if it is not already <code>Logger.ERROR</code>. |
---|
792 | |
---|
793 | @param message message string |
---|
794 | """ |
---|
795 | self.messageList.append((Logger.WARNING, "Warning: "+message)) |
---|
796 | if not self.status == Logger.ERROR: |
---|
797 | self.status = Logger.WARNING |
---|
798 | return |
---|
799 | def logError(self, message): |
---|
800 | """Logs an error message. |
---|
801 | |
---|
802 | The status is set to <code>Logger.ERROR</code>. |
---|
803 | |
---|
804 | @param message message string |
---|
805 | """ |
---|
806 | self.messageList.append((Logger.ERROR, "Error: "+message)) |
---|
807 | self.status = Logger.ERROR |
---|
808 | return |
---|
809 | def getStatus(self): |
---|
810 | """Gets the current status. |
---|
811 | |
---|
812 | The status can be |
---|
813 | <ul> |
---|
814 | <li><code>Logger.INFO</code> |
---|
815 | <li><code>Logger.WARNING</code> |
---|
816 | <li><code>Logger.ERROR</code> |
---|
817 | </ul> |
---|
818 | |
---|
819 | @return status |
---|
820 | """ |
---|
821 | return self.status |
---|
822 | def getMessageList(self): |
---|
823 | """Returns the list of log messages. |
---|
824 | |
---|
825 | @return list of tuples (status, message) |
---|
826 | """ |
---|
827 | return self.messageList |
---|
828 | |
---|
829 | class LogInterface: |
---|
830 | def __init__(self): |
---|
831 | self.loggerList = [] |
---|
832 | def addLogger(self, logger): |
---|
833 | self.loggerList.append(logger) |
---|
834 | return |
---|
835 | def removeLogger(self, logger): |
---|
836 | self.loggerList.remove(logger) |
---|
837 | return |
---|
838 | # protected |
---|
839 | def _logInfo(self, message): |
---|
840 | for logger in self.loggerList: |
---|
841 | logger.logInfo(message) |
---|
842 | return |
---|
843 | def _logWarning(self, message): |
---|
844 | for logger in self.loggerList: |
---|
845 | logger.logWarning(message) |
---|
846 | return |
---|
847 | def _logError(self, message): |
---|
848 | for logger in self.loggerList: |
---|
849 | logger.logWarning(message) |
---|
850 | return |
---|
851 | |
---|
852 | class PathName(LogInterface): |
---|
853 | """Splits a pathname independent of the underlying os. |
---|
854 | |
---|
855 | Blender saves pathnames in the os specific manner. Using os.path may result in problems |
---|
856 | when the export is done on a different os than the creation of the .blend file. |
---|
857 | """ |
---|
858 | def __init__(self, pathName): |
---|
859 | self.pathName = pathName |
---|
860 | LogInterface.__init__(self) |
---|
861 | return |
---|
862 | def dirname(self): |
---|
863 | return os.path.dirname(self.pathName) |
---|
864 | def basename(self): |
---|
865 | baseName = os.path.basename(self.pathName) |
---|
866 | # split from non-os directories |
---|
867 | # \\ |
---|
868 | baseName = baseName.split('\\').pop() |
---|
869 | # / |
---|
870 | baseName = baseName.split('/').pop() |
---|
871 | if (baseName != baseName.replace(' ','_')): |
---|
872 | # replace whitespace with underscore |
---|
873 | self._logWarning("Whitespaces in filename \"%s\" replaced with underscores." % baseName) |
---|
874 | baseName = baseName.replace(' ','_') |
---|
875 | return baseName |
---|
876 | def path(self): |
---|
877 | return self.pathName |
---|
878 | |
---|
879 | class ExportOptions: |
---|
880 | """Encapsulates export options common to all objects. |
---|
881 | """ |
---|
882 | # TODO: Model for GUI |
---|
883 | def __init__(self, rotXAngle, rotYAngle, rotZAngle, scale, useWorldCoordinates, colouredAmbient, exportPath, materialFilename): |
---|
884 | """Constructor. |
---|
885 | """ |
---|
886 | # floating point accuracy |
---|
887 | self.accuracy = 1e-6 |
---|
888 | # export transformation |
---|
889 | self.rotXAngle = rotXAngle |
---|
890 | self.rotYAngle = rotYAngle |
---|
891 | self.rotZAngle = rotZAngle |
---|
892 | self.scale = scale |
---|
893 | self.useWorldCoordinates = useWorldCoordinates |
---|
894 | self.colouredAmbient = colouredAmbient |
---|
895 | # file settings |
---|
896 | self.exportPath = exportPath |
---|
897 | self.materialFilename = materialFilename |
---|
898 | return |
---|
899 | |
---|
900 | def transformationMatrix(self): |
---|
901 | """Returns the matrix representation for the additional transformation on export. |
---|
902 | """ |
---|
903 | rotationMatrix = Mathutils.RotationMatrix(self.rotXAngle,4,'x') |
---|
904 | rotationMatrix *= Mathutils.RotationMatrix(self.rotYAngle,4,'y') |
---|
905 | rotationMatrix *= Mathutils.RotationMatrix(self.rotZAngle,4,'z') |
---|
906 | scaleMatrix = Mathutils.Matrix([self.scale,0,0],[0,self.scale,0],[0,0,self.scale]) |
---|
907 | scaleMatrix.resize4x4() |
---|
908 | return rotationMatrix*scaleMatrix |
---|
909 | |
---|
910 | class ObjectExporter: |
---|
911 | """Interface. Exports a Blender object to Ogre. |
---|
912 | """ |
---|
913 | def __init__(self, object): |
---|
914 | """Constructor. |
---|
915 | |
---|
916 | @param object Blender object to export. |
---|
917 | """ |
---|
918 | self.object = object |
---|
919 | return |
---|
920 | |
---|
921 | def getName(self): |
---|
922 | """Returns the name of the object. |
---|
923 | """ |
---|
924 | return self.object.getName() |
---|
925 | |
---|
926 | def getObjectMatrix(self): |
---|
927 | """Returns the object matrix in worldspace. |
---|
928 | """ |
---|
929 | return self.object.matrixWorld |
---|
930 | |
---|
931 | |
---|
932 | class MeshExporter(ObjectExporter): |
---|
933 | """ |
---|
934 | """ |
---|
935 | def getName(self): |
---|
936 | return self.object.getData().name |
---|
937 | |
---|
938 | class ArmatureExporter: |
---|
939 | """Exports an armature of a mesh. |
---|
940 | """ |
---|
941 | # TODO: Provide bone ids for vertex influences. |
---|
942 | def __init__(self, meshObject, armatureObject): |
---|
943 | """Constructor. |
---|
944 | |
---|
945 | @param meshObject ObjectExporter. |
---|
946 | @param armatureObject Blender armature object. |
---|
947 | """ |
---|
948 | self.meshObject = meshObject |
---|
949 | self.armatureObject = armatureObject |
---|
950 | self.skeleton = None |
---|
951 | return |
---|
952 | |
---|
953 | def export(self, actionActuatorList, exportOptions, logger): |
---|
954 | """Exports the armature. |
---|
955 | |
---|
956 | @param actionActuatorList list of animations to export. |
---|
957 | @param exportOptions global export options. |
---|
958 | @param logger Logger Logger for log messages. |
---|
959 | """ |
---|
960 | # convert Armature into Skeleton |
---|
961 | name = None |
---|
962 | if exportOptions.useWorldCoordinates: |
---|
963 | name = self.armatureObject.getData().name |
---|
964 | else: |
---|
965 | name = self.meshObject.getName() + "-" + self.armatureObject.getData().name |
---|
966 | skeleton = Skeleton(name) |
---|
967 | skeleton = self._convertRestpose(skeleton, exportOptions, logger) |
---|
968 | |
---|
969 | # convert ActionActuators into Animations |
---|
970 | self._convertAnimations(skeleton, actionActuatorList, exportOptions, exportLogger) |
---|
971 | |
---|
972 | # write to file |
---|
973 | self._toFile(skeleton, exportOptions, exportLogger) |
---|
974 | |
---|
975 | self.skeleton = skeleton |
---|
976 | return |
---|
977 | |
---|
978 | def _convertAnimations(self, skeleton, armatureActionActuatorList, exportOptions, exportLogger): |
---|
979 | """Converts ActionActuators to Ogre animations. |
---|
980 | """ |
---|
981 | # frames per second |
---|
982 | fps = Blender.Scene.GetCurrent().getRenderingContext().framesPerSec() |
---|
983 | # map armatureActionActuatorList to skeleton.animationsDict |
---|
984 | for armatureActionActuator in armatureActionActuatorList: |
---|
985 | # map armatureActionActuator to animation |
---|
986 | if (not skeleton.animationsDict.has_key(armatureActionActuator.name)): |
---|
987 | # create animation |
---|
988 | animation = Animation(armatureActionActuator.name) |
---|
989 | # map bones to tracks |
---|
990 | for boneName in armatureActionActuator.armatureAction.ipoDict.keys(): |
---|
991 | if (not(animation.tracksDict.has_key(boneName))): |
---|
992 | # get bone object |
---|
993 | if skeleton.bonesDict.has_key(boneName): |
---|
994 | # create track |
---|
995 | track = Track(animation, skeleton.bonesDict[boneName]) |
---|
996 | # map ipocurves to keyframes |
---|
997 | # get ipo for that bone |
---|
998 | ipo = armatureActionActuator.armatureAction.ipoDict[boneName] |
---|
999 | # map curve names to curvepos |
---|
1000 | curveId = {} |
---|
1001 | index = 0 |
---|
1002 | have_quat = 0 |
---|
1003 | for curve in ipo.getCurves(): |
---|
1004 | try: |
---|
1005 | name = curve.getName() |
---|
1006 | if (name == "LocX" or name == "LocY" or name == "LocZ" or \ |
---|
1007 | name == "SizeX" or name == "SizeY" or name == "SizeZ" or \ |
---|
1008 | name == "QuatX" or name == "QuatY" or name == "QuatZ" or name == "QuatW"): |
---|
1009 | curveId[name] = index |
---|
1010 | index += 1 |
---|
1011 | else: |
---|
1012 | # bug: 2.28 does not return "Quat*"... |
---|
1013 | if not have_quat: |
---|
1014 | curveId["QuatX"] = index |
---|
1015 | curveId["QuatY"] = index+1 |
---|
1016 | curveId["QuatZ"] = index+2 |
---|
1017 | curveId["QuatW"] = index+3 |
---|
1018 | index += 4 |
---|
1019 | have_quat = 1 |
---|
1020 | except TypeError: |
---|
1021 | # blender 2.32 does not implement IpoCurve.getName() for action Ipos |
---|
1022 | if not have_quat: |
---|
1023 | # no automatic assignments so far |
---|
1024 | # guess Ipo Names |
---|
1025 | nIpoCurves = ipo.getNcurves() |
---|
1026 | if nIpoCurves in [4,7,10]: |
---|
1027 | exportLogger.logWarning("IpoCurve.getName() not available!") |
---|
1028 | exportLogger.logWarning("The exporter tries to guess the IpoCurve names.") |
---|
1029 | if (nIpoCurves >= 7): |
---|
1030 | # not only Quats |
---|
1031 | # guess: Quats and Locs |
---|
1032 | curveId["LocX"] = index |
---|
1033 | curveId["LocY"] = index+1 |
---|
1034 | curveId["LocZ"] = index+2 |
---|
1035 | index += 3 |
---|
1036 | if (nIpoCurves == 10): |
---|
1037 | # all possible Action IpoCurves |
---|
1038 | curveId["SizeX"] = index |
---|
1039 | curveId["SizeY"] = index+1 |
---|
1040 | curveId["SizeZ"] = index+2 |
---|
1041 | index += 3 |
---|
1042 | if (nIpoCurves >= 4): |
---|
1043 | # at least 4 IpoCurves |
---|
1044 | # guess: 4 Quats |
---|
1045 | curveId["QuatX"] = index |
---|
1046 | curveId["QuatY"] = index+1 |
---|
1047 | curveId["QuatZ"] = index+2 |
---|
1048 | curveId["QuatW"] = index+3 |
---|
1049 | index += 4 |
---|
1050 | have_quat = 1 |
---|
1051 | else: |
---|
1052 | exportLogger.logError("IpoCurve.getName() not available!") |
---|
1053 | exportLogger.logError("Could not guess the IpoCurve names. Other Blender versions may work.") |
---|
1054 | # get all frame numbers between startFrame and endFrame where this ipo has a point in one of its curves |
---|
1055 | frameNumberDict = {} |
---|
1056 | for curveIndex in range(ipo.getNcurves()): |
---|
1057 | for bez in range(ipo.getNBezPoints(curveIndex)): |
---|
1058 | frame = int(ipo.getCurveBeztriple(curveIndex, bez)[3]) |
---|
1059 | frameNumberDict[frame] = frame |
---|
1060 | frameNumberDict[armatureActionActuator.startFrame] = armatureActionActuator.startFrame |
---|
1061 | frameNumberDict[armatureActionActuator.endFrame] = armatureActionActuator.endFrame |
---|
1062 | # remove frame numbers not in the startFrame endFrame range |
---|
1063 | if (armatureActionActuator.startFrame > armatureActionActuator.endFrame): |
---|
1064 | minFrame = armatureActionActuator.endFrame |
---|
1065 | maxFrame = armatureActionActuator.startFrame |
---|
1066 | else: |
---|
1067 | minFrame = armatureActionActuator.startFrame |
---|
1068 | maxFrame = armatureActionActuator.endFrame |
---|
1069 | for frameNumber in frameNumberDict.keys()[:]: |
---|
1070 | if ((frameNumber < minFrame) or (frameNumber > maxFrame)): |
---|
1071 | del frameNumberDict[frameNumber] |
---|
1072 | frameNumberList = frameNumberDict.keys() |
---|
1073 | # convert frame numbers to seconds |
---|
1074 | # frameNumberDict: key = export time, value = frame number |
---|
1075 | frameNumberDict = {} |
---|
1076 | for frameNumber in frameNumberList: |
---|
1077 | if (armatureActionActuator.startFrame <= armatureActionActuator.endFrame): |
---|
1078 | # forward animation |
---|
1079 | time = float(frameNumber-armatureActionActuator.startFrame)/fps |
---|
1080 | else: |
---|
1081 | # backward animation |
---|
1082 | time = float(armatureActionActuator.endFrame-frameNumber)/fps |
---|
1083 | # update animation duration |
---|
1084 | if animation.duration < time: |
---|
1085 | animation.duration = time |
---|
1086 | frameNumberDict[time] = frameNumber |
---|
1087 | # create key frames |
---|
1088 | timeList = frameNumberDict.keys() |
---|
1089 | timeList.sort() |
---|
1090 | for time in timeList: |
---|
1091 | # Blender's ordering of transformations is deltaR*deltaS*deltaT |
---|
1092 | # in the bone's coordinate system. |
---|
1093 | frame = frameNumberDict[time] |
---|
1094 | loc = ( 0.0, 0.0, 0.0 ) |
---|
1095 | rotQuat = Mathutils.Quaternion([1.0, 0.0, 0.0, 0.0]) |
---|
1096 | sizeX = 1.0 |
---|
1097 | sizeY = 1.0 |
---|
1098 | sizeZ = 1.0 |
---|
1099 | blenderLoc = [0, 0, 0] |
---|
1100 | hasLocKey = 0 #false |
---|
1101 | if curveId.has_key("LocX"): |
---|
1102 | blenderLoc[0] = ipo.EvaluateCurveOn(curveId["LocX"], frame) |
---|
1103 | hasLocKey = 1 #true |
---|
1104 | if curveId.has_key("LocY"): |
---|
1105 | blenderLoc[1] = ipo.EvaluateCurveOn(curveId["LocY"], frame) |
---|
1106 | hasLocKey = 1 #true |
---|
1107 | if curveId.has_key("LocZ"): |
---|
1108 | blenderLoc[2] = ipo.EvaluateCurveOn(curveId["LocZ"], frame) |
---|
1109 | hasLocKey = 1 #true |
---|
1110 | if hasLocKey: |
---|
1111 | # Ogre's deltaT is in the bone's parent coordinate system |
---|
1112 | loc = point_by_matrix(blenderLoc, skeleton.bonesDict[boneName].conversionMatrix) |
---|
1113 | if curveId.has_key("QuatX") and curveId.has_key("QuatY") and curveId.has_key("QuatZ") and curveId.has_key("QuatW"): |
---|
1114 | if not (Blender.Get("version") == 234): |
---|
1115 | rot = [ ipo.EvaluateCurveOn(curveId["QuatW"], frame), \ |
---|
1116 | ipo.EvaluateCurveOn(curveId["QuatX"], frame), \ |
---|
1117 | ipo.EvaluateCurveOn(curveId["QuatY"], frame), \ |
---|
1118 | ipo.EvaluateCurveOn(curveId["QuatZ"], frame) ] |
---|
1119 | rotQuat = Mathutils.Quaternion(rot) |
---|
1120 | else: |
---|
1121 | # Blender 2.34 quaternion naming bug |
---|
1122 | rot = [ ipo.EvaluateCurveOn(curveId["QuatX"], frame), \ |
---|
1123 | ipo.EvaluateCurveOn(curveId["QuatY"], frame), \ |
---|
1124 | ipo.EvaluateCurveOn(curveId["QuatZ"], frame), \ |
---|
1125 | ipo.EvaluateCurveOn(curveId["QuatW"], frame) ] |
---|
1126 | rotQuat = Mathutils.Quaternion(rot) |
---|
1127 | rotQuat.normalize() |
---|
1128 | if curveId.has_key("SizeX"): |
---|
1129 | sizeX = ipo.EvaluateCurveOn(curveId["SizeX"], frame) |
---|
1130 | if curveId.has_key("SizeY"): |
---|
1131 | sizeY = ipo.EvaluateCurveOn(curveId["SizeY"], frame) |
---|
1132 | if curveId.has_key("SizeZ"): |
---|
1133 | sizeZ = ipo.EvaluateCurveOn(curveId["SizeZ"], frame) |
---|
1134 | size = (sizeX, sizeY, sizeZ) |
---|
1135 | KeyFrame(track, time, loc, rotQuat, size) |
---|
1136 | # append track |
---|
1137 | animation.tracksDict[boneName] = track |
---|
1138 | else: |
---|
1139 | # ipo name contains bone but armature doesn't |
---|
1140 | exportLogger.logWarning("Unused action channel \"%s\" in action \"%s\" for skeleton \"%s\"." \ |
---|
1141 | % (boneName, armatureActionActuator.armatureAction.name, skeleton.name)) |
---|
1142 | else: |
---|
1143 | # track for that bone already exists |
---|
1144 | exportLogger.logError("Ambiguous bone name \"%s\", track already exists." % boneName) |
---|
1145 | # append animation |
---|
1146 | skeleton.animationsDict[armatureActionActuator.name] = animation |
---|
1147 | else: |
---|
1148 | # animation export name already exists |
---|
1149 | exportLogger.logError("Ambiguous animation name \"%s\"." % armatureActionActuator.name) |
---|
1150 | return |
---|
1151 | |
---|
1152 | def _convertRestpose(self, skeleton, exportOptions, logger): |
---|
1153 | """Calculate inital bone positions and rotations. |
---|
1154 | """ |
---|
1155 | print "convert posed started" |
---|
1156 | obj = self.armatureObject |
---|
1157 | stack = [] |
---|
1158 | matrix = None |
---|
1159 | matrix_one = Mathutils.Matrix([1.0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) |
---|
1160 | if exportOptions.useWorldCoordinates: |
---|
1161 | # world coordinates |
---|
1162 | matrix = obj.getMatrix("worldspace") |
---|
1163 | else: |
---|
1164 | # local mesh coordinates |
---|
1165 | armatureMatrix = obj.getMatrix("worldspace") |
---|
1166 | # Blender returns direct access to matrix but we only want a copy |
---|
1167 | # since we will be inverting it |
---|
1168 | inverseMeshMatrix = matrix_one * self.meshObject.getObjectMatrix() |
---|
1169 | inverseMeshMatrix.invert() |
---|
1170 | matrix = armatureMatrix*inverseMeshMatrix |
---|
1171 | # apply additional export transformation |
---|
1172 | matrix = matrix*exportOptions.transformationMatrix() |
---|
1173 | loc = [ 0.0, 0, 0 ] |
---|
1174 | parent = None |
---|
1175 | |
---|
1176 | # get parent bones |
---|
1177 | #note: in Blender 2.4, bones returns a dictionary of all bones in an armature |
---|
1178 | boneDict = obj.getData().bones |
---|
1179 | for bbone in boneDict.values(): |
---|
1180 | #print bbone, bbone.parent |
---|
1181 | if bbone.parent == None: |
---|
1182 | stack.append([bbone, parent, matrix, loc, 0, matrix_one]) |
---|
1183 | |
---|
1184 | # iterate through bones and build ogre equivalent bones |
---|
1185 | # blend bone matrix in armature space is perfect for ogre equivalency |
---|
1186 | # |
---|
1187 | while len(stack): |
---|
1188 | bbone, parent, accu_mat, parent_pos, parent_ds, invertedOgreTransformation = stack.pop() |
---|
1189 | # preconditions: (R : rotation, T : translation, S : scale, M: general transformation matrix) |
---|
1190 | # accu_mat |
---|
1191 | # points to the tail of the parents bone, i.e. for root bones |
---|
1192 | # accu_mat = M_{object}*R_{additional on export} |
---|
1193 | # and for child bones |
---|
1194 | # accu_mat = T_{length of parent}*R_{parent}*T_{to head of parent}*M_{parent's parent} |
---|
1195 | # invertedOgreTransformation |
---|
1196 | # inverse of transformation done in Ogre so far, i.e. identity for root bones, |
---|
1197 | # M^{-1}_{Ogre, parent's parent}*T^{-1}_{Ogre, parent}*R^{-1}_{Ogre, parent} for child bones. |
---|
1198 | |
---|
1199 | head = bbone.head['BONESPACE'] |
---|
1200 | tail = bbone.tail['BONESPACE'] |
---|
1201 | |
---|
1202 | # get the restmat |
---|
1203 | R_bmat = bbone.matrix['BONESPACE'].rotationPart() |
---|
1204 | rotQuat = R_bmat.toQuat() |
---|
1205 | R_bmat.resize4x4() |
---|
1206 | |
---|
1207 | #get the bone's root offset (in the parent's coordinate system) |
---|
1208 | T_root = [ [ 1, 0, 0, 0 ], |
---|
1209 | [ 0, 1, 0, 0 ], |
---|
1210 | [ 0, 0, 1, 0 ], |
---|
1211 | [ head[0], head[1], head[2], 1 ] ] |
---|
1212 | |
---|
1213 | # get the bone length translation (length along y axis) |
---|
1214 | dx, dy, dz = tail[0] - head[0], tail[1] - head[1], tail[2] - head[2] |
---|
1215 | ds = math.sqrt(dx*dx + dy*dy + dz*dz) |
---|
1216 | T_len = [ [ 1, 0, 0, 0 ], |
---|
1217 | [ 0, 1, 0, 0 ], |
---|
1218 | [ 0, 0, 1, 0 ], |
---|
1219 | [ 0, ds, 0, 1 ] ] |
---|
1220 | |
---|
1221 | # calculate bone points in world coordinates |
---|
1222 | accu_mat = matrix_multiply(accu_mat, T_root) |
---|
1223 | pos = point_by_matrix([ 0, 0, 0 ], accu_mat) |
---|
1224 | |
---|
1225 | accu_mat = tmp_mat = matrix_multiply(accu_mat, R_bmat) |
---|
1226 | # tmp_mat = R_{bone}*T_{to head}*M_{parent} |
---|
1227 | accu_mat = matrix_multiply(accu_mat, T_len) |
---|
1228 | |
---|
1229 | # local rotation and distance from parent bone |
---|
1230 | if parent: |
---|
1231 | rotQuat = bbone.matrix['BONESPACE'].rotationPart().toQuat() |
---|
1232 | else: |
---|
1233 | rotQuat = (bbone.matrix['BONESPACE'].rotationPart().resize4x4()*matrix).toQuat() |
---|
1234 | |
---|
1235 | x, y, z = pos |
---|
1236 | # pos = loc * M_{Ogre} |
---|
1237 | loc = point_by_matrix([x, y, z], invertedOgreTransformation) |
---|
1238 | x, y, z = loc |
---|
1239 | ogreTranslationMatrix = [[ 1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [x, y, z, 1]] |
---|
1240 | |
---|
1241 | # R_{Ogre} is either |
---|
1242 | # the rotation part of R_{bone}*T_{to_head}*M_{parent} for root bones or |
---|
1243 | # the rotation part of R_{bone}*T_{to_head} of child bones |
---|
1244 | ogreRotationMatrix = rotQuat.toMatrix() |
---|
1245 | ogreRotationMatrix.resize4x4() |
---|
1246 | invertedOgreTransformation = matrix_multiply(matrix_invert(ogreTranslationMatrix), invertedOgreTransformation) |
---|
1247 | parent = Bone(skeleton, parent, bbone.name, loc, rotQuat, matrix_multiply(invertedOgreTransformation, tmp_mat)) |
---|
1248 | #print "bone created:", parent |
---|
1249 | # matrix_multiply(invertedOgreTransformation, tmp_mat) is R*T*M_{parent} M^{-1}_{Ogre}T^{-1}_{Ogre}. |
---|
1250 | # Necessary, since Ogre's delta location is in the Bone's parent coordinate system, i.e. |
---|
1251 | # deltaT_{Blender}*R*T*M = deltaT_{Ogre}*T_{Ogre}*M_{Ogre} |
---|
1252 | invertedOgreTransformation = matrix_multiply(matrix_invert(ogreRotationMatrix), invertedOgreTransformation) |
---|
1253 | if bbone.children is not None: |
---|
1254 | for child in bbone.children: |
---|
1255 | # make sure child bone is attached to current parent |
---|
1256 | if child.parent is not None: |
---|
1257 | if child.parent.name == bbone.name: |
---|
1258 | stack.append([child, parent, accu_mat, pos, ds, invertedOgreTransformation]) |
---|
1259 | return skeleton |
---|
1260 | |
---|
1261 | def _toFile(self, skeleton, exportOptions, exportLogger): |
---|
1262 | """Writes converted skeleton to file. |
---|
1263 | """ |
---|
1264 | file = skeleton.name+".skeleton.xml" |
---|
1265 | exportLogger.logInfo("Skeleton \"%s\"" % file) |
---|
1266 | f = open(os.path.join(exportOptions.exportPath, file), "w") |
---|
1267 | f.write(tab(0)+"<skeleton>\n") |
---|
1268 | f.write(tab(1)+"<bones>\n") |
---|
1269 | for bone in skeleton.bones: |
---|
1270 | f.write(tab(2)+"<bone id=\"%d\" name=\"%s\">\n" % (bone.id, bone.name)) |
---|
1271 | |
---|
1272 | x, y, z = bone.loc |
---|
1273 | f.write(tab(3)+"<position x=\"%.6f\" y=\"%.6f\" z=\"%.6f\"/>\n" % (x, y, z)) |
---|
1274 | |
---|
1275 | f.write(tab(3)+"<rotation angle=\"%.6f\">\n" % (bone.rotQuat.angle/360*2*math.pi)) |
---|
1276 | f.write(tab(4)+"<axis x=\"%.6f\" y=\"%.6f\" z=\"%.6f\"/>\n" % tuple(bone.rotQuat.axis)) |
---|
1277 | f.write(tab(3)+"</rotation>\n") |
---|
1278 | f.write(tab(2)+"</bone>\n") |
---|
1279 | f.write(tab(1)+"</bones>\n") |
---|
1280 | |
---|
1281 | f.write(tab(1)+"<bonehierarchy>\n") |
---|
1282 | for bone in skeleton.bones: |
---|
1283 | parent = bone.parent |
---|
1284 | if parent: |
---|
1285 | f.write(tab(2)+"<boneparent bone=\"%s\" parent=\"%s\"/>\n" % (bone.name, parent.name)) |
---|
1286 | f.write(tab(1)+"</bonehierarchy>\n") |
---|
1287 | |
---|
1288 | f.write(tab(1)+"<animations>\n") |
---|
1289 | |
---|
1290 | for animation in skeleton.animationsDict.values(): |
---|
1291 | name = animation.name |
---|
1292 | |
---|
1293 | f.write(tab(2)+"<animation") |
---|
1294 | f.write(" name=\"%s\"" % name) |
---|
1295 | f.write(" length=\"%f\">\n" % animation.duration ) |
---|
1296 | |
---|
1297 | f.write(tab(3)+"<tracks>\n") |
---|
1298 | for track in animation.tracksDict.values(): |
---|
1299 | f.write(tab(4)+"<track bone=\"%s\">\n" % track.bone.name) |
---|
1300 | f.write(tab(5)+"<keyframes>\n") |
---|
1301 | |
---|
1302 | for keyframe in track.keyframes: |
---|
1303 | f.write(tab(6)+"<keyframe time=\"%f\">\n" % keyframe.time) |
---|
1304 | x, y, z = keyframe.loc |
---|
1305 | f.write(tab(7)+"<translate x=\"%.6f\" y=\"%.6f\" z=\"%.6f\"/>\n" % (x, y, z)) |
---|
1306 | f.write(tab(7)+"<rotate angle=\"%.6f\">\n" % (keyframe.rotQuat.angle/360*2*math.pi)) |
---|
1307 | |
---|
1308 | f.write(tab(8)+"<axis x=\"%.6f\" y=\"%.6f\" z=\"%.6f\"/>\n" % tuple(keyframe.rotQuat.axis)) |
---|
1309 | f.write(tab(7)+"</rotate>\n") |
---|
1310 | |
---|
1311 | f.write(tab(7)+"<scale x=\"%f\" y=\"%f\" z=\"%f\"/>\n" % keyframe.scale) |
---|
1312 | |
---|
1313 | f.write(tab(6)+"</keyframe>\n") |
---|
1314 | |
---|
1315 | f.write(tab(5)+"</keyframes>\n") |
---|
1316 | f.write(tab(4)+"</track>\n"); |
---|
1317 | |
---|
1318 | f.write(tab(3)+"</tracks>\n"); |
---|
1319 | f.write(tab(2)+"</animation>\n") |
---|
1320 | |
---|
1321 | f.write(tab(1)+"</animations>\n") |
---|
1322 | f.write(tab(0)+"</skeleton>\n") |
---|
1323 | f.close() |
---|
1324 | convertXMLFile(os.path.join(exportOptions.exportPath, file)) |
---|
1325 | return |
---|
1326 | |
---|
1327 | class ArmatureMeshExporter(ObjectExporter): |
---|
1328 | """Exports an armature object as mesh. |
---|
1329 | |
---|
1330 | Converts a Blender armature into an animated Ogre mesh. |
---|
1331 | """ |
---|
1332 | # TODO: Use observer pattern for progress bar. |
---|
1333 | # TODO: Get bone ids from skeletonExporter class. |
---|
1334 | def __init__(self, armatureObject): |
---|
1335 | """Constructor. |
---|
1336 | |
---|
1337 | @param armatureObject armature object to export. |
---|
1338 | """ |
---|
1339 | # call base class constructor |
---|
1340 | ObjectExporter.__init__(self, armatureObject) |
---|
1341 | self.skeleton = None |
---|
1342 | return |
---|
1343 | |
---|
1344 | def export(self, materialsDict, actionActuatorList, exportOptions, logger): |
---|
1345 | """Exports the mesh object. |
---|
1346 | |
---|
1347 | @param materialsDict dictionary that contains already existing materials. |
---|
1348 | @param actionActuatorList list of animations to export. |
---|
1349 | @param exportOptions global export options. |
---|
1350 | @param logger Logger for log messages. |
---|
1351 | @return materialsDict with the new materials added. |
---|
1352 | """ |
---|
1353 | # export skeleton |
---|
1354 | armatureExporter = ArmatureExporter(self, self.object) |
---|
1355 | armatureExporter.export(actionActuatorList, exportOptions, logger) |
---|
1356 | self.skeleton = armatureExporter.skeleton |
---|
1357 | self._convertToMesh(materialsDict, exportOptions, logger) |
---|
1358 | return materialsDict |
---|
1359 | def getName(self): |
---|
1360 | return self.object.getData().name |
---|
1361 | |
---|
1362 | def _convertToMesh(self, materialsDict, exportOptions, logger): |
---|
1363 | """Creates meshes in form of the armature bones. |
---|
1364 | """ |
---|
1365 | obj = self.object |
---|
1366 | stack = [] |
---|
1367 | # list of bone data (boneName, startPosition, endPosition) |
---|
1368 | boneMeshList = [] |
---|
1369 | matrix = None |
---|
1370 | if exportOptions.useWorldCoordinates: |
---|
1371 | # world coordinates |
---|
1372 | matrix = obj.getMatrix("worldspace") |
---|
1373 | else: |
---|
1374 | # local mesh coordinates |
---|
1375 | armatureMatrix = obj.getMatrix("worldspace") |
---|
1376 | matrix_one = Mathutils.Matrix([1.0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]) |
---|
1377 | # note that blender returns direct access to the objects matrix but we only want |
---|
1378 | # a copy so force a copy |
---|
1379 | inverseMeshMatrix = matrix_one * self.getObjectMatrix() |
---|
1380 | inverseMeshMatrix.invert() |
---|
1381 | matrix = armatureMatrix * inverseMeshMatrix |
---|
1382 | # apply additional export transformation |
---|
1383 | matrix = matrix*exportOptions.transformationMatrix() |
---|
1384 | loc = [ 0.0, 0, 0 ] |
---|
1385 | parent = None |
---|
1386 | |
---|
1387 | # get parent bones |
---|
1388 | boneDict = obj.getData().bones |
---|
1389 | for bbone in boneDict.values(): |
---|
1390 | if bbone.parent == None: |
---|
1391 | stack.append([bbone, parent, matrix, loc, 0]) |
---|
1392 | |
---|
1393 | while len(stack): |
---|
1394 | bbone, parent, accu_mat, parent_pos, parent_ds = stack.pop() |
---|
1395 | # preconditions: (R : rotation, T : translation, S : scale, M: general transformation matrix) |
---|
1396 | # accu_mat |
---|
1397 | # points to the tail of the parents bone, i.e. for root bones |
---|
1398 | # accu_mat = M_{object}*R_{additional on export} |
---|
1399 | # and for child bones |
---|
1400 | # accu_mat = T_{length of parent}*R_{parent}*T_{to head of parent}*M_{parent's parent} |
---|
1401 | # invertedOgreTransformation |
---|
1402 | # inverse of transformation done in Ogre so far, i.e. identity for root bones, |
---|
1403 | # M^{-1}_{Ogre, parent's parent}*T^{-1}_{Ogre, parent}*R^{-1}_{Ogre, parent} for child bones. |
---|
1404 | |
---|
1405 | head = bbone.head['BONESPACE'] |
---|
1406 | tail = bbone.tail['BONESPACE'] |
---|
1407 | |
---|
1408 | # get the restmat |
---|
1409 | R_bmat = bbone.matrix['BONESPACE'].rotationPart() |
---|
1410 | rotQuat = R_bmat.toQuat() |
---|
1411 | R_bmat.resize4x4() |
---|
1412 | |
---|
1413 | # get the bone's root offset (in the parent's coordinate system) |
---|
1414 | T_root = [ [ 1, 0, 0, 0 ], |
---|
1415 | [ 0, 1, 0, 0 ], |
---|
1416 | [ 0, 0, 1, 0 ], |
---|
1417 | [ head[0], head[1], head[2], 1 ] ] |
---|
1418 | |
---|
1419 | # get the bone length translation (length along y axis) |
---|
1420 | dx, dy, dz = tail[0] - head[0], tail[1] - head[1], tail[2] - head[2] |
---|
1421 | ds = math.sqrt(dx*dx + dy*dy + dz*dz) |
---|
1422 | T_len = [ [ 1, 0, 0, 0 ], |
---|
1423 | [ 0, 1, 0, 0 ], |
---|
1424 | [ 0, 0, 1, 0 ], |
---|
1425 | [ 0, ds, 0, 1 ] ] |
---|
1426 | |
---|
1427 | # calculate bone points in world coordinates |
---|
1428 | accu_mat = matrix_multiply(accu_mat, T_root) |
---|
1429 | pos = point_by_matrix([ 0, 0, 0 ], accu_mat) |
---|
1430 | |
---|
1431 | accu_mat = tmp_mat = matrix_multiply(accu_mat, R_bmat) |
---|
1432 | # tmp_mat = R_{bone}*T_{to head}*M_{parent} |
---|
1433 | accu_mat = matrix_multiply(accu_mat, T_len) |
---|
1434 | pos2 = point_by_matrix([ 0, 0, 0 ], accu_mat) |
---|
1435 | boneMeshList.append([bbone.name, pos, pos2]) |
---|
1436 | if bbone.children is not None: |
---|
1437 | for child in bbone.children: |
---|
1438 | # make sure child bone is attached to current parent |
---|
1439 | if child.parent is not None: |
---|
1440 | if child.parent.name == bbone.name: |
---|
1441 | stack.append([child, parent, accu_mat, pos, ds]) |
---|
1442 | |
---|
1443 | self._createMeshFromBoneList(materialsDict, boneMeshList) |
---|
1444 | return |
---|
1445 | |
---|
1446 | def _makeFace(self, submesh, name, p1, p2, p3): |
---|
1447 | normal = vector_normalize(vector_crossproduct( |
---|
1448 | [ p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2] ], |
---|
1449 | [ p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2] ])) |
---|
1450 | v1 = Vertex(submesh, XMLVertex(p1, normal)) |
---|
1451 | v2 = Vertex(submesh, XMLVertex(p2, normal)) |
---|
1452 | v3 = Vertex(submesh, XMLVertex(p3, normal)) |
---|
1453 | |
---|
1454 | id = self.skeleton.bonesDict[name] |
---|
1455 | v1.influences.append(Influence(id, 1.0)) |
---|
1456 | v2.influences.append(Influence(id, 1.0)) |
---|
1457 | v3.influences.append(Influence(id, 1.0)) |
---|
1458 | |
---|
1459 | Face(submesh, v1, v2, v3) |
---|
1460 | return |
---|
1461 | |
---|
1462 | def _createMeshFromBoneList(self, materialsDict, boneMeshList): |
---|
1463 | matName = "SkeletonMaterial" |
---|
1464 | material = materialsDict.get(matName) |
---|
1465 | if not material: |
---|
1466 | material = DefaultMaterial(matName) |
---|
1467 | materialsDict[matName] = material |
---|
1468 | |
---|
1469 | submesh = SubMesh(material) |
---|
1470 | for name, p1, p2 in boneMeshList: |
---|
1471 | axis = blender_bone2matrix(p1, p2, 0) |
---|
1472 | axis = matrix_translate(axis, p1) |
---|
1473 | dx, dy, dz = p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2] |
---|
1474 | ds = math.sqrt(dx*dx + dy*dy + dz*dz) |
---|
1475 | d = 0.1 + 0.2 * (ds / 10.0) |
---|
1476 | c1 = point_by_matrix([-d, 0,-d], axis) |
---|
1477 | c2 = point_by_matrix([-d, 0, d], axis) |
---|
1478 | c3 = point_by_matrix([ d, 0, d], axis) |
---|
1479 | c4 = point_by_matrix([ d, 0,-d], axis) |
---|
1480 | |
---|
1481 | self._makeFace(submesh, name, p2, c1, c2) |
---|
1482 | self._makeFace(submesh, name, p2, c2, c3) |
---|
1483 | self._makeFace(submesh, name, p2, c3, c4) |
---|
1484 | self._makeFace(submesh, name, p2, c4, c1) |
---|
1485 | self._makeFace(submesh, name, c3, c2, c1) |
---|
1486 | self._makeFace(submesh, name, c1, c4, c3) |
---|
1487 | mesh = Mesh([submesh], self.skeleton) |
---|
1488 | mesh.name = self.getName() |
---|
1489 | mesh.write() |
---|
1490 | return |
---|
1491 | |
---|
1492 | ###### |
---|
1493 | # global variables |
---|
1494 | ###### |
---|
1495 | gameEngineMaterialsToggle = Draw.Create(0) |
---|
1496 | armatureToggle = Draw.Create(1) |
---|
1497 | worldCoordinatesToggle = Draw.Create(0) |
---|
1498 | ambientToggle = Draw.Create(0) |
---|
1499 | pathString = Draw.Create(os.path.dirname(Blender.Get('filename'))) |
---|
1500 | materialString = Draw.Create(Blender.Scene.GetCurrent().getName()+".material") |
---|
1501 | scaleNumber = Draw.Create(1.0) |
---|
1502 | fpsNumber = Draw.Create(25) |
---|
1503 | # first rotation, around X-axis |
---|
1504 | rotXNumber = Draw.Create(0.0) |
---|
1505 | # second rotation, around Y-axis |
---|
1506 | rotYNumber = Draw.Create(0.0) |
---|
1507 | # third rotation, around Z-axis |
---|
1508 | rotZNumber = Draw.Create(0.0) |
---|
1509 | selectedObjectsList = Blender.Object.GetSelected() |
---|
1510 | selectedObjectsMenu = Draw.Create(0) |
---|
1511 | scrollbar = ReplacementScrollbar(0,0,0,0,0) |
---|
1512 | # key: objectName, value: armatureName |
---|
1513 | armatureDict = {} |
---|
1514 | # key: armatureName, value: armatureActionActuatorListView |
---|
1515 | # does only contain keys for the current selected objects |
---|
1516 | armatureActionActuatorListViewDict = {} |
---|
1517 | # key: armatureName, value: animationDictList |
---|
1518 | armatureAnimationDictListDict = {} |
---|
1519 | MAXACTUATORS = 100 |
---|
1520 | |
---|
1521 | # button event numbers: |
---|
1522 | BUTTON_EVENT_OK = 101 |
---|
1523 | BUTTON_EVENT_QUIT = 102 |
---|
1524 | BUTTON_EVENT_EXPORT = 103 |
---|
1525 | BUTTON_EVENT_GAMEENGINEMATERIALSTOGGLE = 104 |
---|
1526 | BUTTON_EVENT_ARMATURETOGGLE = 105 |
---|
1527 | BUTTON_EVENT_WORLDCOORDINATESTOGGLE = 106 |
---|
1528 | BUTTON_EVENT_AMBIENTTOGGLE = 107 |
---|
1529 | BUTTON_EVENT_PATHSTRING = 108 |
---|
1530 | BUTTON_EVENT_PATHBUTTON = 109 |
---|
1531 | BUTTON_EVENT_MATERIALSTRING = 1010 |
---|
1532 | BUTTON_EVENT_SCALENUMBER = 1011 |
---|
1533 | BUTTON_EVENT_ROTXNUMBER = 1012 |
---|
1534 | BUTTON_EVENT_ROTYNUMBER = 1013 |
---|
1535 | BUTTON_EVENT_ROTZNUMBER = 1014 |
---|
1536 | BUTTON_EVENT_FPSNUMBER = 1015 |
---|
1537 | BUTTON_EVENT_SCROLLBAR = 1016 |
---|
1538 | BUTTON_EVENT_SCROLLBARUP = 1017 |
---|
1539 | BUTTON_EVENT_SRCROLLBARDOWN = 1018 |
---|
1540 | BUTTON_EVENT_UPDATEBUTTON = 1019 |
---|
1541 | BUTTON_EVENT_SELECTEDOBJECTSMENU = 1020 |
---|
1542 | BUTTON_EVENT_ACTUATOR_RANGESTART = 1021 |
---|
1543 | |
---|
1544 | exportLogger = Logger() |
---|
1545 | |
---|
1546 | OGRE_LOGO = Buffer(GL_BYTE, [48,122*4],[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,64,0,0,0,95,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1547 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,0,0,0,127,0,0,0,127,0,1,0,127,0,2,0,127,2,5,2,127,2,5,2,127,4,6,4,127,5,8,5,127,8,11,8,127,8,11,8,127,3,5,3,127,2,3,2,127,0,1,0,127,0,1,0,127,0,1,0,127,0,1,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,64,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1548 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,0,0,0,127,1,2,1,127,4,6,4,127,10,13,10,127,18,22,18,127,23,28,23,127,24,30,24,127,25,31,25,127,25,31,25,127,26,32,26,127,26,32,26,127,26,32,26,127,25,31,25,127,24,30,24,127,18,23,18,127,3,5,3,127,4,6,4,127,8,11,8,127,9,12,9,127,13,17,13,127,17,22,17,127,15,19,15,127,7,9,7,127,1,2,1,127,0,0,0,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1549 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,2,4,2,127,4,6,4,127,18,22,18,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,18,22,18,127,15,19,15,127,20,26,20,127,25,31,25,127,26,32,26,127,26,32,26,127,25,31,25,127,25,31,25,127,25,31,25,127,26,32,26,127,24,30,24,127,16,20,16,127,4,5,4,127,0,0,0,95,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1550 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,1,1,1,127,13,15,13,127,12,15,12,127,24,29,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,29,23,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,28,23,127,3,5,3,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1551 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,1,1,1,127,19,24,19,127,11,15,11,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,28,23,127,17,21,17,127,22,28,22,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,28,23,127,3,5,3,127,0,0,0,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1552 | [0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,20,24,20,127,16,20,16,127,20,25,20,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,22,28,22,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,28,23,127,3,5,3,127,0,0,0,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1553 | [0,0,0,0,0,0,0,0,0,0,0,64,5,7,5,127,26,32,26,127,15,19,15,127,41,48,41,127,38,45,38,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,28,23,127,3,4,3,127,0,0,0,127,58,66,58,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1554 | [0,0,0,0,0,0,0,0,0,0,0,127,20,24,20,127,27,34,27,127,26,32,26,127,47,55,47,127,47,55,47,127,39,46,39,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,11,16,11,127,0,1,0,127,3,3,3,127,94,106,94,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1555 | [0,0,0,0,0,0,0,0,0,0,0,127,33,39,33,127,45,52,45,127,28,32,28,127,47,55,47,127,44,51,44,127,39,46,39,127,27,33,27,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,21,26,21,127,0,2,0,127,0,0,0,127,23,26,23,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1556 | [0,0,0,0,0,0,0,0,0,0,0,127,24,28,24,127,33,40,33,127,18,22,18,127,29,35,29,127,25,31,25,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,5,8,5,127,1,2,1,127,0,0,0,127,70,79,70,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,94,105,94,127,70,79,70,127,76,86,76,127,90,101,90,127,103,116,103,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1557 | [0,0,0,0,0,0,0,64,0,0,0,127,4,6,4,127,12,16,12,127,22,27,22,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,29,23,127,28,34,28,127,35,42,35,127,28,35,28,127,25,31,25,127,23,29,23,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,17,21,17,127,0,2,0,127,0,0,0,127,31,36,31,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,100,112,100,127,92,103,92,127,103,116,103,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,100,112,100,127,81,92,81,127,68,77,68,127,65,73,65,127,65,73,65,127,76,86,76,127,78,88,78,127,83,94,83,127,92,103,92,127,85,95,85,127,31,35,31,127,6,7,6,127,6,7,6,127,13,14,13,127,13,14,13,127,19,21,19,127,26,29,26,127,26,29,26,127,48,54,48,127,96,108,96,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,70,78,70,127,3,3,3,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,12,13,11,127,23,26,23,127,36,40,36,127,49,55,49,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1558 | [0,0,0,64,0,0,0,127,2,4,2,127,16,20,16,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,24,30,24,127,26,33,26,127,59,68,59,127,81,91,81,127,87,98,87,127,86,96,86,127,80,90,80,127,71,79,71,127,59,66,59,127,36,41,35,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,24,31,24,127,26,32,26,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,5,8,5,127,0,1,0,127,18,20,18,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,91,103,91,127,58,65,58,127,29,33,29,127,6,7,6,127,0,0,0,127,0,0,0,127,1,2,1,127,22,24,22,127,54,61,54,127,94,106,94,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,88,99,88,127,51,58,51,127,18,21,18,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,17,19,17,127,48,54,48,127,80,91,80,127,102,115,102,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,29,33,29,127,0,0,0,127,41,31,14,127,33,25,11,127,18,14,6,127,2,2,1,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1559 | [0,0,0,127,2,3,2,127,24,29,24,127,26,32,26,127,24,30,24,127,25,31,25,127,24,30,24,127,24,30,24,127,24,30,24,127,23,29,23,127,34,41,34,127,78,88,78,127,87,98,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,87,97,87,127,87,97,87,127,84,93,84,127,62,69,62,127,34,40,34,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,28,23,127,26,30,26,127,36,38,36,127,47,50,46,127,39,42,37,127,34,40,34,127,30,37,30,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,15,19,15,127,0,1,0,127,0,0,0,127,102,115,102,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,94,106,94,127,43,48,43,127,4,5,4,127,0,0,0,127,0,0,0,127,0,0,0,127,6,5,2,127,16,12,5,127,2,2,1,127,0,0,0,127,0,0,0,127,7,8,7,127,58,65,58,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,96,108,96,127,41,47,41,127,1,1,1,127,0,0,0,127,0,0,0,127,6,5,2,127,27,21,9,127,42,33,14,127,46,36,16,127,46,36,16,127,33,25,11,127,31,24,11,127,25,19,9,127,16,12,5,127,12,9,4,127,0,0,0,127,107,82,36,127,115,88,38,127,107,82,36,127,107,82,36,127,100,76,33,127,92,71,31,127,88,68,30,127,0,0,0,127,4,3,2,127,0,0,0,127,0,0,0,127,0,0,0,127,13,15,13,127,65,73,65,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,13,14,13,127,0,0,0,127,107,82,36,127,122,94,41,127,122,94,41,127,122,94,41,127,109,84,36,127,96,73,32,127,80,62,27,127,65,50,22,127,52,40,17,127,37,28,12,127,21,16,7,127,2,2,1,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1560 | [0,0,0,127,9,11,9,127,48,56,48,127,45,53,45,127,41,48,41,127,33,40,33,127,34,41,34,127,37,44,37,127,54,62,54,127,77,87,77,127,87,97,87,127,87,97,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,79,88,79,127,61,69,61,127,25,31,25,127,25,31,25,127,23,28,23,127,19,23,19,127,42,43,41,127,60,60,59,127,61,61,59,127,61,61,59,127,63,63,61,127,35,37,34,127,38,45,38,127,33,39,33,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,15,19,15,127,0,1,0,127,0,0,0,127,102,115,102,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,81,91,81,127,9,11,9,127,0,0,0,127,2,2,1,127,44,34,15,127,86,66,29,127,115,88,38,127,122,94,41,127,122,94,41,127,121,92,40,127,94,72,31,127,39,30,13,127,0,0,0,127,0,0,0,127,40,45,40,127,101,114,101,127,105,118,105,127,105,118,105,127,105,118,105,127,85,95,85,127,11,13,11,127,0,0,0,127,4,3,2,127,50,38,17,127,94,72,31,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,92,71,31,127,0,0,0,127,107,82,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,100,76,33,127,2,2,1,127,105,81,35,127,98,75,33,127,60,46,20,127,23,18,8,127,0,0,0,127,1,1,1,127,90,102,90,127,105,118,105,127,105,118,105,127,105,118,105,127,6,7,6,127,0,0,0,127,115,88,38,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,8,6,3,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1561 | [0,0,0,127,3,5,3,127,45,53,45,127,46,54,46,127,46,54,46,127,47,55,47,127,46,54,46,127,68,78,68,127,87,98,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,87,98,87,127,67,76,67,127,38,46,38,127,21,26,21,127,50,52,50,127,60,60,59,127,61,61,59,127,60,60,58,127,60,60,58,127,60,60,58,127,61,61,59,127,39,41,38,127,52,59,52,127,67,76,67,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,15,19,15,127,0,1,0,127,0,0,0,127,102,115,102,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,59,67,59,127,1,1,1,127,0,0,0,127,35,27,12,127,105,81,35,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,86,66,29,127,8,6,3,127,0,0,0,127,36,40,36,127,105,118,105,127,105,118,105,127,82,92,82,127,7,7,7,127,0,0,0,127,31,24,10,127,107,82,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,80,62,27,127,0,0,0,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,82,63,28,127,46,36,16,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,27,21,9,127,0,0,0,127,78,88,78,127,105,118,105,127,105,118,105,127,105,118,105,127,0,0,0,127,0,0,0,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,100,76,33,127,0,0,0,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1562 | [0,0,0,127,0,2,0,127,41,49,41,127,46,54,46,127,46,54,46,127,49,56,49,127,77,87,77,127,87,98,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,85,96,85,127,55,64,55,127,44,52,44,127,23,28,23,127,17,22,17,127,90,92,90,127,84,84,82,127,60,60,58,127,60,60,58,127,60,60,58,127,60,60,58,127,61,61,59,127,39,41,38,127,54,62,54,127,62,71,62,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,15,20,15,127,0,1,0,127,0,0,0,127,102,115,102,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,81,90,81,127,1,1,1,127,0,0,0,127,61,47,21,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,103,79,34,127,12,9,4,127,0,0,0,127,47,52,47,127,93,104,93,127,8,9,8,127,0,0,0,127,52,40,17,127,121,92,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,77,59,26,127,0,0,0,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,63,49,21,127,105,81,35,127,122,94,41,127,122,94,41,127,122,94,41,127,100,76,33,127,0,0,0,127,9,11,9,127,101,113,101,127,105,118,105,127,105,118,105,127,105,118,105,127,0,0,0,127,0,0,0,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,69,53,23,127,0,0,0,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1563 | [0,0,0,127,0,1,0,127,37,44,37,127,46,54,46,127,49,57,49,127,79,89,79,127,87,97,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,56,64,56,127,46,53,46,127,25,31,25,127,22,27,22,127,25,31,25,127,44,47,44,127,116,116,115,127,59,59,57,127,60,60,58,127,60,60,58,127,60,60,58,127,61,61,59,127,38,41,37,127,69,78,69,127,45,53,45,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,15,20,15,127,0,0,0,127,5,6,5,127,104,117,104,127,105,118,105,127,105,118,105,127,105,118,105,127,93,104,93,127,8,9,8,127,0,0,0,127,61,47,21,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,96,73,32,127,2,2,1,127,0,0,0,127,24,28,24,127,0,0,0,127,37,28,12,127,121,92,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,77,59,26,127,10,8,3,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,88,68,30,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,39,30,13,127,0,0,0,127,43,49,43,127,105,118,105,127,105,118,105,127,105,118,105,127,93,105,93,127,0,0,0,127,14,11,5,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,39,30,13,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1564 | [0,0,0,64,0,1,0,127,21,25,21,127,48,57,49,127,82,92,82,127,87,97,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,87,97,87,127,87,98,87,127,60,69,60,127,43,50,43,127,29,36,29,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,116,116,116,127,71,71,70,127,60,60,58,127,60,60,58,127,60,60,58,127,62,62,60,127,30,32,29,127,75,85,75,127,29,36,29,127,25,31,25,127,24,30,24,127,24,30,24,127,23,28,23,127,10,14,10,127,0,0,0,127,40,45,40,127,105,118,105,127,105,118,105,127,105,118,105,127,105,118,105,127,33,38,33,127,0,0,0,127,39,30,13,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,67,52,23,127,0,0,0,127,0,0,0,127,10,8,3,127,113,87,38,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,107,82,36,127,84,65,28,127,71,54,24,127,115,88,38,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,67,51,22,127,16,12,5,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,122,94,41,127,122,94,41,127,122,94,41,127,105,81,35,127,2,2,1,127,0,0,0,127,0,0,0,127,18,21,18,127,61,69,61,127,102,115,102,127,92,103,92,127,0,0,0,127,16,12,5,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,60,46,20,127,52,40,17,127,69,53,23,127,86,66,29,127,10,8,3,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1565 | [0,0,0,0,0,0,0,127,2,5,2,127,49,57,49,127,87,98,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,87,98,87,127,86,97,86,127,75,84,75,127,53,61,53,127,34,41,34,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,22,28,22,127,96,97,96,127,93,93,92,127,59,59,58,127,60,60,58,127,60,60,58,127,61,61,59,127,34,39,34,127,74,84,74,127,23,29,23,127,25,31,25,127,37,39,34,127,47,47,41,127,44,45,39,127,17,18,16,127,0,0,0,127,52,59,52,127,105,118,105,127,105,118,105,127,105,118,105,127,81,92,81,127,0,0,0,127,8,6,3,127,111,85,37,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,50,38,17,127,16,12,5,127,33,25,11,127,103,79,34,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,23,18,8,127,0,0,0,127,69,53,23,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,77,59,26,127,27,21,9,127,0,0,0,127,0,0,0,127,0,0,0,127,92,71,31,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,61,47,21,127,18,14,6,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,117,90,39,127,88,68,29,127,54,41,18,127,14,11,5,127,0,0,0,127,0,0,0,127,17,18,17,127,68,76,68,127,0,0,0,127,21,16,7,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,31,24,11,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1566 | [0,0,0,0,0,0,0,95,0,0,0,127,37,43,37,127,89,100,89,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,87,97,87,127,88,99,88,127,82,92,82,127,61,69,61,127,36,42,36,127,27,32,27,127,23,29,23,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,29,23,127,78,80,76,127,102,102,102,127,58,58,57,127,60,60,58,127,60,60,58,127,58,58,56,127,40,47,40,127,56,64,56,127,24,29,23,127,44,45,40,127,49,49,43,127,49,49,43,127,46,46,41,127,41,42,37,127,0,0,0,127,38,43,38,127,105,118,105,127,105,118,105,127,105,118,105,127,33,37,33,127,0,0,0,127,61,47,21,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,77,59,26,127,0,0,0,127,0,0,0,127,0,0,0,127,12,9,4,127,113,87,38,127,122,94,41,127,122,94,41,127,122,94,41,127,84,65,28,127,4,3,2,127,115,88,38,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,42,33,14,127,0,0,0,127,119,91,40,127,102,78,34,127,75,57,25,127,52,40,17,127,88,68,29,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,61,47,21,127,31,24,11,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,84,65,28,127,19,15,7,127,0,0,0,127,4,5,4,127,0,0,0,127,31,24,11,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,111,85,37,127,115,88,38,127,122,94,41,127,122,94,41,127,48,37,16,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1567 | [0,0,0,0,0,0,0,32,0,0,0,127,6,7,5,127,67,75,67,127,89,100,89,127,87,97,87,127,87,97,87,127,87,98,87,127,88,99,88,127,88,98,88,127,80,90,80,127,62,71,62,127,45,52,45,127,39,46,39,127,57,65,57,127,65,74,65,127,59,67,59,127,54,61,54,127,55,61,55,127,28,34,28,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,24,30,24,127,64,67,64,127,109,109,108,127,58,58,57,127,60,60,58,127,61,60,59,127,50,50,47,127,47,55,47,127,33,39,33,127,44,44,39,127,48,48,42,127,48,48,42,127,28,30,25,127,36,37,31,127,48,48,42,127,1,2,1,127,36,41,36,127,105,118,105,127,105,118,105,127,99,111,99,127,4,5,4,127,2,2,1,127,113,87,38,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,65,50,22,127,0,0,0,127,30,34,30,127,27,30,27,127,0,0,0,127,67,51,22,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,58,44,19,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,71,54,24,127,0,0,0,127,18,14,6,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,54,41,18,127,31,24,11,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,56,43,19,127,0,0,0,127,0,0,0,127,31,24,11,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,37,28,12,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1568 | [0,0,0,0,0,0,0,0,0,0,0,95,0,0,0,127,2,3,2,127,28,32,28,127,58,65,58,127,56,64,56,127,50,57,50,127,46,54,46,127,42,49,42,127,43,50,43,127,62,71,62,127,80,90,80,127,87,98,87,127,87,98,87,127,87,97,87,127,87,98,87,127,86,97,87,127,78,85,78,127,46,52,46,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,24,30,24,127,64,67,64,127,104,104,104,127,58,58,57,127,60,60,58,127,62,61,60,127,34,38,33,127,37,43,37,127,50,51,44,127,48,48,42,127,48,48,42,127,23,27,22,127,32,36,30,127,95,95,82,127,43,45,39,127,0,0,0,127,45,51,45,127,105,118,105,127,105,118,105,127,71,80,71,127,0,0,0,127,35,27,12,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,103,79,35,127,2,2,1,127,0,0,0,127,11,13,11,127,0,0,0,127,65,50,22,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,23,18,8,127,0,0,0,127,35,27,12,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,46,36,16,127,41,31,14,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,119,91,40,127,37,28,12,127,50,38,17,127,73,56,24,127,107,82,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,69,53,23,127,0,0,0,127,44,34,15,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,27,21,9,127,0,0,0,127,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,0,0,0,0,0], |
---|
1569 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,8,10,8,127,51,59,51,127,84,95,84,127,87,98,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,87,127,63,71,63,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,23,29,23,127,76,78,75,127,100,100,99,127,58,58,57,127,61,60,59,127,53,54,51,127,24,30,24,127,29,33,28,127,77,76,63,127,47,48,42,127,29,32,27,127,24,30,24,127,30,35,29,127,90,91,84,127,28,29,25,127,0,0,0,127,77,86,76,127,105,118,105,127,105,118,105,127,44,50,44,127,0,0,0,127,69,53,23,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,81,62,27,127,4,3,2,127,0,0,0,127,12,9,4,127,107,82,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,4,3,2,127,0,0,0,127,54,41,18,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,46,36,16,127,46,36,16,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,100,76,33,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,48,37,16,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,42,33,14,127,46,36,16,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,16,12,5,127,0,0,0,127,0,0,0,127,4,3,2,127,6,5,2,127,0,0,0,95,0,0,0,0], |
---|
1570 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,64,0,0,0,95,1,1,1,127,60,68,60,127,87,98,87,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,87,97,87,127,73,82,73,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,22,28,22,127,89,92,89,127,87,87,86,127,59,59,58,127,60,59,58,127,31,35,31,127,25,31,25,127,43,45,38,127,74,74,62,127,43,43,38,127,22,28,22,127,25,31,25,127,24,30,24,127,26,32,26,127,13,14,12,127,0,0,0,127,100,113,100,127,105,118,105,127,105,118,105,127,21,24,21,127,0,0,0,127,98,75,33,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,113,87,38,127,92,71,31,127,117,90,39,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,19,15,7,127,0,0,0,127,71,54,24,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,39,30,13,127,50,38,17,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,82,63,28,127,0,0,0,127,23,26,23,127,38,42,38,127,5,7,5,127,0,0,0,127,96,73,32,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,111,85,37,127,54,41,18,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,82,63,28,127,16,12,5,127,16,12,5,127,16,12,5,127,12,9,4,127,46,35,16,127,82,63,28,127,117,90,39,127,46,36,16,127,0,0,0,127,0,0,0,0], |
---|
1571 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,33,38,33,127,89,99,89,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,84,94,84,127,28,35,28,127,25,31,25,127,25,31,25,127,25,31,25,127,22,28,22,127,100,101,100,127,73,73,71,127,61,60,59,127,35,38,35,127,24,30,24,127,24,30,24,127,48,51,41,127,69,69,57,127,36,37,32,127,24,30,24,127,28,34,28,127,25,31,25,127,25,31,25,127,17,21,17,127,0,0,0,127,80,90,80,127,105,118,105,127,105,118,105,127,6,7,6,127,0,0,0,127,115,88,38,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,56,43,19,127,0,0,0,127,88,68,29,127,117,90,39,127,107,82,36,127,92,71,31,127,80,62,27,127,69,53,23,127,60,46,20,127,46,36,16,127,33,25,11,127,23,18,8,127,4,3,2,127,61,47,21,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,65,50,22,127,0,0,0,127,20,22,20,127,26,30,26,127,0,0,0,127,2,2,1,127,109,84,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,100,76,33,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,77,59,26,127,21,16,7,127,60,46,20,127,94,72,31,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,54,41,18,127,0,0,0,127,0,0,0,0], |
---|
1572 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,6,7,6,127,81,91,81,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,88,98,88,127,60,68,60,127,27,33,27,127,24,30,24,127,25,31,25,127,22,28,22,127,91,91,91,127,57,58,56,127,31,36,31,127,24,30,24,127,25,31,25,127,25,31,25,127,27,31,26,127,70,71,58,127,41,42,36,127,37,43,37,127,66,74,66,127,23,29,23,127,25,31,25,127,19,22,19,127,0,0,0,127,75,84,75,127,105,118,105,127,102,114,102,127,0,0,0,127,4,3,2,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,117,90,39,127,31,24,10,127,2,2,1,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,4,3,2,127,61,47,21,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,46,36,16,127,0,0,0,127,0,0,0,127,0,0,0,127,8,6,3,127,73,56,24,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,61,47,21,127,0,0,0,127,0,0,0,0], |
---|
1573 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,45,52,45,127,87,98,88,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,82,92,82,127,46,54,46,127,34,41,34,127,25,31,25,127,25,31,25,127,26,30,26,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,24,30,24,127,33,37,31,127,48,48,42,127,43,43,38,127,66,74,65,127,23,29,23,127,25,31,25,127,20,25,20,127,0,0,0,127,70,78,70,127,105,118,105,127,92,103,92,127,0,0,0,127,16,12,5,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,86,66,29,127,48,37,16,127,31,24,11,127,16,12,5,127,23,18,8,127,33,25,11,127,52,40,17,127,71,54,24,127,96,73,32,127,117,90,39,127,63,49,21,127,73,56,24,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,88,68,29,127,77,59,26,127,77,59,26,127,90,69,30,127,117,90,39,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,73,56,24,127,0,0,0,127,0,0,0,32], |
---|
1574 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,25,28,25,127,88,99,88,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,86,97,86,127,87,98,87,127,70,79,70,127,46,54,46,127,47,55,47,127,45,52,45,127,30,37,30,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,24,30,24,127,44,52,44,127,72,81,72,127,70,79,70,127,23,29,23,127,25,31,25,127,21,25,21,127,0,0,0,127,66,73,65,127,105,118,105,127,92,103,92,127,0,0,0,127,16,12,5,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,80,62,27,127,77,59,26,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,77,59,26,127,0,0,0,127,0,0,0,64], |
---|
1575 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,1,0,127,64,72,64,127,87,97,87,127,86,97,86,127,86,97,86,127,87,97,87,127,86,97,86,127,86,96,86,127,85,95,85,127,71,80,71,127,47,55,47,127,46,54,46,127,46,54,46,127,46,54,46,127,47,55,47,127,31,38,31,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,23,29,23,127,59,67,59,127,77,87,77,127,58,66,58,127,25,31,25,127,25,31,25,127,22,27,22,127,0,0,0,127,48,54,48,127,105,118,105,127,92,103,92,127,0,0,0,127,16,12,5,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,98,75,33,127,80,62,27,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,92,71,31,127,0,0,0,127,0,0,0,64], |
---|
1576 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,127,14,16,14,127,88,99,88,127,88,98,88,127,88,98,88,127,72,82,72,127,51,59,51,127,52,61,52,127,55,63,55,127,47,55,47,127,45,53,45,127,45,53,45,127,46,54,46,127,46,54,46,127,46,54,46,127,45,53,45,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,37,44,37,127,76,86,76,127,73,82,73,127,32,39,32,127,23,29,23,127,2,2,2,127,30,34,30,95,105,118,105,64,98,111,98,64,0,0,0,95,4,3,2,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,115,88,38,127,92,71,31,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,119,91,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,98,75,33,127,0,0,0,127,0,0,0,64], |
---|
1577 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,21,24,21,127,55,62,55,127,51,57,50,127,64,72,64,127,86,96,86,127,85,95,85,127,84,94,84,127,86,96,86,127,84,95,84,127,82,92,82,127,75,85,75,127,52,60,52,127,46,54,46,127,46,54,46,127,45,53,45,127,26,32,26,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,29,36,29,127,28,34,28,127,24,30,24,127,62,71,62,127,88,99,88,127,66,75,66,127,24,30,24,127,8,11,8,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,105,81,35,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,98,75,33,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,100,76,33,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,107,82,36,127,0,0,0,127,0,0,0,64], |
---|
1578 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,31,36,31,127,35,40,35,127,33,36,32,127,31,34,31,127,47,55,47,127,51,59,51,127,47,55,47,127,39,46,39,127,29,36,29,127,37,43,37,127,52,60,52,127,77,87,77,127,49,58,49,127,46,54,46,127,40,48,40,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,29,35,29,127,80,90,80,127,59,67,59,127,24,30,24,127,24,30,24,127,76,86,76,127,87,98,87,127,39,46,39,127,17,22,17,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,75,57,25,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,79,60,26,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,113,87,38,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,71,55,24,127,103,79,35,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,117,90,39,127,0,0,0,127,0,0,0,64], |
---|
1579 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,41,48,41,127,69,79,69,127,39,45,39,127,47,54,47,127,77,87,77,127,86,97,86,127,88,97,87,127,87,97,86,127,82,93,83,127,57,65,57,127,25,31,25,127,24,30,24,127,26,32,26,127,26,32,26,127,26,32,26,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,75,85,75,127,87,98,87,127,67,75,67,127,23,29,23,127,23,29,23,127,56,64,56,127,85,95,85,127,75,84,75,127,24,30,24,127,3,3,3,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,127,29,22,10,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,119,91,40,127,8,6,3,127,109,84,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,119,91,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,98,75,33,127,6,5,2,127,107,82,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,0,0,0,127,0,0,0,64], |
---|
1580 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,12,15,12,127,45,53,46,127,48,56,48,127,65,72,63,127,98,81,79,127,123,119,119,127,117,108,108,127,94,79,76,127,88,88,80,127,64,73,64,127,24,30,24,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,35,41,35,127,86,96,86,127,87,98,87,127,61,69,61,127,23,29,23,127,24,30,24,127,46,53,46,127,84,94,84,127,87,98,87,127,55,63,55,127,10,12,10,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,92,71,31,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,75,57,25,127,0,0,0,127,52,40,17,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,98,75,33,127,12,9,4,127,0,0,0,127,109,84,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,14,11,5,127,0,0,0,95], |
---|
1581 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,22,26,22,127,30,37,30,127,23,29,23,127,41,40,35,127,91,73,72,127,113,103,103,127,100,75,75,127,87,58,58,127,83,72,66,127,54,63,55,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,30,25,127,34,41,34,127,69,78,69,127,81,91,81,127,34,41,34,127,25,31,25,127,23,29,23,127,61,69,61,127,82,92,82,127,75,85,75,127,82,92,82,127,24,29,24,127,1,1,1,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,127,23,18,8,127,119,91,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,17,14,6,127,0,0,0,127,2,2,1,127,96,73,32,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,75,58,25,127,6,5,2,127,0,0,0,127,0,0,0,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,18,14,6,127,0,0,0,127], |
---|
1582 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,24,29,24,127,48,56,48,127,28,34,28,127,24,30,24,127,25,31,25,127,36,37,32,127,68,55,52,127,82,63,62,127,80,52,52,127,81,82,74,127,28,34,28,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,24,30,24,127,23,29,23,127,25,31,25,127,24,30,24,127,25,31,25,127,24,29,24,127,56,64,56,127,87,97,87,127,70,79,70,127,88,99,88,127,49,57,49,127,10,12,10,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,44,34,15,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,67,52,23,127,0,0,0,127,0,0,0,95,0,0,0,127,12,9,4,127,109,84,36,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,100,76,33,127,33,25,11,127,0,0,0,127,0,0,0,127,0,0,0,95,0,0,0,127,107,82,36,127,117,90,39,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,31,24,11,127,0,0,0,127], |
---|
1583 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,14,16,14,127,81,91,81,127,72,81,72,127,43,51,43,127,23,29,23,127,24,30,24,127,23,30,24,127,23,30,23,127,25,31,25,127,26,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,26,32,26,127,32,39,32,127,30,37,30,127,24,30,24,127,25,31,25,127,25,31,25,127,25,32,25,127,83,93,83,127,77,86,77,127,87,97,87,127,80,90,80,127,22,27,22,127,1,1,1,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,46,35,15,127,121,92,40,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,96,73,32,127,4,3,2,127,0,0,0,95,0,0,0,0,0,0,0,32,0,0,0,127,12,9,4,127,98,75,33,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,96,73,32,127,40,31,14,127,2,2,1,127,0,0,0,127,0,0,0,64,0,0,0,0,0,0,0,32,0,0,0,127,0,0,0,127,0,0,0,127,2,2,1,127,16,12,5,127,25,19,9,127,33,25,11,127,46,36,16,127,56,43,19,127,61,47,21,127,77,59,26,127,84,65,28,127,92,71,31,127,107,82,36,127,115,88,38,127,122,94,41,127,122,94,41,127,39,30,13,127,0,0,0,127], |
---|
1584 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,18,21,18,127,83,93,83,127,89,100,89,127,71,81,71,127,54,61,54,127,37,44,37,127,24,30,24,127,23,29,23,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,24,30,24,127,42,50,42,127,70,79,70,127,87,98,87,127,74,83,74,127,28,35,28,127,25,31,25,127,24,30,24,127,42,49,42,127,76,86,76,127,86,97,86,127,88,99,88,127,41,49,41,127,11,14,11,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,27,21,9,127,105,81,35,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,98,75,33,127,12,9,4,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,2,2,1,127,58,44,19,127,113,87,38,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,105,81,35,127,63,49,21,127,21,16,7,127,0,0,0,127,0,0,0,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,16,12,5,127,6,5,2,127,0,0,0,95], |
---|
1585 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,13,17,13,127,61,70,61,127,85,96,85,127,89,100,89,127,88,98,88,127,77,87,77,127,60,67,60,127,26,32,26,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,25,31,25,127,12,16,12,127,12,15,12,127,40,46,40,127,80,90,80,127,80,89,80,127,34,40,34,127,24,30,24,127,23,29,23,127,51,59,51,127,88,99,88,127,86,97,86,127,76,85,76,127,22,27,22,127,1,2,1,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,4,3,2,127,59,46,20,127,111,85,37,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,119,91,40,127,65,50,22,127,4,3,2,127,0,0,0,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,0,0,0,127,4,3,2,127,44,34,15,127,80,62,27,127,111,85,37,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,122,94,41,127,121,92,40,127,100,76,33,127,75,57,25,127,48,37,16,127,18,13,6,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,127,0,0,0,64,0,0,0,0], |
---|
1586 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,127,19,23,19,127,46,53,46,127,64,72,64,127,80,90,80,127,85,96,85,127,74,84,74,127,28,34,28,127,25,31,25,127,25,31,25,127,25,30,25,127,25,31,25,127,25,31,25,127,25,31,25,127,17,21,17,127,1,3,1,127,0,1,0,127,0,0,0,127,9,11,9,127,51,59,52,127,82,93,83,127,45,52,45,127,23,29,23,127,24,30,24,127,59,67,59,127,88,99,88,127,85,96,85,127,30,37,30,127,12,15,12,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,0,0,0,127,4,3,2,127,42,33,14,127,82,63,28,127,107,82,36,127,103,79,35,127,84,65,28,127,54,41,18,127,12,9,4,127,0,0,0,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,0,0,0,127,0,0,0,127,0,0,0,127,10,8,3,127,25,19,9,127,31,24,11,127,31,24,11,127,31,24,11,127,31,24,11,127,18,14,6,127,35,27,12,127,105,81,35,127,80,62,27,127,54,41,18,127,29,22,10,127,6,5,2,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,95,0,0,0,64,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1587 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,8,10,8,127,33,39,33,127,44,51,44,127,46,53,46,127,44,52,44,127,39,46,39,127,25,30,25,127,25,31,25,127,25,31,25,127,24,30,24,127,15,19,15,127,5,7,5,127,0,1,0,127,0,0,0,127,0,0,0,95,0,0,0,64,0,0,0,64,0,1,0,127,21,24,21,127,66,74,66,127,57,66,57,127,24,30,24,127,23,29,23,127,52,60,52,127,40,47,40,127,24,30,24,127,23,28,23,127,1,2,1,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,95,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,64,0,0,0,95,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,64,0,0,0,64,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1588 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,0,0,0,127,11,13,11,127,23,28,23,127,33,39,33,127,36,43,36,127,23,29,23,127,20,26,20,127,11,15,11,127,3,4,3,127,0,1,0,127,0,0,0,127,0,0,0,95,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,3,5,3,127,37,41,37,127,58,66,58,127,27,33,27,127,24,30,24,127,26,32,26,127,25,31,25,127,25,31,25,127,8,9,8,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,64,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1589 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,0,0,0,127,0,0,0,127,0,0,0,127,0,1,0,127,0,0,0,127,0,0,0,127,0,0,0,127,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,127,12,15,12,127,42,49,42,127,32,39,32,127,24,30,24,127,25,31,25,127,25,31,25,127,18,22,18,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1590 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,2,2,2,127,23,27,23,127,37,43,37,127,26,33,26,127,25,31,25,127,24,30,24,127,4,4,4,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1591 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,4,5,4,127,24,28,23,127,29,35,29,127,25,31,25,127,12,16,12,127,0,0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1592 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,95,4,4,4,127,11,14,11,127,16,20,16,127,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
---|
1593 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,64,0,0,0,127,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]) |
---|
1594 | |
---|
1595 | ####################################################################################### |
---|
1596 | ## math functions |
---|
1597 | |
---|
1598 | def matrix_translate(m, v): |
---|
1599 | m[3][0] += v[0] |
---|
1600 | m[3][1] += v[1] |
---|
1601 | m[3][2] += v[2] |
---|
1602 | return m |
---|
1603 | |
---|
1604 | def matrix_multiply(b, a): |
---|
1605 | """ matrix_multiply(b, a) = a*b |
---|
1606 | """ |
---|
1607 | return [ [ |
---|
1608 | a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0], |
---|
1609 | a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1], |
---|
1610 | a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2], |
---|
1611 | 0.0, |
---|
1612 | ], [ |
---|
1613 | a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0], |
---|
1614 | a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1], |
---|
1615 | a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2], |
---|
1616 | 0.0, |
---|
1617 | ], [ |
---|
1618 | a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0], |
---|
1619 | a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1], |
---|
1620 | a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2], |
---|
1621 | 0.0, |
---|
1622 | ], [ |
---|
1623 | a[3][0] * b[0][0] + a[3][1] * b[1][0] + a[3][2] * b[2][0] + b[3][0], |
---|
1624 | a[3][0] * b[0][1] + a[3][1] * b[1][1] + a[3][2] * b[2][1] + b[3][1], |
---|
1625 | a[3][0] * b[0][2] + a[3][1] * b[1][2] + a[3][2] * b[2][2] + b[3][2], |
---|
1626 | 1.0, |
---|
1627 | ] ] |
---|
1628 | |
---|
1629 | def matrix_invert(m): |
---|
1630 | det = (m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) |
---|
1631 | - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) |
---|
1632 | + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])) |
---|
1633 | if det == 0.0: return None |
---|
1634 | det = 1.0 / det |
---|
1635 | r = [ [ |
---|
1636 | det * (m[1][1] * m[2][2] - m[2][1] * m[1][2]), |
---|
1637 | - det * (m[0][1] * m[2][2] - m[2][1] * m[0][2]), |
---|
1638 | det * (m[0][1] * m[1][2] - m[1][1] * m[0][2]), |
---|
1639 | 0.0, |
---|
1640 | ], [ |
---|
1641 | - det * (m[1][0] * m[2][2] - m[2][0] * m[1][2]), |
---|
1642 | det * (m[0][0] * m[2][2] - m[2][0] * m[0][2]), |
---|
1643 | - det * (m[0][0] * m[1][2] - m[1][0] * m[0][2]), |
---|
1644 | 0.0 |
---|
1645 | ], [ |
---|
1646 | det * (m[1][0] * m[2][1] - m[2][0] * m[1][1]), |
---|
1647 | - det * (m[0][0] * m[2][1] - m[2][0] * m[0][1]), |
---|
1648 | det * (m[0][0] * m[1][1] - m[1][0] * m[0][1]), |
---|
1649 | 0.0, |
---|
1650 | ] ] |
---|
1651 | r.append([ |
---|
1652 | -(m[3][0] * r[0][0] + m[3][1] * r[1][0] + m[3][2] * r[2][0]), |
---|
1653 | -(m[3][0] * r[0][1] + m[3][1] * r[1][1] + m[3][2] * r[2][1]), |
---|
1654 | -(m[3][0] * r[0][2] + m[3][1] * r[1][2] + m[3][2] * r[2][2]), |
---|
1655 | 1.0, |
---|
1656 | ]) |
---|
1657 | return r |
---|
1658 | |
---|
1659 | def matrix_transpose(m): |
---|
1660 | return [ [ m[0][0], m[1][0], m[2][0], m[3][0] ], |
---|
1661 | [ m[0][1], m[1][1], m[2][1], m[3][1] ], |
---|
1662 | [ m[0][2], m[1][2], m[2][2], m[3][2] ], |
---|
1663 | [ m[0][3], m[1][3], m[2][3], m[3][3] ] ] |
---|
1664 | |
---|
1665 | def matrix_rotate(axis, angle): |
---|
1666 | vx = axis[0] |
---|
1667 | vy = axis[1] |
---|
1668 | vz = axis[2] |
---|
1669 | vx2 = vx * vx |
---|
1670 | vy2 = vy * vy |
---|
1671 | vz2 = vz * vz |
---|
1672 | cos = math.cos(angle) |
---|
1673 | sin = math.sin(angle) |
---|
1674 | co1 = 1.0 - cos |
---|
1675 | return [ |
---|
1676 | [vx2 * co1 + cos, vx * vy * co1 + vz * sin, vz * vx * co1 - vy * sin, 0.0], |
---|
1677 | [vx * vy * co1 - vz * sin, vy2 * co1 + cos, vy * vz * co1 + vx * sin, 0.0], |
---|
1678 | [vz * vx * co1 + vy * sin, vy * vz * co1 - vx * sin, vz2 * co1 + cos, 0.0], |
---|
1679 | [0.0, 0.0, 0.0, 1.0], |
---|
1680 | ] |
---|
1681 | |
---|
1682 | def point_by_matrix(p, m): |
---|
1683 | return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0] + m[3][0], |
---|
1684 | p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1] + m[3][1], |
---|
1685 | p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]] |
---|
1686 | |
---|
1687 | def vector_by_matrix(p, m): |
---|
1688 | return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0], |
---|
1689 | p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1], |
---|
1690 | p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2]] |
---|
1691 | |
---|
1692 | def vector_normalize(v): |
---|
1693 | global exportLogger |
---|
1694 | l = math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) |
---|
1695 | if l <= 0.000001: |
---|
1696 | exportLogger.logError("error in normalize") |
---|
1697 | return [0 , l, 0] |
---|
1698 | return [v[0] / l, v[1] / l, v[2] / l] |
---|
1699 | |
---|
1700 | def normal_by_matrix(n, m): |
---|
1701 | m = matrix_transpose(matrix_invert(m)) |
---|
1702 | return vector_normalize(vector_by_matrix(n, m)) |
---|
1703 | |
---|
1704 | |
---|
1705 | def vector_dotproduct(v1, v2): |
---|
1706 | return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] |
---|
1707 | |
---|
1708 | def vector_crossproduct(v1, v2): |
---|
1709 | return [ |
---|
1710 | v1[1] * v2[2] - v1[2] * v2[1], |
---|
1711 | v1[2] * v2[0] - v1[0] * v2[2], |
---|
1712 | v1[0] * v2[1] - v1[1] * v2[0], |
---|
1713 | ] |
---|
1714 | |
---|
1715 | ####################################################################################### |
---|
1716 | ## data structures |
---|
1717 | |
---|
1718 | class MaterialInterface: |
---|
1719 | def getName(self): |
---|
1720 | """Returns the material name. |
---|
1721 | |
---|
1722 | @return Material name. |
---|
1723 | """ |
---|
1724 | return |
---|
1725 | def write(self, f): |
---|
1726 | """Write material script entry. |
---|
1727 | |
---|
1728 | @param f Material script file object to write into. |
---|
1729 | """ |
---|
1730 | return |
---|
1731 | |
---|
1732 | class DefaultMaterial(MaterialInterface): |
---|
1733 | def __init__(self, name): |
---|
1734 | self.name = name |
---|
1735 | return |
---|
1736 | def getName(self): |
---|
1737 | return self.name |
---|
1738 | def write(self, f): |
---|
1739 | f.write("material %s\n" % self.getName()) |
---|
1740 | f.write("{\n") |
---|
1741 | self.writeTechniques(f) |
---|
1742 | f.write("}\n") |
---|
1743 | return |
---|
1744 | def writeTechniques(self, f): |
---|
1745 | f.write(tab(1) + "technique\n" + tab(1) + "{\n") |
---|
1746 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
1747 | # empty pass |
---|
1748 | f.write(tab(2) + "}\n") # pass |
---|
1749 | f.write(tab(1) + "}\n") # technique |
---|
1750 | return |
---|
1751 | |
---|
1752 | class GameEngineMaterial(DefaultMaterial): |
---|
1753 | def __init__(self, blenderMesh, blenderFace): |
---|
1754 | self.mesh = blenderMesh |
---|
1755 | self.face = blenderFace |
---|
1756 | # check if a Blender material is assigned |
---|
1757 | try: |
---|
1758 | blenderMaterial = self.mesh.materials[self.face.mat] |
---|
1759 | except: |
---|
1760 | blenderMaterial = None |
---|
1761 | self.material = blenderMaterial |
---|
1762 | DefaultMaterial.__init__(self, self._createName()) |
---|
1763 | return |
---|
1764 | def writeTechniques(self, f): |
---|
1765 | mat = self.material |
---|
1766 | if (not(mat) |
---|
1767 | and not(self.mesh.vertexColors) |
---|
1768 | and not(self.mesh.vertexUV or self.mesh.faceUV)): |
---|
1769 | # default material |
---|
1770 | DefaultMaterial.writeTechniques(self, f) |
---|
1771 | else: |
---|
1772 | # default material |
---|
1773 | # SOLID, white, no specular |
---|
1774 | f.write(tab(1)+"technique\n") |
---|
1775 | f.write(tab(1)+"{\n") |
---|
1776 | f.write(tab(2)+"pass\n") |
---|
1777 | f.write(tab(2)+"{\n") |
---|
1778 | # ambient |
---|
1779 | # (not used in Blender's game engine) |
---|
1780 | if mat: |
---|
1781 | if (not(mat.mode & Blender.Material.Modes["TEXFACE"]) |
---|
1782 | and not(mat.mode & Blender.Material.Modes["VCOL_PAINT"]) |
---|
1783 | and (ambientToggle.val)): |
---|
1784 | ambientRGBList = mat.rgbCol |
---|
1785 | else: |
---|
1786 | ambientRGBList = [1.0, 1.0, 1.0] |
---|
1787 | # ambient <- amb * ambient RGB |
---|
1788 | ambR = clamp(mat.amb * ambientRGBList[0]) |
---|
1789 | ambG = clamp(mat.amb * ambientRGBList[1]) |
---|
1790 | ambB = clamp(mat.amb * ambientRGBList[2]) |
---|
1791 | ##f.write(tab(3)+"ambient %f %f %f\n" % (ambR, ambG, ambB)) |
---|
1792 | # diffuse |
---|
1793 | # (Blender's game engine uses vertex colours |
---|
1794 | # instead of diffuse colour. |
---|
1795 | # |
---|
1796 | # diffuse is defined as |
---|
1797 | # (mat->r, mat->g, mat->b)*(mat->emit + mat->ref) |
---|
1798 | # but it's not used.) |
---|
1799 | if self.mesh.vertexColors: |
---|
1800 | #TODO: Broken in Blender 2.36. |
---|
1801 | # Blender does not handle "texface" mesh with vertexcolours |
---|
1802 | f.write(tab(3)+"diffuse vertexcolour\n") |
---|
1803 | elif mat: |
---|
1804 | if (not(mat.mode & Blender.Material.Modes["TEXFACE"]) |
---|
1805 | and not(mat.mode & Blender.Material.Modes["VCOL_PAINT"])): |
---|
1806 | # diffuse <- rgbCol |
---|
1807 | diffR = clamp(mat.rgbCol[0]) |
---|
1808 | diffG = clamp(mat.rgbCol[1]) |
---|
1809 | diffB = clamp(mat.rgbCol[2]) |
---|
1810 | f.write(tab(3)+"diffuse %f %f %f\n" % (diffR, diffG, diffB)) |
---|
1811 | elif (mat.mode & Blender.Material.Modes["VCOL_PAINT"]): |
---|
1812 | f.write(tab(3)+"diffuse vertexcolour\n") |
---|
1813 | if mat: |
---|
1814 | # specular <- spec * specCol, hard/4.0 |
---|
1815 | specR = clamp(mat.spec * mat.specCol[0]) |
---|
1816 | specG = clamp(mat.spec * mat.specCol[1]) |
---|
1817 | specB = clamp(mat.spec * mat.specCol[2]) |
---|
1818 | specShine = mat.hard/4.0 |
---|
1819 | f.write(tab(3)+"specular %f %f %f %f\n" % (specR, specG, specB, specShine)) |
---|
1820 | # emissive |
---|
1821 | # (not used in Blender's game engine) |
---|
1822 | if(not(mat.mode & Blender.Material.Modes["TEXFACE"]) |
---|
1823 | and not(mat.mode & Blender.Material.Modes["VCOL_PAINT"])): |
---|
1824 | # emissive <-emit * rgbCol |
---|
1825 | emR = clamp(mat.emit * mat.rgbCol[0]) |
---|
1826 | emG = clamp(mat.emit * mat.rgbCol[1]) |
---|
1827 | emB = clamp(mat.emit * mat.rgbCol[2]) |
---|
1828 | ##f.write(tab(3)+"emissive %f %f %f\n" % (emR, emG, emB)) |
---|
1829 | # scene_blend <- transp |
---|
1830 | if (self.face.mode == Blender.NMesh.FaceTranspModes["ALPHA"]): |
---|
1831 | f.write(tab(3)+"scene_blend alpha_blend \n") |
---|
1832 | elif (self.face.mode == Blender.NMesh.FaceTranspModes["ADD"]): |
---|
1833 | #TODO: Broken in Blender 2.36. |
---|
1834 | #f.write(tab(3)+"scene_blend add\n") |
---|
1835 | pass |
---|
1836 | # cull_hardware/cull_software |
---|
1837 | if (self.face.mode & Blender.NMesh.FaceModes['TWOSIDE']): |
---|
1838 | f.write(tab(3) + "cull_hardware none\n") |
---|
1839 | f.write(tab(3) + "cull_software none\n") |
---|
1840 | # shading |
---|
1841 | # (Blender's game engine is initialized with glShadeModel(GL_FLAT)) |
---|
1842 | ##f.write(tab(3) + "shading flat\n") |
---|
1843 | # texture |
---|
1844 | if (self.face.mode & Blender.NMesh.FaceModes['TEX']) and (self.face.image): |
---|
1845 | f.write(tab(3)+"texture_unit\n") |
---|
1846 | f.write(tab(3)+"{\n") |
---|
1847 | f.write(tab(4)+"texture %s\n" % PathName(self.face.image.filename).basename()) |
---|
1848 | f.write(tab(3)+"}\n") # texture_unit |
---|
1849 | f.write(tab(2)+"}\n") # pass |
---|
1850 | f.write(tab(1)+"}\n") # technique |
---|
1851 | return |
---|
1852 | # private |
---|
1853 | def _createName(self): |
---|
1854 | """Create unique material name. |
---|
1855 | |
---|
1856 | The name consists of several parts: |
---|
1857 | <OL> |
---|
1858 | <LI>rendering material name/</LI> |
---|
1859 | <LI>blend mode (ALPHA, ADD, SOLID)</LI> |
---|
1860 | <LI>/TEX</LI> |
---|
1861 | <LI>/texture file name</LI> |
---|
1862 | <LI>/VertCol</LI> |
---|
1863 | <LI>/TWOSIDE></LI> |
---|
1864 | </OL> |
---|
1865 | """ |
---|
1866 | materialName = '' |
---|
1867 | # nonempty rendering material? |
---|
1868 | if self.material: |
---|
1869 | materialName += self.material.getName() + '/' |
---|
1870 | # blend mode |
---|
1871 | if (self.face.transp == Blender.NMesh.FaceTranspModes['ALPHA']): |
---|
1872 | materialName += 'ALPHA' |
---|
1873 | elif (self.face.transp == Blender.NMesh.FaceTranspModes['ADD']): |
---|
1874 | materialName += 'ADD' |
---|
1875 | else: |
---|
1876 | materialName += 'SOLID' |
---|
1877 | # TEX face mode and texture? |
---|
1878 | if (self.face.mode & Blender.NMesh.FaceModes['TEX']): |
---|
1879 | materialName += '/TEX' |
---|
1880 | if self.face.image: |
---|
1881 | materialName += '/' + PathName(self.face.image.filename).basename() |
---|
1882 | # vertex colours? |
---|
1883 | if self.mesh.vertexColors: |
---|
1884 | materialName += '/VertCol' |
---|
1885 | # two sided? |
---|
1886 | if (self.face.mode & Blender.NMesh.FaceModes['TWOSIDE']): |
---|
1887 | materialName += '/TWOSIDE' |
---|
1888 | return materialName |
---|
1889 | |
---|
1890 | class RenderingMaterial(DefaultMaterial): |
---|
1891 | def __init__(self, blenderMesh, blenderFace): |
---|
1892 | self.mesh = blenderMesh |
---|
1893 | self.face = blenderFace |
---|
1894 | self.key = 0 |
---|
1895 | self.mTexUVCol = None |
---|
1896 | self.mTexUVNor = None |
---|
1897 | self.mTexUVCsp = None |
---|
1898 | self.material = self.mesh.materials[self.face.mat] |
---|
1899 | if self.material: |
---|
1900 | self._generateKey() |
---|
1901 | DefaultMaterial.__init__(self, self._createName()) |
---|
1902 | else: |
---|
1903 | DefaultMaterial.__init__(self, 'None') |
---|
1904 | return |
---|
1905 | def writeTechniques(self, f): |
---|
1906 | # parse material |
---|
1907 | if self.key: |
---|
1908 | if self.TECHNIQUES.has_key(self.key): |
---|
1909 | techniques = self.TECHNIQUES[self.key] |
---|
1910 | techniques(self, f) |
---|
1911 | else: |
---|
1912 | # default |
---|
1913 | self.writeColours(f) |
---|
1914 | else: |
---|
1915 | # Halo or empty material |
---|
1916 | DefaultMaterial('').writeTechniques(f) |
---|
1917 | return |
---|
1918 | def writeColours(self, f): |
---|
1919 | global ambientToggle |
---|
1920 | # receive_shadows |
---|
1921 | self.writeReceiveShadows(f, 1) |
---|
1922 | f.write(tab(1) + "technique\n" + tab(1) + "{\n") |
---|
1923 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
1924 | # ambient |
---|
1925 | if (ambientToggle.val): |
---|
1926 | col = self.material.getRGBCol() |
---|
1927 | else: |
---|
1928 | col = [1.0, 1.0, 1.0] |
---|
1929 | self.writeAmbient(f, col, 3) |
---|
1930 | # diffuse |
---|
1931 | self.writeDiffuse(f, self.material.rgbCol, 3) |
---|
1932 | # specular |
---|
1933 | self.writeSpecular(f, 3) |
---|
1934 | # emissive |
---|
1935 | self.writeEmissive(f, self.material.rgbCol, 3) |
---|
1936 | # blend mode |
---|
1937 | self.writeSceneBlend(f,3) |
---|
1938 | # options |
---|
1939 | self.writeCommonOptions(f, 3) |
---|
1940 | # texture units |
---|
1941 | self.writeDiffuseTexture(f, 3) |
---|
1942 | f.write(tab(2) + "}\n") # pass |
---|
1943 | f.write(tab(1) + "}\n") # technique |
---|
1944 | return |
---|
1945 | def writeTexFace(self, f): |
---|
1946 | # preconditions: TEXFACE set |
---|
1947 | # |
---|
1948 | # Note that an additional Col texture replaces the |
---|
1949 | # TEXFACE texture instead of blend over according to alpha. |
---|
1950 | # |
---|
1951 | # (amb+emit)textureCol + diffuseLight*ref*textureCol + specular |
---|
1952 | # |
---|
1953 | imageFileName = None |
---|
1954 | if self.mTexUVCol: |
---|
1955 | # COL MTex replaces UV/Image Editor texture |
---|
1956 | imageFileName = PathName(self.mTexUVCol.tex.getImage().getFilename()).basename() |
---|
1957 | elif self.face.image: |
---|
1958 | # UV/Image Editor texture |
---|
1959 | imageFileName = PathName(self.face.image.filename).basename() |
---|
1960 | |
---|
1961 | self.writeReceiveShadows(f, 1) |
---|
1962 | f.write(tab(1) + "technique\n" + tab(1) + "{\n") |
---|
1963 | col = [1.0, 1.0, 1.0] |
---|
1964 | # texture pass |
---|
1965 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
1966 | self.writeAmbient(f, col, 3) |
---|
1967 | self.writeDiffuse(f, col, 3) |
---|
1968 | if not(imageFileName): |
---|
1969 | self.writeSpecular(f, 3) |
---|
1970 | self.writeEmissive(f, col, 3) |
---|
1971 | self.writeSceneBlend(f,3) |
---|
1972 | self.writeCommonOptions(f, 3) |
---|
1973 | if imageFileName: |
---|
1974 | f.write(tab(3) + "texture_unit\n") |
---|
1975 | f.write(tab(3) + "{\n") |
---|
1976 | f.write(tab(4) + "texture %s\n" % imageFileName) |
---|
1977 | if self.mTexUVCol: |
---|
1978 | self.writeTextureAddressMode(f, self.mTexUVCol, 4) |
---|
1979 | self.writeTextureFiltering(f, self.mTexUVCol, 4) |
---|
1980 | # multiply with factors |
---|
1981 | f.write(tab(4) + "colour_op modulate\n") |
---|
1982 | f.write(tab(3) + "}\n") # texture_unit |
---|
1983 | f.write(tab(2) + "}\n") # texture pass |
---|
1984 | # specular pass |
---|
1985 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
1986 | f.write(tab(3) + "ambient 0.0 0.0 0.0\n") |
---|
1987 | f.write(tab(3) + "diffuse 0.0 0.0 0.0\n") |
---|
1988 | self.writeSpecular(f, 3) |
---|
1989 | f.write(tab(3) + "scene_blend add\n") |
---|
1990 | hasAlpha = 0 |
---|
1991 | if (self.material.getAlpha() < 1.0): |
---|
1992 | hasAlpha = 1 |
---|
1993 | else: |
---|
1994 | for mtex in self.material.getTextures(): |
---|
1995 | if mtex: |
---|
1996 | if ((mtex.tex.type == Blender.Texture.Types['IMAGE']) |
---|
1997 | and (mtex.mapto & Blender.Texture.MapTo['ALPHA'])): |
---|
1998 | hasAlpha = 1 |
---|
1999 | if (hasAlpha): |
---|
2000 | f.write(tab(3) + "depth_write off\n") |
---|
2001 | self.writeCommonOptions(f, 3) |
---|
2002 | f.write(tab(2) + "}\n") # pass |
---|
2003 | f.write(tab(1) + "}\n") # technique |
---|
2004 | return |
---|
2005 | def writeVertexColours(self, f): |
---|
2006 | # preconditions: VCOL_PAINT set |
---|
2007 | # |
---|
2008 | # ambient = Amb*White resp. Amb*VCol if "Coloured Ambient" |
---|
2009 | # diffuse = Ref*VCol |
---|
2010 | # specular = Spec*SpeRGB, Hard/4.0 |
---|
2011 | # emissive = Emit*VCol |
---|
2012 | # alpha = A |
---|
2013 | # |
---|
2014 | # Best match without vertex shader: |
---|
2015 | # ambient = Amb*white |
---|
2016 | # diffuse = Ref*VCol |
---|
2017 | # specular = Spec*SpeRGB, Hard/4.0 |
---|
2018 | # emissive = black |
---|
2019 | # alpha = 1 |
---|
2020 | # |
---|
2021 | self.writeReceiveShadows(f, 1) |
---|
2022 | f.write(tab(1) + "technique\n" + tab(1) + "{\n") |
---|
2023 | if (self.material.mode & Blender.Material.Modes['SHADELESS']): |
---|
2024 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
2025 | self.writeCommonOptions(f,3) |
---|
2026 | f.write(tab(2) + "}\n") |
---|
2027 | else: |
---|
2028 | # vertex colour pass |
---|
2029 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
2030 | f.write(tab(3) + "ambient 0.0 0.0 0.0\n") |
---|
2031 | f.write(tab(3) + "diffuse vertexcolour\n") |
---|
2032 | self.writeCommonOptions(f, 3) |
---|
2033 | f.write(tab(2) + "}\n") # vertex colour pass |
---|
2034 | |
---|
2035 | # factor pass |
---|
2036 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
2037 | f.write(tab(3) + "ambient 0.0 0.0 0.0\n") |
---|
2038 | ref = self.material.getRef() |
---|
2039 | f.write(tab(3) + "diffuse %f %f %f\n" % (ref, ref, ref)) |
---|
2040 | f.write(tab(3) + "scene_blend modulate\n") |
---|
2041 | self.writeCommonOptions(f, 3) |
---|
2042 | f.write(tab(2) + "}\n") # factor pass |
---|
2043 | |
---|
2044 | # ambient and specular pass |
---|
2045 | f.write(tab(2) + "pass\n" + tab(2) + "{\n") |
---|
2046 | self.writeAmbient(f, [1.0, 1.0, 1.0], 3) |
---|
2047 | f.write(tab(3) + "diffuse 0.0 0.0 0.0\n") |
---|
2048 | self.writeSpecular(f, 3) |
---|
2049 | f.write(tab(3) + "scene_blend add\n") |
---|
2050 | self.writeCommonOptions(f, 3) |
---|
2051 | f.write(tab(2) + "}\n") # specular pass |
---|
2052 | |
---|
2053 | f.write(tab(1) + "}\n") # technique |
---|
2054 | return |
---|
2055 | def writeNormalMap(self, f): |
---|
2056 | # preconditions COL and NOR textures |
---|
2057 | colImage = PathName(self.mTexUVCol.tex.image.filename).basename() |
---|
2058 | norImage = PathName(self.mTexUVNor.tex.image.filename).basename() |
---|
2059 | f.write(""" technique |
---|
2060 | { |
---|
2061 | pass |
---|
2062 | { |
---|
2063 | ambient 1 1 1 |
---|
2064 | diffuse 0 0 0 |
---|
2065 | specular 0 0 0 0 |
---|
2066 | vertex_program_ref Ogre/BasicVertexPrograms/AmbientOneTexture |
---|
2067 | { |
---|
2068 | param_named_auto worldViewProj worldviewproj_matrix |
---|
2069 | param_named_auto ambient ambient_light_colour |
---|
2070 | } |
---|
2071 | } |
---|
2072 | pass |
---|
2073 | { |
---|
2074 | ambient 0 0 0 |
---|
2075 | iteration once_per_light |
---|
2076 | scene_blend add |
---|
2077 | vertex_program_ref Examples/BumpMapVPSpecular |
---|
2078 | { |
---|
2079 | param_named_auto lightPosition light_position_object_space 0 |
---|
2080 | param_named_auto eyePosition camera_position_object_space |
---|
2081 | param_named_auto worldViewProj worldviewproj_matrix |
---|
2082 | } |
---|
2083 | fragment_program_ref Examples/BumpMapFPSpecular |
---|
2084 | { |
---|
2085 | param_named_auto lightDiffuse light_diffuse_colour 0 |
---|
2086 | param_named_auto lightSpecular light_specular_colour 0 |
---|
2087 | } |
---|
2088 | texture_unit |
---|
2089 | { |
---|
2090 | texture %s |
---|
2091 | colour_op replace |
---|
2092 | } |
---|
2093 | texture_unit |
---|
2094 | { |
---|
2095 | cubic_texture nm.png combinedUVW |
---|
2096 | tex_coord_set 1 |
---|
2097 | tex_address_mode clamp |
---|
2098 | } |
---|
2099 | texture_unit |
---|
2100 | { |
---|
2101 | cubic_texture nm.png combinedUVW |
---|
2102 | tex_coord_set 2 |
---|
2103 | tex_address_mode clamp |
---|
2104 | } |
---|
2105 | } |
---|
2106 | pass |
---|
2107 | { |
---|
2108 | lighting off |
---|
2109 | vertex_program_ref Ogre/BasicVertexPrograms/AmbientOneTexture |
---|
2110 | { |
---|
2111 | param_named_auto worldViewProj worldviewproj_matrix |
---|
2112 | param_named ambient float4 1 1 1 1 |
---|
2113 | } |
---|
2114 | scene_blend dest_colour zero |
---|
2115 | texture_unit |
---|
2116 | { |
---|
2117 | texture %s |
---|
2118 | } |
---|
2119 | } |
---|
2120 | } |
---|
2121 | technique |
---|
2122 | { |
---|
2123 | pass |
---|
2124 | { |
---|
2125 | ambient 1 1 1 |
---|
2126 | diffuse 0 0 0 |
---|
2127 | specular 0 0 0 0 |
---|
2128 | vertex_program_ref Ogre/BasicVertexPrograms/AmbientOneTexture |
---|
2129 | { |
---|
2130 | param_named_auto worldViewProj worldviewproj_matrix |
---|
2131 | param_named_auto ambient ambient_light_colour |
---|
2132 | } |
---|
2133 | } |
---|
2134 | pass |
---|
2135 | { |
---|
2136 | ambient 0 0 0 |
---|
2137 | iteration once_per_light |
---|
2138 | scene_blend add |
---|
2139 | vertex_program_ref Examples/BumpMapVP |
---|
2140 | { |
---|
2141 | param_named_auto lightPosition light_position_object_space 0 |
---|
2142 | param_named_auto eyePosition camera_position_object_space |
---|
2143 | param_named_auto worldViewProj worldviewproj_matrix |
---|
2144 | } |
---|
2145 | texture_unit |
---|
2146 | { |
---|
2147 | texture %s |
---|
2148 | colour_op replace |
---|
2149 | } |
---|
2150 | texture_unit |
---|
2151 | { |
---|
2152 | cubic_texture nm.png combinedUVW |
---|
2153 | tex_coord_set 1 |
---|
2154 | tex_address_mode clamp |
---|
2155 | colour_op_ex dotproduct src_texture src_current |
---|
2156 | colour_op_multipass_fallback dest_colour zero |
---|
2157 | } |
---|
2158 | } |
---|
2159 | pass |
---|
2160 | { |
---|
2161 | lighting off |
---|
2162 | vertex_program_ref Ogre/BasicVertexPrograms/AmbientOneTexture |
---|
2163 | { |
---|
2164 | param_named_auto worldViewProj worldviewproj_matrix |
---|
2165 | param_named ambient float4 1 1 1 1 |
---|
2166 | } |
---|
2167 | scene_blend dest_colour zero |
---|
2168 | texture_unit |
---|
2169 | { |
---|
2170 | texture %s |
---|
2171 | } |
---|
2172 | } |
---|
2173 | } |
---|
2174 | """ % (norImage, colImage, norImage, colImage)) |
---|
2175 | return |
---|
2176 | def writeReceiveShadows(self, f, indent=0): |
---|
2177 | if (self.material.mode & Blender.Material.Modes["SHADOW"]): |
---|
2178 | f.write(tab(indent)+"receive_shadows on\n") |
---|
2179 | else: |
---|
2180 | f.write(tab(indent)+"receive_shadows off\n") |
---|
2181 | return |
---|
2182 | def writeAmbient(self, f, col, indent=0): |
---|
2183 | # ambient <- amb * ambient RGB |
---|
2184 | ambR = clamp(self.material.getAmb() * col[0]) |
---|
2185 | ambG = clamp(self.material.getAmb() * col[1]) |
---|
2186 | ambB = clamp(self.material.getAmb() * col[2]) |
---|
2187 | if len(col) < 4: |
---|
2188 | alpha = self.material.getAlpha() |
---|
2189 | else: |
---|
2190 | alpha = col[3] |
---|
2191 | f.write(tab(indent)+"ambient %f %f %f %f\n" % (ambR, ambG, ambB, alpha)) |
---|
2192 | return |
---|
2193 | def writeDiffuse(self, f, col, indent=0): |
---|
2194 | # diffuse = reflectivity*colour |
---|
2195 | diffR = clamp(col[0] * self.material.getRef()) |
---|
2196 | diffG = clamp(col[1] * self.material.getRef()) |
---|
2197 | diffB = clamp(col[2] * self.material.getRef()) |
---|
2198 | if len(col) < 4: |
---|
2199 | alpha = self.material.getAlpha() |
---|
2200 | else: |
---|
2201 | alpha = col[3] |
---|
2202 | f.write(tab(indent)+"diffuse %f %f %f %f\n" % (diffR, diffG, diffB, alpha)) |
---|
2203 | return |
---|
2204 | def writeSpecular(self, f, indent=0): |
---|
2205 | # specular <- spec * specCol, hard/4.0 |
---|
2206 | specR = clamp(self.material.getSpec() * self.material.getSpecCol()[0]) |
---|
2207 | specG = clamp(self.material.getSpec() * self.material.getSpecCol()[1]) |
---|
2208 | specB = clamp(self.material.getSpec() * self.material.getSpecCol()[2]) |
---|
2209 | specShine = self.material.getHardness()/4.0 |
---|
2210 | alpha = self.material.getAlpha() |
---|
2211 | f.write(tab(indent)+"specular %f %f %f %f %f\n" % (specR, specG, specB, alpha, specShine)) |
---|
2212 | return |
---|
2213 | def writeEmissive(self, f, col, indent=0): |
---|
2214 | # emissive <-emit * rgbCol |
---|
2215 | emR = clamp(self.material.getEmit() * col[0]) |
---|
2216 | emG = clamp(self.material.getEmit() * col[1]) |
---|
2217 | emB = clamp(self.material.getEmit() * col[2]) |
---|
2218 | if len(col) < 4: |
---|
2219 | alpha = self.material.getAlpha() |
---|
2220 | else: |
---|
2221 | alpha = col[3] |
---|
2222 | f.write(tab(indent)+"emissive %f %f %f %f\n" % (emR, emG, emB, alpha)) |
---|
2223 | return |
---|
2224 | def writeSceneBlend(self, f, indent=0): |
---|
2225 | hasAlpha = 0 |
---|
2226 | if (self.material.getAlpha() < 1.0): |
---|
2227 | hasAlpha = 1 |
---|
2228 | else: |
---|
2229 | for mtex in self.material.getTextures(): |
---|
2230 | if mtex: |
---|
2231 | if ((mtex.tex.type == Blender.Texture.Types['IMAGE']) |
---|
2232 | and (mtex.mapto & Blender.Texture.MapTo['ALPHA'])): |
---|
2233 | hasAlpha = 1 |
---|
2234 | if (hasAlpha): |
---|
2235 | f.write(tab(indent) + "scene_blend alpha_blend\n") |
---|
2236 | f.write(tab(indent) + "depth_write off\n") |
---|
2237 | return |
---|
2238 | def writeCommonOptions(self, f, indent=0): |
---|
2239 | # Shadeless, ZInvert, NoMist, Env |
---|
2240 | # depth_func <- ZINVERT; ENV |
---|
2241 | if (self.material.mode & Blender.Material.Modes['ENV']): |
---|
2242 | f.write(tab(indent)+"depth_func always_fail\n") |
---|
2243 | elif (self.material.mode & Blender.Material.Modes['ZINVERT']): |
---|
2244 | f.write(tab(indent)+"depth_func greater_equal\n") |
---|
2245 | # twoside |
---|
2246 | # 2.4 raises an exception if face.mode is accessed and mesh has no uv |
---|
2247 | try: |
---|
2248 | if (self.face.mode & Blender.NMesh.FaceModes['TWOSIDE']): |
---|
2249 | f.write(tab(3) + "cull_hardware none\n") |
---|
2250 | f.write(tab(3) + "cull_software none\n") |
---|
2251 | except: |
---|
2252 | pass |
---|
2253 | # lighting <- SHADELESS |
---|
2254 | if (self.material.mode & Blender.Material.Modes['SHADELESS']): |
---|
2255 | f.write(tab(indent)+"lighting off\n") |
---|
2256 | # fog_override <- NOMIST |
---|
2257 | if (self.material.mode & Blender.Material.Modes['NOMIST']): |
---|
2258 | f.write(tab(indent)+"fog_override true\n") |
---|
2259 | return |
---|
2260 | def writeDiffuseTexture(self, f, indent = 0): |
---|
2261 | if self.mTexUVCol: |
---|
2262 | f.write(tab(indent)+"texture_unit\n") |
---|
2263 | f.write(tab(indent)+"{\n") |
---|
2264 | f.write(tab(indent + 1) + "texture %s\n" % PathName(self.mTexUVCol.tex.getImage().getFilename()).basename()) |
---|
2265 | self.writeTextureAddressMode(f, self.mTexUVCol, indent + 1) |
---|
2266 | self.writeTextureFiltering(f, self.mTexUVCol, indent + 1) |
---|
2267 | self.writeTextureColourOp(f, self.mTexUVCol, indent + 1) |
---|
2268 | f.write(tab(indent)+"}\n") # texture_unit |
---|
2269 | return |
---|
2270 | def writeTextureAddressMode(self, f, blenderMTex, indent = 0): |
---|
2271 | # tex_address_mode inside texture_unit |
---|
2272 | # |
---|
2273 | # EXTEND | clamp |
---|
2274 | # CLIP | |
---|
2275 | # CLIPCUBE | |
---|
2276 | # REPEAT | wrap |
---|
2277 | # |
---|
2278 | if (blenderMTex.tex.extend & Blender.Texture.ExtendModes['REPEAT']): |
---|
2279 | f.write(tab(indent) + "tex_address_mode wrap\n") |
---|
2280 | elif (blenderMTex.tex.extend & Blender.Texture.ExtendModes['EXTEND']): |
---|
2281 | f.write(tab(indent) + "tex_address_mode clamp\n") |
---|
2282 | return |
---|
2283 | def writeTextureFiltering(self, f, blenderMTex, indent = 0): |
---|
2284 | # filtering inside texture_unit |
---|
2285 | # |
---|
2286 | # InterPol | MidMap | filtering |
---|
2287 | # ---------+--------+---------- |
---|
2288 | # yes | yes | trilinear |
---|
2289 | # yes | no | linear linear none |
---|
2290 | # no | yes | bilinear |
---|
2291 | # no | no | none |
---|
2292 | # |
---|
2293 | if (blenderMTex.tex.imageFlags & Blender.Texture.ImageFlags['INTERPOL']): |
---|
2294 | if (blenderMTex.tex.imageFlags & Blender.Texture.ImageFlags['MIPMAP']): |
---|
2295 | f.write(tab(indent) + "filtering trilinear\n") |
---|
2296 | else: |
---|
2297 | f.write(tab(indent) + "filtering linear linear none\n") |
---|
2298 | else: |
---|
2299 | if (blenderMTex.tex.imageFlags & Blender.Texture.ImageFlags['MIPMAP']): |
---|
2300 | f.write(tab(indent) + "filtering bilinear\n") |
---|
2301 | else: |
---|
2302 | f.write(tab(indent) + "filtering none\n") |
---|
2303 | return |
---|
2304 | def writeTextureColourOp(self, f, blenderMTex, indent = 0): |
---|
2305 | # colour_op inside texture_unit |
---|
2306 | if ((blenderMTex.tex.imageFlags & Blender.Texture.ImageFlags['USEALPHA']) |
---|
2307 | and not(blenderMTex.mapto & Blender.Texture.MapTo['ALPHA'])): |
---|
2308 | f.write(tab(indent) + "colour_op alpha_blend\n") |
---|
2309 | return |
---|
2310 | # private |
---|
2311 | def _createName(self): |
---|
2312 | # must be called after _generateKey() |
---|
2313 | materialName = self.material.getName() |
---|
2314 | # two sided? |
---|
2315 | try: |
---|
2316 | if (self.face.mode & Blender.Mesh.FaceModes['TWOSIDE']): |
---|
2317 | materialName += '/TWOSIDE' |
---|
2318 | except: |
---|
2319 | pass |
---|
2320 | # use UV/Image Editor texture? |
---|
2321 | if ((self.key & self.TEXFACE) and not(self.key & self.IMAGEUVCOL)): |
---|
2322 | materialName += '/TEXFACE' |
---|
2323 | if self.face.image: |
---|
2324 | materialName += '/' + PathName(self.face.image.filename).basename() |
---|
2325 | return materialName |
---|
2326 | def _generateKey(self): |
---|
2327 | # generates key and populates mTex fields |
---|
2328 | if self.material: |
---|
2329 | if not(self.material.mode & Blender.Material.Modes['HALO']): |
---|
2330 | self.key |= self.NONHALO |
---|
2331 | if (self.material.mode & Blender.Material.Modes['VCOL_LIGHT']): |
---|
2332 | self.key |= self.VCOLLIGHT |
---|
2333 | if (self.material.mode & Blender.Material.Modes['VCOL_PAINT']): |
---|
2334 | self.key |= self.VCOLPAINT |
---|
2335 | if (self.material.mode & Blender.Material.Modes['TEXFACE']): |
---|
2336 | self.key |= self.TEXFACE |
---|
2337 | # textures |
---|
2338 | for mtex in self.material.getTextures(): |
---|
2339 | if mtex: |
---|
2340 | if (mtex.tex.type == Blender.Texture.Types['IMAGE']): |
---|
2341 | if (mtex.texco & Blender.Texture.TexCo['UV']): |
---|
2342 | if (mtex.mapto & Blender.Texture.MapTo['COL']): |
---|
2343 | self.key |= self.IMAGEUVCOL |
---|
2344 | self.mTexUVCol = mtex |
---|
2345 | if (mtex.mapto & Blender.Texture.MapTo['NOR']): |
---|
2346 | # Check "Normal Map" image option |
---|
2347 | if (mtex.tex.imageFlags & 2048): |
---|
2348 | self.key |= self.IMAGEUVNOR |
---|
2349 | self.mTexUVNor = mtex |
---|
2350 | # else bumpmap |
---|
2351 | if (mtex.mapto & Blender.Texture.MapTo['CSP']): |
---|
2352 | self.key |= self.IMAGEUVCSP |
---|
2353 | self.mTexUVCsp = mtex |
---|
2354 | return |
---|
2355 | NONHALO = 1 |
---|
2356 | VCOLLIGHT = 2 |
---|
2357 | VCOLPAINT = 4 |
---|
2358 | TEXFACE = 8 |
---|
2359 | IMAGEUVCOL = 16 |
---|
2360 | IMAGEUVNOR = 32 |
---|
2361 | IMAGEUVCSP = 64 |
---|
2362 | # material techniques export methods |
---|
2363 | TECHNIQUES = { |
---|
2364 | NONHALO|IMAGEUVCOL : writeColours, |
---|
2365 | NONHALO|IMAGEUVCOL|IMAGEUVCSP : writeColours, |
---|
2366 | NONHALO|TEXFACE : writeTexFace, |
---|
2367 | NONHALO|TEXFACE|VCOLLIGHT : writeTexFace, |
---|
2368 | NONHALO|TEXFACE|IMAGEUVCOL : writeTexFace, |
---|
2369 | NONHALO|TEXFACE|IMAGEUVNOR : writeTexFace, |
---|
2370 | NONHALO|TEXFACE|IMAGEUVCSP : writeTexFace, |
---|
2371 | NONHALO|TEXFACE|VCOLLIGHT|IMAGEUVCOL : writeTexFace, |
---|
2372 | NONHALO|TEXFACE|VCOLLIGHT|IMAGEUVNOR : writeTexFace, |
---|
2373 | NONHALO|TEXFACE|VCOLLIGHT|IMAGEUVCSP : writeTexFace, |
---|
2374 | NONHALO|TEXFACE|IMAGEUVCOL|IMAGEUVCSP : writeTexFace, |
---|
2375 | NONHALO|TEXFACE|IMAGEUVNOR|IMAGEUVCSP : writeTexFace, |
---|
2376 | NONHALO|TEXFACE|VCOLLIGHT|IMAGEUVCOL|IMAGEUVCSP : writeTexFace, |
---|
2377 | NONHALO|TEXFACE|VCOLLIGHT|IMAGEUVNOR|IMAGEUVCSP : writeTexFace, |
---|
2378 | NONHALO|VCOLPAINT : writeVertexColours, |
---|
2379 | NONHALO|VCOLPAINT|VCOLLIGHT : writeVertexColours, |
---|
2380 | NONHALO|IMAGEUVCOL|IMAGEUVNOR : writeNormalMap, |
---|
2381 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT : writeNormalMap, |
---|
2382 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLPAINT : writeNormalMap, |
---|
2383 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|TEXFACE : writeNormalMap, |
---|
2384 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|IMAGEUVCSP : writeNormalMap, |
---|
2385 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT|VCOLPAINT : writeNormalMap, |
---|
2386 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT|TEXFACE : writeNormalMap, |
---|
2387 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT|IMAGEUVCSP : writeNormalMap, |
---|
2388 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLPAINT|TEXFACE : writeNormalMap, |
---|
2389 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLPAINT|IMAGEUVCSP : writeNormalMap, |
---|
2390 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|TEXFACE|IMAGEUVCSP : writeNormalMap, |
---|
2391 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLPAINT|TEXFACE|IMAGEUVCSP : writeNormalMap, |
---|
2392 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT|TEXFACE|IMAGEUVCSP : writeNormalMap, |
---|
2393 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT|VCOLPAINT|IMAGEUVCSP : writeNormalMap, |
---|
2394 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT|VCOLPAINT|TEXFACE : writeNormalMap, |
---|
2395 | NONHALO|IMAGEUVCOL|IMAGEUVNOR|VCOLLIGHT|VCOLPAINT|TEXFACE|IMAGEUVCSP : writeNormalMap |
---|
2396 | } |
---|
2397 | |
---|
2398 | class Mesh: |
---|
2399 | def __init__(self, submeshList, skeleton=None, nmesh=None): |
---|
2400 | """Constructor. |
---|
2401 | |
---|
2402 | @param submeshList Submeshes. |
---|
2403 | @param nmesh Blender NMesh. |
---|
2404 | """ |
---|
2405 | self.name = '' |
---|
2406 | self.submeshList = submeshList |
---|
2407 | self.skeleton = skeleton |
---|
2408 | # boolean |
---|
2409 | self.vertexColours = 0 |
---|
2410 | # boolean |
---|
2411 | self.uvCoordinates = 0 |
---|
2412 | # parse nmesh |
---|
2413 | self._parseMesh(nmesh) |
---|
2414 | return |
---|
2415 | def hasVertexColours(self): |
---|
2416 | return self.vertexColours |
---|
2417 | def hasUVCoordinates(self): |
---|
2418 | return self.uvCoordinates |
---|
2419 | def write(self): |
---|
2420 | # write_mesh(name, submeshes, skeleton): |
---|
2421 | global pathString, exportLogger |
---|
2422 | file = self.name + ".mesh.xml" |
---|
2423 | exportLogger.logInfo("Mesh \"%s\"" % file) |
---|
2424 | |
---|
2425 | f = open(os.path.join(pathString.val, file), "w") |
---|
2426 | f.write(tab(0)+"<mesh>\n") |
---|
2427 | f.write(tab(1)+"<submeshes>\n") |
---|
2428 | for submesh in self.submeshList: |
---|
2429 | f.write(tab(2)+"<submesh") |
---|
2430 | f.write(" material=\"%s\"" % submesh.material.name) |
---|
2431 | f.write(" usesharedvertices=\"false\"") |
---|
2432 | f.write(" use32bitindexes=\"false\"") |
---|
2433 | f.write(" operationtype=\"triangle_list\"") |
---|
2434 | f.write(">\n") |
---|
2435 | |
---|
2436 | f.write(tab(3)+"<faces count=\"%d\">\n" % len(submesh.faces)) |
---|
2437 | for face in submesh.faces: |
---|
2438 | v1, v2, v3 = face.vertex1.id, face.vertex2.id, face.vertex3.id |
---|
2439 | f.write(tab(4)+"<face v1=\"%d\" v2=\"%d\" v3=\"%d\"/>\n" % (v1, v2, v3)) |
---|
2440 | f.write(tab(3)+"</faces>\n") |
---|
2441 | |
---|
2442 | f.write(tab(3)+"<geometry vertexcount=\"%d\">\n" % len(submesh.vertices)) |
---|
2443 | if (armatureToggle.val): |
---|
2444 | # use seperate vertexbuffer for position and normals when animated |
---|
2445 | f.write(tab(4)+"<vertexbuffer positions=\"true\" normals=\"true\">\n") |
---|
2446 | for v in submesh.vertices: |
---|
2447 | f.write(XMLVertexStringView(v.xmlVertex).toString(5, ['normal','position'])) |
---|
2448 | f.write(tab(4)+"</vertexbuffer>\n") |
---|
2449 | if (self.hasUVCoordinates() and self.hasVertexColours()): |
---|
2450 | f.write(tab(4)+"<vertexbuffer") |
---|
2451 | f.write(" texture_coord_dimensions_0=\"2\" texture_coords=\"1\"") |
---|
2452 | f.write(" colours_diffuse=\"true\">\n") |
---|
2453 | for v in submesh.vertices: |
---|
2454 | f.write(XMLVertexStringView(v.xmlVertex).toString(5, ['texcoordList','colourDiffuse'])) |
---|
2455 | f.write(tab(4)+"</vertexbuffer>\n") |
---|
2456 | elif self.hasUVCoordinates(): |
---|
2457 | f.write(tab(4)+"<vertexbuffer") |
---|
2458 | f.write(" texture_coord_dimensions_0=\"2\" texture_coords=\"1\">\n") |
---|
2459 | for v in submesh.vertices: |
---|
2460 | f.write(XMLVertexStringView(v.xmlVertex).toString(5, ['texcoordList'])) |
---|
2461 | f.write(tab(4)+"</vertexbuffer>\n") |
---|
2462 | elif self.hasVertexColours(): |
---|
2463 | f.write(tab(4)+"<vertexbuffer") |
---|
2464 | f.write(" colours_diffuse=\"true\">\n") |
---|
2465 | for v in submesh.vertices: |
---|
2466 | f.write(XMLVertexStringView(v.xmlVertex).toString(5, ['colourDiffuse'])) |
---|
2467 | f.write(tab(4)+"</vertexbuffer>\n") |
---|
2468 | else: |
---|
2469 | # use only one vertex buffer if mesh is not animated |
---|
2470 | f.write(tab(4)+"<vertexbuffer ") |
---|
2471 | f.write("positions=\"true\" ") |
---|
2472 | f.write("normals=\"true\"") |
---|
2473 | if self.hasUVCoordinates(): |
---|
2474 | f.write(" texture_coord_dimensions_0=\"2\" texture_coords=\"1\"") |
---|
2475 | if self.hasVertexColours(): |
---|
2476 | f.write(" colours_diffuse=\"true\"") |
---|
2477 | f.write(">\n") |
---|
2478 | for v in submesh.vertices: |
---|
2479 | f.write(XMLVertexStringView(v.xmlVertex).toString(5)) |
---|
2480 | f.write(tab(4)+"</vertexbuffer>\n") |
---|
2481 | f.write(tab(3)+"</geometry>\n") |
---|
2482 | |
---|
2483 | if self.skeleton: |
---|
2484 | f.write(tab(3)+"<boneassignments>\n") |
---|
2485 | for v in submesh.vertices: |
---|
2486 | for influence in v.influences: |
---|
2487 | f.write(tab(4)+"<vertexboneassignment ") |
---|
2488 | f.write("vertexindex=\"%d\" boneindex=\"%d\" weight=\"%.6f\"/>\n" |
---|
2489 | % (v.id, influence.bone.id, influence.weight)) |
---|
2490 | f.write(tab(3)+"</boneassignments>\n") |
---|
2491 | f.write(tab(2)+"</submesh>\n") |
---|
2492 | f.write(tab(1)+"</submeshes>\n") |
---|
2493 | |
---|
2494 | if self.skeleton: |
---|
2495 | f.write(tab(1)+"<skeletonlink name=\"%s.skeleton\"/>\n" % self.skeleton.name) |
---|
2496 | |
---|
2497 | f.write(tab(0)+"</mesh>\n") |
---|
2498 | f.close() |
---|
2499 | convertXMLFile(os.path.join(pathString.val, file)) |
---|
2500 | return |
---|
2501 | # private |
---|
2502 | def _parseMesh(self, mesh): |
---|
2503 | if mesh: |
---|
2504 | self.name = mesh.name |
---|
2505 | if mesh.vertexColors: |
---|
2506 | self.vertexColors = 1 |
---|
2507 | if (mesh.faceUV or mesh.vertexUV): |
---|
2508 | self.uvCoordinates = 1 |
---|
2509 | return |
---|
2510 | |
---|
2511 | class SubMesh: |
---|
2512 | def __init__(self, material): |
---|
2513 | self.material = material |
---|
2514 | self.vertices = [] |
---|
2515 | self.faces = [] |
---|
2516 | |
---|
2517 | def rename_vertices(self, new_vertices): |
---|
2518 | # Rename (change ID) of all vertices, such as self.vertices == new_vertices. |
---|
2519 | for i in range(len(new_vertices)): new_vertices[i].id = i |
---|
2520 | self.vertices = new_vertices |
---|
2521 | |
---|
2522 | class XMLVertex: |
---|
2523 | """Vertex in Ogre. |
---|
2524 | |
---|
2525 | @cvar threshold Floating point precicsion. |
---|
2526 | """ |
---|
2527 | threshold = 1e-6 |
---|
2528 | def __init__(self, position=None, normal=None, colourDiffuse=None, colourSpecular=None, texcoordList=None): |
---|
2529 | """Constructor. |
---|
2530 | |
---|
2531 | @param position list with x, y and z coordinate of the position |
---|
2532 | @param normal list with x, y and z coordinate of the normal vector |
---|
2533 | @param colourDiffuse list with RGBA floats |
---|
2534 | @param colourSpecular list with RGBA floats |
---|
2535 | @param texcoordList list of list with u and v texture coordinates. |
---|
2536 | """ |
---|
2537 | self.elementDict = {} |
---|
2538 | if position: |
---|
2539 | self.elementDict['position'] = position |
---|
2540 | if normal: |
---|
2541 | self.elementDict['normal'] = normal |
---|
2542 | if colourDiffuse: |
---|
2543 | self.elementDict['colourDiffuse'] = colourDiffuse |
---|
2544 | if colourSpecular: |
---|
2545 | self.elementDict['colourSpecular'] = colourSpecular |
---|
2546 | if texcoordList: |
---|
2547 | self.elementDict['texcoordList'] = texcoordList |
---|
2548 | return |
---|
2549 | def hasPosition(self): |
---|
2550 | return self.elementDict.has_key('position') |
---|
2551 | def hasNormal(self): |
---|
2552 | return self.elementDict.has_key('normal') |
---|
2553 | def hasVertexColour(self): |
---|
2554 | return self.elementDict.has_key('colourDiffuse') or self.elementDict.has_key('colourSpecular') |
---|
2555 | def hasDiffuseColour(self): |
---|
2556 | return self.elementDict.has_key('colourDiffuse') |
---|
2557 | def hasSpecularColour(self): |
---|
2558 | return self.elementDict.has_key('colourSpecular') |
---|
2559 | def nTextureCoordinates(self): |
---|
2560 | nTextureCoordinates = 0 |
---|
2561 | if self.elementDict.has_key('texcoordList'): |
---|
2562 | nTextureCoordinates = len(self.elementDict['texcoordList']) |
---|
2563 | return nTextureCoordinates |
---|
2564 | def __getitem__(self, key): |
---|
2565 | return self.elementDict[key] |
---|
2566 | def __ne__(self, other): |
---|
2567 | """Tests if it differs from another Vertex. |
---|
2568 | |
---|
2569 | @param other the XMLVertex to compare with |
---|
2570 | @return <code>true</code> if they differ, else <code>false</code> |
---|
2571 | """ |
---|
2572 | return not self.__eq__(other) |
---|
2573 | def __eq__(self, other): |
---|
2574 | """Tests if it is equal to another Vertex. |
---|
2575 | |
---|
2576 | @param other the XMLVertex to compare with |
---|
2577 | @return <code>true</code> if they are equal, else <code>false</code> |
---|
2578 | """ |
---|
2579 | areEqual = 0 |
---|
2580 | if (self.getElements() == other.getElements()): |
---|
2581 | compared = 0 |
---|
2582 | itemIterator = self.elementDict.iteritems() |
---|
2583 | while (not compared): |
---|
2584 | try: |
---|
2585 | (element, value) = itemIterator.next() |
---|
2586 | if element == 'position' or element == 'normal': |
---|
2587 | otherValue = other[element] |
---|
2588 | if ((math.fabs(value[0] - otherValue[0]) > XMLVertex.threshold) or |
---|
2589 | (math.fabs(value[1] - otherValue[1]) > XMLVertex.threshold) or |
---|
2590 | (math.fabs(value[2] - otherValue[2]) > XMLVertex.threshold)): |
---|
2591 | # test fails |
---|
2592 | compared = 1 |
---|
2593 | elif element == 'colourDiffuse' or element == 'colourSpecular': |
---|
2594 | otherValue = other[element] |
---|
2595 | if ((math.fabs(value[0] - otherValue[0]) > XMLVertex.threshold) or |
---|
2596 | (math.fabs(value[1] - otherValue[1]) > XMLVertex.threshold) or |
---|
2597 | (math.fabs(value[2] - otherValue[2]) > XMLVertex.threshold) or |
---|
2598 | (math.fabs(value[3] - otherValue[3]) > XMLVertex.threshold)): |
---|
2599 | # test fails |
---|
2600 | compared = 1 |
---|
2601 | elif element == 'texcoordList': |
---|
2602 | otherValue = other[element] |
---|
2603 | if len(value) == len(otherValue): |
---|
2604 | for uv, otherUV in zip(value, otherValue): |
---|
2605 | if ((math.fabs(uv[0] - otherUV[0]) > XMLVertex.threshold) or |
---|
2606 | (math.fabs(uv[1] - otherUV[1]) > XMLVertex.threshold)): |
---|
2607 | # test fails |
---|
2608 | compared = 1 |
---|
2609 | else: |
---|
2610 | # test fails |
---|
2611 | compared = 1 |
---|
2612 | else: |
---|
2613 | # test fails, unknown element |
---|
2614 | compared = 1 |
---|
2615 | except StopIteration: |
---|
2616 | # objects are equal |
---|
2617 | areEqual = 1 |
---|
2618 | compared = 1 |
---|
2619 | return areEqual |
---|
2620 | # getter and setter |
---|
2621 | def getElements(self): |
---|
2622 | return self.elementDict.keys() |
---|
2623 | def getPosition(self): |
---|
2624 | return self.elementDict['position'] |
---|
2625 | def getNormal(self): |
---|
2626 | return self.elementDict['normal'] |
---|
2627 | def getColourDiffuse(self): |
---|
2628 | return self.elementDict['colourDiffuse'] |
---|
2629 | def getColourSpecular(self): |
---|
2630 | return self.elementDict['colourSpecular'] |
---|
2631 | def getTextureCoordinatesList(self): |
---|
2632 | return self.elementDict['texcoordList'] |
---|
2633 | def setPosition(self, position): |
---|
2634 | if position: |
---|
2635 | self.elementDict['position'] = position |
---|
2636 | else: |
---|
2637 | del self.elementDict['position'] |
---|
2638 | return |
---|
2639 | def setNormal(self, normal): |
---|
2640 | if normal: |
---|
2641 | self.elementDict['normal'] = normal |
---|
2642 | else: |
---|
2643 | del self.elementDict['normal'] |
---|
2644 | return |
---|
2645 | def setColourDiffuse(self, colourDiffuse): |
---|
2646 | if colourDiffuse: |
---|
2647 | self.elementDict['colourDiffuse'] = colourDiffuse |
---|
2648 | else: |
---|
2649 | del self.colourDiffuse |
---|
2650 | return |
---|
2651 | def setColourSpecular(self, colourSpecular): |
---|
2652 | if colourSpecular: |
---|
2653 | self.elementDict['colourSpecular'] = colourSpecular |
---|
2654 | else: |
---|
2655 | del self.elementDict['colourSpecular'] |
---|
2656 | return |
---|
2657 | # special getter and setter |
---|
2658 | def appendTextureCoordinates(self, uvList): |
---|
2659 | """Appends new texture coordinate. |
---|
2660 | |
---|
2661 | @param uvList list with u and v coordinate |
---|
2662 | @return list index |
---|
2663 | """ |
---|
2664 | if self.elementDict.has_key('texcoordList'): |
---|
2665 | self.elementDict['texcoordList'].append(uvList) |
---|
2666 | else: |
---|
2667 | self.elementDict['texcoordList'] = [uvList] |
---|
2668 | return (len(self.elementDict['texcoordList']) -1 ) |
---|
2669 | def setTextureCorrdinates(self, index, uvList): |
---|
2670 | self.elementDict['texcoordList'][index] = uvList |
---|
2671 | return |
---|
2672 | def getTextureCoordinates(self, index=None): |
---|
2673 | return self.elementDict['texcoordList'][index] |
---|
2674 | def deleteTextureCoordinates(self, index=None): |
---|
2675 | """Delete texture coordinates. |
---|
2676 | |
---|
2677 | Delete a pair or all texture coordinates of the vertex. |
---|
2678 | |
---|
2679 | @param index the index of the texture coordinates in the vertex's list of |
---|
2680 | texture coordinates. If <code>None</code> the complete list |
---|
2681 | is deleted. |
---|
2682 | """ |
---|
2683 | if (index != None): |
---|
2684 | del self.elementDict['texcoordList'][index] |
---|
2685 | else: |
---|
2686 | del self.elementDict['texcoordList'] |
---|
2687 | return |
---|
2688 | |
---|
2689 | class XMLVertexStringView: |
---|
2690 | """Viewer class for textual representation of a XMLVertex. |
---|
2691 | |
---|
2692 | @see XMLVertex |
---|
2693 | """ |
---|
2694 | def __init__(self, xmlVertex): |
---|
2695 | if isinstance(xmlVertex, XMLVertex): |
---|
2696 | self.xmlVertex = xmlVertex |
---|
2697 | return |
---|
2698 | def __str__(self): |
---|
2699 | return self.toString() |
---|
2700 | def toString(self, indent=0, keyList=None): |
---|
2701 | """Returns textual representations of its XMLVertex. |
---|
2702 | |
---|
2703 | @param indent Indentation level of the string. |
---|
2704 | @param keyList List of keys of elements to represent in the string. |
---|
2705 | @return string String representation of the XMLVertex. |
---|
2706 | @see XMLVertex#__init__ |
---|
2707 | """ |
---|
2708 | if not keyList: |
---|
2709 | keyList = self.xmlVertex.getElements() |
---|
2710 | else: |
---|
2711 | # remove unavailable elements |
---|
2712 | keyList = [key for key in keyList if key in self.xmlVertex.getElements()] |
---|
2713 | s = self._indent(indent) + "<vertex>\n" |
---|
2714 | if keyList.count('position'): |
---|
2715 | position = self.xmlVertex.getPosition() |
---|
2716 | s += self._indent(indent+1)+"<position x=\"%.6f\" y=\"%.6f\" z=\"%.6f\"/>\n" % tuple(position) |
---|
2717 | if keyList.count('normal'): |
---|
2718 | normal = self.xmlVertex.getNormal() |
---|
2719 | s += self._indent(indent+1)+"<normal x=\"%.6f\" y=\"%.6f\" z=\"%.6f\"/>\n" % tuple(normal) |
---|
2720 | if keyList.count('colourDiffuse'): |
---|
2721 | colourDiffuse = self.xmlVertex.getColourDiffuse() |
---|
2722 | if OGRE_OPENGL_VERTEXCOLOUR: |
---|
2723 | (r, g, b, a) = tuple(colourDiffuse) |
---|
2724 | s += self._indent(indent+1)+"<colour_diffuse value=\"%.6f %.6f %.6f %.6f\"/>\n" % (b, g, r, a) |
---|
2725 | else: |
---|
2726 | s += self._indent(indent+1)+"<colour_diffuse value=\"%.6f %.6f %.6f %.6f\"/>\n" % tuple(colourDiffuse) |
---|
2727 | if keyList.count('colourSpecular'): |
---|
2728 | colourSpecular = self.xmlVertex.getColourSpecular() |
---|
2729 | if OGRE_OPENGL_VERTEXCOLOUR: |
---|
2730 | (r, g, b, a) = tuple(colourSpecular) |
---|
2731 | s += self._indent(indent+1)+"<colour_specular value=\"%.6f %.6f %.6f %.6f\"/>\n" % (b, g, r, a) |
---|
2732 | else: |
---|
2733 | s += self._indent(indent+1)+"<colour_specular value=\"%.6f %.6f %.6f %.6f\"/>\n" % tuple(colourSpecular) |
---|
2734 | if keyList.count('texcoordList'): |
---|
2735 | for uv in self.xmlVertex.getTextureCoordinatesList(): |
---|
2736 | s+=self._indent(indent+1)+"<texcoord u=\"%.6f\" v=\"%.6f\"/>\n" % tuple(uv) |
---|
2737 | s += self._indent(indent) + "</vertex>\n" |
---|
2738 | return s |
---|
2739 | def _indent(self, indent): |
---|
2740 | return " "*indent |
---|
2741 | |
---|
2742 | class Vertex: |
---|
2743 | def __init__(self, submesh, xmlVertex): |
---|
2744 | self.xmlVertex = xmlVertex |
---|
2745 | self.influences = [] |
---|
2746 | |
---|
2747 | self.cloned_from = None |
---|
2748 | self.clones = [] |
---|
2749 | self.submesh = submesh |
---|
2750 | self.id = len(submesh.vertices) |
---|
2751 | submesh.vertices.append(self) |
---|
2752 | |
---|
2753 | class Influence: |
---|
2754 | def __init__(self, bone, weight): |
---|
2755 | self.bone = bone |
---|
2756 | self.weight = weight |
---|
2757 | |
---|
2758 | class Face: |
---|
2759 | def __init__(self, submesh, vertex1, vertex2, vertex3): |
---|
2760 | self.vertex1 = vertex1 |
---|
2761 | self.vertex2 = vertex2 |
---|
2762 | self.vertex3 = vertex3 |
---|
2763 | self.submesh = submesh |
---|
2764 | submesh.faces.append(self) |
---|
2765 | |
---|
2766 | class Skeleton: |
---|
2767 | def __init__(self, name): |
---|
2768 | self.name = name |
---|
2769 | self.bones = [] |
---|
2770 | self.bonesDict = {} |
---|
2771 | self.animationsDict = {} |
---|
2772 | |
---|
2773 | class Bone: |
---|
2774 | def __init__(self, skeleton, parent, name, loc, rotQuat, conversionMatrix): |
---|
2775 | self.parent = parent |
---|
2776 | self.name = name |
---|
2777 | self.loc = loc # offset from parent bone |
---|
2778 | self.rotQuat = rotQuat # axis as quaternion |
---|
2779 | self.children = [] |
---|
2780 | self.conversionMatrix = conversionMatrix # converts Blender's local bone coordinates into Ogre's local bone coordinates |
---|
2781 | |
---|
2782 | if parent: |
---|
2783 | parent.children.append(self) |
---|
2784 | |
---|
2785 | self.id = len(skeleton.bones) |
---|
2786 | skeleton.bones.append(self) |
---|
2787 | skeleton.bonesDict[name] =self |
---|
2788 | |
---|
2789 | class Animation: |
---|
2790 | def __init__(self, name, duration = 0.0): |
---|
2791 | self.name = name |
---|
2792 | self.duration = duration |
---|
2793 | self.tracksDict = {} # Map bone names to tracks |
---|
2794 | |
---|
2795 | class Track: |
---|
2796 | def __init__(self, animation, bone): |
---|
2797 | self.bone = bone |
---|
2798 | self.keyframes = [] |
---|
2799 | |
---|
2800 | self.animation = animation |
---|
2801 | animation.tracksDict[bone.name] = self |
---|
2802 | |
---|
2803 | class KeyFrame: |
---|
2804 | def __init__(self, track, time, loc, rotQuat, scale): |
---|
2805 | self.time = time |
---|
2806 | self.loc = loc |
---|
2807 | self.rotQuat = rotQuat |
---|
2808 | self.scale = scale |
---|
2809 | |
---|
2810 | self.track = track |
---|
2811 | track.keyframes.append(self) |
---|
2812 | |
---|
2813 | ####################################################################################### |
---|
2814 | ## Armature stuff |
---|
2815 | |
---|
2816 | def blender_bone2matrix(head, tail, roll): |
---|
2817 | # Convert bone rest state (defined by bone.head, bone.tail and bone.roll) |
---|
2818 | # to a matrix (the more standard notation). |
---|
2819 | # Taken from blenkernel/intern/armature.c in Blender source. |
---|
2820 | # See also DNA_armature_types.h:47. |
---|
2821 | |
---|
2822 | nor = vector_normalize([ tail[0] - head[0], |
---|
2823 | tail[1] - head[1], |
---|
2824 | tail[2] - head[2] ]) |
---|
2825 | |
---|
2826 | # Find Axis & Amount for bone matrix |
---|
2827 | target = [0.0, 1.0, 0.0] |
---|
2828 | axis = vector_crossproduct(target, nor) |
---|
2829 | |
---|
2830 | # is nor a multiple of target? |
---|
2831 | if vector_dotproduct(axis, axis) > 0.0000000000001: |
---|
2832 | axis = vector_normalize(axis) |
---|
2833 | theta = math.acos(vector_dotproduct(target, nor)) |
---|
2834 | bMatrix = matrix_rotate(axis, theta) |
---|
2835 | |
---|
2836 | else: |
---|
2837 | # point same direction, or opposite? |
---|
2838 | if vector_dotproduct(target, nor) > 0.0: |
---|
2839 | updown = 1.0 |
---|
2840 | else: |
---|
2841 | updown = -1.0 |
---|
2842 | |
---|
2843 | # Quoted from Blender source : "I think this should work ..." |
---|
2844 | bMatrix = [ [updown, 0.0, 0.0, 0.0], |
---|
2845 | [ 0.0, updown, 0.0, 0.0], |
---|
2846 | [ 0.0, 0.0, 1.0, 0.0], |
---|
2847 | [ 0.0, 0.0, 0.0, 1.0] ] |
---|
2848 | |
---|
2849 | rMatrix = matrix_rotate(nor, roll) |
---|
2850 | return matrix_multiply(rMatrix, bMatrix) |
---|
2851 | |
---|
2852 | ####################################################################################### |
---|
2853 | ## Mesh stuff |
---|
2854 | def process_vert_influences(mesh, skeleton): |
---|
2855 | global verticesDict |
---|
2856 | global exportLogger |
---|
2857 | |
---|
2858 | if skeleton: |
---|
2859 | # build bone influence dictionary |
---|
2860 | |
---|
2861 | # get the bone names |
---|
2862 | # build influences tuples of bone name and influence |
---|
2863 | boneWeightDict = {} |
---|
2864 | for bone in skeleton.bones: |
---|
2865 | boneweights = [] |
---|
2866 | try: |
---|
2867 | #boneweights = mesh.getVertsFromGroup(bone.name, 1, [face.v[i].index]) |
---|
2868 | # get all weights for a bone. getting weights for a specific vertex trashes |
---|
2869 | # blender after a few hundred calls |
---|
2870 | #print bone.name |
---|
2871 | boneweights = mesh.getVertsFromGroup(bone.name, 1) |
---|
2872 | boneWeightDict[bone.name] = dict(boneweights) |
---|
2873 | except: |
---|
2874 | pass |
---|
2875 | |
---|
2876 | for vert_index, vertex in verticesDict.iteritems(): |
---|
2877 | influences = [] |
---|
2878 | for boneName, vertWeightDict in boneWeightDict.iteritems(): |
---|
2879 | if vertWeightDict.has_key(vert_index): |
---|
2880 | influences += [(boneName, vertWeightDict[vert_index])] |
---|
2881 | if not influences: |
---|
2882 | exportLogger.logError("Vertex in skinned mesh without influence, check your mesh!") |
---|
2883 | # limit influences to 4 bones per vertex |
---|
2884 | def cmpfunc(x, y): |
---|
2885 | xname, xweight = x |
---|
2886 | yname, yweight = y |
---|
2887 | return cmp(yweight, xweight) |
---|
2888 | # only want the weights with the most influence |
---|
2889 | influences.sort(cmpfunc) |
---|
2890 | # limits weights to maximum of 4 |
---|
2891 | influences = influences[0:4] |
---|
2892 | # and make sure the sum is 1.0 |
---|
2893 | total = 0.0 |
---|
2894 | for name, weight in influences: |
---|
2895 | total += weight |
---|
2896 | for name, weight in influences: |
---|
2897 | vertex.influences.append(Influence(skeleton.bonesDict[name], weight/total)) |
---|
2898 | |
---|
2899 | # remap vertices for faces |
---|
2900 | def process_face(face, submesh, mesh, matrix, skeleton=None): |
---|
2901 | """Process a face of a mesh. |
---|
2902 | |
---|
2903 | @param face Blender.NMesh.NMFace. |
---|
2904 | @param submesh SubMesh the face belongs to. |
---|
2905 | @param mesh Blender.Mesh.Mesh the face belongs to. |
---|
2906 | @param matrix Export translation. |
---|
2907 | @param skeleton Skeleton of the mesh (if any). |
---|
2908 | """ |
---|
2909 | global verticesDict |
---|
2910 | global exportLogger |
---|
2911 | # threshold to compare floats |
---|
2912 | threshold = 1e-6 |
---|
2913 | if len(face.v) in [ 3, 4 ]: |
---|
2914 | if not face.smooth: |
---|
2915 | # calculate the face normal. |
---|
2916 | p1 = face.v[0].co |
---|
2917 | p2 = face.v[1].co |
---|
2918 | p3 = face.v[2].co |
---|
2919 | faceNormal = vector_crossproduct( |
---|
2920 | [p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]], |
---|
2921 | [p1[0] - p2[0], p1[1] - p2[1], p1[2] - p2[2]], |
---|
2922 | ) |
---|
2923 | faceNormal = normal_by_matrix(faceNormal, matrix) |
---|
2924 | |
---|
2925 | face_vertices = [ 0, 0, 0, 0] |
---|
2926 | for i in range(len(face.v)): |
---|
2927 | # position |
---|
2928 | position = point_by_matrix (face.v[i].co, matrix) |
---|
2929 | # Blender separates normal, uv coordinates and colour from vertice coordinates. |
---|
2930 | # normal |
---|
2931 | if face.smooth: |
---|
2932 | normal = normal_by_matrix(face.v[i].no, matrix) |
---|
2933 | else: |
---|
2934 | normal = faceNormal |
---|
2935 | xmlVertex = XMLVertex(position, normal) |
---|
2936 | # uv coordinates |
---|
2937 | if (mesh.vertexUV or mesh.faceUV): |
---|
2938 | uv = [0,0] |
---|
2939 | if mesh.vertexUV: |
---|
2940 | # mesh has sticky/per vertex uv coordinates |
---|
2941 | uv[0] = face.v[i].uvco[0] |
---|
2942 | # origin is now in the top-left (Ogre v0.13.0) |
---|
2943 | uv[1] = 1 - face.v[i].uvco[1] |
---|
2944 | else: |
---|
2945 | # mesh has per face vertex uv coordinates |
---|
2946 | uv[0] = face.uv[i][0] |
---|
2947 | # origin is now in the top-left (Ogre v0.13.0) |
---|
2948 | uv[1] = 1 - face.uv[i][1] |
---|
2949 | xmlVertex.appendTextureCoordinates(uv) |
---|
2950 | # vertex colour |
---|
2951 | if (mesh.vertexColors): |
---|
2952 | colour = face.col[i] |
---|
2953 | xmlVertex.setColourDiffuse([colour.r/255.0, colour.g/255.0, colour.b/255.0, colour.a/255.0]) |
---|
2954 | # check if an equal xmlVertex already exist |
---|
2955 | # get vertex |
---|
2956 | if verticesDict.has_key(face.v[i].index): |
---|
2957 | # vertex already exists |
---|
2958 | vertex = verticesDict[face.v[i].index] |
---|
2959 | # compare xmlVertex to vertex and its clones |
---|
2960 | if (vertex.xmlVertex != xmlVertex): |
---|
2961 | vertexFound = 0 |
---|
2962 | iClone = 0 |
---|
2963 | while ((iClone < len(vertex.clones)) and (not vertexFound)): |
---|
2964 | clone = vertex.clones[iClone] |
---|
2965 | if (clone.xmlVertex == xmlVertex): |
---|
2966 | vertexFound = 1 |
---|
2967 | vertex = clone |
---|
2968 | iClone += 1 |
---|
2969 | if not vertexFound: |
---|
2970 | # create new clone |
---|
2971 | clone = Vertex(submesh, xmlVertex) |
---|
2972 | clone.cloned_from = vertex |
---|
2973 | clone.influences = vertex.influences |
---|
2974 | vertex.clones.append(clone) |
---|
2975 | # write back to dictionary |
---|
2976 | verticesDict[face.v[i].index] = vertex |
---|
2977 | vertex = clone |
---|
2978 | else: |
---|
2979 | # vertex does not exist yet |
---|
2980 | # create vertex |
---|
2981 | vertex = Vertex(submesh, xmlVertex) |
---|
2982 | verticesDict[face.v[i].index] = vertex |
---|
2983 | # postcondition: vertex is current vertex |
---|
2984 | face_vertices[i] = vertex |
---|
2985 | |
---|
2986 | if len(face.v) == 3: |
---|
2987 | Face(submesh, face_vertices[0], face_vertices[1], face_vertices[2]) |
---|
2988 | elif len(face.v) == 4: |
---|
2989 | # Split faces with 4 vertices on the shortest edge |
---|
2990 | differenceVectorList = [[0,0,0],[0,0,0]] |
---|
2991 | for indexOffset in range(2): |
---|
2992 | for coordinate in range(3): |
---|
2993 | differenceVectorList[indexOffset][coordinate] = face_vertices[indexOffset].xmlVertex.getPosition()[coordinate] \ |
---|
2994 | - face_vertices[indexOffset+2].xmlVertex.getPosition()[coordinate] |
---|
2995 | if Mathutils.Vector(differenceVectorList[0]).length < Mathutils.Vector(differenceVectorList[1]).length: |
---|
2996 | Face(submesh, face_vertices[0], face_vertices[1], face_vertices[2]) |
---|
2997 | Face(submesh, face_vertices[2], face_vertices[3], face_vertices[0]) |
---|
2998 | else: |
---|
2999 | Face(submesh, face_vertices[0], face_vertices[1], face_vertices[3]) |
---|
3000 | Face(submesh, face_vertices[3], face_vertices[1], face_vertices[2]) |
---|
3001 | else: |
---|
3002 | exportLogger.logWarning("Ignored face with %d edges." % len(face.v)) |
---|
3003 | return |
---|
3004 | |
---|
3005 | def export_mesh(object, exportOptions): |
---|
3006 | global gameEngineMaterialsToggle |
---|
3007 | global armatureToggle |
---|
3008 | global verticesDict |
---|
3009 | global skeletonsDict |
---|
3010 | global materialsDict |
---|
3011 | global exportLogger |
---|
3012 | |
---|
3013 | if (object.getType() == "Mesh"): |
---|
3014 | # is this mesh attached to an armature? |
---|
3015 | skeleton = None |
---|
3016 | if armatureToggle.val: |
---|
3017 | parent = object.getParent() |
---|
3018 | #if parent and parent.getType() == "Armature" and (not skeletonsDict.has_key(parent.getName())): |
---|
3019 | if (parent and (parent.getType() == "Armature")): |
---|
3020 | if armatureActionActuatorListViewDict.has_key(parent.getName()): |
---|
3021 | actionActuatorList = armatureActionActuatorListViewDict[parent.getName()].armatureActionActuatorList |
---|
3022 | armatureExporter = ArmatureExporter(MeshExporter(object), parent) |
---|
3023 | armatureExporter.export(actionActuatorList, exportOptions, exportLogger) |
---|
3024 | skeleton = armatureExporter.skeleton |
---|
3025 | |
---|
3026 | #Mesh of the object |
---|
3027 | #for 2.4 us Mesh instead of NMesh |
---|
3028 | data = object.getData(False, True) |
---|
3029 | matrix = None |
---|
3030 | if worldCoordinatesToggle.val: |
---|
3031 | matrix = object.getMatrix("worldspace") |
---|
3032 | else: |
---|
3033 | matrix = Mathutils.Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) |
---|
3034 | matrix = matrix*BASE_MATRIX |
---|
3035 | # materials of the object |
---|
3036 | # note: ogre assigns different textures and different facemodes |
---|
3037 | # to different materials |
---|
3038 | objectMaterialDict = {} |
---|
3039 | # faces assign to objectMaterial keys |
---|
3040 | objectMaterialFacesDict = {} |
---|
3041 | |
---|
3042 | # note: these are blender materials. Even if nMaterials = 0 |
---|
3043 | # the face can still have a texture (see above) |
---|
3044 | # meshMaterialList = data.getMaterials(1) |
---|
3045 | meshMaterialList = data.materials |
---|
3046 | # note: material slots may be empty, resp. meshMaterialList entries may be None |
---|
3047 | nMaterials = len(meshMaterialList) |
---|
3048 | |
---|
3049 | # warn if mesh is a subdivision surface |
---|
3050 | #if (data.mode & Blender.Mesh.Modes['SUBSURF']): |
---|
3051 | #exportLogger.logWarning("Mesh \"%s\" is a subdivision surface. Convert it to mesh, if you want to export the subdivision result." % data.name) |
---|
3052 | # create ogre materials |
---|
3053 | for face in data.faces: |
---|
3054 | faceMaterial = None |
---|
3055 | # choose "rendering materials" or "game engine materials" |
---|
3056 | if not(gameEngineMaterialsToggle.val): |
---|
3057 | # rendering materials |
---|
3058 | try: |
---|
3059 | blenderMaterial = meshMaterialList[face.mat] |
---|
3060 | except: |
---|
3061 | exportLogger.logError("Material assignment missing for object \"%s\"!" % data.name) |
---|
3062 | blenderMaterial = None |
---|
3063 | if blenderMaterial: |
---|
3064 | # non-empty material slot |
---|
3065 | faceMaterial = RenderingMaterial(data, face) |
---|
3066 | else: |
---|
3067 | faceMaterial = DefaultMaterial('default') |
---|
3068 | else: |
---|
3069 | # game engine materials |
---|
3070 | if face.image: |
---|
3071 | if (not(face.mode & Blender.Mesh.FaceModes['INVISIBLE']) |
---|
3072 | and not(face.flag & Blender.Mesh.FaceFlags['HIDE'])): |
---|
3073 | faceMaterial = GameEngineMaterial(data, face) |
---|
3074 | else: |
---|
3075 | # check if a Blender material is assigned |
---|
3076 | try: |
---|
3077 | blenderMaterial = meshMaterialList[face.mat] |
---|
3078 | except: |
---|
3079 | blenderMaterial = None |
---|
3080 | if blenderMaterial: |
---|
3081 | faceMaterial = GameEngineMaterial(data, face) |
---|
3082 | else: |
---|
3083 | exportLogger.logWarning("Face of object \"%s\" without material assignment! Using default material." % data.name) |
---|
3084 | faceMaterial = DefaultMaterial('default') |
---|
3085 | if faceMaterial: |
---|
3086 | # insert into Dicts |
---|
3087 | materialName = faceMaterial.getName() |
---|
3088 | material = objectMaterialDict.get(materialName) |
---|
3089 | if material: |
---|
3090 | # append faces |
---|
3091 | faceList = objectMaterialFacesDict[materialName] |
---|
3092 | faceList.append(face) |
---|
3093 | objectMaterialFacesDict[materialName] = faceList |
---|
3094 | else: |
---|
3095 | # create new faces list |
---|
3096 | objectMaterialDict[materialName] = faceMaterial |
---|
3097 | objectMaterialFacesDict[materialName] = [face] |
---|
3098 | # process faces |
---|
3099 | submeshes = [] |
---|
3100 | for materialKey in objectMaterialDict.keys(): |
---|
3101 | submesh = SubMesh(objectMaterialDict[materialKey]) |
---|
3102 | verticesDict = {} |
---|
3103 | for face in objectMaterialFacesDict[materialKey]: |
---|
3104 | process_face(face, submesh, data, matrix, skeleton) |
---|
3105 | if len(submesh.faces): |
---|
3106 | # process verticesDict and add bone influences |
---|
3107 | process_vert_influences(data, skeleton) |
---|
3108 | submeshes.append(submesh) |
---|
3109 | # update global materialsDict |
---|
3110 | material = materialsDict.get(materialKey) |
---|
3111 | if not material: |
---|
3112 | materialsDict[materialKey] = objectMaterialDict[materialKey] |
---|
3113 | # write mesh |
---|
3114 | if len(submeshes) == 0: |
---|
3115 | # no submeshes |
---|
3116 | exportLogger.logWarning("Mesh %s has no visible faces!" % data.name) |
---|
3117 | else: |
---|
3118 | # write mesh |
---|
3119 | mesh = Mesh(submeshes, skeleton, data) |
---|
3120 | mesh.write() |
---|
3121 | return |
---|
3122 | |
---|
3123 | ####################################################################################### |
---|
3124 | ## file output |
---|
3125 | |
---|
3126 | def tab(tabsize): |
---|
3127 | return "\t" * tabsize |
---|
3128 | |
---|
3129 | def clamp(val): |
---|
3130 | if val < 0.0: |
---|
3131 | val = 0.0 |
---|
3132 | if val > 1.0: |
---|
3133 | val = 1.0 |
---|
3134 | return val |
---|
3135 | |
---|
3136 | def convertXMLFile(filename): |
---|
3137 | """Calls the OgreXMLConverter on a file. |
---|
3138 | |
---|
3139 | If the script variable <code>OGRE_XML_CONVERTER</code> is nonempty, the |
---|
3140 | OgreXMLConverter is called to convert the given file. |
---|
3141 | |
---|
3142 | @param filename filename of the XML file to convert. |
---|
3143 | """ |
---|
3144 | global exportLogger |
---|
3145 | if OGRE_XML_CONVERTER != '': |
---|
3146 | commandLine = OGRE_XML_CONVERTER + ' "' + filename + '"' |
---|
3147 | exportLogger.logInfo("Running OgreXMLConverter: " + commandLine) |
---|
3148 | xmlConverter = os.popen(commandLine, 'r') |
---|
3149 | if xmlConverter == None: |
---|
3150 | exportLogger.logError('Could not run OgreXMLConverter!') |
---|
3151 | else: |
---|
3152 | for line in xmlConverter: |
---|
3153 | exportLogger.logInfo("OgreXMLConverter: " + line) |
---|
3154 | xmlConverter.close() |
---|
3155 | return |
---|
3156 | |
---|
3157 | def write_materials(): |
---|
3158 | global ambientToggle, pathString, materialString, exportLogger |
---|
3159 | global materialsDict |
---|
3160 | file = materialString.val |
---|
3161 | exportLogger.logInfo("Materials \"%s\"" % file) |
---|
3162 | f = open(os.path.join(pathString.val, file), "w") |
---|
3163 | for material in materialsDict.values(): |
---|
3164 | material.write(f) |
---|
3165 | f.close() |
---|
3166 | return |
---|
3167 | |
---|
3168 | ####################################################################################### |
---|
3169 | ## main export |
---|
3170 | |
---|
3171 | def export(selectedObjectsList): |
---|
3172 | global pathString, scaleNumber, rotXNumber, rotYNumber, rotZNumber |
---|
3173 | global materialsDict |
---|
3174 | global skeletonsDict |
---|
3175 | global BASE_MATRIX |
---|
3176 | global exportLogger |
---|
3177 | |
---|
3178 | materialsDict = {} |
---|
3179 | skeletonsDict = {} |
---|
3180 | |
---|
3181 | # default: set matrix to 90 degree rotation around x-axis |
---|
3182 | # rotation order: x, y, z |
---|
3183 | # WARNING: Blender uses left multiplication! |
---|
3184 | rotationMatrix = Mathutils.RotationMatrix(rotXNumber.val,4,'x') |
---|
3185 | rotationMatrix *= Mathutils.RotationMatrix(rotYNumber.val,4,'y') |
---|
3186 | rotationMatrix *= Mathutils.RotationMatrix(rotZNumber.val,4,'z') |
---|
3187 | scaleMatrix = Mathutils.Matrix([scaleNumber.val,0,0],[0,scaleNumber.val,0],[0,0,scaleNumber.val]) |
---|
3188 | scaleMatrix.resize4x4() |
---|
3189 | BASE_MATRIX = rotationMatrix*scaleMatrix |
---|
3190 | |
---|
3191 | exportOptions = ExportOptions(rotXNumber.val, rotYNumber.val, rotZNumber.val, scaleNumber.val, |
---|
3192 | worldCoordinatesToggle.val, ambientToggle.val, pathString.val, materialString.val) |
---|
3193 | |
---|
3194 | if not os.path.exists(pathString.val): |
---|
3195 | exportLogger.logError("Invalid path: "+pathString.val) |
---|
3196 | else: |
---|
3197 | exportLogger.logInfo("Exporting selected objects into \"" + pathString.val + "\":") |
---|
3198 | n = 0 |
---|
3199 | for obj in selectedObjectsList: |
---|
3200 | if obj: |
---|
3201 | if obj.getType() == "Mesh": |
---|
3202 | exportLogger.logInfo("Exporting object \"%s\":" % obj.getName()) |
---|
3203 | export_mesh(obj, exportOptions) |
---|
3204 | n = 1 |
---|
3205 | elif obj.getType() == "Armature": |
---|
3206 | exportLogger.logInfo("Exporting object \"%s\":" % obj.getName()) |
---|
3207 | actionActuatorList = armatureActionActuatorListViewDict[obj.getName()].armatureActionActuatorList |
---|
3208 | armatureMeshExporter = ArmatureMeshExporter(obj) |
---|
3209 | armatureMeshExporter.export(materialsDict, actionActuatorList, exportOptions, exportLogger) |
---|
3210 | if n == 0: |
---|
3211 | exportLogger.logWarning("No mesh objects selected!") |
---|
3212 | if len(materialsDict) == 0: |
---|
3213 | exportLogger.logWarning("No materials or textures defined!") |
---|
3214 | else: |
---|
3215 | write_materials() |
---|
3216 | |
---|
3217 | exportLogger.logInfo("Finished.") |
---|
3218 | return exportLogger.getStatus() |
---|
3219 | |
---|
3220 | ####################################################################################### |
---|
3221 | ## GUI |
---|
3222 | |
---|
3223 | ###### |
---|
3224 | # global variables |
---|
3225 | ###### |
---|
3226 | # see above |
---|
3227 | |
---|
3228 | ###### |
---|
3229 | # methods |
---|
3230 | ###### |
---|
3231 | def saveSettings(): |
---|
3232 | """Save all exporter settings of selected and unselected objects into a blender text object. |
---|
3233 | |
---|
3234 | Settings are saved to the text 'ogreexport.cfg' inside the current .blend file. Settings |
---|
3235 | belonging to removed objects in the .blend file will not be saved. |
---|
3236 | |
---|
3237 | @return <code>true</code> on success, else <code>false</code> |
---|
3238 | """ |
---|
3239 | global gameEngineMaterialsToggle |
---|
3240 | global armatureToggle |
---|
3241 | global worldCoordinatesToggle |
---|
3242 | global ambientToggle |
---|
3243 | global pathString |
---|
3244 | global materialString |
---|
3245 | global scaleNumber |
---|
3246 | global rotXNumber, rotYNumber, rotZNumber |
---|
3247 | global fpsNumber |
---|
3248 | global selectedObjectsList |
---|
3249 | global armatureDict |
---|
3250 | global armatureActionActuatorListViewDict |
---|
3251 | global armatureAnimationDictListDict |
---|
3252 | settingsDict = {} |
---|
3253 | success = 0 |
---|
3254 | # save general settings |
---|
3255 | settingsDict['gameEngineMaterialsToggle'] = gameEngineMaterialsToggle.val |
---|
3256 | settingsDict['armatureToggle'] = armatureToggle.val |
---|
3257 | settingsDict['worldCoordinatesToggle'] = worldCoordinatesToggle.val |
---|
3258 | settingsDict['ambientToggle'] = ambientToggle.val |
---|
3259 | settingsDict['pathString'] = pathString.val |
---|
3260 | settingsDict['materialString'] = materialString.val |
---|
3261 | settingsDict['scaleNumber'] = scaleNumber.val |
---|
3262 | settingsDict['rotXNumber'] = rotXNumber.val |
---|
3263 | settingsDict['rotYNumber'] = rotYNumber.val |
---|
3264 | settingsDict['rotZNumber'] = rotZNumber.val |
---|
3265 | if (Blender.Get("version") < 233): |
---|
3266 | settingsDict['fpsNumber'] = fpsNumber.val |
---|
3267 | else: |
---|
3268 | # get blender's "scene->format->frames per second" setting |
---|
3269 | settingsDict['fpsNumber'] = Blender.Scene.GetCurrent().getRenderingContext().framesPerSec() |
---|
3270 | # save object specific settings |
---|
3271 | # check if armature exists (I think this is cleaner than catching NameError exceptions.) |
---|
3272 | # create list of valid armature names |
---|
3273 | armatureNameList = [] |
---|
3274 | for object in Blender.Object.Get(): |
---|
3275 | if (object.getType() == "Armature"): |
---|
3276 | armatureNameList.append(object.getName()) |
---|
3277 | for armatureName in armatureAnimationDictListDict.keys(): |
---|
3278 | if not(armatureName in armatureNameList): |
---|
3279 | # remove obsolete settings |
---|
3280 | del armatureAnimationDictListDict[armatureName] |
---|
3281 | # update settings |
---|
3282 | for armatureName in armatureActionActuatorListViewDict.keys(): |
---|
3283 | armatureAnimationDictListDict[armatureName] = armatureActionActuatorListViewDict[armatureName].getArmatureAnimationDictList() |
---|
3284 | settingsDict['armatureAnimationDictListDict'] = armatureAnimationDictListDict |
---|
3285 | |
---|
3286 | configTextName = 'ogreexport.cfg' |
---|
3287 | # remove old configuration text |
---|
3288 | if configTextName in [text.getName() for text in Blender.Text.Get()]: |
---|
3289 | oldConfigText = Blender.Text.Get(configTextName) |
---|
3290 | oldConfigText.setName('ogreexport.old') |
---|
3291 | Blender.Text.unlink(oldConfigText) |
---|
3292 | # write new configuration text |
---|
3293 | configText = Blender.Text.New(configTextName) |
---|
3294 | configText.write('Ogreexport configuration file.\n\nThis file is automatically created. Please don\'t edit this file directly.\n\n') |
---|
3295 | try: |
---|
3296 | # pickle |
---|
3297 | configText.write(pickle.dumps(settingsDict)) |
---|
3298 | except (PickleError): |
---|
3299 | pass |
---|
3300 | else: |
---|
3301 | success = 1 |
---|
3302 | return success |
---|
3303 | |
---|
3304 | def loadSettings(filename): |
---|
3305 | """Load all exporter settings from text or file. |
---|
3306 | |
---|
3307 | Settings are loaded from a text object called 'ogreexport.cfg'. |
---|
3308 | If it is not found, settings are loaded from the file with the given filename. |
---|
3309 | <p> |
---|
3310 | You have to create armatureActionActuatorListViews with the new |
---|
3311 | armatuerAnimationDictListDict if you want the animation settings |
---|
3312 | to take effect. |
---|
3313 | |
---|
3314 | @param filename where to store the settings |
---|
3315 | @return <code>true</code> on success, else <code>false</code> |
---|
3316 | """ |
---|
3317 | global gameEngineMaterialsToggle |
---|
3318 | global armatureToggle |
---|
3319 | global worldCoordinatesToggle |
---|
3320 | global ambientToggle |
---|
3321 | global pathString |
---|
3322 | global materialString |
---|
3323 | global scaleNumber |
---|
3324 | global rotXNumber, rotYNumber, rotZNumber |
---|
3325 | global fpsNumber |
---|
3326 | global selectedObjectsList |
---|
3327 | global armatureDict |
---|
3328 | global armatureAnimationDictListDict |
---|
3329 | settingsDict = {} |
---|
3330 | success = 0 |
---|
3331 | # try open 'ogreexport.cfg' text |
---|
3332 | configTextName = 'ogreexport.cfg' |
---|
3333 | if configTextName in [text.getName() for text in Blender.Text.Get()]: |
---|
3334 | configText = Blender.Text.Get(configTextName) |
---|
3335 | # compose string from text and unpickle |
---|
3336 | try: |
---|
3337 | # unpickle |
---|
3338 | settingsDict = pickle.loads(string.join(configText.asLines()[4:],'\n')) |
---|
3339 | except (PickleError): |
---|
3340 | pass |
---|
3341 | else: |
---|
3342 | success = 1 |
---|
3343 | # else try open filename |
---|
3344 | if not success and os.path.isfile(filename): |
---|
3345 | # open file |
---|
3346 | try: |
---|
3347 | fileHandle = open(filename,'r') |
---|
3348 | except IOError, (errno, strerror): |
---|
3349 | print "I/O Error(%s): %s" % (errno, strerror) |
---|
3350 | else: |
---|
3351 | try: |
---|
3352 | # load settings |
---|
3353 | unpickler = pickle.Unpickler(fileHandle) |
---|
3354 | settingsDict = unpickler.load() |
---|
3355 | # close file |
---|
3356 | fileHandle.close() |
---|
3357 | except EOFError: |
---|
3358 | print "EOF Error" |
---|
3359 | else: |
---|
3360 | success = 1 |
---|
3361 | # set general settings |
---|
3362 | if settingsDict.has_key('gameEngineMaterialsToggle'): |
---|
3363 | gameEngineMaterialsToggle = Blender.Draw.Create(settingsDict['gameEngineMaterialsToggle']) |
---|
3364 | if settingsDict.has_key('armatureToggle'): |
---|
3365 | armatureToggle = Blender.Draw.Create(settingsDict['armatureToggle']) |
---|
3366 | if settingsDict.has_key('worldCoordinatesToggle'): |
---|
3367 | worldCoordinatesToggle = Blender.Draw.Create(settingsDict['worldCoordinatesToggle']) |
---|
3368 | if settingsDict.has_key('ambientToggle'): |
---|
3369 | ambientToggle = Blender.Draw.Create(settingsDict['ambientToggle']) |
---|
3370 | elif settingsDict.has_key('armatureMeshToggle'): |
---|
3371 | # old default was export in world coordinates |
---|
3372 | worldCoordinatesToggle = Blender.Draw.Create(1) |
---|
3373 | if settingsDict.has_key('pathString'): |
---|
3374 | pathString = Blender.Draw.Create(settingsDict['pathString']) |
---|
3375 | if settingsDict.has_key('materialString'): |
---|
3376 | materialString = Blender.Draw.Create(settingsDict['materialString']) |
---|
3377 | if settingsDict.has_key('scaleNumber'): |
---|
3378 | scaleNumber = Blender.Draw.Create(settingsDict['scaleNumber']) |
---|
3379 | if settingsDict.has_key('rotXNumber'): |
---|
3380 | rotXNumber = Blender.Draw.Create(settingsDict['rotXNumber']) |
---|
3381 | if settingsDict.has_key('rotYNumber'): |
---|
3382 | rotYNumber = Blender.Draw.Create(settingsDict['rotYNumber']) |
---|
3383 | if settingsDict.has_key('rotZNumber'): |
---|
3384 | rotZNumber = Blender.Draw.Create(settingsDict['rotZNumber']) |
---|
3385 | if settingsDict.has_key('fpsNumber'): |
---|
3386 | fpsNumber = Blender.Draw.Create(settingsDict['fpsNumber']) |
---|
3387 | # set object specific settings |
---|
3388 | if settingsDict.has_key('armatureAnimationDictListDict'): |
---|
3389 | armatureAnimationDictListDict = settingsDict['armatureAnimationDictListDict'] |
---|
3390 | elif settingsDict.has_key('animationDictListDict'): |
---|
3391 | # convert old animationDictListDict |
---|
3392 | ## create list of valid armature names |
---|
3393 | armatureNameList = [] |
---|
3394 | for object in Blender.Object.Get(): |
---|
3395 | if (object.getType() == "Armature"): |
---|
3396 | armatureNameList.append(object.getName()) |
---|
3397 | # create armatureAnimationDictListDict |
---|
3398 | armatureAnimationDictListDict = {} |
---|
3399 | animationDictListDict = settingsDict['animationDictListDict'] |
---|
3400 | for armatureName in armatureNameList: |
---|
3401 | if animationDictListDict.has_key(armatureName): |
---|
3402 | # convert animationDictList |
---|
3403 | armatureActionDict = ArmatureAction.createArmatureActionDict(Blender.Object.Get(armatureName)) |
---|
3404 | armatureActionActuatorListView = ArmatureActionActuatorListView(armatureActionDict, MAXACTUATORS, BUTTON_EVENT_ACTUATOR_RANGESTART,{}) |
---|
3405 | armatureActionActuatorListView.setAnimationDictList(animationDictListDict[armatureName]) |
---|
3406 | armatureAnimationDictListDict[armatureName] = armatureActionActuatorListView.getArmatureAnimationDictList() |
---|
3407 | return success |
---|
3408 | |
---|
3409 | def refreshGUI(): |
---|
3410 | """refresh GUI after export and selection change |
---|
3411 | """ |
---|
3412 | global exportLogger |
---|
3413 | global selectedObjectsList, armatureToggle, armatureDict |
---|
3414 | global armatureActionActuatorListViewDict |
---|
3415 | global armatureAnimationDictListDict |
---|
3416 | # export settings |
---|
3417 | exportLogger = Logger() |
---|
3418 | # synchronize armatureAnimationDictListDict |
---|
3419 | for armatureName in armatureActionActuatorListViewDict.keys(): |
---|
3420 | armatureAnimationDictListDict[armatureName] = armatureActionActuatorListViewDict[armatureName].getArmatureAnimationDictList() |
---|
3421 | selectedObjectsList = Blender.Object.GetSelected() |
---|
3422 | if not selectedObjectsList: |
---|
3423 | # called from command line |
---|
3424 | selectedObjectsList = [] |
---|
3425 | armatureDict = {} |
---|
3426 | # create fresh armatureDict |
---|
3427 | for object in selectedObjectsList: |
---|
3428 | if (object.getType() == "Armature"): |
---|
3429 | # add armature to armatureDict |
---|
3430 | armatureDict[object.getName()] = object.getName() |
---|
3431 | elif (object.getType() == "Mesh"): |
---|
3432 | parent = object.getParent() |
---|
3433 | if parent and parent.getType() == "Armature": |
---|
3434 | # add armature to armatureDict |
---|
3435 | armatureDict[object.getName()] = parent.getName() |
---|
3436 | # refresh ArmatureActionActuatorListViews |
---|
3437 | for armatureName in armatureDict.values(): |
---|
3438 | # create armatureActionDict |
---|
3439 | armatureActionDict = ArmatureAction.createArmatureActionDict(Blender.Object.Get(armatureName)) |
---|
3440 | # get animationDictList |
---|
3441 | armatureAnimationDictList = None |
---|
3442 | if armatureAnimationDictListDict.has_key(armatureName): |
---|
3443 | armatureAnimationDictList = armatureAnimationDictListDict[armatureName] |
---|
3444 | if armatureActionActuatorListViewDict.has_key(armatureName): |
---|
3445 | # refresh armatureActionActuators |
---|
3446 | armatureActionActuatorListViewDict[armatureName].refresh(armatureActionDict) |
---|
3447 | else: |
---|
3448 | # create armatureActionActuatorListView |
---|
3449 | armatureActionActuatorListViewDict[armatureName] = ArmatureActionActuatorListView(armatureActionDict, MAXACTUATORS, BUTTON_EVENT_ACTUATOR_RANGESTART, armatureAnimationDictList) |
---|
3450 | return |
---|
3451 | |
---|
3452 | def initGUI(): |
---|
3453 | """initialization of the GUI |
---|
3454 | """ |
---|
3455 | global armatureActionActuatorListViewDict |
---|
3456 | if KEEP_SETTINGS: |
---|
3457 | # load exporter settings |
---|
3458 | loadSettings(Blender.Get('filename')+".ogre") |
---|
3459 | armatureActionActuatorListViewDict = {} |
---|
3460 | refreshGUI() |
---|
3461 | return |
---|
3462 | |
---|
3463 | def exitGUI(): |
---|
3464 | if KEEP_SETTINGS: |
---|
3465 | # save exporter settings |
---|
3466 | saveSettings() |
---|
3467 | Blender.Draw.Exit() |
---|
3468 | return |
---|
3469 | |
---|
3470 | def pathSelectCallback(fileName): |
---|
3471 | """handles FileSelector output |
---|
3472 | """ |
---|
3473 | global pathString |
---|
3474 | # strip path from fileName |
---|
3475 | pathString = Blender.Draw.Create(os.path.dirname(fileName)) |
---|
3476 | return |
---|
3477 | |
---|
3478 | def eventCallback(event,value): |
---|
3479 | """handles keyboard and mouse events |
---|
3480 | <p> |
---|
3481 | exits on ESCKEY<br> |
---|
3482 | exits on QKEY |
---|
3483 | """ |
---|
3484 | global scrollbar |
---|
3485 | global selectedObjectsList, selectedObjectsMenu, armatureActionActuatorListViewDict, armatureDict |
---|
3486 | # eventFilter for current ArmatureActionActuatorListView |
---|
3487 | if (len(selectedObjectsList) > 0): |
---|
3488 | selectedObjectsListIndex = selectedObjectsMenu.val |
---|
3489 | selectedObjectName = selectedObjectsList[selectedObjectsListIndex].getName() |
---|
3490 | if armatureDict.has_key(selectedObjectName): |
---|
3491 | armatureName = armatureDict[selectedObjectName] |
---|
3492 | armatureActionActuatorListViewDict[armatureName].eventFilter(event, value) |
---|
3493 | scrollbar.eventFilter(event, value) |
---|
3494 | if (value != 0): |
---|
3495 | # pressed |
---|
3496 | if (event == Draw.ESCKEY): |
---|
3497 | exitGUI() |
---|
3498 | if (event == Draw.QKEY): |
---|
3499 | exitGUI() |
---|
3500 | return |
---|
3501 | |
---|
3502 | def buttonCallback(event): |
---|
3503 | """handles button events |
---|
3504 | """ |
---|
3505 | global materialString, doneMessageBox, eventCallback, buttonCallback, scrollbar |
---|
3506 | global selectedObjectsList, selectedObjectsMenu, armatureActionActuatorListViewDict, armatureDict |
---|
3507 | global fpsNumber |
---|
3508 | # buttonFilter for current ArmatureActionActuatorListView |
---|
3509 | if (len(selectedObjectsList) > 0): |
---|
3510 | selectedObjectsListIndex = selectedObjectsMenu.val |
---|
3511 | selectedObjectName = selectedObjectsList[selectedObjectsListIndex].getName() |
---|
3512 | if armatureDict.has_key(selectedObjectName): |
---|
3513 | armatureName = armatureDict[selectedObjectName] |
---|
3514 | armatureActionActuatorListViewDict[armatureName].buttonFilter(event) |
---|
3515 | scrollbar.buttonFilter(event) |
---|
3516 | if (event == BUTTON_EVENT_OK): # Ok |
---|
3517 | # restart |
---|
3518 | refreshGUI() |
---|
3519 | Draw.Register(gui, eventCallback, buttonCallback) |
---|
3520 | elif (event == BUTTON_EVENT_UPDATEBUTTON): |
---|
3521 | # update list of selected objects |
---|
3522 | refreshGUI() |
---|
3523 | Draw.Redraw(1) |
---|
3524 | elif (event == BUTTON_EVENT_SELECTEDOBJECTSMENU): |
---|
3525 | # selected object changed |
---|
3526 | Draw.Redraw(1) |
---|
3527 | elif (event == BUTTON_EVENT_QUIT): # Quit |
---|
3528 | exitGUI() |
---|
3529 | elif (event == BUTTON_EVENT_GAMEENGINEMATERIALSTOGGLE): |
---|
3530 | Draw.Redraw(1) |
---|
3531 | elif (event == BUTTON_EVENT_ARMATURETOGGLE): # armatureToggle |
---|
3532 | Draw.Redraw(1) |
---|
3533 | elif (event == BUTTON_EVENT_PATHBUTTON): # pathButton |
---|
3534 | Blender.Window.FileSelector(pathSelectCallback, "Export Directory", pathString.val) |
---|
3535 | Draw.Redraw(1) |
---|
3536 | elif (event == BUTTON_EVENT_MATERIALSTRING): # materialString |
---|
3537 | materialString = Blender.Draw.Create(PathName(materialString.val).basename()) |
---|
3538 | if (len(materialString.val) == 0): |
---|
3539 | materialString = Blender.Draw.Create(Blender.Scene.GetCurrent().getName() + ".material") |
---|
3540 | Draw.Redraw(1) |
---|
3541 | elif (event == BUTTON_EVENT_SCROLLBAR): # scrollbar |
---|
3542 | Draw.Redraw(1) |
---|
3543 | elif (event == BUTTON_EVENT_EXPORT): # export |
---|
3544 | Draw.Register(exportMessageBox, None, None) |
---|
3545 | Draw.Draw() |
---|
3546 | # export |
---|
3547 | if (Blender.Get("version") >= 233): |
---|
3548 | # get blender's current "scene->format->frames per second" setting |
---|
3549 | fpsNumber = Draw.Create(Blender.Scene.GetCurrent().getRenderingContext().framesPerSec()) |
---|
3550 | export(selectedObjectsList) |
---|
3551 | # set donemessage |
---|
3552 | scrollbar = ReplacementScrollbar(0,0,len(exportLogger.getMessageList())-1,BUTTON_EVENT_SCROLLBARUP,BUTTON_EVENT_SRCROLLBARDOWN) |
---|
3553 | Draw.Register(doneMessageBox, eventCallback, buttonCallback) |
---|
3554 | Draw.Redraw(1) |
---|
3555 | return |
---|
3556 | |
---|
3557 | def frameDecorator(x, y, width): |
---|
3558 | """draws title and logo onto the frame |
---|
3559 | |
---|
3560 | @param x upper left x coordinate |
---|
3561 | @param y upper left y coordinate |
---|
3562 | @param width screen width to use |
---|
3563 | @return used height |
---|
3564 | """ |
---|
3565 | # title |
---|
3566 | glColor3ub(210, 236, 210) |
---|
3567 | glRectf(x,y-41,x+width,y-17) |
---|
3568 | title = "Mesh and Armature Exporter" |
---|
3569 | glColor3ub(50, 62, 50) |
---|
3570 | glRasterPos2i(x+126, y-34) |
---|
3571 | Draw.Text(title, "normal") |
---|
3572 | glRasterPos2i(x+127, y-34) |
---|
3573 | Draw.Text(title, "normal") |
---|
3574 | |
---|
3575 | # logo |
---|
3576 | glRasterPos2i(x+1, y-48) |
---|
3577 | glEnable(GL_BLEND) |
---|
3578 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) |
---|
3579 | glDrawPixels(122, 48, GL_RGBA, GL_BYTE, OGRE_LOGO) |
---|
3580 | glColor3f(0,0,0) |
---|
3581 | return 50 |
---|
3582 | |
---|
3583 | def gui(): |
---|
3584 | """draws the screen |
---|
3585 | """ |
---|
3586 | global gameEngineMaterialsToggle, armatureToggle, worldCoordinatesToggle, \ |
---|
3587 | ambientToggle, pathString, materialString, scaleNumber, fpsNumber, \ |
---|
3588 | scrollbar, rotXNumber, rotYNumber, rotZNumber |
---|
3589 | global selectedObjectsList, selectedObjectsMenu, armatureActionActuatorListViewDict, armatureDict |
---|
3590 | # get size of the window |
---|
3591 | guiRectBuffer = Buffer(GL_FLOAT, 4) |
---|
3592 | glGetFloatv(GL_SCISSOR_BOX, guiRectBuffer) |
---|
3593 | guiRect = [0, 0, int(guiRectBuffer.list[2]), int(guiRectBuffer.list[3])] |
---|
3594 | |
---|
3595 | remainRect = guiRect[:] |
---|
3596 | remainRect[0] += 10 |
---|
3597 | remainRect[1] += 10 |
---|
3598 | remainRect[2] -= 10 |
---|
3599 | remainRect[3] -= 10 |
---|
3600 | |
---|
3601 | # clear background |
---|
3602 | glClearColor(0.6,0.6,0.6,1) # Background: grey |
---|
3603 | glClear(GL_COLOR_BUFFER_BIT) |
---|
3604 | |
---|
3605 | remainRect[3] -= frameDecorator(remainRect[0], remainRect[3], remainRect[2]-remainRect[0]) |
---|
3606 | |
---|
3607 | # export settings |
---|
3608 | remainRect[3] -= 5 |
---|
3609 | # first row |
---|
3610 | materialString = Draw.String("Material File: ", BUTTON_EVENT_MATERIALSTRING, \ |
---|
3611 | remainRect[0],remainRect[3]-25, 450, 20, \ |
---|
3612 | materialString.val, 255,"all material definitions go in this file (relative to the save path)") |
---|
3613 | remainRect[3] -= 25 |
---|
3614 | # second row |
---|
3615 | gameEngineMaterialsToggle = Draw.Toggle("Game Engine Materials", BUTTON_EVENT_GAMEENGINEMATERIALSTOGGLE, \ |
---|
3616 | remainRect[0], remainRect[3]-25, 220, 20, \ |
---|
3617 | gameEngineMaterialsToggle.val, "export game engine materials instead of rendering materials") |
---|
3618 | # scale settings |
---|
3619 | scaleNumber = Draw.Number("Mesh Scale Factor: ", BUTTON_EVENT_SCALENUMBER, \ |
---|
3620 | remainRect[0]+230, remainRect[3]-25, 220, 20, \ |
---|
3621 | scaleNumber.val, 0.0, 1000.0, "scale factor") |
---|
3622 | remainRect[3] -= 25 |
---|
3623 | # third row |
---|
3624 | armatureToggle = Draw.Toggle("Export Armatures", BUTTON_EVENT_ARMATURETOGGLE, \ |
---|
3625 | remainRect[0], remainRect[3]-25, 220, 20, \ |
---|
3626 | armatureToggle.val, "export skeletons and bone weights in meshes") |
---|
3627 | rotXNumber = Draw.Number("RotX: ", BUTTON_EVENT_ROTXNUMBER, \ |
---|
3628 | remainRect[0]+230, remainRect[3]-25, 220, 20, \ |
---|
3629 | rotXNumber.val, -360.0, 360.0, "angle of the first rotation, around the x-axis") |
---|
3630 | remainRect[3] -= 25 |
---|
3631 | # fourth row |
---|
3632 | worldCoordinatesToggle = Draw.Toggle("World Coordinates", BUTTON_EVENT_WORLDCOORDINATESTOGGLE, \ |
---|
3633 | remainRect[0], remainRect[3]-25, 220, 20, \ |
---|
3634 | worldCoordinatesToggle.val, "use world coordinates instead of object coordinates") |
---|
3635 | rotYNumber = Draw.Number("RotY: ", BUTTON_EVENT_ROTYNUMBER, \ |
---|
3636 | remainRect[0]+230, remainRect[3]-25, 220, 20, \ |
---|
3637 | rotYNumber.val, -360.0, 360.0, "angle of the second rotation, around the y-axis") |
---|
3638 | remainRect[3] -= 25 |
---|
3639 | # fifth row |
---|
3640 | ambientToggle = Draw.Toggle("Coloured Ambient", BUTTON_EVENT_AMBIENTTOGGLE, \ |
---|
3641 | remainRect[0], remainRect[3]-25, 220, 20, \ |
---|
3642 | ambientToggle.val, "use Amb factor times diffuse colour as ambient instead of Amb factor times white") |
---|
3643 | rotZNumber = Draw.Number("RotZ: ", BUTTON_EVENT_ROTZNUMBER, \ |
---|
3644 | remainRect[0]+230, remainRect[3]-25, 220, 20, \ |
---|
3645 | rotZNumber.val, -360.0, 360.0, "angle of the third rotation, around the z-axis") |
---|
3646 | # sixth row |
---|
3647 | if ((armatureToggle.val == 1) and (Blender.Get("version") < 233)): |
---|
3648 | remainRect[3] -= 25 |
---|
3649 | fpsNumber = Draw.Number("Frs/Sec: ", BUTTON_EVENT_FPSNUMBER, \ |
---|
3650 | remainRect[0]+230, remainRect[3]-25, 220, 20, \ |
---|
3651 | fpsNumber.val, 1, 120, "animation speed in frames per second") |
---|
3652 | remainRect[3] -= 35 |
---|
3653 | |
---|
3654 | # Path setting |
---|
3655 | pathString = Draw.String("Path: ", BUTTON_EVENT_PATHSTRING, \ |
---|
3656 | 10, 50, guiRect[2]-91, 20, \ |
---|
3657 | pathString.val, 255, "the directory where the exported files are saved") |
---|
3658 | Draw.Button("Select", BUTTON_EVENT_PATHBUTTON, guiRect[2]-80, 50, 70, 20, "select the export directory") |
---|
3659 | # button panel |
---|
3660 | Draw.Button("Export", BUTTON_EVENT_EXPORT,10,10,100,30,"export selected objects") |
---|
3661 | # Draw.Button("Help",BUTTON_EVENT_HELP ,(guiRect[2])/2-50,10,100,30,"notes on usage") |
---|
3662 | Draw.Button("Quit", BUTTON_EVENT_QUIT,guiRect[2]-110,10,100,30,"quit without exporting") |
---|
3663 | remainRect[1] += 70 |
---|
3664 | |
---|
3665 | # rename animation part |
---|
3666 | #if (armatureToggle.val == 1): |
---|
3667 | animationText = "Animation settings of" |
---|
3668 | xOffset = Draw.GetStringWidth(animationText) + 5 |
---|
3669 | selectedObjectsMenuName = "" |
---|
3670 | selectedObjectsMenuIndex = 0 |
---|
3671 | if (len(selectedObjectsList) > 0): |
---|
3672 | for object in selectedObjectsList: |
---|
3673 | # add menu string |
---|
3674 | selectedObjectsMenuName += object.getName() + " %x" + ("%d" % selectedObjectsMenuIndex) + "|" |
---|
3675 | selectedObjectsMenuIndex += 1 |
---|
3676 | else: |
---|
3677 | selectedObjectsMenuName = "No objects selected! %t" |
---|
3678 | selectedObjectsMenu = Draw.Menu(selectedObjectsMenuName, BUTTON_EVENT_SELECTEDOBJECTSMENU, \ |
---|
3679 | remainRect[0]+xOffset, remainRect[3]-20, 140, 20, \ |
---|
3680 | selectedObjectsMenu.val, "Objects selected for export") |
---|
3681 | xOffset += 141 |
---|
3682 | # update button |
---|
3683 | Draw.Button("Update", BUTTON_EVENT_UPDATEBUTTON, remainRect[0]+xOffset, remainRect[3]-20, 60, 20, "update list of selected objects") |
---|
3684 | remainRect[3] -= 25 |
---|
3685 | if (armatureToggle.val == 1): |
---|
3686 | # draw armatureActionActuator |
---|
3687 | if (len(selectedObjectsList) > 0): |
---|
3688 | selectedObjectsListIndex = selectedObjectsMenu.val |
---|
3689 | selectedObjectName = selectedObjectsList[selectedObjectsListIndex].getName() |
---|
3690 | if armatureDict.has_key(selectedObjectName): |
---|
3691 | glRasterPos2i(remainRect[0],remainRect[3]+10) |
---|
3692 | Draw.Text(animationText) |
---|
3693 | armatureName = armatureDict[selectedObjectName] |
---|
3694 | armatureActionActuatorListViewDict[armatureName].draw(remainRect[0], remainRect[1], remainRect[2]-remainRect[0], remainRect[3]-remainRect[1]) |
---|
3695 | return |
---|
3696 | |
---|
3697 | def exportMessageBox(): |
---|
3698 | """informs on the export progress |
---|
3699 | """ |
---|
3700 | # get size of the window |
---|
3701 | guiRectBuffer = Buffer(GL_FLOAT, 4) |
---|
3702 | glGetFloatv(GL_SCISSOR_BOX, guiRectBuffer) |
---|
3703 | guiRect = [0, 0, int(guiRectBuffer.list[2]), int(guiRectBuffer.list[3])] |
---|
3704 | |
---|
3705 | remainRect = guiRect[:] |
---|
3706 | remainRect[0] += 10 |
---|
3707 | remainRect[1] += 10 |
---|
3708 | remainRect[2] -= 10 |
---|
3709 | remainRect[3] -= 10 |
---|
3710 | |
---|
3711 | # clear background |
---|
3712 | glClearColor(0.6,0.6,0.6,1) # Background: grey |
---|
3713 | glClear(GL_COLOR_BUFFER_BIT) |
---|
3714 | |
---|
3715 | remainRect[3] -= frameDecorator(remainRect[0], remainRect[3], remainRect[2]-remainRect[0]) |
---|
3716 | |
---|
3717 | # export information |
---|
3718 | ## center view |
---|
3719 | exportMessage = "Exporting, please wait!" |
---|
3720 | exportMessageWidth = Draw.GetStringWidth(exportMessage, 'normal') |
---|
3721 | textPosition = [0, 0] |
---|
3722 | textPosition[0] = (remainRect[0] + remainRect[2] - exportMessageWidth)/2 |
---|
3723 | textPosition[1] = (remainRect[1] + remainRect[3])/2 |
---|
3724 | glRasterPos2i(textPosition[0], textPosition[1]) |
---|
3725 | glColor3f(0,0,0) # Defaul color: black |
---|
3726 | Draw.Text(exportMessage, "normal") |
---|
3727 | return |
---|
3728 | |
---|
3729 | def doneMessageBox(): |
---|
3730 | """displays export message and log |
---|
3731 | """ |
---|
3732 | global exportLogger |
---|
3733 | EXPORT_SUCCESS_MESSAGE = "Successfully exported!" |
---|
3734 | EXPORT_WARNING_MESSAGE = "Exported with warnings!" |
---|
3735 | EXPORT_ERROR_MESSAGE = "Error in export!" |
---|
3736 | # get size of the window |
---|
3737 | guiRectBuffer = Buffer(GL_FLOAT, 4) |
---|
3738 | glGetFloatv(GL_SCISSOR_BOX, guiRectBuffer) |
---|
3739 | guiRect = [0, 0, int(guiRectBuffer.list[2]), int(guiRectBuffer.list[3])] |
---|
3740 | |
---|
3741 | remainRect = guiRect[:] |
---|
3742 | remainRect[0] += 10 |
---|
3743 | remainRect[1] += 10 |
---|
3744 | remainRect[2] -= 10 |
---|
3745 | remainRect[3] -= 10 |
---|
3746 | |
---|
3747 | # clear background |
---|
3748 | glClearColor(0.6,0.6,0.6,1) # Background: grey |
---|
3749 | glClear(GL_COLOR_BUFFER_BIT) |
---|
3750 | |
---|
3751 | remainRect[3] -= frameDecorator(remainRect[0], remainRect[3], remainRect[2]-remainRect[0]) |
---|
3752 | |
---|
3753 | # OK button |
---|
3754 | Draw.Button("OK", BUTTON_EVENT_OK,10,10,100,30,"return to export settings") |
---|
3755 | Draw.Button("Quit", BUTTON_EVENT_QUIT,guiRect[2]-110,10,100,30,"quit export script") |
---|
3756 | remainRect[1] += 40 |
---|
3757 | |
---|
3758 | # message |
---|
3759 | status = exportLogger.getStatus() |
---|
3760 | doneMessage = '' |
---|
3761 | if (status == Logger.INFO): |
---|
3762 | doneMessage= EXPORT_SUCCESS_MESSAGE |
---|
3763 | elif (status == Logger.WARNING): |
---|
3764 | doneMessage = EXPORT_WARNING_MESSAGE |
---|
3765 | glColor3f(1.0,1.0,0.0) |
---|
3766 | Blender.BGL.glRectf(remainRect[0], remainRect[3]-24, remainRect[0]+Draw.GetStringWidth(doneMessage), remainRect[3]-7) |
---|
3767 | elif (status == Logger.ERROR): |
---|
3768 | doneMessage = EXPORT_ERROR_MESSAGE |
---|
3769 | glColor3f(1.0,0.0,0.0) |
---|
3770 | Blender.BGL.glRectf(remainRect[0], remainRect[3]-24, remainRect[0]+Draw.GetStringWidth(doneMessage), remainRect[3]-7) |
---|
3771 | remainRect[3] -= 20 |
---|
3772 | glColor3f(0.0,0.0,0.0) # Defaul color: black |
---|
3773 | glRasterPos2i(remainRect[0],remainRect[3]) |
---|
3774 | Draw.Text(doneMessage,"normal") |
---|
3775 | |
---|
3776 | remainRect[3] -= 20 |
---|
3777 | glColor3f(0.0,0.0,0.0) # Defaul color: black |
---|
3778 | glRasterPos2i(remainRect[0],remainRect[3]) |
---|
3779 | Draw.Text("Export Log:","small") |
---|
3780 | remainRect[3] -= 4 |
---|
3781 | |
---|
3782 | # black border |
---|
3783 | logRect = remainRect[:] |
---|
3784 | logRect[2] -= 22 |
---|
3785 | glColor3f(0,0,0) # Defaul color: black |
---|
3786 | glRectf(logRect[0],logRect[1],logRect[2],logRect[3]) |
---|
3787 | logRect[0] += 1 |
---|
3788 | logRect[1] += 1 |
---|
3789 | logRect[2] -= 1 |
---|
3790 | logRect[3] -= 1 |
---|
3791 | glColor3f(0.662,0.662,0.662) # Background: grey |
---|
3792 | glRectf(logRect[0],logRect[1],logRect[2],logRect[3]) |
---|
3793 | |
---|
3794 | # display export log |
---|
3795 | exportLog = exportLogger.getMessageList() |
---|
3796 | scrollPanelRect = remainRect[:] |
---|
3797 | loglineiMax = len(exportLog) |
---|
3798 | loglinei = scrollbar.getCurrentValue() |
---|
3799 | while (((logRect[3]-logRect[1]) >= 20) and ( loglinei < loglineiMax )): |
---|
3800 | logRect[3] -= 16 |
---|
3801 | (status, message) = exportLog[loglinei] |
---|
3802 | if (status == Logger.WARNING): |
---|
3803 | glColor3f(1.0,1.0,0.0) |
---|
3804 | glRecti(logRect[0],logRect[3]-4,logRect[2],logRect[3]+13) |
---|
3805 | elif (status == Logger.ERROR): |
---|
3806 | glColor3f(1.0,0.0,0.0) |
---|
3807 | glRecti(logRect[0],logRect[3]-4,logRect[2],logRect[3]+13) |
---|
3808 | glColor3f(0,0,0) |
---|
3809 | glRasterPos2i(logRect[0]+4,logRect[3]) |
---|
3810 | Draw.Text(message) |
---|
3811 | loglinei += 1 |
---|
3812 | # clip log text |
---|
3813 | glColor3f(0.6,0.6,0.6) # Background: grey |
---|
3814 | glRectf(scrollPanelRect[2]-22,scrollPanelRect[1], guiRect[2],scrollPanelRect[3]) |
---|
3815 | # draw scrollbar |
---|
3816 | scrollbar.draw(scrollPanelRect[2]-20, scrollPanelRect[1], 20, scrollPanelRect[3]-scrollPanelRect[1]) |
---|
3817 | return |
---|
3818 | |
---|
3819 | ###### |
---|
3820 | # Main |
---|
3821 | ###### |
---|
3822 | if (__name__ == "__main__"): |
---|
3823 | initGUI() |
---|
3824 | Draw.Register(gui, eventCallback, buttonCallback) |
---|