#!BPY #************************************************************************************************** # Supreme Commander Importer for Blender3D - www.blender3d.org # # Written by dan - www.sup-com.net # # History # 0.1.0 06/06/06 - Initial version. # 0.2.0 06/06/10 - Added SCA (Animation) support # 0.3.0 06/07/02 - Alpha release # # Todo # - Material/uv map 2 # - Bone pos/rot for scm & sca. Not perfect to use gentle words. # - Make sca loading independent of the scm_mesh. (e.g get bone pos/loc from armature instead) # - GUI for loading # #************************************************************************************************** """ Name: 'SupCom Model (.scm) 3.5' Blender: 232 Group: 'Import' Tooltip: 'Import Supreme Commander Models (*.scm) and Animations (*.sca)' """ import Blender from Blender import NMesh, Scene, Object from Blender import Mathutils from Blender.Mathutils import * from Blender.BGL import * from Blender import Draw from Blender.Draw import * import os from os import path import struct import string import math from math import * VERSION = '3.5' ###################################################### # User defined behaviour, Select as you need ###################################################### #Enable Progress Bar ( 0 = faster ) PROG_BAR_ENABLE = 1 #how many steps a progress bar has (the lesser the faster) PROG_BAR_STEP = 25 #LOG File for debuging #Enable LOG File (0 = Disabled , 1 = Enabled ) LOG_ENABLE = 0 #Filename / Path. Default is blender directory Filename SC-E_LOG.txt LOG_FILENAME = "SC-E_LOG.txt" ###################################################### # Init Supreme Commander SCM( _bone, _vertex, _mesh), SCA(_bone, _frame, _anim) Layout ###################################################### #xy_to_xz_transform = Matrix([1, 0, 0], [ 0, 0, 1], [ 0, 1, 0]) xy_to_xz_transform = Matrix([1, 0, 0], [ 0, 0, 1], [ 0, -1, 0]) # -1 0 0 # 0 0 1 # 0 1 0 class scm_bone : name = "" #rest_pose_inv = [] rel_mat = [] rel_mat_inv = [] position = [] rotation = [] #abs_pos = [] parent = 0 parent_index = 0 rel_matrix_inv = [] #children = [] #numchildren = 0 #global xy_to_xz_transform def __init__(self, name): self.name = name #self.rest_pose_inv = [[0.0] * 4] * 4 #self.position = [0.0] * 3 #self.rotation = [0.0] * 4 self.rel_mat_inv = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]) self.rel_mat = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]) self.rotation = Quaternion(0,0,0,0) self.position = Vector(0,0,0) def load(self, file): #global xy_to_xz_transform bonestruct = '16f3f4f4i' buffer = file.read(struct.calcsize(bonestruct)) readout = struct.unpack(bonestruct, buffer) #supcom information: readRPI = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]) #// Inverse transform of the bone relative to the local origin of the mesh #// 4x4 Matrix with row major (i.e. D3D default ordering) for i in range(4): readRPI[i] = readout[i*4:i*4+4] self.rel_mat_inv = Matrix(readRPI[0], readRPI[1], readRPI[2], readRPI[3])#*xy_to_xz_transform #note rot here changes pointing direction of spikie self.rel_mat = self.rel_mat_inv.invert() #self.rel_mat = (Matrix(rest_pose_inv).invert()) #// Position relative to the parent bone. pos = readout[16:19] self.position = Vector(pos[0], pos[1], pos[2]) #// Rotation relative to the parent bone. rot = readout[19:23] self.rotation = Quaternion( rot[0], rot[1], rot[2], rot[3] ) #// Index of the bone's parent in the SCM_BoneData array self.parent_index = readout[24] # Read bone name #oldpos = file.tell() #file.seek(bone[..], 0) #self.name = file.readline() #file.seek(oldpos, 0) return self def dump(self): print 'Bone ', self.name print 'Position ', self.position print 'Rotation ', self.rotation print 'Parent Idx ', self.parent_index if (self.parent != 0): print 'Parent ', self.parent.name else: print 'Parent ' print 'Rest Pose Inv.' #for row in range(4): #print ' ', self.rest_pose_inv[row] class scm_vertex : position = [] tangent = [] normal = [] binormal = [] uv1 = [] uv2 = [] bone_index = [] def __init__(self): self.position = Vector(0,0,0) self.tangent = Vector(0,0,0) self.normal = Vector(0,0,0) self.binormal = Vector(0,0,0) self.uv1 = Vector(0,0) self.uv2 = Vector(0,0) self.bone_index = [0]*4 def load(self, file): vertstruct = '3f3f3f3f2f2f4B' vertsize = struct.calcsize(vertstruct) buffer = file.read(vertsize) vertex = struct.unpack(vertstruct, buffer) self.position = vertex[0:3] self.tangent = vertex[3:6] self.normal = vertex[6:9] self.binormal = vertex[9:12] self.uv1 = vertex[12:14] self.uv2 = vertex[14:16] self.bone_index = vertex[16:20] return self def dump(self): print 'position ', self.position print 'tangent ', self.tangent print 'normal ', self.normal print 'binormal ', self.binormal print 'uv1 ', self.uv1 print 'uv2 ', self.uv2 print 'bones ', self.bone_index class scm_mesh : bones = [] vertices = [] faces = [] info = [] filename = "" def __init__(self): self.bones = [] self.vertices = [] self.faces = [] self.info = [] self.filename = "" def load(self, filename): global xy_to_xz_transform self.filename = filename scm = file(filename, 'rb') # Read header headerstruct = '4s11L' buffer = scm.read(struct.calcsize(headerstruct)) header = struct.unpack(headerstruct, buffer) marker = header[0] version = header[1] boneoffset = header[2] bonecount = header[3] vertoffset = header[4] extravertoffset = header[5] vertcount = header[6] indexoffset = header[7] indexcount = header[8] tricount = indexcount / 3 #? infooffset = header[9] infocount = header[10] totalbonecount = header[11] if (marker != 'MODL'): print 'Not a valid scm' return if (version != 5): print 'Unsupported version (%d)' % version return # Read bone names scm.seek(pad(scm.tell()), 1) length = (boneoffset - 4) - scm.tell() # This should probably be handeled by the scm_bone reader as it contains the nameoffset. But I'm lazy # and logic tells me it's written in the same order as the bones. buffer = scm.read(length) rawnames = struct.unpack(str(length)+'s',buffer) bonenames = string.split(rawnames[0],'\0')[:-1] # Read bones scm.seek(boneoffset, 0) for b in range(0, totalbonecount): bone = scm_bone(bonenames[b]) bone.load(scm) self.bones.append(bone) #show them (for debug) #for b in range(0, totalbonecount): #print "bone %d has %d children = " %(b, self.bones[b].numchildren) # Set parent (this could probably be done in the other loop since parents are usually written to the file # before the children. But you never know.. for bone in self.bones: if (bone.parent_index != -1): bone.parent = self.bones[bone.parent_index] else: bone.parent = 0 # the bone matrix relative to the parent. if (bone.parent != 0): mrel = (bone.rel_mat) * Matrix(bone.parent.rel_mat).invert() #* xy_to_xz_transform bone.rel_matrix_inv = Matrix(mrel).invert() else: mrel = bone.rel_mat * xy_to_xz_transform #there is no parent bone.rel_matrix_inv = Matrix(mrel).invert() #self.rest_pose = Matrix(self.rest_pose[0], self.rest_pose[1], self.rest_pose[2], self.rest_pose[3]) in sc = rest pose inv #self.rel_mat = (Matrix(self.rest_pose).invert()) * xy_to_xz_transform in sc = rest pose yz # Read vertices scm.seek(vertoffset, 0) for b in range(0, vertcount): vert = scm_vertex() vert.load(scm) self.vertices.append(vert) # Read extra vertex data # Not implemented in Sup Com 1.0! # Read indices (triangles) tristruct = '3h' trisize = struct.calcsize(tristruct) scm.seek(indexoffset, 0) for t in range(tricount): buffer = scm.read(trisize) face = struct.unpack(tristruct, buffer) self.faces.append(list(face)) # Read info if (infocount > 0): scm.seek(infooffset) buffer = scm.read() rawinfo = struct.unpack(str(len(buffer))+'s',buffer) self.info = string.split(rawinfo[0],'\0')[:-1] scm.close() return self def dump(self): print '' print 'Filename: ', self.filename print 'Bones ', len(self.bones) print 'Verts ', len(self.vertices) print 'Faces ', len(self.faces) print '' print 'INFO: ' for info in self.info: print ' ', info class sca_bone: position = [] rotation = [] #changed: rototation -> rotation pose_pos = [] pose_rot = [] rel_matrix = [] pose_matrix = [] #rel_mat = None def __init__(self, pos, rot): self.position = pos self.rotation = rot self.rel_matrix = None self.pose_matrix = None #self.rel_mat = None def dump(self): print 'Position ', self.position print 'Rotation ', self.rotation class sca_frame: keytime = 0.0 keyflags = 0 bones = [] anim = None def __init__(self, anim): self.keytime = 0.0 self.keyflags = 0 self.bones = [] self.anim = anim def load(self, file): frameheader_fmt = 'fl' frameheader_size = struct.calcsize(frameheader_fmt) buffer = file.read(frameheader_size) (self.keytime, self.keyflags) = struct.unpack(frameheader_fmt, buffer) posrot_fmt = '3f4f' posrot_size = struct.calcsize(posrot_fmt) for b in range (0, self.anim.numbones) : buffer = file.read(posrot_size) posrot = struct.unpack(posrot_fmt, buffer) bone = sca_bone(posrot[0:3], posrot[3:7]) self.bones.append(bone) def dump(self): print 'Time ', self.keytime print 'Flags ', self.keyflags class sca_anim : filename = "" frames = [] bones = [] bonelinks = [] bonenames = [] numbones = 0 duration = 0.0 def __init__(self): self.filename = "" self.frames = [] self.bones = [] self.numbones = 0 self.bonelinks = [] self.bonenames = [] self.duration = 0.0 def calcAnimBoneMatrix(self, frame, bone_index, armature_bones, frame_index): global xy_to_xz_transform bone = frame.bones[bone_index]; parent_index = self.bonelinks[bone_index] # note that the pos/rot of the armature_bones are still in relative supcom coordinates. # so we can correct the relative pos-increase by the relative armature-increase pose_rel_pos = Vector(bone.position) pose_rel_rot = Quaternion(bone.rotation) # the matrix representation... it's easier to work with matrix notation I think. # the rotation: pose_rel_matrix = (pose_rel_rot.toMatrix()).resize4x4() # the translation: for i in xrange(3): pose_rel_matrix[3][i] = pose_rel_pos[i] #pose_rel_matrix = pose_rel_matrix * xy_to_xz_transform #rel_pos = pose_rel_pos - armature_bones[bone_index].position #rel_rot = DifferenceQuats(pose_rel_rot, armature_bones[bone_index].rotation) if (parent_index == -1) : # for the root bone, this is already the absolution pos/rot, but, # the root bone should be rotated into the blender coordinates bone.rel_matrix = pose_rel_matrix * xy_to_xz_transform #testmat =(bone.rel_mat) * Matrix(bone.parent.rel_mat).invert() if (parent_index >= 0): # for all the children, they are seen relative to the parents. bone.rel_matrix = pose_rel_matrix # Call all children for b in range(len(self.bonelinks)): if (self.bonelinks[b] == bone_index): self.calcAnimBoneMatrix(frame, b, armature_bones, frame_index) # the (rendered) animation positions are relative to # both the parent, and to the relative rest position of the bone. bone.pose_matrix = Matrix(bone.rel_matrix * armature_bones[bone_index].rel_matrix_inv)#* xy_to_xz_transform) #bone.pose_matrix = bone.pose_matrix * xy_to_xz_transform # pose position relative to the armature bone.pose_pos = Vector(bone.pose_matrix.translationPart()) bone.pose_rot = bone.pose_matrix.toQuat() #test = bone.pose_matrix.toQuat() #bone.pose_rot = Quaternion( test.x, test.y, test.z, test.w) def load(self, filename): self.filename = filename sca = file(filename, 'rb') # Read header headerstruct = '4sllflllll' buffer = sca.read(struct.calcsize(headerstruct)) header = struct.unpack(headerstruct, buffer) (magic, \ version, \ numframes, \ self.duration, \ self.numbones, \ namesoffset, \ linksoffset, \ animoffset, \ framesize) = struct.unpack(headerstruct, buffer) if (magic != 'ANIM'): print 'Not a valid .sca animation file' return if (version != 5): print 'Unsupported sca version: %d' % version return # Read bone names sca.seek(namesoffset, 0) length = linksoffset - namesoffset buffer = sca.read(length) rawnames = struct.unpack(str(length)+'s',buffer) self.bonenames = string.split(rawnames[0], '\0')[:-1] # Read links links_fmt = str(self.numbones)+'l' links_size = struct.calcsize(links_fmt) buffer = sca.read(links_size) self.bonelinks = struct.unpack(links_fmt, buffer) posrot_fmt = '3f4f' posrot_size = struct.calcsize(posrot_fmt) sca.seek(animoffset) buffer = sca.read(posrot_size) root_posrot = struct.unpack(posrot_fmt, buffer) for f in range (0, numframes) : frame = sca_frame(self) frame.load(sca) self.frames.append(frame) sca.close() return self def dump(self): print 'SCA: ', self.filename print 'Duration: %fs' % self.duration print 'Num loaded frames ', len(self.frames) print 'Bonelinks' for link in self.bonelinks: print ' ', link print 'Bone names' for name in self.bonenames: print ' ', name def pad(size): val = 32 - (size % 32) if (val > 31): return 0 return val #************************************************************************************************** # Blender Interface #************************************************************************************************** def read_scm() : global xy_to_xz_transform global scm_filepath # [0] both [1] path [2] name global sca_filepath # [0] both [1] path [2] name print "=== LOADING Sup Com Model ===" print "" xy_to_xz_transform.resize4x4() scene = Blender.Scene.GetCurrent() mesh = scm_mesh() if (mesh.load(scm_filepath[0]) == None): print 'Failed to load %s' %scm_filepath[2] return ProgBarLSCM = ProgressBar( "Imp: load SCM", (2*len(mesh.vertices) + len(mesh.faces))) armature_name = string.rstrip(scm_filepath[2], ".scm") print "armature ", armature_name ### CREATE ARMATURE armObj = Object.New('Armature', armature_name) #bad armData = Blender.Armature.Armature(armature_name) armData.drawAxes = True armData.makeEditable() for index in range(len(mesh.bones)): bone = mesh.bones[index] blender_bone = Blender.Armature.Editbone() #not nice parent may not exist, but usualy should exist (depends on storing in scm) if (bone.parent != 0) : blender_bone.parent = armData.bones[bone.parent.name] #blender_bone.options(Armature.CONNECTED) blender_bone.matrix = Matrix(bone.rel_mat * xy_to_xz_transform) armData.bones[bone.name] = blender_bone #save changes (after linking!) armObj.link(armData) scene.link(armObj) #scene.objects.new(armData) ### CREATE MESH meshData = Blender.Mesh.New('Mesh') ProgBarLSCM.text = "IMP: Verticles" #add verts vertlist = [] for vert in mesh.vertices: ProgBarLSCM.do() vertlist.append(Vector(vert.position)*xy_to_xz_transform) meshData.verts.extend(vertlist) meshData.vertexUV = True for i_v in xrange(len(meshData.verts)): uv1 = mesh.vertices[i_v].uv1 meshData.verts[i_v].uvco = Vector(uv1[0], 1.0-uv1[1]) ProgBarLSCM.text = "IMP: Faces" #reverse faces #for face in mesh.faces: # face.reverse() #add faces meshData.faces.extend(mesh.faces) meshData.faceUV = True for face in meshData.faces : ProgBarLSCM.do() face.uv = [face.verts[i].uvco for i in range(3)] #put in scene mesh_obj = Object.New('Mesh','Mesh') mesh_obj.link(meshData) #scene.objects.new(meshData) #assigns vertex groups #mesh must be in object for bone in mesh.bones: meshData.addVertGroup(bone.name) for vertex_index in range(len(mesh.vertices)): ProgBarLSCM.do() vertex = mesh.vertices[vertex_index] bone_index = vertex.bone_index[0] meshData.assignVertsToGroup(mesh.bones[bone_index].name, [vertex_index], 1.0, Blender.Mesh.AssignModes.REPLACE) #'REPLACE' # it works... but you've to select/change to edit mode for the object to show up. # dunno why that is, maybe because Nmesh is depracated. meshData.update() #bones disapear wen update ? #armData.update() scene.link(mesh_obj) #must be in scene #armObj = None #meshObj = None #for obj in Object.Get(): # if obj.getType() == 'Armature': # armObj = obj # if obj.getType() == 'Mesh': # meshObj = obj #mesh_obj = Blender.Object.Get('Mesh') armObj.makeParentDeform([mesh_obj], 0, 0) #makeParentVertex(objects, indices, noninverse=0, fast=0) meshData.update() armData.update() if len(mesh.info): print "=== INFO ===" for info in mesh.info: print "",info print "=== COMPLETE ===" if sca_filepath[0] != "" : read_anim(mesh) def read_anim(mesh): global xy_to_xz_transform global sca_filepath # [0] both [1] path [2] name #xy_to_xz_quat = xy_to_xz_transform.toQuat() print "=== LOADING Sup Com Animation ===" print "" anim = sca_anim() anim.load(sca_filepath[0]) ProgBarLSCA = ProgressBar( "Imp: Frames", len(anim.frames)) scene = Blender.Scene.GetCurrent() arm_obj = None for obj in scene.objects: data = obj.getData() if type(data) is Blender.Types.ArmatureType: arm_obj = obj break if arm_obj == None: print "couldn't apply animation, no armature in the scene" return #arm_obj = armObj print arm_obj.name #actionpath, actionname = os.path.split(filename) action = Blender.Armature.NLA.NewAction(sca_filepath[2]) action.setActive(arm_obj) pose = arm_obj.getPose() for frame_index in xrange(len(anim.frames)): ProgBarLSCA.do() Blender.Set("curframe", frame_index+1) frame = anim.frames[frame_index] # this changes the relative orientation (supcom) to absolute orientation (blender) anim.calcAnimBoneMatrix(frame, 0, mesh.bones, frame_index) # this inserts the bones information into blender. for b in range(len(frame.bones)): pose_bone = pose.bones[anim.bonenames[b]] if (pose_bone == None): print 'Frame %d - Bone \"%s\" not found' % (frame_index, anim.bonenames[b]) continue anim_bone = frame.bones[b] pose_bone.loc = anim_bone.pose_pos pose_bone.quat = anim_bone.pose_rot pose_bone.size = Vector(1,1,1) pose.update() pose_bone.insertKey(arm_obj, frame_index+1, [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT, Blender.Object.Pose.SIZE]) pose.update() Blender.Set("curframe", 1) #scene = Blender.Scene.GetCurrent() context = scene.getRenderingContext() context.endFrame(len(anim.frames)+1) print "=== COMPLETE ===" ###################################################### # GUI ###################################################### log = [] log_max_lines = 14 LOG_FILE = None #log to file def LOGn(message): global LOG_FILE global LOG_ENABLE global LOG_FILENAME if LOG_ENABLE : if LOG_FILE == None : LOG_FILE = open( LOG_FILENAME, 'w') LOG_FILE.write('SupCom Exporter LOG File:\n\n') LOGp( "LOG enabled: %s" % (LOG_FILENAME)) Log(message + '\n') else : LOG_FILE.write(message + '\n') #Log to file, to console and exp window def LOGp(message): global log, log_max_lines LOGn(message) print message log.append(message) if len(log) > log_max_lines: del log[0] counter = [] cLog = [] #log for a amount of errors like vertex errors def countLOG(message): global cLog global counter cont = False for i in xrange(len(cLog)): if cLog[i] == message: cont = True counter[i] +=1 break if not cont : cLog.append( message) counter.append( 1) def closeLog(): global cLog, LOG_FILE global counter for i in xrange(len(cLog)): LOGp("%s (Times:%d)" % (cLog[i], counter[i])) if LOG_FILE != None : LOG_FILE.close() Blender.Window.RedrawAll() class ProgressBar : global PROG_BAR_STEP global PROG_BAR_ENABLE progress = 0 progressold = 0 current = 0 end = 0 div = 0 text = "None" def __init__(self, text, end): self.progress = 0 self.progressold = 0 self.current = 0 self.end = end self.text = text self.div = PROG_BAR_STEP #it looks like blender needs to init this progress bar with 0.0 if PROG_BAR_ENABLE : Blender.Window.DrawProgressBar ( 0.0 , text) def do(self): if PROG_BAR_ENABLE : self.current += 1 self.progress = (self.current*self.div)/self.end if self.progress != self.progressold : self.progressold = self.progress Blender.Window.DrawProgressBar ( float(self.progress)/self.div , self.text) # Events EVENT_DRAW = 1 EVENT_EXIT = 2 EVENT_SCMDIR = 3 EVENT_SCADIR = 4 show_log = 0 sca_filepath = [ "", "", "None"] scm_filepath = [ "", "", "None"] def anim_fileselector_callback(filename): global sca_filepath sca_filepath[0] = filename #print "Filename%sI\n" % filename #if ( filename != "" ) : #sca_filepath = [ "" , "None"] #return #else : length = len(filename) if filename[length-4:length] == ".sca" : sca_filepath[1], sca_filepath[2] = os.path.split(filename) else : sca_filepath[0] = "" sca_filepath[1] = "" sca_filepath[2] = "Non Supported" #sca_filepath[1] , sca_filepath[2] = os.path.split(filename) def fileselector_callback(filename): global scm_filepath #sadly you cant check whether the cancel button is pressed scm_filepath[0] = filename #print "Filename%sI\n" % filename #if ( filename != "" ) : length = len(filename) if filename[length-4:length] == ".scm" : scm_filepath[1], scm_filepath[2] = os.path.split(filename) else : scm_filepath[0] = "" scm_filepath[1] = "" scm_filepath[2] = "Non Supported" # Exit() #def forcequit() # Exit() def draw(): global EVENT_DRAW, EVENT_EXIT,EVENT_SCADIR,EVENT_SCADIR global scm_filepath, sca_filepath, show_log global log_max_lines, log global VERSION # Titles glClear(GL_COLOR_BUFFER_BIT) top = 60 + log_max_lines * 12 + 8 #top = 500 top_x = 304 glColor3f(0.8, 0.8, 1) glRecti(top_x, top, 4, 4) glBegin(GL_LINES) glColor3f(0.8, 0.8, 0.8) glVertex2d(4, top) glVertex2d(4, 4) glVertex2d(4, 4) glVertex2d(top_x, 4) glColor3f(0.5, 0.5, 0.5) glVertex2d(top_x, top) glVertex2d(4, top) glVertex2d(top_x, top) glVertex2d(top_x, top-1) glEnd() glColor3f(0, 0, 0) glRasterPos2d(10, top-16) Text("Supreme Commander Importer " + VERSION) # Show exporting log if show_log: for index in range(0, len(log)): i = (len(log) - 1) - index glRasterPos2i(10, 40 + i*12) Text(log[index]) #, 'tiny') Button("Close", EVENT_EXIT , 10, 10, 80, 18) # Exporter GUI else: #if scm_directory.val == 'scm': #if scm_filepath[1] == 'None' : #automatically launch the browse window once # Blender.Window.FileSelector (fileselector_callback, "Select SCM File", "*.scm") #Exit() # why dont you go to exit?, never # forcequit() Blender.Draw.Button("Browse SCM", EVENT_SCMDIR, 10, 45, 80, 18, "Select scm") Blender.Draw.Button("Browse SCA", EVENT_SCADIR, 10, 80, 80, 18, "Select sca") glRasterPos2d(100, 47) if scm_filepath[0] == "" : Text("SCM: " + scm_filepath[2]) else: Text(":" + scm_filepath[2]) glRasterPos2d(100, 82) if sca_filepath[0] == "" : Text("SCA: " + sca_filepath[2]) else : Text(":" + sca_filepath[2]) # Draw and Exit Buttons Button("Import", EVENT_DRAW , 10, 10, 80, 18) Button("Exit", EVENT_EXIT , 100, 10, 80, 18) def event(evt, val): if (evt == QKEY and not val): Exit() def bevent(evt): global EVENT_DRAW,EVENT_EXIT global scm_filepath global show_log if (evt == EVENT_EXIT): #show_log = 1 Exit() elif (evt == EVENT_SCMDIR): Blender.Window.FileSelector (fileselector_callback, "Select SCM File") Blender.Redraw() elif (evt == EVENT_SCADIR): if scm_filepath[0] != "" : Blender.Window.FileSelector (anim_fileselector_callback, "Select SCA File", scm_filepath[1]+"\\") else : Blender.Window.FileSelector (anim_fileselector_callback, "Select SCA File") Blender.Redraw() elif (evt == EVENT_DRAW): if (scm_filepath[0] != ''): show_log = 1 read_scm() #if (sca_filepath[0] != ''): # show_log = 1 # read_sca() Blender.Redraw() Register(draw, event, bevent) #open fileselector automaticly Blender.Window.FileSelector (fileselector_callback, "Select SCM File")