diff --git a/3d-converter-0.8.0/3d_converter.egg-info/PKG-INFO b/3d-converter-0.8.0/3d_converter.egg-info/PKG-INFO
deleted file mode 100644
index 1cd65d1..0000000
--- a/3d-converter-0.8.0/3d_converter.egg-info/PKG-INFO
+++ /dev/null
@@ -1,25 +0,0 @@
-Metadata-Version: 2.1
-Name: 3d-converter
-Version: 0.8.0
-Summary: Python 3D Models Converter
-Home-page: https://github.com/vorono4ka/3d-converter
-Author: Vorono4ka
-Author-email: crowo4ka@gmail.com
-License: GPLv3
-Description: ## `Python 3D Models Converter`
-
- **Version**: 0.8.0
-
- ### Thanks a lot for motivating [AMIRMISTIK]!
-
- ### **THIS IS NOT RELEASE VERSION!**
-
-
- [AMIRMISTIK]: https://www.youtube.com/channel/UCksd1LeoySP5St6dKlv6mvQ
-
-Platform: UNKNOWN
-Classifier: Programming Language :: Python :: 3
-Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
-Classifier: Operating System :: OS Independent
-Requires-Python: >=3.7
-Description-Content-Type: text/markdown
diff --git a/3d-converter-0.8.0/3d_converter.egg-info/SOURCES.txt b/3d-converter-0.8.0/3d_converter.egg-info/SOURCES.txt
deleted file mode 100644
index 922e012..0000000
--- a/3d-converter-0.8.0/3d_converter.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-README.md
-setup.py
-3d_converter.egg-info/PKG-INFO
-3d_converter.egg-info/SOURCES.txt
-3d_converter.egg-info/dependency_links.txt
-3d_converter.egg-info/top_level.txt
-models_converter/__init__.py
-models_converter/formats/__init__.py
-models_converter/formats/dae.py
-models_converter/formats/gltf.py
-models_converter/formats/obj.py
-models_converter/formats/scw/__init__.py
-models_converter/formats/scw/parser.py
-models_converter/formats/scw/writer.py
-models_converter/formats/scw/chunks/__init__.py
-models_converter/formats/scw/chunks/came.py
-models_converter/formats/scw/chunks/chunk.py
-models_converter/formats/scw/chunks/geom.py
-models_converter/formats/scw/chunks/head.py
-models_converter/formats/scw/chunks/mate.py
-models_converter/formats/scw/chunks/node.py
-models_converter/formats/scw/chunks/wend.py
-models_converter/utils/__init__.py
-models_converter/utils/reader.py
-models_converter/utils/writer.py
-models_converter/utils/matrix/__init__.py
-models_converter/utils/matrix/matrix2x2.py
-models_converter/utils/matrix/matrix3x3.py
-models_converter/utils/matrix/matrix4x4.py
\ No newline at end of file
diff --git a/3d-converter-0.8.0/3d_converter.egg-info/dependency_links.txt b/3d-converter-0.8.0/3d_converter.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/3d-converter-0.8.0/3d_converter.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/3d-converter-0.8.0/3d_converter.egg-info/top_level.txt b/3d-converter-0.8.0/3d_converter.egg-info/top_level.txt
deleted file mode 100644
index da3db61..0000000
--- a/3d-converter-0.8.0/3d_converter.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-models_converter
diff --git a/3d-converter-0.8.0/README.md b/3d-converter-0.8.0/README.md
deleted file mode 100644
index 7ec19cc..0000000
--- a/3d-converter-0.8.0/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-## `Python 3D Models Converter`
-
-**Version**: 0.8.0
-
-### Thanks a lot for motivating [AMIRMISTIK]!
-
-### **THIS IS NOT RELEASE VERSION!**
-
-
-[AMIRMISTIK]: https://www.youtube.com/channel/UCksd1LeoySP5St6dKlv6mvQ
diff --git a/3d-converter-0.8.0/models_converter/__init__.py b/3d-converter-0.8.0/models_converter/__init__.py
deleted file mode 100644
index f5dd35a..0000000
--- a/3d-converter-0.8.0/models_converter/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-__all__ = [
- 'formats',
- 'chunks',
- 'utils'
-]
diff --git a/3d-converter-0.8.0/models_converter/formats/__init__.py b/3d-converter-0.8.0/models_converter/formats/__init__.py
deleted file mode 100644
index 3e518f9..0000000
--- a/3d-converter-0.8.0/models_converter/formats/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-__all__ = [
- 'scw',
- 'dae',
- 'obj',
- 'gltf'
-]
diff --git a/3d-converter-0.8.0/models_converter/formats/dae.py b/3d-converter-0.8.0/models_converter/formats/dae.py
deleted file mode 100644
index 2c2dbe1..0000000
--- a/3d-converter-0.8.0/models_converter/formats/dae.py
+++ /dev/null
@@ -1,786 +0,0 @@
-from xml.etree.ElementTree import *
-
-from ..utils.matrix.matrix4x4 import Matrix4x4
-
-
-def _(*args):
- print('[ScwUtils]', end=' ')
- for arg in args:
- print(arg, end=' ')
- print()
-
-
-class Collada:
- def __init__(self):
- self.version = '1.4.1'
- self.xml_namespace = 'http://www.collada.org/2005/11/COLLADASchema'
- self.collada = Element('COLLADA', version=self.version, xmlns=self.xml_namespace)
-
- @staticmethod
- def write_source(parent,
- source_id: str,
- array_tag: str,
- array_data: list,
- stride: int,
- params: list):
- source = SubElement(parent, 'source', id=source_id)
-
- array = SubElement(source, array_tag)
- array.attrib = {'id': f'{source_id}-array',
- 'count': f'{len(array_data) * stride}'}
-
- technique_common = SubElement(source, 'technique_common')
- accessor = SubElement(technique_common, 'accessor')
- accessor.attrib = {'source': f'#{source_id}-array',
- 'count': f'{len(array_data)}',
- 'stride': f'{stride}'}
-
- for param_data in params:
- param = SubElement(accessor, 'param')
- param.attrib = param_data
-
- array.text = ' '.join(array_data)
-
- @staticmethod
- def write_input(parent,
- semantic: str,
- source_id: str,
- offset: int = None):
- attributes = {
- 'semantic': semantic,
- 'source': f'#{source_id}'
- }
-
- if offset is not None:
- attributes['offset'] = f'{offset}'
-
- _input = SubElement(parent, 'input')
- _input.attrib = attributes
-
-
-class Writer:
- def __init__(self):
- self.writen = ''
-
- def write(self, data: dict):
- dae = Collada()
- asset = SubElement(dae.collada, 'asset')
-
- #
- library_materials = SubElement(dae.collada, 'library_materials')
- library_effects = SubElement(dae.collada, 'library_effects')
- # library_images = SubElement(dae.collada, 'library_images')
- library_geometries = SubElement(dae.collada, 'library_geometries')
- library_controllers = SubElement(dae.collada, 'library_controllers')
- library_animations = SubElement(dae.collada, 'library_animations')
- # library_cameras = SubElement(dae.collada, 'library_cameras')
- library_visual_scenes = SubElement(dae.collada, 'library_visual_scenes')
- #
-
- #
- contributor = SubElement(asset, 'contributor')
- SubElement(contributor, 'author').text = 'Vorono4ka'
- SubElement(contributor, 'authoring_tool').text = 'models_converter (https://github.com/vorono4ka/3d-converter)'
-
- if 'version' in data['header']:
- SubElement(contributor, 'comments').text = 'SCW Version: ' + str(data['header']['version'])
- #
-
- #
- for material_data in data['materials']:
- material_name = material_data['name']
-
- SubElement(library_materials, 'material', id=material_name)
- effect_name = f'{material_name}-effect'
-
- material = SubElement(library_materials, 'material', id=material_name)
- SubElement(material, 'instance_effect', url=f'#{effect_name}')
-
- effect = SubElement(library_effects, 'effect', id=effect_name)
- profile = SubElement(effect, 'profile_COMMON')
- technique = SubElement(profile, 'technique', sid='common')
-
- ambient_data = material_data['effect']['ambient']
- diffuse_data = material_data['effect']['diffuse']
- emission_data = material_data['effect']['emission']
- specular_data = material_data['effect']['specular']
-
- phong = SubElement(technique, 'phong')
-
- if type(ambient_data) is list:
- ambient = SubElement(phong, 'ambient')
- ambient_data[3] /= 255
- ambient_data = [str(item) for item in ambient_data]
- SubElement(ambient, 'color').text = ' '.join(ambient_data)
- # else:
- # SubElement(ambient, 'texture', texture=ambient_data, texcoord='CHANNEL0')
-
- if type(diffuse_data) is list:
- diffuse = SubElement(phong, 'diffuse')
- diffuse_data[3] /= 255
- diffuse_data = [str(item) for item in diffuse_data]
- SubElement(diffuse, 'color').text = ' '.join(diffuse_data)
- # else:
- # SubElement(diffuse, 'texture', texture=diffuse_data, texcoord='CHANNEL0')
-
- if type(emission_data) is list:
- emission = SubElement(phong, 'emission')
- emission_data[3] /= 255
- emission_data = [str(item) for item in emission_data]
- SubElement(emission, 'color').text = ' '.join(emission_data)
- # else:
- # SubElement(emission, 'texture', texture=emission_data, texcoord='CHANNEL0')
-
- if type(specular_data) is list:
- specular = SubElement(phong, 'specular')
- specular_data[3] /= 255
- specular_data = [str(item) for item in specular_data]
- SubElement(specular, 'color').text = ' '.join(specular_data)
- # else:
- # SubElement(specular, 'texture', texture=specular_data, texcoord='CHANNEL0')
- #
-
- #
- for geometry_data in data['geometries']:
- geometry_name = geometry_data['name']
-
- geometry = SubElement(library_geometries, 'geometry', id=f'{geometry_name}-geom')
- mesh = SubElement(geometry, 'mesh')
-
- #
- for vertex_data in geometry_data['vertices']:
- params = []
-
- vertex_type = vertex_data['type']
- vertex_name = vertex_data['name']
- vertex = vertex_data['vertex']
- stride = len(vertex[0])
-
- if vertex_type == 'VERTEX':
- vertex_type = 'POSITION'
-
- source_name = f'{geometry_name}-{vertex_name}'
-
- if vertex_type in ['POSITION', 'NORMAL']:
- params.append({'name': 'X', 'type': 'float'})
- params.append({'name': 'Y', 'type': 'float'})
- params.append({'name': 'Z', 'type': 'float'})
- elif vertex_type in ['TEXCOORD']:
- params.append({'name': 'S', 'type': 'float'})
- params.append({'name': 'T', 'type': 'float'})
-
- dae.write_source(
- mesh,
- source_name,
- 'float_array',
- [' '.join([str(sub_item * vertex_data['scale']) for sub_item in item]) for item in vertex],
- stride,
- params
- )
-
- if vertex_type == 'POSITION':
- vertices = SubElement(mesh, 'vertices', id=f'{source_name}-vertices')
- dae.write_input(vertices, 'POSITION', source_name)
- #
-
- #
- for material in geometry_data['materials']:
- polygons_data = material['polygons']
- material_name = material['name']
-
- triangles = SubElement(mesh, 'triangles',
- count=f'{len(polygons_data)}',
- material=material_name)
- for _input in material['inputs']:
- input_offset = _input['offset']
- input_name = _input['name']
- input_type = _input['type']
-
- if input_type == 'POSITION':
- input_type = 'VERTEX'
- source_id = f'{geometry_name}-{input_name}'
- if input_type == 'VERTEX':
- source_id = f'{source_id}-vertices'
-
- dae.write_input(triangles, input_type, source_id, input_offset)
- polygons = SubElement(triangles, 'p')
-
- formatted_polygons_data = []
- for polygon in polygons_data:
- for point in polygon:
- for vertex in point:
- formatted_polygons_data.append(str(vertex))
-
- polygons.text = ' '.join(formatted_polygons_data)
- #
-
- #
- if geometry_data['have_bind_matrix']:
- joints_matrices = []
- joints_names = []
-
- controller = SubElement(library_controllers, 'controller', id=f'{geometry_name}-cont')
- skin = SubElement(controller, 'skin', source=f'#{geometry_name}-geom')
-
- if 'bind_matrix' in geometry_data:
- bind_matrix_data = [str(value) for value in geometry_data['bind_matrix']]
- SubElement(skin, 'bind_shape_matrix').text = ' '.join(bind_matrix_data)
-
- for joint in geometry_data['joints']:
- joints_names.append(joint['name'])
- joint_matrix = [str(value) for value in joint['matrix']]
- joint_matrix = ' '.join(joint_matrix)
- joints_matrices.append(joint_matrix)
-
- joints_names_source_id = f'{geometry_name}-joints'
- joints_matrices_source_id = f'{geometry_name}-joints-bind-matrices'
- weights_source_id = f'{geometry_name}-weights'
-
- dae.write_source(
- skin,
- joints_names_source_id,
- 'Name_array',
- joints_names,
- 1,
- [{'name': 'JOINT', 'type': 'name'}]
- )
-
- dae.write_source(
- skin,
- joints_matrices_source_id,
- 'float_array',
- joints_matrices,
- 16,
- [{'name': 'TRANSFORM', 'type': 'float4x4'}]
- )
-
- dae.write_source(
- skin,
- weights_source_id,
- 'float_array',
- [str(value) for value in geometry_data['weights']['weights']],
- 1,
- [{'name': 'WEIGHT', 'type': 'float'}]
- )
-
- joints = SubElement(skin, 'joints')
- dae.write_input(joints, 'JOINT', joints_names_source_id)
- dae.write_input(joints, 'INV_BIND_MATRIX', joints_matrices_source_id)
-
- vertex_weights_data = [str(value) for value in geometry_data['weights']['vertex_weights']]
- vcount = [str(value) for value in geometry_data['weights']['vcount']]
-
- vertex_weights = SubElement(skin, 'vertex_weights', count=f'{len(vcount)}')
- dae.write_input(vertex_weights, 'JOINT', joints_names_source_id, 0)
- dae.write_input(vertex_weights, 'WEIGHT', weights_source_id, 1)
-
- SubElement(vertex_weights, 'vcount').text = ' '.join(vcount)
- SubElement(vertex_weights, 'v').text = ' '.join(vertex_weights_data)
- #
- #
-
- #
-
- visual_scene = SubElement(library_visual_scenes, 'visual_scene',
- id='3dConverterScene',
- name='3d-Converter Scene')
-
- for node_data in data['nodes']:
- parent_name = node_data['parent']
- parent = visual_scene
- if parent_name != '':
- parent = visual_scene.find(f'.//*[@id="{parent_name}"]')
- if parent is None:
- parent = visual_scene
- node_name = node_data['name']
-
- node = SubElement(parent, 'node', id=node_data['name'])
-
- for instance in node_data['instances']:
- instance_type = instance['instance_type']
- instance_name = instance['instance_name']
- bind_material = None
-
- if instance_type == 'CONT':
- instance_controller = SubElement(node, 'instance_controller', url=f'#{instance_name}-cont')
- bind_material = SubElement(instance_controller, 'bind_material')
- elif instance_type == 'GEOM':
- instance_controller = SubElement(node, 'instance_geometry', url=f'#{instance_name}-geom')
- bind_material = SubElement(instance_controller, 'bind_material')
-
- if instance_type in ['GEOM', 'CONT']:
- technique_common = SubElement(bind_material, 'technique_common')
- for bind in instance['binds']:
- symbol = bind['symbol']
- target = bind['target']
-
- SubElement(technique_common, 'instance_material',
- symbol=symbol,
- target=f'#{target}')
- else:
- if parent_name != '' and len(node_data['instances']) == 0:
- node.attrib['type'] = 'JOINT'
-
- #
- frame_rate = data['header']['frame_rate']
- time_input = []
- matrix_output = []
- #
-
- frames = node_data['frames']
- for frame in frames:
- frame_id = frame['frame_id']
- matrix = Matrix4x4(size=(4, 4))
-
- time_input.append(str(frame_id/frame_rate))
-
- position_xyz = (frame['position']['x'], frame['position']['y'], frame['position']['z'])
- rotation_xyz = (frame['rotation']['x'], frame['rotation']['y'], frame['rotation']['z'])
- scale_xyz = (frame['scale']['x'], frame['scale']['y'], frame['scale']['z'])
-
- matrix.put_rotation(rotation_xyz, frame['rotation']['w'])
- matrix.put_position(position_xyz)
- matrix.put_scale(scale_xyz)
-
- matrix = matrix.translation_matrix @ matrix.rotation_matrix @ matrix.scale_matrix
- matrix_values = []
- for row in matrix.matrix:
- for column in row:
- matrix_values.append(str(column))
-
- if node_data['frames'].index(frame) == 0:
- SubElement(node, 'matrix', sid='transform').text = ' '.join(matrix_values)
- matrix_output.append(' '.join(matrix_values))
-
- if len(frames) > 1:
- animation = SubElement(library_animations, 'animation', id=node_name)
-
- dae.write_source(
- animation,
- f'{node_name}-time-input',
- 'float_array',
- time_input,
- 1,
- [{'name': 'TIME', 'type': 'float'}]
- )
- dae.write_source(
- animation,
- f'{node_name}-matrix-output',
- 'float_array',
- matrix_output,
- 16,
- [{'name': 'TRANSFORM', 'type': 'float4x4'}]
- )
- dae.write_source(
- animation,
- f'{node_name}-interpolation',
- 'Name_array',
- ['LINEAR'] * len(frames),
- 1,
- [{'name': 'INTERPOLATION', 'type': 'name'}]
- )
-
- sampler = SubElement(animation, 'sampler', id=f'{node_name}-sampler')
-
- dae.write_input(
- sampler,
- 'INPUT',
- f'{node_name}-time-input'
- )
-
- dae.write_input(
- sampler,
- 'OUTPUT',
- f'{node_name}-matrix-output'
- )
-
- dae.write_input(
- sampler,
- 'INTERPOLATION',
- f'{node_name}-interpolation'
- )
-
- SubElement(animation, 'channel',
- source=f'#{node_name}-sampler',
- target=f'{node_name}/transform')
-
- scene = SubElement(dae.collada, 'scene')
- SubElement(scene, 'instance_visual_scene',
- url='#3dConverterScene',
- name='3d-Converter Scene')
-
- #
-
- self.writen = tostring(dae.collada, xml_declaration=True).decode()
-
-
-class Parser:
- def node(self, nodes):
- nodes_list = []
- for node in nodes:
- instance_geometry = node.findall('collada:instance_geometry', self.namespaces)
- instance_controller = node.findall('collada:instance_controller', self.namespaces)
-
- instances = [*instance_geometry, *instance_controller]
-
- children = self.node(node.findall('collada:node', self.namespaces))
-
- if 'name' not in node.attrib:
- node.attrib['name'] = node.attrib['id']
-
- node_data = {
- 'name': node.attrib['name'],
- 'instances': []
- }
-
- for instance in instances:
- instance_data = {}
- binds = []
-
- bind_material = instance.find('collada:bind_material', self.namespaces)
- technique_common = bind_material[0]
-
- for instance_material in technique_common:
- binds.append({
- 'symbol': instance_material.attrib['symbol'],
- 'target': instance_material.attrib['target'][1:]
- })
-
- if instance_geometry:
- instance_data['instance_type'] = 'GEOM'
-
- geometry_url = instance.attrib['url']
- instance_data['instance_name'] = geometry_url[1:]
- elif instance_controller:
- instance_data['instance_type'] = 'CONT'
-
- controller_url = instance.attrib['url']
- instance_data['instance_name'] = controller_url[1:]
-
- instance_data['binds'] = binds
- node_data['instances'].append(instance_data)
-
- matrix = node.findall('collada:matrix', self.namespaces)
- if matrix:
- matrix_data = matrix[0].text.split()
- matrix_data = [[float(value) for value in matrix_data[x:x + 4]] for x in range(0, len(matrix_data), 4)]
-
- node_data['matrix'] = matrix_data
-
- node_data['children'] = children
-
- nodes_list.append(node_data)
-
- return nodes_list
-
- def fix_nodes_list(self, nodes, parent: str = ''):
- for node in nodes:
- node_data = {
- 'name': node['name'],
- 'parent': parent,
- 'instances': node['instances']
- }
-
- if len(node_data['instances']) == 0:
- node_data['frames_settings'] = [0, 0, 0, 0, 0, 0, 0, 0]
- node_data['frames'] = []
-
- if 'matrix' in node:
- matrix = Matrix4x4(matrix=node['matrix'])
-
- # scale = matrix.get_scale()
- position = matrix.get_position()
-
- node_data['frames'] = [
- {
- 'frame_id': 0,
- 'rotation': {'x': 0, 'y': 0, 'z': 0, 'w': 0},
- 'position': position,
- 'scale': {'x': 1, 'y': 1, 'z': 1}
- }
- ]
- else:
- node_data['frames'] = []
-
- # node_data['frames'] = node['frames']
- self.parsed['nodes'].append(node_data)
- self.fix_nodes_list(node['children'], node['name'])
-
- def __init__(self, file_data):
- self.parsed = {'header': {'version': 2,
- 'frame_rate': 30,
- 'materials_file': 'sc3d/character_materials.scw'},
- 'materials': [],
- 'geometries': [],
- 'cameras': [],
- 'nodes': []}
-
- self.geometry_info = {}
-
- root = fromstring(file_data)
-
- self.namespaces = {
- 'collada': 'http://www.collada.org/2005/11/COLLADASchema'
- }
-
- #
- self.library_materials = root.find('./collada:library_materials', self.namespaces)
- self.library_effects = root.find('./collada:library_effects', self.namespaces)
-
- self.library_geometries = root.find('./collada:library_geometries', self.namespaces)
- self.library_controllers = root.find('./collada:library_controllers', self.namespaces)
-
- self.instance_scene = root.find('./collada:scene', self.namespaces).find('collada:instance_visual_scene',
- self.namespaces)
- self.library_scenes = root.find('./collada:library_visual_scenes', self.namespaces)
- #
-
- if self.library_materials is None:
- self.library_materials = []
-
- def parse(self):
- for material in self.library_materials:
- material_name = material.attrib['name']
-
- instance_effect = material.find('collada:instance_effect', self.namespaces)
- if instance_effect is not None:
- effect_url = instance_effect.attrib['url'][1:]
- effect = self.library_effects.find(f'collada:effect[@id="{effect_url}"]', self.namespaces)
-
- if effect is not None:
- # profile = None
- # for item in effect:
- # if 'profile' in item.tag:
- # profile = item
- # technique = profile.find('collada:technique', self.namespaces)
- #
- # emission_data = None
- # ambient_data = None
- # diffuse_data = None
- #
- # emission = technique[0].find('collada:emission', self.namespaces)
- # ambient = technique[0].find('collada:ambient', self.namespaces)
- # diffuse = technique[0].find('collada:diffuse', self.namespaces)
- #
- # if 'color' in emission[0].tag:
- # emission_data = [float(item) for item in emission[0].text.split()]
- # emission_data[3] *= 255
- # elif 'texture' in emission[0].tag:
- # # emission_data = emission[0].attrib['texture']
- # emission_data = '.'
- #
- # if 'color' in ambient[0].tag:
- # ambient_data = [float(item) for item in ambient[0].text.split()]
- # ambient_data[3] *= 255
- # elif 'texture' in ambient[0].tag:
- # # ambient_data = ambient[0].attrib['texture']
- # ambient_data = '.'
- #
- # if 'color' in diffuse[0].tag:
- # diffuse_data = [float(item) for item in diffuse[0].text.split()]
- # diffuse_data[3] *= 255
- # elif 'texture' in diffuse[0].tag:
- # # diffuse_data = diffuse[0].attrib['texture']
- # diffuse_data = '.'
-
- material_data = {
- 'name': material_name,
- 'effect': {
- 'ambient': [0, 0, 0, 255], # ambient_data,
- 'diffuse': '.', # diffuse_data,
- 'specular': '.',
- 'colorize': [255, 255, 255, 255],
- 'emission': [0, 0, 0, 255], # emission_data,
- 'lightmaps': {
- 'diffuse': 'sc3d/diffuse_lightmap.png',
- 'specular': 'sc3d/specular_lightmap.png'
- },
- 'shader_define_flags': 3014
- }
- }
-
- self.parsed['materials'].append(material_data)
-
- scene_url = self.instance_scene.attrib['url'][1:]
- scene = self.library_scenes.find(f'collada:visual_scene[@id="{scene_url}"]', self.namespaces)
-
- nodes = self.node(scene.findall('collada:node', self.namespaces))
- self.fix_nodes_list(nodes)
- self.parse_nodes()
-
- def parse_nodes(self):
- nodes = self.parsed['nodes']
- for node_index in range(len(nodes)):
- node = nodes[node_index]
- for instance in node['instances']:
- controller = None
- geometry = None
-
- if instance['instance_type'] == 'CONT':
- controller = self.library_controllers \
- .find(f'collada:controller[@id="{instance["instance_name"]}"]', self.namespaces)
-
- geometry_url = controller[0].attrib['source'][1:]
- geometry = self.library_geometries \
- .find(f'collada:geometry[@id="{geometry_url}"]', self.namespaces)
- elif instance['instance_type'] == 'GEOM':
- geometry = self.library_geometries \
- .find(f'collada:geometry[@id="{instance["instance_name"]}"]', self.namespaces)
-
- if not ('name' in geometry.attrib):
- geometry.attrib['name'] = geometry.attrib['id']
-
- instance['instance_name'] = geometry.attrib['name']
-
- for suffix in ['-skin', '-cont']:
- instance['instance_name'] = instance['instance_name'].removesuffix(suffix)
- for suffix in ['-mesh', '-geom']:
- instance['instance_name'] = instance['instance_name'].removesuffix(suffix)
-
- self.parsed['nodes'][node_index] = node
-
- if geometry is not None:
- self.geometry_info = {'name': '',
- 'group': '', # node['parent'],
- 'vertices': [],
- 'have_bind_matrix': False,
- 'materials': []}
- if controller is not None:
- self.parse_controller(controller)
-
- self.parse_geometry(geometry)
-
- def parse_controller(self, controller):
- self.geometry_info['have_bind_matrix'] = True
-
- skin = controller[0]
-
- bind_shape_matrix = skin.find('collada:bind_shape_matrix', self.namespaces).text
- bind_shape_matrix = [float(x) for x in bind_shape_matrix.split()]
-
- self.geometry_info['bind_matrix'] = bind_shape_matrix
-
- self.geometry_info['joints'] = []
- joints = skin.find('collada:joints', self.namespaces)
- joint_inputs = joints.findall('collada:input', self.namespaces)
- for _input in joint_inputs:
- # semantic = _input.attrib['semantic']
- source_url = _input.attrib['source']
- source = skin.find(f'collada:source[@id="{source_url[1:]}"]', self.namespaces)
-
- accessor = source.find('collada:technique_common/collada:accessor', self.namespaces)
- accessor_stride = int(accessor.attrib['stride'])
- accessor_source_url = accessor.attrib['source']
- accessor_source = source.find(f'collada:*[@id="{accessor_source_url[1:]}"]', self.namespaces)
- params = accessor.findall('collada:param', self.namespaces)
-
- for param in params:
- param_name = param.attrib['name']
- # param_type = param.attrib['type']
-
- if param_name == 'JOINT':
- for name in accessor_source.text.split():
- self.geometry_info['joints'].append({
- 'name': name
- })
-
- if param_name == 'TRANSFORM':
- for x in range(int(accessor_source.attrib['count']) // int(accessor_stride)):
- matrix = []
- for y in accessor_source.text.split()[x * accessor_stride:(x + 1) * accessor_stride]:
- matrix.append(float(y))
- self.geometry_info['joints'][x]['matrix'] = matrix
-
- self.geometry_info['weights'] = {}
- vertex_weights = skin.find('collada:vertex_weights', self.namespaces)
- vertex_weights_inputs = vertex_weights.findall('collada:input', self.namespaces)
- for _input in vertex_weights_inputs:
- semantic = _input.attrib['semantic']
- source_url = _input.attrib['source']
- source = skin.find(f'collada:source[@id="{source_url[1:]}"]', self.namespaces)
-
- if semantic == 'WEIGHT':
- accessor = source.find('collada:technique_common/collada:accessor', self.namespaces)
- accessor_source_url = accessor.attrib['source']
- accessor_source = source.find(f'collada:*[@id="{accessor_source_url[1:]}"]', self.namespaces)
-
- params = accessor.findall('collada:param', self.namespaces)
- for param in params:
- param_name = param.attrib['name']
- # param_type = param.attrib['type']
-
- if param_name == 'WEIGHT':
- weights = [float(x) for x in accessor_source.text.split()]
- self.geometry_info['weights']['weights'] = weights
-
- vcount = vertex_weights.find('collada:vcount', self.namespaces).text
- vcount = [int(x) for x in vcount.split()]
- self.geometry_info['weights']['vcount'] = vcount
-
- v = vertex_weights.find('collada:v', self.namespaces).text
- v = [int(x) for x in v.split()]
- self.geometry_info['weights']['vertex_weights'] = v
-
- def parse_geometry(self, geometry):
- name = geometry.attrib['name']
-
- if name[-5:] in ['-mesh', '-geom']:
- name = name[:-5]
-
- self.geometry_info['name'] = name
- self.geometry_info['group'] = name
-
- mesh = geometry[0]
-
- triangles = mesh.findall('collada:triangles', self.namespaces)
- if triangles:
- pass
- else:
- triangles = mesh.findall('collada:polylist', self.namespaces)
- inputs = triangles[0].findall('collada:input', self.namespaces)
- for _input in inputs:
- semantic = _input.attrib['semantic']
- source_link = _input.attrib['source'][1:]
- source = mesh.find(f'*[@id="{source_link}"]')
-
- if semantic == 'VERTEX':
- vertices_input = source[0]
- semantic = vertices_input.attrib['semantic']
- source_link = vertices_input.attrib['source'][1:]
- source = mesh.find(f'*[@id="{source_link}"]')
-
- float_array = source.find('collada:float_array', self.namespaces)
- accessor = source.find('collada:technique_common/collada:accessor', self.namespaces)
-
- vertex_temp = [float(floating) for floating in float_array.text.split()]
-
- scale = max(max(vertex_temp), abs(min(vertex_temp)))
- if scale < 1:
- scale = 1
- if semantic == 'TEXCOORD':
- vertex_temp[1::2] = [1 - x for x in vertex_temp[1::2]]
- vertex_temp = [value / scale for value in vertex_temp]
-
- vertex = []
- for x in range(0, len(vertex_temp), len(accessor)):
- vertex.append(vertex_temp[x: x + len(accessor)])
-
- self.geometry_info['vertices'].append({'type': semantic,
- 'index': len(self.geometry_info['vertices']),
- 'scale': scale,
- 'vertex': vertex})
- for triangle in triangles:
- triangles_material = triangle.attrib['material']
-
- p = triangle.find('collada:p', self.namespaces)
- polygons_temp = [int(integer) for integer in p.text.split()]
-
- polygons = [
- [
- polygons_temp[polygon_index + point_index:polygon_index + point_index + 3]
- for point_index in range(0, len(inputs) * 3, 3)
- ] for polygon_index in range(0, len(polygons_temp), len(inputs) * 3)
- ]
- self.geometry_info['materials'].append({'name': triangles_material,
- 'polygons': polygons})
- self.parsed['geometries'].append(self.geometry_info)
diff --git a/3d-converter-0.8.0/models_converter/formats/gltf.py b/3d-converter-0.8.0/models_converter/formats/gltf.py
deleted file mode 100644
index 281da6b..0000000
--- a/3d-converter-0.8.0/models_converter/formats/gltf.py
+++ /dev/null
@@ -1,779 +0,0 @@
-import json
-
-from models_converter.formats.dae import Writer
-from models_converter.utils.reader import Reader
-
-
-def to_camelcase(property_name: str):
- words = property_name.split('_')
- for word_index in range(len(words)):
- word = words[word_index]
- if word_index > 0:
- word = list(word)
- word[0] = word[0].upper()
-
- word = ''.join(word)
-
- words[word_index] = word
- camelcase_name = ''.join(words)
- return camelcase_name
-
-
-def to_lowercase(property_name: str):
- letters = list(property_name)
-
- for letter_index in range(len(letters)):
- letter = letters[letter_index]
-
- if letter.isupper():
- letter = f'_{letter.lower()}'
-
- letters[letter_index] = letter
-
- lowercase_name = ''.join(letters)
- return lowercase_name
-
-
-def get_data_from_dict(dictionary, key, default=None):
- if key in dictionary:
- return dictionary[key]
- return default
-
-
-from_dict = get_data_from_dict
-
-
-class GlTFProperty:
- def __init__(self):
- self.extensions = None
- self.extras = None
-
- def from_dict(self, dictionary: dict):
- if dictionary:
- for key, value in dictionary.items():
- attribute_name = to_lowercase(key)
- value_type = type(value)
-
- attribute_value = getattr(self, attribute_name)
- attribute_value_type = type(attribute_value)
-
- if attribute_value is None or value_type in [int, str]:
- attribute_value = value
- elif issubclass(attribute_value_type, GlTFProperty):
- if value_type is list:
- value_type = attribute_value_type
- values = []
-
- for item in value:
- new_value = value_type()
- new_value.from_dict(item)
-
- values.append(new_value)
-
- attribute_value = values
- else:
- attribute_value = attribute_value_type()
- attribute_value.from_dict(value)
-
- setattr(self, attribute_name, attribute_value)
-
- def to_dict(self) -> dict:
- dictionary = {}
- for key, value in self.__dict__.items():
- if value is not None:
- attribute_name = to_camelcase(key)
- value_type = type(value)
-
- attribute_value = None
-
- if value_type is list:
- attribute_value = []
- for item in value:
- item_type = type(item)
-
- if issubclass(item_type, GlTFProperty):
- item = item.to_dict()
- attribute_value.append(item)
- elif issubclass(value_type, GlTFProperty):
- attribute_value = value.to_dict()
- elif attribute_value is None:
- attribute_value = value
-
- dictionary[attribute_name] = attribute_value
- return dictionary
-
- def __getitem__(self, item):
- item = to_lowercase(item)
- if hasattr(self, item):
- return getattr(self, item)
- else:
- raise IndexError('The object has no attribute named ' + item)
-
- def __repr__(self) -> str:
- return f'<{self.__class__.__name__} ({self.to_dict()})>'
-
-
-class Accessor(GlTFProperty):
- class Sparse(GlTFProperty):
- class Indices(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.buffer_view = None
- self.component_type = None
-
- self.byte_offset = 0
-
- class Values(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.buffer_view = None
-
- self.byte_offset = 0
-
- def __init__(self):
- super().__init__()
- self.count = None
- self.indices = self.Indices()
- self.values = self.Values()
-
- def __init__(self):
- super().__init__()
- self.component_type = None
- self.count = None
- self.type = None
-
- self.buffer_view = None
- self.byte_offset = 0
- self.normalized = False
- self.max = None
- self.min = None
- self.sparse = self.Sparse()
- self.name = None
-
-
-class Animation(GlTFProperty):
- class AnimationSampler(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.input = None
- self.output = None
-
- self.interpolation = None # Default: 'LINEAR'
-
- class Channel(GlTFProperty):
- class Target(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.path = None
-
- self.node = None
-
- def __init__(self):
- super().__init__()
- self.sampler = None
- self.target = self.Target()
-
- def __init__(self):
- super().__init__()
- self.channels = self.Channel()
- self.samplers = self.AnimationSampler()
-
- self.name = None
-
-
-class Asset(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.version = None
-
- self.copyright = None
- self.generator = None
- self.min_version = None
-
-
-class Buffer(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.byte_length = None
-
- self.uri = None
- self.name = None
-
-
-class BufferView(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.buffer = None
- self.byte_length = None
-
- self.byte_offset = 0
- self.byte_stride = None
- self.target = None
- self.name = None
-
-
-class Camera(GlTFProperty):
- class Orthographic(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.xmag = None
- self.ymag = None
- self.zfar = None
- self.znear = None
-
- class Perspective(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.yfov = None
- self.znear = None
-
- self.aspect_ratio = None
- self.zfar = None
-
- def __init__(self):
- super().__init__()
- self.type = None
-
- self.orthographic = None
- self.perspective = None
- self.name = None
-
-
-class Image(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.uri = None
- self.mime_type = None
- self.buffer_view = None
- self.name = None
-
-
-class Material(GlTFProperty):
- class NormalTextureInfo(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.index = None
-
- self.tex_coord = None # Default: 0
- self.scale = None # Default: 1
-
- class OcclusionTextureInfo(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.index = None
-
- self.tex_coord = None # Default: 0
- self.strength = None # Default: 1
-
- class PbrMetallicRoughness(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.base_color_factor = None # Default: [1, 1, 1, 1]
- self.base_color_texture = None
- self.metallic_factor = None # Default: 1
- self.roughness_factor = None # Default: 1
- self.metallic_roughness_texture = None
-
- def __init__(self):
- super().__init__()
- self.name = None
- self.pbr_metallic_roughness = None
- self.normal_texture = None
- self.occlusion_texture = None
- self.emissive_texture = None
- self.emissive_factor = None # Default: [0, 0, 0]
- self.alpha_mode = None # Default: 'OPAQUE'
- self.alpha_cutoff = None # Default: 0.5
- self.double_sided = None # Default: False
-
-
-class Mesh(GlTFProperty):
- class Primitive(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.attributes = None
-
- self.indices = None
- self.material = None
- self.mode = None # Default: 4
- self.targets = None
-
- def __init__(self):
- super().__init__()
- self.primitives = self.Primitive()
-
- self.weights = None
- self.name = None
-
-
-class Node(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.camera = None
- self.children = None
- self.skin = None
- self.matrix = None # Default: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
- self.mesh = None
- self.rotation = None # Default: [0, 0, 0, 1]
- self.scale = None # Default: [1, 1, 1]
- self.translation = None # Default: [0, 0, 0]
- self.weights = None
- self.name = None
-
-
-class Sampler(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.mag_filter = None
- self.min_filter = None
- self.wrap_s = None # Default: 10497
- self.wrap_t = None # Default: 10497
- self.name = None
-
-
-class Scene(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.nodes = None
- self.name = None
-
-
-class Skin(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.joints = None
-
- self.inverse_bind_matrices = None
- self.skeleton = None
- self.name = None
-
-
-class Texture(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.sampler = None
- self.source = None
- self.name = None
-
-
-class TextureInfo(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.index = None
-
- self.tex_coord = None # Default: 0
-
-
-class GlTF(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.asset = Asset()
-
- self.extensions_used = None
- self.extensions_required = None
-
- self.accessors = Accessor()
- self.animations = Animation()
- self.buffers = Buffer()
- self.buffer_views = BufferView()
- self.cameras = Camera()
- self.images = Image()
- self.materials = Material()
- self.meshes = Mesh()
- self.nodes = Node()
- self.samplers = Sampler()
- self.scene = None
- self.scenes = Scene()
- self.skins = Skin()
- self.textures = Texture()
-
-
-class GlTFChunk:
- def __init__(self):
- self.chunk_length = 0
- self.chunk_name = b''
- self.data = b''
-
-
-class Parser(Reader):
- def __init__(self, initial_bytes: bytes):
- super().__init__(initial_bytes, 'little')
-
- self.magic = self.read(4)
- if self.magic != b'glTF':
- raise TypeError('File Magic isn\'t "glTF"')
-
- self.parsed = {
- 'header': {
- 'frame_rate': 30
- },
- 'materials': [],
- 'geometries': [],
- 'cameras': [],
- 'nodes': []
- }
-
- self.version = None
- self.length = None
-
- self.json_chunk = None
- self.bin_chunk = None
-
- self.buffer_views = []
- self.accessors = []
- self.buffers = []
-
- self.gltf = GlTF()
-
- def parse_bin(self):
- super().__init__(self.bin_chunk.data, 'little')
-
- for buffer in self.gltf.buffers:
- parsed_buffer = self.read(buffer.byte_length)
- self.buffers.append(parsed_buffer)
-
- for buffer_view in self.gltf.buffer_views:
- super().__init__(self.buffers[buffer_view.buffer], 'little')
-
- self.read(buffer_view.byte_offset)
-
- length = buffer_view.byte_length
- data = self.read(length)
-
- self.buffer_views.append(data)
-
- for accessor in self.gltf.accessors:
- super().__init__(self.buffer_views[accessor.buffer_view], '<')
- temp_accessor = []
-
- self.read(accessor.byte_offset)
-
- types = {
- 5120: self.readByte,
- 5121: self.readUByte,
- 5122: self.readShort,
- 5123: self.readUShort,
- 5125: self.readUInt32,
- 5126: self.readFloat
- }
-
- items_count = {
- 'SCALAR': 1,
- 'VEC2': 2,
- 'VEC3': 3,
- 'VEC4': 4,
- 'MAT2': 4,
- 'MAT3': 9,
- 'MAT4': 16
- }
-
- for x in range(accessor.count):
- temp_list = []
- for i in range(items_count[accessor.type]):
- temp_list.append(types[accessor.component_type]())
- temp_accessor.append(temp_list)
-
- if accessor.normalized:
- for item_index, data in enumerate(temp_accessor):
- new_data = []
- for item in data:
- if accessor['component_type'] == 5120:
- new_data.append(max(item / 127, -1.0))
- elif accessor['component_type'] == 5121:
- new_data.append(item / 255)
- elif accessor['component_type'] == 5122:
- new_data.append(max(item / 32767, -1.0))
- elif accessor['component_type'] == 5123:
- new_data.append(item / 65535)
- else:
- new_data.append(item)
- temp_accessor[item_index] = new_data
-
- self.accessors.append(temp_accessor)
-
- def parse(self):
- #
-
- self.version = self.readUInt32()
- self.length = self.readUInt32()
-
- self.json_chunk = GlTFChunk()
- self.bin_chunk = GlTFChunk()
-
- self.json_chunk.chunk_length = self.readUInt32()
- self.json_chunk.chunk_name = self.read(4)
- self.json_chunk.data = self.read(self.json_chunk.chunk_length)
-
- self.bin_chunk.chunk_length = self.readUInt32()
- self.bin_chunk.chunk_name = self.read(4)
- self.bin_chunk.data = self.read(self.bin_chunk.chunk_length)
-
- #
-
- self.gltf.from_dict(json.loads(self.json_chunk.data))
-
- self.parse_bin()
-
- #
-
- scene_id = self.gltf.scene
- scene = self.gltf.scenes[scene_id]
-
- for node_id in scene.nodes:
- node = self.gltf.nodes[node_id]
- self.parse_node(node)
-
- #
-
- def parse_node(self, node: Node, parent: str = None):
- node_name = node.name
- # node_name = node_name.split('|')
- # if len(node_name) > 1:
- # node_name = node_name[1]
- # parent = node_name[0]
- # else:
- # node_name = node_name[0]
-
- # node_name = node_name.split(':')
- # if len(node_name) > 1:
- # if node_name[1] == 'PIV':
- # print(node.name, node.translation)
- # # else:
- # print(node)
- # node_name = node_name[0]
- # else:
- # node_name = node_name[0]
-
- node_data = {
- 'name': node_name,
- 'parent': parent,
- 'has_target': False,
- 'frames': []
- }
-
- if node.mesh:
- node_data['has_target'] = True
- node_data['target_type'] = 'GEOM'
-
- geometry_data = {
- 'name': '',
- 'group': '',
- 'vertices': [],
- 'have_bind_matrix': False,
- 'weights': {
- 'vertex_weights': [],
- 'weights': [],
- 'vcount': []
- },
- 'materials': []
- }
-
- if node.skin:
- geometry_data['have_bind_matrix'] = True
- geometry_data['bind_matrix'] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
- geometry_data['joints'] = []
- node_data['target_type'] = 'CONT'
-
- skin_id = node.skin
- skin = self.gltf.skins[skin_id]
- bind_matrices = self.accessors[skin.inverse_bind_matrices]
-
- for joint in skin.joints:
- joint_index = skin['joints'].index(joint)
- joint_node = self.gltf.nodes[joint]
- joint_name = joint_node['name']
- matrix = bind_matrices[joint_index]
-
- joint_data = {
- 'name': joint_name,
- 'matrix': matrix
- }
- geometry_data['joints'].append(joint_data)
-
- mesh_id = node.mesh
- mesh = self.gltf.meshes[mesh_id]
- mesh_name = mesh.name
- mesh_name = mesh_name.split('|')
-
- if len(mesh_name) > 1:
- geometry_data['group'] = mesh_name[0]
- geometry_data['name'] = mesh_name[1]
- else:
- geometry_data['name'] = mesh_name[0]
-
- node_data['target'] = geometry_data['name']
- node_data['binds'] = []
-
- offsets = {
- 'POSITION': 0,
- 'NORMAL': 0,
- 'TEXCOORD': 0
- }
-
- for primitive in mesh.primitives:
- if primitive.to_dict() != {}:
- primitive_index = mesh.primitives.index(primitive)
- attributes = primitive.attributes
- material_id = primitive.material
- polygons_id = primitive.indices
-
- inputs = []
-
- polygons = self.accessors[polygons_id]
- material = self.gltf.materials[material_id]
-
- material_name = material.extensions['SC_shader']['name']
- node_data['binds'].append({
- 'symbol': material_name,
- 'target': material_name
- })
-
- for attribute_id in attributes:
- attribute = attributes[attribute_id]
- if attribute_id == 'POSITION':
- position = self.accessors[attribute]
-
- geometry_data['vertices'].append({
- 'type': 'POSITION',
- 'name': f'position_{primitive_index}',
- 'index': len(geometry_data['vertices']),
- 'scale': 1,
- 'vertex': position
- })
-
- inputs.append({
- 'type': 'POSITION',
- 'offset': '1',
- 'name': f'position_{primitive_index}',
- })
- elif attribute_id == 'NORMAL':
- normal = self.accessors[attribute]
-
- geometry_data['vertices'].append({
- 'type': 'NORMAL',
- 'name': f'normal_{primitive_index}',
- 'index': len(geometry_data['vertices']),
- 'scale': 1,
- 'vertex': normal
- })
-
- inputs.append({
- 'type': 'NORMAL',
- 'offset': '0',
- 'name': f'normal_{primitive_index}',
- })
- elif attribute_id.startswith('TEXCOORD'):
- texcoord = self.accessors[attribute]
-
- texcoord = [[item[0], 1 - item[1]] for item in texcoord]
-
- geometry_data['vertices'].append({
- 'type': 'TEXCOORD',
- 'name': f'texcoord_{primitive_index}',
- 'index': len(geometry_data['vertices']),
- 'scale': 1,
- 'vertex': texcoord
- })
-
- inputs.append({
- 'type': 'TEXCOORD',
- 'offset': '2',
- 'name': f'texcoord_{primitive_index}',
- })
- elif attribute_id.startswith('JOINTS'):
- vertex_weights = self.accessors[attribute]
- elif attribute_id.startswith('WEIGHTS'):
- weights = self.accessors[attribute]
-
- for x in range(len(vertex_weights)):
- geometry_data['weights']['vcount'].append(0)
-
- temp_list = [
- [vertex_weights[x][0], weights[x][0]],
- [vertex_weights[x][1], weights[x][1]],
- [vertex_weights[x][2], weights[x][2]],
- [vertex_weights[x][3], weights[x][3]]
- ]
- for pair in temp_list:
- if pair[1] != 0:
- geometry_data['weights']['vcount'][x] += 1
- geometry_data['weights']['vertex_weights'].append(pair[0])
- if pair[1] not in geometry_data['weights']['weights']:
- geometry_data['weights']['weights'].append(pair[1])
- geometry_data['weights']['vertex_weights'].append(
- geometry_data['weights']['weights'].index(pair[1])
- )
-
- polygons = [
- [
- [
- value[0] + offsets['NORMAL'],
- value[0] + offsets['POSITION'],
- value[0] + offsets['TEXCOORD']
- ] for value in polygons[x:x + 3]
- ] for x in range(0, len(polygons), 3)
- ]
-
- geometry_data['materials'].append({
- 'name': material_name,
- 'inputs': inputs,
- 'polygons': polygons
- })
-
- for attribute_id in attributes:
- if attribute_id == 'POSITION':
- offsets['POSITION'] += len(position)
- elif attribute_id == 'NORMAL':
- offsets['NORMAL'] += len(normal)
- elif attribute_id.startswith('TEXCOORD'):
- offsets['TEXCOORD'] += len(texcoord)
-
- self.parsed['geometries'].append(geometry_data)
-
- self.parsed['nodes'].append(node_data)
-
- if node.translation or node.rotation or node.scale:
- node_data['frames'].append({
- 'frame_id': 0,
- 'rotation': {'x': 0, 'y': 0, 'z': 0, 'w': 0},
- 'position': {'x': 0, 'y': 0, 'z': 0},
- 'scale': {'x': 1, 'y': 1, 'z': 1}
- })
-
- if node.translation:
- node_data['frames'][0]['position'] = {
- 'x': node.translation[0],
- 'y': node.translation[1],
- 'z': node.translation[2]
- }
- if node.rotation:
- node_data['frames'][0]['rotation'] = {
- 'x': node.rotation[0],
- 'y': node.rotation[1],
- 'z': node.rotation[2],
- 'w': node.rotation[3]
- }
- if node.scale:
- node_data['frames'][0]['scale'] = {
- 'x': node.scale[0],
- 'y': node.scale[1],
- 'z': node.scale[2]
- }
-
- if node.children:
- for child_id in node.children:
- child = self.gltf.nodes[child_id]
- self.parse_node(child, node_name)
-
-
-if __name__ == '__main__':
- with open('../crow_geo.glb', 'rb') as fh:
- file_data = fh.read()
- fh.close()
- parser = Parser(file_data)
- parser.parse()
-
- writer = Writer()
- with open('../crow_geo.dae', 'w') as fh:
- fh.write(writer.writen)
- fh.close()
diff --git a/3d-converter-0.8.0/models_converter/formats/obj.py b/3d-converter-0.8.0/models_converter/formats/obj.py
deleted file mode 100644
index ecdada4..0000000
--- a/3d-converter-0.8.0/models_converter/formats/obj.py
+++ /dev/null
@@ -1,189 +0,0 @@
-def _(*args):
- print('[ScwUtils]', end=' ')
- for arg in args:
- print(arg, end=' ')
- print()
-
-
-class Writer:
- def __init__(self):
- self.writen = ''
-
- self.temp_vertices_offsets = {
- 'POSITION': 0,
- 'TEXCOORD': 0,
- 'NORMAL': 0
- }
-
- self.vertices_offsets = {
- 'POSITION': 0,
- 'TEXCOORD': 0,
- 'NORMAL': 0
- }
-
- def write(self, data: dict):
- for geom in data['geometries']:
- for key in self.vertices_offsets.keys():
- self.vertices_offsets[key] = self.temp_vertices_offsets[key]
- prefix = ''
-
- name = geom['name']
- vertices = geom['vertices']
- materials = geom['materials']
- for vertex in vertices:
- if vertex['type'] == 'POSITION':
- prefix = 'v '
- elif vertex['type'] == 'NORMAL':
- prefix = 'vn '
- elif vertex['type'] == 'TEXCOORD':
- prefix = 'vt '
-
- self.temp_vertices_offsets[vertex['type']] += len(vertex['vertex'])
-
- for item in vertex['vertex']:
- temp_string = prefix
- for subitem in item:
- temp_string += str(subitem * vertex['scale']) + ' '
- self.writen += f'{temp_string}\n'
- self.writen += '\n\n'
- for material in materials:
- self.writen += f'o {name}_{material["name"]}\n\n'
- for item in material['polygons']:
- temp_string = 'f '
- for subitem in item:
- temp_list = [
- str(subitem[0] + self.vertices_offsets['POSITION'] + 1), # POSITION
- str(subitem[2] + self.vertices_offsets['TEXCOORD'] + 1), # TEXCOORD
- str(subitem[1] + self.vertices_offsets['NORMAL'] + 1) # NORMAL
- ]
-
- temp_string += '/'.join(temp_list) + ' '
- self.writen += f'{temp_string}\n'
- self.writen += '\n\n'
-
-
-class Parser:
- def __init__(self, file_data: str):
- #
-
- self.parsed = {'header': {'version': 2,
- 'frame_rate': 30,
- 'materials_file': 'sc3d/character_materials.scw'},
- 'materials': [],
- 'geometries': [],
- 'cameras': [],
- 'nodes': []}
-
- self.lines = file_data.split('\n')
-
- #
- self.position_temp, self.position = [], []
- self.normals_temp, self.normals = [], []
- self.texcoord_temp, self.texcoord = [], []
- #
-
- self.polygons = []
-
- #
-
- self.parse()
-
- def parse(self):
- geometry_name = 'This model haven \'t a chunk_name!:( Its VERY SAD!'
- is_first_name = True
- for line in self.lines:
- items = line.split()[1:]
- if line.startswith('v '): # POSITION
- for item in items:
- self.position_temp.append(float(item))
- elif line.startswith('vn '): # NORMAL
- for item in items:
- self.normals_temp.append(float(item))
- elif line.startswith('vt '): # TEXCOORD
- if len(items) > 2:
- items = items[:-1]
- for item in items:
- self.texcoord_temp.append(float(item))
- elif line.startswith('f '):
- temp_list = []
- if len(items) > 3:
- _('It is necessary to triangulate the model')
- break
- for item in items:
- second_temp_list = []
- if len(item.split('/')) == 2:
- _('Model have not normals or texture')
- break
- elif len(item.split('/')) == 1:
- _('Model have not normals and texture')
- break
- for x in item.split('/'):
- second_temp_list.append(int(x) - 1)
- temp_list.append([second_temp_list[0], second_temp_list[2], second_temp_list[1]])
- self.polygons.append(temp_list)
- elif line.startswith('o '):
- # if not is_first_name:
- # position_scale = self.get_vertex_scale(self.position_temp)
- # normals_scale = self.get_vertex_scale(self.normals_temp)
- # texcoord_scale = self.get_vertex_scale(self.texcoord_temp)
- #
- # self.parsed['geometries'].append({
- # 'chunk_name': geometry_name,
- # 'group': '',
- # 'vertices': [
- # {'type': 'POSITION', 'index': 0, 'scale': position_scale, 'vertex': self.position},
- # {'type': 'NORMAL', 'index': 1, 'scale': normals_scale, 'vertex': self.normals},
- # {'type': 'TEXCOORD', 'index': 2, 'scale': texcoord_scale, 'vertex': self.texcoord}
- # ],
- # 'have_bind_matrix': False,
- # 'materials': [{'chunk_name': 'character_mat', 'polygons': self.polygons}]
- # })
- #
- # #
- #
- # #
- # self.position_temp, self.position = [], []
- # self.normals_temp, self.normals = [], []
- # self.texcoord_temp, self.texcoord = [], []
- # #
- #
- # self.polygons = []
- #
- # #
- # geometry_name = line.split('o ')[0]
- if is_first_name:
- geometry_name = line.split('o ')[0]
-
- position_scale = self.get_vertex_scale(self.position_temp)
- normals_scale = self.get_vertex_scale(self.normals_temp)
- texcoord_scale = self.get_vertex_scale(self.texcoord_temp)
-
- for x in range(0, len(self.position_temp), 3):
- self.position.append(self.position_temp[x: x + 3])
-
- for x in range(0, len(self.normals_temp), 3):
- self.normals.append(self.normals_temp[x: x + 3])
-
- for x in range(0, len(self.texcoord_temp), 2):
- self.texcoord.append(self.texcoord_temp[x: x + 2])
-
- self.parsed['geometries'].append({
- 'chunk_name': geometry_name,
- 'group': '',
- 'vertices': [
- {'type': 'POSITION', 'index': 0, 'scale': position_scale, 'vertex': self.position},
- {'type': 'NORMAL', 'index': 1, 'scale': normals_scale, 'vertex': self.normals},
- {'type': 'TEXCOORD', 'index': 2, 'scale': texcoord_scale, 'vertex': self.texcoord}
- ],
- 'have_bind_matrix': False,
- 'materials': [{'chunk_name': 'character_mat', 'polygons': self.polygons}]
- })
-
- # TODO: nodes
-
- @staticmethod
- def get_vertex_scale(vertex_data: list):
- vertex_scale = max(max(vertex_data), abs(min(vertex_data)))
- if vertex_scale < 1:
- vertex_scale = 1
- return vertex_scale
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/__init__.py b/3d-converter-0.8.0/models_converter/formats/scw/__init__.py
deleted file mode 100644
index cb85844..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from .writer import Writer
-from .parser import Parser
-
-__all__ = [
- 'Writer',
- 'Parser'
-]
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/__init__.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/__init__.py
deleted file mode 100644
index b8bd048..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from .chunk import Chunk
-from .head import HEAD
-from .mate import MATE
-from .geom import GEOM
-from .came import CAME
-from .node import NODE
-from .wend import WEND
-
-__all__ = [
- 'Chunk',
- 'HEAD',
- 'MATE',
- 'GEOM',
- 'CAME',
- 'NODE',
- 'WEND'
-]
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/came.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/came.py
deleted file mode 100644
index eb76959..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/came.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from . import Chunk
-
-
-class CAME(Chunk):
- def __init__(self, header=None):
- super().__init__(header)
- self.chunk_name = 'CAME'
-
- def parse(self, buffer: bytes):
- super().parse(buffer)
-
- setattr(self, 'name', self.readString())
- setattr(self, 'v1', self.readFloat())
- setattr(self, 'xFov', self.readFloat())
- setattr(self, 'aspectRatio', self.readFloat())
- setattr(self, 'zNear', self.readFloat())
- setattr(self, 'zFar', self.readFloat())
-
- def encode(self):
- super().encode()
-
- self.writeString(getattr(self, 'name'))
- self.writeFloat(getattr(self, 'v1'))
- self.writeFloat(getattr(self, 'xFov'))
- self.writeFloat(getattr(self, 'aspectRatio'))
- self.writeFloat(getattr(self, 'zNear'))
- self.writeFloat(getattr(self, 'zFar'))
-
- self.length = len(self.buffer)
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/chunk.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/chunk.py
deleted file mode 100644
index 4f28584..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/chunk.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from ....utils.reader import Reader
-from ....utils.writer import Writer
-
-
-class Chunk(Writer, Reader):
- def __init__(self, header=None):
- super().__init__()
-
- if header is None:
- header = {}
-
- self.header = header
- self.chunk_name = ''
-
- self.buffer = b''
- self.length = 0
-
- def from_dict(self, dictionary: dict):
- if dictionary:
- for key, value in dictionary.items():
- setattr(self, key, value)
-
- def to_dict(self) -> dict:
- dictionary = {}
- for key, value in self.__dict__.items():
- if key in ['header', 'buffer', 'length', 'endian', 'i']:
- continue
- if value is not None:
- attribute_name = key
- value_type = type(value)
-
- attribute_value = None
-
- if value_type is list:
- attribute_value = []
- for item in value:
- item_type = type(item)
-
- if issubclass(item_type, Chunk):
- item = item.to_dict()
- attribute_value.append(item)
- elif issubclass(value_type, Chunk):
- attribute_value = value.to_dict()
- elif attribute_value is None:
- attribute_value = value
-
- dictionary[attribute_name] = attribute_value
- return dictionary
-
- def __getitem__(self, key):
- if hasattr(self, key):
- return getattr(self, key)
- else:
- raise IndexError('The object has no attribute named ' + key)
-
- def __repr__(self) -> str:
- return f'<{self.__class__.__name__} ({self.to_dict()})>'
-
- def set(self, key: str, value):
- setattr(self, key, value)
-
- def parse(self, buffer: bytes):
- Reader.__init__(self, buffer, 'big')
-
- def encode(self):
- Writer.__init__(self, 'big')
-
- self.length = len(self.buffer)
-
- get = __getitem__
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/geom.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/geom.py
deleted file mode 100644
index ffa2c5d..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/geom.py
+++ /dev/null
@@ -1,268 +0,0 @@
-from . import Chunk
-
-
-class GEOM(Chunk):
- def __init__(self, header: dict):
- super().__init__(header)
- self.chunk_name = 'GEOM'
-
- def parse(self, buffer: bytes):
- super().parse(buffer)
-
- setattr(self, 'name', self.readString())
- setattr(self, 'group', self.readString())
- if self.header['version'] < 2:
- matrix = []
- for x in range(4):
- temp_list = []
- for x1 in range(4):
- temp_list.append(self.readFloat())
- matrix.append(temp_list)
-
- self.parse_vertices()
- self.parse_skin()
- self.parse_materials()
-
- def parse_vertices(self):
- vertices = []
- inputs = []
-
- vertex_count = self.readUByte()
- for x in range(vertex_count):
- vertex = []
- vertex_type = self.readString()
- vertex_index = self.readUByte()
- self.readUByte() # sub_index
- vertex_stride = self.readUByte()
- vertex_scale = self.readFloat()
- vertex_count = self.readUInt32()
-
- if vertex_type == 'VERTEX':
- vertex_type = 'POSITION'
-
- for x1 in range(vertex_count):
- coordinates_massive = []
- for x2 in range(vertex_stride):
- coordinate = self.readShort()
- coordinates_massive.append(coordinate / 32512)
- if vertex_type == 'TEXCOORD':
- coordinates_massive[1::2] = [1 - x for x in coordinates_massive[1::2]]
- vertex.append(coordinates_massive)
-
- inputs.append({
- 'type': vertex_type,
- 'offset': vertex_index,
- 'name': f'{vertex_type.lower()}_0'
- })
-
- vertices.append({
- 'name': f'{vertex_type.lower()}_0',
- 'type': vertex_type,
- 'index': vertex_index,
- 'scale': vertex_scale,
- 'vertex': vertex
- })
- setattr(self, 'inputs', inputs)
- setattr(self, 'vertices', vertices)
-
- def parse_skin(self):
- bind_matrix = []
-
- setattr(self, 'have_bind_matrix', self.readBool())
- if getattr(self, 'have_bind_matrix'):
- for x in range(16):
- bind_matrix.append(self.readFloat())
-
- setattr(self, 'bind_matrix', bind_matrix)
-
- self.parse_joints()
- self.parse_weights()
-
- def parse_joints(self):
- joints = []
-
- joint_counts = self.readUByte()
- for x in range(joint_counts):
- joint_matrix = []
- joint_name = self.readString()
- for x1 in range(16):
- joint_matrix.append(self.readFloat())
- joints.append({'name': joint_name, 'matrix': joint_matrix})
-
- setattr(self, 'joints', joints)
-
- def parse_weights(self):
- vertex_weights = []
- weights = []
- vcount = []
-
- vertex_weights_count = self.readUInt32()
- for x in range(vertex_weights_count):
- vcount.append(0)
- joint_a = self.readUByte()
- joint_b = self.readUByte()
- joint_c = self.readUByte()
- joint_d = self.readUByte()
- weight_a = self.readUShort()
- weight_b = self.readUShort()
- weight_c = self.readUShort()
- weight_d = self.readUShort()
- temp_list = [
- [joint_a, weight_a],
- [joint_b, weight_b],
- [joint_c, weight_c],
- [joint_d, weight_d]
- ]
- for pair in temp_list:
- if pair[1] != 0:
- vcount[x] += 1
- vertex_weights.append(pair[0])
- if pair[1] / 65535 not in weights:
- weights.append(pair[1] / 65535)
- vertex_weights.append(weights.index(pair[1] / 65535))
-
- setattr(self, 'weights',
- {
- 'vertex_weights': vertex_weights,
- 'weights': weights,
- 'vcount': vcount
- })
-
- def parse_materials(self):
- materials = []
-
- materials_count = self.readUByte()
- for x in range(materials_count):
- polygons = []
- material_name = self.readString()
- self.readString()
- polygons_count = self.readUShort()
- inputs_count = self.readUByte()
- vertex_id_length = self.readUByte()
- for x1 in range(polygons_count):
- temp_list = []
- for x2 in range(3):
- second_temp_list = []
- for x3 in range(inputs_count):
- second_temp_list.append(self.readUInteger(vertex_id_length))
- temp_list.append(second_temp_list)
- polygons.append(temp_list)
- materials.append({
- 'name': material_name,
- 'inputs': getattr(self, 'inputs'),
- 'polygons': polygons
- })
-
- setattr(self, 'materials', materials)
-
- def encode(self):
- super().encode()
-
- self.writeString(self.get('name'))
- self.writeString(self.get('group'))
-
- self.encode_vertices(self.get('vertices'))
-
- self.encode_skin()
-
- self.encode_materials()
-
- self.length = len(self.buffer)
-
- def encode_vertices(self, vertices: dict):
- self.writeUByte(len(vertices))
- for vertex in vertices:
- self.writeString(vertex['type'])
- self.writeUByte(vertex['index'])
- self.writeUByte(0) # sub_index
- self.writeUByte(len(vertex['vertex'][0]))
- self.writeFloat(vertex['scale'])
- self.writeUInt32(len(vertex['vertex']))
- for coordinates_massive in vertex['vertex']:
- if vertex['type'] == 'TEXCOORD':
- coordinates_massive[1::2] = [1 - x for x in coordinates_massive[1::2]]
- for coordinate in coordinates_massive:
- # coordinate /= vertex['scale']
- coordinate *= 32512
- self.writeShort(round(coordinate))
-
- def encode_skin(self):
- self.writeBool(self.get('have_bind_matrix'))
- if self.get('have_bind_matrix'):
- for x in self.get('bind_matrix'):
- self.writeFloat(x)
-
- self.encode_joints()
-
- self.encode_weight()
-
- def encode_joints(self):
- if self.get('have_bind_matrix'):
- self.writeUByte(len(self.get('joints')))
-
- for joint in self.get('joints'):
- self.writeString(joint['name'])
- for x in joint['matrix']:
- self.writeFloat(x)
- else:
- self.writeUByte(0)
-
- def encode_weight(self):
- if self.get('have_bind_matrix'):
- self.writeUInt32(len(self.get('weights')['vcount']))
- past_index = 0
- for vcount in self.get('weights')['vcount']:
- temp_list = []
- for x in range(vcount):
- vertex_weights_index = x * 2 + past_index * 2
- joint_id = self.get('weights')['vertex_weights'][vertex_weights_index]
- weight_id = self.get('weights')['vertex_weights'][vertex_weights_index + 1]
-
- weight = self.get('weights')['weights'][weight_id]
-
- if weight > 1:
- weight = 1
- elif weight < 0:
- weight = 0
-
- weight = int(weight * 65535)
-
- temp_list.append([joint_id, weight])
- past_index += vcount
- while len(temp_list) < 4:
- temp_list.append([0, 0])
- for x in temp_list:
- self.writeUByte(x[0])
- for x in temp_list:
- self.writeUShort(x[1])
- else:
- self.writeUInt32(0)
-
- def encode_materials(self):
- self.writeUByte(len(self.get('materials')))
- for material in self.get('materials'):
- self.writeString(material['name'])
- self.writeString('')
- self.writeUShort(len(material['polygons']))
-
- # Calculate settings
- inputs_count = len(material['polygons'][0][0])
-
- maximal_value = 0
- for points in material['polygons']:
- for point in points:
- for vertex in point:
- if vertex > maximal_value:
- maximal_value = vertex
-
- short_length = 1 if maximal_value <= 255 else 2
-
- # Write Settings
- self.writeUByte(inputs_count)
- self.writeUByte(short_length)
-
- # Write Polygons
- for points in material['polygons']:
- for point in points:
- for vertex in point:
- self.writeUInteger(vertex, short_length)
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/head.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/head.py
deleted file mode 100644
index 2b17bbe..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/head.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from . import Chunk
-
-
-class HEAD(Chunk):
- def __init__(self, header=None):
- super().__init__(header)
- self.chunk_name = 'HEAD'
-
- def parse(self, buffer: bytes):
- super().parse(buffer)
-
- setattr(self, 'version', self.readUShort())
- setattr(self, 'frame_rate', self.readUShort())
- setattr(self, 'v1', self.readUShort())
- setattr(self, 'v2', self.readUShort())
- setattr(self, 'materials_file', self.readString())
- if self.get('version') == 2:
- setattr(self, 'v3', self.readUByte())
-
- def encode(self):
- super().encode()
-
- self.writeUShort(2) # getattr(self, 'version')
- self.writeUShort(getattr(self, 'frame_rate'))
- self.writeUShort(0) # getattr(self, 'v1')
- self.writeUShort(249) # getattr(self, 'v2')
- self.writeString(getattr(self, 'materials_file'))
- self.writeUByte(0) # getattr(self, 'v3')
-
- self.length = len(self.buffer)
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/mate.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/mate.py
deleted file mode 100644
index a508caa..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/mate.py
+++ /dev/null
@@ -1,174 +0,0 @@
-from . import Chunk
-
-
-class MATE(Chunk):
- def __init__(self, header: dict):
- super().__init__(header)
- self.chunk_name = 'MATE'
-
- def parse(self, buffer: bytes):
- super().parse(buffer)
-
- setattr(self, 'name', self.readString())
- setattr(self, 'shader', self.readString())
- setattr(self, 'v1', self.readUByte())
- setattr(self, 'v2', self.readUByte())
-
- effect = {}
- a = self.readUByte()
- r = self.readUByte()
- g = self.readUByte()
- b = self.readUByte()
- ambient_color = (r, g, b, a)
- effect['ambient'] = ambient_color
-
- use_diffuse_tex = self.readBool()
- if use_diffuse_tex:
- diffuse_tex = self.readString()
- effect['diffuse'] = diffuse_tex
- else:
- a = self.readUByte()
- r = self.readUByte()
- g = self.readUByte()
- b = self.readUByte()
- diffuse_color = (r, g, b, a)
- effect['diffuse'] = diffuse_color
-
- use_specular_tex = self.readBool()
- if use_specular_tex:
- specular_tex = self.readString()
- effect['specular'] = specular_tex
- else:
- a = self.readUByte()
- r = self.readUByte()
- g = self.readUByte()
- b = self.readUByte()
- specular_color = (r, g, b, a)
- effect['specular'] = specular_color
-
- setattr(self, 'v3', self.readString())
- setattr(self, 'v4', self.readString())
-
- use_colorize_tex = self.readBool()
- if use_colorize_tex:
- colorize_tex = self.readString()
- effect['colorize'] = colorize_tex
- else:
- a = self.readUByte()
- r = self.readUByte()
- g = self.readUByte()
- b = self.readUByte()
- colorize_color = (r, g, b, a)
- effect['colorize'] = colorize_color
-
- use_emission_tex = self.readBool()
- if use_emission_tex:
- emission_tex = self.readString()
- effect['emission'] = emission_tex
- else:
- a = self.readUByte()
- r = self.readUByte()
- g = self.readUByte()
- b = self.readUByte()
- emission_color = (r, g, b, a)
- effect['emission'] = emission_color
-
- setattr(self, 'opacity_texture', self.readString())
- setattr(self, 'v5', self.readFloat())
- setattr(self, 'v6', self.readFloat())
-
- effect['lightmaps'] = {
- 'diffuse': self.readString(),
- 'specular': self.readString()
- }
-
- if self.header['version'] == 2:
- setattr(self, 'v7', self.readString())
-
- shader_define_flags = self.readUInt32()
- effect['shader_define_flags'] = shader_define_flags
-
- if shader_define_flags & 32768:
- self.readFloat()
- self.readFloat()
- self.readFloat()
- self.readFloat()
-
- setattr(self, 'effect', effect)
-
- def encode(self):
- super().encode()
-
- self.writeString(getattr(self, 'name'))
- self.writeString(getattr(self, 'shader'))
- self.writeUByte(4) # getattr(self, 'v1')
- self.writeUByte(0) # getattr(self, 'v2')
-
- effect = getattr(self, 'effect')
- r, g, b, a = effect['ambient']
- self.writeUByte(a)
- self.writeUByte(r)
- self.writeUByte(g)
- self.writeUByte(b)
-
- use_diffuse_tex = type(effect['diffuse']) is str
- self.writeBool(use_diffuse_tex)
- if use_diffuse_tex:
- self.writeString(effect['diffuse'])
- else:
- r, g, b, a = effect['diffuse']
- self.writeUByte(a)
- self.writeUByte(r)
- self.writeUByte(g)
- self.writeUByte(b)
-
- use_specular_tex = type(effect['specular']) is str
- self.writeBool(use_specular_tex)
- if use_specular_tex:
- self.writeString(effect['specular'])
- else:
- r, g, b, a = effect['specular']
- self.writeUByte(a)
- self.writeUByte(r)
- self.writeUByte(g)
- self.writeUByte(b)
-
- self.writeString('.') # getattr(self, 'v3')
- self.writeString('') # getattr(self, 'v4')
-
- use_colorize_tex = type(effect['colorize']) is str
- self.writeBool(use_colorize_tex)
- if use_colorize_tex:
- self.writeString(effect['colorize'])
- else:
- r, g, b, a = effect['colorize']
- self.writeUByte(a)
- self.writeUByte(r)
- self.writeUByte(g)
- self.writeUByte(b)
-
- use_emission_tex = type(effect['emission']) is str
- self.writeBool(use_emission_tex)
- if use_emission_tex:
- self.writeString(effect['emission'])
- else:
- r, g, b, a = effect['emission']
- self.writeUByte(a)
- self.writeUByte(r)
- self.writeUByte(g)
- self.writeUByte(b)
-
- self.writeString(getattr(self, 'opacity_texture'))
- self.writeFloat(1) # getattr(self, 'v5')
- self.writeFloat(0) # getattr(self, 'v6')
-
- self.writeString(effect['lightmaps']['diffuse'])
- self.writeString(effect['lightmaps']['specular'])
-
- if self.header['version'] == 2:
- self.writeString(getattr(self, 'v7'))
-
- self.writeUInt32(effect['shader_define_flags'])
-
- self.length = len(self.buffer)
-
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/node.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/node.py
deleted file mode 100644
index b76ae33..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/node.py
+++ /dev/null
@@ -1,145 +0,0 @@
-from . import Chunk
-
-
-class NODE(Chunk):
- def __init__(self, header: dict):
- super().__init__(header)
- self.chunk_name = 'NODE'
-
- def parse(self, buffer: bytes):
- super().parse(buffer)
- nodes = []
-
- nodes_count = self.readUShort()
- for node in range(nodes_count):
- node_data = {
- 'name': self.readString(),
- 'parent': self.readString()
- }
-
- instances_count = self.readUShort()
- node_data['instances'] = [{}] * instances_count
- for x in range(instances_count):
- instance_type = self.readChar(4)
- instance_name = self.readString()
-
- node_data['instances'][x] = {}
- if instance_type in ['GEOM', 'CONT']:
- materials_count = self.readUShort()
- binds = []
- for bind in range(materials_count):
- binds.append({})
- symbol = self.readString()
- target = self.readString()
- binds[bind] = {'symbol': symbol,
- 'target': target}
- node_data['instances'][x]['binds'] = binds
- elif instance_type in ['CAME']:
- target = self.readString()
- node_data['instances'][x]['target'] = target
- node_data['instances'][x]['instance_name'] = instance_name
- node_data['instances'][x]['instance_type'] = instance_type
-
- frames_count = self.readUShort()
- node_data['frames'] = []
- if frames_count > 0:
- rotation = {'x': 0, 'y': 0, 'z': 0, 'w': 0}
- scale_x, scale_y, scale_z = 0, 0, 0
- pos_x, pos_y, pos_z = 0, 0, 0
-
- settings = list(bin(self.readUByte())[2:].zfill(8))
- settings = [bool(int(value)) for value in settings]
- node_data['frames_settings'] = settings
- for frame in range(frames_count):
- frame_data = {
- 'frame_id': self.readUShort()
- }
-
- if settings[7] or frame == 0: # Rotation
- rotation = {
- 'x': self.readNShort(),
- 'y': self.readNShort(),
- 'z': self.readNShort(),
- 'w': self.readNShort()
- }
-
- if settings[4] or frame == 0: # Position X
- pos_x = self.readFloat()
- if settings[5] or frame == 0: # Position Y
- pos_y = self.readFloat()
- if settings[6] or frame == 0: # Position Z
- pos_z = self.readFloat()
-
- if settings[1] or frame == 0: # Scale X
- scale_x = self.readFloat()
- if settings[2] or frame == 0: # Scale Y
- scale_y = self.readFloat()
- if settings[3] or frame == 0: # Scale Z
- scale_z = self.readFloat()
-
- frame_data['rotation'] = rotation
- frame_data['position'] = {
- 'x': pos_x,
- 'y': pos_y,
- 'z': pos_z
- }
- frame_data['scale'] = {
- 'x': scale_x,
- 'y': scale_y,
- 'z': scale_z
- }
-
- node_data['frames'].append(frame_data)
- nodes.append(node_data)
- setattr(self, 'nodes', nodes)
-
- def encode(self):
- super().encode()
-
- self.writeUShort(len(self.get('nodes')))
- for node in self.get('nodes'):
- self.writeString(node['name'])
- self.writeString(node['parent'])
-
- self.writeUShort(len(node['instances']))
- for instance in node['instances']:
- self.writeChar(instance['instance_type'])
- self.writeString(instance['instance_name'])
- self.writeUShort(len(instance['binds']))
- for bind in instance['binds']:
- self.writeString(bind['symbol'])
- self.writeString(bind['target'])
-
- if 'frames_settings' in node:
- frames_settings = node['frames_settings']
- else:
- frames_settings = None
- self.encode_frames(node['frames'], frames_settings)
-
- self.length = len(self.buffer)
-
- def encode_frames(self, frames, frames_settings):
- self.writeUShort(len(frames))
- if len(frames) > 0:
- self.writeUByte(int(''.join([('1' if item else '0') for item in frames_settings])[::], 2))
- for frame in frames:
- self.writeUShort(frame['frame_id'])
- if frames_settings[7] or frames.index(frame) == 0: # Rotation
- self.writeNShort(frame['rotation']['x'])
- self.writeNShort(frame['rotation']['y'])
- self.writeNShort(frame['rotation']['z'])
- self.writeNShort(frame['rotation']['w'])
-
- if frames_settings[4] or frames.index(frame) == 0: # Position X
- self.writeFloat(frame['position']['x'])
- if frames_settings[5] or frames.index(frame) == 0: # Position Y
- self.writeFloat(frame['position']['y'])
- if frames_settings[6] or frames.index(frame) == 0: # Position Z
- self.writeFloat(frame['position']['z'])
-
- if frames_settings[1] or frames.index(frame) == 0: # Scale X
- self.writeFloat(frame['scale']['x'])
- if frames_settings[2] or frames.index(frame) == 0: # Scale Y
- self.writeFloat(frame['scale']['y'])
- if frames_settings[3] or frames.index(frame) == 0: # Scale Z
- self.writeFloat(frame['scale']['z'])
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/chunks/wend.py b/3d-converter-0.8.0/models_converter/formats/scw/chunks/wend.py
deleted file mode 100644
index 0252602..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/chunks/wend.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from . import Chunk
-
-
-class WEND(Chunk):
- def __init__(self, header=None):
- super().__init__(header)
- self.chunk_name = 'WEND'
-
- def parse(self, buffer: bytes):
- super().parse(buffer)
-
- def encode(self):
- super().encode()
-
- self.length = len(self.buffer)
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/parser.py b/3d-converter-0.8.0/models_converter/formats/scw/parser.py
deleted file mode 100644
index df8649f..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/parser.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from ...utils.reader import Reader
-from .chunks import *
-
-
-class Parser(Reader):
- def __init__(self, file_data: bytes):
- super().__init__(file_data)
- self.file_data = file_data
- self.parsed = {
- 'header': {},
- 'materials': [],
- 'geometries': [],
- 'cameras': [],
- 'nodes': []
- }
- self.chunks = []
-
- file_magic = self.read(4)
- if file_magic != b'SC3D':
- raise TypeError('File Magic isn\'t "SC3D"')
-
- def split_chunks(self):
- # len(Chunk Length) + len(Chunk Name) + len(Chunk CRC)
- while len(self.file_data[self.tell():]) >= 12:
- chunk_length = self.readUInt32()
- chunk_name = self.readChar(4)
- chunk_data = self.read(chunk_length)
- chunk_crc = self.readUInt32()
-
- self.chunks.append({
- 'chunk_name': chunk_name,
- 'data': chunk_data,
- 'crc': chunk_crc
- })
-
- def parse(self):
- for chunk in self.chunks:
- chunk_name = chunk['chunk_name']
- chunk_data = chunk['data']
-
- if chunk_name == 'HEAD':
- head = HEAD()
- head.parse(chunk_data)
-
- self.parsed['header'] = head.to_dict()
- elif chunk_name == 'MATE':
- mate = MATE(self.parsed['header'])
- mate.parse(chunk_data)
- self.parsed['materials'].append(mate.to_dict())
- elif chunk_name == 'GEOM':
- geom = GEOM(self.parsed['header'])
- geom.parse(chunk_data)
- self.parsed['geometries'].append(geom.to_dict())
- elif chunk_name == 'CAME':
- came = CAME(self.parsed['header'])
- came.parse(chunk_data)
- self.parsed['cameras'].append(came.to_dict())
- elif chunk_name == 'NODE':
- node = NODE(self.parsed['header'])
- node.parse(chunk_data)
- self.parsed['nodes'] = node.to_dict()['nodes']
- elif chunk_name == 'WEND':
- wend = WEND()
- wend.parse(chunk_data)
- else:
- raise TypeError(f'Unknown chunk: {chunk_name}')
diff --git a/3d-converter-0.8.0/models_converter/formats/scw/writer.py b/3d-converter-0.8.0/models_converter/formats/scw/writer.py
deleted file mode 100644
index b55efb2..0000000
--- a/3d-converter-0.8.0/models_converter/formats/scw/writer.py
+++ /dev/null
@@ -1,51 +0,0 @@
-import binascii
-
-from .chunks import *
-
-
-class Writer:
- def __init__(self):
- self.writen = b'SC3D'
-
- def write(self, data: dict):
-
- header = data['header']
- head = HEAD()
- head.from_dict(header)
-
- self.write_chunk(head)
-
- # TODO: materials
- for material in data['materials']:
- mate = MATE(header)
- mate.from_dict(material)
-
- self.write_chunk(mate)
-
- for geometry in data['geometries']:
- geom = GEOM(header)
- geom.from_dict(geometry)
-
- self.write_chunk(geom)
-
- # TODO: cameras
- for camera in data['cameras']:
- came = CAME(header)
- came.from_dict(camera)
-
- self.write_chunk(came)
-
- node = NODE(header)
- node.from_dict({'nodes': data['nodes']})
-
- self.write_chunk(node)
-
- wend = WEND()
-
- self.write_chunk(wend)
-
- def write_chunk(self, chunk: Chunk):
- chunk.encode()
-
- self.writen += chunk.length.to_bytes(4, 'big') + chunk.chunk_name.encode('utf-8') + chunk.buffer
- self.writen += binascii.crc32(chunk.chunk_name.encode('utf-8') + chunk.buffer).to_bytes(4, 'big')
diff --git a/3d-converter-0.8.0/models_converter/utils/__init__.py b/3d-converter-0.8.0/models_converter/utils/__init__.py
deleted file mode 100644
index 87b30e1..0000000
--- a/3d-converter-0.8.0/models_converter/utils/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-__all__ = [
- 'reader',
- 'writer',
- 'matrix'
-]
diff --git a/3d-converter-0.8.0/models_converter/utils/reader.py b/3d-converter-0.8.0/models_converter/utils/reader.py
deleted file mode 100644
index ddf0668..0000000
--- a/3d-converter-0.8.0/models_converter/utils/reader.py
+++ /dev/null
@@ -1,119 +0,0 @@
-class Reader:
- def __init__(self, buffer: bytes, endian: str = 'big'):
- self.buffer = buffer
- self.endian = endian
- self.i = 0
-
- def read(self, length: int = 1) -> bytes:
- result = self.buffer[self.i:self.i + length]
- self.i += length
-
- return result
-
- def readUInteger(self, length: int = 1) -> int:
- result = 0
- for x in range(length):
- byte = self.buffer[self.i]
-
- bit_padding = x * 8
- if self.endian == 'big':
- bit_padding = (8 * (length - 1)) - bit_padding
-
- result |= byte << bit_padding
- self.i += 1
-
- return result
-
- def readInteger(self, length: int = 1) -> int:
- integer = self.readUInteger(length)
- result = integer
- if integer > 2 ** (length * 8) / 2:
- result -= 2 ** (length * 8)
- return result
-
- def readUInt64(self) -> int:
- return self.readUInteger(8)
-
- def readInt64(self) -> int:
- return self.readInteger(8)
-
- def readFloat(self) -> float:
- as_int = self.readUInt32()
- binary = bin(as_int)
- binary = binary[2:].zfill(32)
-
- sign = -1 if binary[0] == '1' else 1
- exponent = int(binary[1:9], 2) - 127
- mantissa_base = binary[9:]
- mantissa_bin = '1' + mantissa_base
- mantissa = 0
- val = 1
-
- if exponent == -127:
- if mantissa_base[1] == -1:
- return 0
- else:
- exponent = -126
- mantissa_bin = '0' + mantissa_base
-
- for char in mantissa_bin:
- mantissa += val * int(char)
- val = val / 2
-
- result = sign * 2 ** exponent * mantissa
- return result
-
- def readUInt32(self) -> int:
- return self.readUInteger(4)
-
- def readInt32(self) -> int:
- return self.readInteger(4)
-
- def readNUInt16(self) -> float:
- return self.readUInt16() / 65535
-
- def readUInt16(self) -> int:
- return self.readUInteger(2)
-
- def readNInt16(self) -> float:
- return self.readInt16() / 32512
-
- def readInt16(self) -> int:
- return self.readInteger(2)
-
- def readUInt8(self) -> int:
- return self.readUInteger()
-
- def readInt8(self) -> int:
- return self.readInteger()
-
- def readBool(self) -> bool:
- if self.readUInt8() >= 1:
- return True
- else:
- return False
-
- readUInt = readUInteger
- readInt = readInteger
-
- readULong = readUInt64
- readLong = readInt64
-
- readNUShort = readNUInt16
- readNShort = readNInt16
-
- readUShort = readUInt16
- readShort = readInt16
-
- readUByte = readUInt8
- readByte = readInt8
-
- def readChar(self, length: int = 1) -> str:
- return self.read(length).decode('utf-8')
-
- def readString(self) -> str:
- length = self.readUShort()
- return self.readChar(length)
-
- def tell(self) -> int:
- return self.i
diff --git a/3d-converter-0.8.0/setup.py b/3d-converter-0.8.0/setup.py
deleted file mode 100644
index 9db5ce4..0000000
--- a/3d-converter-0.8.0/setup.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import setuptools
-
-with open('README.md') as fh:
- long_description = fh.read()
- fh.close()
-
-setuptools.setup(
- name='3d-converter',
- version='0.8.0',
- author='Vorono4ka',
- author_email='crowo4ka@gmail.com',
- description='Python 3D Models Converter',
- long_description=long_description,
- long_description_content_type='text/markdown',
- url='https://github.com/vorono4ka/3d-converter',
- license='GPLv3',
- packages=setuptools.find_packages(),
- classifiers=[
- 'Programming Language :: Python :: 3',
- 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
- 'Operating System :: OS Independent',
- ],
- python_requires='>=3.7',
-)
diff --git a/3d_converter.egg-info/PKG-INFO b/3d_converter.egg-info/PKG-INFO
index 8ac1aac..c785db6 100644
--- a/3d_converter.egg-info/PKG-INFO
+++ b/3d_converter.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: 3d-converter
-Version: 0.8.1
+Version: 0.8.5
Summary: Python 3D Models Converter
Home-page: https://github.com/vorono4ka/3d-converter
Author: Vorono4ka
@@ -8,7 +8,7 @@ Author-email: crowo4ka@gmail.com
License: GPLv3
Description: ## `Python 3D Models Converter`
- **Version**: 0.8.1
+ **Version**: 0.8.5
### Thanks a lot for motivating [AMIRMISTIK]!
diff --git a/3d_converter.egg-info/SOURCES.txt b/3d_converter.egg-info/SOURCES.txt
index 922e012..cf33c16 100644
--- a/3d_converter.egg-info/SOURCES.txt
+++ b/3d_converter.egg-info/SOURCES.txt
@@ -1,3 +1,4 @@
+LICENSE
README.md
setup.py
3d_converter.egg-info/PKG-INFO
@@ -7,8 +8,27 @@ setup.py
models_converter/__init__.py
models_converter/formats/__init__.py
models_converter/formats/dae.py
-models_converter/formats/gltf.py
models_converter/formats/obj.py
+models_converter/formats/gltf/__init__.py
+models_converter/formats/gltf/accessor.py
+models_converter/formats/gltf/animation.py
+models_converter/formats/gltf/asset.py
+models_converter/formats/gltf/buffer.py
+models_converter/formats/gltf/buffer_view.py
+models_converter/formats/gltf/camera.py
+models_converter/formats/gltf/chunk.py
+models_converter/formats/gltf/gltf.py
+models_converter/formats/gltf/gltf_property.py
+models_converter/formats/gltf/image.py
+models_converter/formats/gltf/material.py
+models_converter/formats/gltf/mesh.py
+models_converter/formats/gltf/node.py
+models_converter/formats/gltf/parser.py
+models_converter/formats/gltf/sampler.py
+models_converter/formats/gltf/scene.py
+models_converter/formats/gltf/skin.py
+models_converter/formats/gltf/texture.py
+models_converter/formats/gltf/texture_info.py
models_converter/formats/scw/__init__.py
models_converter/formats/scw/parser.py
models_converter/formats/scw/writer.py
diff --git a/README.md b/README.md
index 6f2fcc1..d249ccf 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
## `Python 3D Models Converter`
-**Version**: 0.8.1
+**Version**: 0.8.5
### Thanks a lot for motivating [AMIRMISTIK]!
diff --git a/models_converter/formats/dae.py b/models_converter/formats/dae.py
index 1792769..5cc442f 100644
--- a/models_converter/formats/dae.py
+++ b/models_converter/formats/dae.py
@@ -285,6 +285,22 @@ def write(self, data: dict):
id='3dConverterScene',
name='3d-Converter Scene')
+ not_joint_nodes = []
+ node_index = 0
+
+ parent_name = None
+ while node_index < len(not_joint_nodes) or len(not_joint_nodes) == 0:
+ if len(not_joint_nodes) > 0:
+ parent_name = not_joint_nodes[node_index]
+
+ for _node in data['nodes']:
+ if _node['instances'] or _node['name'] == parent_name:
+ if not (_node['name'] in not_joint_nodes):
+ not_joint_nodes.append(_node['name'])
+ if not (_node['parent'] in not_joint_nodes):
+ not_joint_nodes.append(_node['parent'])
+ node_index += 1
+
for node_data in data['nodes']:
parent_name = node_data['parent']
parent = visual_scene
@@ -318,7 +334,7 @@ def write(self, data: dict):
symbol=symbol,
target=f'#{target}')
else:
- if parent_name != '' and len(node_data['instances']) == 0:
+ if not (node_data['name'] in not_joint_nodes):
node.attrib['type'] = 'JOINT'
#
diff --git a/models_converter/formats/gltf.py b/models_converter/formats/gltf.py
deleted file mode 100644
index 281da6b..0000000
--- a/models_converter/formats/gltf.py
+++ /dev/null
@@ -1,779 +0,0 @@
-import json
-
-from models_converter.formats.dae import Writer
-from models_converter.utils.reader import Reader
-
-
-def to_camelcase(property_name: str):
- words = property_name.split('_')
- for word_index in range(len(words)):
- word = words[word_index]
- if word_index > 0:
- word = list(word)
- word[0] = word[0].upper()
-
- word = ''.join(word)
-
- words[word_index] = word
- camelcase_name = ''.join(words)
- return camelcase_name
-
-
-def to_lowercase(property_name: str):
- letters = list(property_name)
-
- for letter_index in range(len(letters)):
- letter = letters[letter_index]
-
- if letter.isupper():
- letter = f'_{letter.lower()}'
-
- letters[letter_index] = letter
-
- lowercase_name = ''.join(letters)
- return lowercase_name
-
-
-def get_data_from_dict(dictionary, key, default=None):
- if key in dictionary:
- return dictionary[key]
- return default
-
-
-from_dict = get_data_from_dict
-
-
-class GlTFProperty:
- def __init__(self):
- self.extensions = None
- self.extras = None
-
- def from_dict(self, dictionary: dict):
- if dictionary:
- for key, value in dictionary.items():
- attribute_name = to_lowercase(key)
- value_type = type(value)
-
- attribute_value = getattr(self, attribute_name)
- attribute_value_type = type(attribute_value)
-
- if attribute_value is None or value_type in [int, str]:
- attribute_value = value
- elif issubclass(attribute_value_type, GlTFProperty):
- if value_type is list:
- value_type = attribute_value_type
- values = []
-
- for item in value:
- new_value = value_type()
- new_value.from_dict(item)
-
- values.append(new_value)
-
- attribute_value = values
- else:
- attribute_value = attribute_value_type()
- attribute_value.from_dict(value)
-
- setattr(self, attribute_name, attribute_value)
-
- def to_dict(self) -> dict:
- dictionary = {}
- for key, value in self.__dict__.items():
- if value is not None:
- attribute_name = to_camelcase(key)
- value_type = type(value)
-
- attribute_value = None
-
- if value_type is list:
- attribute_value = []
- for item in value:
- item_type = type(item)
-
- if issubclass(item_type, GlTFProperty):
- item = item.to_dict()
- attribute_value.append(item)
- elif issubclass(value_type, GlTFProperty):
- attribute_value = value.to_dict()
- elif attribute_value is None:
- attribute_value = value
-
- dictionary[attribute_name] = attribute_value
- return dictionary
-
- def __getitem__(self, item):
- item = to_lowercase(item)
- if hasattr(self, item):
- return getattr(self, item)
- else:
- raise IndexError('The object has no attribute named ' + item)
-
- def __repr__(self) -> str:
- return f'<{self.__class__.__name__} ({self.to_dict()})>'
-
-
-class Accessor(GlTFProperty):
- class Sparse(GlTFProperty):
- class Indices(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.buffer_view = None
- self.component_type = None
-
- self.byte_offset = 0
-
- class Values(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.buffer_view = None
-
- self.byte_offset = 0
-
- def __init__(self):
- super().__init__()
- self.count = None
- self.indices = self.Indices()
- self.values = self.Values()
-
- def __init__(self):
- super().__init__()
- self.component_type = None
- self.count = None
- self.type = None
-
- self.buffer_view = None
- self.byte_offset = 0
- self.normalized = False
- self.max = None
- self.min = None
- self.sparse = self.Sparse()
- self.name = None
-
-
-class Animation(GlTFProperty):
- class AnimationSampler(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.input = None
- self.output = None
-
- self.interpolation = None # Default: 'LINEAR'
-
- class Channel(GlTFProperty):
- class Target(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.path = None
-
- self.node = None
-
- def __init__(self):
- super().__init__()
- self.sampler = None
- self.target = self.Target()
-
- def __init__(self):
- super().__init__()
- self.channels = self.Channel()
- self.samplers = self.AnimationSampler()
-
- self.name = None
-
-
-class Asset(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.version = None
-
- self.copyright = None
- self.generator = None
- self.min_version = None
-
-
-class Buffer(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.byte_length = None
-
- self.uri = None
- self.name = None
-
-
-class BufferView(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.buffer = None
- self.byte_length = None
-
- self.byte_offset = 0
- self.byte_stride = None
- self.target = None
- self.name = None
-
-
-class Camera(GlTFProperty):
- class Orthographic(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.xmag = None
- self.ymag = None
- self.zfar = None
- self.znear = None
-
- class Perspective(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.yfov = None
- self.znear = None
-
- self.aspect_ratio = None
- self.zfar = None
-
- def __init__(self):
- super().__init__()
- self.type = None
-
- self.orthographic = None
- self.perspective = None
- self.name = None
-
-
-class Image(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.uri = None
- self.mime_type = None
- self.buffer_view = None
- self.name = None
-
-
-class Material(GlTFProperty):
- class NormalTextureInfo(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.index = None
-
- self.tex_coord = None # Default: 0
- self.scale = None # Default: 1
-
- class OcclusionTextureInfo(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.index = None
-
- self.tex_coord = None # Default: 0
- self.strength = None # Default: 1
-
- class PbrMetallicRoughness(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.base_color_factor = None # Default: [1, 1, 1, 1]
- self.base_color_texture = None
- self.metallic_factor = None # Default: 1
- self.roughness_factor = None # Default: 1
- self.metallic_roughness_texture = None
-
- def __init__(self):
- super().__init__()
- self.name = None
- self.pbr_metallic_roughness = None
- self.normal_texture = None
- self.occlusion_texture = None
- self.emissive_texture = None
- self.emissive_factor = None # Default: [0, 0, 0]
- self.alpha_mode = None # Default: 'OPAQUE'
- self.alpha_cutoff = None # Default: 0.5
- self.double_sided = None # Default: False
-
-
-class Mesh(GlTFProperty):
- class Primitive(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.attributes = None
-
- self.indices = None
- self.material = None
- self.mode = None # Default: 4
- self.targets = None
-
- def __init__(self):
- super().__init__()
- self.primitives = self.Primitive()
-
- self.weights = None
- self.name = None
-
-
-class Node(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.camera = None
- self.children = None
- self.skin = None
- self.matrix = None # Default: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
- self.mesh = None
- self.rotation = None # Default: [0, 0, 0, 1]
- self.scale = None # Default: [1, 1, 1]
- self.translation = None # Default: [0, 0, 0]
- self.weights = None
- self.name = None
-
-
-class Sampler(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.mag_filter = None
- self.min_filter = None
- self.wrap_s = None # Default: 10497
- self.wrap_t = None # Default: 10497
- self.name = None
-
-
-class Scene(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.nodes = None
- self.name = None
-
-
-class Skin(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.joints = None
-
- self.inverse_bind_matrices = None
- self.skeleton = None
- self.name = None
-
-
-class Texture(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.sampler = None
- self.source = None
- self.name = None
-
-
-class TextureInfo(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.index = None
-
- self.tex_coord = None # Default: 0
-
-
-class GlTF(GlTFProperty):
- def __init__(self):
- super().__init__()
- self.asset = Asset()
-
- self.extensions_used = None
- self.extensions_required = None
-
- self.accessors = Accessor()
- self.animations = Animation()
- self.buffers = Buffer()
- self.buffer_views = BufferView()
- self.cameras = Camera()
- self.images = Image()
- self.materials = Material()
- self.meshes = Mesh()
- self.nodes = Node()
- self.samplers = Sampler()
- self.scene = None
- self.scenes = Scene()
- self.skins = Skin()
- self.textures = Texture()
-
-
-class GlTFChunk:
- def __init__(self):
- self.chunk_length = 0
- self.chunk_name = b''
- self.data = b''
-
-
-class Parser(Reader):
- def __init__(self, initial_bytes: bytes):
- super().__init__(initial_bytes, 'little')
-
- self.magic = self.read(4)
- if self.magic != b'glTF':
- raise TypeError('File Magic isn\'t "glTF"')
-
- self.parsed = {
- 'header': {
- 'frame_rate': 30
- },
- 'materials': [],
- 'geometries': [],
- 'cameras': [],
- 'nodes': []
- }
-
- self.version = None
- self.length = None
-
- self.json_chunk = None
- self.bin_chunk = None
-
- self.buffer_views = []
- self.accessors = []
- self.buffers = []
-
- self.gltf = GlTF()
-
- def parse_bin(self):
- super().__init__(self.bin_chunk.data, 'little')
-
- for buffer in self.gltf.buffers:
- parsed_buffer = self.read(buffer.byte_length)
- self.buffers.append(parsed_buffer)
-
- for buffer_view in self.gltf.buffer_views:
- super().__init__(self.buffers[buffer_view.buffer], 'little')
-
- self.read(buffer_view.byte_offset)
-
- length = buffer_view.byte_length
- data = self.read(length)
-
- self.buffer_views.append(data)
-
- for accessor in self.gltf.accessors:
- super().__init__(self.buffer_views[accessor.buffer_view], '<')
- temp_accessor = []
-
- self.read(accessor.byte_offset)
-
- types = {
- 5120: self.readByte,
- 5121: self.readUByte,
- 5122: self.readShort,
- 5123: self.readUShort,
- 5125: self.readUInt32,
- 5126: self.readFloat
- }
-
- items_count = {
- 'SCALAR': 1,
- 'VEC2': 2,
- 'VEC3': 3,
- 'VEC4': 4,
- 'MAT2': 4,
- 'MAT3': 9,
- 'MAT4': 16
- }
-
- for x in range(accessor.count):
- temp_list = []
- for i in range(items_count[accessor.type]):
- temp_list.append(types[accessor.component_type]())
- temp_accessor.append(temp_list)
-
- if accessor.normalized:
- for item_index, data in enumerate(temp_accessor):
- new_data = []
- for item in data:
- if accessor['component_type'] == 5120:
- new_data.append(max(item / 127, -1.0))
- elif accessor['component_type'] == 5121:
- new_data.append(item / 255)
- elif accessor['component_type'] == 5122:
- new_data.append(max(item / 32767, -1.0))
- elif accessor['component_type'] == 5123:
- new_data.append(item / 65535)
- else:
- new_data.append(item)
- temp_accessor[item_index] = new_data
-
- self.accessors.append(temp_accessor)
-
- def parse(self):
- #
-
- self.version = self.readUInt32()
- self.length = self.readUInt32()
-
- self.json_chunk = GlTFChunk()
- self.bin_chunk = GlTFChunk()
-
- self.json_chunk.chunk_length = self.readUInt32()
- self.json_chunk.chunk_name = self.read(4)
- self.json_chunk.data = self.read(self.json_chunk.chunk_length)
-
- self.bin_chunk.chunk_length = self.readUInt32()
- self.bin_chunk.chunk_name = self.read(4)
- self.bin_chunk.data = self.read(self.bin_chunk.chunk_length)
-
- #
-
- self.gltf.from_dict(json.loads(self.json_chunk.data))
-
- self.parse_bin()
-
- #
-
- scene_id = self.gltf.scene
- scene = self.gltf.scenes[scene_id]
-
- for node_id in scene.nodes:
- node = self.gltf.nodes[node_id]
- self.parse_node(node)
-
- #
-
- def parse_node(self, node: Node, parent: str = None):
- node_name = node.name
- # node_name = node_name.split('|')
- # if len(node_name) > 1:
- # node_name = node_name[1]
- # parent = node_name[0]
- # else:
- # node_name = node_name[0]
-
- # node_name = node_name.split(':')
- # if len(node_name) > 1:
- # if node_name[1] == 'PIV':
- # print(node.name, node.translation)
- # # else:
- # print(node)
- # node_name = node_name[0]
- # else:
- # node_name = node_name[0]
-
- node_data = {
- 'name': node_name,
- 'parent': parent,
- 'has_target': False,
- 'frames': []
- }
-
- if node.mesh:
- node_data['has_target'] = True
- node_data['target_type'] = 'GEOM'
-
- geometry_data = {
- 'name': '',
- 'group': '',
- 'vertices': [],
- 'have_bind_matrix': False,
- 'weights': {
- 'vertex_weights': [],
- 'weights': [],
- 'vcount': []
- },
- 'materials': []
- }
-
- if node.skin:
- geometry_data['have_bind_matrix'] = True
- geometry_data['bind_matrix'] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
- geometry_data['joints'] = []
- node_data['target_type'] = 'CONT'
-
- skin_id = node.skin
- skin = self.gltf.skins[skin_id]
- bind_matrices = self.accessors[skin.inverse_bind_matrices]
-
- for joint in skin.joints:
- joint_index = skin['joints'].index(joint)
- joint_node = self.gltf.nodes[joint]
- joint_name = joint_node['name']
- matrix = bind_matrices[joint_index]
-
- joint_data = {
- 'name': joint_name,
- 'matrix': matrix
- }
- geometry_data['joints'].append(joint_data)
-
- mesh_id = node.mesh
- mesh = self.gltf.meshes[mesh_id]
- mesh_name = mesh.name
- mesh_name = mesh_name.split('|')
-
- if len(mesh_name) > 1:
- geometry_data['group'] = mesh_name[0]
- geometry_data['name'] = mesh_name[1]
- else:
- geometry_data['name'] = mesh_name[0]
-
- node_data['target'] = geometry_data['name']
- node_data['binds'] = []
-
- offsets = {
- 'POSITION': 0,
- 'NORMAL': 0,
- 'TEXCOORD': 0
- }
-
- for primitive in mesh.primitives:
- if primitive.to_dict() != {}:
- primitive_index = mesh.primitives.index(primitive)
- attributes = primitive.attributes
- material_id = primitive.material
- polygons_id = primitive.indices
-
- inputs = []
-
- polygons = self.accessors[polygons_id]
- material = self.gltf.materials[material_id]
-
- material_name = material.extensions['SC_shader']['name']
- node_data['binds'].append({
- 'symbol': material_name,
- 'target': material_name
- })
-
- for attribute_id in attributes:
- attribute = attributes[attribute_id]
- if attribute_id == 'POSITION':
- position = self.accessors[attribute]
-
- geometry_data['vertices'].append({
- 'type': 'POSITION',
- 'name': f'position_{primitive_index}',
- 'index': len(geometry_data['vertices']),
- 'scale': 1,
- 'vertex': position
- })
-
- inputs.append({
- 'type': 'POSITION',
- 'offset': '1',
- 'name': f'position_{primitive_index}',
- })
- elif attribute_id == 'NORMAL':
- normal = self.accessors[attribute]
-
- geometry_data['vertices'].append({
- 'type': 'NORMAL',
- 'name': f'normal_{primitive_index}',
- 'index': len(geometry_data['vertices']),
- 'scale': 1,
- 'vertex': normal
- })
-
- inputs.append({
- 'type': 'NORMAL',
- 'offset': '0',
- 'name': f'normal_{primitive_index}',
- })
- elif attribute_id.startswith('TEXCOORD'):
- texcoord = self.accessors[attribute]
-
- texcoord = [[item[0], 1 - item[1]] for item in texcoord]
-
- geometry_data['vertices'].append({
- 'type': 'TEXCOORD',
- 'name': f'texcoord_{primitive_index}',
- 'index': len(geometry_data['vertices']),
- 'scale': 1,
- 'vertex': texcoord
- })
-
- inputs.append({
- 'type': 'TEXCOORD',
- 'offset': '2',
- 'name': f'texcoord_{primitive_index}',
- })
- elif attribute_id.startswith('JOINTS'):
- vertex_weights = self.accessors[attribute]
- elif attribute_id.startswith('WEIGHTS'):
- weights = self.accessors[attribute]
-
- for x in range(len(vertex_weights)):
- geometry_data['weights']['vcount'].append(0)
-
- temp_list = [
- [vertex_weights[x][0], weights[x][0]],
- [vertex_weights[x][1], weights[x][1]],
- [vertex_weights[x][2], weights[x][2]],
- [vertex_weights[x][3], weights[x][3]]
- ]
- for pair in temp_list:
- if pair[1] != 0:
- geometry_data['weights']['vcount'][x] += 1
- geometry_data['weights']['vertex_weights'].append(pair[0])
- if pair[1] not in geometry_data['weights']['weights']:
- geometry_data['weights']['weights'].append(pair[1])
- geometry_data['weights']['vertex_weights'].append(
- geometry_data['weights']['weights'].index(pair[1])
- )
-
- polygons = [
- [
- [
- value[0] + offsets['NORMAL'],
- value[0] + offsets['POSITION'],
- value[0] + offsets['TEXCOORD']
- ] for value in polygons[x:x + 3]
- ] for x in range(0, len(polygons), 3)
- ]
-
- geometry_data['materials'].append({
- 'name': material_name,
- 'inputs': inputs,
- 'polygons': polygons
- })
-
- for attribute_id in attributes:
- if attribute_id == 'POSITION':
- offsets['POSITION'] += len(position)
- elif attribute_id == 'NORMAL':
- offsets['NORMAL'] += len(normal)
- elif attribute_id.startswith('TEXCOORD'):
- offsets['TEXCOORD'] += len(texcoord)
-
- self.parsed['geometries'].append(geometry_data)
-
- self.parsed['nodes'].append(node_data)
-
- if node.translation or node.rotation or node.scale:
- node_data['frames'].append({
- 'frame_id': 0,
- 'rotation': {'x': 0, 'y': 0, 'z': 0, 'w': 0},
- 'position': {'x': 0, 'y': 0, 'z': 0},
- 'scale': {'x': 1, 'y': 1, 'z': 1}
- })
-
- if node.translation:
- node_data['frames'][0]['position'] = {
- 'x': node.translation[0],
- 'y': node.translation[1],
- 'z': node.translation[2]
- }
- if node.rotation:
- node_data['frames'][0]['rotation'] = {
- 'x': node.rotation[0],
- 'y': node.rotation[1],
- 'z': node.rotation[2],
- 'w': node.rotation[3]
- }
- if node.scale:
- node_data['frames'][0]['scale'] = {
- 'x': node.scale[0],
- 'y': node.scale[1],
- 'z': node.scale[2]
- }
-
- if node.children:
- for child_id in node.children:
- child = self.gltf.nodes[child_id]
- self.parse_node(child, node_name)
-
-
-if __name__ == '__main__':
- with open('../crow_geo.glb', 'rb') as fh:
- file_data = fh.read()
- fh.close()
- parser = Parser(file_data)
- parser.parse()
-
- writer = Writer()
- with open('../crow_geo.dae', 'w') as fh:
- fh.write(writer.writen)
- fh.close()
diff --git a/models_converter/formats/gltf/__init__.py b/models_converter/formats/gltf/__init__.py
new file mode 100644
index 0000000..bad092d
--- /dev/null
+++ b/models_converter/formats/gltf/__init__.py
@@ -0,0 +1,35 @@
+from .accessor import Accessor
+from .animation import Animation
+from .asset import Asset
+from .buffer import Buffer
+from .buffer_view import BufferView
+from .camera import Camera
+from .gltf_property import GlTFProperty
+from .image import Image
+from .material import Material
+from .mesh import Mesh
+from .node import Node
+from .sampler import Sampler
+from .scene import Scene
+from .skin import Skin
+from .texture import Texture
+
+from .parser import Parser
+
+__all__ = [
+ 'Accessor',
+ 'Animation',
+ 'Asset',
+ 'Buffer',
+ 'BufferView',
+ 'Camera',
+ 'Image',
+ 'Material',
+ 'Mesh',
+ 'Node',
+ 'Sampler',
+ 'Scene',
+ 'Skin',
+ 'Texture',
+ 'Parser'
+]
diff --git a/models_converter/formats/gltf/accessor.py b/models_converter/formats/gltf/accessor.py
new file mode 100644
index 0000000..ad20dd0
--- /dev/null
+++ b/models_converter/formats/gltf/accessor.py
@@ -0,0 +1,39 @@
+from .gltf_property import GlTFProperty
+
+
+class Accessor(GlTFProperty):
+ class Sparse(GlTFProperty):
+ class Indices(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.buffer_view = None
+ self.component_type = None
+
+ self.byte_offset = 0
+
+ class Values(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.buffer_view = None
+
+ self.byte_offset = 0
+
+ def __init__(self):
+ super().__init__()
+ self.count = None
+ self.indices = self.Indices()
+ self.values = self.Values()
+
+ def __init__(self):
+ super().__init__()
+ self.component_type = None
+ self.count = None
+ self.type = None
+
+ self.buffer_view = None
+ self.byte_offset = 0
+ self.normalized = False
+ self.max = None
+ self.min = None
+ self.sparse = self.Sparse()
+ self.name = None
diff --git a/models_converter/formats/gltf/animation.py b/models_converter/formats/gltf/animation.py
new file mode 100644
index 0000000..d9476d0
--- /dev/null
+++ b/models_converter/formats/gltf/animation.py
@@ -0,0 +1,32 @@
+from .gltf_property import GlTFProperty
+
+
+class Animation(GlTFProperty):
+ class AnimationSampler(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.input = None
+ self.output = None
+
+ self.interpolation = None # Default: 'LINEAR'
+
+ class Channel(GlTFProperty):
+ class Target(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.path = None
+
+ self.node = None
+
+ def __init__(self):
+ super().__init__()
+ self.sampler = None
+ self.target = self.Target()
+
+ def __init__(self):
+ super().__init__()
+ self.channels = self.Channel()
+ self.samplers = self.AnimationSampler()
+
+ self.name = None
+
diff --git a/models_converter/formats/gltf/asset.py b/models_converter/formats/gltf/asset.py
new file mode 100644
index 0000000..d063162
--- /dev/null
+++ b/models_converter/formats/gltf/asset.py
@@ -0,0 +1,11 @@
+from .gltf_property import GlTFProperty
+
+
+class Asset(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.version = None
+
+ self.copyright = None
+ self.generator = None
+ self.min_version = None
diff --git a/models_converter/formats/gltf/buffer.py b/models_converter/formats/gltf/buffer.py
new file mode 100644
index 0000000..0008f51
--- /dev/null
+++ b/models_converter/formats/gltf/buffer.py
@@ -0,0 +1,10 @@
+from .gltf_property import GlTFProperty
+
+
+class Buffer(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.byte_length = None
+
+ self.uri = None
+ self.name = None
diff --git a/models_converter/formats/gltf/buffer_view.py b/models_converter/formats/gltf/buffer_view.py
new file mode 100644
index 0000000..1e7bfea
--- /dev/null
+++ b/models_converter/formats/gltf/buffer_view.py
@@ -0,0 +1,13 @@
+from .gltf_property import GlTFProperty
+
+
+class BufferView(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.buffer = None
+ self.byte_length = None
+
+ self.byte_offset = 0
+ self.byte_stride = None
+ self.target = None
+ self.name = None
diff --git a/models_converter/formats/gltf/camera.py b/models_converter/formats/gltf/camera.py
new file mode 100644
index 0000000..18e849a
--- /dev/null
+++ b/models_converter/formats/gltf/camera.py
@@ -0,0 +1,28 @@
+from .gltf_property import GlTFProperty
+
+
+class Camera(GlTFProperty):
+ class Orthographic(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.xmag = None
+ self.ymag = None
+ self.zfar = None
+ self.znear = None
+
+ class Perspective(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.yfov = None
+ self.znear = None
+
+ self.aspect_ratio = None
+ self.zfar = None
+
+ def __init__(self):
+ super().__init__()
+ self.type = None
+
+ self.orthographic = None
+ self.perspective = None
+ self.name = None
diff --git a/models_converter/formats/gltf/chunk.py b/models_converter/formats/gltf/chunk.py
new file mode 100644
index 0000000..b21a94e
--- /dev/null
+++ b/models_converter/formats/gltf/chunk.py
@@ -0,0 +1,5 @@
+class GlTFChunk:
+ def __init__(self):
+ self.chunk_length = 0
+ self.chunk_name = b''
+ self.data = b''
diff --git a/models_converter/formats/gltf/gltf.py b/models_converter/formats/gltf/gltf.py
new file mode 100644
index 0000000..c5a4b7e
--- /dev/null
+++ b/models_converter/formats/gltf/gltf.py
@@ -0,0 +1,26 @@
+from .gltf_property import GlTFProperty
+from . import *
+
+
+class GlTF(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.asset = Asset()
+
+ self.extensions_used = None
+ self.extensions_required = None
+
+ self.accessors = Accessor()
+ self.animations = Animation()
+ self.buffers = Buffer()
+ self.buffer_views = BufferView()
+ self.cameras = Camera()
+ self.images = Image()
+ self.materials = Material()
+ self.meshes = Mesh()
+ self.nodes = Node()
+ self.samplers = Sampler()
+ self.scene = None
+ self.scenes = Scene()
+ self.skins = Skin()
+ self.textures = Texture()
diff --git a/models_converter/formats/gltf/gltf_property.py b/models_converter/formats/gltf/gltf_property.py
new file mode 100644
index 0000000..7d554c4
--- /dev/null
+++ b/models_converter/formats/gltf/gltf_property.py
@@ -0,0 +1,94 @@
+def to_camelcase(property_name: str):
+ words = property_name.split('_')
+ for word_index in range(len(words)):
+ word = words[word_index]
+ if word_index > 0:
+ word = word.capitalize()
+ words[word_index] = word
+ camelcase_name = ''.join(words)
+ return camelcase_name
+
+
+def to_lowercase(property_name: str):
+ letters = list(property_name)
+
+ for letter_index in range(len(letters)):
+ letter = letters[letter_index]
+
+ if letter.isupper():
+ letter = f'_{letter.lower()}'
+
+ letters[letter_index] = letter
+
+ lowercase_name = ''.join(letters)
+ return lowercase_name
+
+
+class GlTFProperty:
+ def __init__(self):
+ self.extensions = None
+ self.extras = None
+
+ def from_dict(self, dictionary: dict):
+ if dictionary:
+ for key, value in dictionary.items():
+ attribute_name = to_lowercase(key)
+ value_type = type(value)
+
+ attribute_value = getattr(self, attribute_name)
+ attribute_value_type = type(attribute_value)
+
+ if attribute_value is None or value_type in [int, str]:
+ attribute_value = value
+ elif issubclass(attribute_value_type, GlTFProperty):
+ if value_type is list:
+ value_type = attribute_value_type
+ values = []
+
+ for item in value:
+ new_value = value_type()
+ new_value.from_dict(item)
+
+ values.append(new_value)
+
+ attribute_value = values
+ else:
+ attribute_value = attribute_value_type()
+ attribute_value.from_dict(value)
+
+ setattr(self, attribute_name, attribute_value)
+
+ def to_dict(self) -> dict:
+ dictionary = {}
+ for key, value in self.__dict__.items():
+ if value is not None:
+ attribute_name = to_camelcase(key)
+ value_type = type(value)
+
+ attribute_value = None
+
+ if value_type is list:
+ attribute_value = []
+ for item in value:
+ item_type = type(item)
+
+ if issubclass(item_type, GlTFProperty):
+ item = item.to_dict()
+ attribute_value.append(item)
+ elif issubclass(value_type, GlTFProperty):
+ attribute_value = value.to_dict()
+ elif attribute_value is None:
+ attribute_value = value
+
+ dictionary[attribute_name] = attribute_value
+ return dictionary
+
+ def __getitem__(self, item):
+ item = to_lowercase(item)
+ if hasattr(self, item):
+ return getattr(self, item)
+ else:
+ raise IndexError('The object has no attribute named ' + item)
+
+ def __repr__(self) -> str:
+ return f'<{self.__class__.__name__} ({self.to_dict()})>'
diff --git a/models_converter/formats/gltf/image.py b/models_converter/formats/gltf/image.py
new file mode 100644
index 0000000..270cbb8
--- /dev/null
+++ b/models_converter/formats/gltf/image.py
@@ -0,0 +1,10 @@
+from .gltf_property import GlTFProperty
+
+
+class Image(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.uri = None
+ self.mime_type = None
+ self.buffer_view = None
+ self.name = None
diff --git a/models_converter/formats/gltf/material.py b/models_converter/formats/gltf/material.py
new file mode 100644
index 0000000..35cc76f
--- /dev/null
+++ b/models_converter/formats/gltf/material.py
@@ -0,0 +1,40 @@
+from .gltf_property import GlTFProperty
+
+
+class Material(GlTFProperty):
+ class NormalTextureInfo(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.index = None
+
+ self.tex_coord = None # Default: 0
+ self.scale = None # Default: 1
+
+ class OcclusionTextureInfo(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.index = None
+
+ self.tex_coord = None # Default: 0
+ self.strength = None # Default: 1
+
+ class PbrMetallicRoughness(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.base_color_factor = None # Default: [1, 1, 1, 1]
+ self.base_color_texture = None
+ self.metallic_factor = None # Default: 1
+ self.roughness_factor = None # Default: 1
+ self.metallic_roughness_texture = None
+
+ def __init__(self):
+ super().__init__()
+ self.name = None
+ self.pbr_metallic_roughness = None
+ self.normal_texture = None
+ self.occlusion_texture = None
+ self.emissive_texture = None
+ self.emissive_factor = None # Default: [0, 0, 0]
+ self.alpha_mode = None # Default: 'OPAQUE'
+ self.alpha_cutoff = None # Default: 0.5
+ self.double_sided = None # Default: False
diff --git a/models_converter/formats/gltf/mesh.py b/models_converter/formats/gltf/mesh.py
new file mode 100644
index 0000000..f636ae1
--- /dev/null
+++ b/models_converter/formats/gltf/mesh.py
@@ -0,0 +1,20 @@
+from .gltf_property import GlTFProperty
+
+
+class Mesh(GlTFProperty):
+ class Primitive(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.attributes = None
+
+ self.indices = None
+ self.material = None
+ self.mode = None # Default: 4
+ self.targets = None
+
+ def __init__(self):
+ super().__init__()
+ self.primitives = self.Primitive()
+
+ self.weights = None
+ self.name = None
diff --git a/models_converter/formats/gltf/node.py b/models_converter/formats/gltf/node.py
new file mode 100644
index 0000000..920e39d
--- /dev/null
+++ b/models_converter/formats/gltf/node.py
@@ -0,0 +1,16 @@
+from .gltf_property import GlTFProperty
+
+
+class Node(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.camera = None
+ self.children = None
+ self.skin = None
+ self.matrix = None # Default: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
+ self.mesh = None
+ self.rotation = None # Default: [0, 0, 0, 1]
+ self.scale = None # Default: [1, 1, 1]
+ self.translation = None # Default: [0, 0, 0]
+ self.weights = None
+ self.name = None
diff --git a/models_converter/formats/gltf/parser.py b/models_converter/formats/gltf/parser.py
new file mode 100644
index 0000000..807cb65
--- /dev/null
+++ b/models_converter/formats/gltf/parser.py
@@ -0,0 +1,378 @@
+import json
+
+from models_converter.formats.gltf.chunk import GlTFChunk
+from models_converter.formats.gltf.gltf import GlTF
+from models_converter.formats.gltf.node import Node
+from models_converter.utils.reader import Reader
+
+
+class Parser(Reader):
+ def __init__(self, initial_bytes: bytes):
+ super().__init__(initial_bytes, 'little')
+
+ self.magic = self.read(4)
+ if self.magic != b'glTF':
+ raise TypeError('File Magic isn\'t "glTF"')
+
+ self.parsed = {
+ 'header': {
+ 'frame_rate': 30
+ },
+ 'materials': [],
+ 'geometries': [],
+ 'cameras': [],
+ 'nodes': []
+ }
+
+ self.version = None
+ self.length = None
+
+ self.json_chunk = None
+ self.bin_chunk = None
+
+ self.buffer_views = []
+ self.accessors = []
+ self.buffers = []
+
+ self.gltf = GlTF()
+
+ def parse_bin(self):
+ super().__init__(self.bin_chunk.data, 'little')
+
+ for buffer in self.gltf.buffers:
+ parsed_buffer = self.read(buffer.byte_length)
+ self.buffers.append(parsed_buffer)
+
+ for buffer_view in self.gltf.buffer_views:
+ super().__init__(self.buffers[buffer_view.buffer], 'little')
+
+ self.read(buffer_view.byte_offset)
+
+ length = buffer_view.byte_length
+ data = self.read(length)
+
+ self.buffer_views.append(data)
+
+ for accessor in self.gltf.accessors:
+ super().__init__(self.buffer_views[accessor.buffer_view], 'little')
+ temp_accessor = []
+
+ self.read(accessor.byte_offset)
+
+ types = {
+ 5120: (self.readByte, 1),
+ 5121: (self.readUByte, 1),
+ 5122: (self.readShort, 2),
+ 5123: (self.readUShort, 2),
+ 5125: (self.readUInt32, 4),
+ 5126: (self.readFloat, 4)
+ }
+
+ items_count = {
+ 'SCALAR': 1,
+ 'VEC2': 2,
+ 'VEC3': 3,
+ 'VEC4': 4,
+ 'MAT2': 4,
+ 'MAT3': 9,
+ 'MAT4': 16
+ }
+
+ component_nb = items_count[accessor.type]
+ read_type, bytes_per_elem = types[accessor.component_type]
+ default_stride = bytes_per_elem * component_nb
+
+ stride = self.gltf.buffer_views[accessor.buffer_view].byte_stride or default_stride
+ if default_stride == stride:
+ for x in range(accessor.count):
+ temp_list = []
+ for i in range(component_nb):
+ temp_list.append(read_type())
+ temp_accessor.append(temp_list)
+ else:
+ elems_per_stride = stride // bytes_per_elem
+ num_elems = (accessor.count - 1) * elems_per_stride + component_nb
+
+ temp_list = []
+ for i in range(num_elems):
+ temp_list.append(read_type())
+
+ temp_accessor = [temp_list[x:x + component_nb] for x in range(0, num_elems, elems_per_stride)]
+
+ if accessor.normalized:
+ for item_index, data in enumerate(temp_accessor):
+ new_data = []
+ for value in data:
+ if accessor.component_type == 5120:
+ value = max(value / 127, -1.0)
+ elif accessor.component_type == 5121:
+ value /= 255
+ elif accessor.component_type == 5122:
+ value = max(value / 32767, -1.0)
+ elif accessor.component_type == 5123:
+ value /= 65535
+ new_data.append(value)
+ temp_accessor[item_index] = new_data
+
+ self.accessors.append(temp_accessor)
+
+ def parse(self):
+ #
+
+ self.version = self.readUInt32()
+ self.length = self.readUInt32()
+
+ self.json_chunk = GlTFChunk()
+ self.bin_chunk = GlTFChunk()
+
+ self.json_chunk.chunk_length = self.readUInt32()
+ self.json_chunk.chunk_name = self.read(4)
+ self.json_chunk.data = self.read(self.json_chunk.chunk_length)
+
+ self.bin_chunk.chunk_length = self.readUInt32()
+ self.bin_chunk.chunk_name = self.read(4)
+ self.bin_chunk.data = self.read(self.bin_chunk.chunk_length)
+
+ #
+
+ self.gltf.from_dict(json.loads(self.json_chunk.data))
+
+ self.parse_bin()
+
+ #
+
+ scene_id = self.gltf.scene
+ scene = self.gltf.scenes[scene_id]
+
+ for node_id in scene.nodes:
+ node = self.gltf.nodes[node_id]
+ self.parse_node(node)
+
+ #
+
+ def parse_node(self, node: Node, parent: str = None):
+ node_name = node.name
+
+ node_data = {
+ 'name': node_name,
+ 'parent': parent,
+ 'instances': [],
+ 'frames': []
+ }
+
+ instance = None
+ if node.mesh:
+ instance = {
+ 'instance_type': 'GEOM',
+ 'instance_name': None,
+ 'binds': []
+ }
+ geometry_data = {
+ 'name': '',
+ 'group': '',
+ 'vertices': [],
+ 'have_bind_matrix': False,
+ 'weights': {
+ 'vertex_weights': [],
+ 'weights': [],
+ 'vcount': []
+ },
+ 'materials': []
+ }
+
+ if node.skin:
+ instance['instance_type'] = 'CONT'
+
+ geometry_data['have_bind_matrix'] = True
+ geometry_data['bind_matrix'] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
+ geometry_data['joints'] = []
+
+ skin_id = node.skin
+ skin = self.gltf.skins[skin_id]
+ bind_matrices = self.accessors[skin.inverse_bind_matrices]
+ bind_matrices = [[m[0::4], m[1::4], m[2::4], m[3::4]] for m in bind_matrices]
+ for matrix_index in range(len(bind_matrices)):
+ m = bind_matrices[matrix_index]
+
+ matrix = m[0]
+ matrix.extend(m[1])
+ matrix.extend(m[2])
+ matrix.extend(m[3])
+
+ bind_matrices[matrix_index] = matrix
+
+ for joint in skin.joints:
+ joint_index = skin['joints'].index(joint)
+ joint_node = self.gltf.nodes[joint]
+ joint_name = joint_node['name']
+ matrix = bind_matrices[joint_index]
+
+ joint_data = {
+ 'name': joint_name,
+ 'matrix': matrix
+ }
+ geometry_data['joints'].append(joint_data)
+
+ mesh_id = node.mesh
+ mesh = self.gltf.meshes[mesh_id]
+ mesh_name = mesh.name
+ mesh_name = mesh_name.split('|')
+
+ if len(mesh_name) > 1:
+ geometry_data['group'] = mesh_name[0]
+ geometry_data['name'] = mesh_name[1]
+ else:
+ geometry_data['name'] = mesh_name[0]
+
+ instance['instance_name'] = geometry_data['name']
+
+ offsets = {
+ 'POSITION': 0,
+ 'NORMAL': 0,
+ 'TEXCOORD': 0
+ }
+
+ for primitive in mesh.primitives:
+ if primitive.to_dict() != {}:
+ primitive_index = mesh.primitives.index(primitive)
+ attributes = primitive.attributes
+ material_id = primitive.material
+ polygons_id = primitive.indices
+
+ inputs = []
+
+ polygons = self.accessors[polygons_id]
+ material = self.gltf.materials[material_id]
+
+ material_name = material.extensions['SC_shader']['name']
+ instance['binds'].append({
+ 'symbol': material_name,
+ 'target': material_name
+ })
+
+ position = []
+ normal = []
+ texcoord = []
+
+ vertex_weights = 0
+
+ for attribute_id in attributes:
+ attribute = attributes[attribute_id]
+ vertex = None
+
+ if attribute_id == 'POSITION':
+ position = self.accessors[attribute]
+ vertex = position
+ elif attribute_id == 'NORMAL':
+ normal = self.accessors[attribute]
+ vertex = normal
+ elif attribute_id.startswith('TEXCOORD'):
+ texcoord = self.accessors[attribute]
+
+ texcoord = [[item[0], 1 - item[1]] for item in texcoord]
+ attribute_id = 'TEXCOORD'
+ vertex = texcoord
+ elif attribute_id.startswith('JOINTS'):
+ vertex_weights = self.accessors[attribute]
+ elif attribute_id.startswith('WEIGHTS'):
+ weights = self.accessors[attribute]
+
+ for x in range(len(vertex_weights)):
+ geometry_data['weights']['vcount'].append(0)
+
+ temp_list = [
+ [vertex_weights[x][0], weights[x][0]],
+ [vertex_weights[x][1], weights[x][1]],
+ [vertex_weights[x][2], weights[x][2]],
+ [vertex_weights[x][3], weights[x][3]]
+ ]
+ for pair in temp_list:
+ if pair[1] != 0:
+ geometry_data['weights']['vcount'][x] += 1
+ geometry_data['weights']['vertex_weights'].append(pair[0])
+ if pair[1] not in geometry_data['weights']['weights']:
+ geometry_data['weights']['weights'].append(pair[1])
+ geometry_data['weights']['vertex_weights'].append(
+ geometry_data['weights']['weights'].index(pair[1])
+ )
+ for weight_index in range(len(geometry_data['weights']['weights'])):
+ geometry_data['weights']['weights'][weight_index] /= 255
+
+ if vertex:
+ geometry_data['vertices'].append({
+ 'type': attribute_id,
+ 'name': f'{attribute_id.lower()}_{primitive_index}',
+ 'index': len(geometry_data['vertices']),
+ 'scale': 1,
+ 'vertex': vertex
+ })
+
+ inputs.append({
+ 'type': attribute_id,
+ 'offset': len(inputs),
+ 'name': f'{attribute_id.lower()}_{primitive_index}',
+ })
+
+ polygons = [
+ [
+ [
+ point[0] + offsets['NORMAL'],
+ point[0] + offsets['POSITION'],
+ point[0] + offsets['TEXCOORD']
+ ] for point in polygons[x:x + 3]
+ ] for x in range(0, len(polygons), 3)
+ ]
+
+ geometry_data['materials'].append({
+ 'name': material_name,
+ 'inputs': inputs,
+ 'polygons': polygons
+ })
+
+ for attribute_id in attributes:
+ if attribute_id == 'POSITION':
+ offsets['POSITION'] += len(position)
+ elif attribute_id == 'NORMAL':
+ offsets['NORMAL'] += len(normal)
+ elif attribute_id.startswith('TEXCOORD'):
+ offsets['TEXCOORD'] += len(texcoord)
+
+ self.parsed['geometries'].append(geometry_data)
+
+ if instance is not None:
+ node_data['instances'].append(instance)
+
+ self.parsed['nodes'].append(node_data)
+
+ if node.translation or node.rotation or node.scale:
+ node_data['frames'].append({
+ 'frame_id': 0,
+ 'rotation': {'x': 0, 'y': 0, 'z': 0, 'w': 0},
+ 'position': {'x': 0, 'y': 0, 'z': 0},
+ 'scale': {'x': 1, 'y': 1, 'z': 1}
+ })
+
+ if node.translation:
+ node_data['frames'][0]['position'] = {
+ 'x': node.translation[0],
+ 'y': node.translation[1],
+ 'z': node.translation[2]
+ }
+ if node.rotation:
+ node_data['frames'][0]['rotation'] = {
+ 'x': node.rotation[0],
+ 'y': node.rotation[1],
+ 'z': node.rotation[2],
+ 'w': node.rotation[3]
+ }
+ if node.scale:
+ node_data['frames'][0]['scale'] = {
+ 'x': node.scale[0],
+ 'y': node.scale[1],
+ 'z': node.scale[2]
+ }
+
+ if node.children:
+ for child_id in node.children:
+ child = self.gltf.nodes[child_id]
+ self.parse_node(child, node_name)
diff --git a/models_converter/formats/gltf/sampler.py b/models_converter/formats/gltf/sampler.py
new file mode 100644
index 0000000..d18167e
--- /dev/null
+++ b/models_converter/formats/gltf/sampler.py
@@ -0,0 +1,11 @@
+from .gltf_property import GlTFProperty
+
+
+class Sampler(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.mag_filter = None
+ self.min_filter = None
+ self.wrap_s = None # Default: 10497
+ self.wrap_t = None # Default: 10497
+ self.name = None
diff --git a/models_converter/formats/gltf/scene.py b/models_converter/formats/gltf/scene.py
new file mode 100644
index 0000000..916e5dd
--- /dev/null
+++ b/models_converter/formats/gltf/scene.py
@@ -0,0 +1,8 @@
+from .gltf_property import GlTFProperty
+
+
+class Scene(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.nodes = None
+ self.name = None
diff --git a/models_converter/formats/gltf/skin.py b/models_converter/formats/gltf/skin.py
new file mode 100644
index 0000000..d0334bd
--- /dev/null
+++ b/models_converter/formats/gltf/skin.py
@@ -0,0 +1,11 @@
+from .gltf_property import GlTFProperty
+
+
+class Skin(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.joints = None
+
+ self.inverse_bind_matrices = None
+ self.skeleton = None
+ self.name = None
diff --git a/models_converter/formats/gltf/texture.py b/models_converter/formats/gltf/texture.py
new file mode 100644
index 0000000..0f1efda
--- /dev/null
+++ b/models_converter/formats/gltf/texture.py
@@ -0,0 +1,9 @@
+from .gltf_property import GlTFProperty
+
+
+class Texture(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.sampler = None
+ self.source = None
+ self.name = None
diff --git a/models_converter/formats/gltf/texture_info.py b/models_converter/formats/gltf/texture_info.py
new file mode 100644
index 0000000..78749ef
--- /dev/null
+++ b/models_converter/formats/gltf/texture_info.py
@@ -0,0 +1,9 @@
+from models_converter.formats.gltf import GlTFProperty
+
+
+class TextureInfo(GlTFProperty):
+ def __init__(self):
+ super().__init__()
+ self.index = None
+
+ self.tex_coord = None # Default: 0
diff --git a/models_converter/formats/obj.py b/models_converter/formats/obj.py
index ecdada4..673edd3 100644
--- a/models_converter/formats/obj.py
+++ b/models_converter/formats/obj.py
@@ -47,7 +47,7 @@ def write(self, data: dict):
self.writen += f'{temp_string}\n'
self.writen += '\n\n'
for material in materials:
- self.writen += f'o {name}_{material["name"]}\n\n'
+ self.writen += f'o {name}|{material["name"]}\n\n'
for item in material['polygons']:
temp_string = 'f '
for subitem in item:
@@ -63,11 +63,14 @@ def write(self, data: dict):
class Parser:
- def __init__(self, file_data: str):
- #
+ def __init__(self, file_data: bytes or str):
+ if type(file_data) is bytes:
+ file_data = file_data.decode()
self.parsed = {'header': {'version': 2,
'frame_rate': 30,
+ 'first_frame': 0,
+ 'last_frame': 0,
'materials_file': 'sc3d/character_materials.scw'},
'materials': [],
'geometries': [],
@@ -76,22 +79,27 @@ def __init__(self, file_data: str):
self.lines = file_data.split('\n')
- #
self.position_temp, self.position = [], []
self.normals_temp, self.normals = [], []
self.texcoord_temp, self.texcoord = [], []
- #
- self.polygons = []
+ def parse(self):
+ polygons = []
+ geometry_name = None
+ material = 'character_mat'
+ position_scale, normals_scale, texcoord_scale = 1, 1, 1
- #
+ vertices_offsets = {
+ 'POSITION': 0,
+ 'TEXCOORD': 0,
+ 'NORMAL': 0
+ }
- self.parse()
+ names = [line[2:].split('|')[0]
+ for line in list(filter(lambda line: line.startswith('o '), self.lines))]
- def parse(self):
- geometry_name = 'This model haven \'t a chunk_name!:( Its VERY SAD!'
- is_first_name = True
- for line in self.lines:
+ for line_index in range(len(self.lines)):
+ line = self.lines[line_index]
items = line.split()[1:]
if line.startswith('v '): # POSITION
for item in items:
@@ -119,67 +127,110 @@ def parse(self):
break
for x in item.split('/'):
second_temp_list.append(int(x) - 1)
- temp_list.append([second_temp_list[0], second_temp_list[2], second_temp_list[1]])
- self.polygons.append(temp_list)
+ temp_list.append([second_temp_list[0] - vertices_offsets['POSITION'],
+ second_temp_list[2] - vertices_offsets['TEXCOORD'],
+ second_temp_list[1] - vertices_offsets['NORMAL']])
+ polygons.append(temp_list)
elif line.startswith('o '):
- # if not is_first_name:
- # position_scale = self.get_vertex_scale(self.position_temp)
- # normals_scale = self.get_vertex_scale(self.normals_temp)
- # texcoord_scale = self.get_vertex_scale(self.texcoord_temp)
- #
- # self.parsed['geometries'].append({
- # 'chunk_name': geometry_name,
- # 'group': '',
- # 'vertices': [
- # {'type': 'POSITION', 'index': 0, 'scale': position_scale, 'vertex': self.position},
- # {'type': 'NORMAL', 'index': 1, 'scale': normals_scale, 'vertex': self.normals},
- # {'type': 'TEXCOORD', 'index': 2, 'scale': texcoord_scale, 'vertex': self.texcoord}
- # ],
- # 'have_bind_matrix': False,
- # 'materials': [{'chunk_name': 'character_mat', 'polygons': self.polygons}]
- # })
- #
- # #
- #
- # #
- # self.position_temp, self.position = [], []
- # self.normals_temp, self.normals = [], []
- # self.texcoord_temp, self.texcoord = [], []
- # #
- #
- # self.polygons = []
- #
- # #
- # geometry_name = line.split('o ')[0]
- if is_first_name:
- geometry_name = line.split('o ')[0]
-
- position_scale = self.get_vertex_scale(self.position_temp)
- normals_scale = self.get_vertex_scale(self.normals_temp)
- texcoord_scale = self.get_vertex_scale(self.texcoord_temp)
-
- for x in range(0, len(self.position_temp), 3):
- self.position.append(self.position_temp[x: x + 3])
-
- for x in range(0, len(self.normals_temp), 3):
- self.normals.append(self.normals_temp[x: x + 3])
-
- for x in range(0, len(self.texcoord_temp), 2):
- self.texcoord.append(self.texcoord_temp[x: x + 2])
-
- self.parsed['geometries'].append({
- 'chunk_name': geometry_name,
- 'group': '',
- 'vertices': [
- {'type': 'POSITION', 'index': 0, 'scale': position_scale, 'vertex': self.position},
- {'type': 'NORMAL', 'index': 1, 'scale': normals_scale, 'vertex': self.normals},
- {'type': 'TEXCOORD', 'index': 2, 'scale': texcoord_scale, 'vertex': self.texcoord}
- ],
- 'have_bind_matrix': False,
- 'materials': [{'chunk_name': 'character_mat', 'polygons': self.polygons}]
- })
-
- # TODO: nodes
+ geometry_name = items[0]
+ if '|' in items[0]:
+ geometry_name, material = items[0].split('|')
+
+ if self.position_temp:
+ self.position = []
+ position_scale = self.get_vertex_scale(self.position_temp)
+ for x in range(0, len(self.position_temp), 3):
+ self.position.append([vertex / position_scale for vertex in self.position_temp[x: x + 3]])
+
+ if self.normals_temp:
+ self.normals = []
+ normals_scale = self.get_vertex_scale(self.normals_temp)
+ for x in range(0, len(self.normals_temp), 3):
+ self.normals.append([vertex / normals_scale for vertex in self.normals_temp[x: x + 3]])
+
+ if self.texcoord_temp:
+ self.texcoord = []
+ texcoord_scale = self.get_vertex_scale(self.texcoord_temp)
+ for x in range(0, len(self.texcoord_temp), 2):
+ self.texcoord.append([vertex / texcoord_scale for vertex in self.texcoord_temp[x: x + 2]])
+
+ if not line.startswith('f ') and polygons and geometry_name and \
+ self.position and self.normals and self.texcoord:
+ self.position_temp = []
+ self.normals_temp = []
+ self.texcoord_temp = []
+
+ if len(names) >= len(self.parsed['geometries']) + 1 and \
+ names[len(self.parsed['geometries']) + 1] != geometry_name:
+ vertices_offsets['POSITION'] += len(self.position)
+ vertices_offsets['TEXCOORD'] += len(self.normals)
+ vertices_offsets['NORMAL'] += len(self.texcoord)
+ if not (self.parsed['geometries'] and self.parsed['geometries'][-1]['name'] == geometry_name):
+ self.parsed['geometries'].append({
+ 'name': geometry_name,
+ 'group': '',
+ 'vertices': [
+ {
+ 'type': 'POSITION',
+ 'name': 'position_0',
+ 'index': 0,
+ 'scale': position_scale,
+ 'vertex': self.position
+ },
+ {
+ 'type': 'NORMAL',
+ 'name': 'normal_0',
+ 'index': 1,
+ 'scale': normals_scale,
+ 'vertex': self.normals
+ },
+ {
+ 'type': 'TEXCOORD',
+ 'name': 'texcoord_0',
+ 'index': 2,
+ 'scale': texcoord_scale,
+ 'vertex': self.texcoord
+ }
+ ],
+ 'have_bind_matrix': False,
+ 'materials': []
+ })
+ self.parsed['geometries'][-1]['materials'].append(
+ {'name': material, 'polygons': polygons, 'inputs': [
+ {'offset': self.parsed['geometries'][-1]['vertices'].index(vertex),
+ 'name': vertex['name'],
+ 'type': vertex['type']}
+ for vertex in self.parsed['geometries'][-1]['vertices']
+ ]}
+ )
+
+ material = 'character_mat'
+ polygons = []
+
+ for geometry in self.parsed['geometries']:
+ self.parsed['nodes'].append({
+ 'name': geometry['name'],
+ 'parent': '',
+ 'instances': [
+ {
+ 'instance_name': geometry['name'],
+ 'instance_type': 'GEOM',
+ 'binds': [
+ {'symbol': material['name'], 'target': material['name']}
+ for material in geometry['materials']
+ ]
+ }
+ ],
+ 'frames': [
+ {
+ 'frame_id': 0,
+ 'rotation': {'x': 0, 'y': 0, 'z': 0, 'w': 0},
+ 'position': {'x': 0, 'y': 0, 'z': 0},
+ 'scale': {'x': 1, 'y': 1, 'z': 1}
+ }
+ ],
+ 'frames_settings': [False] * 8
+ })
@staticmethod
def get_vertex_scale(vertex_data: list):
diff --git a/models_converter/formats/scw/chunks/head.py b/models_converter/formats/scw/chunks/head.py
index 028f489..a0a4371 100644
--- a/models_converter/formats/scw/chunks/head.py
+++ b/models_converter/formats/scw/chunks/head.py
@@ -11,20 +11,23 @@ def parse(self, buffer: bytes):
setattr(self, 'version', self.readUShort())
setattr(self, 'frame_rate', self.readUShort())
- setattr(self, 'v1', self.readUShort())
- setattr(self, 'animation_end_frame', self.readUShort())
+ setattr(self, 'first_frame', self.readUShort())
+ setattr(self, 'last_frame', self.readUShort())
setattr(self, 'materials_file', self.readString())
- if self.get('version') == 2:
+ if self.get('version') >= 1:
setattr(self, 'v3', self.readUByte())
def encode(self):
super().encode()
- self.writeUShort(2) # getattr(self, 'version')
+ setattr(self, 'version', 2)
+
+ self.writeUShort(getattr(self, 'version'))
self.writeUShort(getattr(self, 'frame_rate'))
- self.writeUShort(0) # getattr(self, 'v1')
- self.writeUShort(getattr(self, 'last_frame')) # animation end frame
+ self.writeUShort(getattr(self, 'first_frame'))
+ self.writeUShort(getattr(self, 'last_frame'))
self.writeString(getattr(self, 'materials_file'))
- self.writeUByte(0) # getattr(self, 'v3')
+ if self.get('version') >= 1:
+ self.writeUByte(0) # getattr(self, 'v3')
self.length = len(self.buffer)
diff --git a/setup.py b/setup.py
index 2c275ab..922a0e2 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name='3d-converter',
- version='0.8.1',
+ version='0.8.5',
author='Vorono4ka',
author_email='crowo4ka@gmail.com',
description='Python 3D Models Converter',