You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

311 line
10 KiB

  1. #!/usr/bin/env python3
  2. # -*- Coding: UTF-8 -*-
  3. # ---------------------------------------------------------------------------
  4. # Open Asset Import Library (ASSIMP)
  5. # ---------------------------------------------------------------------------
  6. #
  7. # Copyright (c) 2006-2013, ASSIMP Development Team
  8. #
  9. # All rights reserved.
  10. #
  11. # Redistribution and use of this software in source and binary forms,
  12. # with or without modification, are permitted provided that the following
  13. # conditions are met:
  14. #
  15. # * Redistributions of source code must retain the above
  16. # copyright notice, this list of conditions and the
  17. # following disclaimer.
  18. #
  19. # * Redistributions in binary form must reproduce the above
  20. # copyright notice, this list of conditions and the
  21. # following disclaimer in the documentation and/or other
  22. # materials provided with the distribution.
  23. #
  24. # * Neither the name of the ASSIMP team, nor the names of its
  25. # contributors may be used to endorse or promote products
  26. # derived from this software without specific prior
  27. # written permission of the ASSIMP Development Team.
  28. #
  29. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  30. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  31. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  32. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  33. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  34. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  35. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  36. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  37. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  39. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40. # ---------------------------------------------------------------------------
  41. """Generate BlenderSceneGen.h and BlenderScene.cpp from the
  42. data structures in BlenderScene.h to map from *any* DNA to
  43. *our* DNA"""
  44. import sys
  45. import os
  46. import re
  47. inputfile = os.path.join("..","..","code","BlenderScene.h")
  48. outputfile_gen = os.path.join("..","..","code","BlenderSceneGen.h")
  49. outputfile_src = os.path.join("..","..","code","BlenderScene.cpp")
  50. template_gen = "BlenderSceneGen.h.template"
  51. template_src = "BlenderScene.cpp.template"
  52. # workaround for stackoverflowing when reading the linked list of scene objects
  53. # with the usual approach. See embedded notes for details.
  54. Structure_Convert_Base_fullcode = """
  55. template <> void Structure :: Convert<Base> (
  56. Base& dest,
  57. const FileDatabase& db
  58. ) const
  59. {
  60. // note: as per https://github.com/assimp/assimp/issues/128,
  61. // reading the Object linked list recursively is prone to stack overflow.
  62. // This structure converter is therefore an hand-written exception that
  63. // does it iteratively.
  64. const int initial_pos = db.reader->GetCurrentPos();
  65. std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
  66. Base* saved_prev = NULL;
  67. while(true) {
  68. Base& cur_dest = *todo.first;
  69. db.reader->SetCurrentPos(todo.second);
  70. // we know that this is a double-linked, circular list which we never
  71. // traverse backwards, so don't bother resolving the back links.
  72. cur_dest.prev = NULL;
  73. ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
  74. // just record the offset of the blob data and allocate storage.
  75. // Does _not_ invoke Convert() recursively.
  76. const int old = db.reader->GetCurrentPos();
  77. // the return value of ReadFieldPtr indicates whether the object
  78. // was already cached. In this case, we don't need to resolve
  79. // it again.
  80. if(!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next,"*next",db, true) && cur_dest.next) {
  81. todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
  82. continue;
  83. }
  84. break;
  85. }
  86. db.reader->SetCurrentPos(initial_pos + size);
  87. }
  88. """
  89. Structure_Convert_decl = """
  90. template <> void Structure :: Convert<{a}> (
  91. {a}& dest,
  92. const FileDatabase& db
  93. ) const
  94. """
  95. Structure_Convert_ptrdecl = """
  96. ReadFieldPtr<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);"""
  97. Structure_Convert_rawptrdecl = """
  98. {{
  99. boost::shared_ptr<{type}> {name_canonical};
  100. ReadFieldPtr<{policy}>({destcast}{name_canonical},"{name_dna}",db);
  101. dest.{name_canonical} = {name_canonical}.get();
  102. }}"""
  103. Structure_Convert_arraydecl = """
  104. ReadFieldArray<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);"""
  105. Structure_Convert_arraydecl2d = """
  106. ReadFieldArray2<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);"""
  107. Structure_Convert_normal = """
  108. ReadField<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);"""
  109. DNA_RegisterConverters_decl = """
  110. void DNA::RegisterConverters() """
  111. DNA_RegisterConverters_add = """
  112. converters["{a}"] = DNA::FactoryPair( &Structure::Allocate<{a}>, &Structure::Convert<{a}> );"""
  113. map_policy = {
  114. "" : "ErrorPolicy_Igno"
  115. ,"IGNO" : "ErrorPolicy_Igno"
  116. ,"WARN" : "ErrorPolicy_Warn"
  117. ,"FAIL" : "ErrorPolicy_Fail"
  118. }
  119. #
  120. def main():
  121. # -----------------------------------------------------------------------
  122. # Parse structure definitions from BlenderScene.h
  123. input = open(inputfile,"rt").read()
  124. #flags = re.ASCII|re.DOTALL|re.MULTILINE
  125. flags = re.DOTALL|re.MULTILINE
  126. #stripcoms = re.compile(r"/\*(.*?)*\/",flags)
  127. getstruct = re.compile(r"struct\s+(\w+?)\s*(:\s*ElemBase)?\s*\{(.*?)^\}\s*;",flags)
  128. getsmartx = re.compile(r"(std\s*::\s*)?(vector)\s*<\s*(boost\s*::\s*)?shared_(ptr)\s*<\s*(\w+)\s*>\s*>\s*",flags)
  129. getsmartp = re.compile(r"(boost\s*::\s*)?shared_(ptr)\s*<\s*(\w+)\s*>\s*",flags)
  130. getrawp = re.compile(r"(\w+)\s*\*\s*",flags)
  131. getsmarta = re.compile(r"(std\s*::\s*)?(vector)\s*<\s*(\w+)\s*>\s*",flags)
  132. getpolicy = re.compile(r"\s*(WARN|FAIL|IGNO)",flags)
  133. stripenum = re.compile(r"enum\s+(\w+)\s*{.*?\}\s*;",flags)
  134. assert getsmartx and getsmartp and getsmarta and getrawp and getpolicy and stripenum
  135. enums = set()
  136. #re.sub(stripcoms," ",input)
  137. #print(input)
  138. hits = {}
  139. while 1:
  140. match = re.search(getstruct,input)
  141. if match is None:
  142. break
  143. tmp = match.groups()[2]
  144. while 1:
  145. match2 = re.search(stripenum,tmp)
  146. if match2 is None:
  147. break
  148. tmp = tmp[match2.end():]
  149. enums.add(match2.groups()[0])
  150. hits[match.groups()[0]] = list(
  151. filter(lambda x:x[:2] != "//" and len(x),
  152. map(str.strip,
  153. re.sub(stripenum," ",match.groups()[2]).split(";")
  154. )))
  155. input = input[match.end():]
  156. for e in enums:
  157. print("Enum: "+e)
  158. for k,v in hits.items():
  159. out = []
  160. for line in v:
  161. policy = "IGNO"
  162. py = re.search(getpolicy,line)
  163. if not py is None:
  164. policy = py.groups()[0]
  165. line = re.sub(getpolicy,"",line)
  166. ty = re.match(getsmartx,line) or re.match(getsmartp,line) or\
  167. re.match(getsmarta,line) or re.match(getrawp,line)
  168. if ty is None:
  169. ty = line.split(None,1)[0]
  170. else:
  171. if len(ty.groups()) == 1:
  172. ty = ty.groups()[-1] + "$"
  173. elif ty.groups()[1] == "ptr":
  174. ty = ty.groups()[2] + "*"
  175. elif ty.groups()[1] == "vector":
  176. ty = ty.groups()[-1] + ("*" if len(ty.groups()) == 3 else "**")
  177. else:
  178. assert False
  179. #print(line)
  180. sp = line.split(',')
  181. out.append((ty,sp[0].split(None)[-1].strip(),policy))
  182. for m in sp[1:]:
  183. out.append((ty,m.strip(),policy))
  184. v[:] = out
  185. print("Structure {0}".format(k))
  186. for elem in out:
  187. print("\t"+"\t".join(elem))
  188. print("")
  189. output = open(outputfile_gen,"wt")
  190. templt = open(template_gen,"rt").read()
  191. s = ""
  192. # -----------------------------------------------------------------------
  193. # Structure::Convert<T> declarations for all supported structures
  194. for k,v in hits.items():
  195. s += Structure_Convert_decl.format(a=k)+";\n";
  196. output.write(templt.replace("<HERE>",s))
  197. output = open(outputfile_src,"wt")
  198. templt = open(template_src,"rt").read()
  199. s = ""
  200. # -----------------------------------------------------------------------
  201. # Structure::Convert<T> definitions for all supported structures
  202. for k,v in hits.items():
  203. s += "//" + "-"*80
  204. if k == 'Base':
  205. s += Structure_Convert_Base_fullcode
  206. continue
  207. s += Structure_Convert_decl.format(a=k)+ "{ \n";
  208. for type, name, policy in v:
  209. splits = name.split("[",1)
  210. name_canonical = splits[0]
  211. #array_part = "" if len(splits)==1 else "["+splits[1]
  212. is_raw_ptr = not not type.count("$")
  213. ptr_decl = "*"*(type.count("*") + (1 if is_raw_ptr else 0))
  214. name_dna = ptr_decl+name_canonical #+array_part
  215. #required = "false"
  216. policy = map_policy[policy]
  217. destcast = "(int&)" if type in enums else ""
  218. # POINTER
  219. if is_raw_ptr:
  220. type = type.replace('$','')
  221. s += Structure_Convert_rawptrdecl.format(**locals())
  222. elif ptr_decl:
  223. s += Structure_Convert_ptrdecl.format(**locals())
  224. # ARRAY MEMBER
  225. elif name.count('[')==1:
  226. s += Structure_Convert_arraydecl.format(**locals())
  227. elif name.count('[')==2:
  228. s += Structure_Convert_arraydecl2d.format(**locals())
  229. # NORMAL MEMBER
  230. else:
  231. s += Structure_Convert_normal.format(**locals())
  232. s += "\n\n\tdb.reader->IncPtr(size);\n}\n\n"
  233. # -----------------------------------------------------------------------
  234. # DNA::RegisterConverters - collect all available converter functions
  235. # in a std::map<name,converter_proc>
  236. #s += "#if 0\n"
  237. s += "//" + "-"*80 + DNA_RegisterConverters_decl + "{\n"
  238. for k,v in hits.items():
  239. s += DNA_RegisterConverters_add.format(a=k)
  240. s += "\n}\n"
  241. #s += "#endif\n"
  242. output.write(templt.replace("<HERE>",s))
  243. if __name__ == "__main__":
  244. sys.exit(main())