bam files

This commit is contained in:
David Rose 2009-08-07 18:33:11 +00:00
parent e0a4fcda2d
commit 5bb225ab1f

View File

@ -8,6 +8,7 @@ import os
import glob import glob
import marshal import marshal
import new import new
from direct.showbase import Loader
from direct.showutil import FreezeTool from direct.showutil import FreezeTool
from direct.directnotify.DirectNotifyGlobal import * from direct.directnotify.DirectNotifyGlobal import *
from pandac.PandaModules import * from pandac.PandaModules import *
@ -31,10 +32,13 @@ class Packager:
self.deleteTemp = deleteTemp self.deleteTemp = deleteTemp
class Package: class Package:
def __init__(self, packageName): def __init__(self, packageName, packager):
self.packageName = packageName self.packageName = packageName
self.packager = packager
self.version = 'dev' self.version = 'dev'
self.files = [] self.files = []
self.compressionLevel = 0
self.importedMapsDir = 'imported_maps'
# This records the current list of modules we have added so # This records the current list of modules we have added so
# far. # far.
@ -52,31 +56,58 @@ class Packager:
except OSError: except OSError:
pass pass
multifile = Multifile() self.multifile = Multifile()
multifile.openReadWrite(packageFilename) self.multifile.openReadWrite(packageFilename)
sourceFilename = {} # Build up a cross-reference of files we've already
targetFilename = {} # discovered.
self.sourceFilenames = {}
self.targetFilenames = {}
for file in self.files: for file in self.files:
if not file.newName: if not file.newName:
file.newName = file.filename file.newName = file.filename
sourceFilename[file.filename] = file
targetFilename[file.newName] = file # Convert the source filename to an unambiguous
# filename for searching.
filename = Filename(file.filename)
filename.makeCanonical()
self.sourceFilenames[filename] = file
self.targetFilenames[file.newName] = file
for file in self.files: for file in self.files:
ext = file.filename.getExtension() ext = file.filename.getExtension()
if ext == 'py': if ext == 'py':
self.addPyFile(file) self.addPyFile(file)
else: else:
# An ordinary file. if ext == 'pz':
multifile.addSubfile(file.newName, file.filename, 0) # Strip off an implicit .pz extension.
filename = Filename(file.filename)
filename.setExtension('')
filename = Filename(filename.cStr())
ext = filename.getExtension()
filename = Filename(file.newName)
if filename.getExtension() == 'pz':
filename.setExtension('')
file.newName = filename.cStr()
if ext == 'egg':
self.addEggFile(file)
elif ext == 'bam':
self.addBamFile(file)
elif ext in self.packager.imageExtensions:
self.addTexture(file)
else:
# An ordinary file.
self.multifile.addSubfile(file.newName, file.filename, self.compressionLevel)
# Pick up any unfrozen Python files. # Pick up any unfrozen Python files.
self.freezer.done() self.freezer.done()
self.freezer.addToMultifile(multifile) self.freezer.addToMultifile(self.multifile)
multifile.repack() self.multifile.repack()
multifile.close() self.multifile.close()
# Now that all the files have been packed, we can delete # Now that all the files have been packed, we can delete
# the temporary files. # the temporary files.
@ -106,6 +137,122 @@ class Packager:
self.freezer.addModule(moduleName, newName = moduleName, self.freezer.addModule(moduleName, newName = moduleName,
filename = file.filename) filename = file.filename)
def addEggFile(self, file):
# Precompile egg files to bam's.
np = self.packager.loader.loadModel(file.filename, okMissing = True)
if not np:
raise StandardError, 'Could not read egg file %s' % (file.filename)
bamName = Filename(file.newName)
bamName.setExtension('bam')
self.addNode(np.node(), bamName.cStr())
def addBamFile(self, file):
# Load the bam file so we can massage its textures.
bamFile = BamFile()
if not bamFile.openRead(file.filename):
raise StandardError, 'Could not read bam file %s' % (file.filename)
if not bamFile.resolve():
raise StandardError, 'Could not resolve bam file %s' % (file.filename)
node = bamFile.readNode()
if not node:
raise StandardError, 'Not a model file: %s' % (file.filename)
self.addNode(node, file.newName)
def addNode(self, node, filename):
""" Converts the indicated node to a bam stream, and adds the
bam file to the multifile under the indicated filename. """
# If the Multifile already has a file by this name, don't
# bother adding it again.
if self.multifile.findSubfile(filename) >= 0:
return
# Be sure to import all of the referenced textures, and tell
# them their new location within the multifile.
for tex in NodePath(node).findAllTextures():
if not tex.hasFullpath() and tex.hasRamImage():
# We need to store this texture as a raw-data image.
# Clear the filename so this will happen
# automatically.
tex.clearFilename()
tex.clearAlphaFilename()
else:
# We can store this texture as a file reference to its
# image. Copy the file into our multifile, and rename
# its reference in the texture.
if tex.hasFilename():
tex.setFilename(self.addFoundTexture(tex.getFullpath()))
if tex.hasAlphaFilename():
tex.setAlphaFilename(self.addFoundTexture(tex.getAlphaFullpath()))
# Now generate an in-memory bam file. Tell the bam writer to
# keep the textures referenced by their in-multifile path.
bamFile = BamFile()
stream = StringStream()
bamFile.openWrite(stream)
bamFile.getWriter().setFileTextureMode(bamFile.BTMUnchanged)
bamFile.writeObject(node)
bamFile.close()
# Clean the node out of memory.
node.removeAllChildren()
# Now we have an in-memory bam file.
stream.seekg(0)
self.multifile.addSubfile(filename, stream, self.compressionLevel)
# Flush it so the data gets written to disk immediately, so we
# don't have to keep it around in ram.
self.multifile.flush()
def addFoundTexture(self, filename):
""" Adds the newly-discovered texture to the output, if it has
not already been included. Returns the new name within the
package tree. """
assert not filename.isLocal()
filename = Filename(filename)
filename.makeCanonical()
file = self.sourceFilenames.get(filename, None)
if file:
# Never mind, it's already on the list.
return file.newName
# We have to copy the image into the plugin tree somewhere.
newName = self.importedMapsDir + '/' + filename.getBasename()
uniqueId = 0
while newName in self.targetFilenames:
uniqueId += 1
newName = '%s/%s_%s.%s' % (
self.importedMapsDir, filename.getBasenameWoExtension(),
uniqueId, filename.getExtension())
file = Packager.PackFile(filename, newName = newName)
self.sourceFilenames[filename] = file
self.targetFilenames[newName] = file
self.addTexture(file)
return newName
def addTexture(self, file):
""" Adds a texture image to the output. """
if self.multifile.findSubfile(file.newName) >= 0:
# Already have this texture.
return
# Texture file formats are generally already compressed and
# not further compressible.
self.multifile.addSubfile(file.newName, file.filename, 0)
def __init__(self): def __init__(self):
# The following are config settings that the caller may adjust # The following are config settings that the caller may adjust
@ -141,6 +288,17 @@ class Packager:
# are server-side only and should be ignored by the Scrubber. # are server-side only and should be ignored by the Scrubber.
self.dcClientSuffixes = ['OV'] self.dcClientSuffixes = ['OV']
# Get the list of filename extensions that are recognized as
# image files.
self.imageExtensions = []
for type in PNMFileTypeRegistry.getGlobalPtr().getTypes():
self.imageExtensions += type.getExtensions()
# A Loader for loading models.
self.loader = Loader.Loader(self)
self.sfxManagerList = None
self.musicManager = None
def setup(self): def setup(self):
""" Call this method to initialize the class after filling in """ Call this method to initialize the class after filling in
some of the values in the constructor. """ some of the values in the constructor. """
@ -337,7 +495,7 @@ class Packager:
basename of the package. Follow this with a number of calls basename of the package. Follow this with a number of calls
to file() etc., and close the package with endPackage(). """ to file() etc., and close the package with endPackage(). """
package = self.Package(packageName) package = self.Package(packageName, self)
if self.currentPackage: if self.currentPackage:
package.freezer.excludeFrom(self.currentPackage.freezer) package.freezer.excludeFrom(self.currentPackage.freezer)