diff options
author | Geoffrey Bantle <hairbat@yahoo.com> | 2007-11-22 04:43:24 +0300 |
---|---|---|
committer | Geoffrey Bantle <hairbat@yahoo.com> | 2007-11-22 04:43:24 +0300 |
commit | 78ea4f35646927a65c9a703d09f6e766bdd3b4ca (patch) | |
tree | 9d299663cd8d1bbcd3b92a6b06812ec1b6c02bc6 /release | |
parent | 313553b1edb02660361ebc281516fe8b6c122b7f (diff) |
-> Updated FLT scripts
Blender FLT I/O scripts have been updated to have more features.In addition
several utility scripts/applets have been added to aid in working with FLT
databases within Blender.
Documentation can be found here:
http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_flt
http://wiki.blender.org/index.php/Scripts/Manual/Export/openflight_flt
http://wiki.blender.org/index.php/Scripts/Manual/FLTools
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/flt_defaultp.py | 1 | ||||
-rw-r--r-- | release/scripts/flt_export.py | 1485 | ||||
-rw-r--r-- | release/scripts/flt_filewalker.py | 9 | ||||
-rw-r--r-- | release/scripts/flt_import.py | 1581 | ||||
-rw-r--r-- | release/scripts/flt_palettemanager.py | 388 | ||||
-rw-r--r-- | release/scripts/flt_properties.py | 619 | ||||
-rw-r--r-- | release/scripts/flt_toolbar.py | 594 |
7 files changed, 3710 insertions, 967 deletions
diff --git a/release/scripts/flt_defaultp.py b/release/scripts/flt_defaultp.py new file mode 100644 index 00000000000..5dca8ba63d7 --- /dev/null +++ b/release/scripts/flt_defaultp.py @@ -0,0 +1 @@ +pal = [-256,0,16711680,-16777216,-19529984,-19726592,-19923200,-20119808,-20316416,-20578560,-20840704,-21102848,-21364992,-21692672,-22020352,-22413568,-22806784,-23200000,-23658752,-24117504,-24641792,-25166080,-25755904,-26411264,-27066624,-27787520,-28573952,-29425920,-30343424,-31326464,-32375040,-33489152,-354550016,-371458304,-388366592,-405274880,-422183168,-439156992,-456130816,-473104640,-506855680,-540672256,-574488832,-608305408,-642121984,-676004096,-709886208,-760611072,-811335936,-862060800,-912851200,-980418816,-1048051968,-1115685120,-1183383808,-1267925248,-1352466688,-1453850880,-1555300608,-1656815872,-1775173888,-1893597440,-2028863744,2130771712,-1010376448,-1043996416,-1077681920,-1111367424,-1145052928,-1178738432,-1229201152,-1279663872,-1330126592,-1380654848,-1431183104,-1498488576,-1565794048,-1633165056,-1700536064,-1784684288,-1868832512,-1969823488,-2070814464,2123096320,2005262592,1887428864,1752752384,1601298688,1449779456,1281417472,1096278272,911073536,709026048,490201344,254533888,2023680,-1380857856,-1397700608,-1431320576,-1464940544,-1498560512,-1532180480,-1565865984,-1599551488,-1650014208,-1700476928,-1750939648,-1801402368,-1851865088,-1919170560,-1986476032,-2053781504,-2121086976,2089797632,2005649408,1904723968,1803798528,1686030336,1568262144,1450493952,1315883008,1164494848,1013041152,844810240,659736576,457885696,239192064,3655680,-1767919872,-1784762624,-1801605376,-1818448128,-1852068096,-1885688064,-1919308032,-1952928000,-1986547968,-2020167936,-2070565120,-2120962304,2123542272,2073079552,2022616832,1955376896,1888136960,1820897024,1736879872,1652797184,1568714496,1467854592,1366994688,1249357568,1131654912,997175040,862695168,711372544,560049920,391950080,207007488,5287680,2139657728,2122880512,2106103296,2089326080,2072548864,2055771648,2022217216,1988662784,1955108352,1921553920,1887933952,1854313984,1803916800,1753519616,1703122432,1652725248,1602328064,1535153664,1467979264,1400804864,1316853248,1232901632,1148950016,1048221184,947426816,846632448,729060864,611489280,477140480,326014464,174888448,6919680,1837268224,1820491008,1803713792,1786936576,1770159360,1753382144,1736604928,1719827712,1686273280,1652718848,1619164416,1585609984,1552055552,1518501120,1468169472,1417837824,1367506176,1317174528,1266842880,1199734016,1132625152,1065516288,998407424,914521344,830635264,729971968,629308672,528645376,411204864,293764352,159546624,8551680,-2086957824,-2103735040,-2120512256,-2137289472,2140900608,2107346176,2073791744,2040237056,2006682368,1973127680,1939572992,1906018304,1855686400,1805354496,1755022592,1704690688,1654358784,1587249664,1520140544,1453031424,1369145088,1285258496,1201371904,1100708096,1000044288,882603264,765162240,630943744,496725248,345729536,177956608,10183680,-1699438080,-1716215552,-1732993024,-1766547712,-1800102400,-1833657088,-1867211776,-1900766464,-1934321152,-1967875840,-2018207744,-2068539904,-2118872064,2125763072,2058653696,1991544320,1924434944,1857325568,1773438720,1689551872,1588887808,1488223744,1387559424,1270117888,1152676352,1018457600,884238592,733242368,565468672,397694976,213144064,11815680,-1311918848,-1345473536,-1379028224,-1412582912,-1446137600,-1479692544,-1513247488,-1546802432,-1597134592,-1647466752,-1697798912,-1748131072,-1798463488,-1865573120,-1932682752,-1999792384,-2083679232,2127400960,2043513856,1942849536,1842184960,1724743168,1607301376,1473082112,1338862848,1187866112,1020092160,852317952,667766528,466437632,248331264,13447680,-924399104,-957954048,-991508992,-1025063936,-1058618880,-1092173824,-1142505984,-1192838144,-1243170560,-1293502976,-1343835392,-1410945024,-1478054656,-1545164544,-1629051648,-1712938752,-1796826112,-1897490688,-1998155264,-2098820096,2078705152,1961262848,1827043328,1676046336,1525049344,1357274880,1172722944,971393792,753287168,518403072,283518720,15079680,-570434304,-603989248,-637544192,-671099136,-704654080,-754986496,-805318912,-855651328,-905983744,-973093632,-1040203520,-1107313408,-1174423296,-1258310656,-1342198016,-1442862848,-1543527680,-1644192512,-1761634816,-1879077120,-2013296896,2147450624,1996453376,1828678656,1660903936,1476351744,1275022080,1056914944,822030336,570368256,301928704,16711680,-503325440,-536880384,-570435328,-603990272,-637545216,-671100416,-721432832,-771765248,-822097664,-872430336,-922763008,-989872896,-1056982784,-1124092928,-1191203072,-1275090688,-1358978304,-1459643136,-1560308224,-1660973312,-1778415872,-1895858432,-2030078464,2113891328,1962893824,1795118848,1610566400,1426013696,1224683520,1006575872,771690752,520028160,-452993792,-469771520,-503326464,-536881408,-570436352,-603991552,-637546752,-671101952,-721434368,-771767040,-822099712,-872432384,-922765056,-989875200,-1056985344,-1124095744,-1191206144,-1275093760,-1358981632,-1459646720,-1560312064,-1677754624,-1795197440,-1912640512,-2046860800,2097108736,1946110720,1778335232,1593782272,1392451840,1174343936,939458560,-419439360,-436217088,-452994816,-469772544,-503327488,-536882688,-570437888,-603993088,-637548288,-671103744,-721436416,-771769088,-822101760,-872434688,-922767616,-989878016,-1056988416,-1124098816,-1207986688,-1291874560,-1375762688,-1476428032,-1577093632,-1694536704,-1811979776,-1946200320,-2080421120,2063547904,1912549376,1744773376,1560219904,1358888960,-385884928,-402662656,-419440384,-436218112,-452995840,-469773824,-503329024,-536884224,-570439424,-603994880,-637550336,-671105792,-721438464,-771771392,-822104320,-872437504,-922770688,-989881088,-1056991744,-1124102400,-1191213312,-1275101440,-1358989824,-1459655680,-1560321536,-1677764864,-1795208448,-1912652288,-2046873600,2097094912,1946095872,1778319360,-335553280,-352331008,-369108736,-385886464,-402664192,-419442176,-436220160,-452998144,-486553344,-520108800,-553664256,-587219712,-620775168,-654330880,-687886592,-738219776,-788552960,-838886144,-889219584,-939553024,-1006663936,-1073774848,-1140886016,-1224774656,-1308663296,-1392552192,-1493218560,-1593885184,-1711329280,-1828773632,-1962995456,-2097217536,-285221632,-301999360,-318777088,-335554816,-352332544,-369110528,-385888512,-402666496,-419444480,-436222720,-453000960,-469779200,-503334656,-536890368,-570446080,-604002048,-637558016,-671113984,-721447424,-771780864,-822114560,-872448256,-922782208,-989893632,-1057005056,-1124116736,-1191228672,-1275118080,-1359007744,-1459674880,-1560342272,-1677787136,-234889984,-234890496,-251668224,-268445952,-285223680,-302001664,-318779648,-335557632,-352335616,-369113856,-385892096,-402670336,-419448576,-436227072,-453005568,-469784320,-503340288,-536896256,-570452480,-604008704,-637565184,-671121664,-704678400,-755012608,-805346816,-855681280,-906016000,-973128192,-1040240640,-1107353344,-1174466304,-1258356736,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-251673344,-268451584,-285229824,-302008064,-318786560,-335565056,-352343808,-369122560,-385901312,-402680320,-419459328,-436238592,-453017856,-486574592,-520131584,-553688576,-587245824,-620803328,-654361088,-687919104,-738254592,-788590336,-838926336,-234889984,-234890496,-234891008,-234891520,-234892032,-234892800,-234893568,-234894336,-234895104,-234896128,-234897152,-234898176,-234899200,-234900480,-234901760,-234903296,-234904832,-234906368,-234908160,-234909952,-234912000,-251691264,-268470784,-285250560,-302030336,-318810368,-335590656,-352371200,-369152000,-385933056,-402714368,-419495936,-8960,-9472,-9984,-10496,-11008,-11776,-12544,-13312,-14080,-15104,-16128,-17152,-18176,-19456,-20736,-22272,-23808,-25344,-27136,-28928,-30976,-33024,-35328,-37888,-40448,-43264,-46336,-49664,-53248,-57088,-61184,-65536,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-930816,-931584,-932608,-933632,-934656,-935680,-936960,-938240,-939776,-941312,-1008384,-1075712,-1143040,-1210624,-1278208,-1346048,-1414144,-1482240,-1550592,-1619200,-1688064,-1757184,-1826560,-1896192,-2031616,-926464,-926976,-927488,-928000,-928512,-929280,-930048,-996352,-1062656,-1129216,-1195776,-1262336,-1328896,-1395712,-1462528,-1529600,-1596672,-1663744,-1731072,-1798400,-1865984,-1999104,-2132480,-2266112,-2399744,-2533632,-2667776,-2867712,-3067904,-3268352,-3469056,-3670016,-926464,-992512,-1058560,-1124608,-1190656,-1256960,-1323264,-1389568,-1455872,-1522432,-1588992,-1655552,-1722112,-1788928,-1855744,-1988352,-2120960,-2253568,-2386432,-2519296,-2652416,-2785536,-2984448,-3183616,-3382784,-3582208,-3847424,-4112896,-4378624,-4644608,-4976384,-5308416,-1188608,-1254656,-1320704,-1386752,-1452800,-1519104,-1585408,-1651712,-1718016,-1784576,-1851136,-1983232,-2115328,-2247680,-2380032,-2512640,-2645248,-2777856,-2976256,-3174656,-3373312,-3571968,-3836416,-4101120,-4365824,-4630784,-4961536,-5292544,-5689344,-6086400,-6483712,-6946816,-1385216,-1451264,-1517312,-1583360,-1649408,-1715712,-1782016,-1848320,-1980160,-2112256,-2244352,-2376448,-2508544,-2640896,-2838784,-3036928,-3235072,-3433216,-3631616,-3895552,-4159744,-4423936,-4688384,-5018624,-5348864,-5744896,-6141184,-6537728,-7000064,-7462656,-7991040,-8585216,-1581824,-1647872,-1713920,-1779968,-1846016,-1977856,-2109696,-2241536,-2373376,-2505472,-2637568,-2769664,-2967296,-3165184,-3363072,-3561216,-3759360,-4023040,-4286976,-4550912,-4880640,-5210368,-5540352,-5936128,-6331904,-6793472,-7255296,-7782912,-8310784,-8904448,-9563904,-10223616,-1712896,-1778944,-1844992,-1976576,-2108160,-2240000,-2371840,-2503680,-2635520,-2767616,-2965248,-3162880,-3360512,-3558400,-3821824,-4085504,-4349184,-4612864,-4942336,-5271808,-5667072,-6062336,-6457856,-6919168,-7380480,-7907584,-8434944,-9028096,-9687040,-10346240,-11071232,-11862016,-1843968,-1975552,-2107136,-2238720,-2370304,-2502144,-2633984,-2765824,-2963200,-3160832,-3358464,-3556096,-3753728,-4017152,-4280576,-4544256,-4873472,-5202688,-5532160,-5927168,-6322432,-6783232,-7244288,-7771136,-8297984,-8890624,-9549056,-10207744,-10932224,-11722496,-12578560,-13500416,-1975040,-2106624,-2238208,-2369792,-2501376,-2633216,-2830592,-3027968,-3225344,-3422976,-3620608,-3883776,-4146944,-4410368,-4673792,-5003008,-5332224,-5726976,-6121984,-6582528,-7043328,-7504128,-8030720,-8623104,-9215488,-9873664,-10597632,-11387392,-12242944,-13164288,-14085888,-15138816,-2237184,-2368768,-2500352,-2631936,-2763520,-2960896,-3158272,-3355648,-3553024,-3816192,-4079360,-4342528,-4605696,-4934656,-5263616,-5658368,-6053120,-6447872,-6908416,-7368960,-7895296,-8421632,-9013760,-9671680,-10329600,-11053312,-11842816,-12698112,-13619200,-14606080,-15658752,-16777216]
\ No newline at end of file diff --git a/release/scripts/flt_export.py b/release/scripts/flt_export.py index 283c24a3ad0..d2e90bc27b8 100644 --- a/release/scripts/flt_export.py +++ b/release/scripts/flt_export.py @@ -1,45 +1,25 @@ #!BPY """ Registration info for Blender menus: Name: 'OpenFlight (.flt)...' -Blender: 237 +Blender: 245 Group: 'Export' Tip: 'Export to OpenFlight v16.0 (.flt)' """ -__author__ = "Greg MacDonald" -__version__ = "1.2 10/20/05" +__author__ = "Greg MacDonald, Geoffrey Bantle" +__version__ = "2.0 11/21/07" __url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") __bpydoc__ = """\ This script exports v16.0 OpenFlight files. OpenFlight is a registered trademark of MultiGen-Paradigm, Inc. -Run from "File->Export" menu. - -Options are available from Blender's "Scripts Config Editor," accessible through -the "Scripts->System" menu from the scripts window. - -Features:<br> -* Heirarchy retained.<br> -* Normals retained.<br> -* First texture exported.<br> -* Diffuse material color is exported as the face color, material color, or both -depending on the option settings.<br> -* Double sided faces are exported as two faces.<br> -* Object transforms exported. - -Things To Be Aware Of:<br> -* Object names are exported, not mesh or data names. -* Material indices that don't have a material associated with them will confuse the -exporter. If a warning appears about this, correct it by deleting the offending -material indices in Blender. - -What's Not Handled:<br> -* Animations.<br> -* Vetex colors.<br> +Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/Export/openflight_flt """ # flt_export.py is an OpenFlight exporter for blender. -# Copyright (C) 2005 Greg MacDonald +# +# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -56,29 +36,87 @@ What's Not Handled:<br> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import Blender +from Blender import Modifier +import os.path +import flt_properties +import flt_defaultp as defaultp from flt_filewalker import FltOut +from flt_filewalker import FileFinder +from flt_properties import * +import shutil + +FF = FileFinder() +records = process_recordDefs() class ExporterOptions: def __init__(self): - self.defaults = { 'Diffuse Color To OpenFlight Material': False, - 'Diffuse Color To OpenFlight Face': True} + self.verbose = 1 + self.tolerance = 0.001 + self.writevcol = True - d = Blender.Registry.GetKey('flt_export', True) + #new stuff + self.export_shading = 0 + self.shading_default = 45.0 + self.basepath = os.path.dirname(Blender.Get('filename')) + self.scale = 1.0 - if d == None or d.keys() != self.defaults.keys(): - d = self.defaults - Blender.Registry.SetKey('flt_export', d, True) + #set externals path + if(os.path.exists(os.path.join(self.basepath,'externals'))): + self.externalspath = os.path.join(self.basepath,'externals') + else: + self.externalspath = self.basepath - self.verbose = 1 - self.tolerance = 0.001 - self.use_mat_color = d['Diffuse Color To OpenFlight Material'] - self.use_face_color = d['Diffuse Color To OpenFlight Face'] + self.doxrefs = 1 + + #texture options + if(os.path.exists(os.path.join(self.basepath,'textures'))): + self.texturespath = os.path.join(self.basepath,'textures') + else: + self.texturespath = self.basepath + + #misc + self.write_attrib_files = 0 + self.copy_textures = 0 + self.export_transform = 0 + self.flattenmesh = False + self.xapp = 1 + reg = Blender.Registry.GetKey('flt_export',1) + if(reg and 'xappath' in reg.keys()): + self.xappath = reg['xappath'] + else: + self.xappath = '' options = ExporterOptions() +tex_files = dict() #a list of (possibly) modified texture path names + +tex_layers = ['Layer0', 'Layer1', 'Layer2', 'Layer3', 'Layer4', 'Layer5', 'Layer6', 'Layer7'] +mask = 2147483648 +mtexmasks = [] +for i in xrange(7): + mtexmasks.append(mask) + mask = mask / 2 FLOAT_TOLERANCE = options.tolerance +#need to move all this stuff to flt_properties.py. identity_matrix = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] +alltypes = [2,4,11,73,63,111] +childtypes = { + 2 : [111,2,73,4,14,63], + 4 : [111], + 73 : [111,2,73,4,14,63], + 63 : [], + 14 : [111,2,73,4,14,63], + 111 : [] +} +recordlen = { + 2: 44, + 4: 28, + 73: 80, + 63: 216, + 14: 384, + 111: 156 +} def is_identity(m): for i in xrange(4): @@ -102,13 +140,47 @@ class MaterialDesc: self.alpha = 1.0 # Range is [0.0, 1.0] class VertexDesc: - def __init__(self, co=None, no=None, uv=None): + def __init__(self, co=None, no=None, uv=None, fltindex=None,cindex=None): if co: self.x, self.y, self.z = tuple(co) else: self.x = self.y = self.z = 0.0 if no: self.nx, self.ny, self.nz = tuple(no) else: self.nx = self.ny = self.nz = 0.0 if uv: self.u, self.v = tuple(uv) else: self.u = self.v = 0.0 + if cindex: self.cindex = cindex + else: self.cindex = 127 + self.fltindex = fltindex + self.accum = 0 + +class shadowVert: + def __init__(self,bvert,object,world,normal): + global options + + self.co = Blender.Mathutils.Vector(bvert.co[0],bvert.co[1],bvert.co[2]) + #if world: + # vec = self.co + # vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + # self.co = Blender.Mathutils.TranslationMatrix(vec) * (self.co * object.getMatrix('worldspace')) + + if normal: + #if world: + # self.no = Blender.Mathutils.Vector(normal * object.getMatrix('worldspace')).normalize() + #else: + self.no = Blender.Mathutils.Vector(normal[0],normal[1],normal[2]) + + else: + #if world: + #self.no = Blender.Mathutils.Vector(bvert.no * object.getMatrix('worldspace')).normalize() + #else: + self.no = Blender.Mathutils.Vector(bvert.no[0],bvert.no[1],bvert.no[2]) + + #do scaling factor + #if options.scale != 1.0: + #self.co[0] = self.co[0] * options.scale + #self.co[1] = self.co[1] * options.scale + #self.co[2] = self.co[2] * options.scale + + self.index = bvert.index class GlobalResourceRepository: def new_face_name(self): @@ -121,44 +193,98 @@ class GlobalResourceRepository: def request_vertex_desc(self, i): return self.vertex_lst[i] - def request_vertex_index(self, desc): - match = None - for i, v in enumerate(self.vertex_lst): - if\ - abs(v.x - desc.x) > FLOAT_TOLERANCE or\ - abs(v.y - desc.y) > FLOAT_TOLERANCE or\ - abs(v.z - desc.z) > FLOAT_TOLERANCE or\ - abs(v.nx - desc.nx) > FLOAT_TOLERANCE or\ - abs(v.ny - desc.ny) > FLOAT_TOLERANCE or\ - abs(v.nz - desc.nz) > FLOAT_TOLERANCE or\ - abs(v.u - desc.u) > FLOAT_TOLERANCE or\ - abs(v.v - desc.v) > FLOAT_TOLERANCE: - pass - else: - match = i - break + def request_vertex_index(self, object, mesh, face, vfindex, uvok,cindex): - if match != None: - return match + flatShadeNorm = None + + if type(face) is list: + vertex = face[vfindex] + elif str(type(face)) == "<type " + "'Blender MVert'>": + vertex = face + elif str(type(face)) == "<type " + "'Blender MEdge'>": + if vfindex == 1: + vertex = face.v1 + elif vfindex == 2: + vertex = face.v2 + elif str(type(face)) == "<type " + "'Blender MFace'>": + if not face.smooth: + flatShadeNorm = face.no + vertex = face.v[vfindex] + else: + return None + + if not self.namehash.has_key(object.name): + self.namehash[object.name] = dict() + indexhash = self.namehash[object.name] + + #export in global space? THIS HAS BEEN MADE REDUNDANT... REMOVE ME + if not options.export_transform: + vertex = shadowVert(vertex,object,True,flatShadeNorm) else: - self.vertex_lst.append(desc) - return len(self.vertex_lst) - 1 - - def request_texture_index(self, filename): + vertex = shadowVert(vertex,object,False,flatShadeNorm) + + + #Check to see if this vertex has been visited before. If not, add + if not indexhash.has_key(vertex.index): + if uvok: + newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex) + else: + newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex) + + indexhash[vertex.index] = [newvdesc] + self.vertex_lst.append(newvdesc) + self.nextvindex = self.nextvindex + 1 + return newvdesc.fltindex + + else: + desclist = indexhash[vertex.index] + if uvok: + faceu = face.uv[vfindex][0] + facev = face.uv[vfindex][1] + else: + faceu = 0.0 + facev = 0.0 + for vdesc in desclist: + if\ + abs(vdesc.x - vertex.co[0]) > FLOAT_TOLERANCE or\ + abs(vdesc.y - vertex.co[1]) > FLOAT_TOLERANCE or\ + abs(vdesc.z - vertex.co[2]) > FLOAT_TOLERANCE or\ + abs(vdesc.nx - vertex.no[0]) > FLOAT_TOLERANCE or\ + abs(vdesc.ny - vertex.no[1]) > FLOAT_TOLERANCE or\ + abs(vdesc.nz - vertex.no[2]) > FLOAT_TOLERANCE or\ + vdesc.cindex != cindex or\ + abs(vdesc.u - faceu) > FLOAT_TOLERANCE or\ + abs(vdesc.v - facev) > FLOAT_TOLERANCE: + pass + else: + return vdesc.fltindex + + #if we get this far, we didnt find a match. Add a new one and return + if uvok: + newvdesc = VertexDesc(vertex.co, vertex.no, face.uv[vfindex], self.nextvindex,cindex=cindex) + else: + newvdesc = VertexDesc(co=vertex.co, no=vertex.no,fltindex=self.nextvindex,cindex=cindex) + indexhash[vertex.index].append(newvdesc) + self.vertex_lst.append(newvdesc) + self.nextvindex = self.nextvindex + 1 + return newvdesc.fltindex + + + def request_texture_index(self, image): match = None for i in xrange(len(self.texture_lst)): - if self.texture_lst[i] != filename: + if self.texture_lst[i] != image: continue match = i break if match != None: return match else: - self.texture_lst.append(filename) + self.texture_lst.append(image) return len(self.texture_lst) - 1 def request_texture_filename(self, index): - return self.texture_lst[index] + return Blender.sys.expandpath(self.texture_lst[index].getFilename()) def texture_count(self): return len(self.texture_lst) @@ -239,7 +365,11 @@ class GlobalResourceRepository: return len(self.color_lst) def __init__(self): + #Vertex handling self.vertex_lst = [] + self.nextvindex = 0 + self.namehash = dict() + self.texture_lst = [] self.material_lst = [] self.color_lst = [[255, 255, 255]] @@ -253,7 +383,6 @@ class Node: if self.object: if options.verbose >= 2: print '\t' * level[0], self.name, self.object.type - level[0] += 1 for child in self.children: @@ -288,183 +417,530 @@ class Node: self.header.fw.write_ushort(length+5) # Length of record self.header.fw.write_string(name, length+1) # name + zero terminator + def write_comment(self,comment): + length = len(comment) + if length >= 65535: + comment = comment[:65530] + length = len(comment) + + pad = (length % 4) - 1 + if pad < 0: + pad = None + reclength = length + 5 + else: + reclength = length + 5 + pad + + self.header.fw.write_short(31) # Comment Opcode + self.header.fw.write_ushort(reclength) # Length of record is 4 + comment length + null terminator + pad + self.header.fw.write_string(comment,length+1) # comment + zero terminator + if pad: + self.header.fw.pad(pad) # pad to multiple of 4 bytes + # Initialization sets up basic tree structure. - def __init__(self, parent, header, object, object_lst): + def __init__(self, parent, header, object,props): + global options + self.header = header self.object = object if object: self.name = self.object.name - self.matrix = self.object.getMatrix('localspace') + if not options.export_transform: + oloc = Blender.Mathutils.Vector(object.getLocation('worldspace')) + vec = Blender.Mathutils.Vector(oloc[0] * options.scale, oloc[1] * options.scale, oloc[2] * options.scale) #scale + self.matrix = self.object.getMatrix('worldspace') * Blender.Mathutils.TranslationMatrix(vec - oloc) + else: + self.matrix = self.object.getMatrix('localspace') #do matrix mult here. + self.props = props + self.child_objects = self.header.parenthash[object.name] else: self.name = 'no name' self.matrix = None - + self.props = None + self.child_objects = self.header.child_objects + self.children = [] self.parent = parent if parent: parent.children.append(self) - - left_over = object_lst[:] - self.child_objects = [] - - # Add children to child list and remove from left_over list. - # Pop is faster then remove - i = len(object_lst) - while i: - i-=1 - if object_lst[i].parent == object: - self.child_objects.append(left_over.pop(i)) - # Spawn children. - self.has_object_child = False # For Database class. for child in self.child_objects: - if child.type == 'Mesh': - BlenderMesh(self, header, child, left_over) - self.has_object_child = True - else: # Treat all non meshes as emptys - BlenderEmpty(self, header, child, left_over) - + if(not child.restrictDisplay): + childprops = None + type = None + if not child.properties.has_key('FLT'): + if child.type == 'Empty': + if child.DupGroup: + childprops = FLTXRef.copy() + type = 63 + else: + childprops = FLTGroup.copy() + type = 2 + elif child.type == 'Mesh': + if self.header.childhash[child.name] or not child.parent: + childprops = FLTGroup.copy() + type = 2 + else: + childprops = FLTObject.copy() + type = 4 + + else: + childprops = dict() + for prop in child.properties['FLT']: + childprops[prop] = child.properties['FLT'][prop] + type = child.properties['FLT']['type'] + + if type in self.childtypes and type in alltypes: + Newnode = FLTNode(self,header,child,childprops,type) + if child.type == 'Mesh': + self.header.mnodes.append(Newnode) class FaceDesc: def __init__(self): self.vertex_index_lst = [] + self.mface = None self.texture_index = -1 self.material_index = -1 self.color_index = 127 - -class BlenderMesh(Node): - def blender_export(self): - Node.blender_export(self) - - mesh = self.object.getData() - mesh_hasuv = mesh.hasFaceUV() - # Gather materials and textures. - tex_index_lst = [] - mat_index_lst = [] - color_index_lst = [] - materials = mesh.getMaterials() - - if not materials: - materials = [Blender.Material.New()] - - for mat in materials: - # Gather Color. - if options.use_face_color: - color_index_lst.append(self.header.GRR.request_color_index(mat.getRGBCol())) + self.renderstyle = 0 + self.twoside = 0 + self.name = None #uses next FLT name if not set... fix resolution of conflicts! + + #Multi-Tex info. Dosn't include first UV Layer! + self.uvlayer = list() #list of list of tuples for UV coordinates. + self.images = list() #list of texture indices for seperate UV layers + self.mtex = list() + self.subface = None #can either be 'Push' or 'Pop' + +def edge_get_othervert(vert, edge): + if edge.v1 == vert: + return edge.v2 + elif edge.v2 == vert: + return edge.v1 + return None + +class FLTNode(Node): + def walkLoop(self, targetvert, startvert, startedge, edgelist, visited, vedges, closeloop): + loop = [targetvert] + + curvert = startvert + curedge = startedge + visited[curedge] = True + found = False + + while not found: + loop.append(curvert) + disk = vedges[curvert.index] + if not closeloop: + if len(disk) == 1: + visited[curedge] = True + break else: - color_index_lst.append(127) # white - # Gather Texture. - mtex_lst = mat.getTextures() - - index = -1 - mtex = mtex_lst[0] # Not doing multi-texturing at the moment. - if mtex != None: - tex = mtex_lst[0].tex - if tex != None: - image = tex.getImage() - if image != None: - filename = image.getFilename() - index = self.header.GRR.request_texture_index(filename) - - tex_index_lst.append(index) - - # Gather Material - mat_desc = MaterialDesc() - mat_desc.name = mat.name - mat_desc.alpha = mat.getAlpha() - mat_desc.shininess = mat.getSpec() * 64.0 # 2.0 => 128.0 - if options.use_mat_color: - mat_desc.diffuse = mat.getRGBCol() + if len(disk) < 2: #what? + visited[curedge] = True + return None + + if disk[0] == curedge: + curedge = disk[1] else: - mat_desc.diffuse = [1.0, 1.0, 1.0] + curedge = disk[0] + if curedge.v1.index == curvert.index: + curvert = curedge.v2 + else: + curvert = curedge.v1 - mat_desc.specular = mat.getSpecCol() - amb = mat.getAmb() - mat_desc.ambient = [amb, amb, amb] - emit = mat.getEmit() - mat_desc.emissive = [emit, emit, emit] + visited[curedge] = True + + if(curvert == targetvert): + found = True + + return loop + + def buildVertFaces(self,vertuse): + for vert in self.exportmesh.verts: + if vertuse[vert.index][0] == False and vertuse[vert.index][1] == 0: + face_desc = FaceDesc() + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, vert, 0,0,0)) + face_desc.renderstyle = 3 + face_desc.color_index = 227 + self.face_lst.append(face_desc) - mat_index_lst.append(self.header.GRR.request_material_index(mat_desc)) + def buildEdgeFaces(self,vertuse): + for edge in self.exportmesh.edges: + v1 = vertuse[edge.v1.index] + v2 = vertuse[edge.v2.index] + if v1[0] == False and v2[0] == False: + if v1[1] == 1 and v2[1] == 1: + face_desc = FaceDesc() + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 1, 0,0)) + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object, self.exportmesh, edge, 2, 0,0)) + face_desc.renderstyle = 3 + face_desc.color_index = 227 + self.face_lst.append(face_desc) + + + def vertwalk(self, startvert, loop, disk, visited): + visited[startvert] = True + for edge in disk[startvert]: + othervert = edge_get_othervert(startvert, edge) + if not visited[othervert]: + loop.append(othervert) + self.vertwalk(othervert,loop,disk,visited) + + def buildOpenFacesNew(self, vertuse): + wireverts = list() + wiredges = list() + visited = dict() + disk = dict() + loops = list() + + for edge in self.exportmesh.edges: + v1 = vertuse[edge.v1.index] + v2 = vertuse[edge.v2.index] + if v1[0] == False and v2[0] == False: + if v1[1] < 3 and v2[1] < 3: + wireverts.append(edge.v1) + wireverts.append(edge.v2) + wiredges.append(edge) + + #build disk data + for vert in wireverts: + visited[vert] = False + disk[vert] = list() + for edge in wiredges: + disk[edge.v1].append(edge) + disk[edge.v2].append(edge) + + #first pass: do open faces + for vert in wireverts: + if not visited[vert] and vertuse[vert.index][1] == 1: + visited[vert] = True + loop = [vert] + othervert = edge_get_othervert(vert, disk[vert][0]) + self.vertwalk(othervert, loop, disk, visited) + if len(loop) > 2: loops.append( ('Open', loop) ) + + for vert in wireverts: + if not visited[vert]: + visited[vert] = True + loop = [vert] + othervert = edge_get_othervert(vert,disk[vert][0]) + self.vertwalk(othervert, loop, disk, visited) + if len(loop) > 2: loops.append( ('closed', loop) ) + + #now go through the loops and append. + for l in loops: + (type, loop) = l + face_desc = FaceDesc() + for i,vert in enumerate(loop): + face_desc.vertex_index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,loop,i,0,0)) + if type == 'closed': + face_desc.renderstyle = 2 + else: + face_desc.renderstyle = 3 + face_desc.color_index = 227 + self.face_lst.append(face_desc) - # Faces described as lists of indices into the GRR's vertex_lst. - for face in mesh.faces: - - face_v = face.v # Faster access - - # Create vertex description list for each face. - if mesh_hasuv: - vertex_lst = [VertexDesc(v.co, v.no, face.uv[i]) for i, v in enumerate(face_v)] - else: - vertex_lst = [VertexDesc(v.co, v.no) for i, v in enumerate(face_v)] + def sortFLTFaces(self,a,b): + aindex = a.getProperty("FLT_ORIGINDEX") + bindex = b.getProperty("FLT_ORIGINDEX") + + if aindex > bindex: + return 1 + elif aindex < bindex: + return -1 + return 0 + + def buildNormFaces(self): + + global options + meshlayers = self.exportmesh.getUVLayerNames() + oldlayer = self.exportmesh.activeUVLayer + uvok = 0 + subfaceok = 0 + subfacelevel = 0 + + #special case + if self.exportmesh.faceUV and len(meshlayers) == 1: + uvok = 1 + elif self.exportmesh.faceUV and tex_layers[0] in meshlayers: + self.exportmesh.activeUVLayer = tex_layers[0] + uvok = 1 + + #Sort faces according to the subfaces/FLT indices + if "FLT_ORIGINDEX" in self.exportmesh.faces.properties and "FLT_SFLEVEL" in self.exportmesh.faces.properties: + exportfaces = list() + for face in self.exportmesh.faces: + exportfaces.append(face) + exportfaces.sort(self.sortFLTFaces) + subfaceok = 1 + else: + exportfaces = self.exportmesh.faces + # Faces described as lists of indices into the GRR's vertex_lst. + for face in exportfaces: + descs = list() + #first we export the face as normal index_lst = [] - for vert_desc in vertex_lst: - index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) - + face_v = face.verts + for i, v in enumerate(face_v): + index_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,face,i,uvok,0)) face_desc = FaceDesc() face_desc.vertex_index_lst = index_lst + face_desc.mface = face + descs.append(face_desc) - if face.materialIndex < len(materials): - face_desc.color_index = color_index_lst[face.materialIndex] - face_desc.texture_index = tex_index_lst[face.materialIndex] - face_desc.material_index = mat_index_lst[face.materialIndex] - else: - if options.verbose >=1: - print 'Warning: Missing material for material index. Materials will not be imported correctly. Fix by deleting abandoned material indices in Blender.' + #deal with subfaces + if subfaceok: + fsflevel = face.getProperty("FLT_SFLEVEL") + for face_desc in descs: + if fsflevel > subfacelevel: + face_desc.subface = 'Push' + subfacelevel = fsflevel + elif fsflevel < subfacelevel: + face_desc.subface = 'Pop' + subfacelevel = fsflevel + + + if uvok and (face.mode & Blender.Mesh.FaceModes.TWOSIDE): + face_desc.renderstyle = 1 + for face_desc in descs: + if "FLT_COL" in self.exportmesh.faces.properties: + color_index = face.getProperty("FLT_COL") +# if(color_index < 127): +# color_index = 127 #sanity check for face color indices + if(color_index == 0): + color_index = 127 + face_desc.color_index = color_index + else: + face_desc.color_index = 127 + if "FLT_ID" in self.exportmesh.faces.properties: + face_desc.name = face.getProperty("FLT_ID") #need better solution than this. + + self.face_lst.append(face_desc) + if uvok: + self.exportmesh.activeUVLayer = oldlayer - self.face_lst.append(face_desc) + def buildTexData(self): + + meshlayers = self.exportmesh.getUVLayerNames() + oldlayer = self.exportmesh.activeUVLayer + uvok = 0 + + if self.exportmesh.faceUV and len(meshlayers) == 1: + uvok = 1 + if self.exportmesh.faceUV and tex_layers[0] in meshlayers: + self.exportmesh.activeUVLayer = tex_layers[0] + uvok = 1 + + if uvok: + #do base layer. UVs have been stored on vertices directly already. + for i, face in enumerate(self.face_lst): + if face.mface: + mface = face.mface + image = mface.image + if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]: + index = self.header.GRR.request_texture_index(image) + else: + index = -1 + face.texture_index = index + + for i, face in enumerate(self.face_lst): + if face.mface: + mface_v = face.mface.v + for v in mface_v: + face.uvlayer.append([]) - # Export double sided face as 2 faces with opposite orientations. - if mesh_hasuv and face.mode & Blender.NMesh.FaceModes['TWOSIDE']: - # Create vertex description list for each face. they have a face mode, so we know they have a UV too. - vertex_lst = [VertexDesc(v.co, -v.no, face.uv[i]) for i, v in enumerate(face_v)] - vertex_lst.reverse() # Reversing flips the face. + for layername in tex_layers[1:]: + if layername in meshlayers: + self.exportmesh.activeUVLayer=layername + for i, face in enumerate(self.face_lst): + if face.mface: + + face.mtex.append(layername) + mface = face.mface + mface_v = mface.v + image = mface.image + + if image != None and mface.mode & Blender.Mesh.FaceModes["TEX"]: + index = self.header.GRR.request_texture_index(image) + face.images.append(index) + else: + face.images.append(-1) + + for j, v in enumerate(mface_v): + face.uvlayer[j].append(tuple(mface.uv[j])) + if uvok: + self.exportmesh.activeUVLayer = oldlayer + def blender_export(self): + global options + Node.blender_export(self) + if self.opcode == 111: + self.exportmesh = Blender.Mesh.New() + self.exportmesh.getFromObject(self.object.name) + + for vert in self.exportmesh.verts: + if not options.export_transform: + vec = vert.co + vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace')) - index_lst = [] - for vert_desc in vertex_lst: - index_lst.append(self.header.GRR.request_vertex_index(vert_desc)) + if options.scale != 1.0: + vert.co = vert.co * options.scale + + if("FLT_VCOL") in self.mesh.verts.properties: + for v in self.exportmesh.verts: + self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.exportmesh,v,0,0,v.getProperty("FLT_VCOL"))) + else: + for v in self.mesh.verts: + self.vert_lst.append(self.header.GRR.request_vertex_index(self.object,self.mesh,v,0,0,127)) + + + + elif self.mesh: + orig_mesh = self.object.getData(mesh=True) + self.exportmesh = Blender.Mesh.New() + default = None + + + if options.export_shading: + mods = self.object.modifiers + hasedsplit = False + for mod in mods: + if mod.type == Blender.Modifier.Types.EDGESPLIT: + hasedsplit = True + break + if not hasedsplit: + default = mods.append(Modifier.Types.EDGESPLIT) + default[Modifier.Settings.EDGESPLIT_ANGLE] = options.shading_default + default[Modifier.Settings.EDGESPLIT_FROM_ANGLE] = True + default[Modifier.Settings.EDGESPLIT_FROM_SHARP] = False + self.object.makeDisplayList() + + self.exportmesh.getFromObject(self.object.name) + + #recalculate vertex positions + for vert in self.exportmesh.verts: + if not options.export_transform: + vec = vert.co + vec = Blender.Mathutils.Vector(vec[0] * options.scale, vec[1] * options.scale, vec[2] * options.scale) #scale + vert.co = Blender.Mathutils.TranslationMatrix(vec) * (vert.co * self.object.getMatrix('worldspace')) - face_desc = FaceDesc() - face_desc.vertex_index_lst = index_lst - if face.materialIndex < len(materials): - face_desc.color_index = color_index_lst[face.materialIndex] - face_desc.texture_index = tex_index_lst[face.materialIndex] - face_desc.material_index = mat_index_lst[face.materialIndex] - else: - if options.verbose >=1: - print 'Error: No material for material index. Delete abandoned material indices in Blender.' - - self.face_lst.append(face_desc) + if options.scale != 1.0: + vert.co = vert.co * options.scale + + flipped = self.object.getMatrix('worldspace').determinant() + + if not options.export_transform: + self.exportmesh.calcNormals() + + + if default: + #remove modifier from list + mods.remove(default) + self.object.makeDisplayList() + + #build some adjacency data + vertuse = list() + wiredges = list() + openends = list() + for v in self.exportmesh.verts: + vertuse.append([False,0]) + + #build face incidence data + for face in self.exportmesh.faces: + for i, v in enumerate(face.verts): + vertuse[v.index][0] = True + + for edge in self.exportmesh.edges: #count valance + vertuse[edge.v1.index][1] = vertuse[edge.v1.index][1] + 1 + vertuse[edge.v2.index][1] = vertuse[edge.v2.index][1] + 1 + + #create all face types + self.buildVertFaces(vertuse) + self.buildEdgeFaces(vertuse) + self.buildOpenFacesNew(vertuse) + self.buildNormFaces() + self.buildTexData() + + if not options.export_transform: + if flipped < 0: + for vdesc in self.header.GRR.vertex_lst: + vdesc.accum = 0 + for face in self.face_lst: + face.vertex_index_lst.reverse() + for vert in face.vertex_index_lst: + self.header.GRR.vertex_lst[vert].accum = 1 + + for vdesc in self.header.GRR.vertex_lst: + if vdesc.accum: + vdesc.nx = vdesc.nx * -1 + vdesc.ny = vdesc.ny * -1 + vdesc.nz = vdesc.nz * -1 + def write_faces(self): + sublevel = 0 for face_desc in self.face_lst: - face_name = self.header.GRR.new_face_name() + if face_desc.name: + face_name = face_desc.name + else: + face_name = self.header.GRR.new_face_name() + #grab the alpha value. + alpha = 0 + if face_desc.texture_index > -1: + try: + typestring = os.path.splitext(self.header.GRR.texture_lst[face_desc.texture_index].getFilename())[1] + if typestring == '.inta' or typestring == '.rgba': + alpha = 1 + except: + pass + + if not alpha: + for index in face_desc.images: + try: + typestring = os.path.splitext(self.header.GRR.texture_lst[index].getFilename())[1] + if typestring == '.inta' or typestring == '.rgba': + alpha = 1 + except: + pass + + if face_desc.subface: + if face_desc.subface == 'Push': + self.header.fw.write_short(19) + self.header.fw.write_ushort(4) + sublevel += 1 + else: + self.header.fw.write_short(20) + self.header.fw.write_ushort(4) + sublevel -= 1 self.header.fw.write_short(5) # Face opcode self.header.fw.write_ushort(80) # Length of record self.header.fw.write_string(face_name, 8) # ASCII ID self.header.fw.write_int(-1) # IR color code - self.header.fw.write_short(0) # Relative priority - self.header.fw.write_char(0) # Draw type + self.header.fw.write_short(0) # Relative priority + self.header.fw.write_char(face_desc.renderstyle) # Draw type self.header.fw.write_char(0) # Draw textured white. self.header.fw.write_ushort(0) # Color name index self.header.fw.write_ushort(0) # Alt color name index self.header.fw.write_char(0) # Reserved - self.header.fw.write_char(1) # Template + self.header.fw.write_char(alpha) # Template self.header.fw.write_short(-1) # Detail tex pat index self.header.fw.write_short(face_desc.texture_index) # Tex pattern index self.header.fw.write_short(face_desc.material_index) # material index self.header.fw.write_short(0) # SMC code - self.header.fw.write_short(0) # Feature code + self.header.fw.write_short(0) # Feature code self.header.fw.write_int(0) # IR material code self.header.fw.write_ushort(0) # transparency 0 = opaque self.header.fw.write_uchar(0) # LOD generation control self.header.fw.write_uchar(0) # line style index - self.header.fw.write_int(0x00000000) # Flags + self.header.fw.write_int(0) # Flags self.header.fw.write_uchar(2) # Light mode + #self.header.fw.write_uchar(3) # Light mode + self.header.fw.pad(7) # Reserved - self.header.fw.write_uint(-1) # Packed color - self.header.fw.write_uint(-1) # Packed alt color + self.header.fw.write_uint(0) # Packed color + self.header.fw.write_uint(0) # Packed alt color self.header.fw.write_short(-1) # Tex map index self.header.fw.write_short(0) # Reserved self.header.fw.write_uint(face_desc.color_index) # Color index @@ -473,7 +949,24 @@ class BlenderMesh(Node): self.header.fw.write_short(-1) # Shader index self.write_longid(face_name) - + + + #Write Multitexture field if appropriate + mtex = len(face_desc.mtex) + if mtex: + uvmask = 0 + for layername in face_desc.mtex: + mask = mtexmasks[tex_layers.index(layername)-1] + uvmask |= mask + self.header.fw.write_ushort(52) # MultiTexture Opcode + self.header.fw.write_ushort(8 + (mtex * 8)) # Length + self.header.fw.write_uint(uvmask) # UV mask + for i in xrange(mtex): + self.header.fw.write_ushort(face_desc.images[i]) # Tex pattern index + self.header.fw.write_ushort(0) # Tex effect + self.header.fw.write_ushort(0) # Tex Mapping index + self.header.fw.write_ushort(0) # Tex data. User defined + self.write_push() # Vertex list record @@ -484,72 +977,95 @@ class BlenderMesh(Node): for vert_index in face_desc.vertex_index_lst: # Offset into vertex palette self.header.fw.write_int(vert_index*64+8) - + + #UV list record + if mtex: + #length = 8 + (numverts * multitex * 8) + self.header.fw.write_ushort(53) # UV List Ocode + self.header.fw.write_ushort(8 + (num_verts*mtex*8)) # Record Length + self.header.fw.write_uint(uvmask) # UV mask + for i, vert_index in enumerate(face_desc.vertex_index_lst): + for uv in face_desc.uvlayer[i]: + self.header.fw.write_float(uv[0]) #U coordinate + self.header.fw.write_float(uv[1]) #V coordinate self.write_pop() + #clean up faces at the end of meshes.... + if sublevel: + self.header.fw.write_short(20) + self.header.fw.write_ushort(4) + + def write_lps(self): + # Vertex list record + self.write_push() + self.header.fw.write_short(72) # Vertex list opcode + num_verts = len(self.vert_lst) + self.header.fw.write_ushort(4*num_verts+4) # Length of record + for vert_index in self.vert_lst: + # Offset into vertex palette + self.header.fw.write_int(vert_index*64+8) + self.write_pop() def write(self): - if self.open_flight_type == 'Object': - self.header.fw.write_short(4) # Object opcode - self.header.fw.write_ushort(28) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(16) - - self.write_longid(self.name) + self.header.fw.write_short(self.opcode) + self.header.fw.write_ushort(recordlen[self.opcode]) + exportdict = FLT_Records[self.opcode].copy() + for key in exportdict.keys(): + if self.props.has_key(key): + exportdict[key] = self.props[key] + + if self.opcode == 63 and options.externalspath: + try: + exportdict['3t200!filename'] = os.path.join(options.externalspath,self.object.DupGroup.name+'.flt') + self.header.xrefnames.append(self.object.DupGroup.name) + except: + pass + + for key in records[self.opcode]: + (type,length,propname) = records[self.opcode][key] + write_prop(self.header.fw,type,exportdict[propname],length) + + if self.props.has_key('comment'): + self.write_comment(self.props['comment']) + self.write_longid(self.name) #fix this! + + if options.export_transform or self.opcode == 63: + #writing transform matrix.... self.write_matrix() - + + if self.opcode == 111: + self.write_lps() + elif self.face_lst != [] or self.children: + self.write_push() if self.face_lst != []: - self.write_push() - + #self.write_push() self.write_faces() + #self.write_pop() - self.write_pop() - else: - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(32) - - self.write_longid(self.name) - - # Because a group can contain faces as well as children. - self.write_push() - - self.write_faces() - - for child in self.children: - child.write() - + if self.children: + #self.write_push() + for child in self.children: + child.write() + #self.write_pop() self.write_pop() - - def __init__(self, parent, header, object, object_lst): - Node.__init__(self, parent, header, object, object_lst) - self.face_lst = [] - - if self.children: - self.open_flight_type= 'Group' - else: # Empty list. - self.open_flight_type = 'Object' - -class BlenderEmpty(Node): - def write(self): - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string(self.name, 8) # ASCII ID - self.header.fw.pad(32) - - self.write_longid(self.name) - - self.write_matrix() + def __init__(self, parent, header, object,props,type): + self.opcode = type #both these next two lines need to be in the node class.... + self.childtypes = childtypes[self.opcode] + Node.__init__(self, parent, header, object,props) + self.face_lst = [] + self.vert_lst = [] #for light points. + self.mesh = None + self.uvlayer = 0 + self.flipx = False + self.flipy = False + self.flipz = False - if self.children: # != [] - self.write_push() - - for child in self.children: - child.write() - self.write_pop() + if self.object.type == 'Mesh': + self.mesh = self.object.getData(mesh=True) + if(self.mesh.faceUV): + self.uvLayer = len(self.mesh.getUVLayerNames()) class Database(Node): def write_header(self): @@ -568,8 +1084,19 @@ class Database(Node): self.fw.write_int(0) # projection type, 0 = flat earth self.fw.pad(30) self.fw.write_short(1) # double precision - self.fw.pad(140) + self.fw.write_int(100) # database origin type + self.fw.pad(88) + try: + self.fw.write_double(self.header.scene.properties['FLT']['origin lat']) #database origin lattitude + except: + self.fw.write_double(0) + try: + self.fw.write_double(self.header.scene.properties['FLT']['origin lon']) #database origin longitude + except: + self.fw.write_double(0) + self.fw.pad(32) self.fw.write_int(0) # ellipsoid model, 0 = WSG 1984 + self.fw.pad(52) def write_vert_pal(self): @@ -579,14 +1106,13 @@ class Database(Node): self.fw.write_short(67) # Vertex palette opcode. self.fw.write_short(8) # Length of record self.fw.write_int(self.GRR.vertex_count() * 64 + 8) # Length of everything. - # Write records for individual vertices. for i in xrange(self.GRR.vertex_count()): desc = self.GRR.request_vertex_desc(i) self.fw.write_short(70) # Vertex with color normal and uv opcode. self.fw.write_ushort(64) # Length of record - self.fw.write_ushort(0) # Color name index - self.fw.write_short(0x2000) # Flags set to no color + self.fw.write_ushort(0) # Color name index + self.fw.write_short(0x20000000) # Flags self.fw.write_double(desc.x) self.fw.write_double(desc.y) self.fw.write_double(desc.z) @@ -595,16 +1121,19 @@ class Database(Node): self.fw.write_float(desc.nz) self.fw.write_float(desc.u) self.fw.write_float(desc.v) - self.fw.pad(12) + self.fw.pad(4) + self.fw.write_uint(desc.cindex) + self.fw.pad(4) def write_tex_pal(self): if options.verbose >= 2: print 'Writing texture palette.' # Write record for texture palette - for i in xrange(self.GRR.texture_count()): + for i, img in enumerate(self.GRR.texture_lst): + filename = tex_files[img.name] self.fw.write_short(64) # Texture palette opcode. self.fw.write_short(216) # Length of record - self.fw.write_string(self.GRR.request_texture_filename(i), 200) # Filename + self.fw.write_string(filename, 200) # Filename self.fw.write_int(i) # Texture index self.fw.write_int(0) # X self.fw.write_int(0) # Y @@ -641,13 +1170,17 @@ class Database(Node): self.fw.write_short(32) # Color palette opcode. self.fw.write_short(4228) # Length of record self.fw.pad(128) - count = self.GRR.color_count() + try: + cpalette = self.scene.properties['FLT']['Color Palette'] + except: + cpalette = defaultp.pal + count = len(cpalette) for i in xrange(count): - col = self.GRR.request_max_color(i) - self.fw.write_uchar(255) # alpha - self.fw.write_uchar(col[2]) # b - self.fw.write_uchar(col[1]) # g - self.fw.write_uchar(col[0]) # r + color = struct.unpack('>BBBB',struct.pack('>I',cpalette[i])) + self.fw.write_uchar(color[3]) # alpha + self.fw.write_uchar(color[2]) # b + self.fw.write_uchar(color[1]) # g + self.fw.write_uchar(color[0]) # r self.fw.pad(max(4096-count*4, 0)) def write(self): @@ -657,66 +1190,428 @@ class Database(Node): self.write_mat_pal() self.write_col_pal() - # Wrap everything in a group if it has an object child. - if self.has_object_child: - self.header.fw.write_short(2) # Group opcode - self.header.fw.write_ushort(44) # Length of record - self.header.fw.write_string('g1', 8) # ASCII ID - self.header.fw.pad(32) - self.write_push() - - for child in self.children: - child.write() - + + if options.flattenmesh: + self.mnodes.reverse() + for mnode in self.mnodes: + mnode.write_faces() + else: + for child in self.children: + child.write() self.write_pop() + + def export_textures(self,texturepath): + for i in xrange(self.GRR.texture_count()): + texture = self.GRR.texture_lst[i] + + if options.copy_textures: + filename = os.path.normpath(os.path.join(options.texturespath, os.path.basename(self.GRR.request_texture_filename(i)))) + else: + filename = os.path.normpath(self.GRR.request_texture_filename(i)) + + tex_files[texture.name] = filename + def blender_export(self): + Node.blender_export(self) + self.export_textures(self) + return self.xrefnames def __init__(self, scene, fw): self.fw = fw + self.opcode = 1 + self.childtypes = [73,14,2,63] self.scene = scene - self.all_objects = list(scene.objects) - self.GRR = GlobalResourceRepository() + self.childhash = dict() + self.parenthash = dict() + self.child_objects = list() + self.mnodes = list() + self.xrefnames = list() + for i in self.scene.objects: + self.parenthash[i.name] = list() + self.childhash[i.name] = False + for i in self.scene.objects: + if i.parent: + self.childhash[i.parent.name] = True + self.parenthash[i.parent.name].append(i) + else: + self.child_objects.append(i) - Node.__init__(self, None, self, None, self.all_objects) + self.GRR = GlobalResourceRepository() + Node.__init__(self, None, self, None,None) -def fs_callback(filename): - Blender.Window.WaitCursor(True) - - if Blender.sys.exists(filename): - r = Blender.Draw.PupMenu('Overwrite ' + filename + '?%t|Yes|No') - if r != 1: - if options.verbose >= 1: - print 'Export cancelled.' - return - - time1 = Blender.sys.time() # Start timing +def write_attribute_files(): + for imgname in tex_files: + blentex = Blender.Image.Get(imgname) + exportdict = FLT_Records['Image'].copy() + + if blentex.properties.has_key('FLT'): + for key in exportdict.keys(): + if blentex.properties.has_key(key): + exportdict[key] = blentex.properties['FLT'][key] + + # ClampX/Y override + if blentex.clampX: + exportdict['11i!WrapU'] = 1 + if blentex.clampY: + exportdict['12i!WrapV'] = 1 + + exportdict['16i!Enviorment'] = 0 + + # File type + typecode = 0 + try: + typestring = os.path.splitext(blentex.getFilename())[1] + + if typestring == '.rgba': + typecode = 5 + elif typestring == '.rgb': + typecode = 4 + elif typestring == '.inta': + typecode = 3 + elif typestring == '.int': + typecode = 2 + except: + pass + + exportdict['7i!File Format'] = typecode + + fw = FltOut(tex_files[imgname] + '.attr') + size = blentex.getSize() + fw.write_int(size[0]) + fw.write_int(size[1]) + for key in records['Image']: + (type,length,propname) = records['Image'][key] + write_prop(fw,type,exportdict[propname],length) + fw.close_file() + +#globals used by the scene export function +exportlevel = None +xrefsdone = None + +def dbexport_internal(scene): + global exportlevel + global xrefsdone + global options + + if exportlevel == 0 or not options.externalspath: + fname = os.path.join(options.basepath,scene.name + '.flt') + else: + fname = os.path.join(options.externalspath,scene.name + '.flt') - fw = FltOut(filename) - - db = Database(Blender.Scene.GetCurrent(), fw) + fw = FltOut(fname) + db = Database(scene,fw) if options.verbose >= 1: - print 'Pass 1: Exporting from Blender.\n' - - db.blender_export() + print 'Pass 1: Exporting ', scene.name,'.flt from Blender.\n' + xreflist = db.blender_export() if options.verbose >= 1: - print 'Pass 2: Writing %s\n' % filename - + print 'Pass 2: Writing %s\n' % fname db.write() - fw.close_file() + + if options.doxrefs: + for xname in xreflist: + try: + xrefscene = Blender.Scene.Get(xname) + except: + xrefscene = None + if xrefscene and xname not in xrefsdone: + xrefsdone.append(xname) + exportlevel+=1 + dbexport_internal(xrefscene) + exportlevel-=1 + return fname +#main database export function +def dbexport(): + global exportlevel + global xrefsdone + exportlevel = 0 + xrefsdone = list() + + Blender.Window.WaitCursor(True) + time1 = Blender.sys.time() # Start timing + if options.verbose >= 1: + print '\nOpenFlight Exporter' + print 'Version:', __version__ + print 'Author: Greg MacDonald, Geoffrey Bantle' + print __url__[2] + print + + fname = dbexport_internal(Blender.Scene.GetCurrent()) + if options.verbose >=1: print 'Done in %.4f sec.\n' % (Blender.sys.time() - time1) - Blender.Window.WaitCursor(False) + + #optional: Copy textures + if options.copy_textures: + for imgname in tex_files: + #Check to see if texture exists in target directory + if not os.path.exists(tex_files[imgname]): + #Get original Blender file name + origpath = Blender.sys.expandpath(Blender.Image.Get(imgname).getFilename()) + #copy original to new + shutil.copyfile(origpath,tex_files[imgname]) + + #optional: Write attribute files + if options.write_attrib_files: + write_attribute_files() + + if options.xapp: + cmd= options.xappath + " " + fname + status = os.system(cmd) + + +#Begin UI code +FLTExport = None +FLTClose = None +FLTLabel = None + +FLTBaseLabel = None +FLTTextureLabel = None +FLTXRefLabel = None + +FLTBaseString = None +FLTTextureString = None +FLTXRefString = None + +FLTBasePath = None +FLTTexturePath = None +FLTXRefPath = None + +FLTShadeExport = None +FLTShadeDefault = None + +FLTCopyTex = None +FLTDoXRef = None +FLTGlobal = None + +FLTScale = None + +FLTXAPP = None +FLTXAPPath = None +FLTXAPPString = None +FLTXAPPLabel = None +FLTXAPPChooser = None + +FLTAttrib = None + +def setshadingangle(ID,val): + global options + options.shading_default = val +def setBpath(fname): + global options + options.basepath = os.path.dirname(fname) + #update xref and textures path too.... + if(os.path.exists(os.path.join(options.basepath,'externals'))): + options.externalspath = os.path.join(options.basepath,'externals') + if(os.path.exists(os.path.join(options.texturespath,'textures'))): + options.texturespath = os.path.join(options.basepath,'textures') +def setexportscale(ID,val): + global options + options.scale = val + +def setTpath(fname): + global options + options.texturespath = os.path.dirname(fname) +def setXpath(fname): + global options + options.externalspath = os.path.dirname(fname) +def setXApath(fname): + global options + options.xappath = fname + d = dict() + d['xappath'] = options.xappath + Blender.Registry.SetKey('flt_export', d, 1) +def event(evt, val): + x = 1 +def but_event(evt): + global options + + global FLTExport + global FLTClose + global FLTLabel + + global FLTBaseLabel + global FLTTextureLabel + global FLTXRefLabel + + global FLTBaseString + global FLTTextureString + global FLTXRefString + + global FLTBasePath + global FLTTexturePath + global FLTXRefPath + + global FLTShadeExport + global FLTShadeDefault + + global FLTCopyTex + global FLTDoXRef + global FLTGlobal + + global FLTScale + + + global FLTXAPP + global FLTXAPPath + global FLTXAPPString + global FLTXAPPLabel + global FLTXAPPChooser + + global FLTAttrib + + + + #choose base path for export + if evt == 4: + Blender.Window.FileSelector(setBpath, "DB Root", options.basepath) + + #choose XREF path + if evt == 6: + Blender.Window.FileSelector(setXpath,"DB Externals",options.externalspath) + + #choose texture path + if evt == 8: + Blender.Window.FileSelector(setTpath,"DB Textures",options.texturespath) + + #export shading toggle + if evt == 9: + options.export_shading = FLTShadeExport.val + #export Textures + if evt == 11: + options.copy_textures = FLTCopyTex.val + #export XRefs + if evt == 13: + options.doxrefs = FLTDoXRef.val + #export Transforms + if evt == 12: + options.export_transform = FLTGlobal.val + + if evt == 14: + options.xapp = FLTXAPP.val + if evt == 16: + Blender.Window.FileSelector(setXApath,"External Application",options.xappath) + if evt == 20: + options.write_attrib_files = FLTAttrib.val + + #Export DB + if evt == 1: + dbexport() + + #exit + if evt == 2: + Draw.Exit() + +from Blender.BGL import * +from Blender import Draw +def gui(): + + global options + + global FLTExport + global FLTClose + global FLTLabel + + global FLTBaseLabel + global FLTTextureLabel + global FLTXRefLabel + + global FLTBaseString + global FLTTextureString + global FLTXRefString + + global FLTBasePath + global FLTTexturePath + global FLTXRefPath + + global FLTShadeExport + global FLTShadeDefault + + global FLTCopyTex + global FLTDoXRef + global FLTGlobal + + global FLTScale + + global FLTXAPP + global FLTXAPPath + global FLTXAPPString + global FLTXAPPLabel + global FLTXAPPChooser + + global FLTAttrib + + glClearColor(0.880,0.890,0.730,1.0 ) + glClear(GL_COLOR_BUFFER_BIT) + + areas = Blender.Window.GetScreenInfo() + curarea = Blender.Window.GetAreaID() + curRect = None + + for area in areas: + if area['id'] == curarea: + curRect = area['vertices'] + break + + width = curRect[2] - curRect[0] + height = curRect[3] - curRect[1] + #draw from top to bottom.... + cx = 50 + #Draw Title Bar... + #glRasterPos2d(cx, curRect[3]-100) + #FLTLabel = Draw.Text("FLT Exporter V2.0",'large') + cy = height - 80 + + #base path + FLTBaseLabel = Draw.Label("Base Path:",cx,cy,100,20) + FLTBaseString = Draw.String("",3,cx+100,cy,300,20,options.basepath,255,"Folder to export to") + FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder") + + cy = cy-40 + + #externals path + FLTXRefLabel = Draw.Label("XRefs:",cx,cy,100,20) + FLTXRefString = Draw.String("",5,cx+100,cy,300,20,options.externalspath,255,"Folder for external references") + FLTXRefChooser = Draw.PushButton("...",6,cx+400,cy,20,20,"Choose Folder") + cy = cy-40 + #Textures path + FLTTextureLabel = Draw.Label("Textures:",cx,cy,100,20) + FLTTextureString = Draw.String("",7,cx+100,cy,300,20,options.texturespath,255,"Folder for texture files") + FLTTextureChooser = Draw.PushButton("...",8,cx+400,cy,20,20,"Choose Folder") + cy=cy-40 + #External application path + FLTXAPPLabel = Draw.Label("XApp:",cx,cy,100,20) + FLTXAPPString = Draw.String("",15,cx+100,cy,300,20,options.xappath,255,"External application to launch when done") + FLTXAPPChooser = Draw.PushButton("...",16,cx+400, cy,20,20,"Choose Folder") + + cy = cy-60 + #Shading Options + FLTShadeExport = Draw.Toggle("Default Shading",9,cx,cy,100,20,options.export_shading,"Turn on export of custom shading") + FLTShadDefault = Draw.Number("",10,cx + 120,cy,100,20,options.shading_default,0.0,180.0,"Default shading angle for objects with no custom shading assigned",setshadingangle) + + cy = cy-40 + FLTScale = Draw.Number("Export Scale",14,cx,cy,220,20,options.scale,0.0,100.0,"Export scaling factor",setexportscale) + + cy = cy-40 + #misc Options + FLTCopyTex = Draw.Toggle("Copy Textures",11,cx,cy,220,20,options.copy_textures,"Copy textures to folder indicated above") + cy = cy-40 + FLTGlobal = Draw.Toggle("Export Transforms",12,cx,cy,220,20,options.export_transform,"If unchecked, Global coordinates are used (recommended)") + cy = cy-40 + FLTDoXRef = Draw.Toggle("Export XRefs", 13,cx,cy,220,20,options.doxrefs,"Export External references (only those below current scene!)") + cy = cy-40 + FLTXAPP = Draw.Toggle("Launch External App", 14, cx,cy,220,20,options.xapp,"Launch External Application on export") + cy = cy-40 + FLTAttrib = Draw.Toggle("Write Attribute Files", 20, cx, cy, 220,20,options.write_attrib_files, "Write Texture Attribute files") + #FLTXAPPATH = Draw.String("",15,cx,cy,300,20,options.xappath,255,"External application path") + -if options.verbose >= 1: - print '\nOpenFlight Exporter' - print 'Version:', __version__ - print 'Author: Greg MacDonald' - print __url__[2] - print + #Draw export/close buttons + FLTExport = Draw.PushButton("Export",1,cx,20,100,20,"Export to FLT") + FLTClose = Draw.PushButton("Close", 2, cx+120,20,100,20,"Close window") -fname = Blender.sys.makename(ext=".flt") -Blender.Window.FileSelector(fs_callback, "Export OpenFlight v16.0", fname) + +Draw.Register(gui,event,but_event)
\ No newline at end of file diff --git a/release/scripts/flt_filewalker.py b/release/scripts/flt_filewalker.py index 442c9728e91..4a9b86c45d2 100644 --- a/release/scripts/flt_filewalker.py +++ b/release/scripts/flt_filewalker.py @@ -17,6 +17,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +__bpydoc__ ="""\ +File read/write module used by OpenFlight I/O and tool scripts. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. +""" + import Blender from struct import * import re @@ -199,7 +204,9 @@ class FltOut: self.file.close() def __init__(self, filename): - self.file = open(filename, 'wb') + self.file = open(filename, 'wb') + self.filename = filename + class FileFinder: def add_file_to_search_path(self, filename): diff --git a/release/scripts/flt_import.py b/release/scripts/flt_import.py index ca0db650447..220fc9f355c 100644 --- a/release/scripts/flt_import.py +++ b/release/scripts/flt_import.py @@ -1,72 +1,26 @@ #!BPY """ Registration info for Blender menus: Name: 'OpenFlight (.flt)...' -Blender: 238 +Blender: 245 Group: 'Import' Tip: 'Import OpenFlight (.flt)' """ -__author__ = "Greg MacDonald, Campbell Barton" -__version__ = "1.2 10/20/05" +__author__ = "Greg MacDonald, Campbell Barton, Geoffrey Bantle" +__version__ = "2.0 11/21/07" __url__ = ("blender", "elysiun", "Author's homepage, http://sourceforge.net/projects/blight/") __bpydoc__ = """\ This script imports OpenFlight files into Blender. OpenFlight is a registered trademark of MultiGen-Paradigm, Inc. -Run from "File->Import" menu. - -Options are available from Blender's "Scripts Config Editor," accessible through -the "Scripts->System" menu from the scripts window. - -All global_prefs are toggle switches that let the user choose what is imported. Most -are straight-forward, but one option could be a source of confusion. The -"Diffuse Color From Face" option when set pulls the diffuse color from the face -colors. Otherwise the diffuse color comes from the material. What may be -confusing is that this global_prefs only works if the "Diffuse Color" option is set. - -New Features:<br> -* Importer is 14 times faster.<br> -* External triangle module is no longer required, but make sure the importer -has a 3d View screen open while its running or triangulation won't work.<br> -* Should be able to import all versions of flight files. - -Features:<br> -* Heirarchy retained.<br> -* First texture imported.<br> -* Colors imported from face or material.<br> -* LOD seperated out into different layers.<br> -* Asks for location of unfound textures or external references.<br> -* Searches Blender's texture directory in the user preferences panel.<br> -* Triangles with more than 4 verts are triangulated if the Triangle python -module is installed.<br> -* Matrix transforms imported.<br> -* External references to whole files are imported. - -Things To Be Aware Of:<br> -* Each new color and face attribute creates a new material and there are only a maximum of 16 -materials per object.<br> -* For triangulated faces, normals must be recomputed outward manually by typing -CTRL+N in edit mode.<br> -* You can change global_prefs only after an initial import.<br> -* External references are imported as geometry and will be exported that way.<br> -* A work around for not using the Triangle python module is to simply to -triangulate in Creator before importing. This is only necessary if your -model contains 5 or more vertices.<br> -* You have to manually blend the material color with the texture color. - -What's Not Handled:<br> -* Special texture repeating modes.<br> -* Replications and instancing.<br> -* Comment and attribute fields.<br> -* Light points.<br> -* Animations.<br> -* External references to a node within a file.<br> -* Multitexturing.<br> -* Vetex colors.<br> +Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/Import/openflight_flt + +Note: This file is a grab-bag of old and new code. It needs some cleanup still. """ # flt_import.py is an OpenFlight importer for blender. -# Copyright (C) 2005 Greg MacDonald +# Copyright (C) 2005 Greg MacDonald, 2007 Blender Foundation # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -87,15 +41,33 @@ import os import BPyMesh import BPyImage import flt_filewalker +import flt_properties +reload(flt_properties) +from flt_properties import * -Vector= Blender.Mathutils.Vector +#Globals. Should Clean these up and minimize their usage. -def col_to_gray(c): - return 0.3*c[0] + 0.59*c[1] + 0.11*c[2] +typecodes = ['c','C','s','S','i','I','f','d','t'] +records = dict() + +FLTBaseLabel = None +FLTBaseString = None +FLTBaseChooser = None +FLTExport = None +FLTClose = None +FLTDoXRef = None +FLTScale = None +FLTShadeImport = None +FLTAttrib = None + +Vector= Blender.Mathutils.Vector +FLOAT_TOLERANCE = 0.01 +FF = flt_filewalker.FileFinder() +current_layer = 0x01 global_prefs = dict() -global_prefs['verbose']= 1 +global_prefs['verbose']= 4 global_prefs['get_texture'] = True global_prefs['get_diffuse'] = True global_prefs['get_specular'] = False @@ -105,8 +77,41 @@ global_prefs['get_ambient'] = False global_prefs['get_shininess'] = True global_prefs['color_from_face'] = True global_prefs['fltfile']= '' +global_prefs['smoothshading'] = 1 +global_prefs['doxrefs'] = 1 +global_prefs['scale'] = 1.0 +global_prefs['attrib'] = 0 msg_once = False +throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63,111] # Opcodes that indicate its time to return control to parent. +do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] + +#Process FLT record definitions +for record in FLT_Records: + props = dict() + for prop in FLT_Records[record]: + position = '' + slice = 0 + (format,name) = prop.split('!') + for i in format: + if i not in typecodes: + position = position + i + slice = slice + 1 + else: + break + type = format[slice:] + length = type[1:] + if len(length) == 0: + length = 1 + else: + type = type[0] + length = int(length) + + props[int(position)] = (type,length,prop) + records[record] = props + +def col_to_gray(c): + return 0.3*c[0] + 0.59*c[1] + 0.11*c[2] class MaterialDesc: # Was going to use int(f*1000.0) instead of round(f,3), but for some reason # round produces better results, as in less dups. @@ -185,16 +190,14 @@ class VertexDesc: self.y = 0.0 self.z = 0.0 - ''' # IGNORE_NORMALS + self.nx = 0.0 - self.ny = 1.0 + self.ny = 0.0 self.nz = 0.0 - ''' + self.uv= Vector(0,0) - self.r = 1.0 - self.g = 1.0 - self.b = 1.0 - self.a = 1.0 + self.cindex = 127 #default/lowest + self.cnorm = False class LightPointAppDesc: def make_key(self): @@ -222,7 +225,7 @@ class LightPointAppDesc: self.props.update({'LOD scale': 0.0}) class GlobalResourceRepository: - def request_lightpoint_app(self, desc): + def request_lightpoint_app(self, desc, scene): match = self.light_point_app.get(desc.make_key()) if match: @@ -231,7 +234,7 @@ class GlobalResourceRepository: # Create empty and fill with properties. name = desc.props['type'] + ': ' + desc.props['id'] object = Blender.Object.New('Empty', name) - scene.link(object) + scene.objects.link(object) object.Layers= current_layer object.sel= 1 @@ -306,6 +309,9 @@ class GlobalResourceRepository: return tex def __init__(self): + + #list of scenes xrefs belong to. + self.xrefs = dict() # material self.mat_dict = dict() mat_lst = Blender.Material.Get() @@ -341,108 +347,6 @@ class GlobalResourceRepository: # light point self.light_point_app = dict() -# Globals -GRR = GlobalResourceRepository() -FF = flt_filewalker.FileFinder() -scene = Blender.Scene.GetCurrent() # just hope they dont chenge scenes once the file selector pops up. -current_layer = 0x01 - - -# Opcodes that indicate its time to return control to parent. -throw_back_opcodes = [2, 73, 4, 11, 96, 14, 91, 98, 63] -do_not_report_opcodes = [76, 78, 79, 80, 81, 82, 94, 83, 33, 112, 100, 101, 102, 97, 31, 103, 104, 117, 118, 120, 121, 124, 125] - -opcode_name = { 0: 'db', - 1: 'head', - 2: 'grp', - 4: 'obj', - 5: 'face', - 10: 'push', - 11: 'pop', - 14: 'dof', - 19: 'push sub', - 20: 'pop sub', - 21: 'push ext', - 22: 'pop ext', - 23: 'cont', - 31: 'comment', - 32: 'color pal', - 33: 'long id', - 49: 'matrix', - 50: 'vector', - 52: 'multi-tex', - 53: 'uv lst', - 55: 'bsp', - 60: 'rep', - 61: 'inst ref', - 62: 'inst def', - 63: 'ext ref', - 64: 'tex pal', - 67: 'vert pal', - 68: 'vert w col', - 69: 'vert w col & norm', - 70: 'vert w col, norm & uv', - 71: 'vert w col & uv', - 72: 'vert lst', - 73: 'lod', - 74: 'bndin box', - 76: 'rot edge', - 78: 'trans', - 79: 'scl', - 80: 'rot pnt', - 81: 'rot and/or scale pnt', - 82: 'put', - 83: 'eyepoint & trackplane pal', - 84: 'mesh', - 85: 'local vert pool', - 86: 'mesh prim', - 87: 'road seg', - 88: 'road zone', - 89: 'morph vert lst', - 90: 'link pal', - 91: 'snd', - 92: 'rd path', - 93: 'snd pal', - 94: 'gen matrix', - 95: 'txt', - 96: 'sw', - 97: 'line styl pal', - 98: 'clip reg', - 100: 'ext', - 101: 'light src', - 102: 'light src pal', - 103: 'reserved', - 104: 'reserved', - 105: 'bndin sph', - 106: 'bndin cyl', - 107: 'bndin hull', - 108: 'bndin vol cntr', - 109: 'bndin vol orient', - 110: 'rsrvd', - 111: 'light pnt', - 112: 'tex map pal', - 113: 'mat pal', - 114: 'name tab', - 115: 'cat', - 116: 'cat dat', - 117: 'rsrvd', - 118: 'rsrvd', - 119: 'bounding hist', - 120: 'rsrvd', - 121: 'rsrvd', - 122: 'push attrib', - 123: 'pop attrib', - 124: 'rsrvd', - 125: 'rsrvd', - 126: 'curv', - 127: 'road const', - 128: 'light pnt appear pal', - 129: 'light pnt anim pal', - 130: 'indexed lp', - 131: 'lp sys', - 132: 'indx str', - 133: 'shdr pal'} - class Handler: def in_throw_back_lst(self, opcode): return opcode in self.throw_back_lst @@ -487,11 +391,11 @@ class Node: print '-', self.props['comment'], print - + for child in self.children: child.blender_import() - - # Import comment. + +# Import comment. # if self.props['comment'] != '': # name = 'COMMENT: ' + self.props['id'] # t = Blender.Text.New(name) @@ -568,8 +472,8 @@ class Node: else: if global_prefs['verbose'] >= 3: print p + ' ignored' - elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name: - print opcode_name[opcode], 'not handled' + elif global_prefs['verbose'] >= 1 and not opcode in do_not_report_opcodes and opcode in opcode_name: + print 'not handled' def get_level(self): return self.level @@ -581,7 +485,19 @@ class Node: def parse_comment(self): self.props['comment'] = self.header.fw.read_string(self.header.fw.get_length()-4) return True - + + def parse_record(self): + self.props['type'] = self.opcode + props = records[self.opcode] + propkeys = props.keys() + propkeys.sort() + for position in propkeys: + (type,length,name) = props[position] + self.props[name] = read_prop(self.header.fw,type,length) + try: #remove me! + self.props['id'] = self.props['3t8!id'] + except: + pass def __init__(self, parent, header): self.root_handler = Handler() self.child_handler = Handler() @@ -647,20 +563,16 @@ class VertexPalette(Node): return v def parse_vertex_post_common(self, v): - if not v.flags & 0x2000: # 0x2000 = no color - if v.flags & 0x1000: # 0x1000 = packed color - v.a = self.header.fw.read_uchar() - v.b = self.header.fw.read_uchar() - v.g = self.header.fw.read_uchar() - v.r = self.header.fw.read_uchar() - else: - self.header.fw.read_ahead(4) - - color_index = self.header.fw.read_uint() - v.r, v.g, v.b, v.a= self.header.get_color(color_index) - + #if not v.flags & 0x2000: # 0x2000 = no color + #if v.flags & 0x1000: # 0x1000 = packed color + # v.a = self.header.fw.read_uchar() + # v.b = self.header.fw.read_uchar() + # v.g = self.header.fw.read_uchar() + # v.r = self.header.fw.read_uchar() + #else: + self.header.fw.read_ahead(4) #skip packed color + v.cindex = self.header.fw.read_uint() self.vert_desc_lst.append(v) - return True def parse_vertex_c(self): @@ -672,16 +584,10 @@ class VertexPalette(Node): def parse_vertex_cn(self): v = self.parse_vertex_common() - - ''' + v.cnorm = True v.nx = self.header.fw.read_float() v.ny = self.header.fw.read_float() v.nz = self.header.fw.read_float() - ''' - # Just to advance - self.header.fw.read_float() - self.header.fw.read_float() - self.header.fw.read_float() self.parse_vertex_post_common(v) @@ -698,15 +604,10 @@ class VertexPalette(Node): def parse_vertex_cnuv(self): v = self.parse_vertex_common() - ''' + v.cnorm = True v.nx = self.header.fw.read_float() v.ny = self.header.fw.read_float() v.nz = self.header.fw.read_float() - ''' - # Just to advance - self.header.fw.read_float() - self.header.fw.read_float() - self.header.fw.read_float() v.uv[:] = self.header.fw.read_float(), self.header.fw.read_float() @@ -721,89 +622,370 @@ class InterNode(Node): def __init__(self): self.object = None self.mesh = None - self.isMesh = False + self.hasMesh = False self.faceLs= [] self.matrix = None - - def blender_import_my_faces(self): + self.vis = True + self.hasmtex = False + self.uvlayers = dict() + self.blayernames = dict() + self.subfacelevel = 0 + + mask = 2147483648 + for i in xrange(7): + self.uvlayers[mask] = False + mask = mask / 2 + + def blender_import_my_faces(self): + # Add the verts onto the mesh - mesh = self.mesh blender_verts= self.header.vert_pal.blender_verts vert_desc_lst= self.header.vert_pal.vert_desc_lst - vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] - - mesh.verts.extend([blender_verts[i] for i in vert_list]) - + vert_list= [ i for flt_face in self.faceLs for i in flt_face.indices] #splitting faces apart. Is this a good thing? + face_edges= [] + face_verts= [] + self.mesh.verts.extend([blender_verts[i] for i in vert_list]) new_faces= [] new_faces_props= [] ngon= BPyMesh.ngon vert_index= 1 + + #add vertex color layer for baked face colors. + self.mesh.addColorLayer("FLT_Fcol") + self.mesh.activeColorLayer = "FLT_Fcol" + + FLT_OrigIndex = 0 for flt_face in self.faceLs: - material_index= flt_face.blen_mat_idx - image= flt_face.blen_image - + if flt_face.tex_index != -1: + try: + image= self.header.tex_pal[flt_face.tex_index][1] + except KeyError: + image= None + else: + image= None face_len= len(flt_face.indices) + #create dummy uvert dicts + if len(flt_face.uverts) == 0: + for i in xrange(face_len): + flt_face.uverts.append(dict()) + #May need to patch up MTex info + if self.hasmtex: + #For every layer in mesh, there should be corresponding layer in the face + for mask in self.uvlayers.keys(): + if self.uvlayers[mask]: + if not flt_face.uvlayers.has_key(mask): #Does the face have this layer? + #Create Layer info for this face + flt_face.uvlayers[mask] = dict() + flt_face.uvlayers[mask]['texture index'] = -1 + flt_face.uvlayers[mask]['texture enviorment'] = 3 + flt_face.uvlayers[mask]['texture mapping'] = 0 + flt_face.uvlayers[mask]['texture data'] = 0 + + #now go through and create dummy uvs for this layer + for uvert in flt_face.uverts: + uv = Vector(0.0,0.0) + uvert[mask] = uv + # Get the indicies in reference to the mesh. - uvs= [vert_desc_lst[j].uv for j in flt_face.indices] - if face_len <=4: # tri or quad + if face_len == 1: + pass + elif face_len == 2: + face_edges.append((vert_index, vert_index+1)) + elif flt_face.props['draw type'] == 2 or flt_face.props['draw type'] == 3: + i = 0 + while i < (face_len-1): + face_edges.append((vert_index + i, vert_index + i + 1)) + i = i + 1 + if flt_face.props['draw type'] == 2: + face_edges.append((vert_index + i,vert_index)) + elif face_len == 3 or face_len == 4: # tri or quad + #if face_len == 1: + # pass + #if face_len == 2: + # face_edges.append((vert_index, vert_index+1)) new_faces.append( [i+vert_index for i in xrange(face_len)] ) - new_faces_props.append((material_index, image, uvs)) + new_faces_props.append((None, image, uvs, flt_face.uverts, flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,0, flt_face.subfacelevel)) else: # fgon mesh_face_indicies = [i+vert_index for i in xrange(face_len)] - tri_ngons= ngon(mesh, mesh_face_indicies) + tri_ngons= ngon(self.mesh, mesh_face_indicies) new_faces.extend([ [mesh_face_indicies[t] for t in tri] for tri in tri_ngons]) - new_faces_props.extend( [ (material_index, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]) ) for tri in tri_ngons ] ) + new_faces_props.extend( [ (None, image, (uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]), [flt_face.uverts[tri[0]], flt_face.uverts[tri[1]], flt_face.uverts[tri[2]]], flt_face.uvlayers, flt_face.color_index, flt_face.props,FLT_OrigIndex,1, flt_face.subfacelevel) for tri in tri_ngons ]) vert_index+= face_len - - mesh.faces.extend(new_faces) - - try: mesh.faceUV= True - except: pass - - for i, f in enumerate(mesh.faces): - f.mat, f.image, f.uv= new_faces_props[i] - + FLT_OrigIndex+=1 + + self.mesh.faces.extend(new_faces) + self.mesh.edges.extend(face_edges) + + #add in the FLT_ORIGINDEX layer + if len(self.mesh.faces): + try: self.mesh.faceUV= True + except: pass + + if self.mesh.faceUV == True: + self.mesh.renameUVLayer(self.mesh.activeUVLayer, 'Layer0') + + #create name layer for faces + self.mesh.faces.addPropertyLayer("FLT_ID",Blender.Mesh.PropertyTypes["STRING"]) + #create layer for face color indices + self.mesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) + #create index layer for faces. This is needed by both FGONs and subfaces + self.mesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"]) + #create temporary FGON flag layer. Delete after remove doubles + self.mesh.faces.addPropertyLayer("FLT_FGON",Blender.Mesh.PropertyTypes["INT"]) + self.mesh.faces.addPropertyLayer("FLT_SFLEVEL", Blender.Mesh.PropertyTypes["INT"]) + + for i, f in enumerate(self.mesh.faces): + f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] #fix this! + f.mode |= Blender.Mesh.FaceModes["LIGHT"] + props = new_faces_props[i] + #f.mat = props[0] + f.image = props[1] + f.uv = props[2] + #set vertex colors + color = self.header.get_color(props[5]) + if not color: + color = [255,255,255,255] + for mcol in f.col: + mcol.a = color[3] + mcol.r = color[0] + mcol.g = color[1] + mcol.b = color[2] + + f.setProperty("FLT_SFLEVEL", props[9]) + f.setProperty("FLT_ORIGINDEX",i) + f.setProperty("FLT_ID",props[6]['id']) + #if props[5] > 13199: + # print "Warning, invalid color index read in! Using default!" + # f.setProperty("FLT_COL",127) + #else: + if(1): #uh oh.... + value = struct.unpack('>i',struct.pack('>I',props[5]))[0] + f.setProperty("FLT_COL",value) + + #if props[8]: + # f.setProperty("FLT_FGON",1) + #else: + # f.setProperty("FLT_FGON",0) + + + #Create multitex layers, if present. + actuvlayer = self.mesh.activeUVLayer + if(self.hasmtex): + #For every multi-tex layer, we have to add a new UV layer to the mesh + for i,mask in enumerate(reversed(sorted(self.uvlayers))): + if self.uvlayers[mask]: + self.blayernames[mask] = "Layer" + str(i+1) + self.mesh.addUVLayer(self.blayernames[mask]) + + #Cycle through availible multi-tex layers and add face UVS + for mask in self.uvlayers: + if self.uvlayers[mask]: + self.mesh.activeUVLayer = self.blayernames[mask] + for j, f in enumerate(self.mesh.faces): + f.transp |= Blender.Mesh.FaceTranspModes["ALPHA"] + f.mode |= Blender.Mesh.FaceModes["LIGHT"] + props = new_faces_props[j] + uvlayers = props[4] + if uvlayers.has_key(mask): #redundant + uverts = props[3] + for k, uv in enumerate(f.uv): + uv[0] = uverts[k][mask][0] + uv[1] = uverts[k][mask][1] + + uvlayer = uvlayers[mask] + tex_index = uvlayer['texture index'] + if tex_index != -1: + try: + f.image = self.header.tex_pal[tex_index][1] + except KeyError: + f.image = None + + if global_prefs['smoothshading'] == True and len(self.mesh.faces): + #We need to store per-face vertex normals in the faces as UV layers and delete them later. + self.mesh.addUVLayer("FLTNorm1") + self.mesh.addUVLayer("FLTNorm2") + self.mesh.activeUVLayer = "FLTNorm1" + for f in self.mesh.faces: + f.smooth = 1 + #grab the X and Y components of normal and store them in UV + for i, uv in enumerate(f.uv): + vert = f.v[i].index + vert_desc = vert_desc_lst[vert_list[vert-1]] + if vert_desc.cnorm: + uv[0] = vert_desc.nx + uv[1] = vert_desc.ny + else: + uv[0] = 0.0 + uv[1] = 0.0 + + #Now go through and populate the second UV Layer with the z component + self.mesh.activeUVLayer = "FLTNorm2" + for f in self.mesh.faces: + for i, uv in enumerate(f.uv): + vert = f.v[i].index + vert_desc = vert_desc_lst[vert_list[vert-1]] + if vert_desc.cnorm: + uv[0] = vert_desc.nz + uv[1] = 0.0 + else: + uv[0] = 0.0 + uv[1] = 0.0 + + + + #Finally, go through, remove dummy vertex, remove doubles and add edgesplit modifier. + Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) + self.mesh.verts.delete(0) # remove the dummy vert + self.mesh.sel= 1 + self.header.scene.update(1) #slow! + self.mesh.remDoubles(0.0001) + + edgeHash = dict() + + for edge in self.mesh.edges: + edgeHash[edge.key] = edge.index + + + if global_prefs['smoothshading'] == True and len(self.mesh.faces): + + #rip out the custom vertex normals from the mesh and place them in a face aligned list. Easier to compare this way. + facenorms = [] + self.mesh.activeUVLayer = "FLTNorm1" + for face in self.mesh.faces: + facenorm = [] + for uv in face.uv: + facenorm.append(Vector(uv[0],uv[1],0.0)) + facenorms.append(facenorm) + self.mesh.activeUVLayer = "FLTNorm2" + for i, face in enumerate(self.mesh.faces): + facenorm = facenorms[i] + for j, uv in enumerate(face.uv): + facenorm[j][2] = uv[0] + self.mesh.removeUVLayer("FLTNorm1") + self.mesh.removeUVLayer("FLTNorm2") + + #find hard edges + #store edge data for lookup by faces + #edgeHash = dict() + #for edge in self.mesh.edges: + # edgeHash[edge.key] = edge.index + + edgeNormHash = dict() + #make sure to align the edgenormals to key value! + for i, face in enumerate(self.mesh.faces): + + facenorm = facenorms[i] + faceEdges = [] + faceEdges.append((face.v[0].index,face.v[1].index,facenorm[0],facenorm[1],face.edge_keys[0])) + faceEdges.append((face.v[1].index,face.v[2].index,facenorm[1],facenorm[2],face.edge_keys[1])) + if len(face.v) == 3: + faceEdges.append((face.v[2].index,face.v[0].index,facenorm[2],facenorm[0],face.edge_keys[2])) + elif len(face.v) == 4: + faceEdges.append((face.v[2].index,face.v[3].index,facenorm[2],facenorm[3],face.edge_keys[2])) + faceEdges.append((face.v[3].index,face.v[0].index,facenorm[3],facenorm[0],face.edge_keys[3])) + + #check to see if edgeNormal has been placed in the edgeNormHash yet + #this is a redundant test, and should be optimized to not be called as often as it is. + for j, faceEdge in enumerate(faceEdges): + #the value we are looking for is (faceEdge[2],faceEdge[3]) + hashvalue = (faceEdge[2],faceEdge[3]) + if (faceEdge[0],faceEdge[1]) != faceEdge[4]: + hashvalue = (hashvalue[1],hashvalue[0]) + assert (faceEdge[1],faceEdge[0]) == faceEdge[4] + if edgeNormHash.has_key(faceEdge[4]): + #compare value in the hash, if different, mark as sharp + edgeNorm = edgeNormHash[faceEdge[4]] + if\ + abs(hashvalue[0][0] - edgeNorm[0][0]) > FLOAT_TOLERANCE or\ + abs(hashvalue[0][1] - edgeNorm[0][1]) > FLOAT_TOLERANCE or\ + abs(hashvalue[0][2] - edgeNorm[0][2]) > FLOAT_TOLERANCE or\ + abs(hashvalue[1][0] - edgeNorm[1][0]) > FLOAT_TOLERANCE or\ + abs(hashvalue[1][1] - edgeNorm[1][1]) > FLOAT_TOLERANCE or\ + abs(hashvalue[1][2] - edgeNorm[1][2]) > FLOAT_TOLERANCE: + edge = self.mesh.edges[edgeHash[faceEdge[4]]] + edge.flag |= Blender.Mesh.EdgeFlags.SHARP + + else: + edgeNormHash[faceEdge[4]] = hashvalue + + #add in edgesplit modifier + mod = self.object.modifiers.append(Blender.Modifier.Types.EDGESPLIT) + mod[Blender.Modifier.Settings.EDGESPLIT_FROM_SHARP] = True + mod[Blender.Modifier.Settings.EDGESPLIT_FROM_ANGLE] = False + + if(actuvlayer): + self.mesh.activeUVLayer = actuvlayer + def blender_import(self): -# name = self.props['type'] + ': ' + self.props['id'] + if self.vis and self.parent: + self.vis = self.parent.vis name = self.props['id'] - if self.isMesh: - self.object = Blender.Object.New('Mesh', name) - #self.mesh = self.object.getData() + + if self.hasMesh: self.mesh = Blender.Mesh.New() - self.mesh.verts.extend( Vector() ) # DUMMYVERT - self.object.link(self.mesh) + self.mesh.name = 'FLT_FaceList' + self.mesh.fakeUser = True + self.mesh.verts.extend( Vector()) #DUMMYVERT + self.object = self.header.scene.objects.new(self.mesh) else: - self.object = Blender.Object.New('Empty', name) + self.object = self.header.scene.objects.new('Empty') - if self.parent: - self.parent.object.makeParent([self.object]) + self.object.name = name + self.header.group.objects.link(self.object) - scene.link(self.object) - self.object.Layer = current_layer - self.object.sel = 1 + #id props import + self.object.properties['FLT'] = dict() + for key in self.props: + try: + self.object.properties['FLT'][key] = self.props[key] + except: #horrible... + pass + if self.parent and self.parent.object and (self.header.scene == self.parent.header.scene): + self.parent.object.makeParent([self.object]) + + if self.vis == False: + self.object.restrictDisplay = True + self.object.restrictRender = True + + else: #check for LOD children and set the proper flags + lodlist = list() + for child in self.children: + if child.props.has_key('type') and child.props['type'] == 73: + lodlist.append(child) + + def LODmin(a,b): + if a.props['5d!switch in'] < b.props['5d!switch in']: + return a + return b + + min= None + if len(lodlist) > 1: + for lod in lodlist: + lod.vis = False + min = lodlist[0] + for i in xrange(len(lodlist)): + min= LODmin(min,lodlist[i]) + min.vis = True + + if self.matrix: + self.object.setMatrix(self.matrix) + Node.blender_import(self) # Attach faces to self.faceLs - if self.isMesh: + if self.hasMesh: # Add all my faces into the mesh at once self.blender_import_my_faces() - - if self.matrix: - self.object.setMatrix(self.matrix) - - # Attach properties - #for name, value in self.props.items(): - # self.object.addProperty(name, value) - + def parse_face(self): - child = Face(self) + child = Face(self, self.subfacelevel) child.parse() return True @@ -838,6 +1020,11 @@ class InterNode(Node): child.parse() return True + def parse_dof(self): + child = DOF(self) + child.parse() + return True + def parse_indexed_light_point(self): child = IndexedLightPoint(self) child.parse() @@ -857,32 +1044,42 @@ class InterNode(Node): m[i].append(f) self.matrix = Blender.Mathutils.Matrix(m[0], m[1], m[2], m[3]) -EDGE_FGON= Blender.Mesh.EdgeFlags['FGON'] -FACE_TEX= Blender.Mesh.FaceModes['TEX'] + def parse_subpush(self): + self.parse_push() + self.subfacelevel+= 1 + return True + def parse_subpop(self): + self.parse_pop() + self.subfacelevel -= 1 + return True + + class Face(Node): - def __init__(self, parent): + def __init__(self, parent,subfacelevel): Node.__init__(self, parent, parent.header) self.root_handler.set_handler({31: self.parse_comment, - 10: self.parse_push}) + 10: self.parse_push, + 52: self.parse_multitex}) self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({72: self.parse_vertex_list, 10: self.parse_push, - 11: self.parse_pop}) + 11: self.parse_pop, + 53: self.parse_uvlist}) if parent: - parent.isMesh = True + parent.hasMesh = True - self.indices = list() # face verts here + self.subfacelevel = subfacelevel + self.indices = list() # face verts here + self.uvlayers = dict() # MultiTexture layers keyed to layer bitmask. + self.uverts = list() # Vertex aligned list of dictionaries keyed to layer bitmask. + self.uvmask = 0 # Bitfield read from MTex record self.comment = '' - self.props = dict.fromkeys(['ir color', 'priority', - 'draw type', 'texture white', 'template billboard', - 'smc', 'fid', 'ir material', 'lod generation control', - 'flags', 'light mode']) - - self.header.fw.read_ahead(8) # face id + self.props = dict() + self.props['id'] = self.header.fw.read_string(8) # Load face. self.props['ir color'] = self.header.fw.read_int() self.props['priority'] = self.header.fw.read_short() @@ -919,186 +1116,14 @@ class Face(Node): self.alt_color_index = self.header.fw.read_uint() #self.header.fw.read_ahead(2) #self.shader_index = self.header.fw.read_short() - - - """ - def blender_import_face(self, material_index, image): - - - mesh = self.parent.mesh - face_len= len(self.indices) - - mesh_vert_len_orig= len(mesh.verts) - mesh.verts.extend([ self.header.vert_pal.blender_verts[i] for i in self.indices]) - - # Exception for an edge - if face_len==2: - mesh.edges.extend((mesh.verts[-1], mesh.verts[-2])) - return - - - mesh_face_indicies = range(mesh_vert_len_orig, mesh_vert_len_orig+face_len) - - #print mesh_face_indicies , 'mesh_face_indicies ' - - # First we need to triangulate NGONS - if face_len>4: - tri_indicies = [[i+mesh_vert_len_orig for i in t] for t in BPyMesh.ngon(mesh, mesh_face_indicies) ] # use range because the verts are in order. - else: - tri_indicies= [mesh_face_indicies] # can be a quad but thats ok - - # Extend face or ngon - - mesh.faces.extend(tri_indicies) - #print mesh.faces, 'mesh.faces' - mesh.faceUV= True - - # Now set UVs - for i in xrange(len(mesh.faces)-len(tri_indicies), len(mesh.faces)): - f= mesh.faces[i] - f_v= f.v - for j, uv in enumerate(f.uv): - vertex_index_flt= self.indices[f_v[j].index - mesh_vert_len_orig] - - vert_desc = self.header.vert_pal.vert_desc_lst[vertex_index_flt] - uv.x, uv.y= vert_desc.u, vert_desc.v - - # Only a bug in 2.42, fixed in cvs - for c in f.col: - c.r=c.g=c.b= 255 - - f.mat = material_index - if image: - f.image = image - else: - f.mode &= ~FACE_TEX - - # FGon - - if face_len>4: - # Add edges we know are not fgon - end_index= len(mesh.verts) - start_index= end_index - len(self.indices) - edge_dict= dict([ ((i, i+1), None) for i in xrange(start_index, end_index-1)]) - edge_dict[(start_index, end_index)]= None # wish this was a set - - fgon_edges= {} - for tri in tri_indicies: - for i in (0,1,2): - i1= tri[i] - i2= tri[i-1] - - # Sort - if i1>i2: - i1,i2= i2,i1 - - if not edge_dict.has_key( (i1,i2) ): # if this works its an edge vert - fgon_edges[i1,i2]= None - - - # Now set fgon flags - for ed in mesh.edges: - i1= ed.v1.index - i2= ed.v2.index - if i1>i2: - i1,i2= i2,i1 - - if fgon_edges.has_key( (i1,i2) ): - # This is an edge tagged for fgonning? - fgon_edges[i1, i2] - ed.flag |= EDGE_FGON - del fgon_edges[i1, i2] # make later searches faster? - - if not fgon_edges: - break - """ - + def parse_comment(self): self.comment = self.header.fw.read_string(self.header.fw.get_length()-4) return True - # returns a tuple (material, image) where material is the blender material and - # image is the blender image or None. - def create_blender_material(self): - # Create face material. - mat_desc = MaterialDesc() - - if self.mat_index != -1: - if not self.mat_index in self.header.mat_desc_pal: - if global_prefs['verbose'] >= 1: - #print 'Warning: Material index', self.mat_index, 'not in material palette.' - pass - else: - mat_pal_desc = self.header.mat_desc_pal[self.mat_index] - mat_desc.alpha = mat_pal_desc.alpha * self.alpha # combine face and mat alphas - mat_desc.ambient = mat_pal_desc.ambient - mat_desc.diffuse = mat_pal_desc.diffuse - mat_desc.specular = mat_pal_desc.specular - mat_desc.emissive = mat_pal_desc.emissive - mat_desc.shininess = mat_pal_desc.shininess - else: - # if no material get alpha from just face. - mat_desc.alpha = self.alpha - - # Color. - if global_prefs['color_from_face']: - color = None - if not self.props['flags'] & 0x40000000: - if self.props['flags'] & 0x10000000: # packed color - color = self.packed_color - else: - color = self.header.get_color(self.color_index) - - if color: - r = float(color[0])/255.0 - g = float(color[1])/255.0 - b = float(color[2])/255.0 - mat_desc.diffuse = [r, g, b] - - # Texture - image = None - if self.tex_index != -1 and self.tex_index in self.header.bl_tex_pal: - mat_desc.tex0 = self.header.bl_tex_pal[self.tex_index] - if mat_desc.tex0: - mat_desc.name = FF.strip_path(self.header.tex_pal[self.tex_index]) - image = mat_desc.tex0.image - - # OpenFlight Face Attributes - mat_desc.face_props = self.props - - # Get material. - mat = GRR.request_mat(mat_desc) - - # Add material to mesh. - mesh = self.parent.mesh - - # Return where it is in the mesh for faces. - mesh_materials= mesh.materials - - material_index= -1 - for i,m in enumerate(mesh_materials): - if m.name==mat.name: - material_index= i - break - - if material_index==-1: - material_index= len(mesh_materials) - if material_index==16: - material_index= 15 - if global_prefs['verbose'] >= 1: - print 'Warning: Too many materials per mesh object. Only a maximum of 16 ' + \ - 'allowed. Using 16th material instead.' - - else: - mesh_materials.append(mat) - mesh.materials= mesh_materials - - return (material_index, image) - - def blender_import(self): vert_count = len(self.indices) - if vert_count < 3: + if vert_count < 1: if global_prefs['verbose'] >= 2: print 'Warning: Ignoring face with no vertices.' return @@ -1106,18 +1131,21 @@ class Face(Node): # Assign material and image self.parent.faceLs.append(self) - self.blen_mat_idx, self.blen_image= self.create_blender_material() - - - + #need to store comment in mesh prop layer! # Store comment info in parent. - if self.comment != '': - if self.parent.props['comment'] != '': - self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment - else: - self.parent.props['comment'] = self.comment - + #if self.comment != '': + # if self.parent.props['comment'] != '': + # self.parent.props['comment'] += '\n\nFrom Face:\n' + self.comment + # else: + # self.parent.props['comment'] = self.comment + + if self.uvlayers: + #Make sure that the mesh knows about the layers that this face uses + self.parent.hasmtex = True + for mask in self.uvlayers.keys(): + self.parent.uvlayers[mask] = True + def parse_vertex_list(self): length = self.header.fw.get_length() fw = self.header.fw @@ -1138,8 +1166,49 @@ class Face(Node): ' to vertex index.' % byte_offset ''' return True - - + + def parse_multitex(self): + #Parse MultiTex Record. + length = self.header.fw.get_length() + fw = self.header.fw + #num layers == (length - 8) / 4 + uvmask = fw.read_uint() + mask = 2147483648 + for i in xrange(7): + if mask & uvmask: + uvlayer = dict() + self.uvlayers[mask] = uvlayer + mask = mask / 2 + + #read in record for each individual layer. + for key in reversed(sorted(self.uvlayers)): + uvlayer = self.uvlayers[key] + uvlayer['texture index'] = fw.read_ushort() + uvlayer['texture enviorment'] = fw.read_ushort() + uvlayer['texture mapping'] = fw.read_ushort() + uvlayer['texture data'] = fw.read_ushort() + + self.uvmask = uvmask + + def parse_uvlist(self): + #for each uvlayer, add uv vertices + length = self.header.fw.get_length() + fw = self.header.fw + uvmask = fw.read_uint() + if uvmask != self.uvmask: #This should never happen! + fw.read_ahead(self.length - 4) #potentially unnessecary? + else: + #need to store in uvverts dictionary for each vertex. + totverts = len(self.indices) + for i in xrange(totverts): + uvert = dict() + for key in reversed(sorted(self.uvlayers)): + uv = Vector(0.0,0.0) + uv[0] = fw.read_float() + uv[1] = fw.read_float() + uvert[key] = uv + self.uverts.append(uvert) + class Object(InterNode): def __init__(self, parent): Node.__init__(self, parent, parent.header) @@ -1152,15 +1221,15 @@ class Object(InterNode): self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({5: self.parse_face, - #130: self.parse_indexed_light_point, - #111: self.parse_inline_light_point, + 19: self.parse_subpush, + 20: self.parse_subpop, + 111: self.parse_inline_light_point, 10: self.parse_push, 11: self.parse_pop}) - self.props['type'] = 'Object' - self.props['id'] = self.header.fw.read_string(8) - - + self.props = dict() + self.props['comment'] = '' + self.parse_record() class Group(InterNode): def __init__(self, parent): @@ -1174,15 +1243,16 @@ class Group(InterNode): self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({5: self.parse_face, - #130: self.parse_indexed_light_point, - #111: self.parse_inline_light_point, + 19: self.parse_subpush, + 20: self.parse_subpop, + 111: self.parse_inline_light_point, 2: self.parse_group, 73: self.parse_lod, 4: self.parse_object, 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, - 14: self.parse_unhandled, + 14: self.parse_dof, 91: self.parse_unhandled, 98: self.parse_unhandled, 63: self.parse_xref}) @@ -1190,20 +1260,48 @@ class Group(InterNode): 'special2', 'significance', 'layer code', 'loop count', 'loop duration', 'last frame duration']) - self.props['type'] = 'Group' self.props['comment'] = '' - self.props['id'] = self.header.fw.read_string(8) - self.props['priority'] = self.header.fw.read_short() - self.header.fw.read_ahead(2) - self.props['flags'] = self.header.fw.read_int() - self.props['special1'] = self.header.fw.read_short() - self.props['special2'] = self.header.fw.read_short() - self.props['significance'] = self.header.fw.read_short() - self.props['layer code'] = self.header.fw.read_char() - self.header.fw.read_ahead(5) - self.props['loop count'] = self.header.fw.read_int() - self.props['loop duration'] = self.header.fw.read_float() - self.props['last frame duration'] = self.header.fw.read_float() + self.parse_record() + + #self.props['type'] = str(self.opcode) + ':' + opcode_name[self.opcode] + #props = records[self.opcode] + #propkeys = props.keys() + #propkeys.sort() + #for position in propkeys: + # (type,length,name) = props[position] + # self.props[name] = read_prop(self.header.fw,type,length) + #self.props['id'] = self.props['3t8!id'] + +class DOF(InterNode): + def blender_import(self): + InterNode.blender_import(self) + + def __init__(self, parent): + Node.__init__(self, parent, parent.header) + InterNode.__init__(self) + + self.root_handler.set_handler({33: self.parse_long_id, + 31: self.parse_comment, + 10: self.parse_push, + 49: self.parse_matrix}) + self.root_handler.set_throw_back_lst(throw_back_opcodes) + + self.child_handler.set_handler({#130: self.parse_indexed_light_point, + 111: self.parse_inline_light_point, + 2: self.parse_group, + 73: self.parse_lod, + 4: self.parse_object, + 10: self.parse_push, + 11: self.parse_pop, + 96: self.parse_unhandled, + 14: self.parse_dof, + 91: self.parse_unhandled, + 98: self.parse_unhandled, + 63: self.parse_xref}) + self.props = dict() + self.props['comment'] = '' + self.parse_record() + class XRef(InterNode): def parse(self): @@ -1214,31 +1312,66 @@ class XRef(InterNode): def __init__(self, parent): Node.__init__(self, parent, parent.header) InterNode.__init__(self) - + self.root_handler.set_handler({49: self.parse_matrix}) self.root_handler.set_throw_back_lst(throw_back_opcodes) - xref_filename = self.header.fw.read_string(200) - filename = FF.find(xref_filename) + self.props = dict() + self.props['comment'] = '' + self.parse_record() - self.props['type'] = 'XRef' + xref_filename = self.props['3t200!filename'] + self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(xref_filename))[0] #this is really wrong as well.... - if filename != None: - self.xref = Database(filename, self) - self.props['id'] = 'X: ' + Blender.sys.splitext(Blender.sys.basename(filename))[0] + if global_prefs['doxrefs'] and os.path.exists(xref_filename) and not self.header.grr.xrefs.has_key(xref_filename): + self.xref = Database(xref_filename, self.header.grr, self) + self.header.grr.xrefs[xref_filename] = self.xref else: self.xref = None - self.props['id'] = 'X: broken' + + + def blender_import(self): + #name = self.props['type'] + ': ' + self.props['id'] + name = self.props['id'] + self.object = self.header.scene.objects.new('Empty') + self.object.name = name + self.object.enableDupGroup = True + self.header.group.objects.link(self.object) + + #for broken links its ok to leave this empty! they purely for visual purposes anyway..... + try: + self.object.DupGroup = self.header.grr.xrefs[self.props['3t200!filename']].group + except: + pass + + if self.parent and self.parent.object: + self.parent.object.makeParent([self.object]) + #id props import + self.object.properties['FLT'] = dict() + for key in self.props: + try: + self.object.properties['FLT'][key] = self.props[key] + except: #horrible... + pass + + self.object.Layer = current_layer + self.object.sel = 1 + if self.matrix: + self.object.setMatrix(self.matrix) + Node.blender_import(self) + + class LOD(InterNode): def blender_import(self): - self.move_to_next_layer() + #self.move_to_next_layer() InterNode.blender_import(self) - + #self.object.properties['FLT'] = self.props.copy() + def __init__(self, parent): Node.__init__(self, parent, parent.header) InterNode.__init__(self) - + self.root_handler.set_handler({33: self.parse_long_id, 31: self.parse_comment, 10: self.parse_push, @@ -1246,18 +1379,20 @@ class LOD(InterNode): self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({2: self.parse_group, + 111: self.parse_inline_light_point, 73: self.parse_lod, 4: self.parse_object, 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, # switch - 14: self.parse_unhandled, # DOF + 14: self.parse_dof, # DOF 91: self.parse_unhandled, # sound 98: self.parse_unhandled, # clip 63: self.parse_xref}) - self.props['type'] = 'LOD' - self.props['id'] = self.header.fw.read_string(8) + self.props = dict() + self.props['comment'] = '' + self.parse_record() class InlineLightPoint(InterNode): def __init__(self, parent): @@ -1274,119 +1409,49 @@ class InlineLightPoint(InterNode): 11: self.parse_pop}) self.indices = list() - - self.props = dict.fromkeys(['id', 'type', 'comment', 'draw order', 'appearance']) - self.app_props = dict() - + self.props = dict() self.props['comment'] = '' - self.props['type'] = 'Light Point' - self.props['id'] = self.header.fw.read_string(8) - - self.app_props.update({'smc': self.header.fw.read_short()}) - self.app_props.update({'fid': self.header.fw.read_short()}) - self.app_props.update({'back color: a': self.header.fw.read_uchar()}) - self.app_props.update({'back color: b': self.header.fw.read_uchar()}) - self.app_props.update({'back color: g': self.header.fw.read_uchar()}) - self.app_props.update({'back color: r': self.header.fw.read_uchar()}) - self.app_props.update({'display mode': self.header.fw.read_int()}) - self.app_props.update({'intensity': self.header.fw.read_float()}) - self.app_props.update({'back intensity': self.header.fw.read_float()}) - self.app_props.update({'minimum defocus': self.header.fw.read_float()}) - self.app_props.update({'maximum defocus': self.header.fw.read_float()}) - self.app_props.update({'fading mode': self.header.fw.read_int()}) - self.app_props.update({'fog punch mode': self.header.fw.read_int()}) - self.app_props.update({'directional mode': self.header.fw.read_int()}) - self.app_props.update({'range mode': self.header.fw.read_int()}) - self.app_props.update({'min pixel size': self.header.fw.read_float()}) - self.app_props.update({'max pixel size': self.header.fw.read_float()}) - self.app_props.update({'actual size': self.header.fw.read_float()}) - self.app_props.update({'trans falloff pixel size': self.header.fw.read_float()}) - self.app_props.update({'trans falloff exponent': self.header.fw.read_float()}) - self.app_props.update({'trans falloff scalar': self.header.fw.read_float()}) - self.app_props.update({'trans falloff clamp': self.header.fw.read_float()}) - self.app_props.update({'fog scalar': self.header.fw.read_float()}) - self.app_props.update({'fog intensity': self.header.fw.read_float()}) - self.app_props.update({'size threshold': self.header.fw.read_float()}) - self.app_props.update({'directionality': self.header.fw.read_int()}) - self.app_props.update({'horizontal lobe angle': self.header.fw.read_float()}) - self.app_props.update({'vertical lobe angle': self.header.fw.read_float()}) - self.app_props.update({'lobe roll angle': self.header.fw.read_float()}) - self.app_props.update({'dir falloff exponent': self.header.fw.read_float()}) - self.app_props.update({'dir ambient intensity': self.header.fw.read_float()}) - self.header.fw.read_ahead(12) # Animation settings. - self.app_props.update({'significance': self.header.fw.read_float()}) - self.props['draw order'] = self.header.fw.read_int() - self.app_props.update({'flags': self.header.fw.read_int()}) - #self.fw.read_ahead(12) # More animation settings. - - # return dictionary: lp_app name => index list - def group_points(self, props): - - name_to_indices = {} - - for i in self.indices: - vert_desc = self.header.vert_pal.vert_desc_lst[i] - app_desc = LightPointAppDesc() - app_desc.props.update(props) - # add vertex normal and color - app_desc.props.update({'nx': vert_desc.nx}) - app_desc.props.update({'ny': vert_desc.ny}) - app_desc.props.update({'nz': vert_desc.nz}) - - app_desc.props.update({'r': vert_desc.r}) - app_desc.props.update({'g': vert_desc.g}) - app_desc.props.update({'b': vert_desc.b}) - app_desc.props.update({'a': vert_desc.a}) - - app_name = GRR.request_lightpoint_app(app_desc) + self.parse_record() - if name_to_indices.get(app_name): - name_to_indices[app_name].append(i) - else: - name_to_indices.update({app_name: [i]}) - - return name_to_indices def blender_import(self): - name = '%s: %s' % (self.props['type'], self.props['id']) + - name_to_indices = self.group_points(self.app_props) + name = self.props['id'] + self.mesh= Blender.Mesh.New() + self.mesh.name = 'FLT_LP' + self.object = self.header.scene.objects.new(self.mesh) + self.object.name = name + #self.mesh.verts.extend(Vector() ) # DUMMYVERT + self.object.Layer = current_layer + self.object.sel= 1 + + self.object.properties['FLT'] = dict() + for key in self.props: + try: + self.object.properties['FLT'][key] = self.props[key] + except: #horrible... + pass + + if self.parent and self.parent.object and self.header.scene == self.parent.header.scene: + self.parent.object.makeParent([self.object]) - for app_name, indices in name_to_indices.iteritems(): - self.object = Blender.Object.New('Mesh', name) - #self.mesh = self.object.getData() - self.mesh= Blender.Mesh.New() - self.mesh.verts.extend( Vector() ) # DUMMYVERT - self.object.link(self.mesh) + if self.matrix: + self.object.setMatrix(self.matrix) - if self.parent: - self.parent.object.makeParent([self.object]) - - for i in indices: - vert = self.header.vert_pal.blender_verts[i] - self.mesh.verts.append(vert) - - scene.link(self.object) - self.object.Layer = current_layer - self.object.sel= 1 - - if self.matrix: - self.object.setMatrix(self.matrix) + self.mesh.verts.extend([self.header.vert_pal.blender_verts[i] for i in self.indices]) + + #add color index information. + self.mesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"]) + for i, vindex in enumerate(self.indices): + vdesc = self.header.vert_pal.vert_desc_lst[vindex] + v = self.mesh.verts[i] + v.setProperty("FLT_VCOL",vdesc.cindex) + #for i, v in enumerate(self.mesh.verts): + # vdesc = self.header.vert_pal.vert_desc_lst[i] + # v.setProperty("FLT_VCOL",vdesc.cindex) + self.mesh.update() - # Import comment. - if self.props['comment'] != '': - name = 'COMMENT: ' + self.props['id'] - t = Blender.Text.New(name) - t.write(self.props['comment']) - self.props['comment'] = name - - # Attach properties. - self.props.update({'appearance': app_name}) - for name, value in self.props.iteritems(): - self.object.addProperty(name, value) - - self.mesh.update() - def parse_vertex_list(self): length = self.header.fw.get_length() fw = self.header.fw @@ -1432,7 +1497,7 @@ class IndexedLightPoint(InterNode): app_desc.props.update({'b': vert_desc.b}) app_desc.props.update({'a': vert_desc.a}) - app_name = GRR.request_lightpoint_app(app_desc) + app_name = self.header.grr.request_lightpoint_app(app_desc, self.header.scene) if name_to_indices.get(app_name): name_to_indices[app_name].append(i) @@ -1448,7 +1513,6 @@ class IndexedLightPoint(InterNode): for app_name, indices in name_to_indices.iteritems(): self.object = Blender.Object.New('Mesh', name) - #self.mesh = self.object.getData() self.mesh= Blender.Mesh.New() self.mesh.verts.extend( Vector() ) # DUMMYVERT self.object.link(self.mesh) @@ -1460,7 +1524,7 @@ class IndexedLightPoint(InterNode): vert = self.header.vert_pal.blender_verts[i] self.mesh.verts.append(vert) - scene.link(self.object) + self.header.scene.objects.link(self.object) self.object.Layer = current_layer @@ -1543,7 +1607,7 @@ class Unhandled(InterNode): 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, # switch - 14: self.parse_unhandled, # DOF + 14: self.parse_dof, # DOF 91: self.parse_unhandled, # sound 98: self.parse_unhandled, # clip 63: self.parse_xref}) @@ -1552,30 +1616,31 @@ class Unhandled(InterNode): class Database(InterNode): def blender_import(self): - self.tex_pal = dict(self.tex_pal_lst) - del self.tex_pal_lst - - # Setup Textures - bl_tex_pal_lst = list() - for i in self.tex_pal.iterkeys(): - path_filename = FF.find(self.tex_pal[i]) + for key in self.tex_pal.keys(): + path_filename= FF.find(self.tex_pal[key][0]) if path_filename != None: - img = GRR.request_image(path_filename) + img = self.grr.request_image(path_filename) if img: - tex = GRR.request_texture(img) - tex.setName(FF.strip_path(self.tex_pal[i])) - bl_tex_pal_lst.append( (i, tex) ) - else: - bl_tex_pal_lst.append( (i, None) ) + self.tex_pal[key][1] = img elif global_prefs['verbose'] >= 1: - print 'Warning: Unable to find', self.tex_pal[i] - - self.bl_tex_pal = dict(bl_tex_pal_lst) - - # Setup Materials - self.mat_desc_pal = dict(self.mat_desc_pal_lst) - - InterNode.blender_import(self) + print 'Warning: Unable to find', self.tex_pal[key][0] + + self.scene.properties['FLT'] = dict() + for key in self.props: + try: + self.scene.properties['FLT'][key] = self.props[key] + except: #horrible... + pass + + self.scene.properties['FLT']['Main'] = 0 + self.scene.properties['FLT']['Filename'] = self.bname + + #import color palette + carray = list() + for color in self.col_pal: + carray.append(struct.unpack('>i',struct.pack('>BBBB',color[0],color[1],color[2],color[3]))[0]) + self.scene.properties['FLT']['Color Palette'] = carray + Node.blender_import(self) def parse_appearance_palette(self): props = dict() @@ -1696,9 +1761,10 @@ class Database(InterNode): return True def get_color(self, color_index): + color = None index = color_index / 128 intensity = float(color_index - 128.0 * index) / 127.0 - + if index >= 0 and index <= 1023: brightest = self.col_pal[index] r = int(brightest[0] * intensity) @@ -1707,7 +1773,7 @@ class Database(InterNode): a = int(brightest[3]) color = [r, g, b, a] - + return color def parse_color_palette(self): @@ -1728,15 +1794,56 @@ class Database(InterNode): def parse_texture_palette(self): name = self.fw.read_string(200) index = self.fw.read_int() - self.tex_pal_lst.append( (index, name) ) + self.tex_pal[index]= [name, None] return True - - def __init__(self, filename, parent=None): + + def read_attribute_files(self): + for tex in self.tex_pal.keys(): + [name,image] = self.tex_pal[tex] + basename = os.path.basename(name) + if(image): + basename = basename + ".attr" + dirname = os.path.dirname(Blender.sys.expandpath(image.getFilename())) #can't rely on original info stored in pallette since it might be relative link + newpath = os.path.join(dirname, basename) + if os.path.exists(newpath) and not image.properties.has_key('FLT'): + fw = flt_filewalker.FltIn(newpath) + fw.read_ahead(8) #We dont care what the attribute file says about x/y dimensions + image.properties['FLT']={} + + #need to steal code from parse records.... + props = records['Image'] + propkeys = props.keys() + propkeys.sort() + for position in propkeys: + (type,length,name) = props[position] + image.properties['FLT'][name] = read_prop(fw,type,length) + fw.close_file() + + #copy clamp settings + wrap = image.properties['FLT']['10i!Wrap'] + wrapu = image.properties['FLT']['11i!WrapU'] + wrapv = image.properties['FLT']['12i!WrapV'] + + if wrapu == 3 or wrapv == 3: + wrapuv = (wrap,wrap) + else: + wrapuv = (wrapu, wrapv) + image.clampX = wrapuv[0] + image.clampY = wrapuv[1] + + elif not os.path.exists(newpath): + print "Cannot read attribute file:" + newpath + + def __init__(self, filename, grr, parent=None): if global_prefs['verbose'] >= 1: print 'Parsing:', filename print self.fw = flt_filewalker.FltIn(filename) + self.filename = filename + self.bname = os.path.splitext(os.path.basename(filename))[0] + self.grr = grr + Node.__init__(self, parent, self) InterNode.__init__(self) @@ -1753,23 +1860,26 @@ class Database(InterNode): self.root_handler.set_throw_back_lst(throw_back_opcodes) self.child_handler.set_handler({#130: self.parse_indexed_light_point, - #111: self.parse_inline_light_point, + 111: self.parse_inline_light_point, 2: self.parse_group, 73: self.parse_lod, 4: self.parse_object, 10: self.parse_push, 11: self.parse_pop, 96: self.parse_unhandled, - 14: self.parse_unhandled, + 14: self.parse_dof, 91: self.parse_unhandled, 98: self.parse_unhandled, 63: self.parse_xref}) + self.scene = Blender.Scene.New(self.bname) + self.group = Blender.Group.New(self.bname) + self.vert_pal = None self.lightpoint_appearance_pal = dict() self.tex_pal = dict() - self.tex_pal_lst = list() - self.bl_tex_pal = dict() + #self.tex_pal_lst = list() + #self.bl_tex_pal = dict() self.col_pal = list() self.mat_desc_pal_lst = list() self.mat_desc_pal = dict() @@ -1778,7 +1888,70 @@ class Database(InterNode): 'sw lon', 'ne lat', 'ne lon', 'origin lat', 'origin lon', 'lambert lat1', 'lambert lat2', 'ellipsoid model', 'utm zone', 'radius', 'major axis', 'minor axis']) -def select_file(filename): + +def clearparent(root,childhash): + for child in childhash[root]: + clearparent(child,childhash) + root.clrParent(2,0) + +def fixscale(root,childhash): + for child in childhash[root]: + fixscale(child,childhash) + location = Blender.Mathutils.Vector(root.getLocation('worldspace')) + if location[0] != 0.0 and location[1] != 0.0 and location[2] != 0.0: + #direction = Blender.Mathutils.Vector(0-location[0],0-location[1],0-location[2]) #reverse vector + smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4) + root.setLocation(location * smat) + #if its a mesh, we need to scale all of its vertices too + if root.type == 'Mesh': + smat = Blender.Mathutils.ScaleMatrix(global_prefs['scale'],4) + rmesh = root.getData(mesh=True) + for v in rmesh.verts: + v.co = v.co * smat + + +def reparent(root,childhash,sce): + for child in childhash[root]: + reparent(child,childhash,sce) + + root.makeParent(childhash[root]) + sce.update(1) + +def update_scene(root,sdone): + for object in root.objects: + if object.DupGroup: + try: + child = Blender.Scene.Get(object.DupGroup.name) + except: + child = None + if child and child not in sdone: + update_scene(child,sdone) + root.makeCurrent() + #create a list of children for each object + childhash = dict() + for object in root.objects: + childhash[object] = list() + + for object in root.objects: + if object.parent: + childhash[object.parent].append(object) + + for object in root.objects: + if not object.parent: + #recursivley go through and clear all the children of their transformation, starting at deepest level first. + clearparent(object,childhash) + #now fix the location of everything + fixscale(object,childhash) + #now fix the parenting + reparent(object,childhash,root) + + for object in root.objects: + object.makeDisplayList() + root.update(1) + sdone.append(root) + + +def select_file(filename, grr): if not Blender.sys.exists(filename): msg = 'Error: File ' + filename + ' does not exist.' Blender.Draw.PupMenu(msg) @@ -1801,13 +1974,12 @@ def select_file(filename): global_prefs['get_ambient'] = False global_prefs['get_shininess'] = True global_prefs['color_from_face'] = True + global_prefs['log to blender'] = True + + - # Start loading the file, - # first set the context Blender.Window.WaitCursor(True) Blender.Window.EditMode(0) - for ob in scene.objects: - ob.sel=0 FF.add_file_to_search_path(filename) @@ -1817,7 +1989,7 @@ def select_file(filename): print load_time = Blender.sys.time() - db = Database(filename) + db = Database(filename,grr) db.parse() load_time = Blender.sys.time() - load_time @@ -1828,23 +2000,15 @@ def select_file(filename): import_time = Blender.sys.time() db.blender_import() - import_time = Blender.sys.time() - import_time - - Blender.Window.ViewLayer(range(1,21)) - - # FIX UP AFTER DUMMY VERT AND REMOVE DOUBLES - Blender.Mesh.Mode(Blender.Mesh.SelectModes['VERTEX']) - for ob in scene.objects.context: - if ob.type=='Mesh': - me=ob.getData(mesh=1) - me.verts.delete(0) # remove the dummy vert - me.sel= 1 - me.remDoubles(0.0001) + if global_prefs['attrib']: + print "reading attribute files" + db.read_attribute_files() + Blender.Window.ViewLayer(range(1,21)) - Blender.Window.RedrawAll() - + update_scene(db.scene,[]) + import_time = Blender.sys.time() - import_time if global_prefs['verbose'] >= 1: print 'Done.' print @@ -1854,37 +2018,112 @@ def select_file(filename): Blender.Window.WaitCursor(False) +def setimportscale(ID,val): + global global_prefs + global_prefs['scale'] = val +def setBpath(fname): + global_prefs['fltfile'] = fname -if global_prefs['verbose'] >= 1: - print - print 'OpenFlight Importer' - print 'Version:', __version__ - print 'Author: Greg MacDonald' - print __url__[2] - print +def event(evt,val): + pass +def but_event(evt): + + global FLTBaseLabel + global FLTBaseString + global FLTBaseChooser + global FLTExport + global FLTClose + + global FLTDoXRef + global FLTShadeImport + global FLTAttrib + + #Import DB + if evt == 1: + if global_prefs['verbose'] >= 1: + print + print 'OpenFlight Importer' + print 'Version:', __version__ + print 'Author: Greg MacDonald, Campbell Barton, Geoffrey Bantle' + print __url__[2] + print + + GRR = GlobalResourceRepository() + select_file(global_prefs['fltfile'], GRR) + #choose base path for export + if evt == 4: + Blender.Window.FileSelector(setBpath, "DB Root", global_prefs['fltfile']) + #Import custom shading? + if evt == 9: + global_prefs['smoothshading'] = FLTShadeImport.val + #Import Image attribute files + if evt == 10: + global_prefs['attrib'] = FLTAttrib.val + #export XRefs + if evt == 13: + global_prefs['doxrefs'] = FLTDoXRef.val + + if evt == 2: + Draw.Exit() + -if __name__ == '__main__': - Blender.Window.FileSelector(select_file, "Import OpenFlight", "*.flt") - #select_file('/fe/flt/helnwsflt/helnws.flt') - #select_file('/fe/flt/Container_006.flt') - #select_file('/fe/flt/NaplesORIGINALmesh.flt') - #select_file('/Anti_tank_D30.flt') - #select_file('/metavr/file_examples/flt/cherrypoint/CherryPoint_liter_runway.flt') + +from Blender.BGL import * +from Blender import Draw +def gui(): + + global FLTBaseLabel + global FLTBaseString + global FLTBaseChooser -""" -TIME= Blender.sys.time() -import os -PATH= 'c:\\flt_test' -for FNAME in os.listdir(PATH): - if FNAME.lower().endswith('.flt'): - FPATH= os.path.join(PATH, FNAME) - newScn= Blender.Scene.New(FNAME) - newScn.makeCurrent() - scene= newScn - select_file(FPATH) - -print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME) -""" -
\ No newline at end of file + global FLTExport + global FLTClose + + global FLTDoXRef + global FLTShadeImport + + global FLTAttrib + + + glClearColor(0.772,0.832,0.847,1.0) + glClear(GL_COLOR_BUFFER_BIT) + + areas = Blender.Window.GetScreenInfo() + curarea = Blender.Window.GetAreaID() + curRect = None + + for area in areas: + if area['id'] == curarea: + curRect = area['vertices'] + break + + width = curRect[2] - curRect[0] + height = curRect[3] - curRect[1] + cx = 50 + cy = height - 80 + + FLTBaseLabel = Draw.Label("Base file:",cx,cy,100,20) + FLTBaseString = Draw.String("",3,cx+100,cy,300,20,global_prefs['fltfile'],255,"Root DB file") + FLTBaseChooser = Draw.PushButton("...",4,cx+400,cy,20,20,"Choose Folder") + + cy = cy-40 + FLTScale = Draw.Number("Import Scale",14,cx,cy,220,20,global_prefs['scale'],0.0,100.0,"Export scaleing factor",setimportscale) + + cy = cy-40 + FLTDoXRef = Draw.Toggle("Import XRefs", 13,cx,cy,220,20,global_prefs['doxrefs'],"Import External references") + + cy = cy-40 + FLTShadeImport = Draw.Toggle("Import Custom Shading",9,cx,cy,220,20,global_prefs['smoothshading'],"Import custom shading via edgesplit modifiers") + + cy = cy-40 + FLTAttrib = Draw.Toggle("Import Attribute Files", 10,cx,cy,220,20,global_prefs['attrib'],"Import Image Attribute files") + + cy = cy - 40 + FLTExport = Draw.PushButton("Import",1,cx,20,100,20,"Import FLT Database") + FLTClose = Draw.PushButton("Close",2,cx+120,20,100,20,"Close Window") + + + +Draw.Register(gui,event,but_event)
\ No newline at end of file diff --git a/release/scripts/flt_palettemanager.py b/release/scripts/flt_palettemanager.py new file mode 100644 index 00000000000..c641a0a4f08 --- /dev/null +++ b/release/scripts/flt_palettemanager.py @@ -0,0 +1,388 @@ +#!BPY + +""" +Name: 'FLT Palette Manager' +Blender: 240 +Group: 'Misc' +Tooltip: 'Manage FLT colors' +""" + +__author__ = "Geoffrey Bantle" +__version__ = "1.0 11/21/2007" +__email__ = ('scripts', 'Author, ') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ + +This script manages colors in OpenFlight databases. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Todo: +-Figure out whats causing the PC speaker to beep when initializing... + +Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/FLTools +""" + +# -------------------------------------------------------------------------- +# flt_palettemanager.py version 0.1 2005/04/08 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2007: Blender Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender.Draw as Draw +from Blender.BGL import * +import Blender +import flt_properties +import flt_defaultp as defaultp +from flt_properties import * + + +palette_size = 12 +palette_x = 0 +palette_y = 0 + +colors = list() +curint = 1.0 +curswatch = 0 +#make a default palette, not very useful. +cinc = 1.0 / 1024.0 +cstep = 0.0 +picker = None +ptt = "" +for i in xrange(1024): + colors.append([cstep,cstep,cstep]) + cstep = cstep + cinc +def update_state(): + state = dict() + state["activeScene"] = Blender.Scene.getCurrent() + state["activeObject"] = state["activeScene"].getActiveObject() + state["activeMesh"] = None + if state["activeObject"] and state["activeObject"].type == 'Mesh': + state["activeMesh"] = state["activeObject"].getData(mesh=True) + + state["activeFace"] = None + if state["activeMesh"]: + if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: + state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] + + return state + +def pack_face_index(index, intensity): + return ((127*intensity)+(128*index)) +def unpack_face_index(face_index): + index = face_index / 128 + intensity = float(face_index - 128.0 * index) / 127.0 + return(index,intensity) + +def event(evt,val): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + + areas = Blender.Window.GetScreenInfo() + curarea = Blender.Window.GetAreaID() + curRect = None + editmode = 0 + + for area in areas: + if area['id'] == curarea: + curRect = area['vertices'] + break + + if evt == Draw.LEFTMOUSE: + mval = Blender.Window.GetMouseCoords() + rastx = mval[0] - curRect[0] + rasty = mval[1] - curRect[1] + + swatchx = (rastx -palette_x) / palette_size #+state["palette_x"] + swatchy = (rasty -palette_y) / palette_size #+state["palette_y"] + if rastx > palette_x and rastx < (palette_x + palette_size * 32) and rasty > palette_y and rasty < (palette_y+ palette_size* 32): + if swatchx < 32 and swatchy < 32: + curswatch = (swatchx * 32) + swatchy + Draw.Redraw(1) + + elif swatchy < 34 and swatchx < 32: + curint = 1.0 - (float(rastx-palette_x)/(palette_size*32.0)) + Draw.Redraw(1) + + #copy current color and intensity to selected faces. + elif evt == Draw.CKEY: + + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + #retrieve color from palette + color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + actmesh = state["activeMesh"] + if actmesh: + if(Blender.Window.GetKeyQualifiers() != Blender.Window.Qual["CTRL"]): + selfaces = list() + for face in actmesh.faces: + if face.sel: + selfaces.append(face) + + if not "FLT_COL" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) + for face in actmesh.faces: + face.setProperty("FLT_COL",127) #default + try: + actmesh.activeColorLayer = "FLT_Fcol" + except: + actmesh.addColorLayer("FLT_Fcol") + actmesh.activeColorLayer = "FLT_Fcol" + + + for face in selfaces: + #First append packed index + color and store in face property + face.setProperty("FLT_COL",int(pack_face_index(curswatch,curint))) + #Save baked color to face vertex colors + for col in face.col: + col.r = int(color[0] * curint) + col.g = int(color[1] * curint) + col.b = int(color[2] * curint) + col.a = int(color[3] * curint) + else: + if Blender.Mesh.Mode() == Blender.Mesh.SelectModes['VERTEX']: + if not 'FLT_VCOL' in actmesh.verts.properties: + actmesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"]) + for vert in actmesh.verts: + vert.setProperty("FLT_VCOL",127) + else: + for vert in actmesh.verts: + if vert.sel: + vert.setProperty("FLT_VCOL",int(pack_face_index(curswatch,curint))) + + if editmode: + Blender.Window.EditMode(1) + + Blender.Window.RedrawAll() + + #grab color and intensity from active face + elif evt == Draw.VKEY: + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + actmesh = state["activeMesh"] + activeFace = state["activeFace"] + + + if activeFace: + if not "FLT_COL" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) + for face in actmesh.faces: + face.setProperty("FLT_COL",127) #default + try: + actmesh.activeColorLayer = "FLT_Fcol" + except: + actmesh.addColorLayer("FLT_Fcol") + actmesh.activeColorLayer = "FLT_Fcol" + tcol = activeFace.getProperty("FLT_COL") + (index,intensity) = unpack_face_index(tcol) + curswatch = index + curint = intensity + + if editmode: + Blender.Window.EditMode(1) + + Blender.Window.RedrawAll() + + elif evt == Draw.ESCKEY: + Draw.Exit() + + if editmode: + Blender.Window.EditMode(1) + +def update_all(): + global colors + state = update_state() + #update the baked FLT colors for all meshes. + for object in state["activeScene"].objects: + if object.type == "Mesh": + mesh = object.getData(mesh=True) + if 'FLT_COL' in mesh.faces.properties: + mesh.activeColorLayer = "FLT_Fcol" + for face in mesh.faces: + (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) + color = struct.unpack('>BBBB',struct.pack('>I',colors[index])) + #update the vertex colors for this face + for col in face.col: + col.r = int(color[0] * intensity) + col.g = int(color[1] * intensity) + col.b = int(color[2] * intensity) + col.a = 255 + + +def but_event(evt): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + global picker + state = update_state() + + if evt == 1: + if picker.val: + rval = (int(picker.val[0]*255),int(picker.val[1]*255),int(picker.val[2]*255),255) + rval = struct.pack('>BBBB',rval[0],rval[1],rval[2],rval[3]) + rval = struct.unpack('>i',rval) + colors[curswatch] = rval[0] + #go cd through all meshes and update their FLT colors + update_all() + + Draw.Redraw(1) +def init_pal(): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + + state = update_state() + + if not state["activeScene"].properties.has_key('FLT'): + state["activeScene"].properties['FLT'] = dict() + + try: + colors = state["activeScene"].properties['FLT']['Color Palette'] + except: + state["activeScene"].properties['FLT']['Color Palette'] = defaultp.pal + colors = state["activeScene"].properties['FLT']['Color Palette'] + +def draw_palette(): + global palette_size + global palette_x + global palette_y + global colors + global curint + global curswatch + global picker + + state = update_state() + init_pal() + + ssize = palette_size + xpos = palette_x + cid = 0 + + highlight = [(palette_x,palette_y),(palette_x+palette_size,palette_y),(palette_x+palette_size,palette_y+palette_size),(palette_x,palette_y+palette_size)] + for x in xrange(32): + ypos = palette_y + for y in xrange(32): + color = struct.unpack('>BBBB',struct.pack('>I',colors[cid])) + glColor3f(color[0]/255.0,color[1]/255.0,color[2]/255.0) + glBegin(GL_POLYGON) + glVertex2i(xpos,ypos) + glVertex2i(xpos+ssize,ypos) + glVertex2i(xpos+ssize,ypos+ssize) + glVertex2i(xpos,ypos+ssize) + glEnd() + + if curswatch == cid: + highlight[0] = (xpos,ypos) + highlight[1] = (xpos+ssize,ypos) + highlight[2] = (xpos+ssize,ypos+ssize) + highlight[3] = (xpos,ypos+ssize) + + glColor3f(0.0,0.0,0.0) + glBegin(GL_LINE_LOOP) + glVertex2i(xpos,ypos) + glVertex2i(xpos+ssize,ypos) + glVertex2i(xpos+ssize,ypos+ssize) + glVertex2i(xpos,ypos+ssize) + glVertex2i(xpos,ypos) + glEnd() + + + cid = cid + 1 + ypos = ypos + ssize + + xpos = xpos + ssize + + #draw intensity gradient + color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + color = [color[0]/255.0,color[1]/255.0,color[2]/255.0] + colsteps = [color[0]/255.0,color[1]/255.0,color[2]/255.0] + stripwidth = (palette_size * 32.0) / 256 + strippad = palette_size / 2.0 + + xpos = palette_x + grady = (palette_y + (palette_size * 32.0)) + strippad + for x in xrange(256): + color[0] = color[0] - colsteps[0] + color[1] = color[1] - colsteps[1] + color[2] = color[2] - colsteps[2] + + glColor3f(color[0], color[1] ,color[2]) + glBegin(GL_POLYGON) + glVertex2f(xpos,grady) + glVertex2f(xpos+stripwidth,grady) + glVertex2f(xpos+stripwidth,grady+palette_size) + glVertex2f(xpos,grady+palette_size) + glEnd() + xpos = xpos + stripwidth + + #draw intensity slider bar + #xposition == 512 - ((curint) * 512) + xpos = ((palette_size*32) * (1.0 - curint)) + palette_x + glColor3f(1.0,1.0,1.0) + glBegin(GL_LINE_LOOP) + glVertex2i(xpos-6,grady-1) + glVertex2i(xpos+6,grady-1) + glVertex2i(xpos+6,grady+palette_size+1) + glVertex2i(xpos-6,grady+palette_size+1) + #glVertex2i(xpos-6,grady+7) + glEnd() + + #draw color picker + color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) + pickcol = (color[0]/255.0,color[1]/255.0,color[2]/255.0) + picker = Blender.Draw.ColorPicker(1,highlight[0][0]+1,highlight[0][1]+1,ssize-2,ssize-2,pickcol,ptt) + + #draw highlight swatch + glColor3f(1.0,1.0,1.0) + glBegin(GL_LINE_LOOP) + glVertex2i(highlight[0][0],highlight[0][1]) + glVertex2i(highlight[1][0],highlight[1][1]) + glVertex2i(highlight[2][0],highlight[2][1]) + glVertex2i(highlight[3][0],highlight[3][1]) + glVertex2i(highlight[0][0],highlight[0][1]) + glEnd() + +def gui(): + glClearColor(0.5,0.5,0.5,1.0) + glClear(GL_COLOR_BUFFER_BIT) + draw_palette() + + +init_pal() +Draw.Register(gui,event,but_event) + diff --git a/release/scripts/flt_properties.py b/release/scripts/flt_properties.py new file mode 100644 index 00000000000..07bcc8def1d --- /dev/null +++ b/release/scripts/flt_properties.py @@ -0,0 +1,619 @@ +#!BPY +# flt_properties.py. For setting default OpenFLight ID property types +# Copyright (C) 2007 Blender Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +__bpydoc__ ="""\ +Utility functions and data defintions used by OpenFlight I/O and tool scripts. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. +""" + + +import struct + +bitsLSB = [2147483648] +for i in xrange(31): + bitsLSB.append(bitsLSB[-1]/2) +bitsRSB = bitsLSB[:] +bitsRSB.reverse() + +def pack_color(col): + return struct.pack('>B',col[3]) + struct.pack('>B',col[2]) + struct.pack('>B',col[1]) + struct.pack('>B',col[0]) + +def unpack_color(col): + string = struct.pack('>I', col) + r = struct.unpack('>B',string[3:4]) + g = struct.unpack('>B',string[2:3]) + b = struct.unpack('>B',string[1:2]) + a = struct.unpack('>B',string[0:1]) + return [r,g,b,a] + +def reverse_bits(len,num): + bitbucket = list() + rval = 0 + + for i in xrange(len): + if num & bitsRSB[i]: + bitbucket.append(1) + else: + bitbucket.append(0) + + bitbucket.reverse() + + for i, bit in enumerate(bitbucket): + if bit: + rval |= bitsLSB[i] + + return rval + + +opcode_name = { 0: 'db', + 1: 'head', + 2: 'grp', + 4: 'obj', + 5: 'face', + 10: 'push', + 11: 'pop', + 14: 'dof', + 19: 'push sub', + 20: 'pop sub', + 21: 'push ext', + 22: 'pop ext', + 23: 'cont', + 31: 'comment', + 32: 'color pal', + 33: 'long id', + 49: 'matrix', + 50: 'vector', + 52: 'multi-tex', + 53: 'uv lst', + 55: 'bsp', + 60: 'rep', + 61: 'inst ref', + 62: 'inst def', + 63: 'ext ref', + 64: 'tex pal', + 67: 'vert pal', + 68: 'vert w col', + 69: 'vert w col & norm', + 70: 'vert w col, norm & uv', + 71: 'vert w col & uv', + 72: 'vert lst', + 73: 'lod', + 74: 'bndin box', + 76: 'rot edge', + 78: 'trans', + 79: 'scl', + 80: 'rot pnt', + 81: 'rot and/or scale pnt', + 82: 'put', + 83: 'eyepoint & trackplane pal', + 84: 'mesh', + 85: 'local vert pool', + 86: 'mesh prim', + 87: 'road seg', + 88: 'road zone', + 89: 'morph vert lst', + 90: 'link pal', + 91: 'snd', + 92: 'rd path', + 93: 'snd pal', + 94: 'gen matrix', + 95: 'txt', + 96: 'sw', + 97: 'line styl pal', + 98: 'clip reg', + 100: 'ext', + 101: 'light src', + 102: 'light src pal', + 103: 'reserved', + 104: 'reserved', + 105: 'bndin sph', + 106: 'bndin cyl', + 107: 'bndin hull', + 108: 'bndin vol cntr', + 109: 'bndin vol orient', + 110: 'rsrvd', + 111: 'light pnt', + 112: 'tex map pal', + 113: 'mat pal', + 114: 'name tab', + 115: 'cat', + 116: 'cat dat', + 117: 'rsrvd', + 118: 'rsrvd', + 119: 'bounding hist', + 120: 'rsrvd', + 121: 'rsrvd', + 122: 'push attrib', + 123: 'pop attrib', + 124: 'rsrvd', + 125: 'rsrvd', + 126: 'curv', + 127: 'road const', + 128: 'light pnt appear pal', + 129: 'light pnt anim pal', + 130: 'indexed lp', + 131: 'lp sys', + 132: 'indx str', + 133: 'shdr pal'} + + +typecodes = ['c','C','s','S','i','I','f','d','t'] + +FLT_GRP = 2 +FLT_OBJ = 4 +FLT_LOD = 73 +FLT_XRF = 63 +FLT_DOF = 14 +FLT_ILP = 111 +FLT_DB = 1 +FLT_FCE = 5 + +#not actual opcodes +FLT_NUL = 0 +FLT_EXP = -1 + +#valid childtypes for each FLT node type +FLT_CHILDTYPES = { + FLT_GRP : [111,2,73,4,14,63], + FLT_OBJ : [111], + FLT_LOD : [111,2,73,4,14,63], + FLT_XRF : [], + FLT_DOF : [111,2,73,4,14,63], + FLT_ILP : [] +} + +#List of nodes that can have faces as children +FLT_FACETYPES = [ + FLT_GRP, + FLT_OBJ, + FLT_LOD, + FLT_DOF +] + +def write_prop(fw,type,value,length): + if type == 'c': + fw.write_char(value) + elif type == 'C': + fw.write_uchar(value) + elif type == 's': + fw.write_short(value) + elif type == 'S': + fw.write_ushort(value) + elif type == 'i': + fw.write_int(value) + elif type == 'I': + fw.write_uint(value) + elif type == 'd': + fw.write_double(value) + elif type == 'f': + fw.write_float(value) + elif type == 't': + fw.write_string(value,length) + +def read_prop(fw,type,length): + rval = None + if type == 'c': + rval = fw.read_char() + elif type == 'C': + rval = fw.read_uchar() + elif type == 's': + rval = fw.read_short() + elif type == 'S': + rval = fw.read_ushort() + elif type == 'i': + rval = fw.read_int() + elif type == 'I': + rval = fw.read_uint() + elif type == 'd': + rval = fw.read_double() + elif type == 'f': + rval = fw.read_float() + elif type == 't': + rval = fw.read_string(length) + return rval + +FLTGroup = { + '3t8!id' : 'G', + '4s!priority' : 0, + '5s!reserved1' : 0, + '6i!flags' : 0, + '7s!special1' : 0, + '8s!special2' : 0, + '9s!significance' : 0, + '10c!layer code' : 0, + '11c!reserved2' : 0, + '12i!reserved3' : 0, + '13i!loop count' : 0, + '14f!loop duration' : 0, + '15f!last frame duration' : 0 +} +FLTGroupDisplay = [5,11,12] + +FLTObject = { + '3t8!id' : 'O', + '4I!flags' : 0, + '5s!priority' : 0, + '6S!transp' : 0, + '7s!SFX1' : 0, + '8s!SFX2' : 0, + '9s!significance' : 0, + '10s!reserved' : 0 +} +FLTObjectDisplay = [10] + +FLTLOD = { + '3t8!id' : 'L', + '4i!reserved' : 0, + '5d!switch in' : 0, + '6d!switch out' : 0, + '7s!sfx ID1' : 0, + '8s!sfx ID2' : 0, + '9I!flags' : 0, + '10d!X co' : 0, + '11d!Y co' : 0, + '12d!Z co' : 0, + '13d!Transition' : 0, + '14d!Sig Size' : 0 +} +FLTLODDisplay = [4] + +FLTInlineLP = { + '3t8!id' : 'Lp', + '4s!smc' : 0, + '5s!fid' : 0, + '6C!back color: a' : 255, + '7C!back color: b' : 255, + '8C!back color: g' : 255, + '9C!back color: r' : 255, + '10i!display mode' : 255, + '11f!intensity' : 1.0, + '12f!back intensity' : 0.0, + '13f!minimum defocus' : 0.0, + '14f!maximum defocus' : 1.0, + '15i!fading mode' : 0, + '16i!fog punch mode' : 0, + '17i!directional mode' : 1, + '18i!range mode' : 0, + '19f!min pixel size' : 1.0, + '20f!max pixel size' : 1024, + '21f!actual size' : 0.25, + '22f!trans falloff pixel size' : 0.25, + '23f!trans falloff exponent' : 1.0, + '24f!trans falloff scalar' : 1.0, + '25f!trans falloff clamp' : 1.0, + '26f!fog scalar' : 0.25, + '27f!fog intensity' : 1.0, + '28f!size threshold' : 0.1, + '29i!directionality' : 0, + '30f!horizontal lobe angle' : 180.0, + '31f!vertical lobe angle' : 180.0, + '32f!lobe roll angle' : 0.0, + '33f!dir falloff exponent' : 1.0, + '34f!dir ambient intensity' : 0.1, + '35f!anim period' : 0, + '36f!anim phase' : 0, + '37f!anim enabled' : 0, + '38f!significance' : 0.0, + '39i!draw order' : 0, + '40I!flags' : 813875616, + '41f!roti' : 0, + '42f!rotj' : 0, + '43f!rotk' : 0 +} + +FLTInlineLPDisplay = [35,36,37,41,42,43] + +FLTXRef = { + '3t200!filename' : '', #we dont actually use this value on export + '4i!reserved' : 0, + '5I!flag' : -478150656, + '6s!bbox' : 0, + '7s!reserved' : 0 +} + +FLTXRefDisplay = [4,7,3] + +FLTDOF = { + '3t8!id' : 'D', + '4i!reserved' : 0, + '5d!ORIGX' : 0.0, + '6d!ORIGY' : 0.0, + '7d!ORIGZ' : 0.0, + '8d!XAXIS-X' : 10.0, + '9d!XAXIS-Y' : 0.0, + '10d!XAXIS-Z' : 0.0, + '11d!XYPLANE-X' : 0.0, + '12d!XYPLANE-Y' : 10.0, + '13d!XZPLANE-Z' : 0.0, + '14d!ZMIN' : 0.0, + '15d!ZMAX' : 0.0, + '16d!ZCUR' : 0.0, + '17d!ZSTEP' : 0.0, + '18d!YMIN' : 0.0, + '19d!YMAX' : 0.0, + '20d!YCUR' : 0.0, + '21d!YSTEP' : 0.0, + '22d!XMIN' : 0.0, + '23d!XMAX' : 0.0, + '24d!XCUR' : 0.0, + '25d!XSTEP' : 0.0, + '26d!PITCH-MIN' : 0.0, + '27d!PITCH-MAX' : 0.0, + '28d!PITCH-CUR' : 0.0, + '29d!PITCH-STEP' : 0.0, + '30d!ROLL-MIN' : 0.0, + '31d!ROLL-MAX' : 0.0, + '32d!ROLL-CUR' : 0.0, + '33d!ROLL-STEP' : 0.0, + '34d!YAW-MIN' : 0.0, + '35d!YAW-MAX' : 0.0, + '36d!YAW-CUR' : 0.0, + '37d!YAW-STEP' : 0.0, + '38d!ZSIZE-MIN' : 0.0, + '39d!ZSIZE-MAX' : 0.0, + '40d!ZSIZE-CUR' : 1.0, + '41d!ZSIZE-STEP' : 0.0, + '42d!YSIZE-MIN' : 0.0, + '43d!YSIZE-MAX' : 0.0, + '44d!YSIZE-CUR' : 1.0, + '45d!YSIZE-STEP' : 0.0, + '46d!XSIZE-MIN' : 0.0, + '47d!XSIZE-MAX' : 0.0, + '48d!XSIZE-CUR' : 1.0, + '49d!XSIZE-STEP' : 0.0, + '50I!FLAG' : 1897582, + '51i!reserved2' : 0 +} + +FLTDOFDisplay = [4] + +FLTImage = { + '3i!RealU Direction' : 0, + '4i!RealV Direction' : 0, + '5i!UpX' : 0, + '6i!UpY' : 0, + '7i!File Format' : 0, + '8i!Min Filter' : 1, + '9i!Mag Filter' : 1, + '10i!Wrap' : 0, + '11i!WrapU' : 0, + '12i!WrapV' : 0, + '13i!Modified' : 0, + '14i!PivotX' : 0, + '15i!PivotY' : 0, + '16i!Enviorment' : 0, + '17i!WhiteAlpha' : 0, + '18i!reserved1' : 0, + '19i!reserved2' : 0, + '20i!reserved3' : 0, + '21i!reserved4' : 0, + '22i!reserved5' : 0, + '23i!reserved6' : 0, + '24i!reserved7' : 0, + '25i!reserved8' : 0, + '26i!reserved9' : 0, + '27d!RealU Direction' : 0, + '28d!RealV Direction' : 0, + '29i!Origin' : 0, + '30i!Kernel no.' : 0, + '31i!Internal Format' : 0, + '32i!External Format' : 0, + '33i!MipMap Filter?' : 0, + '34f!MMF1' : 0.0, + '35f!MMF2' : 0.0, + '36f!MMF3' : 0.0, + '37f!MMF4' : 0.0, + '38f!MMF5' : 0.0, + '39f!MMF6' : 0.0, + '40f!MMF7' : 0.0, + '41f!MMF8' : 0.0, + '42i!Tex CPs?' : 0, + '43f!LOD0 CP' : 0.0, + '44f!Scale0 CP' : 0.0, + '45f!LOD1 CP' : 0.0, + '46f!Scale1 CP' : 0.0, + '47f!LOD2 CP' : 0.0, + '48f!Scale2 CP' : 0.0, + '49f!LOD3 CP' : 0.0, + '50f!Scale3 CP' : 0.0, + '51f!LOD4 CP' : 0.0, + '52f!Scale4 CP' : 0.0, + '53f!LOD5 CP' : 0.0, + '54f!Scale5 CP' : 0.0, + '55f!LOD6 CP' : 0.0, + '56f!Scale6 CP' : 0.0, + '57f!LOD7 CP' : 0.0, + '58f!Scale7 CP' : 0.0, + '59f!Control Clamp' : 0.0, + '60i!Mag Alpha Filter' : 0, + '61i!Mag Color Filter' : 0, + '62f!reserved10' : 0, + '63f!reserved11' : 0, + '64f!reserved12' : 0, + '65f!reserved13' : 0, + '66f!reserved14' : 0, + '67f!reserved15' : 0, + '68f!reserved16' : 0, + '69f!reserved17' : 0, + '70f!reserved18' : 0, + '71d!Lambert Central' : 0.0, + '72d!Lambert Upper' : 0.0, + '73d!Lambert Lower' : 0.0, + '74d!reserved19' : 0, + '75f!reserved20' : 0, + '76f!reserved21' : 0, + '77f!reserved22' : 0, + '78f!reserved23' : 0, + '79f!reserved24' : 0, + '80i!Tex Detail?' : 0, + '81i!Tex J' : 0, + '82i!Tex K' : 0, + '83i!Tex M' : 0, + '84i!Tex N' : 0, + '85i!Tex Scramble' : 0, + '86i!Tex Tile?' : 0, + '87f!Tex Tile LLU' : 0.0, + '88f!Tex Tile LLV' : 0.0, + '89f!Tex Tile URU' : 0.0, + '90f!Tex Tile URV' : 0.0, + '91i!Projection' : 0, + '92i!Earth Model' : 0, + '93i!reserved25' : 0, + '94i!UTM Zone' : 0, + '95i!Image Origin' : 0, + '96i!GPU' : 0, + '97i!reserved26' : 0, + '98i!reserved27' : 0, + '99i!GPU Hemi' : 0, + '100i!reserved41' : 0, + '101i!reserved42' : 0, + '102i!reserved43' : 0, + '103i!Cubemap' : 0, + '104t588!reserved44' : '', + '105t512!Comments' : '', + '106i!reserved28' : 0, + '107i!reserved29' : 0, + '108i!reserved30' : 0, + '109i!reserved31' : 0, + '110i!reserved32' : 0, + '111i!reserved33' : 0, + '112i!reserved34' : 0, + '113i!reserved35' : 0, + '114i!reserved36' : 0, + '115i!reserved37' : 0, + '116i!reserved38' : 0, + '117i!reserved39' : 0, + '118i!reserved40' : 0, + '119i!reserved45' : 0, + '120i!Format Version' : 0, + '121i!GPU num' : 0, +} + +FLTImageDisplay = [18,19,29,21,22,23,24,25,26,62,63,64,65,66,67,68,69,70,74,75,76,77,78,79,93,97,98,102,114] + +FLTHeader = { + '3t8!id' : 'db', + '4i!version' : 1620, + '5i!editversion' : 0, + '6t32!date' : 0, + '7s!NGID' : 0, + '8s!NLID' : 0, + '9s!NOID' : 0, + '10s!NFID' : 0, + '11s!UMULT' : 1, + '12c!units' : 0, + '13c!set white' : 0, + '14I!flags' : 0x80000000, + '15i!reserved1' : 0, + '16i!reserved2' : 0, + '17i!reserved3' : 0, + '18i!reserved4' : 0, + '19i!reserved5' : 0, + '20i!reserved6' : 0, + '21i!projection type' : 0, + '22i!reserved7' : 0, + '23i!reserved8' : 0, + '24i!reserved9' : 0, + '25i!reserved10' : 0, + '26i!reserved11' : 0, + '27i!reserved12' : 0, + '28i!reserved13' : 0, + '29s!NDID' : 0, + '30s!vstore' : 1, + '31i!origin' : 0, + '32d!sw x' : 0, + '33d!sw y' : 0, + '34d!dx' : 0, + '35d!dy' : 0, + '36s!NSID' : 0, + '37s!NPID' : 0, + '38i!reserved14' : 0, + '39i!reserved15' : 0, + '40s!NCID' : 0, + '41s!NTID' : 0, + '42s!NBID' : 0, + '43s!NWID' : 0, + '44i!reserved14' : 0, + '45d!sw lat' : 0, + '46d!sw lon' : 0, + '47d!ne lat' : 0, + '48d!ne lon' : 0, + '49d!origin lat' : 0, + '50d!origin lon' : 0, + '51d!lambert lat1' : 0, + '52d!lambert lat2' : 0, + '53s!NLSID' : 0, + '54s!NLPID' : 0, + '55s!NRID' : 0, + '56s!NCATID' : 0, + '57s!reserved15' : 0, + '58s!reserved16' : 0, + '59s!reserved17' : 0, + '60s!reserved18' : 0, + '61i!ellipsoid model' : 1, + '62s!NAID' : 0, + '63s!NCVID' : 0, + '64s!utm zone' : 0, + '65t6!reserved19' : 0, + '66d!dz' : 0, + '67d!radius' : 0, + '68S!NMID' : 0, + '69S!NLPSID' : 0, + '70i!reserved20' : 0, + '71d!major axis' : 0, + '72d!minor axis' : 0, +} + +FLT_Records = { + 2 : FLTGroup, + 4 : FLTObject, + 73 : FLTLOD, + 63 : FLTXRef, + 14 : FLTDOF, + 1 : FLTHeader, + 111 : FLTInlineLP, + 'Image' : FLTImage +} + +def process_recordDefs(): + records = dict() + for record in FLT_Records: + props = dict() + for prop in FLT_Records[record]: + position = '' + slice = 0 + (format,name) = prop.split('!') + for i in format: + if i not in typecodes: + position = position + i + slice = slice + 1 + else: + break + type = format[slice:] + length = type[1:] + if len(length) == 0: + length = 1 + else: + type = type[0] + length = int(length) + + props[int(position)] = (type,length,prop) + records[record] = props + return records + + diff --git a/release/scripts/flt_toolbar.py b/release/scripts/flt_toolbar.py new file mode 100644 index 00000000000..d8a4aa8b4a0 --- /dev/null +++ b/release/scripts/flt_toolbar.py @@ -0,0 +1,594 @@ +#!BPY + +""" +Name: 'FLT Toolbar' +Blender: 240 +Group: 'Misc' +Tooltip: 'Tools for working with FLT databases' +""" + +__author__ = "Geoffrey Bantle" +__version__ = "1.0 11/21/07" +__email__ = ('scripts', 'Author, ') +__url__ = ('blender', 'elysiun') + +__bpydoc__ ="""\ +This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a +registered trademark of MultiGen-Paradigm, Inc. + +Feature overview and more availible at: +http://wiki.blender.org/index.php/Scripts/Manual/FLTools +""" + +# -------------------------------------------------------------------------- +# flt_palettemanager.py version 0.1 2005/04/08 +# -------------------------------------------------------------------------- +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# Copyright (C) 2007: Blender Foundation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# -------------------------------------------------------------------------- + +import Blender.Draw as Draw +from Blender.BGL import * +import Blender +import flt_properties +reload(flt_properties) +from flt_properties import * + +xrefprefix = "" +xrefstack = list() +vofsstack = list() +vquatstack = list() +prop_w = 256 +prop_h = 256 + + +#event codes +evcode = { + "XREF_MAKE" : 100, + "XREF_EDIT" : 101, + "XREF_FILE" : 102, + "XREF_PICK" : 103, + "XREF_SELECT" : 104, + "XREF_POP" : 105, + "XREF_PREFIX" : 106, + "FACE_NAME" : 200, + "FACE_MAKESUB" : 201, + "FACE_KILLSUB" : 202, + "FACE_SELSUB" : 203, + "SCENE_UPDATE" : 303, + "IDPROP_COPY" : 501, + "IDPROP_KILL" : 502, + "CLIGHT_MAKE" : 700 +} + +XREF_PREFIX = None +XREF_MAKE = None +XREF_EDIT = None +XREF_SELECT = None +XREF_POP = None +FACE_MAKESUB = None +FACE_SELSUB = None +FACE_KILLSUB = None +IDPROP_KILL = None +IDPROP_COPY = None +SCENE_UPDATE = None +CLIGHT_MAKE = None + +def update_state(): + state = dict() + state["activeScene"] = Blender.Scene.getCurrent() + state["activeObject"] = state["activeScene"].getActiveObject() + if state["activeObject"] and not state["activeObject"].sel: + state["activeObject"] = None + state["activeMesh"] = None + if state["activeObject"] and state["activeObject"].type == 'Mesh': + state["activeMesh"] = state["activeObject"].getData(mesh=True) + + state["activeFace"] = None + if state["activeMesh"]: + if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: + state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] + + #update editmode + state["editmode"] = Blender.Window.EditMode() + + return state +def pack_face_index(index, intensity): + return ((127*intensity)+(128*index)) +def unpack_face_index(face_index): + index = face_index / 128 + intensity = float(face_index - 128.0 * index) / 127.0 + return(index,intensity) + +def idprops_append(object, typecode, props): + object.properties["FLT"] = dict() + object.properties["FLT"]['type'] = typecode + for prop in props: + object.properties["FLT"][prop] = props[prop] + object.properties["FLT"]['3t8!id'] = object.name + +def idprops_kill(object): + state = update_state() + if object and object.properties.has_key('FLT'): + object.properties.pop('FLT') + +def idprops_copy(source): + state = update_state() + if source.properties.has_key('FLT'): + for object in state["activeScene"].objects: + if object.sel and object != source and (state["activeScene"].Layers & object.Layers): + idprops_kill(object) + object.properties['FLT'] = dict() + for key in source.properties['FLT']: + object.properties['FLT'][key] = source.properties['FLT'][key] + +def update_all(): + state = update_state() + #update the baked FLT colors for all meshes. + for object in state["activeScene"].objects: + if object.type == "Mesh": + mesh = object.getData(mesh=True) + if 'FLT_COL' in mesh.faces.properties: + mesh.activeColorLayer = "FLT_Fcol" + for face in mesh.faces: + (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) + color = struct.unpack('>BBBB',struct.pack('>I',state["colors"][index])) + #update the vertex colors for this face + for col in face.col: + col.r = int(color[0] * intensity) + col.g = int(color[1] * intensity) + col.b = int(color[2] * intensity) + col.a = 255 + + +#Change this to find the deep parent +def xref_create(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + + def findchildren(object): + children = list() + for candidate in state["activeScene"].objects: + if candidate.parent == object: + children.append(candidate) + retlist = list(children) + for child in children: + retlist = retlist + findchildren(child) + return retlist + + actObject = state["activeObject"] + if actObject and xrefprefix: + scenenames = list() + for scene in Blender.Scene.Get(): + scenenames.append(scene.name) + + if xrefprefix in scenenames: + #build a unique name for the xref... + suffix = 1 + found = False + while not found: + candidate = xrefprefix + str(suffix) + if not candidate in scenenames: + xrefname = candidate + found = True + suffix+=1 + else: + xrefname = xrefprefix + #create our XRef node + xnode = state["activeScene"].objects.new('Empty') + xnode.name = 'X:' + xrefname + xnode.properties['FLT'] = dict() + for prop in FLTXRef: + xnode.properties['FLT'][prop] = FLTXRef[prop] + xnode.properties['FLT']['3t200!filename'] = xrefname + '.flt' + xnode.properties['FLT']['type'] = 63 + xnode.enableDupGroup = True + xnode.DupGroup = Blender.Group.New(xrefname) #this is dangerous... be careful! + + #copy rot and loc of actObject + xnode.setLocation(actObject.getLocation()) + xnode.setEuler(actObject.getEuler()) + + #build the new scene + xrefscene = Blender.Scene.New(xrefname) + xrefscene.properties['FLT'] = dict() + xrefscene.properties['FLT']['Filename'] = xrefname + xrefscene.properties['FLT']['Main'] = 0 + + #find the children of actObject so that we can add them to the group + linkobjects = findchildren(actObject) + linkobjects.append(actObject) + for object in linkobjects: + xrefscene.objects.link(object) + state["activeScene"].objects.unlink(object) + xnode.DupGroup.objects.link(object) + #clear rotation of actObject and location + actObject.setLocation(0.0,0.0,0.0) + actObject.setEuler(0.0,0.0,0.0) + + xrefscene.update(1) + state["activeScene"].update(1) + +def xref_edit(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + + actObject = state["activeObject"] + + if actObject and actObject.type == 'Empty' and actObject.DupGroup: +# if actObject.properties.has_key('FLT') and actObject.properties['FLT']['type'] == 63: + for FLTscene in Blender.Scene.Get(): + if FLTscene.properties.has_key('FLT') and FLTscene.name == actObject.DupGroup.name: + actObject.sel = 0 + xrefstack.append(state["activeScene"]) + vofsstack.append(Blender.Window.GetViewOffset()) + vquatstack.append(Blender.Window.GetViewQuat()) + FLTscene.makeCurrent() + Blender.Window.SetViewOffset(0.0,0.0,0.0) + +def xref_finish(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + if xrefstack: + scene = xrefstack.pop() + Blender.Window.SetViewQuat(vquatstack.pop()) + Blender.Window.SetViewOffset(vofsstack.pop()) + scene.makeCurrent() + + +def sortSub(a,b): + aindex = a.getProperty("FLT_ORIGINDEX") + bindex = b.getProperty("FLT_ORIGINDEX") + + if aindex > bindex: + return 1 + elif aindex < bindex: + return -1 + return 0 + +def subface_make(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + editmode = 0 + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + + state = update_state() + + actmesh = state["activeMesh"] + activeFace = state["activeFace"] + if actmesh: + if not "FLT_ORIGINDEX" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"]) + for i, face in enumerate(actmesh.faces): + face.setProperty("FLT_ORIGINDEX",i) + if not "FLT_SFLEVEL" in actmesh.faces.properties: + actmesh.faces.addPropertyLayer("FLT_SFLEVEL",Blender.Mesh.PropertyTypes["INT"]) + + #attach the subfaces to the active face. Note, this doesnt really work 100 percent properly yet, just enough for one level! + if activeFace: + #steps: + #remove actface and selected faces from the facelist + #quicksort facelist + #append actface and subfaces to end of facelist. + #generate new indices + facelist = list() + sublist = list() + for face in actmesh.faces: + facelist.append(face) + for face in facelist: + if face == activeFace: + face.setProperty("FLT_SFLEVEL",0) + sublist.insert(0,face) + elif face.sel: + face.setProperty("FLT_SFLEVEL",1) + sublist.append(face) + for face in sublist: + facelist.remove(face) + facelist.sort(sortSub) + for face in sublist: + facelist.append(face) + for i, face in enumerate(facelist): + face.setProperty("FLT_ORIGINDEX",i) + else: + pass + + if editmode: + Blender.Window.EditMode(1) + +def subface_kill(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + editmode = 0 + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + actmesh = state["activeMesh"] + if actmesh: + if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: + for i,face in enumerate(actmesh.faces): + face.setProperty("FLT_ORIGINDEX",i) + face.setProperty("FLT_SFLEVEL",0) + if editmode: + Blender.Window.EditMode(1) + +def subface_select(): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + editmode = 0 + if Blender.Window.EditMode(): + Blender.Window.EditMode(0) + editmode = 1 + state = update_state() + + actmesh = state["activeMesh"] + activeFace = state["activeFace"] + if actmesh and activeFace: + if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: + facelist = list() + actIndex = None + sublevel = None + for face in actmesh.faces: + facelist.append(face) + facelist.sort(sortSub) + for i, face in enumerate(facelist): + if face == activeFace: + actIndex = i + sublevel = face.getProperty("FLT_SFLEVEL")+1 + break + leftover = facelist[actIndex+1:] + for face in leftover: + if face.getProperty("FLT_SFLEVEL") == sublevel: + face.sel = 1 + else: + break + if editmode: + Blender.Window.EditMode(1) + +def select_by_typecode(typecode): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + + state = update_state() + + for object in state["activeScene"].objects: + if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers: + object.select(1) +def clight_make(): + state = update_state() + actmesh = state["activeMesh"] + actobj = state["activeObject"] + + if actobj and actmesh: + actobj.properties['FLT'] = dict() + actobj.properties['FLT']['type'] = 111 + for prop in FLTInlineLP: + actobj.properties['FLT'][prop] = FLTInlineLP[prop] + + actmesh.verts.addPropertyLayer("FLT_VCOL", Blender.Mesh.PropertyTypes["INT"]) + for v in actmesh.verts: + v.setProperty("FLT_VCOL", 67295) + +def event(evt,val): + if evt == Draw.ESCKEY: + Draw.Exit() + +def but_event(evt): + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + global evcode + + state = update_state() + + #do Xref buttons + if evt == evcode["XREF_PREFIX"]: + xrefprefix = XREF_PREFIX.val + if evt == evcode["XREF_EDIT"]: + xref_edit() + if evt == evcode["XREF_SELECT"]: + select_by_typecode(63) + if evt == evcode["XREF_MAKE"]: + xref_create() + #do scene buttons + if evt == evcode["SCENE_UPDATE"]: + update_all() + #do face buttons + if evt == evcode["FACE_MAKESUB"]: + subface_make() + if evt== evcode["FACE_KILLSUB"]: + subface_kill() + if evt== evcode["FACE_SELSUB"]: + subface_select() + #common buttons + if evt == evcode["IDPROP_KILL"]: + if state["activeObject"]: + idprops_kill(state["activeObject"]) + if evt == evcode["IDPROP_COPY"]: + if state["activeObject"]: + idprops_copy(state["activeObject"]) + if evt == evcode["XREF_POP"]: + xref_finish() + if evt == evcode["CLIGHT_MAKE"]: + clight_make() + Draw.Redraw(1) + Blender.Window.RedrawAll() + + +def box(x,y,w,h,c,mode): + glColor3f(c[0],c[1],c[2]) + if mode == "outline": + glBegin(GL_LINE_LOOP) + else: + glBegin(GL_POLYGON) + glVertex2i(x,y) + glVertex2i(x+w,y) + glVertex2i(x+w,y+h) + glVertex2i(x,y+h) + glEnd() + +def draw_postcommon(x,y,finaly): + global sheetlabel + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + global evcode + + state = update_state() + + width = prop_w + height = prop_h + + #draw the header + glColor3f(0.15,0.15,0.15) + glBegin(GL_POLYGON) + glVertex2i(x-1,y) + glVertex2i(x+width+1,y) + glVertex2i(x+width+1,y-25) + glVertex2i(x-1,y-25) + glEnd() + glColor3f(1,1,1) + glRasterPos2i(x,y-20) + sheetlabel = Blender.Draw.Text("FLT Tools Panel") + #draw the box outline + glColor3f(0,0,0) + glBegin(GL_LINE_LOOP) + glVertex2i(x-1,y) + glVertex2i(x+1+width,y) + glVertex2i(x+1+width,finaly-1) + glVertex2i(x-1,finaly-1) + glEnd() + return finaly + + +def draw_propsheet(x,y): + global XREF_PREFIX + global XREF_MAKE + global XREF_EDIT + global XREF_SELECT + global XREF_POP + global FACE_MAKESUB + global FACE_SELSUB + global FACE_KILLSUB + global IDPROP_KILL + global IDPROP_COPY + global SCENE_UPDATE + global CLIGHT_MAKE + global xrefprefix + global xrefstack + global vofsstack + global vquatstack + global prop_w + global prop_h + global evcode + + state = update_state() + + width = prop_w + height = prop_h + origx = x + origy = y + + #draw Xref tools + y = y-20 + XREF_PREFIX = Blender.Draw.String("XRef Name:",evcode["XREF_PREFIX"],x,y,width,20,xrefprefix,18,"Xref prefix name, Actual name is generated from this") + y = y-20 + XREF_MAKE = Blender.Draw.PushButton("Make XRef",evcode["XREF_MAKE"],x,y,width,20,"Make External Reference") + y = y-20 + XREF_EDIT = Blender.Draw.PushButton("Edit XRef",evcode["XREF_EDIT"],x,y,width,20,"Edit External Reference") + y = y-20 + XREF_SELECT = Blender.Draw.PushButton("Select XRefs",evcode["XREF_SELECT"],x,y,width,20,"Select External References") + y = y - 20 + XREF_POP = Blender.Draw.PushButton("Return to previous scene",evcode["XREF_POP"],x,y,width,20,"Go up one level in xref hierarchy") + + #Draw facetools + y = y-20 + FACE_MAKESUB = Blender.Draw.PushButton("Make Subfaces",evcode["FACE_MAKESUB"],x,y,width,20,"Make subfaces") + y = y-20 + FACE_SELSUB = Blender.Draw.PushButton("Select Subfaces",evcode["FACE_SELSUB"],x,y,width,20,"Select subfaces") + y = y-20 + FACE_KILLSUB = Blender.Draw.PushButton("Kill Subfaces",evcode["FACE_KILLSUB"],x,y,width,20,"Kill subfaces") + + #Draw ID Property tools + y = y - 20 + IDPROP_KILL = Blender.Draw.PushButton("Delete ID props",evcode["IDPROP_KILL"],x,y,width,20,"Delete ID props") + y = y - 20 + IDPROP_COPY = Blender.Draw.PushButton("Copy to selected",evcode["IDPROP_COPY"],x,y,width,20, "Copy from active to all selected") + + y= y - 20 + CLIGHT_MAKE = Blender.Draw.PushButton("Make Light Point", evcode["CLIGHT_MAKE"],x,y,width,20,"Create inline light points from current mesh") + #General tools + y = y-20 + SCENE_UPDATE = Blender.Draw.PushButton("Update All",evcode["SCENE_UPDATE"],x,y,width,20,"Update all vertex colors") + draw_postcommon(origx, origy,y) + +def gui(): + #draw the propsheet/toolbox. + psheety = 256 + #psheetx = psheety + 10 + draw_propsheet(0,psheety) +Draw.Register(gui,event,but_event) + |