def export(self, scene): theObjects = scene.objects print "Starting OBJ export to " + self.filename if not checkFile(self.filename): return Blender.Window.WaitCursor(1) Window.DrawProgressBar(0, "Examining textures") self.texture = getTexture(self, theObjects, self.iscsl, 7) if self.regions: (pwidth, pheight) = PanelRegionHandler().panelimage().size for img, (n, x1, y1, width, height) in self.regions.iteritems(): self.regions[img] = (float(x1) / pwidth, float(y1) / pheight, float(width) / pwidth, float(height) / pheight) #clock=time.clock() # Processor time self.file = open(self.filename, "w") self.writeHeader() self.writeObjects(theObjects) checkLayers(self, theObjects) self.file.close() Window.DrawProgressBar(1, "Finished") #print "%s CPU time" % (time.clock()-clock) print "Finished - exported %s primitives\n" % self.nprim if self.log: r = Draw.PupMenu(("Exported %s primitives%%t|" % self.nprim) + '|'.join([a[0] for a in self.log])) if r > 0: raise ExportError(None, self.log[r - 1][1]) else: Draw.PupMenu("Exported %s primitives%%t|OK" % self.nprim)
# # Copyright (c) 2007 Jonathan Harris # # This code is licensed under version 2 of the GNU General Public License. # http://www.gnu.org/licenses/gpl-2.0.html # # See ReadMe-XPlane2Blender.html for usage. # from Blender import Draw, Image, Window from math import log from XPlaneUtils import PanelRegionHandler image = Image.GetCurrent() # may be None h = PanelRegionHandler() opts = [] if not image: pass elif h.isRegion(image): opts.append('Delete this region%x1') opts.append('Reload all regions%x3') elif h.isPanel(image): if h.countRegions() < PanelRegionHandler.REGIONCOUNT: opts.append('Create new region...%x2') else: opts.append( 'Can\'t create new region - already using maximum of %d regions%%x0' % PanelRegionHandler.REGIONCOUNT) opts.append('Reload all regions%x3')
def getTexture (expobj, theObjects, iscsl, fileformat,want_draped=0): texture=None multierr=[] panelerr=(fileformat==7 and expobj.iscockpit) havepanel=False panelobjs=[] nobj=len(theObjects) texlist=[] layers=0 if find_prop_list(theObjects,'panel_ok') != None: expobj.ispanelok=True if iscsl: expobj.lod=[0,1000,4000,100000] # list of lod limits else: expobj.lod=[0,1000,4000,10000] # list of lod limits thisdir=normpath(dirname(Blender.Get('filename'))) h=PanelRegionHandler() lod_keys = [['lod_0', 0], ['lod_1',1], ['lod_2',2],['lod_3',3]]; for l in lod_keys: src_o=find_prop_list(theObjects,l[0]) if src_o != None: layer=l[1] #print "object %s layer %d found LOD %s" % (object.name,layer,get_prop(object,l[0],0)) expobj.lod[layer] = float(get_prop(src_o,l[0],0)) if layer<3 and expobj.lod[layer+1]<=expobj.lod[layer]: expobj.lod[layer+1]=expobj.lod[layer]+1 if expobj.layermask!=7: expobj.layermask=7 #print "Info:\tMultiple Levels Of Detail found" expobj.log.append(("Multiple Levels Of Detail found",[])) for o in range (nobj-1,-1,-1): object=theObjects[o] if h.isHandlerObj(object): continue objType=object.getType() if expobj.layermask==1 and not expobj.iscockpit: if layers==0: layers = object.Layer&7 elif object.Layer&7 and layers^(object.Layer&7): expobj.layermask=7 #print "Info:\tMultiple Levels Of Detail found" expobj.log.append(("Multiple Levels Of Detail found", [])) if not object.Layer&expobj.layermask: continue if objType == "Mesh": mesh=object.getData(mesh=True) if isLight(object): material=mesh.materials[0] mtex=material.getTextures()[0] if mtex: image=mtex.tex.image if image: texture=checkdup(image.filename, thisdir, texture, texlist, multierr, object) continue print 'Warn:\tIgnoring custom light "%s" with no texture' % object.name expobj.log.append(('Ignoring custom light "%s" with no texture' % object.name, [object])) elif mesh.faceUV: #print '%s (%d)' % (object.getName(), len(mesh.faces)) for face in mesh.faces: has_draped = (face.mode&Mesh.FaceModes.TILES) and has_prop(object,'ATTR_draped') if (face.mode&Mesh.FaceModes.TEX) and face.image and len(face.v) in [3,4] and has_draped == want_draped: #print ' this is face, image is %s.\n' % face.image.filename if expobj.ispanelok: isregion=h.isRegion(face.image) if isregion: expobj.regions[face.image]=isregion if fileformat>7 and isregion: pass elif 'panel.' in face.image.name.lower() or isregion: if fileformat>7 and expobj.regions: raise ExportError('You can\'t use the panel texture since you\'ve used panel regions.\n\tI found a face using the panel texture in "%s"' % object.name, (object, mesh, [face])) if fileformat==7 and len(face.v)==3: raise ExportError('Only quads can use the instrument panel texture,\n\tbut I found a tri using the panel texture in "%s"' % object.name, (object, mesh, [face])) havepanel=True if not object in panelobjs: panelobjs.append(object) if panelerr: # Check that at least one panel texture is OK if isregion: #(n,xoff,yoff,width,height)=isregion panelerr=0 # Should check else: xoff=yoff=0 try: (width,height)=face.image.getSize() except RuntimeError: raise ExportError("Can't load instrument panel texture file") for uv in face.uv: if uv[0]<0.0 or uv[0]>1.0 or (1-uv[1])*height>768 or uv[1]>1.0: break else: panelerr=0 else: texture=checkdup(face.image.filename, thisdir, texture, texlist, multierr, object) else: texture=checkdup(face.image.filename, thisdir, texture, texlist, multierr, object) elif (expobj.iscockpit and objType == "Lamp" and object.getType() == Lamp.Types.Lamp): raise ExportError("Cockpit objects can't contain lights",[object]) if multierr: raise ExportError("The OBJ format supports one texture file, but you've used multiple texture files; see the Console for a list of the files", multierr) if fileformat>7 and havepanel and expobj.regions: raise ExportError("You can't use the panel texture since you've used panel regions.\n\tUse the panel texture, or panel regions, but not both", panelobjs) if havepanel and panelerr: raise ExportError("At least one face that uses the instrument panel texture must be within the top 768 lines of the panel texture") if not texture: return None # try: # img=Image.Load(texture) # (width,height)=img.getSize() # except: # raise ExportError("Can't load texture file \"%s\"" % texture) # if 2**int(log(width,2))!=width or 2**int(log(height,2))!=height: # raise ExportError("Texture file height and width must be powers of two.\n\tPlease resize the file. Use Image->Replace and fixup UV mapping\n\tto load the new file") l=texture.rfind(sep) if l!=-1: l=l+1 else: l=0 if texture[l:].find(' ')!=-1: raise ExportError('Texture filename "%s" contains spaces.\n\tPlease rename the file. Use Image->Replace to load the renamed file' % texture[l:]) if texture[-4:].lower() in ['.dds', '.png', '.bmp']: if fileformat==7: texture=texture[:-4] else: raise ExportError("Texture file must be in DDS, PNG or BMP format.\n\tPlease convert the file. Use Image->Replace to load the new file") # try to guess correct texture path if expobj.iscockpit: print "Info:\tUsing algorithms appropriate for a cockpit object." expobj.log.append(("Using algorithms appropriate for a cockpit object",[])) return basename(texture) # v7 or v7-compatibility mode for prefix in ["custom object textures", "autogen textures"]: l=texture.lower().rfind(prefix) if l!=-1: texture = texture[l+len(prefix)+1:].replace(sep,'/') return texture # texture is relative to .obj file - find common prefix a=Blender.Get('filename').split(sep) b=texture.split(sep) for i in range(min(len(a),len(b))): if a[i].lower()!=b[i].lower(): if i==0: break # it's hopeless c='' for l in range(i,len(a)-1): c+='../' for l in range(i,len(b)-1): c+=b[l]+'/' if ' ' in c: break # spaces not allowed if '/Custom Scenery' in c or '/Aircraft' in c or '/X-Plane' in c: break # Can't step out of scenery or aircraft package return c+basename(texture) # just return bare filename print "Warn:\tCan't guess path for texture file. Please edit the .obj file to fix." expobj.log.append(("Can't guess path for texture file. Please edit the .obj file to fix", [])) return basename(texture)
def writeObjects (self, theObjects): if self.layermask==1: lseq=[1] else: lseq=[1,2,4] h=PanelRegionHandler() # Count the objects nobj=0 objlen=1 for layer in lseq: for object in theObjects: if object.Layer&layer: objlen=objlen+1 if self.optimise: npasses=Face.BUCKET+1 else: npasses=1 objlen=objlen*(2+npasses) for layer in lseq: meshes=[] self.updateLayer(layer) # 1st pass: Build meshes for o in range (len(theObjects)-1,-1,-1): object=theObjects[o] if not object.Layer&layer or h.isHandlerObj(object): continue Window.DrawProgressBar(float(nobj)/objlen, "Exporting %s%% ..." % ( nobj*100/objlen)) nobj=nobj+1 objType=object.getType() if objType == "Mesh": if isLight(object): print 'Warn:\tIgnoring custom light "%s"' % object.name self.log.append(('Ignoring custom light "%s"' % object.name, [object])) elif not isLine(object, self.linewidth): meshes.append(self.sortMesh(object, layer)) elif objType == "Lamp": pass # Handled later elif objType == 'Empty': for prop in object.getAllProperties(): if prop.type in ['INT', 'FLOAT'] and prop.name.startswith('group '): self.file.write("\nATTR_layer_group\t%s\t%d\t//\n\n" % (prop.name[6:].strip(), int(prop.data))) #elif objType not in ['Camera','Lattice']: # print 'Warn:\tIgnoring %s "%s"' % (objType.lower(), object.name) # self.log.append(('Ignoring %s "%s"' % (objType.lower(), object.name), [object])) # Hack! Find a kosher panel texture and put it last if self.iscockpit: panelsorted=0 i=len(meshes)-1 while i>=0 and not panelsorted: if meshes[i].faces: for j in range(len(meshes[i].faces)): if meshes[i].faces[j].kosher: mesh=MyMesh(meshes[i].name) mesh.faces.append(meshes[i].faces[j]) meshes[i].faces[j]=0 # Remove original face meshes.append(mesh) panelsorted=1 break i=i-1 # 2nd to 2**n+1th pass: Output meshes for passno in range(npasses): strips=[] for i in range(len(meshes)): Window.DrawProgressBar(float(nobj)/objlen, "Exporting %s%% ..." % ( nobj*100/objlen)) nobj=nobj+1 if meshes[i]: self.makeStrips(strips, meshes[i], passno) for (strip, firstvertex, name) in strips: if len(strip)>1 and len(strip[0].v)==3: self.writeStrip(strip, firstvertex, name) for (strip, firstvertex, name) in strips: if len(strip)==1 and len(strip[0].v)==3: self.writeStrip(strip, firstvertex, name) for (strip, firstvertex, name) in strips: if len(strip)>1 and len(strip[0].v)==4: self.writeStrip(strip, firstvertex, name) for (strip, firstvertex, name) in strips: if len(strip)==1 and len(strip[0].v)==4: self.writeStrip(strip, firstvertex, name) # last pass: Output Lines and Lamps for o in range (len(theObjects)-1,-1,-1): object=theObjects[o] if not object.Layer&layer: continue Window.DrawProgressBar(float(nobj)/objlen, "Exporting %s%% ..." % ( nobj*100/objlen)) nobj=nobj+1 objType=object.getType() if objType == "Mesh" and isLine(object, self.linewidth): self.writeLine(object) elif objType == "Lamp": self.writeLamp(object) self.file.write("end\t\t\t// eof\n\n") self.file.write("// Built with Blender %4.2f. Exported with XPlane2Blender %s.\n" % (float(Blender.Get('version'))/100, self.version))
# # Copyright (c) 2007 Jonathan Harris # # This code is licensed under version 2 of the GNU General Public License. # http://www.gnu.org/licenses/gpl-2.0.html # # See ReadMe-XPlane2Blender.html for usage. # from Blender import Draw, Image, Window from math import log from XPlaneUtils import PanelRegionHandler image=Image.GetCurrent() # may be None h=PanelRegionHandler() opts=[] if not image: pass elif h.isRegion(image): opts.append('Delete this region%x1') opts.append('Reload all regions%x3') elif h.isPanel(image): if h.countRegions()<PanelRegionHandler.REGIONCOUNT: opts.append('Create new region...%x2') else: opts.append('Can\'t create new region - already using maximum of %d regions%%x0' % PanelRegionHandler.REGIONCOUNT) opts.append('Reload all regions%x3') elif image and 'panel.' in image.name.lower() and '.region' not in image.name.lower(): opts.append('Create new region...%x2')
def getTexture(expobj, theObjects, iscsl, fileformat, want_draped=0): texture = None multierr = [] panelerr = (fileformat == 7 and expobj.iscockpit) havepanel = False panelobjs = [] nobj = len(theObjects) texlist = [] layers = 0 if find_prop_list(theObjects, 'panel_ok') != None: expobj.ispanelok = True if iscsl: expobj.lod = [0, 1000, 4000, 100000] # list of lod limits else: expobj.lod = [0, 1000, 4000, 10000] # list of lod limits thisdir = normpath(dirname(Blender.Get('filename'))) h = PanelRegionHandler() lod_keys = [['lod_0', 0], ['lod_1', 1], ['lod_2', 2], ['lod_3', 3]] for l in lod_keys: src_o = find_prop_list(theObjects, l[0]) if src_o != None: layer = l[1] #print "object %s layer %d found LOD %s" % (object.name,layer,get_prop(object,l[0],0)) expobj.lod[layer] = float(get_prop(src_o, l[0], 0)) if layer < 3 and expobj.lod[layer + 1] <= expobj.lod[layer]: expobj.lod[layer + 1] = expobj.lod[layer] + 1 if expobj.layermask != 7: expobj.layermask = 7 #print "Info:\tMultiple Levels Of Detail found" expobj.log.append(("Multiple Levels Of Detail found", [])) for o in range(nobj - 1, -1, -1): object = theObjects[o] if h.isHandlerObj(object): continue objType = object.getType() if expobj.layermask == 1 and not expobj.iscockpit: if layers == 0: layers = object.Layer & 7 elif object.Layer & 7 and layers ^ (object.Layer & 7): expobj.layermask = 7 #print "Info:\tMultiple Levels Of Detail found" expobj.log.append(("Multiple Levels Of Detail found", [])) if not object.Layer & expobj.layermask: continue if objType == "Mesh": mesh = object.getData(mesh=True) if isLight(object): material = mesh.materials[0] mtex = material.getTextures()[0] if mtex: image = mtex.tex.image if image: texture = checkdup(image.filename, thisdir, texture, texlist, multierr, object) continue print 'Warn:\tIgnoring custom light "%s" with no texture' % object.name expobj.log.append( ('Ignoring custom light "%s" with no texture' % object.name, [object])) elif mesh.faceUV: #print '%s (%d)' % (object.getName(), len(mesh.faces)) for face in mesh.faces: has_draped = (face.mode & Mesh.FaceModes.TILES) and has_prop( object, 'ATTR_draped') if (face.mode & Mesh.FaceModes.TEX) and face.image and len( face.v) in [3, 4] and has_draped == want_draped: #print ' this is face, image is %s.\n' % face.image.filename if expobj.ispanelok: isregion = h.isRegion(face.image) if isregion: expobj.regions[face.image] = isregion if fileformat > 7 and isregion: pass elif 'panel.' in face.image.name.lower( ) or isregion: if fileformat > 7 and expobj.regions: raise ExportError( 'You can\'t use the panel texture since you\'ve used panel regions.\n\tI found a face using the panel texture in "%s"' % object.name, (object, mesh, [face])) if fileformat == 7 and len(face.v) == 3: raise ExportError( 'Only quads can use the instrument panel texture,\n\tbut I found a tri using the panel texture in "%s"' % object.name, (object, mesh, [face])) havepanel = True if not object in panelobjs: panelobjs.append(object) if panelerr: # Check that at least one panel texture is OK if isregion: #(n,xoff,yoff,width,height)=isregion panelerr = 0 # Should check else: xoff = yoff = 0 try: (width, height) = face.image.getSize() except RuntimeError: raise ExportError( "Can't load instrument panel texture file" ) for uv in face.uv: if uv[0] < 0.0 or uv[0] > 1.0 or ( 1 - uv[1] ) * height > 768 or uv[1] > 1.0: break else: panelerr = 0 else: texture = checkdup(face.image.filename, thisdir, texture, texlist, multierr, object) else: texture = checkdup(face.image.filename, thisdir, texture, texlist, multierr, object) elif (expobj.iscockpit and objType == "Lamp" and object.getType() == Lamp.Types.Lamp): raise ExportError("Cockpit objects can't contain lights", [object]) if multierr: raise ExportError( "The OBJ format supports one texture file, but you've used multiple texture files; see the Console for a list of the files", multierr) if fileformat > 7 and havepanel and expobj.regions: raise ExportError( "You can't use the panel texture since you've used panel regions.\n\tUse the panel texture, or panel regions, but not both", panelobjs) if havepanel and panelerr: raise ExportError( "At least one face that uses the instrument panel texture must be within the top 768 lines of the panel texture" ) if not texture: return None # try: # img=Image.Load(texture) # (width,height)=img.getSize() # except: # raise ExportError("Can't load texture file \"%s\"" % texture) # if 2**int(log(width,2))!=width or 2**int(log(height,2))!=height: # raise ExportError("Texture file height and width must be powers of two.\n\tPlease resize the file. Use Image->Replace and fixup UV mapping\n\tto load the new file") l = texture.rfind(sep) if l != -1: l = l + 1 else: l = 0 if texture[l:].find(' ') != -1: raise ExportError( 'Texture filename "%s" contains spaces.\n\tPlease rename the file. Use Image->Replace to load the renamed file' % texture[l:]) if texture[-4:].lower() in ['.dds', '.png', '.bmp']: if fileformat == 7: texture = texture[:-4] else: raise ExportError( "Texture file must be in DDS, PNG or BMP format.\n\tPlease convert the file. Use Image->Replace to load the new file" ) # try to guess correct texture path if expobj.iscockpit: print "Info:\tUsing algorithms appropriate for a cockpit object." expobj.log.append( ("Using algorithms appropriate for a cockpit object", [])) return basename(texture) # v7 or v7-compatibility mode for prefix in ["custom object textures", "autogen textures"]: l = texture.lower().rfind(prefix) if l != -1: texture = texture[l + len(prefix) + 1:].replace(sep, '/') return texture # texture is relative to .obj file - find common prefix a = Blender.Get('filename').split(sep) b = texture.split(sep) for i in range(min(len(a), len(b))): if a[i].lower() != b[i].lower(): if i == 0: break # it's hopeless c = '' for l in range(i, len(a) - 1): c += '../' for l in range(i, len(b) - 1): c += b[l] + '/' if ' ' in c: break # spaces not allowed if '/Custom Scenery' in c or '/Aircraft' in c or '/X-Plane' in c: break # Can't step out of scenery or aircraft package return c + basename(texture) # just return bare filename print "Warn:\tCan't guess path for texture file. Please edit the .obj file to fix." expobj.log.append( ("Can't guess path for texture file. Please edit the .obj file to fix", [])) return basename(texture)
def writeObjects(self, theObjects): if self.layermask == 1: lseq = [1] else: lseq = [1, 2, 4] h = PanelRegionHandler() # Count the objects nobj = 0 objlen = 1 for layer in lseq: for object in theObjects: if object.Layer & layer: objlen = objlen + 1 if self.optimise: npasses = Face.BUCKET + 1 else: npasses = 1 objlen = objlen * (2 + npasses) for layer in lseq: meshes = [] self.updateLayer(layer) # 1st pass: Build meshes for o in range(len(theObjects) - 1, -1, -1): object = theObjects[o] if not object.Layer & layer or h.isHandlerObj(object): continue Window.DrawProgressBar( float(nobj) / objlen, "Exporting %s%% ..." % (nobj * 100 / objlen)) nobj = nobj + 1 objType = object.getType() if objType == "Mesh": if isLight(object): print 'Warn:\tIgnoring custom light "%s"' % object.name self.log.append( ('Ignoring custom light "%s"' % object.name, [object])) elif not isLine(object, self.linewidth): meshes.append(self.sortMesh(object, layer)) elif objType == "Lamp": pass # Handled later elif objType == 'Empty': for prop in object.getAllProperties(): if prop.type in ['INT', 'FLOAT' ] and prop.name.startswith('group '): self.file.write( "\nATTR_layer_group\t%s\t%d\t//\n\n" % (prop.name[6:].strip(), int(prop.data))) #elif objType not in ['Camera','Lattice']: # print 'Warn:\tIgnoring %s "%s"' % (objType.lower(), object.name) # self.log.append(('Ignoring %s "%s"' % (objType.lower(), object.name), [object])) # Hack! Find a kosher panel texture and put it last if self.iscockpit: panelsorted = 0 i = len(meshes) - 1 while i >= 0 and not panelsorted: if meshes[i].faces: for j in range(len(meshes[i].faces)): if meshes[i].faces[j].kosher: mesh = MyMesh(meshes[i].name) mesh.faces.append(meshes[i].faces[j]) meshes[i].faces[j] = 0 # Remove original face meshes.append(mesh) panelsorted = 1 break i = i - 1 # 2nd to 2**n+1th pass: Output meshes for passno in range(npasses): strips = [] for i in range(len(meshes)): Window.DrawProgressBar( float(nobj) / objlen, "Exporting %s%% ..." % (nobj * 100 / objlen)) nobj = nobj + 1 if meshes[i]: self.makeStrips(strips, meshes[i], passno) for (strip, firstvertex, name) in strips: if len(strip) > 1 and len(strip[0].v) == 3: self.writeStrip(strip, firstvertex, name) for (strip, firstvertex, name) in strips: if len(strip) == 1 and len(strip[0].v) == 3: self.writeStrip(strip, firstvertex, name) for (strip, firstvertex, name) in strips: if len(strip) > 1 and len(strip[0].v) == 4: self.writeStrip(strip, firstvertex, name) for (strip, firstvertex, name) in strips: if len(strip) == 1 and len(strip[0].v) == 4: self.writeStrip(strip, firstvertex, name) # last pass: Output Lines and Lamps for o in range(len(theObjects) - 1, -1, -1): object = theObjects[o] if not object.Layer & layer: continue Window.DrawProgressBar( float(nobj) / objlen, "Exporting %s%% ..." % (nobj * 100 / objlen)) nobj = nobj + 1 objType = object.getType() if objType == "Mesh" and isLine(object, self.linewidth): self.writeLine(object) elif objType == "Lamp": self.writeLamp(object) self.file.write("end\t\t\t// eof\n\n") self.file.write( "// Built with Blender %4.2f. Exported with XPlane2Blender %s.\n" % (float(Blender.Get('version')) / 100, self.version))