source: OGRE/trunk/ogrenew/Tools/BlenderExport/ogreexport.py @ 692

Revision 692, 227.3 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

Line 
1#!BPY
2
3"""
4Name: 'Ogre XML'
5Blender: 240
6Group: 'Export'
7Tooltip: '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__ = """\
15Exports selected meshes with armature animations to Ogre3D.
16
17Read 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.
50KEEP_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.
55OGRE_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.
60OGRE_OPENGL_VERTEXCOLOUR = 0
61
62#######################################################################################
63## Code starts here.
64
65# epydoc doc format
66__docformat__ = "javadoc en"
67
68######
69# imports
70######
71import Blender, sys, os, math, string
72if 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######
82from Blender import Draw
83from Blender import Mathutils
84from Blender.BGL import *
85
86######
87# Classes
88######
89class 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
320class 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
426class 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
445class 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
764class 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
829class 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
852class 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
879class 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
910class 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   
932class MeshExporter(ObjectExporter):
933    """
934    """
935    def getName(self):
936        return self.object.getData().name
937       
938class 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       
1327class 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######
1495gameEngineMaterialsToggle = Draw.Create(0)
1496armatureToggle = Draw.Create(1)
1497worldCoordinatesToggle = Draw.Create(0)
1498ambientToggle = Draw.Create(0)
1499pathString = Draw.Create(os.path.dirname(Blender.Get('filename')))
1500materialString = Draw.Create(Blender.Scene.GetCurrent().getName()+".material")
1501scaleNumber = Draw.Create(1.0)
1502fpsNumber = Draw.Create(25)
1503# first rotation, around X-axis
1504rotXNumber = Draw.Create(0.0)
1505# second rotation, around Y-axis
1506rotYNumber = Draw.Create(0.0)
1507# third rotation, around Z-axis
1508rotZNumber = Draw.Create(0.0)
1509selectedObjectsList = Blender.Object.GetSelected()
1510selectedObjectsMenu = Draw.Create(0)
1511scrollbar = ReplacementScrollbar(0,0,0,0,0)
1512# key: objectName, value: armatureName
1513armatureDict = {}
1514# key: armatureName, value: armatureActionActuatorListView
1515# does only contain keys for the current selected objects
1516armatureActionActuatorListViewDict = {}
1517# key: armatureName, value: animationDictList
1518armatureAnimationDictListDict = {}
1519MAXACTUATORS = 100
1520
1521# button event numbers:
1522BUTTON_EVENT_OK = 101
1523BUTTON_EVENT_QUIT = 102
1524BUTTON_EVENT_EXPORT = 103
1525BUTTON_EVENT_GAMEENGINEMATERIALSTOGGLE = 104
1526BUTTON_EVENT_ARMATURETOGGLE = 105
1527BUTTON_EVENT_WORLDCOORDINATESTOGGLE = 106
1528BUTTON_EVENT_AMBIENTTOGGLE = 107
1529BUTTON_EVENT_PATHSTRING = 108
1530BUTTON_EVENT_PATHBUTTON = 109
1531BUTTON_EVENT_MATERIALSTRING = 1010
1532BUTTON_EVENT_SCALENUMBER = 1011
1533BUTTON_EVENT_ROTXNUMBER = 1012
1534BUTTON_EVENT_ROTYNUMBER = 1013
1535BUTTON_EVENT_ROTZNUMBER = 1014
1536BUTTON_EVENT_FPSNUMBER = 1015
1537BUTTON_EVENT_SCROLLBAR = 1016
1538BUTTON_EVENT_SCROLLBARUP = 1017
1539BUTTON_EVENT_SRCROLLBARDOWN = 1018
1540BUTTON_EVENT_UPDATEBUTTON = 1019
1541BUTTON_EVENT_SELECTEDOBJECTSMENU = 1020
1542BUTTON_EVENT_ACTUATOR_RANGESTART = 1021
1543
1544exportLogger = Logger()
1545
1546OGRE_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
1598def 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
1604def 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
1629def 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
1659def 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
1665def 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
1682def 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
1687def 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
1692def 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
1700def normal_by_matrix(n, m):
1701  m = matrix_transpose(matrix_invert(m))
1702  return vector_normalize(vector_by_matrix(n, m))
1703
1704
1705def vector_dotproduct(v1, v2):
1706  return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
1707
1708def 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   
1718class 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
1732class 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   
1752class 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
1890class 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
2398class 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
2511class 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
2522class 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
2689class 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
2742class 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
2753class Influence:
2754  def __init__(self, bone, weight):
2755    self.bone   = bone
2756    self.weight = weight
2757   
2758class 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
2766class Skeleton:
2767  def __init__(self, name):
2768    self.name = name
2769    self.bones = []
2770    self.bonesDict = {}
2771    self.animationsDict = {}
2772
2773class 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
2789class 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   
2795class 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   
2803class 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
2816def 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
2854def 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
2900def 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
3005def 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
3126def tab(tabsize):
3127    return "\t" * tabsize
3128   
3129def clamp(val):
3130    if val < 0.0:
3131        val = 0.0
3132    if val > 1.0:
3133        val = 1.0
3134    return val
3135
3136def 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
3157def 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
3171def 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######
3231def 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
3304def 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   
3409def 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
3452def 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
3463def exitGUI():
3464    if KEEP_SETTINGS:
3465        # save exporter settings
3466        saveSettings()
3467    Blender.Draw.Exit()
3468    return
3469
3470def 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   
3478def 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
3502def 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
3557def 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
3583def 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
3697def 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   
3729def 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######
3822if (__name__ == "__main__"):
3823    initGUI()
3824    Draw.Register(gui, eventCallback, buttonCallback)
Note: See TracBrowser for help on using the repository browser.