22
33import math
44import struct
5- from typing import TYPE_CHECKING , List , Optional , Sequence , Tuple , TypeVar , Union , cast
5+ from typing import TYPE_CHECKING , List , Optional , Tuple , Union , cast
66
77from ..classes .generated import (
88 ChannelInfo ,
3434Tuple3f = Tuple [float , float , float ]
3535Tuple4f = Tuple [float , float , float , float ]
3636
37- T = TypeVar ("T" )
38-
39-
40- def flat_list_to_tuples (data : Sequence [T ], item_size : int ) -> List [tuple [T , ...]]:
41- return [tuple (data [i : i + item_size ]) for i in range (0 , len (data ), item_size )]
42-
4337
4438def vector_list_to_tuples (
4539 data : Union [List [Vector2f ], List [Vector3f ], List [Vector4f ]],
@@ -58,14 +52,12 @@ def vector_list_to_tuples(
5852 raise ValueError ("Unknown vector type" )
5953
6054
61- def zeros (shape : Union [Tuple [int ], Tuple [int , int ]]) -> Union [List , List [List ]]:
62- if len (shape ) == 1 :
63- return [0 ] * shape [0 ]
64- elif len (shape ) == 2 :
65- m , n = shape
66- return [[0 ] * n for _ in range (m )]
67- else :
68- raise ValueError ("Invalid shape" )
55+ def lists_to_tuples (data : List [list ]) -> List [tuple ]:
56+ return [tuple (v ) for v in data ]
57+
58+
59+ def zeros (m : int , n : int ) -> List [list ]:
60+ return [[0 ] * n for _ in range (m )]
6961
7062
7163def normalize (* vector : float ) -> Tuple [float , ...]:
@@ -234,21 +226,12 @@ def copy_from_mesh(self):
234226
235227 if self .m_BoneWeights is None and mesh .m_Skin :
236228 # BoneInfluence == BoneWeight in terms of usage in UnityPy due to int simplification
237- self .m_BoneWeights = zeros ((len (mesh .m_Skin ), 4 ))
238- self .m_BoneIndices = zeros ((len (mesh .m_Skin ), 4 ))
239- for skin , indices , weights in zip (mesh .m_Skin , self .m_BoneIndices , self .m_BoneWeights ):
240- indices [:] = [
241- skin .boneIndex_0_ ,
242- skin .boneIndex_1_ ,
243- skin .boneIndex_2_ ,
244- skin .boneIndex_3_ ,
245- ]
246- weights [:] = [
247- skin .weight_0_ ,
248- skin .weight_1_ ,
249- skin .weight_2_ ,
250- skin .weight_3_ ,
251- ]
229+ self .m_BoneIndices = [
230+ (skin .boneIndex_0_ , skin .boneIndex_1_ , skin .boneIndex_2_ , skin .boneIndex_3_ ) for skin in mesh .m_Skin
231+ ]
232+ self .m_BoneWeights = [
233+ (skin .weight_0_ , skin .weight_1_ , skin .weight_2_ , skin .weight_3_ ) for skin in mesh .m_Skin
234+ ]
252235
253236 def copy_from_spriterenderdata (self ):
254237 rd = self .src
@@ -401,10 +384,7 @@ def read_vertex_data(self, m_Channels: list[ChannelInfo], m_Streams: list[Stream
401384 buff = buff [::- 1 ]
402385 componentBytes [componentDataSrc : componentDataSrc + component_byte_size ] = buff
403386
404- count = len (componentBytes ) // component_byte_size
405- component_data = struct .unpack (f">{ count } { component_dtype } " , componentBytes )
406- component_data = flat_list_to_tuples (component_data , channel_dimension )
407-
387+ component_data = list (struct .iter_unpack (f">{ channel_dimension } { component_dtype } " , componentBytes ))
408388 self .assign_channel_vertex_data (chn , component_data )
409389
410390 def assign_channel_vertex_data (self , channel : int , component_data : list ):
@@ -483,10 +463,11 @@ def get_channel_component_size(self, m_Channel: ChannelInfo):
483463 def decompress_compressed_mesh (self ):
484464 # TODO: m_Triangles????
485465
486- # Vertex
487466 version = self .version
467+ assert isinstance (self .src , Mesh )
488468 m_CompressedMesh = self .src .m_CompressedMesh
489469
470+ # Vertex
490471 self .m_VertexCount = m_VertexCount = m_CompressedMesh .m_Vertices .m_NumItems // 3
491472
492473 if m_CompressedMesh .m_Vertices .m_NumItems > 0 :
@@ -543,8 +524,8 @@ def decompress_compressed_mesh(self):
543524 normalData = unpack_floats (m_CompressedMesh .m_Normals , shape = (2 ,))
544525 signs = unpack_ints (m_CompressedMesh .m_NormalSigns )
545526
546- self . m_Normals = zeros (( self .m_VertexCount , 3 ) )
547- for srcNrm , sign , dstNrm in zip (normalData , signs , self . m_Normals ):
527+ normals = zeros (self .m_VertexCount , 3 )
528+ for srcNrm , sign , dstNrm in zip (normalData , signs , normals ):
548529 x , y = srcNrm
549530 zsqr = 1 - x * x - y * y
550531 if zsqr >= 0 :
@@ -555,13 +536,15 @@ def decompress_compressed_mesh(self):
555536 dstNrm [:] = normalize (x , y , z )
556537 if sign == 0 :
557538 dstNrm [2 ] *= - 1
539+ self .m_Normals = lists_to_tuples (normals )
558540
559541 # Tangent
560542 if m_CompressedMesh .m_Tangents .m_NumItems > 0 :
561543 tangentData = unpack_floats (m_CompressedMesh .m_Tangents , shape = (2 ,))
562544 signs = unpack_ints (m_CompressedMesh .m_TangentSigns , shape = (2 ,))
563- self .m_Tangents = zeros ((self .m_VertexCount , 4 ))
564- for srcTan , (sign_z , sign_w ), dstTan in zip (tangentData , signs , self .m_Tangents ):
545+
546+ tangents = zeros (self .m_VertexCount , 4 )
547+ for srcTan , (sign_z , sign_w ), dstTan in zip (tangentData , signs , tangents ):
565548 x , y = srcTan
566549 zsqr = 1 - x * x - y * y
567550 z = 0
@@ -574,6 +557,7 @@ def decompress_compressed_mesh(self):
574557 z = - z
575558 w = 1.0 if sign_w > 0 else - 1.0
576559 dstTan [:] = x , y , z , w
560+ self .m_Tangents = lists_to_tuples (tangents )
577561
578562 # FloatColor
579563 if version [0 ] >= 5 : # 5.0 and up
@@ -589,14 +573,14 @@ def decompress_compressed_mesh(self):
589573 j = 0
590574 sum = 0
591575
592- self . m_BoneWeights = zeros (( self .m_VertexCount , 4 ) )
593- self . m_BoneIndices = zeros (( self .m_VertexCount , 4 ) )
576+ boneWeights = zeros (self .m_VertexCount , 4 )
577+ boneIndices = zeros (self .m_VertexCount , 4 )
594578
595579 boneIndicesIterator = iter (boneIndicesData )
596580 for weight , boneIndex in zip (weightsData , boneIndicesIterator ):
597581 # read bone index and weight
598- self . m_BoneWeights [vertexIndex ][j ] = weight / 31
599- self . m_BoneIndices [vertexIndex ][j ] = boneIndex
582+ boneWeights [vertexIndex ][j ] = weight / 31
583+ boneIndices [vertexIndex ][j ] = boneIndex
600584
601585 j += 1
602586 sum += weight
@@ -612,13 +596,16 @@ def decompress_compressed_mesh(self):
612596 # we read three weights, but they don't add up to one. calculate the fourth one, and read
613597 # missing bone index. continue with next vertex.
614598 elif j == 3 : #
615- self . m_BoneWeights [vertexIndex ][j ] = 1 - sum
616- self . m_BoneIndices [vertexIndex ][j ] = next (boneIndicesIterator )
599+ boneWeights [vertexIndex ][j ] = 1 - sum
600+ boneIndices [vertexIndex ][j ] = next (boneIndicesIterator )
617601
618602 vertexIndex += 1
619603 j = 0
620604 sum = 0
621605
606+ self .m_BoneWeights = lists_to_tuples (boneWeights )
607+ self .m_BoneIndices = lists_to_tuples (boneIndices )
608+
622609 # IndexBuffer
623610 if m_CompressedMesh .m_Triangles .m_NumItems > 0 : #
624611 self .m_IndexBuffer = unpack_ints (m_CompressedMesh .m_Triangles )
@@ -637,10 +624,10 @@ def decompress_compressed_mesh(self):
637624
638625 def get_triangles (self ) -> List [List [Tuple [int , ...]]]:
639626 assert self .m_IndexBuffer is not None
627+ assert self .src .m_SubMeshes is not None
640628
641629 submeshes : List [List [Tuple [int , ...]]] = []
642630
643- assert self .src and self .src .m_SubMeshes is not None , "No submesh data!"
644631 for m_SubMesh in self .src .m_SubMeshes :
645632 firstIndex = m_SubMesh .firstByte // 2
646633 if not self .m_Use16BitIndices :
@@ -652,38 +639,37 @@ def get_triangles(self) -> List[List[Tuple[int, ...]]]:
652639 triangles : List [Tuple [int , ...]]
653640
654641 if topology == MeshTopology .Triangles :
655- triangles = self .m_IndexBuffer [firstIndex : firstIndex + indexCount ] # type: ignore
656- triangles = [triangles [i : i + 3 ] for i in range (0 , len (triangles ), 3 )] # type: ignore
657- elif self .version [0 ] < 4 or topology == MeshTopology .TriangleStrip : # TriangleStrip
658- # todo: use as_strided, then fix winding, finally remove degenerates
659- triIndex = 0
660- triangles = [None ] * (indexCount - 2 ) # type: ignore
642+ triangles = [
643+ tuple (self .m_IndexBuffer [i : i + 3 ]) for i in range (firstIndex , firstIndex + indexCount , 3 )
644+ ]
661645
662- for i in range (indexCount - 2 ):
663- a , b , c = self .m_IndexBuffer [firstIndex + i : firstIndex + i + 3 ]
646+ elif self .version [0 ] < 4 or topology == MeshTopology .TriangleStrip :
647+ triangles = [()] * (indexCount - 2 )
648+ triIndex = 0
649+ for i in range (firstIndex , firstIndex + indexCount - 2 ):
650+ a , b , c = self .m_IndexBuffer [i : i + 3 ]
664651 # skip degenerates
665652 if a == b or a == c or b == c :
666653 continue
667-
668654 # do the winding flip-flop of strips
669- if i & 1 :
670- triangles [triIndex ] = b , a , c
655+ if ( i - firstIndex ) & 1 :
656+ triangles [triIndex ] = ( b , a , c )
671657 else :
672- triangles [triIndex ] = a , b , c
658+ triangles [triIndex ] = ( a , b , c )
673659 triIndex += 1
674-
675660 triangles = triangles [:triIndex ]
661+ m_SubMesh .indexCount = len (triangles ) * 3
676662
677663 elif topology == MeshTopology .Quads :
678664 # one quad is two triangles, so // 4 * 2 = // 2
679- # TODO: use as_strided
680- triangles = [None ] * (indexCount // 2 ) # type: ignore
665+ triangles = [()] * (indexCount // 2 )
681666 triIndex = 0
682667 for i in range (firstIndex , firstIndex + indexCount , 4 ):
683668 a , b , c , d = self .m_IndexBuffer [i : i + 4 ]
684- triangles [triIndex ] = a , b , c
685- triangles [triIndex + 1 ] = a , c , d
669+ triangles [triIndex ] = ( a , b , c )
670+ triangles [triIndex + 1 ] = ( a , c , d )
686671 triIndex += 2
672+
687673 else :
688674 raise ValueError ("Failed getting triangles. Submesh topology is lines or points." )
689675
0 commit comments