Advertisement
Guest User

Untitled

a guest
Sep 16th, 2010
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.31 KB | None | 0 0
  1. #MOD AO PLATE MAKER
  2. #by Beherith mysterme@gmail.com
  3.  
  4. #how to use:
  5. # 1. install xnormal, python 2.6 and python imaging library (PIL)
  6. # 2. edit xnormalpath (in this file) to contain the path to xnormal.
  7. # Remember that the slashes '\' must be replaced with \\,
  8. # and that you shoudlnt leave out the trailing \", because it allows spaces into the path
  9. # 3. install imagemagick, make sure to allow it to modify your path
  10. # 4. copy the desired .fbi files and .s3o and .3do files and their preexisting gound plates next to this script into their respective 'units', 'unittextures' and 'objects3d' folders
  11. # Dont place unitdefs into subdirectories in 'units', place them all into the root of 'units'
  12. # Script will only run on units that have (maxvelocity=0 or no max velocity tag) and no waterline tag
  13. # 5. run python aobaker.py from the command line
  14. # Specifying a unitname like so:
  15. # python aobaker.py armllt
  16. # results in aobaker only running on that file
  17. # 6. copy the fbi files back into the mod, copy all the *_aoplate.dds files into unittextures
  18. # 7. run spring!
  19.  
  20. #-------------------------------------------------
  21. #Todo:
  22. #fix bake:
  23. # clamp to max
  24. # expand to min
  25. # increase to 256 rays
  26. # fiddle with burn
  27. #make better documentation (yeah like thats gonna happen)
  28. #add support for fucking luadefs (dislike lua)
  29. #-------------------------------------------------
  30. import winsound
  31. import sys
  32. import os
  33. from struct import *
  34. import Image
  35. xnormalpath="\"C:\\Program Files (x86)\\Santiago Orgaz\\xNormal\\3.17.0\\x64\\"
  36. pnum=1
  37. vnum=1
  38. runxnormal=1
  39. runimagemagick=1
  40. runnvdxt=1
  41. only=''
  42. cwd=os.getcwd()
  43. aoraysperpixel=256
  44. aoplaterez=128
  45. defdir='.\\units\\'
  46. texdir='.\\unittextures\\'
  47. objdir='.\\objects3d\\'
  48. print 'Working in :',cwd
  49. if len(sys.argv)==2:
  50. only=sys.argv[1]
  51.  
  52. for filename in os.listdir(os.getcwd()+defdir):
  53. if (".fbi" in filename.lower() and only in filename) or (".lua" in filename.lower() and only in filename):# or len(sys.argv>2 filename in sys.argv:# and filename.partition('.')[0]>'armdf':
  54.  
  55. pnum=1
  56. fname=filename.partition('.')[0]+'.3do'
  57. outfname=fname.partition('.')[0]+'.obj'
  58. #f=open(fname,'rb')
  59. vnum=1
  60. deftype='fbi'
  61. if 'lua' in filename:
  62. deftype='lua'
  63. fbifilename=fname.partition('.')[0]+'.lua'
  64. else:
  65. fbifilename=fname.partition('.')[0]+'.fbi'
  66. print 'Definition type is',deftype
  67. fbi=open(defdir+fbifilename,'r')
  68. fbiln=fbi.readlines()
  69. static=0
  70. #-----------------Parse for FBIs for static buildings-------------------
  71. nomaxvel=1
  72. wl=0
  73. mv=-1
  74. for l in fbiln:
  75. if 'maxvelocity' in l.lower():
  76. nomaxvel=0
  77. mv=-1
  78. try:
  79. mv=float(l.partition('=')[2].strip().strip(';,'))
  80. except ValueError:
  81. print 'cant parse maxvelocity!'
  82. if mv==0.0:
  83. static=1
  84. break
  85.  
  86. for l in fbiln:
  87. if 'waterline' in l.lower():
  88. static=0
  89. wl=1
  90. break
  91. # if 'useBuildingGroundDecal' in l.lower():
  92. # static=0
  93. if nomaxvel==1:
  94. static=1
  95. if static==0:
  96. print filename, ': not static (mv',mv, ' no mv:',nomaxvel,' waterline:',wl
  97. continue
  98.  
  99.  
  100. objectname=''
  101.  
  102. fpx=0
  103. fpz=0
  104.  
  105. #-----------------Parse fbi for footprint-------------------
  106.  
  107. for l in fbiln:
  108. if 'footprintx' in l.lower():
  109. try:
  110. fpx=int(l.partition('=')[2].strip().strip(';,'))
  111. except ValueError:
  112. print 'cant parse footprintx!'
  113. break
  114. for l in fbiln:
  115. if 'footprintz' in l.lower():
  116. try:
  117. fpz=int(l.partition('=')[2].strip().strip(';,'))
  118. except ValueError:
  119. print 'cant parse footprintz!'
  120. break
  121. for l in fbiln:
  122. if 'objectname' in l.lower():
  123. if deftype=='fbi':
  124. objectname=l.partition('=')[2].strip().strip(';').strip()
  125. else:
  126. objectname=l.partition('=')[2].strip().strip(',').strip().strip('[]\"')
  127. break
  128. print 'fbi parsed' , filename
  129.  
  130. #------------------------Parse for pre existing groundplate (preferably one not made by this)--------------
  131. preplate=''
  132. for l in fbiln:
  133. if 'buildinggrounddecaltype' in l.lower():
  134. if 'aoplane.dds' in l.lower().partition('=')[2]:
  135. print filename, ' already contains an aoplate'
  136. break
  137. else:
  138. if '.dds' in l.lower() or '.png' in l.lower() or '.tga' in l.lower():
  139. preplate=l.lower().partition('=')[2].strip().strip(',[];\"').strip()
  140. try:
  141. pp=open(texdir+preplate,'r')
  142. except IOError:
  143. print 'Cant open premade plate',texdir+preplate,' referenced from',filename
  144. preplate=''
  145. break
  146. pp.close()
  147. if '.dds' in l.lower():
  148. cmd='convert '+texdir+preplate+' '+texdir+preplate.partition('.')[0]+'.tga'
  149. preplate=preplate.partition('.')[0]+'.tga'
  150. print cmd
  151. os.system(cmd)
  152.  
  153. else:
  154. print 'Error, groundplate not .DDS format!'
  155. preplate=''
  156. ppx=0
  157. ppy=0
  158. pprez=aoplaterez
  159. if preplate!='':
  160. for l in fbiln:
  161. if 'buildinggrounddecalsizex' in l.lower():
  162. try:
  163. ppx=int(l.partition('=')[2].strip().strip(',[];').strip())
  164. except ValueError:
  165. print 'Failed to parse buildingGroundDecalSizeX in',l,'in file:',filename
  166. if 'buildinggrounddecalsizey' in l.lower():
  167. try:
  168. ppy=int(l.partition('=')[2].strip().strip(',[];').strip())
  169. except ValueError:
  170. print 'Failed to parse buildingGroundDecalSizeY in',l,'in file:',filename
  171. if ppx>0 and ppy>0:
  172. try:
  173. ppimg=Image.open(texdir+preplate,'r')
  174. ppsizex,ppsizey=ppimg.size
  175. except:
  176. print '------ERROR!-------------------------------Unable to open preexisting groundplate file!',preplate,filename
  177. continue
  178. if ppsizex!=ppsizey:
  179. print ' fucked up ground plate dimensions!', ppsizex, ppsizey
  180. else:
  181. pprez=ppsizex
  182. print 'plate sizes parsed successfully! ',ppx, ppy,pprez
  183. else:
  184. print 'plate sizes not parsed well!'
  185. preplate=''
  186.  
  187. def reads3o(filename):
  188.  
  189. try:
  190. s3o=open(filename,'rb')
  191. except IOError:
  192. print "FAILED TO OPEN s3o file ",filename,'!\n'
  193. return
  194. magic=s3o.read(12)
  195. header=s3o.read(4+5*4+4*4)
  196. header=unpack('ifffffiiii',header)
  197. print 'header:',header
  198. recursereads3o(s3o, header[6],0,0,0)
  199.  
  200. def recursereads3o(f,p,ox,oy,oz):
  201. global pnum
  202. global vnum
  203.  
  204. f.seek(p)
  205. piece=f.read(10*4+3*4)
  206. piece=unpack('iiiiiiiiiifff',piece)
  207. obj.write('o object'+str(pnum)+'\n')
  208. # print 'piece:',piece
  209. # print 'numchilds:',piece[1]
  210. # print 'numvertices:',piece[3]
  211. # print 'verticeoffset:',piece[4]
  212. # print 'primitivetype:',piece[6]
  213. # print 'vertextablesize:',piece[7]
  214. # print 'vertextableoffset:',piece[8]
  215. # print 'piece:',piece
  216. # print 'piece:',piece
  217. # print 'piece:',piece
  218. pnum+=1
  219. nv=piece[3]
  220. f.seek(piece[4])
  221. vertices=[]
  222. ox+=piece[10]
  223. oy+=piece[11]
  224. oz+=piece[12]
  225. # print 'numverts:',nv
  226. for i in range(0,nv):
  227. try:
  228. readdata=f.read(4*8)
  229. if len(readdata)!=32:
  230. print '-----======ERROR, read data is only ',len(readdata)
  231.  
  232. #print 'vertex read success'
  233. v=unpack('ffffffff',readdata)
  234. #print 'vertex', v, i, ' of ',nv
  235. except error:
  236. print 'readdatalength:',len(readdata)
  237. print v, i, ' of ',nv
  238.  
  239. #print v[0] / (65536.0),v[1] / (65536.0), v[2] / (65536.0)
  240. obj.write('v '+str(v[0]+ox)+' '+str(v[1]+oy)+' '+str(v[2]+oz)+'\n')
  241. obj.write('vn '+str(v[3])+' '+str(v[4])+' '+str(v[5])+'\n')
  242. obj.write('vt 0 0\n') # or should be this for proper export: obj.write('vt '+str(v[6])+' '+str(v[7])+'\n')
  243. vertices.append([v[0]+piece[10],v[1]+piece[11],v[2]+piece[12]])
  244.  
  245. f.seek(piece[8])
  246. vtable=f.read(piece[7]*4)
  247.  
  248.  
  249. unpackstr=''
  250. for i in range(0,piece[7]):
  251. unpackstr+='l'
  252. # print 'vtable length:',len(vtable)
  253. prims=unpack(unpackstr,vtable)
  254. # print 'primitives:',len(prims),' ',prims
  255. if piece[6]==0: #triangles:
  256. for i in range(0,len(prims),3):
  257. obj.write('f '+str(prims[i]+vnum)+'/'+str(prims[i]+vnum)+'/'+str(prims[i]+vnum)+' '+str(prims[i+1]+vnum)+'/'+str(prims[i+1]+vnum)+'/'+str(prims[i+1]+vnum)+' '+str(prims[i+2]+vnum)+'/'+str(prims[i+2]+vnum)+'/'+str(prims[i+2]+vnum)+'\n')
  258. if piece[6]==2: #quads:
  259. for i in range(0,len(prims),4):
  260. obj.write('f '+str(prims[i]+vnum)+'/'+str(prims[i]+vnum)+'/'+str(prims[i]+vnum)+' '+str(prims[i+1]+vnum)+'/'+str(prims[i+1]+vnum)+'/'+str(prims[i+1]+vnum)+' '+str(prims[i+2]+vnum)+'/'+str(prims[i+2]+vnum)+'/'+str(prims[i+2]+vnum)+' '+str(prims[i+3]+vnum)+'/'+str(prims[i+3]+vnum)+'/'+str(prims[i+3]+vnum)+'\n')
  261.  
  262. if piece[6]==1: #tristrips:
  263. fstr='f'
  264. for i in prims:
  265. if i>100000000: #0xffffffff means end of strip:
  266. fstr+='\n'
  267. obj.write(fstr)
  268. fstr='f'
  269. else:
  270. fstr+= ' '+str(i+vnum)+'/'+str(i+vnum)+'/'+str(i+vnum)
  271.  
  272. vnum+=nv
  273. f.seek(piece[2])
  274. for i in range(0,piece[1]):
  275. f.seek(piece[2]+4*i)
  276.  
  277. child=f.read(4)
  278. # print child
  279. f.seek(unpack('l',child)[0])
  280. recursereads3o(f,unpack('l',child)[0],ox,oy,oz)
  281.  
  282. return
  283.  
  284.  
  285.  
  286. def recurseread3do(px, py, pz):
  287. #--------------------- unpack 3d0 files to OBJ files------------------------
  288. #print 'reading 3do'
  289. global vnum
  290. global pnum
  291. main=f.read(13*4)
  292. mo=unpack('lllllllllllll', main)
  293.  
  294. # print mo
  295. f.seek(mo[7])
  296. obj.write('o object'+str(pnum)+'\n')
  297.  
  298. pnum+=1
  299. nv=mo[1]
  300. f.seek(mo[9])
  301. vertices=[]
  302. for i in range(0,nv):
  303. v=unpack('lll',f.read(4*3))
  304.  
  305. #print v[0] / (65536.0),v[1] / (65536.0), v[2] / (65536.0)
  306. obj.write('v '+str( (v[0]+px+mo[4]) / (65536.0))+' '+str( (v[1]+py+mo[5]) / (65536.0))+' '+str( (v[2]+pz+mo[6]) / (65536.0))+'\n')
  307. vertices.append([v[0] / (65536.0),v[1] / (65536.0), v[2] / (65536.0)])
  308. f.seek(mo[10])
  309.  
  310. np=mo[2]
  311.  
  312. if vnum==1:
  313. obj.write('vt 0 0'+'\n')
  314. firstplate=1
  315. for i in range(0,np):
  316. f.seek(mo[10]+32*i)
  317. p=unpack('llllllll',f.read(4*8))
  318. #print p
  319. nvi=p[1]
  320. f.seek(p[3])
  321. if nvi==3:
  322. vi=unpack('HHH',f.read(2*3))
  323. if nvi==4:
  324. vi=unpack('HHHH',f.read(2*4))
  325. if not (nvi==3 or nvi==4):
  326. continue
  327. if p[4]==0:
  328. # print 'no texture on primitive ',p
  329. continue
  330. if nvi==4 and firstplate==1: #remove selection plate from 3do
  331. if vi[0]+vnum==1:
  332. vsum1= abs(vertices[vi[0]+1][0]) +abs(vertices[vi[0]+1][2])
  333. vsum2= abs(vertices[vi[0]+2][0]) +abs(vertices[vi[0]+2][2] )
  334. vsum3= abs(vertices[vi[0]+3][0]) +abs(vertices[vi[0]+3][2] )
  335. vsum4= abs(vertices[vi[0]][0]) +abs(vertices[vi[0]][2])
  336. print vsum4
  337. if (abs(vsum1-vsum2)<0.01 and abs(vsum1-vsum3)<0.01 and abs(vsum1-vsum4)<0.01) :
  338. firstplate=0
  339. print 'Skipping first plate'
  340. continue
  341.  
  342. obj.write('f')
  343. for j in vi:
  344. obj.write(' '+str(j+vnum)+'/1/')
  345. obj.write('\n')
  346. vnum+=nv
  347.  
  348. if mo[12]!=0:##child
  349. f.seek(mo[12])
  350. recurseread3do(px+mo[4],py+mo[5],pz+mo[6])
  351. if mo[11]!=0: ##sibling
  352. f.seek(mo[11])
  353. recurseread3do(px,py,pz)
  354. filetype=''
  355. if '.s3o' not in objectname.lower():
  356. print 'objtype 3do', objectname
  357. try:
  358. f=open(objdir+objectname.partition('.')[0]+'.3do','rb')
  359. except IOError:
  360. print "FAILED TO OPEN 3d0 file ",objectname,'!\n'
  361. continue
  362. obj=open(outfname,'w')
  363. filetype='3do'
  364. print 'wtf'
  365. recurseread3do(0,0,0)
  366. else:
  367. print 'objtype s3o'
  368. filetype='s3o'
  369. obj=open(outfname,'w')
  370. reads3o(objdir+objectname)
  371.  
  372. print 'working on: ',filename,' vertices: ',vnum,' parts:',pnum
  373. obj.write('o groundplane\n')
  374. #--------------------- create AO plate ------------------------
  375. largeao=''
  376. size=8*max(fpz,fpz)
  377. if size>=5*8:
  378. largeao='large'
  379. size+=24
  380. else:
  381. size+=16
  382. if preplate=='':
  383. sizex=size
  384. sizez=size
  385. else:
  386. sizex=ppx*8
  387. sizez=ppy*8
  388.  
  389. obj.write('v '+str(sizex)+' 0 '+str(sizez)+'\n')
  390. obj.write('v '+str(sizex)+' 0 '+str(-sizez)+'\n')
  391. obj.write('v '+str(-sizex)+' 0'+str(-sizez)+'\n')
  392. obj.write('v '+str(-sizex)+' 0 '+str(sizez)+'\n')
  393. obj.write('vt 1 0\n')
  394. obj.write('vt 1 1\n')
  395. obj.write('vt 0 1\n')
  396. obj.write('vt 0 0\n')
  397. if filetype=='3do':
  398. obj.write('f '+str(vnum)+'/2/ '+str(vnum+1)+'/3/ '+str(vnum+2)+'/4/ '+str(vnum+3)+'/5/ \n')
  399.  
  400. else:
  401. obj.write('vn 0 1 0\n')
  402. obj.write('vn 0 1 0\n')
  403. obj.write('vn 0 1 0\n')
  404. obj.write('vn 0 1 0\n')
  405. obj.write('f '+str(vnum)+'/'+str(vnum)+'/'+str(vnum)+' '+str(vnum+1)+'/'+str(vnum+1)+'/'+str(vnum+1)+' '+str(vnum+2)+'/'+str(vnum+2)+'/'+str(vnum+2)+' '+str(vnum+3)+'/'+str(vnum+3)+'/'+str(vnum+3)+'\n')
  406.  
  407. obj.close()
  408. #--------------------- edit xnormal settings XML file------------------------
  409. xml=open('aoplane.xml','r')
  410. xmlln=xml.readlines()
  411. xmlfilename='xnormalsettings.xml'
  412. xmlout=open(xmlfilename,'w')
  413. for l in xmlln:
  414. if 'S:\\models\\!AO\\corfus+plane2.obj' in l:
  415. print 'found .obj in xml'
  416. l=l.replace('S:\\models\\!AO\\corfus+plane2.obj',cwd+'\\'+outfname)
  417. if 'S:\\models\\!AO\\corfusplaneuniform.bmp' in l:
  418. l=l.replace('S:\\models\\!AO\\corfusplaneuniform.bmp',cwd+'\\'+outfname.partition('.')[0]+'_ao.bmp')
  419. print 'found .bmp in xml'
  420. if 'Width=\"128\" Height=\"128\"' in l:
  421. l=l.replace('Width=\"128\" Height=\"128\"','Width=\"'+str(pprez)+'\" Height=\"'+str(pprez)+'\"')
  422. if 'Width=\"128\" Height=\"128\"' in l:
  423. l=l.replace('Width=\"128\" Height=\"128\"','Width=\"'+str(pprez)+'\" Height=\"'+str(pprez)+'\"')
  424. xmlout.write(l)
  425. xmlout.close()
  426. #--------------------- run xnormal------------------------
  427. if runxnormal==1:
  428. os.system('del '+outfname.partition('.')[0]+'_ao_occlusion.bmp')
  429. cmd=xnormalpath+'xnormal.exe\" '+xmlfilename
  430. print cmd
  431. os.system(cmd)
  432.  
  433. #--------------------- Adjust color balance of AO bake ------------------------------------------
  434. img=Image.open(outfname.partition('.')[0]+'_ao_occlusion.bmp')
  435. impl=img.load()
  436.  
  437. w,h=img.size
  438. tl=img.getpixel((0,0))
  439. bl=img.getpixel((0,h-1))
  440. tr=img.getpixel((w-1,0))
  441. br=img.getpixel((w-1,h-1))
  442. modifier= min(tl[0]+tl[1]+tl[2],tr[0]+tr[1]+tr[2],bl[0]+bl[1]+bl[2],br[0]+br[1]+br[2])-10
  443. modifier=255 -int(modifier/3.0)
  444. maxdarkness =32
  445. darken=0.8
  446.  
  447. for x in range(w):
  448. for y in range(h):
  449. px=img.getpixel((x,y))
  450. p=(px[1]+px[2]+px[0])/3
  451. p=min(p+modifier,255)
  452. p=p-(255-p)/8
  453.  
  454. p=max(maxdarkness,p)
  455. img.putpixel((x,y),(p,p,p))
  456. img.save(outfname.partition('.')[0]+'_ao_normalized.bmp')
  457.  
  458.  
  459. #--------------------- make color channel black, and put AO bake into alpha channel------------------------
  460.  
  461. if runimagemagick==1:
  462. if filetype =='s3o':
  463. cmd='convert -flip '+outfname.partition('.')[0]+'_ao_normalized.bmp '+outfname.partition('.')[0]+'_ao_normalized.bmp'
  464. print cmd
  465. os.system(cmd)
  466. cmd='composite.exe -compose Multiply -negate '+outfname.partition('.')[0]+'_ao_normalized.bmp aomask'+str(pprez)+largeao+'.bmp aotemp.bmp'
  467. print cmd
  468. os.system(cmd)
  469.  
  470. cmd='composite -compose CopyOpacity aotemp.bmp black'+str(pprez)+'.bmp '+outfname.partition('.')[0]+'_aoplane.tga'
  471. print cmd
  472. os.system(cmd)
  473. if preplate !='':
  474. preplateimg=Image.open(texdir+preplate)
  475.  
  476. w,h=preplateimg.size
  477.  
  478.  
  479. aoplane=Image.open(outfname.partition('.')[0]+'_aoplane.tga')
  480. w2,h2=aoplane.size
  481. aoplane.save(outfname.partition('.')[0]+'_aoplane_ao_only.png')
  482. if w!=w2 or h!=h2:
  483. print "i fucking knew this would happen, damned plate and ao sizes dont match!", h,w,h2,w2
  484. continue
  485. preplateimg.load()
  486. aoplane.load()
  487. alpha=Image.new('L',(w,h))
  488. for x in range(w):
  489. for y in range(h):
  490. platepix=preplateimg.getpixel((x,y))
  491. aopix=aoplane.getpixel((x,y))
  492.  
  493. if 1==1:#len(aopix)==4 and len(platepix)==4:
  494. np=[0,0,0]#,0]
  495. if platepix[3]<=3: #transparent pixel! (or is it fully opaque? we shall see)
  496. #np[3]=aopix[3]
  497. alpha.putpixel((x,y),aopix[3])
  498. else:
  499. alpha.putpixel((x,y),platepix[3])
  500. np[0]=platepix[0]*(255-aopix[3])/255
  501. np[1]=platepix[1]*(255-aopix[3])/255
  502. np[2]=platepix[2]*(255-aopix[3])/255
  503. preplateimg.putpixel((x,y),(np[0],np[1],np[2]))
  504. else:
  505. print 'Wrong channel amount for plate or ao!', preplate, outfname
  506. # if x*y%1024==0:
  507. # print 'ao:',aopix, 'pl:',platepix, 'np',np
  508. alpha.save(outfname.partition('.')[0]+'_aoplane_merged_a.bmp')
  509. preplateimg=preplateimg.convert('RGB')
  510. preplateimg.save(outfname.partition('.')[0]+'_aoplane_merged.bmp')
  511. preplateimg.save(outfname.partition('.')[0]+'_aoplane.png')
  512. cmd='composite -compose CopyOpacity '+outfname.partition('.')[0]+'_aoplane_merged_a.bmp '+ outfname.partition('.')[0]+'_aoplane_merged.bmp '+ outfname.partition('.')[0]+'_aoplane.tga'
  513. print cmd
  514. os.system(cmd)
  515. #preplateimg.close()
  516. #aoplane.close()
  517.  
  518.  
  519. #--------------------- compress to dds------------------------
  520. if runnvdxt==1:
  521. if preplate=='':
  522. cmd='nvdxt -dxt5 -quality_highest -file '+outfname.partition('.')[0]+'_aoplane.tga'
  523. else:
  524. cmd='nvdxt -dxt5 -quality_highest -file '+outfname.partition('.')[0]+'_aoplane.tga'
  525. print cmd
  526. os.system(cmd)
  527.  
  528. #--------------------- edit FBI file to contain ground decal info------------------------
  529. fbi.close()
  530. fbi=open(fbifilename,'w')
  531. bracketcount=0
  532. alreadyhasgroundplate=0
  533. for l in fbiln:
  534. if 'buildinggrounddecaltype' in l.lower() and (outfname.partition('.')[0]+'_aoplane.dds') in l.lower():
  535. alreadyhasgroundplate=1
  536. if 'return lowerkeys' in l.lower():
  537. fbi.write(l)
  538. continue
  539. if '{' in l:
  540. bracketcount+=1
  541. if '}' in l:
  542. bracketcount-=1
  543. if bracketcount==0 and alreadyhasgroundplate==0:
  544. if deftype=='fbi':
  545.  
  546. decalinfo=' buildingGroundDecalDecaySpeed=30;\n buildingGroundDecalSizeX='+str(sizex/8)+ ';\n buildingGroundDecalSizeY='+str(sizez/8)+';\n useBuildingGroundDecal=1;\n buildingGroundDecalType='+outfname.partition('.')[0]+'_aoplane.dds;\n}\n'
  547. else:
  548. decalinfo=' buildingGroundDecalDecaySpeed=30,\n buildingGroundDecalSizeX='+str(sizex/8)+ ',\n buildingGroundDecalSizeY='+str(sizez/8)+',\n useBuildingGroundDecal = true,\n buildingGroundDecalType=[['+outfname.partition('.')[0]+'_aoplane.dds]],\n}\n'
  549.  
  550. print decalinfo
  551. fbi.write(decalinfo)
  552. alreadyhasgroundplate=1
  553. else:
  554. fbi.write(l)
  555. else:
  556. fbi.write(l)
  557. fbi.close()
  558.  
  559. winsound.Beep(500,500) #yep, this shit can run so long it needs to BEEEP when its done :D
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567. #------------------------s3o format:
  568.  
  569. # struct S3OHeader{
  570. # char magic[12]; ///< "Spring unit\0"
  571.  
  572. # int version; ///< 0 for this version
  573. # float radius; ///< radius of collision sphere
  574. # float height; ///< height of whole object
  575. # float midx; ///< these give the offset from origin(which is supposed to lay in the ground plane) to the middle of the unit collision sphere
  576. # float midy;
  577. # float midz;
  578. # int rootPiece; ///< offset in file to root piece
  579. # int collisionData; ///< offset in file to collision data, must be 0 for now (no collision data)
  580. # int texture1; ///< offset in file to char* filename of first texture
  581. # int texture2; ///< offset in file to char* filename of second texture
  582.  
  583.  
  584. # struct Piece{
  585. #0 int name; ///< offset in file to char* name of this piece
  586. #1 int numChilds; ///< number of sub pieces this piece has
  587. #2 int childs; ///< file offset to table of dwords containing offsets to child pieces
  588. #3 int numVertices; ///< number of vertices in this piece
  589. #4 int vertices; ///< file offset to vertices in this piece
  590. #5 int vertexType; ///< 0 for now
  591. #6 int primitiveType; ///< type of primitives for this piece, 0=triangles,1 triangle strips,2=quads
  592. #7 int vertexTableSize; ///< number of indexes in vertice table
  593. #8 int vertexTable; ///< file offset to vertice table, vertice table is made up of dwords indicating vertices for this piece, to indicate end of a triangle strip use 0xffffffff
  594. #9 int collisionData; ///< offset in file to collision data, must be 0 for now (no collision data)
  595. #10 float xoffset; ///< offset from parent piece
  596. #11 float yoffset;
  597. #12 float zoffset;
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606. # Unoffical .3do by Dan Melchione
  607. # Unoffical Revision by Dark Rain
  608. # Verion 0.9.1
  609. # November 7th 2002
  610.  
  611. # Copyright (c)1995 Dan Melchione - All Rights Reserved
  612.  
  613. # You have permission to distrbute this file without charge,
  614. # but may not alter it in any way. This includes copying
  615. # the included information for you own description of the
  616. # 3do file format. Please if send me any change requests.
  617. # Thanks for your cooperation.
  618.  
  619. # About the revision : Well the website is dead and it's been
  620. # FOUR years so I assume its a moot point to try to contact him.
  621.  
  622. # The latest version of this document can be found at:
  623. # "http://www.tauniverse.com/~visual-ta/" , in the file format section.
  624.  
  625.  
  626. # The old link for the latest version was :
  627. # http://www.melchione.com/totala/formats/3dofrmt.txt
  628. # But it's dead so....
  629.  
  630. # Question, Comments, Complaints To: dmelchione@melchione.com
  631.  
  632. # Question, Comments, Complaints about this revision To: RochDenis@hotmail.com
  633.  
  634. # .3do files are used by Total Annihilation (designed by Chris Taylor)
  635. # for drawing the 3 dimensional objects (hence the extension of .3do).
  636. # This document what I have found about the file format so far.
  637.  
  638. # The numbers used in this file are hexadecimal.
  639.  
  640. # The beginning of the file starts with following structure:
  641.  
  642. # typedef struct tagObject
  643. # {
  644. # long VersionSignature;
  645. # long NumberOfVertexes;
  646. # long NumberOfPrimitives;
  647. # long OffsetToselectionPrimitive;
  648. # long XFromParent;
  649. # long YFromParent;
  650. # long ZFromParent;
  651. # long OffsetToObjectName;
  652. # long Always_0;
  653. # long OffsetToVertexArray;
  654. # long OffsetToPrimitiveArray;
  655. # long OffsetToSiblingObject;
  656. # long OffsetToChildObject;
  657. # } Object;
  658.  
  659. # /*
  660. # The fields of this structure are:
  661.  
  662. # VersionSignature:
  663. # This is field is always one. I assume that it represents the signature
  664. # (which is a somewhat standard thing to do at the beginning of a
  665. # structure)
  666.  
  667. # NumberOfVertexes:
  668. # This field represents the number of vertexes used by this object. A
  669. # vertex is simply a 3D point.
  670.  
  671. # NumberOfPrimitives:
  672. # This field represents the number of primitives used by this object.
  673. # A primitive is a simple 3D object like a point, line, triangle, or
  674. # quad.
  675.  
  676. # OffsetToselectionPrimitive:
  677. # This fiel is an offset to a primitive in the parent object that
  678. # will serve as the "selection" rectangle in TA. All Child
  679. # and Sibling objects should have this value set to -1.
  680.  
  681. # XFromParent:
  682. # YFromParent:
  683. # ZFromParent:
  684. # This appears to be the location of the object relative to the parent
  685. # object. This first object in a file doesn't have any parents.
  686. # It appears to be a fixed-point integer. The scale is the same as the
  687. # one used to describe the primitives of an object.
  688.  
  689. # OffsetToObjectName:
  690. # This field is an offset to the name of the object. The name of the
  691. # object is stored as a null terminated string.
  692.  
  693. # Always_0:
  694. # This field appears to always be zero. If anyone finds a case where this
  695. # is not so, or has any more onfo, please let me know.
  696.  
  697. # OffsetToVertexArray:
  698. # This is an offset to an array of vertexes used by this object. The
  699. # number of vertexes in the array is stored above in NumberOfVertexes.
  700.  
  701. # OffsetToPrimitiveArray:
  702. # This is an offset to an array of primitives used by this object. The
  703. # number of primitives is stored above in NumberOfPrimitives.
  704.  
  705. # OffsetToSiblingObject:
  706. # This is an offset to a sibling object. A sibling object is an object
  707. # which shares the same parent as this object. The sibling object
  708. # structure appears to be identical. The objects act like a linked
  709. # list, terminated by a NULL (offset 00000000)
  710.  
  711. # OffsetToChildObject:
  712. # This is an offset to a child object. A child object is an object
  713. # which has the current object as a parent. The child object
  714. # structure appears to be identical. The objects act like a linked
  715. # list, terminated by a NULL (offset 00000000)
  716.  
  717. # */
  718.  
  719. # If we examine the armsy.3do file (the arm shipyard) and overlay the
  720. # above structure we end up with the following:
  721.  
  722. # 00000000 Object
  723. # 01 00 00 00 00000001 VersionSignature
  724. # C4 00 00 00 000000C4 VertexCount
  725. # 6D 00 00 00 0000006D PrimitiveCount
  726. # 00 00 00 00 00000000 OffsetToselectionPrimitive
  727. # 00000010
  728. # 00 00 00 00 00000000 XFromParent
  729. # 00 00 00 00 00000000 YFromParent
  730. # 00 00 00 00 00000000 ZFromParent
  731. # E5 1A 00 00 00001AE5 OffsetToObjectName (base)
  732. # 00000020
  733. # 00 00 00 00 00000000 Always_0
  734. # 15 04 00 00 00000415 OffsetToVertexArray
  735. # 45 0D 00 00 00000D45 OffsetToPrimitiveArray
  736. # 00 00 00 00 00000000 OffsetToSiblingObject
  737. # 00000030
  738. # EA 1A 00 00 00001AEA OffsetToChildObject
  739.  
  740. # The object has C4 vertexes (at offset 415), 6D primitives (at offset D45),
  741. # the name of the object is base, and it has a child object at offset 00001AEA.
  742.  
  743. # The child object at 1AEA has the same structure:
  744.  
  745. # 00001AEA Object
  746. # 01 00 00 00 00000001 VersionSignature
  747. # 29 00 00 00 00000029 VertexCount
  748. # 25 00 00 00 00000025 PrimitiveCount
  749. # FF FF FF FF FFFFFFFF OffsetToselectionPrimitive
  750. # 00001AFA
  751. # 01 00 CD FF FFCD0001 XFromParent
  752. # 00 40 F7 FF FFF74000 YFromParent
  753. # 00 40 CC FF FFCC4000 ZFromParent
  754. # DA 22 00 00 000022DD OffsetToObjectName (turret)
  755. # 00001B0A
  756. # 00 00 00 00 00000000 Always_0
  757. # 4E 1C 00 00 00001C4E OffsetToVertexArray
  758. # 3A 1E 00 00 00001E3A OffsetToPrimitiveArray
  759. # E2 22 00 00 000022E2 OffsetToSiblingObject
  760. # 00001B1A
  761. # 00 37 00 00 00003700 OffsetToChildObject
  762.  
  763. # In this case the object has 29 vertexes (at offset 1C4E), 25 primitives
  764. # (at offset 1E3A), a sibling object at offset 22E2, and a child object
  765. # at offset 3700.
  766.  
  767. # If you repeat following the sibling and child object nodes you end
  768. # up with the following tree of objects:
  769. # base
  770. # turret1
  771. # nano1
  772. # beam1
  773. # turret2
  774. # nano2
  775. # beam2
  776. # slip
  777. # light
  778. # explode
  779. # explode1
  780. # explode2
  781.  
  782. # We find that a number of the objects (for example slip) have only one
  783. # vertex and no primitives. This is used in scripting, you can set smoke
  784. # points, targets, explosions etc etc.
  785.  
  786. # 00002ADA
  787. # 01 00 00 00 00000001 VersionSignature
  788. # 01 00 00 00 00000001 VertexCount
  789. # 00 00 00 00 00000000 PrimitiveCount
  790. # FF FF FF FF FFFFFFFF OffsetToselectionPrimitive
  791. # 00002AEA
  792. # 00 00 00 00 00000000 XFromParent
  793. # 00 40 F7 FF FFF74000 YFromParent
  794. # 00 00 00 00 00000000 ZFromParent
  795. # 1A 2B 00 00 00002B1A OffsetToObjectName (slip)
  796. # 00002AFA
  797. # 00 00 00 00 00000000 Always_0
  798. # 0E 2B 00 00 00002B0E OffsetToVertexArray
  799. # 1A 2B 00 00 00002B1A OffsetToPrimitiveArray
  800. # 1F 2B 00 00 00002B1F OffsetToSiblingObject
  801. # 00002B0A
  802. # 00 00 00 00 00000000 OffsetToChildObject
  803.  
  804. # In cavedog created .3do files a list of texture names always appear
  805. # to be stored at offset 00000034 (more on this later):
  806.  
  807. # From armysy.3d0:
  808.  
  809. # char TextureNameArray[][];
  810.  
  811. # 00000034 TextureNameArray
  812. # * Pointed to by OffsetToTextureName in PrimitiveArray
  813. # * Always at offset 34 for cavedog units
  814. # 6E 6F 69 73 65 36 62 00 41 72 6D 34 62 00 41 72 noise6b.Arm4b.Ar
  815. # 6D 42 75 69 32 62 00 41 72 6D 56 33 62 00 67 72 mBui2b.ArmV3b.gr
  816. # 61 79 6E 6F 69 73 65 33 00 6E 6F 69 73 65 32 62 aynoise3.noise2b
  817. # 00 41 72 6D 70 61 6E 65 6C 31 00 33 32 58 47 6F .Armpanel1.32XGo
  818. # 75 72 61 75 64 00 6E 6F 69 73 65 36 61 00 66 6C uraud.noise6a.fl
  819. # 61 73 68 69 6E 67 30 32 00 6D 65 74 61 6C 33 63 ashing02.metal3c
  820. # 00 6D 65 74 61 6C 33 61 00 6D 65 74 61 6C 33 62 .metal3a.metal3b
  821. # 00 .
  822.  
  823. # In cavedog created .3do files after the texture names appears to be a
  824. # list of vertex indexes (more on this later)
  825.  
  826. # short VertexIndexArray[];
  827.  
  828. # 000000A5 VertexIndexArray
  829. # * Pointed to by OffsetToVertexIndexArray in PrimitiveArray
  830. # C0 00
  831. # C3 00
  832. # C1 00
  833. # C2 00
  834. # B9 00
  835. # B8 00
  836. # BB 00
  837. # BA 00
  838. # 000000B5
  839. # ...
  840. # 00000405
  841. # 06 00
  842. # 0E 00
  843. # 0F 00
  844. # 07 00
  845. # 08 00
  846. # 00 00
  847. # 07 00
  848. # 0F 00
  849.  
  850. # In cavedog created .3do files after the vertex indexes appears to be
  851. # the vertexes themselves. These vertexes are pointed to in the Object
  852. # structure (above) by the OffsetToVertexArray field. The format
  853. # appears to be the following:
  854.  
  855. # typedef struct tagVertex
  856. # {
  857. # long x;
  858. # long y;
  859. # long z;
  860. # } Vertex;
  861.  
  862. # Vertex VertexArray[];
  863.  
  864. # 00000415
  865. # 6D 9A D0 FF VertexArray[0].x
  866. # 00 40 F7 FF VertexArray[0].y
  867. # 7B 59 32 00 VertexArray[0].z
  868. # AD 98 CF FF VertexArray[1].x
  869. # 00000425
  870. # ... ...
  871. # 00000535
  872. # 6C DA C3 FF VertexArray[C2].z
  873. # 00 C0 0D 00 VertexArray[C3].y
  874. # 7B 19 2A 00 VertexArray[C3].x
  875. # 6C 5A D7 FF VertexArray[C3].z
  876.  
  877. # In cavedog created .3do files after the vertexes appears to be
  878. # the array of primitives. These primitives are pointed to in the Object
  879. # structure (above) by the OffsetToPrimitiveArray field. The format
  880. # appears to be the following:
  881.  
  882. # typedef struct tagPrimitive
  883. # {
  884. # long ColorIndex;
  885. # long NumberOfVertexIndexes;
  886. # long Always_0;
  887. # long OffsetToVertexIndexArray;
  888. # long OffsetToTextureName;
  889. # long Unknown_1;
  890. # long Unknown_2;
  891. # long Unknown_3;
  892. # } Primitive;
  893.  
  894. # /*
  895. # ColorIndex:
  896. # This is the index of a color in the TA color palette. For the color
  897. # palette, check out at the very end of this file for more detail, it
  898. # would take too much space to display here.
  899.  
  900. # NumberOfVertexIndexes:
  901. # This indicates the number of vertexes used by the primitive as well
  902. # as the primitive type (example: 1 = point, 2 = line, 3 = triangle,
  903. # 4 = quad)
  904.  
  905. # Always_0:
  906. # This field always appears to be 0.
  907.  
  908. # OffsetToVertexIndexArray:
  909. # This points to a an array of shorts which are indexes into the objects
  910. # vertex array. This allows multiple primitives to share the same
  911. # vertexes.
  912.  
  913. # OffsetToTextureName:
  914. # This points to a null terminated string which indicates which texture
  915. # to use for this primtive. A value of 0 probably means no texture.
  916.  
  917. # You may notice that there is no u,v mapping coordinates for
  918. # the textures. That's because you have to generate them. They're
  919. # generated via the order of the polygon indexes. It really depends
  920. # on you API which index is the "TO RIGHT" of the texture, the "BOTTOM LEFT" etc.
  921. # You have to find it yourself. A good trick to do that, is to just have a ground
  922. # plate in 3do builder and apply a texture to it. Fiddle with the textures coordinates
  923. # order till you get the same result. You might have noticed that 3DO builder allows
  924. # you to set the orientation of a texture? It simply does that by changing the index
  925. # order.
  926.  
  927.  
  928. # Unknown_1:
  929. # Unknown_2:
  930. # Unknown_3:
  931. # These are Cavedog-specific used for their editor, and are
  932. # not needed. Always set to 0 or ignore them.
  933.  
  934. # */
  935.  
  936. # From armsy.3d0:
  937. # 00000D45 PrimitiveArray
  938. # * Pointed to by OffsetToPrimitiveArray in Header
  939. # 00000D45
  940. # 00 00 00 00 Unknown_0
  941. # 04 00 00 00 NumberOfVertexIndexes
  942. # 00 00 00 00 Always_0
  943. # A5 00 00 00 OffsetToVertexIndexArray
  944. # 00 00 00 00 OffsetToTextureName
  945. # 00 00 00 00 Unknown_0
  946. # 00 00 00 00 Unknown_1
  947. # 01 00 00 00 Unknown_2
  948. # 00000D65
  949. # ... ...
  950. # 00001AC5
  951. # 00 00 00 00 Unknown_0
  952. # 04 00 00 00 NumberOfVertexIndexes
  953. # 00 00 00 00 Always_0
  954. # 0D 04 00 00 OffsetToVertexIndexArray
  955. # 52 00 00 00 OffsetToTextureName
  956. # 00 00 00 00 Unknown_0
  957. # 00 00 00 00 Unknown_1
  958. # 00 00 00 00 Unknown_2
  959.  
  960. # In cavedog created .3do files after the pritives appears more objects,
  961. # texture names, etc. By following the linked lists in the Object
  962. # structures you can map out the entire file.
  963.  
  964. # You may notice that there is no animation data stored in these files.
  965. # This is because the animation data is stored in .bos (basic object script?)
  966. # files which are compiled into .cob (cobble) files. I haven't started
  967. # looking at these yet, so if anyone has any useful infomation please
  968. # let me know.
  969.  
  970. # Well thats it for now, check back for updates. Let me know what
  971. # you find so we can share the wealth.
  972.  
  973.  
  974. # Dan Melchione
  975. # dmelchione@melchione.com
  976.  
  977. # Dark Rain
  978. # RochDenis@hotmail.com
  979.  
  980. # -----------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement