WilliJ Posted January 27, 2012 Share Posted January 27, 2012 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 # ============================================================== ## 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 mathimport structfrom struct import *import Blenderfrom Blender import * # Object, NMesh, Material, Texture, BGL, Draw, Windowfrom Blender.BGL import *# =========# GLOBALS# =========# Interfacefnbox = Draw.Create("")tdbox = Draw.Create("")menu = Draw.Create(2001)winwidth = 50winheight = 50# main=0, help=5Mode = 0prevmode = 0# button IDsBUTTON_BROWSE = 1401BUTTON_FNBOX = 1402BUTTON_TDBOX = 1403BUTTON_EXIT = 1500BUTTON_HELP = 1501BUTTON_HELPEND = 1502BUTTON_PRESETS = 1986BUTTON_IMPORT = 1600BUTTON_EXPORT = 1601BUTTON_TOGSPLIT = 1162BUTTON_TOGBPATCH = 1164BUTTON_TOGUVTEX = 1210BUTTON_TOGPRELIT = 1211BUTTON_TOGNORMALS = 1212BUTTON_TOGMODULATE = 1213BUTTON_ZLOCK = 2240# default optionsFileFormat = 1 # dff=1, col=2ImportSplit = 0ExportSplit = 1ExtractBonePatch = 0ExportType = 2001ExportVersion = (-1, 3074)FlagUVTEX = 1FlagPRELIT = 0FlagNORMALS = 1FlagMODULATE = 1bZLOCK = 0# preset IDsDFF_OTHER = 2007GTA3_CAR = 2004GTA3_HUMAN = 2005GTA3_WORLD = 2006VC_CAR = 2001VC_HUMAN = 2002VC_WORLD = 2003# geometry flagsGEOMETRY_TRISTRIP = 1GEOMETRY_POSITIONS = 2GEOMETRY_UVTEXTURE = 4GEOMETRY_PRELIT = 8GEOMETRY_NORMALS = 16GEOMETRY_LIGHT = 32GEOMETRY_MODULATE = 64GEOMETRY_ETEXTURE = 128# internalxgeometrycount = 0xdummycount = 0xframecount = 0xatomiclist = ""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 texthelptext = [ (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 Theethdef 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 bonedef 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 geometrylistdef 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 atomicsdef 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 1def 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]) + sectiondatadef 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 = 1tmpstr = 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 272texture = 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 += effecthaseffect = 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) Link to comment Share on other sites More sharing options...
serabella Posted January 30, 2012 Share Posted January 30, 2012 where do I put the script? LOL Link to comment Share on other sites More sharing options...
WilliJ Posted January 31, 2012 Share Posted January 31, 2012 (edited) 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. 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 Edited January 31, 2012 by WilliJ Link to comment Share on other sites More sharing options...
DYOM designer Posted April 23, 2016 Share Posted April 23, 2016 please how to install it in blender 6.22 Link to comment Share on other sites More sharing options...
cl55684 Posted November 23, 2020 Share Posted November 23, 2020 (edited) Loved this old tool and recovered that file. https://mega.nz/folder/k6B2zbCA#qU3YvVBG5XjLKxuPeVW4Dw Edited November 23, 2020 by CleytonGames Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now