Blender V2.61 - r43446
|
00001 # ##### BEGIN GPL LICENSE BLOCK ##### 00002 # 00003 # This program is free software; you can redistribute it and/or 00004 # modify it under the terms of the GNU General Public License 00005 # as published by the Free Software Foundation; either version 2 00006 # of the License, or (at your option) any later version. 00007 # 00008 # This program is distributed in the hope that it will be useful, 00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 # GNU General Public License for more details. 00012 # 00013 # You should have received a copy of the GNU General Public License 00014 # along with this program; if not, write to the Free Software Foundation, 00015 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00016 # 00017 # ##### END GPL LICENSE BLOCK ##### 00018 00019 # <pep8 compliant> 00020 00021 """ 00022 Experemental module (for developers only), exposes DNA data via python 00023 uses no blender/python modules, pure python + autogenerated ctypes api. 00024 00025 Exposes: 00026 * pydna.main: main database access. 00027 * pydna.types: a module of all DNA ctypes structures. 00028 00029 * Utility method: CAST(dna_type) 00030 * Utility method for ListBase: ITER(dna_type) 00031 00032 Example: 00033 import sys 00034 sys.path.append("/b/intern/tools") 00035 00036 import pydna 00037 00038 for obj in pydna.main.object.ITER("Object"): 00039 print("Object:", obj.id.name) 00040 if obj.data: 00041 data = pydna.types.ID.from_address(obj.data) 00042 print(" ObData:", data.name) 00043 """ 00044 00045 import ctypes 00046 import struct 00047 00048 00049 def _api(): 00050 00051 def is_ctypes_subclass(other, main_class): 00052 while other: 00053 if other is main_class: 00054 return True 00055 other = getattr(other, "_type_", None) 00056 return False 00057 00058 def is_ctypes_initialized(other): 00059 _other = other 00060 while other: 00061 if hasattr(other, "_fields_"): 00062 return True 00063 other = getattr(other, "_type_", None) 00064 print(_other, "NOT INIT") 00065 return False 00066 00067 def is_ctypes_base(other): 00068 while type(getattr(other, "_type_", "")) != str: 00069 other = other._type_ 00070 return other 00071 00072 class MixIn: 00073 pass 00074 00075 blend_cdll = ctypes.CDLL("") 00076 blend_lib = ctypes.LibraryLoader("") 00077 00078 def blend_parse_dna(): 00079 # from dna.c 00080 sdna_str_pt = blend_cdll.DNAstr 00081 sdna_len_pt = blend_cdll.DNAlen 00082 00083 # cast 00084 sdna_len_pt = ctypes.c_void_p.from_address(ctypes.addressof(sdna_len_pt)) 00085 sdna_len = ctypes.c_int.from_address(sdna_len_pt.value) 00086 00087 blend_sdna = ctypes.string_at(sdna_str_pt, sdna_len) 00088 00089 ofs = 0 00090 assert(blend_sdna[ofs:ofs + 8] == b'SDNANAME') 00091 ofs += 8 00092 00093 sdna_names_len = struct.unpack("i", blend_sdna[ofs:ofs + 4])[0] 00094 ofs += 4 00095 00096 blend_sdna_names = blend_sdna[ofs:].split(b'\0', sdna_names_len) 00097 blend_sdna_remainder = blend_sdna_names.pop(-1) # last item is not a name. 00098 ofs = len(blend_sdna) - len(blend_sdna_remainder) 00099 ofs = (ofs + 3) & ~3 00100 00101 assert(blend_sdna[ofs:ofs + 4] == b'TYPE') 00102 ofs += 4 00103 00104 sdna_types_len = struct.unpack("i", blend_sdna[ofs:ofs + 4])[0] 00105 ofs += 4 00106 00107 blend_sdna_types = blend_sdna[ofs:].split(b'\0', sdna_types_len) 00108 blend_sdna_remainder = blend_sdna_types.pop(-1) 00109 ofs = len(blend_sdna) - len(blend_sdna_remainder) 00110 ofs = (ofs + 3) & ~3 00111 00112 assert(blend_sdna[ofs:ofs + 4] == b'TLEN') 00113 ofs += 4 00114 00115 blend_sdna_typelens = struct.unpack("%dh" % sdna_types_len, blend_sdna[ofs:ofs + (sdna_types_len * 2)]) 00116 ofs += sdna_types_len * 2 00117 ofs = (ofs + 3) & ~3 00118 00119 # array of pointers to short arrays 00120 assert(blend_sdna[ofs:ofs + 4] == b'STRC') 00121 ofs += 4 00122 00123 sdna_structs_len = struct.unpack("i", blend_sdna[ofs:ofs + 4])[0] 00124 ofs += 4 00125 00126 blend_sdna_structs = [] 00127 00128 for i in range(sdna_structs_len): 00129 struct_type, struct_tot = struct.unpack("hh", blend_sdna[ofs:ofs + 4]) 00130 ofs += 4 00131 struct_type_name_pairs = struct.unpack("%dh" % struct_tot * 2, blend_sdna[ofs:ofs + (struct_tot * 4)]) 00132 00133 # convert into pairs, easier to understand (type, name) 00134 struct_type_name_pairs = [(struct_type_name_pairs[j], struct_type_name_pairs[j + 1]) for j in range(0, struct_tot * 2, 2)] 00135 00136 blend_sdna_structs.append((struct_type, struct_type_name_pairs)) 00137 ofs += struct_tot * 4 00138 # ofs = (ofs + 1) & ~1 00139 00140 return blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs 00141 00142 def create_dna_structs(blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs): 00143 00144 # create all subclasses of ctypes.Structure 00145 ctypes_structs = {name: type(name.decode(), (ctypes.Structure, MixIn), {}) for name in blend_sdna_types} 00146 ctypes_basic = {b"float": ctypes.c_float, b"double": ctypes.c_double, b"int": ctypes.c_int, b"short": ctypes.c_short, b"char": ctypes.c_char, b"void": ctypes.c_void_p} 00147 ctypes_fields = {} 00148 00149 # collect fields 00150 for struct_id, struct_type_name_pairs in blend_sdna_structs: 00151 struct_name = blend_sdna_types[struct_id] 00152 ctype_struct = ctypes_structs[struct_name] 00153 fields = [] 00154 00155 for stype, sname in struct_type_name_pairs: 00156 name_string = blend_sdna_names[sname] 00157 type_string = blend_sdna_types[stype] 00158 type_py = ctypes_basic.get(type_string) 00159 if type_py is None: 00160 type_py = ctypes_structs.get(type_string) 00161 00162 # todo, these might need to be changed 00163 name_string = name_string.replace(b"(", b"") 00164 name_string = name_string.replace(b")", b"") 00165 00166 # * First parse the pointer * 00167 pointer_count = 0 00168 while name_string[0] == 42: # '*' 00169 pointer_count += 1 00170 name_string = name_string[1:] 00171 00172 # alredy a pointer 00173 if type_py is ctypes.c_void_p: 00174 pointer_count -= 1 00175 elif type_py is ctypes.c_char and pointer_count == 1: 00176 type_py = ctypes.c_char_p 00177 pointer_count = 0 00178 00179 if pointer_count < 0: 00180 Exception("error parsing pointer") 00181 00182 for i in range(pointer_count): 00183 type_py = ctypes.POINTER(type_py) 00184 00185 # * Now parse the array [] * 00186 if b'[' in name_string: 00187 name_string = name_string.replace(b'[', b' ') 00188 name_string = name_string.replace(b']', b' ') 00189 name_split = name_string.split() 00190 name_string = name_split[0] 00191 for array_dim in reversed(name_split[1:]): 00192 type_py = type_py * int(array_dim) 00193 00194 fields.append((name_string.decode(), type_py)) 00195 00196 ctypes_fields[struct_name] = fields 00197 00198 # apply fields all in one go! 00199 for struct_id, struct_type_name_pairs in blend_sdna_structs: 00200 struct_name = blend_sdna_types[struct_id] 00201 ctype_struct = ctypes_structs[struct_name] 00202 try: 00203 ctype_struct._fields_ = ctypes_fields[struct_name] 00204 except: 00205 print("Error:", struct_name) 00206 import traceback 00207 traceback.print_exc() 00208 # print(fields) 00209 00210 # test fields 00211 for struct_id, struct_type_name_pairs in blend_sdna_structs: 00212 ctype_struct = ctypes_structs[blend_sdna_types[struct_id]] 00213 if blend_sdna_typelens[struct_id] != ctypes.sizeof(ctype_struct): 00214 print("Size Mismatch for %r blender:%d vs python:%d" % (blend_sdna_types[struct_id], blend_sdna_typelens[struct_id], ctypes.sizeof(ctype_struct))) 00215 00216 return ctypes_structs 00217 00218 def decorate_api(struct_dict): 00219 00220 # * Decotate the api * 00221 00222 # listbase iter 00223 00224 type_cast_lb = struct_dict[b'ListBase'] 00225 type_cast_link = struct_dict[b'Link'] 00226 00227 def list_base_iter(self, type_name): 00228 if type(type_name) == str: 00229 type_cast = struct_dict[type_name.encode('ASCII')] 00230 else: 00231 # allow passing types direcly 00232 type_cast = type_name 00233 00234 # empty listbase 00235 if self.first is None: 00236 ret = None 00237 else: 00238 try: 00239 ret = type_cast_link.from_address(ctypes.addressof(self.first)) 00240 except TypeError: 00241 ret = type_cast_link.from_address(self.first) 00242 00243 while ret is not None: 00244 return_value = type_cast.from_address(ctypes.addressof(ret)) 00245 try: 00246 next_pointer = getattr(ret.next, "contents") 00247 except: 00248 next_pointer = None 00249 00250 if next_pointer: 00251 ret = type_cast_link.from_address(ctypes.addressof(next_pointer)) 00252 else: 00253 ret = None 00254 00255 yield return_value 00256 00257 struct_dict[b'ListBase'].ITER = list_base_iter 00258 00259 def CAST(self, to): 00260 if type(to) == str: 00261 type_cast = struct_dict[to.encode('ASCII')] 00262 else: 00263 type_cast = to 00264 00265 return type_cast.from_address(ctypes.addressof(self)) 00266 00267 MixIn.CAST = CAST 00268 00269 blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs = blend_parse_dna() 00270 struct_dict = create_dna_structs(blend_sdna_names, blend_sdna_types, blend_sdna_typelens, blend_sdna_structs) 00271 00272 # print out all structs 00273 ''' 00274 for struct_id, struct_type_name_pairs in blend_sdna_structs: 00275 print("") 00276 sruct_name = blend_sdna_types[struct_id].decode() 00277 print("typedef struct %s {" % sruct_name) 00278 for stype, sname in struct_type_name_pairs: 00279 print(" %s %s;" % (blend_sdna_types[stype].decode(), blend_sdna_names[sname].decode())) 00280 print("} %s;" % sruct_name) 00281 ''' 00282 00283 decorate_api(struct_dict) # not essential but useful 00284 00285 # manually wrap Main 00286 Main = type("Main", (ctypes.Structure, ), {}) 00287 _lb = struct_dict[b"ListBase"] 00288 Main._fields_ = [("next", ctypes.POINTER(Main)), 00289 ("prev", ctypes.POINTER(Main)), 00290 ("name", ctypes.c_char * 240), 00291 ("versionfile", ctypes.c_short), 00292 ("subversionfile", ctypes.c_short), 00293 ("minversionfile", ctypes.c_short), 00294 ("minsubversionfile", ctypes.c_short), 00295 ("revision", ctypes.c_int), 00296 ("curlib", ctypes.POINTER(struct_dict[b"Library"])), 00297 ("scene", _lb), 00298 ("library", _lb), 00299 ("object", _lb), 00300 ("mesh", _lb), 00301 ("curve", _lb), 00302 ("mball", _lb), 00303 ("mat", _lb), 00304 ("tex", _lb), 00305 ("image", _lb), 00306 ("latt", _lb), 00307 ("lamp", _lb), 00308 ("camera", _lb), 00309 ("ipo", _lb), 00310 ("key", _lb), 00311 ("world", _lb), 00312 ("screen", _lb), 00313 ("script", _lb), 00314 ("vfont", _lb), 00315 ("text", _lb), 00316 ("sound", _lb), 00317 ("group", _lb), 00318 ("armature", _lb), 00319 ("action", _lb), 00320 ("nodetree", _lb), 00321 ("brush", _lb), 00322 ("particle", _lb), 00323 ("wm", _lb), 00324 ("gpencil", _lb), 00325 ] 00326 del _lb 00327 00328 # import bpy 00329 # main = Main.from_address(bpy.data.as_pointer()) 00330 # main is the first pointer in Global. 00331 main_address = ctypes.POINTER(ctypes.c_void_p).from_address(ctypes.addressof(blend_cdll.G)).contents.value 00332 main = Main.from_address(main_address) 00333 00334 return main, struct_dict 00335 00336 main, _struct_dict = _api() 00337 00338 # types dict 00339 types = type(ctypes)("pydna.types") 00340 types.__dict__.update({s.__name__: s for s in _struct_dict.values()})