diff --git a/README.md b/README.md
index 84eafd0..8d906c2 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,5 @@
## Python 3D Models Converter
-**Version**: 0.8.8
+A module, which helps convert different 3d formats
-### **THIS IS NOT RELEASE VERSION!**
-
-### Thanks a lot for motivating [AMIRMISTIK]!
-
-
-[AMIRMISTIK]: https://www.youtube.com/channel/UCksd1LeoySP5St6dKlv6mvQ
+**Version**: 0.9.0
diff --git a/models_converter/formats/gltf/__init__.py b/models_converter/formats/gltf/__init__.py
index 009586a..9eabcaf 100644
--- a/models_converter/formats/gltf/__init__.py
+++ b/models_converter/formats/gltf/__init__.py
@@ -32,5 +32,6 @@
'Scene',
'Skin',
'Texture',
- 'Parser'
+ 'Parser',
+ 'Writer'
]
diff --git a/models_converter/formats/gltf/accessor.py b/models_converter/formats/gltf/accessor.py
index ad20dd0..7a64eb6 100644
--- a/models_converter/formats/gltf/accessor.py
+++ b/models_converter/formats/gltf/accessor.py
@@ -21,8 +21,8 @@ def __init__(self):
def __init__(self):
super().__init__()
self.count = None
- self.indices = self.Indices()
- self.values = self.Values()
+ self.indices = self.Indices
+ self.values = self.Values
def __init__(self):
super().__init__()
@@ -35,5 +35,5 @@ def __init__(self):
self.normalized = False
self.max = None
self.min = None
- self.sparse = self.Sparse()
+ self.sparse = self.Sparse
self.name = None
diff --git a/models_converter/formats/gltf/animation.py b/models_converter/formats/gltf/animation.py
index d9476d0..0b85574 100644
--- a/models_converter/formats/gltf/animation.py
+++ b/models_converter/formats/gltf/animation.py
@@ -21,12 +21,12 @@ def __init__(self):
def __init__(self):
super().__init__()
self.sampler = None
- self.target = self.Target()
+ self.target = self.Target
def __init__(self):
super().__init__()
- self.channels = self.Channel()
- self.samplers = self.AnimationSampler()
+ self.channels = self.Channel
+ self.samplers = self.AnimationSampler
self.name = None
diff --git a/models_converter/formats/gltf/gltf.py b/models_converter/formats/gltf/gltf.py
index c5a4b7e..eb1b175 100644
--- a/models_converter/formats/gltf/gltf.py
+++ b/models_converter/formats/gltf/gltf.py
@@ -5,22 +5,22 @@
class GlTF(GlTFProperty):
def __init__(self):
super().__init__()
- self.asset = Asset()
+ 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.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()
+ 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
index 7d554c4..2f7b83d 100644
--- a/models_converter/formats/gltf/gltf_property.py
+++ b/models_converter/formats/gltf/gltf_property.py
@@ -1,3 +1,7 @@
+from models_converter.utilities.math import Vector3, Quaternion
+from models_converter.utilities.matrix.matrix4x4 import Matrix4x4
+
+
def to_camelcase(property_name: str):
words = property_name.split('_')
for word_index in range(len(words)):
@@ -9,19 +13,16 @@ def to_camelcase(property_name: str):
return camelcase_name
-def to_lowercase(property_name: str):
- letters = list(property_name)
-
- for letter_index in range(len(letters)):
- letter = letters[letter_index]
+def to_lowercase(property_name: str) -> str:
+ result = ''
- if letter.isupper():
- letter = f'_{letter.lower()}'
+ for char in property_name:
+ if char.isupper():
+ char = f'_{char.lower()}'
- letters[letter_index] = letter
+ result += char
- lowercase_name = ''.join(letters)
- return lowercase_name
+ return result
class GlTFProperty:
@@ -36,13 +37,14 @@ def from_dict(self, dictionary: dict):
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]:
+ if attribute_value is None or value_type in (int, str, bool):
attribute_value = value
- elif issubclass(attribute_value_type, GlTFProperty):
+ elif type(attribute_value) in (Vector3, Quaternion, Matrix4x4) and type(value) is list:
+ attribute_value = type(attribute_value)(*value)
+ elif issubclass(attribute_value, GlTFProperty):
if value_type is list:
- value_type = attribute_value_type
+ value_type = attribute_value
values = []
for item in value:
@@ -53,7 +55,7 @@ def from_dict(self, dictionary: dict):
attribute_value = values
else:
- attribute_value = attribute_value_type()
+ attribute_value = attribute_value()
attribute_value.from_dict(value)
setattr(self, attribute_name, attribute_value)
diff --git a/models_converter/formats/gltf/mesh.py b/models_converter/formats/gltf/mesh.py
index f636ae1..91076cf 100644
--- a/models_converter/formats/gltf/mesh.py
+++ b/models_converter/formats/gltf/mesh.py
@@ -14,7 +14,7 @@ def __init__(self):
def __init__(self):
super().__init__()
- self.primitives = self.Primitive()
+ 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
index 920e39d..94a8b10 100644
--- a/models_converter/formats/gltf/node.py
+++ b/models_converter/formats/gltf/node.py
@@ -1,4 +1,6 @@
from .gltf_property import GlTFProperty
+from ...utilities.math import Vector3, Quaternion
+from ...utilities.matrix.matrix4x4 import Matrix4x4
class Node(GlTFProperty):
@@ -7,10 +9,10 @@ def __init__(self):
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.matrix = Matrix4x4(size=(4, 4))
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.rotation = Quaternion() # Default: [0, 0, 0, 1]
+ self.scale = Vector3(1, 1, 1) # Default: [1, 1, 1]
+ self.translation = Vector3() # 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
index 391a984..9c6e75a 100644
--- a/models_converter/formats/gltf/parser.py
+++ b/models_converter/formats/gltf/parser.py
@@ -5,17 +5,13 @@
from models_converter.formats.gltf.gltf import GlTF
from models_converter.formats.gltf.node import Node
from models_converter.formats.universal import Scene, Geometry
-from models_converter.utilities.math import Vector3, Quaternion
+from models_converter.interfaces import ParserInterface
from models_converter.utilities.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"')
+class Parser(ParserInterface):
+ def __init__(self, data: bytes):
+ self.file_data = data
self.scene = Scene()
@@ -32,37 +28,46 @@ def __init__(self, initial_bytes: bytes):
self.gltf = GlTF()
def parse_bin(self):
- super().__init__(self.bin_chunk.data, 'little')
+ reader = Reader(self.bin_chunk.data, 'little')
for buffer in self.gltf.buffers:
- parsed_buffer = self.read(buffer.byte_length)
+ parsed_buffer = reader.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')
+ reader.__init__(self.buffers[buffer_view.buffer], 'little')
- self.read(buffer_view.byte_offset)
+ reader.read(buffer_view.byte_offset)
length = buffer_view.byte_length
- data = self.read(length)
+ data = reader.read(length)
self.buffer_views.append(data)
for accessor in self.gltf.accessors:
- super().__init__(self.buffer_views[accessor.buffer_view], 'little')
- temp_accessor = []
+ reader.__init__(self.buffer_views[accessor.buffer_view], 'little')
- self.read(accessor.byte_offset)
+ reader.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)
+ 5120: (reader.readByte, 1),
+ 5121: (reader.readUByte, 1),
+ 5122: (reader.readShort, 2),
+ 5123: (reader.readUShort, 2),
+ 5125: (reader.readUInt32, 4),
+ 5126: (reader.readFloat, 4)
}
+ if accessor.normalized:
+ types = {
+ 5120: (lambda: max(reader.readByte() / 127, -1.0), 1),
+ 5121: (lambda: reader.readUByte() / 255, 1),
+ 5122: (lambda: max(reader.readShort() / 32767, -1.0), 2),
+ 5123: (lambda: reader.readUShort() / 65535, 2),
+ 5125: (reader.readUInt32, 4),
+ 5126: (reader.readFloat, 4)
+ }
+
items_count = {
'SCALAR': 1,
'VEC2': 2,
@@ -73,69 +78,49 @@ def parse_bin(self):
'MAT4': 16
}
- component_nb = items_count[accessor.type]
- read_type, bytes_per_elem = types[accessor.component_type]
- default_stride = bytes_per_elem * component_nb
+ components_count = items_count[accessor.type]
+ read_type, bytes_per_element = types[accessor.component_type]
+ default_stride = bytes_per_element * components_count
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())
+ elements_per_stride = stride // bytes_per_element
+ elements_count = accessor.count * elements_per_stride
- temp_accessor = [temp_list[x:x + component_nb] for x in range(0, num_elems, elems_per_stride)]
+ temp_list = []
+ for i in range(elements_count):
+ temp_list.append(read_type())
- 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)
+ self.accessors.append([
+ temp_list[i:i + components_count]
+ for i in range(0, elements_count, elements_per_stride)
+ ])
def parse(self):
- #
+ reader = Reader(self.file_data, 'little')
+
+ magic = reader.read(4)
+ if magic != b'glTF':
+ raise TypeError('Wrong file magic! "676c5446" expected, but given is ' + magic.hex())
- self.version = self.readUInt32()
- self.length = self.readUInt32()
+ self.version = reader.readUInt32()
+ self.length = reader.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.json_chunk.chunk_length = reader.readUInt32()
+ self.json_chunk.chunk_name = reader.read(4)
+ self.json_chunk.data = reader.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.bin_chunk.chunk_length = reader.readUInt32()
+ self.bin_chunk.chunk_name = reader.read(4)
+ self.bin_chunk.data = reader.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]
@@ -143,10 +128,14 @@ def parse(self):
node = self.gltf.nodes[node_id]
self.parse_node(node)
- #
+ # TODO: animations
+ # for animation in self.gltf.animations:
+ # for channel in animation.channels:
+ # sampler: Animation.AnimationSampler = animation.samplers[channel.sampler]
+ # input_accessor = self.accessors[sampler.input]
def parse_node(self, gltf_node: Node, parent: str = None):
- node_name = gltf_node.name
+ node_name = gltf_node.name.split('|')[-1]
node = universal.Node(
name=node_name,
@@ -154,8 +143,8 @@ def parse_node(self, gltf_node: Node, parent: str = None):
)
instance = None
- if gltf_node.mesh:
- mesh = self.gltf.meshes[gltf_node.mesh] # TODO: merge _geo.glb and _.*.glb files to fix TypeError
+ if gltf_node.mesh is not None and type(self.gltf.meshes) is list:
+ mesh = self.gltf.meshes[gltf_node.mesh]
mesh_name = mesh.name.split('|')
group = 'GEO'
@@ -166,7 +155,7 @@ def parse_node(self, gltf_node: Node, parent: str = None):
geometry = Geometry(name=name, group=group)
- if gltf_node.skin:
+ if gltf_node.skin is not None:
instance = universal.Node.Instance(name=geometry.get_name(), instance_type='CONT')
geometry.set_controller_bind_matrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
@@ -195,11 +184,9 @@ def parse_node(self, gltf_node: Node, parent: str = None):
else:
instance = universal.Node.Instance(name=geometry.get_name(), instance_type='GEOM')
- offsets = {
- 'POSITION': 0,
- 'NORMAL': 0,
- 'TEXCOORD': 0
- }
+ position_offset = 0
+ normal_offset = 0
+ texcoord_offset = 0
for primitive in mesh.primitives:
if primitive.to_dict() != {}:
@@ -226,10 +213,24 @@ def parse_node(self, gltf_node: Node, parent: str = None):
if attribute_id == 'POSITION':
position = self.accessors[attribute]
- points = position
+ points = list(map(
+ lambda point: (
+ point[0] * gltf_node.scale.x + gltf_node.translation.x,
+ point[1] * gltf_node.scale.y + gltf_node.translation.y,
+ point[2] * gltf_node.scale.z + gltf_node.translation.z
+ ),
+ position
+ ))
elif attribute_id == 'NORMAL':
normal = self.accessors[attribute]
- points = normal
+ points = list(map(
+ lambda point: (
+ point[0] * gltf_node.scale.x,
+ point[1] * gltf_node.scale.y,
+ point[2] * gltf_node.scale.z
+ ),
+ normal
+ ))
elif attribute_id.startswith('TEXCOORD'):
texcoord = self.accessors[attribute]
@@ -259,9 +260,9 @@ def parse_node(self, gltf_node: Node, parent: str = None):
triangles = [
[
[
- point[0] + offsets['NORMAL'],
- point[0] + offsets['POSITION'],
- point[0] + offsets['TEXCOORD']
+ point[0] + normal_offset,
+ point[0] + position_offset,
+ point[0] + texcoord_offset
] for point in triangles[x:x + 3]
] for x in range(0, len(triangles), 3)
]
@@ -270,11 +271,11 @@ def parse_node(self, gltf_node: Node, parent: str = None):
for attribute_id in attributes:
if attribute_id == 'POSITION':
- offsets['POSITION'] += len(position)
+ position_offset += len(position)
elif attribute_id == 'NORMAL':
- offsets['NORMAL'] += len(normal)
+ normal_offset += len(normal)
elif attribute_id.startswith('TEXCOORD'):
- offsets['TEXCOORD'] += len(texcoord)
+ texcoord_offset += len(texcoord)
self.scene.add_geometry(geometry)
@@ -283,28 +284,12 @@ def parse_node(self, gltf_node: Node, parent: str = None):
self.scene.add_node(node)
- if gltf_node.translation or gltf_node.rotation or gltf_node.scale:
- node.add_frame(universal.Node.Frame(0, Vector3(), Vector3(1, 1, 1), Quaternion()))
-
- if gltf_node.translation:
- node.get_frames()[0].set_position(Vector3(
- gltf_node.translation[0],
- gltf_node.translation[1],
- gltf_node.translation[2]
- ))
- if gltf_node.rotation:
- node.get_frames()[0].set_rotation(Quaternion(
- gltf_node.rotation[0],
- gltf_node.rotation[1],
- gltf_node.rotation[2],
- gltf_node.rotation[3]
- ))
- if gltf_node.scale:
- node.get_frames()[0].set_scale(Vector3(
- gltf_node.scale[0],
- gltf_node.scale[1],
- gltf_node.scale[2]
- ))
+ node.add_frame(universal.Node.Frame(
+ 0,
+ gltf_node.translation,
+ gltf_node.scale,
+ gltf_node.rotation
+ ))
if gltf_node.children:
for child_id in gltf_node.children:
diff --git a/models_converter/formats/scw/parser.py b/models_converter/formats/scw/parser.py
index 1998e7e..657d56a 100644
--- a/models_converter/formats/scw/parser.py
+++ b/models_converter/formats/scw/parser.py
@@ -4,22 +4,21 @@
from .chunks import *
-class Parser(ParserInterface, Reader):
+class Parser(ParserInterface):
def __init__(self, file_data: bytes):
- Reader.__init__(self, file_data)
-
self.file_data = file_data
self.scene = Scene()
self.chunks = []
self.header = None
- file_magic = self.read(4)
+ def parse(self):
+ reader = Reader(self.file_data)
+ file_magic = reader.read(4)
if file_magic != b'SC3D':
raise TypeError('File Magic isn\'t "SC3D"')
- def parse(self):
- self._split_chunks()
+ self._split_chunks(reader)
for chunk in self.chunks:
chunk_name = chunk['chunk_name']
@@ -52,13 +51,13 @@ def parse(self):
else:
raise TypeError(f'Unknown chunk: {chunk_name}')
- def _split_chunks(self):
+ def _split_chunks(self, reader: Reader):
# len(Chunk Length) + len(Chunk Name) + len(Chunk CRC)
- while len(self.file_data[self.tell():]) >= 12:
- chunk_length = self.readUInt32()
- chunk_name = self.readChars(4)
- chunk_data = self.read(chunk_length)
- chunk_crc = self.readUInt32()
+ while reader.tell() <= len(self.file_data) - 12:
+ chunk_length = reader.readUInt32()
+ chunk_name = reader.readChars(4)
+ chunk_data = reader.read(chunk_length)
+ chunk_crc = reader.readUInt32()
self.chunks.append({
'chunk_name': chunk_name,
diff --git a/models_converter/formats/universal/node.py b/models_converter/formats/universal/node.py
index c5bfc6a..ec380ef 100644
--- a/models_converter/formats/universal/node.py
+++ b/models_converter/formats/universal/node.py
@@ -104,3 +104,9 @@ def get_frames(self) -> List[Frame]:
def add_frame(self, frame: Frame):
self._frames.append(frame)
+
+ def set_frames(self, frames: List[Frame]):
+ self._frames.clear()
+
+ for frame in frames:
+ self._frames.append(frame)
diff --git a/models_converter/formats/universal/scene.py b/models_converter/formats/universal/scene.py
index 2125a30..3acfc80 100644
--- a/models_converter/formats/universal/scene.py
+++ b/models_converter/formats/universal/scene.py
@@ -38,6 +38,13 @@ def get_nodes(self) -> List[Node]:
def add_node(self, node: Node):
self._nodes.append(node)
+ def import_nodes(self, animation_scene):
+ for node in self._nodes:
+ for animation_node in animation_scene.get_nodes():
+ if node.get_name() == animation_node.get_name():
+ node.set_frames(animation_node.get_frames())
+ break
+
def get_frame_rate(self) -> int:
return self._frame_rate
diff --git a/models_converter/interfaces/parser_interface.py b/models_converter/interfaces/parser_interface.py
index f20d998..9cfe292 100644
--- a/models_converter/interfaces/parser_interface.py
+++ b/models_converter/interfaces/parser_interface.py
@@ -1,11 +1,16 @@
+import abc
+
from models_converter.formats.universal import Scene
class ParserInterface:
- def __init__(self):
+ @abc.abstractmethod
+ def __init__(self, file_data: bytes or str):
self.scene: Scene or None = None
- raise NotImplementedError('This is an abstract class')
-
+ @abc.abstractmethod
def parse(self):
- raise NotImplementedError('This is an abstract class')
+ """
+
+ :return:
+ """
diff --git a/models_converter/interfaces/writer_interface.py b/models_converter/interfaces/writer_interface.py
index d48f25c..0221572 100644
--- a/models_converter/interfaces/writer_interface.py
+++ b/models_converter/interfaces/writer_interface.py
@@ -1,13 +1,19 @@
+import abc
+
from models_converter.formats.universal import Scene
class WriterInterface:
MAGIC: bytes
+ @abc.abstractmethod
def __init__(self):
self.writen: bytes or str = None
- raise NotImplementedError('This is an abstract class')
-
+ @abc.abstractmethod
def write(self, scene: Scene):
- raise NotImplementedError('This is an abstract class')
+ """
+
+ :param scene:
+ :return:
+ """
diff --git a/models_converter/utilities/math/quaternion.py b/models_converter/utilities/math/quaternion.py
index 1038576..c60810a 100644
--- a/models_converter/utilities/math/quaternion.py
+++ b/models_converter/utilities/math/quaternion.py
@@ -7,3 +7,6 @@ def __init__(self, x: float = 0, y: float = 0, z: float = 0, w: float = 1):
def clone(self):
return Quaternion(self.x, self.y, self.z, self.w)
+
+ def __repr__(self):
+ return f'({self.x:.2f}, {self.y:.2f}, {self.z:.2f}, {self.w:.2f})'
diff --git a/models_converter/utilities/math/vector3.py b/models_converter/utilities/math/vector3.py
index 335ce98..ba149cf 100644
--- a/models_converter/utilities/math/vector3.py
+++ b/models_converter/utilities/math/vector3.py
@@ -6,3 +6,6 @@ def __init__(self, x: float = 0, y: float = 0, z: float = 0):
def clone(self):
return Vector3(self.x, self.y, self.z)
+
+ def __repr__(self):
+ return f'({self.x:.2f}, {self.y:.2f}, {self.z:.2f})'
diff --git a/models_converter/utilities/matrix/__init__.py b/models_converter/utilities/matrix/__init__.py
index 4589a76..76da29d 100644
--- a/models_converter/utilities/matrix/__init__.py
+++ b/models_converter/utilities/matrix/__init__.py
@@ -53,7 +53,7 @@ def __str__(self):
return str(self.matrix)
@staticmethod
- def get_identity_matrix(size: tuple):
+ def get_identity_matrix(size: tuple[int, int]):
matrix = []
for y in range(size[1]):
diff --git a/models_converter/utilities/reader.py b/models_converter/utilities/reader.py
index 467891f..2450a45 100644
--- a/models_converter/utilities/reader.py
+++ b/models_converter/utilities/reader.py
@@ -1,5 +1,8 @@
+import typing
+
+
class Reader:
- def __init__(self, buffer: bytes, endian: str = 'big'):
+ def __init__(self, buffer: bytes, endian: typing.Literal['big', 'little'] = 'big'):
self.buffer = buffer
self.endian = endian
self.i = 0
diff --git a/models_converter/utils/__pycache__/__init__.cpython-38.pyc b/models_converter/utils/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index 7440424..0000000
Binary files a/models_converter/utils/__pycache__/__init__.cpython-38.pyc and /dev/null differ
diff --git a/models_converter/utils/__pycache__/__init__.cpython-39.pyc b/models_converter/utils/__pycache__/__init__.cpython-39.pyc
deleted file mode 100644
index 485012b..0000000
Binary files a/models_converter/utils/__pycache__/__init__.cpython-39.pyc and /dev/null differ
diff --git a/models_converter/utils/__pycache__/reader.cpython-39.pyc b/models_converter/utils/__pycache__/reader.cpython-39.pyc
deleted file mode 100644
index d904bf0..0000000
Binary files a/models_converter/utils/__pycache__/reader.cpython-39.pyc and /dev/null differ
diff --git a/models_converter/utils/__pycache__/writer.cpython-39.pyc b/models_converter/utils/__pycache__/writer.cpython-39.pyc
deleted file mode 100644
index 70b909f..0000000
Binary files a/models_converter/utils/__pycache__/writer.cpython-39.pyc and /dev/null differ
diff --git a/models_converter/utils/matrix/__pycache__/__init__.cpython-38.pyc b/models_converter/utils/matrix/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index 1edbe5e..0000000
Binary files a/models_converter/utils/matrix/__pycache__/__init__.cpython-38.pyc and /dev/null differ
diff --git a/models_converter/utils/matrix/__pycache__/__init__.cpython-39.pyc b/models_converter/utils/matrix/__pycache__/__init__.cpython-39.pyc
deleted file mode 100644
index 4941021..0000000
Binary files a/models_converter/utils/matrix/__pycache__/__init__.cpython-39.pyc and /dev/null differ
diff --git a/models_converter/utils/matrix/__pycache__/matrix2x2.cpython-39.pyc b/models_converter/utils/matrix/__pycache__/matrix2x2.cpython-39.pyc
deleted file mode 100644
index 9ec91e1..0000000
Binary files a/models_converter/utils/matrix/__pycache__/matrix2x2.cpython-39.pyc and /dev/null differ
diff --git a/models_converter/utils/matrix/__pycache__/matrix3x3.cpython-39.pyc b/models_converter/utils/matrix/__pycache__/matrix3x3.cpython-39.pyc
deleted file mode 100644
index 09c0e41..0000000
Binary files a/models_converter/utils/matrix/__pycache__/matrix3x3.cpython-39.pyc and /dev/null differ
diff --git a/models_converter/utils/matrix/__pycache__/matrix4x4.cpython-39.pyc b/models_converter/utils/matrix/__pycache__/matrix4x4.cpython-39.pyc
deleted file mode 100644
index d41f0ae..0000000
Binary files a/models_converter/utils/matrix/__pycache__/matrix4x4.cpython-39.pyc and /dev/null differ
diff --git a/setup.py b/setup.py
index be7912e..7958b50 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name='3d-converter',
- version='0.8.8',
+ version='0.9.0',
author='Vorono4ka',
author_email='crowo4ka@gmail.com',
description='Python 3D Models Converter',
@@ -20,5 +20,5 @@
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: OS Independent',
],
- python_requires='>=3.7',
+ python_requires='>=3.9',
)