Ë
    ;ƒÉjá(  ã                   óÂ  — d Z ddlZddlZddlZddlZddlZddlZddlZddlZej                  j                  ej                  j                  ej                  j                  e«      «      «      Zej                  j                  dej                  j                  ed«      «       ddlZddlZg d¢Zg d¢ZdZdZdZd	Zd
Zd„ Zd„ Zd„ Zd„ Zdefd„Zd„ Zd„ Z e!dk(  rƒejD                  dd Z#e#re#d   dk(  r e e#d    e$e#d   «      «       yde#v r e$e#e#jK                  d«      dz      «      ndZ&de#v r e'e#e#jK                  d«      dz      «      neZ( ee#d   e&e(«       yy)aa  Lighter copy of one library asset: fewer triangles, same look, saved as a new DRAFT version of the same id (games keep
the active version until someone presses 'Use in games').
usage: python3 tools/lighter.py <asset id> [--target <triangles>] [--max-change <pct>]   (no --target = auto)
       python3 tools/lighter.py --activate <asset id> <version>
Auto tries growing error budgets with glTF-Transform simplify (meshoptimizer), renders every try against the original on
the gex44 GPU from 4 sides (tools/gpu/lighter_compare.sh) and keeps the lightest whose worst side changes at most
--max-change % of the model's pixels and no small spot changes by more than MAX_SPOT in brightness. A copy keeps the original's geometry compression (Draco / meshopt) and textures.
Prints the new version number. Exit 3 = no copy worth making (the reason is the last stderr line).é    NÚlib)Únpxz-yz@gltf-transform/cli@4.5.1)	gü©ñÒMb@?gü©ñÒMbP?gü©ñÒMb`?gú~j¼t“h?gü©ñÒMbp?gú~j¼t“x?gü©ñÒMb€?gü©ñÒMb�?g¸…ëQ¸ž?g      @g333333Ã?é2   iˆ  zrrigged and animated people keep their mesh (skin weights, morph targets): the Cast lane makes their light versionsc                  óþ   — t        j                  t        t        | «      z   ddd¬«      }|j                  rHt        d|j                  xs |j                  j                  «       j                  «       d   d d › �«      ‚y )NTiX  ©Úcapture_outputÚtextÚtimeoutzglTF-Transform failed: éÿÿÿÿi,  )
Ú
subprocessÚrunÚGTÚlistÚ
returncodeÚ
SystemExitÚstderrÚstdoutÚstripÚ
splitlines)ÚargsÚrs     útools/lighter.pyÚgtr      sm   € Ü�‰”rœD ›J‘°tÀ$ÐPSÔT€AØ‡|‚|ÜÐ2°A·H±HÒ4HÀÇÁ×3OÑ3OÓ3Q×3\Ñ3\Ó3^Ð_aÑ3bÐcgÐdgÐ3hÐ2iÐjÓkÐkð ó    c                 óè   — |dz   }t        d| |d|d›dt        |«      «       |dv r#t        |||«       t        j                  |«       nt        j                  ||«       t        j                  |«      S )Nz.raw.glbÚsimplifyz--ratioz.4fz--error)ÚdracoÚmeshopt)r   ÚstrÚosÚremoveÚreplaceÚglbÚmeasure)ÚsrcÚoutÚratioÚerrorÚcodecÚraws         r   Úmaker+      se   € Ø
�
Ñ
€CÜ€z�3˜˜Y¨5°¨+¸	Ä3ÀuÃ:ÔNØÐ$Ñ$Ü
ˆ5�#�sÔÜ
�	‰	�#�ä
�
‰
�3˜ÔÜ�;‰;�sÓÐr   c           	      ó–  — |› d�}t        j                  | |D �cg c]!  }t        j                  j	                  |«      ‘Œ# c}dœt        |d«      «       t        j                  t        › d�||› d�g|¢ddd¬«      }|› d	�}|j                  st        j                  j                  |«      sIt        d
|j                  xs |j                  j                  «       j                  «       dd  xs d› �«      ‚t        j                   t        |«      «      }|j#                  d«      st        d
|j#                  d«      › �«      ‚|d   S c c}w )Nz
/spec.json)ÚrowÚfilesÚwz/tools/gpu/lighter_compare.shú/compareTi„  r   z/compare/result.jsonzGPU check failed: r   z	no outputÚokr(   Úresults)ÚjsonÚdumpr    ÚpathÚbasenameÚopenr   r   ÚROOTr   Úexistsr   r   r   r   r   ÚloadÚget)r-   Újdr.   ÚspecÚfr   Úresr&   s           r   Úcomparer@   *   s+  € ØˆT�Ð€DÜ‡I�I�cÀ%Ö$H¸Q¤R§W¡W×%5Ñ%5°aÕ%8Ò$HÑIÌ4ÐPTÐVYË?Ô[Ü�‰œ4˜&Ð =Ð>ÀÈÈÈHÀoÐ^ÐX]Ð^ÐosÐz~ð  ILô  	M€AØˆDÐ$Ð
%€CØ‡|‚|œ2Ÿ7™7Ÿ>™>¨#Ô.ÜÐ-¨q¯x©xÒ/C¸1¿8¹8×.JÑ.JÓ.L×.WÑ.WÓ.YÐZ\ÐZ]Ð.^Ò.mÐbmÐ-nÐoÓpÐpÜ
�)‰)”D˜“IÓ
€CØ�7‰7�4Œ=ÜÐ-¨c¯g©g°gÓ.>Ð-?Ð@ÓAÐAØˆy‰>Ðùò %Is   š&E
c                 óš  — ddl m} d|fD ��cg c]3  }t        d«      D �cg c]  }|j                  | › d|› d|› d�«      ‘Œ c}‘Œ5 }}}|j	                  ddd	«      }t        |«      D ]2  \  }}t        |«      D ]  \  }	}
|j                  |
|	d
z  |d
z  f«       Œ! Œ4 |j                  d«      j                  | › d�d¬«       yc c}w c c}}w )zRcompare.jpg: top row the original from 4 sides, bottom row the copy that was kept.r   )ÚImageé   ú	/compare/Ú_ú.jpgÚRGB)i   i   Úwhitei   )i@  i   z/compare.jpgéV   )ÚqualityN)	ÚPILrB   Úranger7   ÚnewÚ	enumerateÚpasteÚresizeÚsave)r<   ÚpickrB   ÚiÚkÚrowsÚimÚyr   ÚxÚts              r   ÚsheetrZ   7   sÓ   € åØRSÐUYÐQZ×[ÈA¼eÀA»hÖG¸ˆU�Z‰Z˜2˜$˜i¨ s¨!¨A¨3¨dÐ3Õ4ÔGÐ[€DÑ[Ø	�‰�5Ð,¨gÓ	6€BÜ˜$“ò ,‰ˆˆ1Ü˜a“Lò 	,‰DˆAˆqØ�H‰H�Q˜˜S™ ! c¡'Ð*Õ+ñ	,ð,ð ‡I�IˆkÓ×Ñ 2 $ lÐ 3¸RÐÕ@ùò HùÓ[s   ŽC !CÁCÃCc                 óZ  ‡$— t        j                  t        «      }| |vrt        d| › �«      ‚t        j                  ||    «      }||    d   d   dz   }| j                  d«      \  }}|j                  d«      d   dv s"|j                  d	«      s|j                  d
«      rt        t        «      ‚|d   d   |d   d   }	}|t        k  r=t        d|d›dt        d›d�t        j                  ¬«       t        j                  d«       |�$d|cxk  r|k  sn t        d|dz
  d›d|d›d�«      ‚t        › d|› d|› �}
t        j                  j!                  |
«      rt#        j$                  |
«       t        j&                  |
«       |d   d   j                  d«      d   }|
› d�}t#        j(                  t        › d|› d�|«       g Š$|�.|
› d�}‰$j+                  |t-        ||||z  d|	«      ||z  df«       nÉt/        «       }t0        D ]t  }|
› d |› d�}t-        ||d!||	«      }|d   |v s|d   |dt2        d"z  z
  z  k\  rt        j4                  |«       ŒL|j7                  |d   «       ‰$j+                  ||d!|f«       Œv ‰$s@t9        |
«       t        d#|d›d$�t        j                  ¬«       t        j                  d«       | |d%   j                  d&«      |d'   j                  d(d«      d)œ}t;        ||
|g‰$D �cg c]  }|d   ‘Œ	 c}z   «      }|dd  D �cg c]  }|d*   ‘Œ	 }}|dd  D �cg c]  }|d+   ‘Œ	 }}|�d}n¯t=        t?        ||«      «      D ���cg c]  \  }\  }}||k  sŒ|t@        k  sŒ|‘Œ }}}}|sat9        |
«       t        d,‰$d   d   d   d›d-|d   d.›d/|d0›d1|d   › d2t@        › d�t        j                  ¬«       t        j                  d«       tC        |ˆ$fd3„¬4«      }‰$|   \  }}}}d|d   |z  z
  }|t2        k  rCt9        |
«       t        d5|dz  d6›d7�t        j                  ¬«       t        j                  d«       tE        jF                  tI        |d8«      jK                  «       «      jM                  «       }t#        j(                  |t        › d|› d�«       tO        |
|dz   «       tQ        jR                  |«      } | jU                  d9d «       || d<   d:| d;<   i | d   ¥dd<|› �i¥| d<   |d   |d=   |d>   |d?   |d@   |dA   |dB   |d   |dC   dDœ	| d<   tW        t/        | j                  dE«      xs g «      dFhz  «      | dE<   ||dz      dG   }!i dH|d   “dI|“dJtY        |dz  d«      “dK||dz      d*   “dL|!D �"cg c]  }"|"dM   ‘Œ	 c}"“dN|“d+||dz      d+   “dOt@        “dP|�dQndR“dQ|“dStY        |dT«      “dU|“dVt?        ‰$||«      D ���cg c]  \  }}}|d   d   |d   ||dWœ‘Œ c}}}“dXdY“dZt        j                  j[                  |
«      “d[t]        j^                  d\t]        j`                  «       «      “| d]<   i | d^   ¥d_d`|d   › da|d   d›db|d›dc|dz  d6›dd||dz      d*   d.›de||dz      d+   › df�i¥| d^<   t        jb                  | «      | dg<   t        jd                  t        | «      }#t9        |
«       t        |#|d   › dh|dz  d6›dd||dz      d*   › di||dz      d+   › �t        j                  ¬«       t        |«       y c c}w c c}w c c}w c c}}}w c c}"w c c}}}w )jNúunknown asset r   Úversioné   ú/ú.r   )Ú	characterÚmotionzpart.characterÚrigÚrenderÚtrisr)   zalready light: ú,z$ triangles (lighter copies start at ú))Úfileé   éd   ztarget must be between 100 and z triangles (the model has z/jobs/lighter-z-vr.   r#   ú:z/source.glbz/store/blobs/ú.glbz/target.glbz/egš™™™™™©?é   z2already lean: even the largest error budget keeps z triangles within a few %Ú
provenanceÚkitÚsizeÚscale_to_class)Úidro   ÚscaleÚworstÚspotz already lean: the smallest cut (z triangles) already changes z.1fz) % of the model on its worst side (limit Úgz %) or a spot by z/255 (limit c                 ó   •— ‰|    d   d   S )Nr^   re   © )rS   Útriess    €r   ú<lambda>zlighter.<locals>.<lambda>t   s   ø€  U¨1¡X¨a¡[°Ñ%8€ r   )Úkeyz6already lean: the copy that keeps the look saves only z.0fz % of the trianglesÚrbÚactiveÚdraftÚstatuszsha256:ÚvertsÚ	materialsÚ
draw_callsÚtexturesÚgpu_mb_decodedÚbytesÚ
extensions)	re   r€   r�   r‚   rƒ   r„   r…   r)   r†   Ú
techniquesÚ	decimatedÚsidesÚfromÚ	tris_fromÚ
saving_pctÚ
change_pctÚ	sides_pctÚpctÚmax_change_pctÚmax_spotÚmodeÚtargetÚautor'   rC   r(   Útried)re   r(   r�   ru   ÚmethodzNglTF-Transform 4.5.1 simplify (meshoptimizer), original compression re-appliedÚjobÚmadez%Y-%m-%dT%H:%M:%SZÚlighterrJ   Úgateszlighter copy of vz: z of z triangles (-z %), worst side z- % of the model's pixels changed, worst spot z/255Úreleasez tris (-z	 %, spot )3ÚcardlibÚload_allr8   r   r}   ÚsplitÚ
startswithr;   ÚNO_RIGÚMIN_TRISÚprintÚsysr   Úexitr    r5   ÚisdirÚshutilÚrmtreeÚmakedirsÚcopyfileÚappendr+   ÚsetÚERRORSÚ
MIN_SAVINGr!   ÚaddÚdoner@   rN   ÚzipÚMAX_SPOTÚminÚhashlibÚsha256r7   ÚreadÚ	hexdigestrZ   ÚcopyÚdeepcopyÚpopÚsortedÚroundr6   ÚtimeÚstrftimeÚgmtimeÚrelease_hashÚwrite)%Úaidr“   Ú
max_changeÚallcr%   ÚverÚclsÚslugÚtris0r)   r<   ÚsglbÚsourcer>   ÚseenÚeÚmr-   rY   r?   r   rt   ru   rR   rS   r/   Úspr1   r'   ÚerrÚsavingÚhÚcr‰   ÚsÚpry   s%                                       @r   r™   r™   B   s“  ø€ Ü×ÑœDÓ!€DØ
�$�Ü˜>¨#¨Ð/Ó0Ð0Ü
�.‰.˜˜c™Ó
#€C¨4°©9°R©=¸Ñ+CÀaÑ+G SØ—	‘	˜#“�I€CˆØ
‡y�y�ƒ~�aÑÐ3Ñ3°s·~±~ÐFVÔ7WÐ[^×[bÑ[bÐchÔ[iÜœÓ Ð Ø�x‘= Ñ(¨#¨h©-¸Ñ*@ˆ5€EØŒxÒÜ�  a˜yÐ(LÌXÐVWÈLÐXYÐZÔad×akÑakÕlÜ�‰�ŒØÐ #¨Ô"7°%Ô"7ÜÐ:¸5À1¹9ÀQ¸-ÐGaÐbgÐhiÐajÐjkÐlÓmÐmÜˆ6� ˜v R¨ uÐ	-€BÜ	‡w�w‡}�}�RÔÜ�‰�bÔÜ‡K�K�„OØˆw‰<˜Ñ×$Ñ$ SÓ)¨!Ñ,€DØˆt�;Ð€FÜ
‡O�O”t�f˜M¨$¨¨tÐ4°fÔ=Ø€EØÐØˆd�+ÐˆØ�‰�aœ˜f a¨°%©¸¸EÓBÀFÈUÁNÐTUÐVÕWä‹uˆÜò 	?ˆAØ�$�b˜˜˜4Ð ˆAÜ�V˜Q  a¨Ó/ˆAØ�‰y˜DÑ  A f¡I°¸!¼jÈ1¹nÑ:LÑ1MÒ$MÜ—	‘	˜!”˜hØ�H‰H�Q�v‘YÔ §¡¨q°!°T¸1¨oÕ!>ð	?ñ Ü�ŒHÜÐFÀuÈQÀiÐOhÐiÔps×pzÑpzÕ{Ü�H‰H�QŒKØ˜S Ñ.×2Ñ2°5Ó9ÀCÈÁKÇOÁOÐTdÐfgÓDhÑ
i€CÜ
�#�r˜F˜8°UÖ&;° q¨£tÒ&;Ñ;Ó
<€CØ!$ Q R Ö)˜AˆQˆw‹ZÐ)€EÐ)Ø" 1 2˜wÖ'˜!ˆAˆf‹IÐ'€DÐ'ØÐØ‰ä"+¬C°°tÓ,<Ó"=×dÐd‘J�A‘w˜˜2ÀÀjÃÐUWÔ[cÓUcŠaÐdˆÒdÙÜ�ŒHÜÐ4°U¸1±X¸a±[ÀÑ5HÈÐ4KÐKgÐhmÐnoÑhpÐqtÐguð v;Ø;EÀa¸.ÐHYÐZ^Ð_`ÑZaÐYbÐbnÔowÐnxÐxyð{ô BE÷  BLñ  BLõMä�H‰H�QŒKÜ�2Ó8Ô9ˆØ˜T‘{Ñ€A€qˆ%�Ø��6‘˜UÑ"Ñ"€FØ”
ÒÜˆRŒÜÐFÀvÐPSÁ|ÐTWÐFXÐXkÐlÔsv×s}Ñs}Õ~Ü�‰�ŒÜ�‰”t˜A˜t“}×)Ñ)Ó+Ó,×6Ñ6Ó8€AÜ
‡O�O�Aœ$˜˜}¨Q¨C¨tÐ4Ô5Ü	ˆ"ˆd�Q‰hÔÜ�‰�cÓ€AØ‡E�Eˆ(�DÔØ€A€i�LØ€A€h�KØ5�A�g‘JÐ5 ¨°° }Ñ5€A€g�JØ˜V™9¨q°©zÈÈ+ÉÐfgÐhtÑfuØ  ™}ÀÐBRÑ@SÐ^_Ð`gÑ^hÐstÐu|Ñs}Ø!" <¡ñ2€A€h�Kô œS §¡ |Ó!4Ò!:¸Ó;¸{¸mÑKÓL€A€l�OØ��q‘‰M˜'Ñ"€Eðm�F˜C 	™Nð m¨K¸ð mÀÌeÐTZÐ]`ÑT`ÐbcÓNdð mØ  # d¨Q¡h¡-°Ñ"8ðmØ:EÐZ_ÖG`ÐUVÈÈ%ËÒG`ðmØbrÐt~ðmà˜C  q¡™M¨&Ñ1ðmà3=¼xðmð ¨Ð(:™HÀðmð IQÐRXðmð [bÔchÐinÐpqÓcrðmð u|ð  ~Aðmð ÔqtÐuzð  }Bð  DHó  rI÷  Jð  JÑemÐefÐhiÐkm q¨¡t¨F¡|¸aÀ¹dÐRSÐ]_Ó`ô  Jð	mð
 Ðnðmð œ2Ÿ7™7×+Ñ+¨BÓ/ðmð 28¼¿¹ÐG[Ô]a×]hÑ]hÓ]jÓ9kðm€A€i�Lð?�a˜	‘lð ? GÐ/@ÀÀYÁÐ@PÐPRÐSTÐU[ÑS\Ð]^ÐR_Ð_cÐdiÐjkÐclð mØ #™ cÐ*Ð*:¸3¸tÀa¹x¹=ÈÑ;QÐRUÐ:Vð W"Ø"% d¨Q¡h¡-°Ñ"7Ð!8¸ð.>ñ ?€A€i�Lô ×'Ñ'¨Ó*€A€i�LÜ�‰”d˜AÓ€AÜˆ„HÜ	ˆ!��&‘	ˆ{˜( 6¨C¡<°Ð"4Ð4DÀSÈÐPQÉÁ]ÐSZÑE[ÐD\Ð\eÐfiÐjnÐqrÑjrÑfsÐtzÑf{Ðe|Ð}ô  EH÷  EOñ  EOõ  PÜ	ˆ#…Jùò] '<ùÚ)ùÚ'ùô eùò6 Haùô Js0   Ë3\Ì\Ì$\Í\Í!	\Í+\Ö\!×\&c                 ór  — t        j                  | «      D ]3  }|j                  d«      s|dk(  sŒt        j                  | › d|› �«       Œ5 t         j                  j                  | › d�«      rJt        j                  | › d�«      D ].  }|j                  d«      sŒt        j                  | › d|› �«       Œ0 yy)z�Keep the evidence (compare/result.json, compare.jpg = original over the kept copy), drop the tries and their
    renders: the kept copy lives in store/blobs.rl   z	spec.jsonr_   r0   rF   rD   N)r    ÚlistdirÚendswithr!   r5   r¥   )r<   Úns     r   r¯   r¯   ™   s¢   € ô �Z‰Z˜‹^ò #ˆØ�:‰:�fÔ  kÓ!1Ü�I‰I˜˜˜A˜a˜S�kÕ"ð#ô 
‡w�w‡}�}˜�t˜8�_Ô%Ü—‘˜r˜d (˜OÓ,ò 	/ˆAØ�z‰z˜&Õ!Ü—	‘	˜R˜D 	¨!¨Ð-Õ.ñ	/ð &r   c                 ó(  — t        j                  t        «      }| |vrt        d| › �«      ‚||    D �ci c]  }|d   |“Œ
 }}||vrt        | › d|› �«      ‚||   }|d   dk(  rt        d|› d�«      ‚|d   dk(  r.|j	                  d	«      r|d	   d
   |v r||d	   d
      d   nd|d<   ||    D ]9  }||u rd|d<   n|j                  dd«      €Œ t        j                  t        |«       Œ; t        j                  t        |«       t        |«       yc c}w )zgMake <version> the one games get. A draft lighter copy takes its source's status (approved, legacy...).r\   r]   z	 has no vr   Ú
deprecatedÚvz% was withdrawn: it cannot go to gamesr~   r™   rŠ   Ú	candidateTr}   N)rœ   r�   r8   r   r;   r¹   rÀ   r¢   )rÁ   r]   rÃ   rÑ   ÚvsrY   s         r   ÚactivaterÝ   ¥   s>  € ä×ÑœDÓ!€DØ
�$�Ü˜>¨#¨Ð/Ó0Ð0Ø#'¨¡9Ö	-˜aˆ!ˆI‰,˜‰/Ð	-€BÐ	-Ø�bÑÜ˜C˜5 	¨'¨Ð3Ó4Ð4Ø
ˆ7‰€AØˆ�{�lÒ"Ü˜1˜W˜IÐ%JÐKÓLÐLØˆ�{�gÒØ<=¿E¹EÀ)Ô<LÐQRÐS\ÑQ]Ð^dÑQeÐikÑQk�b˜˜9™ fÑ-Ñ.¨xÒ8Ðq|ˆˆ(‰Ø�#‰Yò ˆØ�‰6ØˆAˆhŠKØ�U‰U�8˜TÓ"Ð*ØÜ�‰”d˜AÕðô ‡M�M”$˜ÔÜ	ˆ'…Nùò 
.s   ³DÚ__main__r^   z
--activaterm   z--targetz--max-change))Ú__doc__r·   r³   r3   r    r¦   r   r£   r¼   r5   ÚdirnameÚabspathÚ__file__r8   ÚinsertÚjoinr#   Úcardrœ   r   r¬   Ú
MAX_CHANGEr­   r±   r¡   r    r   r+   r@   rZ   r™   r¯   rÝ   Ú__name__ÚargvÚaÚintÚindexÚtgÚfloatÚmcrx   r   r   ú<module>rï      sW  ðñf÷ >× =× =× =Ø	‡w�w‡��r—w‘w—‘ r§w¡w§¡°xÓ'@ÓAÓB€Ø ‡�‡���2—7‘7—<‘<  eÓ,Ô -ß â/€Ú	H€Ø€
à€
Ø€à€Ø	}€òlòò
òAð ¨ó Tòn	/òð. ˆzÒØ�‰��ˆ€AÙˆQˆq‰T�\Ò!Ù��1‘‘s˜1˜Q™4“yÕ!à0:¸a±‰S��1—7‘7˜:Ó&¨Ñ*Ñ+Ô,ÀTˆØ6DÈÑ6I‰U�1�Q—W‘W˜^Ó,¨qÑ0Ñ1Ô2ÈzˆÙ��!‘�b˜"Õð r   