
    +j?                         d Z ddlZddlZddlZddlZddlmZ ddlZddl	m
Z
 ddlZddlmZ ddlZddlmZ ddlmZmZmZ dd	Zd
 Z	 	 ddZ G d dej                  Z G d de          ZdefdZdS )zMSave-side 3D nodes: mesh packing/slicing helpers + GLB writer + SaveGLB node.    N)BytesIO)Image)override)args)ComfyExtensionIOTypesFc           
         t          |           }t          d | D                       }t          d |D                       }| d                             ||| d         j        d         f          }	|d                             |||d         j        d         f          }
t	          j        d | D             | d         j        t          j                  }t	          j        d |D             |d         j        t          j                  }t          t          | |                    D ]0\  }\  }}||	|d |j        d         f<   ||
|d |j        d         f<   1d }||d                             |||d         j        d         f          }t          |          D ]k\  }}|j        d         | |         j        d         k    s0J d| d	|j        d          d
| |         j        d          d            |||d |j        d         f<   ld }||d                             |||d         j        d         f          }t          |          D ]k\  }}|j        d         | |         j        d         k    s0J d| d	|j        d          d
| |         j        d          d            |||d |j        d         f<   lt          j        |	|
||||||          S )Nc              3   0   K   | ]}|j         d          V  dS r   Nshape.0vs     :/home/wildlama/comfy/ComfyUI/comfy_extras/nodes_save_3d.py	<genexpr>z+pack_variable_mesh_batch.<locals>.<genexpr>   s(      44aqwqz444444    c              3   0   K   | ]}|j         d          V  dS r   r   r   fs     r   r   z+pack_variable_mesh_batch.<locals>.<genexpr>   s(      ..1AGAJ......r   r      c                 (    g | ]}|j         d          S r   r   r   s     r   
<listcomp>z,pack_variable_mesh_batch.<locals>.<listcomp>   s    !?!?!?!'!*!?!?!?r   )devicedtypec                 (    g | ]}|j         d          S r   r   r   s     r   r   z,pack_variable_mesh_batch.<locals>.<listcomp>   s    :::q
:::r   z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#   ir   r   packed_colorsc
packed_uvsus                       r   pack_variable_mesh_batchr;      s   
 XJ44844444L.......Iqk++ZxPQ{GXYZG[,\]]O8%%z9eAhnQ>O&PQQLL!?!?h!?!?!?QRHZbgbmnnnM,::E:::58?Z_ZefffKs8U3344 ) )	6Aq*+;AGAJ;''(Q^$$Mq	++ZvayWXGY,Z[[f%% 	. 	.DAq71:!!21!5555sss!'!*ssRSIZ[\I]sss 655 -.M![agaj[.))J
V%%z<Qa&QRR
cNN 	+ 	+DAq71:!!21!5555iqii
iix{?PQR?Siii 655 *+Jq+171:+~&&:o|$M7$1{RWY Y Y Yr   c                    t          | dd           }t          | dd           }t          | dd           t          | j        |                                                   }t          | j        |                                                   }| j        |d |f         }| j        |d |f         }|||d |f         nd }|||d |f         nd }	||||	fS |||         nd }|||         nd }	| j        |         | j        |         ||	fS )Nr    r   r"   )getattrintr"   itemr#   r.   r/   )
meshindexv_colorsv_uvsvertex_count
face_countr.   r/   r0   r   s
             r   get_mesh_batch_itemrF   <   s.    t_d33HD%&&Et_d++74-e499;;<<)%0557788
=!56
5+:+-.3;3G%,.//T-2->eE=L=())D++ ( 4Xe__$F+%,,C=E!2FC??r   c           	         |                                                                                      t          j                  }|                                                                                     t          j                  }	|C|                                                                                     t          j                  nd}
|C|                                                                                     t          j                  nd}|t          j        |dd          }|j        d         }|dk    rt          d          |	j	        dk    rft          |	                                          }t          |	                                          }|dk     s||k    rt          d| d| d|           |
1|
j        d         |k    r t          d	|
j        d          d
|           |1|j        d         |k    r t          d|j        d          d
|           |	                    t          j                  }d}|9t                      }|                    |d           |                                }|                                }|                                }|
|
                                nd}||                                nd}||nd}d } ||          } ||          } ||          } ||          } ||          }d                    |||||g          }t'          |          }d}t'          |          } t'          |          }!|!t'          |          z   }"|"t'          |          z   }#|#t'          |          z   }$d||ddd|!| ddg}%dddt'          |          d|                    d                                          |                    d                                          dddd|j	        ddg}&ddi}'|
t'          |
          dk    rs|%                    d|"t'          |          dd           t'          |&          }(|&                    t'          |%          dz
  ddt'          |
          dd           |(|'d<   |t'          |          dk    r|%                    d|#t'          |          dd           t'          |&          }(|&                    t'          |%          dz
  ddt'          |          |j        d         dk    rdndd           |(|'d <   |'dd!d"})g }*g }+g },g }-g }.|r=|;|-                    g d#ddd$d%i id&d'           |.                    d%           d|)d(<   |d|'v r|%                    d|$t'          |          d)           |*                    t'          |%          dz
  d*d+           |,                    d,d,d-d-d.           |+                    ddd/           |-                    ddd0ddd1d&d2           d|)d(<   d3d4d5d6t'          |          ig|%|&d7|)gigd8digd9dgigdd:}/|*r|*|/d;<   |,r|,|/d<<   |+r|+|/d=<   |-r|-|/d><   |.r|.|/d?<   |r||/d@         dA<   t-          j        |/                              dB          }0dC }1 |1|0          }2t3          j        dDdEdFdGt'          |2          z   dHz   t'          |          z             }3t3          j        dIt'          |2          dJ          }4t3          j        dIt'          |          dK          }5t7          |dL          5 }6|6                    |3           |6                    |4           |6                    |2           |6                    |5           |6                    |           ddd           n# 1 swxY w Y   |S )Mai  
    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)formatr   c                 B    dt          |           dz  z
  dz  }| d|z  z   S )N       r%   bufferpadding_lengths     r   pad_to_4_bytesz save_glb.<locals>.pad_to_4_bytes   s+    s6{{Q/14.000r   i  )rQ   
byteOffset
byteLengthtargeti  i  VEC3)axis)
bufferViewrT   componentTypecounttyper&   minr   i  SCALAR)rY   rT   rZ   r[   r\   POSITIONVEC2
TEXCOORD_0   VEC4COLOR_0rM   )
attributesindicesmode)rI   rI   rI   rI   )baseColorFactormetallicFactorroughnessFactorKHR_materials_unlitT)pbrMetallicRoughness
extensionsdoubleSidedmaterial)rQ   rT   rU   z	image/png)rY   mimeTypei&  i/  )	magFilter	minFilterwrapSwrapT)sourcesampler)rA   texCoord)baseColorTextureri   rj   )rl   rn   z2.0ComfyUI)version	generatorrU   
primitivesr@   nodes)assetbuffersbufferViews	accessorsmeshesr}   scenessceneimagessamplerstextures	materialsextensionsUsedr~   extrasutf8c                 B    dt          |           dz  z
  dz  }| d|z  z   S )NrM       rO   rP   s     r   pad_json_to_4_bytesz%save_glb.<locals>.pad_json_to_4_bytes&  s+    s6{{Q/14~---r   z<4sIIs   glTF         z<IIiJSONiBIN wb)cpunumpyastypenpfloat32r*   clipr   
ValueErrorsizer>   r]   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_bufferrS   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;;$$&&--bh77L58_SWWYY__%%bj111$FBOB[!!##))++222:>>>aeIGIsC00	"G!||67771<##%%&&<##%%&&!88tw[[[[[UY[[   fl1o88XaXXwXX
 
 	
 !3w!>!>e9?1+=ee\cee
 
 	
 ""29--H ii3u---LLNN!))++O%%''N%+%7!!!SJ+4+@I%%'''cM*;*G&&SN1 1 1 ,^O<<*N>::&z22)>-88*N>::((  K //n--455)C0E,F,FFO(3/@+A+AA,s3G/H/HH ..		
 	
 --		
 	
L  !%%???**1133???**1133	
 	
 !]	
 	
I$ '?c&kkAoo)j//	
 
 	 	 	 9~~l++a/![[
 
 	 	 	 .:\*Y!!3!3,m,,	
 
 	 	 	 9~~l++a/!^^'oa0A55FF6
 
 	 	 	 +7Y' + I FHHIO 	""* 	8L8L8L`cx{$|$|0"5
 
 	 	 	
 	4555 !	*$9M)M)M-n--
 
 	 	 	
 	S%6%6%:TTUUUdX]^^___133444./Q$?$?"%#&% %
  
 
 	 	 	 !"	* #;;!3{#3#345# 9+./1+aS>"	 	D   X $#Z $#Z &%[ 1!0 +"*Wh 
4  ''//I. . . +*955 Wgq&3?O;P;P2PST2TWZ[fWgWg2ghhJ E3/?+@+@*MM {5#k*:*:JGG 
h		 	
	!"""	 !!!	 !!!	               Os   A*___c                   l    e Zd Zed             Zedej        ej        z  dede	j
        fd            ZdS )SaveGLBc                 X   t          j        ddddgdddt           j                            t           j                            d          t           j        t           j        t           j        t           j        t           j	        t           j
        t           j        t           j        t           j        t           j        t           j        t           j        t           j        gd	
          t           j                            dd          gt           j        j        t           j        j        g          S )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_schemazSaveGLB.define_schemaA  s    y(-{; (""GMM&))). 6# #  & 	 1<HH), I$bi&=>;
 
 
 	
r   r@   r   returnc                    t          j        |t          j                              \  }}}}}g }i }t          j        so| j        j        !t          j        | j        j                  |d<   | j        j	        6| j        j	        D ])}	t          j        | j        j	        |	                   ||	<   *t          |t          j                  rg|j        pd}
| d|dd|
 }|                    t          j                            ||                     |                    ||dd           |dz  }nt'          |d	d           }d }||                    d
d                                                                          dz                      t0          j                  }|j        dk    r|j        d         dk    sJ dt9          |j                               t;          |j        j        d                   D ]}t?          ||          \  }}}}|j        d         dk    s|j        d         dk    rtA          j!        d|            Q|tE          j#        ||         d          nd }| d|dd}tI          ||t          j                            ||          ||||t'          |dd                     |                    ||dd           |dz  }tK          j&        d|i          S )Nr   glb_05z_.output)filename	subfolderr\   r   r!   rH   rI      rM   rb   z,texture must be (B, H, W, 3) RGB, got shape r   z,SaveGLB: skipping empty mesh at batch index RGB)rg   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	   File3DrK   save_toospathr   r   r=   clampr   r   r   r   uint8ndimr   tupleranger.   rF   loggingwarningr   	fromarrayr   r   
NodeOutput)r   r@   r   full_output_folderr  counterr  resultsr   xextr   	texture_b
texture_npr6   
vertices_ifaces_irB   uvs_itex_imgs                       r   executezSaveGLB.executec  sI   LXLlm|  K  `  b  b  Mc  McIHgy/$ 	Jz ,%)Z
0A%B%B"z'31 J JA"&*SZ-Ea-H"I"IHQKKdEL)) %	+&C11g111C11ALL&8!<<===NN&     
 qLGG  i66IJ$'ooc377;;==CCEEKSSTVT\]]
!!++
0@0D0I0I0I\5IYCZCZ\\ 1J0II 4=.q122  7J4QR7S7S4
GXu#A&!++w}Q/?1/D/DO$VST$V$VWWWHRH^%/*Q-eDDDDdh33'3333Wbgll;Mq.Q.QS["'/'.&tWe<<	> > > >
  !!*$      
 1}w0000r   N)__name__
__module____qualname__classmethodr   r	   r-   r  strr   r  r%   r   r   r   r   @  sn        
 
 [
B 215:4 21s 21r} 21 21 21 [21 21 21r   r   c                   L    e Zd Zedeeej                          fd            ZdS )Save3DExtensionr   c                    K   t           gS N)r   )selfs    r   get_node_listzSave3DExtension.get_node_list  s      yr   N)	r&  r'  r(  r   listr\   r   	ComfyNoder1  r+  r   r   r-  r-    sE        T$r|*<%=    X  r   r-  r   c                  "   K   t                      S r/  )r-  r+  r   r   comfy_entrypointr5    s      r   )NNNF)NNNNF)__doc__r   r  r  r   ior   r   r   PILr   r(   typing_extensionsr   r  comfy.cli_argsr   comfy_api.latestr   r   r	   r;   rF   r   r3  r   r-  r5  r+  r   r   <module>r<     s   S S   				                   & & & & & &           6 6 6 6 6 6 6 6 6 6&Y &Y &Y &YR@ @ @& 26EJn n n nbV1 V1 V1 V1 V1bl V1 V1 V1r    n         r   