completely overhauled models framework... now loads Model, Mesh, Material, and Texture (plus TextureFile) fixed a number of bugs/inflexibilities in gamedata xml parser refactored the various modules to use "init" functions to better control when they get loaded (ie, before or after OpenGL init) which it turns out is *very important*, because if the shaders and textures get loaded before OpenGL does, they don't work. go figure.
276 lines
7.2 KiB
Python
Executable file
276 lines
7.2 KiB
Python
Executable file
import glob
|
|
import os
|
|
try:
|
|
from xml.etree.cElementTree import parse
|
|
except ImportError:
|
|
from elementtree.ElementTree import parse
|
|
import files
|
|
import shader
|
|
from deprecate import deprecated
|
|
|
|
class MissingNode(object):
|
|
def __init__(self):
|
|
self.text = None
|
|
def get(self, name):
|
|
return None
|
|
|
|
class GameDataTagDef(object):
|
|
def __init__(self):
|
|
self.multi = False
|
|
self.opt = False
|
|
self.type = None
|
|
self.default = None
|
|
|
|
class GameDataNode(object):
|
|
def __init__(self):
|
|
self.dict = {}
|
|
self.missing = False
|
|
|
|
def __setitem__(self, name, val):
|
|
self.dict[name] = val
|
|
def __getitem__(self, name):
|
|
return self.dict[name]._value
|
|
def __getattr__(self, name):
|
|
if name == 'dict':
|
|
raise AttributeError, name
|
|
try:
|
|
return self.dict[name]
|
|
except KeyError:
|
|
if name == '_value':
|
|
return None
|
|
raise AttributeError, name
|
|
def __setattr__(self, name, val):
|
|
if name == 'dict':
|
|
return object.__setattr__(self, name, val)
|
|
try:
|
|
self.dict[name] = val
|
|
except KeyError:
|
|
object.__setattr__(self, name, val)
|
|
def add_multi(self, key, value):
|
|
if not self.dict.has_key(key):
|
|
self.dict[key] = []
|
|
self.dict[key].append(value)
|
|
def add_single(self, key, value):
|
|
self.dict[key] = value
|
|
def __repr__(self):
|
|
return """<GameDataNode "%s">""" % (self.dict['_name'],)
|
|
def has_key(self, key):
|
|
return self.dict.has_key(key)
|
|
|
|
class XMLGameDataReader(object):
|
|
def __init__(self, bin, xml):
|
|
self._bin = bin
|
|
self._xml = xml
|
|
self._tree = self.construct()
|
|
self._name = xml.tag
|
|
|
|
|
|
def value_as_type(self, value, type):
|
|
if type == 'string':
|
|
return value
|
|
elif type == 'bool':
|
|
if value and value[0].lower() in ('y', 't', '1'):
|
|
return True
|
|
else:
|
|
return False
|
|
elif type == 'int':
|
|
return int(value)
|
|
elif type == 'float':
|
|
return float(value)
|
|
elif type == 'csvarray':
|
|
# csvarrays are always ints...
|
|
return [int(x.strip()) for x in value.split(',')]
|
|
else:
|
|
raise TypeError, type
|
|
|
|
def create_datatag_def(self, tag):
|
|
d = GameDataTagDef()
|
|
if tag.get('multiple') != None and tag.get('multiple')[0].lower() == 'y':
|
|
d.multi = True
|
|
if tag.get('optional') != None and tag.get('optional')[0].lower() == 'y':
|
|
d.opt = True
|
|
if tag.get('data') != None:
|
|
d.type = tag.get('data')
|
|
if tag.get('default') != None:
|
|
d.default = self.value_as_type(tag.get('default'), d.type)
|
|
d.opt = True
|
|
return d
|
|
|
|
def create_attribute_def(self, tag):
|
|
return self.create_datatag_def(tag)
|
|
|
|
def construct_node(self, bin, xml, allow_missing=False):
|
|
node = GameDataNode()
|
|
if isinstance(xml, MissingNode):
|
|
node.missing = True
|
|
value = None
|
|
if bin.tag == 'datatag':
|
|
df = self.create_datatag_def(bin)
|
|
if df.type:
|
|
value = xml.text
|
|
if df.type == 'bool':
|
|
# if tag exists, since it is a bool, that means it's True
|
|
value = not node.missing
|
|
elif (node.missing or value == None) and df.opt:
|
|
value = df.default
|
|
elif (node.missing or value == None) and not allow_missing:
|
|
raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),)
|
|
elif (node.missing or value == None):
|
|
value = None
|
|
else:
|
|
value = self.value_as_type(value, df.type)
|
|
|
|
node['_value'] = value
|
|
elif bin.tag == 'attribute':
|
|
df = self.create_attribute_def(bin)
|
|
if df.type:
|
|
value = xml.get(bin.get('name'))
|
|
if value == None and df.opt:
|
|
value = df.default
|
|
elif not value and not allow_missing:
|
|
raise ValueError, "Missing value for mandatory tag %s" % (bin.get('name'),)
|
|
elif not value:
|
|
value = None
|
|
else:
|
|
value = self.value_as_type(value, df.type)
|
|
|
|
node['_value'] = value
|
|
|
|
node['_def'] = df
|
|
node['_name'] = bin.get('name')
|
|
return node
|
|
|
|
|
|
def construct_recurse(self, bin, xml, allow_missing=False):
|
|
xmldict = {}
|
|
tagdict = {}
|
|
attrdict = {}
|
|
|
|
if bin.tag == 'xml_binary_packing':
|
|
node = GameDataNode()
|
|
else:
|
|
node = self.construct_node(bin, xml, allow_missing)
|
|
|
|
for child in bin.getchildren():
|
|
if child.tag == 'datatag':
|
|
tagdict[child.get('name')] = child
|
|
elif child.tag == 'attribute':
|
|
attrdict[child.get('name')] = child
|
|
else:
|
|
raise ValueError
|
|
|
|
xmlattrdict = {}
|
|
xmltagdict = {}
|
|
|
|
if not isinstance(xml, MissingNode):
|
|
for k, v in xml.items():
|
|
if not k in attrdict:
|
|
raise ValueError, "Key %s not a valid attribute: %s" % (k, attrdict.keys())
|
|
continue
|
|
binchild = attrdict[k]
|
|
xmlchild = xml
|
|
xmlattrdict[k] = 0
|
|
subnode = self.construct_node(binchild, xml, allow_missing)
|
|
if subnode._def.multi:
|
|
node.add_multi(k, subnode)
|
|
else:
|
|
node.add_single(k, subnode)
|
|
|
|
for child in xml.getchildren():
|
|
if not child.tag in tagdict:
|
|
raise ValueError
|
|
continue
|
|
binchild = tagdict[child.tag]
|
|
xmlchild = child
|
|
xmltagdict[child.tag] = 0
|
|
subnode = self.construct_recurse(binchild, xmlchild, allow_missing)
|
|
if subnode._def.multi:
|
|
node.add_multi(child.tag, subnode)
|
|
else:
|
|
node.add_single(child.tag, subnode)
|
|
|
|
|
|
missing = MissingNode()
|
|
for k in tagdict.keys():
|
|
if not k in xmltagdict:
|
|
# Missing datatag
|
|
subnode = self.construct_recurse(tagdict[k], missing, isinstance(xml, MissingNode))
|
|
if not subnode._def.multi:
|
|
node.add_single(k, subnode)
|
|
else:
|
|
node.add_single(k, [])
|
|
|
|
for k in attrdict.keys():
|
|
if not k in xmlattrdict:
|
|
# Missing attribute
|
|
subnode = self.construct_node(attrdict[k], missing, isinstance(xml, MissingNode))
|
|
if not subnode._def.multi:
|
|
node.add_single(k, subnode)
|
|
else:
|
|
node.add_single(k, [])
|
|
|
|
|
|
|
|
return node
|
|
|
|
def construct(self):
|
|
rootname = self._bin.get('name')
|
|
assert rootname == self._xml.tag
|
|
|
|
return self.construct_recurse(self._bin, self._xml)
|
|
|
|
def __getattr__(self, name):
|
|
if name == 'tree':
|
|
raise AttributeError, name
|
|
return self._tree.__getattr__(name)
|
|
def __getitem__(self, name):
|
|
return self._tree.__getitem__(name)
|
|
|
|
|
|
def load_xml_files(binfile, xmlfile):
|
|
bintree = parse(binfile).getroot()
|
|
xmltree = parse(xmlfile).getroot()
|
|
|
|
return XMLGameDataReader(bintree, xmltree)
|
|
|
|
def get(dataname):
|
|
if dataname in get.cache:
|
|
return get.cache[dataname]
|
|
|
|
bin = files.mgr.path("xml/def", "%s.xml" % (dataname,))
|
|
xml = files.mgr.path("xml", "%s.xml" % (dataname,))
|
|
|
|
if not os.path.exists(bin) or not os.path.exists(xml):
|
|
raise OSError("XML data file does not exist")
|
|
|
|
dataobj = load_xml_files(bin, xml)
|
|
|
|
get.cache[dataname] = dataobj
|
|
return dataobj
|
|
|
|
get.cache = {}
|
|
|
|
@deprecated
|
|
def load_gamedata():
|
|
bins = glob.glob(files.mgr.path("xml/def", "*.xml"))
|
|
xmls = glob.glob(files.mgr.path("xml", "*.xml"))
|
|
|
|
binfns = [os.path.split(x)[1] for x in bins]
|
|
xmlfns = [os.path.split(x)[1] for x in xmls]
|
|
ffns = []
|
|
for bfn in binfns:
|
|
if bfn in xmlfns:
|
|
ffns.append(bfn)
|
|
|
|
dataobjs = {}
|
|
for fn in ffns:
|
|
binfile = files.mgr.path("xml/def", fn)
|
|
xmlfile = files.mgr.path("xml", fn)
|
|
dataobj = load_xml_files(binfile, xmlfile)
|
|
dataobjs[dataobj._name] = dataobj
|
|
|
|
shader.mgr.load_shaders(dataobjs['shaders'])
|
|
return dataobjs
|
|
|
|
|
|
|