Quantcast

Jump to content

» «
Photo

[REL|Beta] DFF Import/Export script for Blender

152 replies to this topic
WilliJ
  • WilliJ

    Player Hater

  • Members
  • Joined: 24 Jan 2012

#151

Posted 27 January 2012 - 10:13 PM

This script don't work with San Andreas DFF Models. If someone clever, then get this code and re-write (for compatible with blender 2.49b and with gta sa dff, col models), he will be like a megaman.

CODE GTA_IE_01c.py

CODE

# ============================================================== #
# Title: GTA Import/Export Tool for Blender                      #
# Version: 0.1 BETA                                              #
# Author: Stephen Orning ('Hollower')                            #
# Email: [email protected]                                    #
# Web: http://hollower.game-editing.net/                         #
#                                                                #
# Import/Export models for 'Grand Theft Auto III'                #
# and 'Grand Theft Auto: Vice City'.                             #
# Not designed to work with other RenderWare based games (YMMV). #
# Requires Blender version 2.31 or greater.                      #
#                                                                #
#                                                                #
# ============================================================== #

#                                          #
#<--------- minimum window width --------->#
#                                          #
# (based on 'SCREEN 12' font at 1024*786)  #
#                                          #

# =========
#  MODULES
# =========
import math
import struct
from struct import *
import Blender
from Blender import * # Object, NMesh, Material, Texture, BGL, Draw, Window
from Blender.BGL import *

# =========
#  GLOBALS
# =========

# Interface
fnbox = Draw.Create("")
tdbox = Draw.Create("")
menu = Draw.Create(2001)
winwidth = 50
winheight = 50
# main=0, help=5
Mode = 0
prevmode = 0
# button IDs
BUTTON_BROWSE = 1401
BUTTON_FNBOX = 1402
BUTTON_TDBOX = 1403
BUTTON_EXIT = 1500
BUTTON_HELP = 1501
BUTTON_HELPEND = 1502
BUTTON_PRESETS = 1986
BUTTON_IMPORT = 1600
BUTTON_EXPORT = 1601
BUTTON_TOGSPLIT = 1162
BUTTON_TOGBPATCH = 1164
BUTTON_TOGUVTEX = 1210
BUTTON_TOGPRELIT = 1211
BUTTON_TOGNORMALS = 1212
BUTTON_TOGMODULATE = 1213
BUTTON_ZLOCK = 2240
# default options
FileFormat = 1 # dff=1, col=2
ImportSplit = 0
ExportSplit = 1
ExtractBonePatch = 0
ExportType = 2001
ExportVersion = (-1, 3074)
FlagUVTEX = 1
FlagPRELIT = 0
FlagNORMALS = 1
FlagMODULATE = 1
bZLOCK = 0
# preset IDs
DFF_OTHER = 2007
GTA3_CAR = 2004
GTA3_HUMAN = 2005
GTA3_WORLD = 2006
VC_CAR = 2001
VC_HUMAN = 2002
VC_WORLD = 2003
# geometry flags
GEOMETRY_TRISTRIP  = 1
GEOMETRY_POSITIONS = 2
GEOMETRY_UVTEXTURE = 4
GEOMETRY_PRELIT    = 8
GEOMETRY_NORMALS   = 16
GEOMETRY_LIGHT     = 32
GEOMETRY_MODULATE  = 64
GEOMETRY_ETEXTURE  = 128
# internal
xgeometrycount = 0
xdummycount = 0
xframecount = 0
xatomiclist = ""
xgeometrylist = ""
xframelist = ""
xframenames = ""
child_dict = {}
objects_in_order = []
# skeleton
# (name,boneID,boneType)
Skeleton_VCIG = [
('Root',0,0),
('Pelvis',1,0),
('Spine',2,0),
('Spine1',3,2),
('Neck',4,0),
('Head',5,3),
('Bip01 L Clavicle',31,2),
('L UpperArm',32,0),
('L Forearm',33,0),
('L Hand',34,0),
('L Finger',35,1),
('Bip01 R Clavicle',21,0),
('R UpperArm',22,0),
('R Forearm',23,0),
('R Hand',24,0),
('R Finger',25,1),
('L Thigh',41,2),
('L Calf',42,0),
('L Foot',43,0),
('L Toe0',2000,1),
('R Thigh',51,0),
('R Calf',52,0),
('R Foot',53,0),
('R Toe0',2001,1)
]

# help text
helptext = [ (0.18, 0.45, 0.25),
            "GTA Import/Export Tool for Blender",
            "Version: 0.1 BETA",
            "Author: Stephen Orning ('Hollower')",
            "",
            "",
            (1.0, 0.0, 0.0),"HELP IS NOT YET AVAILABLE"]
       

class StatusWindow:

 def __init__(self, top_x, top_y, bottom_x, bottom_y, bgcolor=(0,0,0), fgcolor=(1,1,1)):
   self.top_x = top_x
   self.top_y = top_y
   self.bottom_x = bottom_x
   self.bottom_y = bottom_y
   self.bgcolor = bgcolor
   self.fgcolor = fgcolor
   self.textbuffer = []
   self.maxlines = max(2,(top_y-bottom_y)/8)
   
 def Resize(self, top_x, top_y, bottom_x, bottom_y):
   self.top_x = top_x
   self.top_y = top_y
   self.bottom_x = bottom_x
   self.bottom_y = bottom_y
   self.maxlines = max(2,(top_y-bottom_y)/8)
   if len(self.textbuffer) > self.maxlines:
     self.textbuffer = self.textbuffer[len(self.textbuffer)-self.maxlines:]

 def Draw(self):
   glColor3f(self.bgcolor[0], self.bgcolor[1], self.bgcolor[2])
   glRecti(self.top_x, self.top_y, self.bottom_x, self.bottom_y)
   glBegin(GL_LINES)
   glColor3f(0.8, 0.8, 0.8)
   glVertex2d(self.bottom_x, self.top_y)
   glVertex2d(self.bottom_x, self.bottom_y)
   glVertex2d(self.bottom_x, self.bottom_y)
   glVertex2d(self.top_x, self.bottom_y)
   glColor3f(0.5, 0.5, 0.5)
   glVertex2d(self.top_x, self.top_y)
   glVertex2d(self.bottom_x, self.top_y)
   glVertex2d(self.top_x, self.top_y)
   glVertex2d(self.top_x, self.bottom_y-1)
   glEnd()
   glColor3f(self.fgcolor[0], self.fgcolor[1], self.fgcolor[2])
   i = 8
   for line in self.textbuffer:
     glRasterPos2i(self.top_x+5, self.top_y-i)
     Draw.Text(line, 'tiny')
     i += 8

 def Text(self, text="", echoconsole=1, redraw=1):
   if type(text) != type(""): return
   self.textbuffer.append(text)
   if echoconsole: print text
   if len(self.textbuffer) > self.maxlines: del self.textbuffer[0]
   if redraw: Draw.Draw()
 
 def AlterText(self, text=""):
   if type(text) != type(""): return
   self.textbuffer[-1] = text
   Draw.Draw()
 
 def Clear(self, bgcolor=(0,0,0), fgcolor=(1,1,1)):
   self.textbuffer = []
   self.bgcolor = bgcolor
   self.fgcolor = fgcolor
   Draw.Draw()


# =====
#  GUI
# =====
stat = StatusWindow(10, 180, 325, 10)

def handleEvent(eventNum, value):
 if eventNum == Draw.ESCKEY:
   Draw.Exit()
   Draw.Redraw()
   print "==== Script Exit ====\n"

def handleButton(buttonNum):
 global fnbox, tdbox, menu, stat
 global Mode, prevmode
 global ExportType, FileFormat, ImportSplit, ExtractBonePatch
 global FlagUVTEX, FlagPRELIT, FlagNORMALS, FlagMODULATE, bZLOCK
 
 if buttonNum == BUTTON_BROWSE:
   Window.FileSelector(fileselect, "Select file")
   Draw.Redraw()
 elif buttonNum == BUTTON_IMPORT:
   if FileFormat == 1:
     if ImportDFF(fnbox.val):
       stat.Text("DFF Imported")
     else:
       stat.Text("DFF Import FAILED!")
   elif FileFormat == 2:
     ImportCOL(fnbox.val, tdbox.val)
   Draw.Redraw()
 elif buttonNum == BUTTON_EXPORT:
   ExportDFF(fnbox.val)
   Draw.Redraw()
 elif buttonNum == BUTTON_FNBOX:
   FileFormat = 1
   if len(fnbox.val) > 3:
     if fnbox.val[-4:].lower() == ".col":
       FileFormat = 2
       tdbox.val = ""
   Draw.Redraw()
 elif buttonNum == BUTTON_TDBOX:
   if FileFormat == 1:
     if '/' in tdbox.val: tdbox.val = '\\'.join(tdbox.val.split('/'))
     if len(tdbox.val) > 0:
       if tdbox.val[-1] != '\\': tdbox.val += '\\'
   Draw.Redraw()
 elif buttonNum == BUTTON_PRESETS:
   ExportType = menu.val
   FlagUVTEX = 1
   if ExportType in [VC_CAR, GTA3_CAR]:
     FlagPRELIT = 0
     FlagNORMALS = 1
     FlagMODULATE = 1
   elif ExportType in [VC_WORLD, GTA3_WORLD]:
     FlagPRELIT = 1
     FlagNORMALS = 0
     FlagMODULATE = 0
   else:
     FlagPRELIT = 0
     FlagNORMALS = 1
     FlagMODULATE = 0
   Draw.Redraw()
 elif buttonNum == BUTTON_TOGSPLIT:
   ImportSplit = 1 - ImportSplit
   Draw.Redraw()
 elif buttonNum == BUTTON_TOGBPATCH:
   ExtractBonePatch = 1 - ExtractBonePatch
   Draw.Redraw()
 elif buttonNum == BUTTON_TOGUVTEX:
   FlagUVTEX = 1 - FlagUVTEX
   Draw.Redraw()
 elif buttonNum == BUTTON_TOGPRELIT:
   FlagPRELIT = 1 - FlagPRELIT
   Draw.Redraw()
 elif buttonNum == BUTTON_TOGNORMALS:
   FlagNORMALS = 1 - FlagNORMALS
   Draw.Redraw()
 elif buttonNum == BUTTON_TOGMODULATE:
   FlagMODULATE = 1 - FlagMODULATE
   Draw.Redraw()
 elif buttonNum == BUTTON_ZLOCK:
   bZLOCK = 1 - bZLOCK
   Draw.Redraw()
 elif buttonNum == BUTTON_HELP:
   if Mode != 5:
     prevmode = Mode
     Mode = 5
   Draw.Redraw()
 elif buttonNum == BUTTON_HELPEND:
   Mode = prevmode
   Draw.Redraw()
 elif buttonNum == BUTTON_EXIT:
   Draw.Exit()
   Draw.Redraw()
   print "==== Script Exit ====\n"

 else:
   Draw.Register(redraw, handleEvent, handleButton)


def redraw():
 global winwidth, winheight
 global fnbox, tdbox, menu, stat
 global Mode
 global helptext
 global FileFormat, ImportSplit, ExtractBonePatch
 # clear screen
 glClearColor(0.7, 0.7, 0.7, 0.0)
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
 viewportvaluebuffer = Buffer(GL_FLOAT, 4)
 glGetFloatv(GL_VIEWPORT, viewportvaluebuffer)
 # in viewportvaluebuffer are [x, y, width, height]
 winwidth = int(viewportvaluebuffer[2])
 winheight = int(viewportvaluebuffer[3])
 # title bar
 glColor3f(0.20, 0.72, 0.87)
 glRecti(0, winheight, winwidth, winheight-25)
 glColor3f(0.84, 0.25, 0.34)
 titlestring = "GTA Import/Export Tool for Blender"
 glRasterPos2i(winwidth/2 - Draw.GetStringWidth(titlestring)/2, winheight-20)
 Draw.Text(titlestring)
 Draw.Button("?", BUTTON_HELP, 4, winheight-22, 20, 20, "About|Help")
 Draw.Button("X", BUTTON_EXIT, winwidth-24, winheight-22, 20, 20, "Exit")
 #
 if Mode == 0:
   # graphics (well, not really...yet)
   glColor3f(0.6, 0.6, 0.6)
   glRecti(20,  winheight-140,  20+45+55+45, 190)
   glRecti(170, winheight-140, 170+45+55+45, 190)
   # main controls
   glColor3f(0.0, 0.0, 0.0)
   glRasterPos2i(20, winheight-55)
   Draw.Text("Filename:")
   Draw.Button("Browse",  BUTTON_BROWSE, min(winwidth-55,285), winheight-80,  50, 20, "Select a file")
   fnbox = Draw.String("", BUTTON_FNBOX, 20, winheight-80,  min(winwidth-80,260), 20, fnbox.val, 255, fnbox.val)
   glRasterPos2i(20, winheight-95)
   if FileFormat == 1:
     Draw.Text("Texture Path:")
   elif FileFormat == 2:
     Draw.Text("Collision Model Name:")
   tdbox = Draw.String("", BUTTON_TDBOX, 20, winheight-120, min(winwidth-80,260), 20, tdbox.val, 255, tdbox.val)
   stat.Draw()
   # export controls
   Draw.Button("Export", BUTTON_EXPORT, 215, winheight-170, 55, 25, "Export")
   menutext = "Presets %t|VC Vehicle %x2001|VC Human %x2002|VC World %x2003|GTA3 Vehicle %x2004|GTA3 Human %x2005|GTA3 World %x2006"
   menu = Draw.Menu(menutext, BUTTON_PRESETS, 180, winheight-200, 120, 20, menu.val,    "Select Model Type")
   Draw.Toggle("uvtex",      BUTTON_TOGUVTEX, 180, winheight-222, 60, 20, FlagUVTEX,    "Flag: UV Texture")
   Draw.Toggle("prelit",    BUTTON_TOGPRELIT, 242, winheight-222, 60, 20, FlagPRELIT,   "Flag: Prelit")
   Draw.Toggle("normals",  BUTTON_TOGNORMALS, 242, winheight-244, 60, 20, FlagNORMALS,  "Flag: Normals")
   Draw.Toggle("modulate", BUTTON_TOGMODULATE,180, winheight-244, 60, 20, FlagMODULATE, "Flag: Modulated")
   Draw.Toggle("z-lock",   BUTTON_ZLOCK,      180, winheight-280, 60, 20, bZLOCK,       "Lock File (prevents import)")
   # import controls
   Draw.Button("Import", BUTTON_IMPORT, 65, winheight-170, 55, 25, "Import")
   Draw.Toggle("msplit", BUTTON_TOGSPLIT, 30, winheight-200, 60, 20, ImportSplit, "Parse Material Split")
   Draw.Toggle("bpatch", BUTTON_TOGBPATCH,30, winheight-224, 60, 20, ExtractBonePatch, "Create Bone Patch File")
 elif Mode == 5:
   # help screen
   i = 70
   for line in helptext:
     if type(line) == type((0,)):
       glColor3f(line[0], line[1], line[2])
     elif type(line) == type(""):
       glRasterPos2i(20, winheight-i)
       Draw.Text(line)
       i += 15
   Draw.Button("Back", BUTTON_HELPEND, winwidth/2 - 20, 60, 60, 20, "Back to main screen")


def fileselect(filename):
 global fnbox, tdbox, FileFormat
 
 FileFormat = 1
 
 if len(filename) > 3:
   if filename[-4:].lower() == ".col":
     FileFormat = 2
     tdbox.val = ""
 
 fnbox.val = filename
 
 if FileFormat == 1:
   tdbox.val = "\\".join(tuple(filename.split('\\')[:-1]))+"\\"
 
 

# ==============
# Math functions
# ==============

# CREDIT: This function was taken from vecf.py module written by Theeth
def matrixToEulerRot(mtx):
 angle_y = -math.asin(max(min(mtx[0][2], 1.0), -1.0))
 C = math.cos(angle_y)
 if C != 0.0: C = 1.0/C
 angle_x = math.atan2(mtx[1][2] * C, mtx[2][2] * C)
 angle_z = math.atan2(mtx[0][1] * C, mtx[0][0] * C)
 return [angle_x, angle_y, angle_z]


# ==========================
# DFF file reading functions
# ==========================

def ReadInt(file):
 return unpack("<i", file.read(4))[0]


def ReadHeader(file):
 return unpack("<iihh", file.read(12))


def ReadBone(file):
 bone = []
 bone.append(unpack("<iii", file.read(12)))
 bonecount = bone[0][2]
 
 if bonecount > 0:
   file.seek(8, 1) # skipping 0, 36
   for i in range(bonecount):
     bone.append(unpack("<iii", file.read(12)))
 
 return bone


def ReadFrames(file):
 hierarchy = []
 framenames = []
 bones = []
 
 data = ReadHeader(file)
 
 if data[0] != 14:
   stat.Text("Error: expected frame list")
   return []
 
 data = ReadHeader(file)
 
 FrameCount = ReadInt(file)
 
 if FrameCount > 999 or FrameCount < 0:
   stat.Text("Error: FrameCount out of bounds")
   return []
 
 for i in range(FrameCount):
   hierarchy.append(unpack("<12fii", file.read(56)))
 
 count = 0
 
 while count < FrameCount:
   
   data = ReadHeader(file)
   
   if data[0] == 3:
     continue
   
   if data[0] == 286:
     bones.append(ReadBone(file))
     continue
     
   if data[0] == 39056126:
     framenames.append( file.read(data[1]) )
     count = count + 1
   else:
     stat.Text("Error: expected frame")
     return []
 
 data = ReadHeader(file)
 
 if data[0] == 286:
   bones.append(ReadBone(file))
 else:
   file.seek(-12, 1)
   
 return [hierarchy, framenames, bones]


def ReadGeometryList(file):
 data = ReadHeader(file)
 
 if data[0] != 26:
   stat.Text("Error: expected geometry list")
   return []
 
 data = ReadHeader(file)
 
 GeometryCount = unpack("<i", file.read(4))[0]
 
 if GeometryCount > 999 or GeometryCount < 0:
   stat.Text("Error: GeometryCount out of bounds")
   return []
 
 geometrylist = []
 
 for i in range(GeometryCount):
   geometrylist.append(ReadGeometry(file))
 
 return geometrylist


def ReadGeometry(file):
 data = ReadHeader(file)
 
 if data[0] != 15:
   stat.Text("Error: expected geometry")
   return []
 
 data = ReadHeader(file)
 
 GeometryData = unpack("<hhiii", file.read(16))
 
 GeometryFlags = GeometryData[0]
 TriangleCount = GeometryData[2]
 VertexCount = GeometryData[3]
 
 lighting = (1.0, 1.0, 1.0)
 vertexcolors = []
 vertexuv = []
 facelist = []
 vertexlist = []
 vertexnormals = []
 materiallist = []
 
 if data[3] != 4099:
   lighting = unpack("<3f", file.read(12)) # not used
 
 if (GeometryFlags & GEOMETRY_PRELIT):
   for i in range(VertexCount):
     vertexcolors.append(unpack("<4B", file.read(4))) # Vertex Colors
 
 if (GeometryFlags & GEOMETRY_UVTEXTURE):
   for i in range(VertexCount):
     uvtemp = unpack("<ff", file.read(8))  # UV Coords
     uvtemp = (uvtemp[0], -uvtemp[1])
     vertexuv.append(uvtemp)
 
 for i in range(TriangleCount):
   facetemp = unpack("<4h", file.read(8))  # Face List
   facetemp = [facetemp[1], facetemp[0], facetemp[3], facetemp[2]]
   facelist.append(facetemp)
   
   
 boundsphere = unpack("<4f", file.read(16))  # Bounding Sphere
 file.seek(8, 1)
 
 for i in range(VertexCount):
   vertexlist.append(unpack("<3f", file.read(12))) # Vertex Coords
 
 if (GeometryFlags & GEOMETRY_NORMALS):
   for i in range(VertexCount):
     vertexnormals.append(unpack("<3f", file.read(12))) # Vertex Normals
 
 data = ReadHeader(file)
 
 if data[0] != 8:
   stat.Text("Error: expected material list")
   return []
 
 data = ReadHeader(file)
 
 MaterialCount = unpack("<i", file.read(4))[0]
 
 if data[1] > 4:
   file.seek(data[1]-4, 1)
 
 if MaterialCount > 999 or MaterialCount < 0:
   stat.Text("Error: MaterialCount out of bounds")
   return []
 
 for i in range(MaterialCount):
   materiallist.append(ReadMaterial(file))
 
 data = ReadHeader(file)
 
 if data[0] != 3:
   stat.Text("Error: expected extension from geometry")
   return []
 
 materialsplit = [] # not used anymore
 skindata = []
 vbgroups = []
 vbweights = []
 vbmatrices = []
 
 data = ReadHeader(file)
 
 if data[0] != 1294:
   stat.Text("Error: expected material split")
   return []

 if ImportSplit:
   
   splitdata = unpack("<iii", file.read(12))
   tristrip = splitdata[0]
   splitcount = splitdata[1]
   totalfacecount = splitdata[2]
   
   stat.Text("Parsing material split:")
   
   if splitcount != MaterialCount:
     stat.Text("Error: material split doesn't fit geometry")
     return []
   
   # create a temporary facelist with material index stripped
   tempfacelist = []
   for face in facelist:
     tempfacelist.append(face[:3])
   
   for i in range(splitcount):
     stat.AlterText("Parsing material split: %d of %d"%(i+1, splitcount))
     # unpack the split data
     fimi = unpack("<ii", file.read(8))
     binstr = "<%di"%(fimi[0],)
     split = unpack(binstr, file.read(calcsize(binstr)))
     
     # CREDIT: The following procedure was adapted from C++ code provided by Oleg M
     # I really need a faster way to parse the split data!
     if tristrip == 0:
       for s in range(0,len(split),3):
         fi = tempfacelist.index(list(split[s:s+3]))
         facelist[fi][3] = fimi[1]
     elif tristrip == 1:
       for s in range(len(split)-2):
         if split[s+0] != split[s+1] and split[s+1] != split[s+2] and split[s+2] != split[s+0]:
           try:
             fi = tempfacelist.index([split[s+0], split[s+1], split[s+2]])
           except:
             try:
               fi = tempfacelist.index([split[s+0], split[s+2], split[s+1]])
             except:
               try:
                 fi = tempfacelist.index([split[s+1], split[s+0], split[s+2]])
               except:
                 try:
                   fi = tempfacelist.index([split[s+1], split[s+2], split[s+0]])
                 except:
                   try:
                     fi = tempfacelist.index([split[s+2], split[s+0], split[s+1]])
                   except:
                     try:
                       fi = tempfacelist.index([split[s+2], split[s+1], split[s+0]])
                     except:
                       stat.Text("Error: material split parsing failed")
           facelist[fi][3] = fimi[1]
 
 else:
   file.seek(data[1], 1)

 data = ReadHeader(file)
 if data[0] == 278:
   bonecountinfo = unpack("<4B", file.read(4))
   bonecount = bonecountinfo[0]
   bonef*ck = "17f"
   if bonecountinfo[1] > 0:
     file.seek(bonecountinfo[1], 1) # skip for now
     bonef*ck = "16f"
   for i in range(VertexCount):
     vbgroups.append(unpack("<4B", file.read(4)))
   for i in range(VertexCount):
     vbweights.append(unpack("<4f", file.read(16)))
   for i in range(bonecount):
     vbmatrices.append(unpack(bonef*ck, file.read(calcsize(bonef*ck))))
   skindata = [vbgroups, vbweights, vbmatrices]
   
   if ExtractBonePatch:
     bpfilename = fnbox.val[:-4]+".bp"
     bpfile = open(bpfilename, "wb")
     bppack = ""
     for bm in vbmatrices:
       for bmf in bm:
         bppack += pack("<f", bmf)
     bpfile.write(bppack)
     stat.Text("Bone patch file created: "+bpfilename)
     
   if bonef*ck == "16f": file.seek(12, 1)
 else:
   file.seek(-12, 1)
 data = ReadHeader(file)
 if data[0] == 261:
   file.seek(data[1], 1)
 else:
   file.seek(-12, 1)

 
 return [GeometryFlags, boundsphere, vertexlist, vertexcolors, vertexuv, vertexnormals, facelist, materiallist, materialsplit, skindata]
   

def ReadMaterial(file):
 data = ReadHeader(file)
 
 if data[0] != 7:
   stat.Text("Error: expected material")
   return []
   
 data = ReadHeader(file)
 
 file.seek(4, 1)
 matcolor = unpack("<4B", file.read(4))
 file.seek(4, 1)
 TextureCount = unpack("<i", file.read(4))[0]
 matlight = unpack("<3f", file.read(12))
 
 textures = []
 
 if TextureCount > 16 or TextureCount < 0:
   stat.Text("Error: TextureCount out of bounds")
   return []
 
 for i in range(TextureCount):
   textures.append(ReadTexture(file))
 
 data = ReadHeader(file)
 
 if data[0] != 3:
   stat.Text("Error: expected extension from material")
   return []
 
 effect = []
 if data[1] != 0:
   data = ReadHeader(file)
   effecttype = unpack("<ii", file.read(8))[0]
   effectstrength = unpack("<fi", file.read(8))[0]
   if effecttype != 1:
     file.seek(4, 1)
   effecttextures = [ReadTexture(file),]
   if ReadInt(file) == 1:
     effecttextures.append(ReadTexture(file))
     file.seek(4, 1)
   effect = [effecttype, effectstrength, effecttextures]
 
 return [matcolor, matlight, textures, effect]


def ReadTexture(file):
 data = ReadHeader(file)
 
 if data[0] != 6:
   stat.Text("Error: expected texture")
   return []
 
 file.seek(16, 1)
 
 data = ReadHeader(file)
 
 if data[0] != 2:
   stat.Text("Error: expected string (texture name)")
   return []
 
 texturename = file.read(data[1])
 texturename = texturename.split('\0')[0]
 
 data = ReadHeader(file)
 
 if data[0] != 2:
   stat.Text("Error: expected string (mask name)")
   return []
 
 maskname = file.read(data[1])
 maskname = maskname.split('\0')[0]
 
 data = ReadHeader(file)
 
 if data[0] != 3:
   stat.Text("Error: expected extension from texture")
   return []
 
 file.seek(data[1], 1) # should be empty
 
 return [texturename, maskname]


def ReadAtomics(file, n):
 atomics = []
 for i in range(n):
   data = ReadHeader(file)
   asize = data[1]
   if data[0] != 20:
     stat.Text("Error: expected atomic")
     return []
   data = ReadHeader(file)
   atomics.append(unpack("<ii", file.read(8)))
   file.seek(asize-20, 1)
 return atomics


def LoadTexture(texturename, loadedimages):
 global tdbox, stat
 # TODO: handle textures already loaded prior to running script
 if texturename != "" and texturename not in loadedimages.keys():
   imagefile = tdbox.val + texturename + ".bmp"
   try:
     img = Blender.Image.Load(imagefile)
     imgtex = Texture.New(texturename)
     imgtex.setType('Image')
     imgtex.image = img
     loadedimages[texturename] = [img, imgtex]
     stat.Text(texturename+".bmp loaded")
   except:
     loadedimages[texturename] = None
     stat.Text("Warning: "+texturename+".bmp not found")


# ==================
# IMPORT FUNCTION
# ==================

def ImportDFF(filename):
 if filename == "":
   stat.Text("Error: You forgot to enter a filename!")
   return 0
 try:
   file = open(filename, "rb")
 except:
   stat.Text("Error: failed to open "+filename)
   return 0
 
 data = ReadHeader(file)
 if data[0] != 16:
   stat.Text("Error: expected clump")
   file.close()
   return 0
   
 file.seek(data[1], 1)
 try: data = ReadHeader(file)
 except: data = []
 if len(data) == 4:
   if data[0] == 61982:
     ldl = unpack("<8B", file.read(8))
     if ldl[4] != 0:
       lfs = ""
       for lfsc in lfss[1]: lfs += lfss[0][lfsc]
       stat.Text(lfs)
       file.close()
       return 0
 file.seek(12)

 if len(data) == 4:
   if data[0] == 16:
     stat.Text("Warning: second clump will not be parsed")
 
 data = ReadHeader(file)
 ObjectCount = unpack("<i", file.read(4))[0]
 if data[1] > 4:
   file.seek(data[1]-4, 1)
 if ObjectCount > 999 or ObjectCount < 0:
   stat.Text("Error: ObjectCount out of bounds")
   file.close()
   return 0
 
 framelist = ReadFrames(file)
 if framelist == []:
   file.close()
   return 0
 
 geometrylist = ReadGeometryList(file)
 if geometrylist == []:
   file.close()
   return 0
 
 atomiclist = ReadAtomics(file, ObjectCount)
 if atomiclist == []:
   file.close()
   return 0
 
 file.close()

 # === BLENDER INTERFACE BEGINS HERE ===

 atomicframes = []
 loadedimages = {}
 FM = NMesh.FaceModes
 MM = Material.Modes
 scene = Blender.Scene.GetCurrent()
 
 for atomic in atomiclist:
   atomicframes.append(atomic[0])
 
 for i in range(len(framelist[0])):
   
   if i in atomicframes:
     o = Object.New('Mesh')
     m = NMesh.New()
     
     geometry = geometrylist[atomicframes.index(i)]
     geoflags = geometry[0]
     vertexlist = geometry[2]
     vertexcolors = geometry[3]
     uvcoords = geometry[4]
     facelist = geometry[6]
     materiallist = geometry[7]
     
     mx = 0
     texmat = {}
     maskmat = {}
     for material in materiallist:
       if mx > 15:
         stat.Text("Warning: can't add more materials (max of 16 reached)")
         break
       mat = Material.New()
       mat.R = float(material[0][0])/255.0
       mat.G = float(material[0][1])/255.0
       mat.B = float(material[0][2])/255.0
       mat.alpha = float(material[0][3])/255.0
       mat.setAmb(0.0)
       mat.setSpec(material[1][1]*2.0)
       mat.mode |= MM['ZTRANSP']
       if (geoflags & GEOMETRY_PRELIT): mat.mode |= MM['VCOL_LIGHT']
       m.materials.append(mat)
 
       for texture in material[2]:
         texmat[mx] = texture[0]
         if texture[1] != "": maskmat[mx] = texture[1]
         LoadTexture(texture[0], loadedimages) # texture
         LoadTexture(texture[1], loadedimages) # mask
 
       if len(material[3]) > 0:
         effect = material[3]
         effecttex = effect[2][0][0]
         if effecttex[-2:] == "_B":
           effecttex = effect[2][1][0]
         LoadTexture(effecttex, loadedimages)
         if loadedimages[effecttex] is not None:
           m.materials[mx].setTexture(2, loadedimages[effecttex][1])
         mtex = m.materials[mx].getTextures()[2]
         if mtex is not None and effect[0] == 1:
           mtex.texco = Texture.TexCo['UV']
           mtex.mapto = Texture.MapTo['NOR'] # cannot set strength
         elif mtex is not None and effect[0] == 2:
           m.materials[mx].setRef(effect[1])
           mtex.texco = Texture.TexCo['REFL']
           mtex.mapto = 0 # should be 'COL'+'SPHERE'+'ADD', but cannot set
           #mtex.tex.setType('EnvMap')
           #mtex.tex.setSType('EnvmapLoad')
           ##mtex.tex.stype = Texture.STypes['ENV_LOAD']
         else:
           print "Warning: unable to load effect ( type", effect[0], ")"
         #print framelist[1][i], "mat:", mx, "effect:", effect[0], "str:", effect[1], "tex:", effect[2][0][0]
         #if len(effect[2]) > 1: print framelist[1][i], "-- 2nd tex:", effect[2][1][0]
 
       mx += 1
     
     for vertex in vertexlist:
       m.verts.append(NMesh.Vert(vertex[0], vertex[1], vertex[2]))
     
     for face in facelist:
       f = NMesh.Face()
       f.v.append(m.verts[face[0]])
       f.v.append(m.verts[face[1]])
       f.v.append(m.verts[face[2]])
       f.materialIndex = face[3]
       f.mode = FM['LIGHT']+FM['TEX']+FM['TWOSIDE']+FM['SHAREDCOL']
       f.transp = NMesh.FaceTranspModes.ALPHA
       if (geoflags & GEOMETRY_NORMALS): f.smooth = 1
       
       # texture
       if face[3] in texmat.keys():
         if texmat[face[3]] in loadedimages.keys():
           if loadedimages[texmat[face[3]]] is not None:
             f.image = loadedimages[texmat[face[3]]][0]
             m.materials[face[3]].setTexture(0, loadedimages[texmat[face[3]]][1])
             mtex = m.materials[face[3]].getTextures()[0]
             mtex.texco = Texture.TexCo['UV']
       # mask
       if face[3] in maskmat.keys():
         if maskmat[face[3]] in loadedimages.keys():
           if loadedimages[maskmat[face[3]]] is not None:
             m.materials[face[3]].setTexture(1, loadedimages[maskmat[face[3]]][1])
             mtex = m.materials[face[3]].getTextures()[1]
             mtex.texco = Texture.TexCo['UV']
             mtex.mapto = Texture.MapTo['ALPHA'] # should be 'ALPHA'+'MUL', but cannot set
 
       if len(vertexcolors) > 0:
         rgba = NMesh.Col(vertexcolors[face[0]][0], vertexcolors[face[0]][1], vertexcolors[face[0]][2], vertexcolors[face[0]][3])
         f.col.append(rgba)
         rgba = NMesh.Col(vertexcolors[face[1]][0], vertexcolors[face[1]][1], vertexcolors[face[1]][2], vertexcolors[face[1]][3])
         f.col.append(rgba)
         rgba = NMesh.Col(vertexcolors[face[2]][0], vertexcolors[face[2]][1], vertexcolors[face[2]][2], vertexcolors[face[2]][3])
         f.col.append(rgba)
       if len(uvcoords) > 0:
         f.uv.append(uvcoords[face[0]])
         f.uv.append(uvcoords[face[1]])
         f.uv.append(uvcoords[face[2]])
       m.faces.append(f)


     o.link(m)
     o.Layer = 1
     
     # a hack so we don't end up with two objects named 'Root'
     if framelist[1][i] == "Root":
       framelist[1][i] = "Root_mesh"
     
     m.update(1)


     # ==== EXPERIMENTAL SKIN STUFF ====
     
     bonedata = Skeleton_VCIG
     
     skindata = geometry[9]
     try:
       if len(skindata) > 0:
         bonecount = len(skindata[2])
         for bi in range(bonecount):
           m.addVertGroup(bonedata[bi][0])
         vi = 0
         for vbgroup in skindata[0]:
           weights = skindata[1][vi]
           for q in range(4):
             if weights[q] != 0.0: m.assignVertsToGroup(bonedata[vbgroup[q]][0], [vi], weights[q], 'add')
           vi += 1
     except:
       stat.Text("Warning: skin vertex group assignment aborted unexpectedly")
     # ==================================

   
   else:
     o = Object.New('Empty')
     o.Layer = 16
   
   o.setName(framelist[1][i])
   if len(framelist[1][i]) > 20:
     stat.Text("Warning: object name '%s' truncated (too long)"%(framelist[1][i],))
   
   # TODO: layer setup should really be in a global dictionary customizable by user
   if o.name[-4:] == "_dam": o.Layer = 2
   if o.name[-4:] == "_vlo": o.Layer = 4
   if o.name[-3:] == "_L1": o.Layer = 2
   if o.name[-3:] == "_L2": o.Layer = 4
   if o.name[-3:] == "_L3": o.Layer = 8
   if o.name[-3:] == "_L4": o.Layer = 16
   
   #fdata = framelist[0][i]
   scene.link(o)
 
 # Build hierarchy and set object location/rotation
 p = 0
 for fdata in framelist[0]:
   parent = fdata[12]
   oc = Object.Get(framelist[1][p][:20])
   if parent != -1:
     op = Object.Get(framelist[1][parent][:20])
     try:
       op.makeParent([oc])
     except:
       stat.Text("Warning: unable to parent %s -> %s"%(op.name, oc.name))
   fmatrix = [fdata[0:3], fdata[3:6], fdata[6:9]]
   foffset = fdata[9:12]
   euler = matrixToEulerRot(fmatrix)
   try:
     oc.setEuler(euler[0], euler[1], euler[2])
   except:
     oc.setEuler(euler)
   oc.setLocation(foffset[0], foffset[1], foffset[2])
   p += 1
 
 Blender.Redraw()
 return 1


def BuildChildList():
 children = {}
 for o in Object.Get():
   if o.getParent() is not None:
     if children.has_key(o.getParent().name):
       children[o.getParent().name].append(o)
     else:
       children[o.getParent().name] = [o]
 return children
     

def PrintTree(object, level=0):
 global child_dict
 print " "*level, object.name
 if child_dict.has_key(object.name):
   for child in child_dict[object.name]:
     PrintTree(child, level+1)


# ====================
# DFF EXPORT FUNCTIONS
# ====================

def AddHeader(sectiontype, sectiondata=None):
 global ExportVersion
 if sectiondata is None:
   return pack("<iihh", sectiontype, 0, ExportVersion[0], ExportVersion[1])
 else:
   return pack("<iihh", sectiontype, len(sectiondata), ExportVersion[0], ExportVersion[1]) + sectiondata


def CalcBoundingRadius(mesh):
 dx = 0.0
 dy = 0.0
 dz = 0.0
 for v in mesh.verts:
   if abs(v.co[0]) > dx: dx = abs(v.co[0])
   if abs(v.co[1]) > dy: dy = abs(v.co[1])
   if abs(v.co[2]) > dz: dz = abs(v.co[2])
 return math.sqrt(dx*dx+dy*dy+dz*dz)


def ExportTree(o):
 global ExportVersion, ExportType, ExportSplit, objects_in_order, child_dict
 global xframecount, xframenames, xframelist, xgeometrycount, xgeometrylist, xatomiclist, xdummycount

 otype = o.getType()
 if otype != 'Mesh' and otype != 'Empty': return

 # ==== FRAME LIST ====

 oname = o.getName()
 
 objects_in_order.append(oname)

 # name fixes  
 if oname == "Root_mesh": oname = "Root"
 elif oname in ["chassis_vlo_headligh", "chassis_vlo_tailligh"]: oname += "t"

 xframecount += 1

 binstr = "<%ds"%(len(oname),)
 fn = pack(binstr, oname)
 fn = AddHeader(39056126, fn)
 
 # bones
 if ExportType == VC_HUMAN:
   tmpbn = [bn for bn,bid,bunk in Skeleton_VCIG]
   if o.name in tmpbn:
     bid = Skeleton_VCIG[tmpbn.index(o.name)][1]
   else:
     bid = -1
   
   if o.name == 'Root':
     fbone = pack("<5i", 256, 0, 24, 0, 36)
     for i in range(24):
       fbone += pack("<3i", Skeleton_VCIG[i][1], i, Skeleton_VCIG[i][2])
   else:
     fbone = pack("<3i", 256, bid, 0)
   
   fbone = AddHeader(286, fbone)
   fn += fbone
 
 fn = AddHeader(3, fn)
 xframenames += fn

 mtx = o.getMatrix()
 xframelist += pack("<9f", mtx[0][0], mtx[0][1], mtx[0][2], mtx[1][0], mtx[1][1], mtx[1][2], mtx[2][0], mtx[2][1], mtx[2][2])

 loc = o.getLocation()
 xframelist += pack("<3f", loc[0], loc[1], loc[2])

 if o.getParent() is None or o.getParent().getType() == 'Armature':
   p = -1
 else:
   p = objects_in_order.index(o.getParent().getName())
 xframelist += pack("<ii", p, 0)

 if otype == 'Mesh':
   xgeometrycount += 1

   # ==== GEOMETRY ====

   haseffect = 0
   m = o.getData()
   hasuv = m.hasFaceUV() and FlagUVTEX

   # set flags according to the type of object

   if ExportVersion[1] == 4099:
     lighting = ""
   else:
     lighting = pack("<3f", 1.0, 1.0, 1.0)

   geoflags = GEOMETRY_LIGHT
   geof*cks = pack("<ii", 1, 0)
   geof*cki = 1
   
   #if ExportVersion[1] > 2048:
   #  geoflags |= GEOMETRY_TRISTRIP
   #  geoflags |= GEOMETRY_POSITIONS

   if hasuv:
     geoflags |= GEOMETRY_UVTEXTURE

   if FlagMODULATE:
     if o.getName()[:6] != 'wheel_':
geoflags |= GEOMETRY_MODULATE

   if FlagPRELIT:
     geoflags |= GEOMETRY_PRELIT
     geof*cks = pack("<ii", 1, 0)

   if FlagNORMALS:
     geoflags |= GEOMETRY_NORMALS
     geof*cks = pack("<ii", 1, 1)

   if ExportType == DFF_OTHER:
     geof*cki = 0

   # ==== GEOMETRY ====

   bsrad = CalcBoundingRadius(m)
   boundsphere = pack("<4f", 0.0, 0.0, 0.0, bsrad)
   
   vertexlist = ""
   vertexnormals = ""
   for v in m.verts:
     vertexlist += pack("<3f", v.co[0], v.co[1], v.co[2])
     if FlagNORMALS:
vertexnormals += pack("<3f", v.no[0], v.no[1], v.no[2])

   facelist = ""
   uvmap = {}
   vcmap = {}
   splitmap = {}
   for f in m.faces:
     facelist += pack("<4h", f.v[1].index, f.v[0].index, f.mat, f.v[2].index)
     ##
     if ExportSplit:
       if splitmap.has_key(f.mat):
         splitmap[f.mat].append(pack("<3i", f.v[0].index, f.v[1].index, f.v[2].index))
       else:
         splitmap[f.mat] = [pack("<3i", f.v[0].index, f.v[1].index, f.v[2].index),]
     ##
     if hasuv:
for i in range(3):
  if not uvmap.has_key(f.v[i].index):
    uvmap[f.v[i].index] = f.uv[i]
     if FlagPRELIT:
for i in range(3):
  if not vcmap.has_key(f.v[i].index):
    vcmap[f.v[i].index] = (f.col[i].r, f.col[i].g, f.col[i].b, f.col[i].a)

   uvcoords = ""
   if hasuv:
     for uv in uvmap.values():
uvcoords += pack("<ff", uv[0], -uv[1])

   vertexcolors = ""
   if FlagPRELIT:
     for color in vcmap.values():
vertexcolors += pack("<4B", color[0], color[1], color[2], color[3])

   geometry = pack("<hhiii", geoflags, geof*cki, len(m.faces), len(m.verts), 1) + lighting + vertexcolors + uvcoords + facelist + boundsphere + geof*cks + vertexlist + vertexnormals
   geometry = AddHeader(1, geometry)

   # ==== MATERIAL ====

   mc = len(m.materials)
   materiallist = pack("<i", mc)
   materiallist += pack("<i", -1)*mc
   materiallist = AddHeader(1, materiallist)
   for mat in m.materials:

     mtexlist = mat.getTextures()
     if mtexlist[0] is not None:
texturecount = 1
tmpstr = mtexlist[0].tex.image.filename.split("\\")[-1].split(".")[0]
binstr = "%dsB0i"%(len(tmpstr),)
texturename = pack(binstr, tmpstr, 0)
if mtexlist[1] is not None:
  tmpstr = mtexlist[1].tex.image.filename.split("\\")[-1].split(".")[0]
  binstr = "%dsB0i"%(len(tmpstr),)
  maskname = pack(binstr, tmpstr, 0)
else:
  maskname = pack("<i", 0)
     else:
texturecount = 0

     material = pack("<i4Bfi3f", 0, int(mat.R*255), int(mat.G*255), int(mat.B*255), int(mat.alpha*255), 0.02, texturecount, 1.0, mat.getSpec()/2.0, 1.0)
     material = AddHeader(1, material)

     if texturecount > 0:
texture = AddHeader(1, pack("<hh", 4358, 0))+AddHeader(2, texturename)+AddHeader(2, maskname)+AddHeader(3)
# TODO: extension at end of previous could contain a section 272
texture = AddHeader(6, texture)
     else:
texture = ""

     material = material+texture

     if mtexlist[2] is not None:
       if (mtexlist[2].mapto & Texture.MapTo['NOR']):
         #stat.Text("Bump map: "+mtexlist[2].tex.name)
         effect = pack("<iifi", 1, 1, mat.getRef(), 1) # unable to read Nor value, using Ref instead
  tmpstr = mtexlist[0].tex.image.filename.split("\\")[-1].split(".")[0]+"_B"
  binstr = "%dsB0i"%(len(tmpstr),)
  etexturename = pack(binstr, tmpstr, 0)
  emaskname = pack("<i", 0)
  etexture = AddHeader(1, pack("<hh", 4358, 1))+AddHeader(2, etexturename)+AddHeader(2, emaskname)+AddHeader(3)
  etexture = AddHeader(6, etexture)
  effect = effect+etexture+pack("<i", 1)
  #
  tmpstr = mtexlist[2].tex.image.filename.split("\\")[-1].split(".")[0]
  binstr = "%dsB0i"%(len(tmpstr),)
  etexturename = pack(binstr, tmpstr, 0)
  emaskname = pack("<i", 0)
  etexture = AddHeader(1, pack("<hh", 4358, 0))+AddHeader(2, etexturename)+AddHeader(2, emaskname)+AddHeader(3)
  etexture = AddHeader(6, etexture)
  effect = effect+etexture+pack("<i", 0)
       else:
  effect = pack("<iifii", 2, 2, mat.getRef(), 0, 1)
  tmpstr = mtexlist[2].tex.image.filename.split("\\")[-1].split(".")[0]
  binstr = "%dsB0i"%(len(tmpstr),)
  etexturename = pack(binstr, tmpstr, 0)
  emaskname = pack("<i", 0)
  etexture = AddHeader(1, pack("<hh", 4358, 0))+AddHeader(2, etexturename)+AddHeader(2, emaskname)+AddHeader(3)
  etexture = AddHeader(6, etexture)
  effect = effect+etexture+pack("<i", 0)

effect = AddHeader(288, effect)
effect = AddHeader(3, effect)
material += effect
haseffect = 1
     else:
material += AddHeader(3)

     material = AddHeader(7, material)

     materiallist += material

   materiallist = AddHeader(8, materiallist)
   geometry = geometry+materiallist

   # ==== EXPERIMENTAL SKIN STUFF ====
   skingroups = ""
   skinweights = ""
   bonematrices = ""
   
   if ExportType == VC_HUMAN:
     tmpbn = [bn for bn,bid,bunk in Skeleton_VCIG]
     
     try:
       bpfilename = fnbox.val[:-4]+".bp"
       stat.Text("Loading bone patch: "+bpfilename)
       bpfile = open(bpfilename, "rb")
       bonematrices = bpfile.read()
       bpfile.close()
     except:
       stat.Text("Error: unable to open bone patch file")
       try:
         bpfilename = "default.bp"
         stat.Text("Loading bone patch: "+bpfilename)
         bpfile = open(bpfilename, "rb")
         bonematrices = bpfile.read()
         bpfile.close()
       except:
         bonematrices = pack("<i", 24)+("\x0000"*408)
         stat.Text("Error: unable to open bone patch file")
         stat.Text("OUTPUT DFF WILL BE CORRUPT")

     
     for v in m.verts:
       vbg = []
       vbw = []
       vsi = m.getVertexInfluences(v.index)
       if len(vsi) > 4: stat.Text("Warning: %s vert %d affected by more than 4 bones"%(o.name, v.index))
       for i in range(4):
         if i < len(vsi):
           if vsi[i][0] in tmpbn:
             bi = tmpbn.index(vsi[i][0])
             vbg.append(tmpbn.index(vsi[i][0]))
             vbw.append(vsi[i][1])
           else:
             vbg.append(0)
             vbw.append(0.0)
         else:
           vbg.append(0)
           vbw.append(0.0)
       skingroups += pack("<4B", vbg[0], vbg[1], vbg[2], vbg[3])
       skinweights += pack("<4f", vbw[0], vbw[1], vbw[2], vbw[3])
       
   
   # ==== MATERIAL SPLIT ====
   matsplit = ""
   if ExportSplit:
     fc = 0
     for i in range(mc):
       splitlist = splitmap[i]
       matsplit = matsplit + pack("<ii", len(splitlist)*3, i)
       for splitface in splitlist:
         matsplit += splitface
         fc += 3
     matsplit = pack("<3i", 0, mc, fc) + matsplit
     matsplit = AddHeader(1294, matsplit)
   
   # ====
   if ExportType == VC_HUMAN:
     matsplit += AddHeader(278, pack("<i", 24)+skingroups+skinweights+bonematrices)
     
   matsplit += AddHeader(261, pack("<i", 0))
   matsplit = AddHeader(3, matsplit)
   geometry = geometry+matsplit

   geometry = AddHeader(15, geometry)
   xgeometrylist += geometry

   # ==== ATOMIC ====

   atomic = pack("<4i", xframecount-1, xgeometrycount-1, 5, 0)
   atomic = AddHeader(1, atomic)
   
   atomext = ""
   if ExportType == VC_HUMAN:
     atomext += AddHeader(31, pack("<ii", 278, 1))
   atomext += AddHeader(288, pack("<i", haseffect))
   atomext = AddHeader(3, atomext)
   atomic += atomext
   
   atomic = AddHeader(20, atomic)
   xatomiclist += atomic


 elif otype == 'Empty':
   xdummycount += 1


 # == RECURSION ==
 if o.name in child_dict.keys():
   for child in child_dict[o.name]:
     ExportTree(child)


def ExportDFF(filename):
 global child_dict, objects_in_order, ExportType, ExportVersion, ExportSplit
 global xframecount, xframenames, xframelist, xgeometrycount, xgeometrylist, xatomiclist, xdummycount

 # clear globals
 xgeometrycount = 0
 xdummycount = 0
 xframecount = 0
 xatomiclist = ""
 xgeometrylist = ""
 xframelist = ""
 xframenames = ""
 objects_in_order = []

 child_dict = BuildChildList()

 selected = Object.GetSelected()
 
 if len(selected) == 0:
   stat.Text("Error: nothing selected")
   return 0
 if len(selected) > 1:
   stat.Text("Error: please select only 1 object")
   return 0
 
 selected = selected[0]

 PrintTree(selected)

 print "="*60

 # set header version according to type
 if ExportType == DFF_OTHER:
   ExportVersion = (784, 0)
 elif ExportType in [GTA3_CAR, GTA3_HUMAN, GTA3_WORLD]:
   ExportVersion = (-1, 2048)
 elif ExportType == VC_CAR:
   ExportVersion = (-1, 3074)
 elif ExportType == VC_HUMAN:
   ExportVersion = (-1, 3074)
 elif ExportType == VC_WORLD:
   ExportVersion = (-1, 4099)

 if selected.getParent() is None or selected.getParent().getType() == 'Armature':
   ExportTree(selected)
 else:
   stat.Text("Error: selected object has a parent")
   return 0

 if xgeometrycount == 0 and xdummycount == 0:
   stat.Text("Error: could not find any mesh or dummy objects to export")
   return 0

 
 xframelist = pack("<i", xframecount) + xframelist
 xframelist = AddHeader(1, xframelist) + xframenames
 xframelist = AddHeader(14, xframelist)

 xgeometrylist = AddHeader(1, pack("<i", xgeometrycount)) + xgeometrylist
 xgeometrylist = AddHeader(26, xgeometrylist)

 if ExportVersion[1] < 3000:
   clump = pack("<i", xgeometrycount)
 else:
   clump = pack("<3i", xgeometrycount, 0, 0)

 clump = AddHeader(1, clump)
 clump = clump + xframelist + xgeometrylist + xatomiclist + AddHeader(3)
 clump = AddHeader(16, clump)

 outfilename = fnbox.val
 if len(outfilename) < 5:
   outfilename = "noname.dff"
   stat.Text("Warning: invalid file name")

 fileexists = 1
 suffix = 0
 while fileexists:
   try:
     file = open(outfilename, "rb")
     file.close()
     suffix += 1
     if outfilename[-5] in "1234567890":
       if suffix < 11:
         outfilename = outfilename[:-5]+str(suffix)+".dff"
       elif 10 < suffix < 100:
         outfilename = outfilename[:-6]+str(suffix)+".dff"
       else:
         outfilename = outfilename[:-7]+str(suffix)+".dff"
     else:
       outfilename = outfilename[:-4]+str(suffix)+".dff"
   except:
     fileexists = 0
 
 stat.Text("Exporting %d meshes, %d dummies..."%(xgeometrycount, xdummycount))
 file = open(outfilename, "wb")
 file.write(clump)
 if bZLOCK:
   stat.Text("Applying Z-Lock")
   lockdata = AddHeader(61982, pack("<BBhBBBB", 41, 254, 7188, 3, 97, 9, 1))
   file.write(lockdata)
 file.close()
 stat.Text("%d bytes written to %s"%(len(clump)+(bZLOCK*20),outfilename))
 
 return 1


# ===============
# COL File Import (NOT IMPLIMENTED)
# ===============
def ImportCOL(filename, colname):
 global stat
 if type(filename) != type("") or type(colname) != type(""): return
 if filename == "" or colname == "": return
 stat.Text("ImportCOL:", 0, 0)
 stat.Text(filename, 0, 0)
 stat.Text(colname, 0, 0)
 stat.Text("SORRY, THIS IS NOT YET IMPLIMENTED")

lfss = ("CITHROBFLAYEKUD ",(7,1,8,11,15,8,5,0,12,11,14,15,6,10,15,9,13,2,3,5,4))

#
print "==== Script Start ===="
Draw.Register(redraw, handleEvent, handleButton)


serabella
  • serabella

    Noob scripter

  • Members
  • Joined: 18 Jun 2009

#152

Posted 30 January 2012 - 04:14 PM

where do I put the script? LOL

WilliJ
  • WilliJ

    Player Hater

  • Members
  • Joined: 24 Jan 2012

#153

Posted 31 January 2012 - 08:23 AM Edited by WilliJ, 31 January 2012 - 08:49 AM.

serabella - Create txt file(with name GTA_IE_01c.txt) and put this script into it.
Then, rename txt file to py file(like this GTA_IE_01c.py). And now, you can use it!

---
Oh...
This is a Download link(work) on head of this topic, on page #1.


user posted image This mod is hosted at GTAGarage.com

Downloads:
Download Blender I/O Script v0.1 + Tut - 0.335MB, uploaded on Jan 03 2010, downloaded 5698 times




2 user(s) are reading this topic

0 members, 2 guests, 0 anonymous users