From 3cad0f978b479c522637a5d9f08ef86938815a05 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 3 Sep 2012 13:35:18 +0900 Subject: [PATCH] Revamp entity class loading for blender integration. Slightly cleaner EntityClass building, and now the directory scanner is part of the EntityClassDict class, which also supports reading/writing plists (for persistent storage in blender). --- tools/io_qfmap/entityclass.py | 153 +++++++++++++++++++++++----------- 1 file changed, 104 insertions(+), 49 deletions(-) diff --git a/tools/io_qfmap/entityclass.py b/tools/io_qfmap/entityclass.py index 9f61dbedd..0d9ccd707 100644 --- a/tools/io_qfmap/entityclass.py +++ b/tools/io_qfmap/entityclass.py @@ -1,20 +1,60 @@ # vim:ts=4:et + +import os from .script import Script +from .qfplist import pldata MAX_FLAGS = 8 class EntityClass: - def __init__(self, text, filename, line = 0): + def __init__(self, name, color, size, flagnames, comment): + self.name = name + self.color = color + self.size = size + self.flagnames = flagnames + self.comment = comment + @classmethod + def from_quaked(cls, text, filename, line = 0): script = Script(filename, text) if line: script.line = line script.getToken() # skip over the leading '/*QUAKED' - self.name = script.getToken() - self.color = self.parse_vector(script) - self.size = self.parse_size(script) - self.flagnames = self.parse_flags(script) - self.comment = self.extract_comment(script) - def parse_vector(self, script): + name = script.getToken() + color = cls.parse_vector(script) + size = cls.parse_size(script) + flagnames = cls.parse_flags(script) + comment = cls.extract_comment(script) + return cls(name, color, size, flagnames, comment) + @classmethod + def from_dictionary(cls, name, d): + if "color" in d: + color = d["color"] + color = float(color[0]), float(color[1]), float(color[2]) + else: + color = (0.0, 0.0, 0.0) + if "size" in d: + mins, maxs = d["size"] + size = ((float(mins[0]), float(mins[1]), float(mins[2])), + (float(maxs[0]), float(maxs[1]), float(maxs[2]))) + else: + size = None + if "flagnames" in d: + flagnames = list(d["flagnames"]) + else: + flagnames = [] + if "comment" in d: + comment = d["comment"] + else: + comment = "" + return cls(name, color, size, flagnames, comment) + def to_dictionary(self): + d = {"color":self.color, "flagnames":self.flagnames, + "comment":self.comment} + if self.size: + d["size"] = self.size + return d + @classmethod + def parse_vector(cls, script): if script.getToken() != "(": raise SyntaxError v = (float(script.getToken()), float(script.getToken()), @@ -22,12 +62,14 @@ class EntityClass: if script.getToken() != ")": raise SyntaxError return v - def parse_size(self, script): + @classmethod + def parse_size(cls, script): if script.getToken() == "?": return None # use brush size script.ungetToken() - return self.parse_vector(script), self.parse_vector(script) - def parse_flags(self, script): + return cls.parse_vector(script), cls.parse_vector(script) + @classmethod + def parse_flags(cls, script): flagnames = [] while script.tokenAvailable(): #any remaining words on the line are flag names, but only MAX_FLAGS @@ -36,7 +78,8 @@ class EntityClass: if len(flagnames) < MAX_FLAGS: flagnames.append(script.token) return tuple(flagnames) - def extract_comment(selk, script): + @classmethod + def extract_comment(cls, script): if not script.tokenAvailable(True): return "" start = pos = script.pos @@ -50,44 +93,56 @@ class EntityClass: script.pos = pos return comment -import os - -def scan_source(fname, entity_classes): - text = open(fname, "rt").read() - line = 1 - pos = 0 - while pos < len(text): - if text[pos:pos + 8] == "/*QUAKED": - start = pos - start_line = line - while pos < len(text) and text[pos:pos + 2] != "*/": +class EntityClassDict: + def __init__(self): + self.path = "" + self.entity_classes = {} + def scan_source(self, fname): + text = open(fname, "rt").read() + line = 1 + pos = 0 + while pos < len(text): + if text[pos:pos + 8] == "/*QUAKED": + start = pos + start_line = line + while pos < len(text) and text[pos:pos + 2] != "*/": + if text[pos] == "\n": + line += 1 + pos += 1 + if pos < len(text): + pos += 2 + ec = EntityClass.from_quaked(text[start:pos], fname, + start_line) + self.entity_classes[ec.name] = ec + print(ec.name) + else: if text[pos] == "\n": line += 1 pos += 1 - if pos < len(text): - pos += 2 - ec = EntityClass(text[start:pos], fname, start_line) - entity_classes[ec.name] = ec - print(ec.name) - else: - if text[pos] == "\n": - line += 1 - pos += 1 - -def scan_directory(path, entity_classes): - files = os.listdir(path) - files.sort() - - for f in files: - if f[0] in [".", "_"]: - continue - if os.path.isdir(os.path.join(path, f)): - scan_directory(os.path.join(path, f), entity_classes) - else: - if f[-3:] == ".qc": - scan_source(os.path.join(path, f), entity_classes) - -def build_entityclasses(path): - entity_classes = {} - scan_directory(path, entity_classes) - return entity_classes + def scan_directory(self, path): + files = os.listdir(path) + files.sort() + for f in files: + if f[0] in [".", "_"]: + continue + if os.path.isdir(os.path.join(path, f)): + self.scan_directory(os.path.join(path, f)) + else: + if f[-3:] == ".qc": + self.scan_source(os.path.join(path, f)) + def from_source_tree(self, path): + self.path = path + self.entity_classes = {} + self.scan_directory(self.path) + def to_plist(self): + pl = pldata() + ec = {} + for k in self.entity_classes.keys(): + ec[k] = self.entity_classes[k].to_dictionary() + return pl.write(ec) + def from_plist(self, plist): + pl = pldata(plist) + ec = pl.parse() + self.entity_classes = {} + for k in ec.keys(): + self.entity_classes[k] = EntityClass.from_dictionary(k, ec[k])