ExtractGeometry.py
1    ##############################################################################
2    #
3    # Extract geometry object from Poserfile.
4    #
5    # Should run with Python 2 and 3 (Poser 10/11/12)
6    # inside and outside of Poser.
7    ##############################################################################
8    
9    
10   # Python 2/3 compatibility --------------------
11   from __future__ import print_function
12   
13   import sys, os, re
14   import wx, gzip
15   from collections import deque
16   
17   if sys.version_info.major > 2:
18       basestring = str
19       map = lambda a, b: [a(_b) for _b in b]
20   
21   try:
22       INSIDEPOSER = True
23       import poser
24   
25   except ImportError:
26       INSIDEPOSER = False
27       app = wx.App()
28       # import POSER_FAKE as poser
29   
30   ##############################################################################
31   
32   globals().setdefault("DEFAULT_DIR", os.path.dirname(__file__))
33   
34   
35   class Filereader(object):
36       """ 
37       Base class to deal with Poser files. 
38       """
39   
40       readlinesearch = re.compile("[{}]").search  # Quick search for curly braces
41   
42       def __init__(self, fname):
43           self.fh = None
44           if not isinstance(fname, basestring):
45               raise ValueError("given parameter must be <str> (filename)")
46   
47           self.filesize = os.path.getsize(fname)
48   
49           if self.fh is None:
50               self.fh = gzip.open(fname) if self.is_zip(fname) else open(fname)
51   
52           self._linebuffer = deque()
53           self.indent = 0
54           self.filepos = 0
55           self.EOF = False
56           self.bufferSize = 64 * 1024
57   
58           assert hasattr(self.fh, "read") and \
59                  hasattr(self.fh, "seek"), \
60               "Something is wrong with this file: '%s'" % fname
61   
62 @staticmethod 63 def is_zip(fname): 64 """ 65 Returns True if <fname> is a zip-file, else False. 66 """ 67 with open(fname, "rb") as fh: 68 return fh.read(3) == chr(0x1f) + chr(0x8b) + chr(0x08) 69
70 def is_closed(self): 71 if callable(self.fh.closed): return self.fh.closed() 72 return self.fh.closed 73
74 def seek(self, pos): 75 assert pos <= self.filesize 76 self._linebuffer.clear() 77 self.fh.seek(pos) 78 self.EOF = False 79 self.filepos = pos 80
81 def readline(self): 82 """:rtype: str""" 83 if len(self._linebuffer) == 0: 84 newline = self.fh.readlines(self.bufferSize) 85 if len(newline) == 0: 86 self.EOF = True 87 return "" 88 self._linebuffer.extend(newline) 89 90 line = str(self._linebuffer.popleft()) 91 length = len(line) 92 self.filepos += length 93 94 s = self.readlinesearch(line) 95 if s: 96 idx = s.start() 97 c = line[idx] 98 if idx == 0: 99 s = line[idx + 1:] 100 self.filepos -= length - 1 101 self._linebuffer.appendleft(s) 102 self.indent += 1 if c == "{" else -1 103 return c 104 else: 105 l = line[idx:] 106 self.filepos -= length - idx 107 self._linebuffer.appendleft(l) 108 return line[:idx] 109 110 return line 111
112 def insertLine(self, line): 113 """:type line: str""" 114 assert isinstance(line, str) 115 self.indent -= line.count("{") 116 self.indent += line.count("}") 117 self._linebuffer.appendleft(line) 118 self.filepos -= len(line) 119 120
121 class Reader(Filereader): 122 def __init__(self, in_name, out_name): 123 super(self.__class__, self).__init__(in_name) 124 self.current_actortype = self.current_actorname = None 125 self.out_fh = open(out_name, "w") 126 print("Original file: ", in_name) 127 print("Modified file:", out_name) 128
129 def current_objname(self): 130 posername = "" 131 fname = self.current_actortype + "_" + self.current_actorname + ".obj" 132 if INSIDEPOSER: 133 user = os.environ.get("USERNAME") 134 path = os.path.join(poser.ContentRootLocation(), "Runtime", "Geometries", user) 135 posername = ":".join(["Runtime", "Geometries", user, fname]) 136 if not os.path.exists(path): 137 os.makedirs(path) 138 else: 139 path = os.path.dirname(self.fh.name) 140 141 return posername, os.path.join(path, fname) 142
143 def run(self): 144 while not self.EOF: 145 line = self.readline() 146 l = re.split(r"\s+", line.strip(), 2) # split line into max 2 parts if possible. 147 148 if self.indent == 1: 149 # All props/actors/figures are at indentation level one. 150 if l[0] in ("actor", "prop"): 151 # Save the last actor/prop name 152 self.current_actortype, self.current_actorname = l 153 154 elif self.indent == 2: 155 # Parameters of above props etc are on indent level 2. 156 if len(l) == 1 and l[0] == "geomCustom": 157 while self.indent == 2: # find start 158 self.readline() 159 160 poser_name, obj_name = self.current_objname() # get a name for this object 161 print("Exported obj:", obj_name) 162 163 with open(obj_name, "w") as obj: 164 t = "\t" * (self.indent - 2) 165 self.out_fh.write(t + "storageOffset 0 0.34870 0\n" + 166 t + "objFileGeom 0 0 " + poser_name or obj_name) 167 168 obj.write("# %s: %s\n#" % (self.current_actortype, self.current_actorname)) 169 while True: 170 # read the objects content 171 line = self.readline().strip() 172 l = re.split(r"\s+", line, 2) 173 if l[0] == "}": 174 break 175 elif l[0].startswith("numb"): 176 obj.write("# %s\n" % line) 177 else: 178 obj.write(line + "\n") 179 obj.write("\n") # make sure file ends with a linefeed 180 181 continue # don't write the last read line 182 183 self.out_fh.write(line) 184 185 self.fh.close() 186 187 188 if __name__ == "__main__": 189 with wx.FileDialog(None, "Select Poser File", 190 DEFAULT_DIR, style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as dialog: 191 if dialog.ShowModal() == wx.ID_OK: 192 fname = dialog.GetPath() 193 DEFAULT_DIR = os.path.dirname(fname) 194 f = fname.rsplit(".", 1) 195 newname = f[0] + "_NEW" + "." + f[-1] 196 reader = Reader(fname, newname) 197 reader.run() 198