scene.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import os
  2. from .. import constants
  3. from . import (
  4. base_classes,
  5. image,
  6. texture,
  7. material,
  8. geometry,
  9. exceptions,
  10. object,
  11. logger,
  12. io,
  13. api
  14. )
  15. class Scene(base_classes.BaseScene):
  16. _defaults = {
  17. constants.METADATA: constants.DEFAULT_METADATA.copy(),
  18. constants.GEOMETRIES: [],
  19. constants.MATERIALS: [],
  20. constants.IMAGES: [],
  21. constants.TEXTURES: []
  22. }
  23. def __init__(self, filepath, options=None):
  24. logger.debug('Scene().__init__(%s, %s)', filepath, options)
  25. base_classes.BaseScene.__init__(self, filepath, options or {})
  26. source_file = api.scene_name()
  27. if source_file:
  28. self[constants.METADATA][constants.SOURCE_FILE] = source_file
  29. @property
  30. def valid_types(self):
  31. valid_types = [api.constants.MESH]
  32. if self.options.get(constants.CAMERAS):
  33. logger.info('Adding cameras to valid object types')
  34. valid_types.append(api.constants.CAMERA)
  35. if self.options.get(constants.LIGHTS):
  36. logger.info('Adding lights to valid object types')
  37. valid_types.append(api.constants.LAMP)
  38. return valid_types
  39. def geometry(self, arg):
  40. logger.debug('Scene().geometry(%s)', arg)
  41. return self._find_node(arg, self[constants.GEOMETRIES])
  42. def image(self, arg):
  43. logger.debug('Scene().image%s)', arg)
  44. return self._find_node(arg, self[constants.IMAGES])
  45. def material(self, arg):
  46. logger.debug('Scene().material(%s)', arg)
  47. return self._find_node(arg, self[constants.MATERIALS])
  48. def parse(self):
  49. logger.debug('Scene().parse()')
  50. if self.options.get(constants.MAPS):
  51. self.__parse_textures()
  52. if self.options.get(constants.MATERIALS):
  53. self.__parse_materials()
  54. self.__parse_geometries()
  55. self.__parse_objects()
  56. def texture(self, arg):
  57. logger.debug('Scene().texture(%s)', arg)
  58. return self._find_node(arg, self[constants.TEXTURES])
  59. def write(self):
  60. logger.debug('Scene().write()')
  61. data = {}
  62. embed_anim = self.options.get(constants.EMBED_ANIMATION, True)
  63. embed = self.options[constants.EMBED_GEOMETRY]
  64. compression = self.options.get(constants.COMPRESSION)
  65. extension = constants.EXTENSIONS.get(compression,
  66. constants.EXTENSIONS[constants.JSON])
  67. #@TODO: test this new logic
  68. export_dir = os.path.dirname(self.filepath)
  69. for key, value in self.items():
  70. if key == constants.GEOMETRIES:
  71. geometries = []
  72. for geometry in value:
  73. if not embed_anim:
  74. geometry.write_animation(export_dir)
  75. if embed:
  76. for each in value:
  77. geometries.append(each.copy())
  78. continue
  79. geom_data = geometry.copy()
  80. geo_type = geom_data[constants.TYPE].lower()
  81. if geo_type == constants.GEOMETRY.lower():
  82. geom_data.pop(constants.DATA)
  83. elif geo_type == constants.BUFFER_GEOMETRY.lower():
  84. geom_data.pop(constants.ATTRIBUTES)
  85. geom_data.pop(constants.METADATA)
  86. url = 'geometry.%s%s' % (geometry.node, extension)
  87. geometry_file = os.path.join(export_dir, url)
  88. geometry.write(filepath=geometry_file)
  89. geom_data[constants.URL] = os.path.basename(url)
  90. geometries.append(geom_data)
  91. data[key] = geometries
  92. elif isinstance(value, list):
  93. data[key] = []
  94. for each in value:
  95. data[key].append(each.copy())
  96. elif isinstance(value, dict):
  97. data[key] = value.copy()
  98. io.dump(self.filepath, data, options=self.options)
  99. if self.options.get(constants.COPY_TEXTURES):
  100. for geo in self[constants.GEOMETRIES]:
  101. logger.info('Copying textures from %s', geo.node)
  102. geo.copy_textures()
  103. def _find_node(self, arg, manifest):
  104. for index in manifest:
  105. uuid = index.get(constants.UUID) == arg
  106. name = index.node == arg
  107. if uuid or name:
  108. return index
  109. else:
  110. logger.debug('No matching node for %s', arg)
  111. def __parse_geometries(self):
  112. logger.debug('Scene().__parse_geometries()')
  113. # this is an important step. please refer to the doc string
  114. # on the function for more information
  115. api.object.prep_meshes(self.options)
  116. geometries = []
  117. # now iterate over all the extracted mesh nodes and parse each one
  118. for mesh in api.object.extracted_meshes():
  119. logger.info('Parsing geometry %s', mesh)
  120. geo = geometry.Geometry(mesh, self)
  121. geo.parse()
  122. geometries.append(geo)
  123. logger.info('Added %d geometry nodes', len(geometries))
  124. self[constants.GEOMETRIES] = geometries
  125. def __parse_materials(self):
  126. logger.debug('Scene().__parse_materials()')
  127. materials = []
  128. for material_name in api.material.used_materials():
  129. logger.info('Parsing material %s', material_name)
  130. materials.append(material.Material(material_name, parent=self))
  131. logger.info('Added %d material nodes', len(materials))
  132. self[constants.MATERIALS] = materials
  133. def __parse_objects(self):
  134. logger.debug('Scene().__parse_objects()')
  135. self[constants.OBJECT] = object.Object(None, parent=self)
  136. self[constants.OBJECT][constants.TYPE] = constants.SCENE.title()
  137. objects = []
  138. for node in api.object.nodes(self.valid_types, self.options):
  139. logger.info('Parsing object %s', node)
  140. obj = object.Object(node, parent=self[constants.OBJECT])
  141. objects.append(obj)
  142. logger.info('Added %d object nodes', len(objects))
  143. self[constants.OBJECT][constants.CHILDREN] = objects
  144. def __parse_textures(self):
  145. logger.debug('Scene().__parse_textures()')
  146. textures = []
  147. for texture_name in api.texture.textures():
  148. logger.info('Parsing texture %s', texture_name)
  149. tex_inst = texture.Texture(texture_name, self)
  150. textures.append(tex_inst)
  151. logger.info('Added %d texture nodes', len(textures))
  152. self[constants.TEXTURES] = textures