
    +j?                         S r SSKrSSKrSSKrSSKrSSKJr  SSKrSSK	J
r
  SSKrSSKJr  SSKrSSKJr  SSKJrJrJr  SS jrS	 r  SS
 jr " S S\R0                  5      r " S S\5      rS\4S jrg)zMSave-side 3D nodes: mesh packing/slicing helpers + GLB writer + SaveGLB node.    N)BytesIO)Image)override)args)ComfyExtensionIOTypesc                    [        U 5      n[        S U  5       5      n[        S U 5       5      nU S   R                  XgU S   R                  S   45      n	US   R                  XhUS   R                  S   45      n
[        R
                  " U  Vs/ s H  oR                  S   PM     snU S   R                  [        R                  S9n[        R
                  " U Vs/ s H  oR                  S   PM     snUS   R                  [        R                  S9n[        [        X5      5       H2  u  nu  pXUS UR                  S   24'   XUS UR                  S   24'   M4     S nUb  US   R                  XgUS   R                  S   45      n[        U5       Hk  u  nnUR                  S   X   R                  S   :X  d-   SU SUR                  S    SX   R                  S    S	35       eUUUS UR                  S   24'   Mm     S nUb  US   R                  XgUS   R                  S   45      n[        U5       Hk  u  nnUR                  S   X   R                  S   :X  d-   S
U SUR                  S    SX   R                  S    S	35       eUUUS UR                  S   24'   Mm     [        R                  " XUUUXUS9$ s  snf s  snf )Nc              3   >   #    U  H  oR                   S    v   M     g7fr   Nshape).0vs     :/home/wildlama/comfy/ComfyUI/comfy_extras/nodes_save_3d.py	<genexpr>+pack_variable_mesh_batch.<locals>.<genexpr>   s     48awwqz8   c              3   >   #    U  H  oR                   S    v   M     g7fr   r   )r   fs     r   r   r      s     .1GGAJr   r      )devicedtypezvertex_colors[z] has z entries, expected z (1:1 with vertices)zuvs[)uvsvertex_colorstexturevertex_countsface_countsunlit)lenmax	new_zerosr   torchtensorr   int64	enumeratezipr	   MESH)verticesfacescolorsr   r   r   
batch_sizemax_vertices	max_facespacked_verticespacked_facesr   r   r   r   ipacked_colorsc
packed_uvsus                       r   pack_variable_mesh_batchr6      s   
 XJ4844L...Iqk++ZxPQ{GXGXYZG[,\]O8%%zeAhnnQ>O&PQLLLh!?h''!*h!?QRHZHZbgbmbmnM,,E:Eq
E:58??Z_ZeZefKs834	6A*+;AGGAJ;''(Q^$ 5 Mq	++ZvayWXGY,Z[f%DAq771:!2!21!55  6!''!*5HIZIZ[\I]H^^rs5 -.M![aggaj[.)	 & J
V%%zQa&QR
cNDAq771:!2!21!55 qc
|+>x{?P?PQR?S>TThi5 *+Jq+1771:+~&	 # ::o$M7$1RWY Y3 "@:s   KK
c                    [        U SS 5      n[        U SS 5      n[        U SS 5      b  [        U R                  U   R                  5       5      n[        U R                  U   R                  5       5      nU R
                  US U24   nU R                  US U24   nUb  X!S U24   OS nUb  X1S U24   OS n	XgX4$ Ub  X!   OS nUb  X1   OS n	U R
                  U   U R                  U   X4$ )Nr   r   r   )getattrintr   itemr   r)   r*   )
meshindexv_colorsv_uvsvertex_count
face_countr)   r*   r+   r   s
             r   get_mesh_batch_itemrA   <   s    t_d3HD%&Et_d+74--e499;<))%05578
==!56

5+:+-.3;3G,./T-2->e=L=()D++ ( 4X_$F+%,C==E!2F??    c           
         U R                  5       R                  5       R                  [        R                  5      nUR                  5       R                  5       R                  [        R
                  5      n	Ub;  UR                  5       R                  5       R                  [        R                  5      OSn
Ub;  UR                  5       R                  5       R                  [        R                  5      OSnUb  [        R                  " USS5      nUR                  S   nUS:X  a  [        S5      eU	R                  S:  aQ  [        U	R                  5       5      n[        U	R                  5       5      nUS:  d  X:  a  [        SU SU SU 35      eU
b1  U
R                  S   U:w  a  [        S	U
R                  S    S
U 35      eUb1  UR                  S   U:w  a  [        SUR                  S    S
U 35      eU	R                  [        R                  5      nSnUb*  [        5       nUR                  USS9  UR!                  5       nUR#                  5       nUR#                  5       nU
b  U
R#                  5       OSnUb  UR#                  5       OSnUb  UOSnS nU" U5      nU" U5      nU" U5      nU" U5      nU" U5      nSR%                  UUUUU/5      n['        U5      nSn['        U5      n ['        U5      n!U!['        U5      -   n"U"['        U5      -   n#U#['        U5      -   n$SUUSS.SU!U SS./n%SSS['        U5      SUR                  SS9R)                  5       UR                  SS9R)                  5       S.SSSUR                  SS./n&SS0n'U
bj  ['        U
5      S:  a[  U%R+                  SU"['        U5      SS.5        ['        U&5      n(U&R+                  ['        U%5      S-
  SS['        U
5      SS.5        U(U'S'   Ub  ['        U5      S:  ap  U%R+                  SU#['        U5      SS.5        ['        U&5      n(U&R+                  ['        U%5      S-
  SS['        U5      UR                  S   S:X  a  SOSS.5        U(U'S '   U'SS!S".n)/ n*/ n+/ n,/ n-/ n.U(       a6  Uc3  U-R+                  / S#QSSS$.S%0 0S&S'.5        U.R+                  S%5        SU)S('   Ub  SU';   a  U%R+                  SU$['        U5      S).5        U*R+                  ['        U%5      S-
  S*S+.5        U,R+                  S,S,S-S-S..5        U+R+                  SSS/.5        U-R+                  SSS0.SSS1.S&S2.5        SU)S('   S3S4S5.S6['        U5      0/U%U&S7U)/0/S8S0/S9S/0/SS:.n/U*(       a  U*U/S;'   U,(       a  U,U/S<'   U+(       a  U+U/S='   U-(       a  U-U/S>'   U.(       a  U.U/S?'   U(       a  UU/S@   SA'   [,        R.                  " U/5      R1                  SB5      n0SC n1U1" U05      n2[2        R4                  " SDSESFSG['        U25      -   SH-   ['        U5      -   5      n3[2        R4                  " SI['        U25      SJ5      n4[2        R4                  " SI['        U5      SK5      n5[7        USL5       n6U6R9                  U35        U6R9                  U45        U6R9                  U25        U6R9                  U55        U6R9                  U5        SSS5        U$ ! , (       d  f       U$ = f)MaA  
Save PyTorch tensor vertices and faces as a GLB file without external dependencies.

Parameters:
vertices: torch.Tensor of shape (N, 3) - The vertex coordinates
faces: torch.Tensor of shape (M, 3) - The face indices (triangle faces)
filepath: str - Output filepath (should end with .glb)
metadata: dict - Optional asset.extras metadata
uvs: torch.Tensor of shape (N, 2) - Optional per-vertex texture coordinates
vertex_colors: torch.Tensor of shape (N, 3) or (N, 4) - Optional per-vertex colors in [0, 1]
texture_image: PIL.Image - Optional baseColor texture, embedded as PNG
N              ?r   zsave_glb: vertices is emptyz&save_glb: face index out of range [0, z): min=z, max=zsave_glb: uvs has z entries but vertex count is zsave_glb: vertex_colors has PNG)formatrB   c                 :    S[        U 5      S-  -
  S-  nU SU-  -   $ )N       r    bufferpadding_lengths     r   pad_to_4_bytes save_glb.<locals>.pad_to_4_bytes   s)    s6{Q/14.000rB   i  )rM   
byteOffset
byteLengthtargeti  i  VEC3)axis)
bufferViewrQ   componentTypecounttyper!   minr   i  SCALAR)rV   rQ   rW   rX   rY   POSITIONVEC2
TEXCOORD_0   VEC4COLOR_0rI   )
attributesindicesmode)rE   rE   rE   rE   )baseColorFactormetallicFactorroughnessFactorKHR_materials_unlitT)pbrMetallicRoughness
extensionsdoubleSidedmaterial)rM   rQ   rR   z	image/png)rV   mimeTypei&  i/  )	magFilter	minFilterwrapSwrapT)sourcesampler)r<   texCoord)baseColorTexturerf   rg   )ri   rk   z2.0ComfyUI)version	generatorrR   
primitivesr;   nodes)assetbuffersbufferViews	accessorsmeshesrz   scenessceneimagessamplerstextures	materialsextensionsUsedr{   extrasutf8c                 :    S[        U 5      S-  -
  S-  nU SU-  -   $ )NrI       rK   rL   s     r   pad_json_to_4_bytes%save_glb.<locals>.pad_json_to_4_bytes&  s)    s6{Q/14~---rB   z<4sIIs   glTF         z<IIiJSONiBIN wb)cpunumpyastypenpfloat32r%   clipr   
ValueErrorsizer9   rZ   r!   uint32r   savegetvaluetobytesjoinr    tolistappendjsondumpsencodestructpackopenwrite)7r)   r*   filepathmetadatar   r   texture_imager   vertices_npfaces_signeduvs_np	colors_npn_vertsfminfmaxfaces_nptexture_png_bytesbufvertices_bufferindices_buffer
uvs_buffercolors_buffertexture_bufferrO   vertices_buffer_paddedindices_buffer_paddeduvs_buffer_paddedcolors_buffer_paddedtexture_buffer_paddedbuffer_datavertices_byte_lengthvertices_byte_offsetindices_byte_lengthindices_byte_offsetuvs_byte_offsetcolors_byte_offsettexture_byte_offsetbuffer_viewsr~   primitive_attributesaccessor_idx	primitiver   r   r   r   extensions_usedgltf	gltf_jsonr   gltf_json_padded
glb_headerjson_chunk_headerbin_chunk_headerr   s7                                                          r   save_glbr   O   s     ,,.&&(//

;K99;$$&--bhh7L58_SWWY__%%bjj1$FBOB[!!#))+222::>aeIGGIsC0	"G!|6771<##%&<##%&!8t8	fUYTZ[  fll1o8 a 11NwiX
 	
 !3w!>*9??1+=*>>[\c[de
 	
 ""299-H i3u-LLN!))+O%%'N%+%7!SJ+4+@I%%'cM*;*G&SN1 ,O<*>:&z2)-8*>:(( K /n-45)C0E,FFO(3/@+AA,s3G/HH ..		
 --		
L  !%???*113???*113	
 !]]	
I$ '?c&kAo)j/	
 	 9~l+a/![
 	 .:\*Y!!3,m,	
 	 9~l+a/!^'ooa0A5F6
 	 +7Y' +I FHHIO"* 	8L`cx{$|0"5
 	
 	45 !	*$9M)M-n-
 	
 	S%6%:TUdX]^_134./Q$?"%#&%
  
 	 !"	* #;!3{#345# 9+./1+aS>"	D X#Z#Z%[!0"*Wh 

4 ''/I. +95 Wgq&3?O;P2PST2TWZ[fWg2ghJ E3/?+@*M {{5#k*:JG 
h		
	!"	 !	 !	 
 O 
	 Os   A[$$
[3c                       \ rS rSr\S 5       r\S\R                  \R                  -  S\	S\
R                  4S j5       rSrg)	SaveGLBi@  c                    [         R                  " SSSS/SSS[         R                  R                  [         R                  R                  S5      [         R
                  [         R                  [         R                  [         R                  [         R                  [         R                  [         R                  [         R                  [         R                  [         R                  [         R                  [         R                   [         R"                  /S	S
9[         R$                  R                  SSS9/[         R&                  R(                  [         R&                  R*                  /S9$ )Nr   zSave 3D Modelzexport 3d modelz	save mesh3dBasicsTr;   zMesh or 3D file to save)typestooltipfilename_prefixz
3d/ComfyUI)default)node_iddisplay_namesearch_aliasescategoryessentials_categoryis_output_nodeinputshidden)r   Schema	MultiTypeInputMesh	File3DGLB
File3DGLTF	File3DOBJ	File3DFBX	File3DSTL
File3DUSDZ	File3DPLYFile3DSPLAT	File3DSPZFile3DKSPLATFile3DSplatAnyFile3DPointCloudAny	File3DAnyStringHiddenpromptextra_pnginfo)clss    r   define_schemaSaveGLB.define_schemaA  s    yy(-{; (""GGMM&))).. 6# # & 		 1<H), II$$bii&=&=>;
 	
rB   r;   r   returnc                 >   [         R                  " U[         R                  " 5       5      u  p4pVn/ n0 n[        R                  (       d  U R
                  R                  b-  [        R                  " U R
                  R                  5      US'   U R
                  R                  bL  U R
                  R                   H2  n	[        R                  " U R
                  R                  U	   5      X'   M4     [        U[        R                  5      (       aj  UR                  =(       d    Sn
U SUS SU
 3nUR                  [        R                   R#                  X;5      5        UR%                  UUSS.5        US-  nGO['        US	S 5      nS nUb  UR)                  S
S5      R+                  5       R-                  5       S-  R/                  [0        R2                  5      nUR4                  S:X  a  UR6                  S   S:X  d   S[9        UR6                  5       35       e[;        UR<                  R6                  S   5       H  n[?        X5      u  nnnnUR6                  S   S:X  d  UR6                  S   S:X  a  [@        RB                  " SU 35        MT  Ub  [D        RF                  " X   SS9OS nU SUS S3n[I        UU[        R                   R#                  X;5      UUUU['        USS5      S9  UR%                  UUSS.5        US-  nM     [J        RL                  " SU0S9$ )Nr   glb_05z_.output)filename	subfolderrY   r   r   rD   rE      rI   r_   z,texture must be (B, H, W, 3) RGB, got shape r   z,SaveGLB: skipping empty mesh at batch index RGB)rd   z_.glbr   F)r   r   r   r   r   )ui)'folder_pathsget_save_image_pathget_output_directoryr   disable_metadatar   r   r   r   r   
isinstancer	   File3DrG   save_toospathr   r   r8   clampr   r   r   r   uint8ndimr   tupleranger)   rA   loggingwarningr   	fromarrayr   r   
NodeOutput)r   r;   r   full_output_folderr  counterr  resultsr   xextr   	texture_b
texture_npr1   
vertices_ifaces_ir=   uvs_itex_imgs                       r   executeSaveGLB.executec  s   LXLlLlm|  K  `  `  b  McIg/$$zz  ,%)ZZ

0A0A%B"zz''311A"&**SZZ-E-Ea-H"IHK 2 dELL))++&C*Agb\C51ALL&8<=NN&  
 qLG  i6IJ$'ooc37;;=CCEKSSTVT\T\]
!!+
0@0@0D0I B5IYIYCZB[\I 4==..q127J47S4
GXu##A&!+w}}Q/?1/DOO&RSTRU$VWHRH^%//*-eDdhj'"U3Wbggll;M.QS["'/'.&tWe<	>
  !!*$  
 1# 3$ }}w00rB    N)__name__
__module____qualname____firstlineno__classmethodr   r	   r(   r  strr   r  r$  __static_attributes__r&  rB   r   r   r   @  sO    
 
B 215::4 21s 21r}} 21 21rB   r   c                   L    \ rS rSr\S\\\R                        4S j5       r	Sr
g)Save3DExtensioni  r   c                    #    [         /$ 7fN)r   )selfs    r   get_node_listSave3DExtension.get_node_list  s     ys   
r&  N)r'  r(  r)  r*  r   listrY   r   	ComfyNoder3  r-  r&  rB   r   r/  r/    s)    T$r||*<%=  rB   r/  r   c                     #    [        5       $ 7fr1  )r/  r&  rB   r   comfy_entrypointr8    s     s   )NNNF)NNNNF)__doc__r   r  r  r   ior   r   r   PILr   r#   typing_extensionsr   r  comfy.cli_argsr   comfy_api.latestr   r   r	   r6   rA   r   r6  r   r/  r8  r&  rB   r   <module>r?     sv    S   	      &   6 6&YR@& 26EJnbV1bll V1rn  rB   