~ubuntu-branches/ubuntu/lucid/blender/lucid

« back to all changes in this revision

Viewing changes to release/scripts/export_fbx.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Coulson
  • Date: 2009-08-06 22:32:19 UTC
  • mfrom: (1.2.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090806223219-8z4eej1u8levu4pz
Tags: 2.49a+dfsg-0ubuntu1
* Merge from debian unstable, remaining changes:
  - debian/control: Build-depend on python-2.6 rather than python-2.5.
  - debian/misc/*.desktop: Add Spanish translation to .desktop 
    files.
  - debian/pyversions: 2.6.
  - debian/rules: Clean *.o of source/blender/python/api2_2x/
* New upstream release (LP: #382153).
* Refreshed patches:
  - 01_sanitize_sys.patch
  - 02_tmp_in_HOME
  - 10_use_systemwide_ftgl
  - 70_portability_platform_detection
* Removed patches merged upstream:
  - 30_fix_python_syntax_warning
  - 90_ubuntu_ffmpeg_52_changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!BPY
2
2
"""
3
3
Name: 'Autodesk FBX (.fbx)...'
4
 
Blender: 244
 
4
Blender: 249
5
5
Group: 'Export'
6
6
Tooltip: 'Selection to an ASCII Autodesk FBX '
7
7
"""
8
8
__author__ = "Campbell Barton"
9
9
__url__ = ['www.blender.org', 'blenderartists.org']
10
 
__version__ = "1.1"
 
10
__version__ = "1.2"
11
11
 
12
12
__bpydoc__ = """\
13
13
This script is an exporter to the FBX file format.
66
66
import BPySys
67
67
import BPyMessages
68
68
 
69
 
import sys
70
 
 
71
69
## This was used to make V, but faster not to do all that
72
70
##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}'
73
71
##v = range(255)
95
93
                dest_dir += Blender.sys.sep
96
94
        
97
95
        image_paths = set()
98
 
        for img in textures:
99
 
                image_paths.add(Blender.sys.expandpath(img.filename))
 
96
        for tex in textures:
 
97
                image_paths.add(Blender.sys.expandpath(tex.filename))
100
98
        
101
99
        # Now copy images
102
100
        copyCount = 0
159
157
# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up.
160
158
def sane_name(data, dct):
161
159
        #if not data: return None
162
 
        name = data.name
 
160
        
 
161
        if type(data)==tuple: # materials are paired up with images
 
162
                data, other = data
 
163
                use_other = True
 
164
        else:
 
165
                other = None
 
166
                use_other = False
 
167
        
 
168
        if data:        name = data.name
 
169
        else:           name = None
 
170
        orig_name = name
 
171
        
 
172
        if other:
 
173
                orig_name_other = other.name
 
174
                name = '%s #%s' % (name, orig_name_other)
 
175
        else:
 
176
                orig_name_other = None
163
177
        
164
178
        # dont cache, only ever call once for each data type now,
165
179
        # so as to avoid namespace collision between types - like with objects <-> bones
166
180
        #try:           return dct[name]
167
181
        #except:                pass
168
182
        
169
 
        orig_name = name
170
183
        if not name:
171
184
                name = 'unnamed' # blank string, ASKING FOR TROUBLE!
172
185
        else:
175
188
        
176
189
        while name in dct.itervalues(): name = increment_string(name)
177
190
        
178
 
        dct[orig_name] = name
 
191
        if use_other: # even if other is None - orig_name_other will be a string or None
 
192
                dct[orig_name, orig_name_other] = name
 
193
        else:
 
194
                dct[orig_name] = name
 
195
                
179
196
        return name
180
197
 
181
198
def sane_obname(data):          return sane_name(data, sane_name_mapping_ob)
184
201
def sane_takename(data):        return sane_name(data, sane_name_mapping_take)
185
202
def sane_groupname(data):       return sane_name(data, sane_name_mapping_group)
186
203
 
187
 
 
 
204
def derived_paths(fname_orig, basepath, FORCE_CWD=False):
 
205
        '''
 
206
        fname_orig - blender path, can be relative
 
207
        basepath - fname_rel will be relative to this
 
208
        FORCE_CWD - dont use the basepath, just add a ./ to the filename.
 
209
                use when we know the file will be in the basepath.
 
210
        '''
 
211
        fname = Blender.sys.expandpath(fname_orig)
 
212
        fname_strip = strip_path(fname)
 
213
        if FORCE_CWD:   fname_rel = '.' + Blender.sys.sep + fname_strip
 
214
        else:                           fname_rel = Blender.sys.relpath(fname, basepath)
 
215
        if fname_rel.startswith('//'): fname_rel = '.' + Blender.sys.sep + fname_rel[2:]
 
216
        return fname, fname_strip, fname_rel
188
217
 
189
218
 
190
219
def mat4x4str(mat):
342
371
        
343
372
        # end batch support
344
373
        
 
374
        # Use this for working out paths relative to the export location
 
375
        basepath = Blender.sys.dirname(filename)
345
376
        
346
377
        # ----------------------------------------------
347
378
        # storage classes
499
530
        if time:
500
531
                curtime = time.localtime()[0:6]
501
532
        else:
502
 
                curtime = [0,0,0,0,0,0]
 
533
                curtime = (0,0,0,0,0,0)
503
534
        # 
504
535
        file.write(\
505
536
'''FBXHeaderExtension:  {
971
1002
                #eDIRECTIONAL
972
1003
                #eSPOT
973
1004
                light_type = light.type
974
 
                if light_type > 3: light_type = 0
 
1005
                if light_type > 2: light_type = 1 # hemi and area lights become directional
975
1006
                
976
1007
                mode = light.mode
977
1008
                if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows:
1141
1172
                        Property: "Width", "int", "",0
1142
1173
                        Property: "Height", "int", "",0''')
1143
1174
                if tex:
1144
 
                        fname = tex.filename
1145
 
                        fname_strip = strip_path(fname)
 
1175
                        fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
1146
1176
                else:
1147
 
                        fname = fname_strip = ''
 
1177
                        fname = fname_strip = fname_rel = ''
1148
1178
                
1149
1179
                file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip)
1150
1180
                
1163
1193
                
1164
1194
                file.write('\n\t\tFilename: "%s"' % fname_strip)
1165
1195
                if fname_strip: fname_strip = '/' + fname_strip
1166
 
                file.write('\n\t\tRelativeFilename: "fbx%s"' % fname_strip) # make relative
 
1196
                file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # make relative
1167
1197
                file.write('\n\t}')
1168
1198
 
1169
1199
        
1202
1232
                }''')
1203
1233
                
1204
1234
                file.write('\n\t\tMedia: "Video::%s"' % texname)
 
1235
                
1205
1236
                if tex:
1206
 
                        fname = tex.filename
1207
 
                        file.write('\n\t\tFileName: "%s"' % strip_path(fname))
1208
 
                        file.write('\n\t\tRelativeFilename: "fbx/%s"' % strip_path(fname)) # need some make relative command
 
1237
                        fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
1209
1238
                else:
1210
 
                        file.write('\n\t\tFileName: ""')
1211
 
                        file.write('\n\t\tRelativeFilename: "fbx"')
 
1239
                        fname = fname_strip = fname_rel = ''
 
1240
                
 
1241
                file.write('\n\t\tFileName: "%s"' % fname_strip)
 
1242
                file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # need some make relative command
1212
1243
                
1213
1244
                file.write('''
1214
1245
                ModelUVTranslation: 0,0
1321
1352
                me = my_mesh.blenData
1322
1353
                
1323
1354
                # if there are non NULL materials on this mesh
1324
 
                if [mat for mat in my_mesh.blenMaterials if mat]:       do_materials = True
1325
 
                else:                                                                                           do_materials = False
 
1355
                if my_mesh.blenMaterials:       do_materials = True
 
1356
                else:                                           do_materials = False
1326
1357
                
1327
1358
                if my_mesh.blenTextures:        do_textures = True
1328
 
                else:                                           do_textures = False                     
 
1359
                else:                                           do_textures = False     
 
1360
                
 
1361
                do_uvs = me.faceUV
1329
1362
                
1330
1363
                
1331
1364
                file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName)
1332
1365
                file.write('\n\t\tVersion: 232') # newline is added in write_object_props
1333
1366
                
1334
 
                write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())
 
1367
                poseMatrix = write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())[3]
 
1368
                pose_items.append((my_mesh.fbxName, poseMatrix))
1335
1369
                
1336
1370
                file.write('\n\t\t}')
1337
1371
                file.write('\n\t\tMultiLayer: 0')
1373
1407
                                else:                           file.write(',%i,%i,%i,%i' % fi )
1374
1408
                        i+=1
1375
1409
                
1376
 
                ed_val = [None, None]
1377
 
                LOOSE = Blender.Mesh.EdgeFlags.LOOSE
 
1410
                file.write('\n\t\tEdges: ')
 
1411
                i=-1
1378
1412
                for ed in me.edges:
1379
 
                        if ed.flag & LOOSE:
1380
 
                                ed_val[0] = ed.v1.index
1381
 
                                ed_val[1] = -(ed.v2.index+1)
1382
1413
                                if i==-1:
1383
 
                                        file.write('%i,%i' % tuple(ed_val) )
 
1414
                                        file.write('%i,%i' % (ed.v1.index, ed.v2.index))
1384
1415
                                        i=0
1385
1416
                                else:
1386
1417
                                        if i==13:
1387
1418
                                                file.write('\n\t\t')
1388
1419
                                                i=0
1389
 
                                        file.write(',%i,%i' % tuple(ed_val) )
 
1420
                                        file.write(',%i,%i' % (ed.v1.index, ed.v2.index))
1390
1421
                                i+=1
1391
 
                del LOOSE
1392
1422
                
1393
1423
                file.write('\n\t\tGeometryVersion: 124')
1394
1424
                
1411
1441
                        i+=1
1412
1442
                file.write('\n\t\t}')
1413
1443
                
 
1444
                # Write Face Smoothing
 
1445
                file.write('''
 
1446
                LayerElementSmoothing: 0 {
 
1447
                        Version: 102
 
1448
                        Name: ""
 
1449
                        MappingInformationType: "ByPolygon"
 
1450
                        ReferenceInformationType: "Direct"
 
1451
                        Smoothing: ''')
 
1452
                
 
1453
                i=-1
 
1454
                for f in me.faces:
 
1455
                        if i==-1:
 
1456
                                file.write('%i' % f.smooth);    i=0
 
1457
                        else:
 
1458
                                if i==54:
 
1459
                                        file.write('\n                   ');    i=0
 
1460
                                file.write(',%i' % f.smooth)
 
1461
                        i+=1
 
1462
                
 
1463
                file.write('\n\t\t}')
 
1464
                
 
1465
                # Write Edge Smoothing
 
1466
                file.write('''
 
1467
                LayerElementSmoothing: 0 {
 
1468
                        Version: 101
 
1469
                        Name: ""
 
1470
                        MappingInformationType: "ByEdge"
 
1471
                        ReferenceInformationType: "Direct"
 
1472
                        Smoothing: ''')
 
1473
                
 
1474
                SHARP = Blender.Mesh.EdgeFlags.SHARP
 
1475
                i=-1
 
1476
                for ed in me.edges:
 
1477
                        if i==-1:
 
1478
                                file.write('%i' % ((ed.flag&SHARP)!=0));        i=0
 
1479
                        else:
 
1480
                                if i==54:
 
1481
                                        file.write('\n                   ');    i=0
 
1482
                                file.write(',%i' % ((ed.flag&SHARP)!=0))
 
1483
                        i+=1
 
1484
                
 
1485
                file.write('\n\t\t}')
 
1486
                del SHARP
 
1487
                
 
1488
                
1414
1489
                # Write VertexColor Layers
1415
1490
                # note, no programs seem to use this info :/
1416
1491
                collayers = []
1434
1509
                                for f in me.faces:
1435
1510
                                        for col in f.col:
1436
1511
                                                if i==-1:
1437
 
                                                        file.write('%i,%i,%i' % (col[0], col[1], col[2]))
 
1512
                                                        file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
1438
1513
                                                        i=0
1439
1514
                                                else:
1440
1515
                                                        if i==7:
1441
1516
                                                                file.write('\n\t\t\t\t')
1442
1517
                                                                i=0
1443
 
                                                        file.write(',%i,%i,%i' % (col[0], col[1], col[2]))
 
1518
                                                        file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
1444
1519
                                                i+=1
1445
1520
                                                ii+=1 # One more Color
1446
1521
                                
1463
1538
                
1464
1539
                # Write UV and texture layers.
1465
1540
                uvlayers = []
1466
 
                if me.faceUV:
 
1541
                if do_uvs:
1467
1542
                        uvlayers = me.getUVLayerNames()
1468
1543
                        uvlayer_orig = me.activeUVLayer
1469
1544
                        for uvindex, uvlayer in enumerate(uvlayers):
1526
1601
                                        if len(my_mesh.blenTextures) == 1:
1527
1602
                                                file.write('0')
1528
1603
                                        else:
1529
 
                                                #texture_mapping_local = {None:0}
1530
1604
                                                texture_mapping_local = {None:-1}
1531
1605
                                                
1532
1606
                                                i = 0 # 1 for dummy
1533
1607
                                                for tex in my_mesh.blenTextures:
1534
 
                                                        texture_mapping_local[tex] = i
1535
 
                                                        i+=1
 
1608
                                                        if tex: # None is set above
 
1609
                                                                texture_mapping_local[tex] = i
 
1610
                                                                i+=1
1536
1611
                                                
1537
1612
                                                i=-1
1538
1613
                                                for f in me.faces:
1582
1657
                                file.write('0')
1583
1658
                        else:
1584
1659
                                # Build a material mapping for this 
1585
 
                                #material_mapping_local = [0] * 16 # local-index : global index.
1586
 
                                material_mapping_local = [-1] * 16 # local-index : global index.
1587
 
                                i= 0 # 1
1588
 
                                for j, mat in enumerate(my_mesh.blenMaterials):
1589
 
                                        if mat:
1590
 
                                                material_mapping_local[j] = i
1591
 
                                                i+=1
1592
 
                                        # else leave as -1
 
1660
                                material_mapping_local = {} # local-mat & tex : global index.
 
1661
                                
 
1662
                                for j, mat_tex_pair in enumerate(my_mesh.blenMaterials):
 
1663
                                        material_mapping_local[mat_tex_pair] = j
1593
1664
                                
1594
1665
                                len_material_mapping_local = len(material_mapping_local)
1595
1666
                                
 
1667
                                mats = my_mesh.blenMaterialList
 
1668
                                
1596
1669
                                i=-1
1597
1670
                                for f in me.faces:
1598
 
                                        f_mat = f.mat
1599
 
                                        if f_mat >= len_material_mapping_local:
1600
 
                                                f_mat = 0
 
1671
                                        try:    mat = mats[f.mat]
 
1672
                                        except:mat = None
 
1673
                                        
 
1674
                                        if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/
 
1675
                                        else: tex = None
1601
1676
                                        
1602
1677
                                        if i==-1:
1603
1678
                                                i=0
1604
 
                                                file.write( '%s' % (material_mapping_local[f_mat]))
 
1679
                                                file.write( '%s' % (material_mapping_local[mat, tex])) # None for mat or tex is ok
1605
1680
                                        else:
1606
1681
                                                if i==55:
1607
1682
                                                        file.write('\n\t\t\t\t')
1608
1683
                                                        i=0
1609
1684
                                                
1610
 
                                                file.write(',%s' % (material_mapping_local[f_mat]))
 
1685
                                                file.write(',%s' % (material_mapping_local[mat, tex]))
1611
1686
                                        i+=1
1612
1687
                        
1613
1688
                        file.write('\n\t\t}')
1642
1717
                                TypedIndex: 0
1643
1718
                        }''')
1644
1719
                
1645
 
                if me.faceUV:
 
1720
                if do_uvs: # same as me.faceUV
1646
1721
                        file.write('''
1647
1722
                        LayerElement:  {
1648
1723
                                Type: "LayerElementUV"
1724
1799
        ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null]
1725
1800
        
1726
1801
        groups = [] # blender groups, only add ones that have objects in the selections
1727
 
        materials = {}
1728
 
        textures = {}
 
1802
        materials = {} # (mat, image) keys, should be a set()
 
1803
        textures = {} # should be a set()
1729
1804
        
1730
1805
        tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error
1731
1806
        
1825
1900
                                        if EXP_MESH_HQ_NORMALS:
1826
1901
                                                BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
1827
1902
                                        
1828
 
                                        for mat in mats:
1829
 
                                                # 2.44 use mat.lib too for uniqueness
1830
 
                                                if mat: materials[mat] = mat
1831
 
                                        
1832
1903
                                        texture_mapping_local = {}
 
1904
                                        material_mapping_local = {}
1833
1905
                                        if me.faceUV:
1834
1906
                                                uvlayer_orig = me.activeUVLayer
1835
1907
                                                for uvlayer in me.getUVLayerNames():
1836
1908
                                                        me.activeUVLayer = uvlayer
1837
1909
                                                        for f in me.faces:
1838
 
                                                                img = f.image
1839
 
                                                                textures[img] = texture_mapping_local[img] = img
 
1910
                                                                tex = f.image
 
1911
                                                                textures[tex] = texture_mapping_local[tex] = None
 
1912
                                                                
 
1913
                                                                try: mat = mats[f.mat]
 
1914
                                                                except: mat = None
 
1915
                                                                
 
1916
                                                                materials[mat, tex] = material_mapping_local[mat, tex] = None # should use sets, wait for blender 2.5
 
1917
                                                                        
1840
1918
                                                        
1841
1919
                                                        me.activeUVLayer = uvlayer_orig
 
1920
                                        else:
 
1921
                                                for mat in mats:
 
1922
                                                        # 2.44 use mat.lib too for uniqueness
 
1923
                                                        materials[mat, None] = material_mapping_local[mat, None] = None
 
1924
                                                else:
 
1925
                                                        materials[None, None] = None
1842
1926
                                        
1843
1927
                                        if EXP_ARMATURE:
1844
1928
                                                armob = BPyObject.getObjectArmature(ob)
1845
1929
                                                blenParentBoneName = None
1846
1930
                                                
1847
 
                                                # Note - Fixed in BPyObject but for now just copy the function because testers wont have up to date modukes,
1848
 
                                                # TODO - remove this for 2.45 release since getObjectArmature has been fixed
1849
 
                                                if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE:
1850
 
                                                        armob = ob.parent
1851
 
                                                
1852
1931
                                                # parent bone - special case
1853
1932
                                                if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE:
1854
1933
                                                        armob = ob.parent
1864
1943
                                        my_mesh = my_object_generic(ob, mtx)
1865
1944
                                        my_mesh.blenData =              me
1866
1945
                                        my_mesh.origData =              origData
1867
 
                                        my_mesh.blenMaterials = mats
1868
 
                                        my_mesh.blenTextures =  texture_mapping_local.values()
 
1946
                                        my_mesh.blenMaterials = material_mapping_local.keys()
 
1947
                                        my_mesh.blenMaterialList = mats
 
1948
                                        my_mesh.blenTextures =  texture_mapping_local.keys()
1869
1949
                                        
1870
1950
                                        # if only 1 null texture then empty the list
1871
1951
                                        if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None:
1984
2064
        # Finished finding groups we use
1985
2065
        
1986
2066
        
1987
 
        materials =     [(sane_matname(mat), mat) for mat in materials.itervalues() if mat]
1988
 
        textures =      [(sane_texname(img), img) for img in textures.itervalues()  if img]
 
2067
        materials =     [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.iterkeys()]
 
2068
        textures =      [(sane_texname(tex), tex) for tex in textures.iterkeys()  if tex]
1989
2069
        materials.sort() # sort by name
1990
2070
        textures.sort()
1991
2071
        
2114
2194
        
2115
2195
        write_camera_default()
2116
2196
        
2117
 
        for matname, mat in materials:
2118
 
                write_material(matname, mat)
 
2197
        for matname, (mat, tex) in materials:
 
2198
                write_material(matname, mat) # We only need to have a material per image pair, but no need to write any image info into the material (dumb fbx standard)
2119
2199
        
2120
2200
        # each texture uses a video, odd
2121
2201
        for texname, tex in textures:
2235
2315
        Model: "Model::Camera Switcher", "CameraSwitcher" {
2236
2316
        }''')
2237
2317
        
2238
 
        for matname, mat in materials:
 
2318
        for matname, (mat, tex) in materials:
2239
2319
                file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname)
2240
2320
 
2241
2321
        if textures:
2287
2367
        if materials:
2288
2368
                for my_mesh in ob_meshes:
2289
2369
                        # Connect all materials to all objects, not good form but ok for now.
2290
 
                        for mat in my_mesh.blenMaterials:
2291
 
                                if mat:
2292
 
                                        file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName))
 
2370
                        for mat, tex in my_mesh.blenMaterials:
 
2371
                                if mat: mat_name = mat.name
 
2372
                                else:   mat_name = None
 
2373
                                
 
2374
                                if tex: tex_name = tex.name
 
2375
                                else:   tex_name = None
 
2376
                                
 
2377
                                file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat_name, tex_name], my_mesh.fbxName))
2293
2378
        
2294
2379
        if textures:
2295
2380
                for my_mesh in ob_meshes:
2507
2592
                                                for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale
2508
2593
                                                        
2509
2594
                                                        if              TX_CHAN=='T':   context_bone_anim_vecs = [mtx[0].translationPart()      for mtx in context_bone_anim_mats]
2510
 
                                                        elif    TX_CHAN=='R':   context_bone_anim_vecs = [mtx[1].toEuler()                      for mtx in context_bone_anim_mats]
2511
 
                                                        else:                                   context_bone_anim_vecs = [mtx[0].scalePart()            for mtx in context_bone_anim_mats]
 
2595
                                                        elif    TX_CHAN=='S':   context_bone_anim_vecs = [mtx[0].scalePart()            for mtx in context_bone_anim_mats]
 
2596
                                                        elif    TX_CHAN=='R':
 
2597
                                                                # Was....
 
2598
                                                                # elif  TX_CHAN=='R':   context_bone_anim_vecs = [mtx[1].toEuler()                      for mtx in context_bone_anim_mats]
 
2599
                                                                # 
 
2600
                                                                # ...but we need to use the previous euler for compatible conversion.
 
2601
                                                                context_bone_anim_vecs = []
 
2602
                                                                prev_eul = None
 
2603
                                                                for mtx in context_bone_anim_mats:
 
2604
                                                                        if prev_eul:    prev_eul = mtx[1].toEuler(prev_eul)
 
2605
                                                                        else:                   prev_eul = mtx[1].toEuler()
 
2606
                                                                        context_bone_anim_vecs.append(prev_eul)
2512
2607
                                                        
2513
2608
                                                        file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation
2514
2609
                                                        
2527
2622
                                                                                if frame!=act_start:
2528
2623
                                                                                        file.write(',')
2529
2624
                                                                                
2530
 
                                                                                # Curve types are 
 
2625
                                                                                # Curve types are 'C,n' for constant, 'L' for linear
2531
2626
                                                                                # C,n is for bezier? - linear is best for now so we can do simple keyframe removal
2532
 
                                                                                file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n'  % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] ))
2533
 
                                                                                #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L'  % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] ))
 
2627
                                                                                file.write('\n\t\t\t\t\t\t\t%i,%.15f,L'  % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] ))
2534
2628
                                                                                frame+=1
2535
2629
                                                                else:
2536
2630
                                                                        # remove unneeded keys, j is the frame, needed when some frames are removed.
2538
2632
                                                                        
2539
2633
                                                                        # last frame to fisrt frame, missing 1 frame on either side.
2540
2634
                                                                        # removeing in a backwards loop is faster
2541
 
                                                                        for j in xrange( (act_end-act_start)-1, 0, -1 ):
2542
 
                                                                                # Is this key reduenant?
2543
 
                                                                                if      abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\
2544
 
                                                                                        abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT:
 
2635
                                                                        #for j in xrange( (act_end-act_start)-1, 0, -1 ):
 
2636
                                                                        # j = (act_end-act_start)-1
 
2637
                                                                        j = len(context_bone_anim_keys)-2
 
2638
                                                                        while j > 0 and len(context_bone_anim_keys) > 2:
 
2639
                                                                                # print j, len(context_bone_anim_keys)
 
2640
                                                                                # Is this key the same as the ones next to it?
 
2641
                                                                                
 
2642
                                                                                # co-linear horizontal...
 
2643
                                                                                if              abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\
 
2644
                                                                                                abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT:
 
2645
                                                                                                
2545
2646
                                                                                        del context_bone_anim_keys[j]
 
2647
                                                                                        
 
2648
                                                                                else:
 
2649
                                                                                        frame_range = float(context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j-1][1])
 
2650
                                                                                        frame_range_fac1 = (context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j][1]) / frame_range
 
2651
                                                                                        frame_range_fac2 = 1.0 - frame_range_fac1
 
2652
                                                                                        
 
2653
                                                                                        if abs(((context_bone_anim_keys[j-1][0]*frame_range_fac1 + context_bone_anim_keys[j+1][0]*frame_range_fac2)) - context_bone_anim_keys[j][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT:
 
2654
                                                                                                del context_bone_anim_keys[j]
 
2655
                                                                                        else:
 
2656
                                                                                                j-=1
 
2657
                                                                                        
 
2658
                                                                                # keep the index below the list length
 
2659
                                                                                if j > len(context_bone_anim_keys)-2:
 
2660
                                                                                        j = len(context_bone_anim_keys)-2
2546
2661
                                                                        
2547
2662
                                                                        if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]:
2548
2663
                                                                                # This axis has no moton, its okay to skip KeyCount and Keys in this case
2555
2670
                                                                                        if frame != context_bone_anim_keys[0][1]: # not the first
2556
2671
                                                                                                file.write(',')
2557
2672
                                                                                        # frame is alredy one less then blenders frame
2558
 
                                                                                        file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n'  % (fbx_time(frame), val ))
2559
 
                                                                                        #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L'  % (fbx_time(frame), val ))
 
2673
                                                                                        file.write('\n\t\t\t\t\t\t\t%i,%.15f,L'  % (fbx_time(frame), val ))
2560
2674
                                                                
2561
2675
                                                                if              i==0:   file.write('\n\t\t\t\t\t\tColor: 1,0,0')
2562
2676
                                                                elif    i==1:   file.write('\n\t\t\t\t\t\tColor: 0,1,0')
2658
2772
        
2659
2773
        # copy images if enabled
2660
2774
        if EXP_IMAGE_COPY:
2661
 
                copy_images( Blender.sys.dirname(filename),  [ tex[1] for tex in textures if tex[1] != None ])  
 
2775
                copy_images( basepath,  [ tex[1] for tex in textures if tex[1] != None ])       
2662
2776
        
2663
2777
        print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)
2664
2778
        return True
2722
2836
        GLOBALS['EVENT'] = e
2723
2837
 
2724
2838
def do_help(e,v):
2725
 
        url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx'
2726
 
        print 'Trying to open web browser with documentation at this address...'
2727
 
        print '\t' + url
2728
 
        
2729
 
        try:
2730
 
                import webbrowser
2731
 
                webbrowser.open(url)
2732
 
        except:
2733
 
                print '...could not open a browser window.'
 
2839
    url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx'
 
2840
    print 'Trying to open web browser with documentation at this address...'
 
2841
    print '\t' + url
 
2842
    
 
2843
    try:
 
2844
        import webbrowser
 
2845
        webbrowser.open(url)
 
2846
    except:
 
2847
        Blender.Draw.PupMenu("Error%t|Opening a webbrowser requires a full python installation")
 
2848
        print '...could not open a browser window.'
2734
2849
 
2735
2850
        
2736
2851
 
2834
2949
                Draw.BeginAlign()
2835
2950
                GLOBALS['ANIM_OPTIMIZE'] =                              Draw.Toggle('Optimize Keyframes',       EVENT_REDRAW, x+20,  y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE'].val,        'Remove double keyframes', do_redraw)
2836
2951
                if GLOBALS['ANIM_OPTIMIZE'].val:
2837
 
                        GLOBALS['ANIM_OPTIMIZE_PRECISSION'] =   Draw.Number('Precission: ',                     EVENT_NONE, x+180,  y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,      3, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)')
 
2952
                        GLOBALS['ANIM_OPTIMIZE_PRECISSION'] =   Draw.Number('Precission: ',                     EVENT_NONE, x+180,  y+0, 160, 20, GLOBALS['ANIM_OPTIMIZE_PRECISSION'].val,      1, 16, 'Tolerence for comparing double keyframes (higher for greater accuracy)')
2838
2953
                Draw.EndAlign()
2839
2954
                
2840
2955
                Draw.BeginAlign()
2912
3027
        # animation opts
2913
3028
        GLOBALS['ANIM_ENABLE'] =                                Draw.Create(1)
2914
3029
        GLOBALS['ANIM_OPTIMIZE'] =                              Draw.Create(1)
2915
 
        GLOBALS['ANIM_OPTIMIZE_PRECISSION'] =   Draw.Create(6) # decimal places
 
3030
        GLOBALS['ANIM_OPTIMIZE_PRECISSION'] =   Draw.Create(4) # decimal places
2916
3031
        GLOBALS['ANIM_ACTION_ALL'] =                    [Draw.Create(0), Draw.Create(1)] # not just the current action
2917
3032
        
2918
3033
        # batch export options