§
    ¨á¾jÙ'  ã                  óˆ  — d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
mZ ddlZddlZddlZddlmZmZmZ ddlmZ ddlZddlmZmZ ddlmZmZ dd	lmZmZmZm Z m!Z!m"Z"m#Z#  ee$¦  «         %                    ¦   «         j&        j&        j&        Z' G d
„ d¦  «        Z( G d„ d¦  «        Z) G d„ d¦  «        Z* G d„ d¦  «        Z+dS )z÷
Empirical Adversarial Stress Test Suite for FreeExile Graphics Optimization:
Adversarially tests LOD Generator, WebP Compressor, Viewport Frustum Culling (10k+ entities),
and validates the Draw Call Budget (< 30 calls for 50 on-screen entities).
é    )ÚannotationsN)ÚPath)ÚDictÚListÚTuple)ÚImage)Úevaluate_lod_generationÚgenerate_sprite_lods)Úcompress_to_webpÚbatch_compress_directory)ÚAABBÚEntityBoundsÚ	Frustum2DÚbenchmark_cullingÚcull_entitiesÚ
intersectsÚproject_isoc                  ó2   — e Zd ZdZdd„Zdd„Zdd„Zdd	„Zd
S )Ú!TestLODGeneratorAdversarialStresszWStress tests for LOD sprite downsampling across extreme dimensions, modes, and entropy.Útmp_pathr   ÚreturnÚNonec                óÈ  — g d¢}|D �]Ù\  }}|d|› d|› d�z  }t          j        d||fd¦  «                             |¦  «         t          ||d|› d|› �z  ¦  «        }g }|d         }|j        }	 |	¦   «         }
|
}|
r|d	         }|j        } |¦   «         }|}|sêd
t          j        |¦  «        t          j        |	¦  «        t          j        |
¦  «        dœz  }|                     |¦  «         |
rTdt          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}x}x}	x}
x}x}}t          j        |d	         ¦  «        5 }t          dt          t          |dz  ¦  «        ¦  «        ¦  «        }t          dt          t          |dz  ¦  «        ¦  «        ¦  «        }|j        }||f}	||	k    }|sªt          j        d|fd||	f¦  «        dt#          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}}	ddd¦  «         n# 1 swxY w Y   |dk    røt)          ||d|› d|› �z  ¦  «        }|j        }d}	||	k    }|sÈt          j        d|fd||	f¦  «        dt#          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        t          j        |	¦  «        dœz  }t          j        d |j        › d!�¦  «        d"z   d|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}}	�ŒÛdS )#zFTests 1x1, 2048x2048, and 4096x2048 textures under Lanczos resampling.©)é   r   )é   r   )i   r   Údim_Úxú.pngÚRGBA)éx   éP   éÈ   éÿ   Úout_Úlod0Úlod2z:%(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.exists
}()
})Úpy3Úpy5Úpy7z?%(py14)s
{%(py14)s = %(py12)s
{%(py12)s = %(py10)s.exists
}()
})Úpy10Úpy12Úpy14r   zassert %(py17)sÚpy17Nr   g      Ð?©ú==)z,%(py2)s
{%(py2)s = %(py0)s.size
} == %(py5)sÚimg_l2©Úpy0Úpy2r)   úassert %(py7)sr*   r   Úeval_çš™™™™™Ù?©ú<=©z7%(py2)s
{%(py2)s = %(py0)s.lod2_size_ratio
} <= %(py5)sÚreszLOD-2 ratio z > 0.40ú
>assert %(py7)s)r   ÚnewÚsaver
   ÚexistsÚ
@pytest_arÚ	_safereprÚappendÚ_format_boolopÚAssertionErrorÚ_format_explanationÚopenÚmaxÚintÚroundÚsizeÚ_call_reprcompareÚ@py_builtinsÚlocalsÚ_should_repr_global_namer	   Úlod2_size_ratioÚ_format_assertmsg)Úselfr   ÚsizesÚwÚhÚpÚpathsÚ@py_assert1Ú@py_assert2Ú@py_assert4Ú@py_assert6Ú@py_assert0Ú@py_assert9Ú@py_assert11Ú@py_assert13Ú@py_format8Ú@py_format15Ú@py_format16Ú@py_format18r1   Ú
expected_wÚ
expected_hÚ@py_assert3Ú@py_format6r;   s                            úPC:\Projects\FreeExile\tests\unit\test_challenger_graphics_optimization_stress.pyÚtest_lod_extreme_dimensionsz=TestLODGeneratorAdversarialStress.test_lod_extreme_dimensions+   sÉ  € à'KÐ'KÐ'KˆØð 	`ñ 	`‰DˆAˆqØÐ- !Ð-Ð- aÐ-Ð-Ð-Ñ-ˆAÝŒI�f˜q !˜fÐ&9Ñ:Ô:×?Ò?ÀÑBÔBÐBÝ(¨¨H°~¸a°~°~À!°~°~Ñ,EÑFÔFˆEØDÐD�5˜”=ÐD�=Ô'ÐDÐ'Ð'Ñ)Ô)ÐDÐ)ÐDÐ)ÐD¨e°F¬mÐD¨mÔ.BÐDÐ.BÐ.BÑ.DÔ.DÐDÐ.DÐDÐDÐDÐDÕDÔD�=ÑDÔDÕDÔDÐ'ÑDÔDÕDÔDÐ)ÑDÔDÐDÐDÑDÐDÐD×DÒDÐDÑDÔDÐDÐ)ÐDÐDÕDÔD¨mÑDÔDÕDÔDÐ.BÑDÔDÕDÔDÐ.DÑDÔDÐDÐDÑDÐDÐD×DÒDÐDÑDÔDÐDÕDÔDÐDÐDÑDÔDÐDÑDÐDÐDÐDÐDÐDÑDÐDÕDÕDÔDÐDÑDÔDÑDÔDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDå”˜E &œMÑ*Ô*ð ?¨fÝ  ¥C­¨a°$©h©¬Ñ$8Ô$8Ñ9Ô9�
Ý  ¥C­¨a°$©h©¬Ñ$8Ô$8Ñ9Ô9�
Ø”{Ð> z°:Ð&>Ð>�{Ð&>Ò>Ð>Ð>Ð>Õ>Ô>Ð>Ð>Ð>Ð>�{Ð&>Ð>Ñ>Ô>Ð>Õ>Ô>Ñ>Ô>Ð>Ð>Õ>Ô>�vÑ>Ô>Ð>Õ>Ô>�vÑ>Ô>Ð>Ð>Õ>Ô>�{Ñ>Ô>Õ>Ô>Ð&>Ñ>Ô>Ð>Ð>Ñ>Ð>Ð>Ð>Ð>Ð>Ñ>Ð>Õ>Õ>Ô>Ð>Ñ>Ô>Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>Ð>ð?ð ?ð ?ñ ?ô ?ð ?ð ?ð ?ð ?ð ?ð ?øøøð ?ð ?ð ?ð ?ð
 �DŠyˆyÝ-¨a°¸OÀA¸O¸OÈ¸O¸OÑ1KÑLÔL�ØÔ*Ð_¨dÐ_Ð*¨dÒ2Ð_Ð_Ð_Õ_Ô_Ð_Ð_Ð_Ð_Ð*¨dÐ_Ñ_Ô_Ð_Õ_Ô_Ñ_Ô_Ð_Ð_Õ_Ô_�sÑ_Ô_Ð_Õ_Ô_�sÑ_Ô_Ð_Ð_Õ_Ô_Ð*Ñ_Ô_Õ_Ô_¨dÑ_Ô_Ð_Ð_Ñ_Ð_Õ_Ô_Ð4_À3ÔCVÐ4_Ð4_Ð4_Ñ_Ô_Ð_Ñ_Ð_Ð_Ð_Ñ_Ð_Õ_Õ_Ô_Ð_Ñ_Ô_Ñ_Ô_Ð_Ð_Ð_Ð_Ð_Ð_Ð_ùð	`ð 	`s   Æ-DKËK	ËK	c                ó¢  ‡— |dz  }t          j        ddd¦  «                             |¦  «         t          ||dz  ¦  «        }|j        }d}||k    }|sªt          j        d|fd||f¦  «        d	t          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        nd	t          j
        |¦  «        t          j
        |¦  «        d
œz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}t          j        d¦  «        Št          ˆfd„t!          d¦  «        D ¦   «         ¦  «        }	|dz  }
t          j        ddt%          |	¦  «        ¦  «                             |
¦  «         t          |
|dz  ¦  «        }|j        }d}||k    }|sªt          j        d|fd||f¦  «        dt          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        ndt          j
        |¦  «        t          j
        |¦  «        d
œz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}dS )z?Tests random uniform noise and completely transparent textures.ztrans_512.pngr    )é   rj   )r   r   r   r   Ú	out_transr7   r8   r:   Ú	res_transr2   r5   r*   Niç  c              3  óB   •K  — | ]}‰                      d ¦  «        V — ŒdS )é   N)Úgetrandbits)Ú.0Ú_Úrngs     €rg   ú	<genexpr>z[TestLODGeneratorAdversarialStress.test_lod_high_entropy_and_transparency.<locals>.<genexpr>G   s/   øè è € ÐQÐQ°q §¢°Ñ 2Ô 2ÐQÐQÐQÐQÐQÐQó    i   znoise_256.png)é   ru   Ú	out_noiseÚ	res_noise)r   r=   r>   r	   rO   r@   rK   rL   rM   rN   rA   rD   rE   ÚrandomÚRandomÚ	bytearrayÚrangeÚ	frombytesÚbytes)rQ   r   Útrans_prl   rW   rY   re   rf   r_   Únoise_bytesÚnoise_prw   rr   s               @rg   Ú&test_lod_high_entropy_and_transparencyzHTestLODGeneratorAdversarialStress.test_lod_high_entropy_and_transparency=   s�  ø€ ð ˜_Ñ,ˆÝŒ	�&˜* lÑ3Ô3×8Ò8¸ÑAÔAÐAÝ+¨G°XÀÑ5KÑLÔLˆ	ØÔ(Ð0¨DÐ0Ð(¨DÒ0Ð0Ð0Ð0Õ0Ô0Ð0Ð0Ð0Ð0Ð(¨DÐ0Ñ0Ô0Ð0Õ0Ô0Ñ0Ô0Ð0Ð0Õ0Ô0ˆyÑ0Ô0Ð0Õ0Ô0ˆyÑ0Ô0Ð0Ð0Õ0Ô0Ð(Ñ0Ô0Õ0Ô0¨DÑ0Ô0Ð0Ð0Ñ0Ð0Ð0Ð0Ð0Ð0Ñ0Ð0Õ0Õ0Ô0Ð0Ñ0Ô0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0õ Œm˜CÑ Ô ˆÝÐQÐQÐQÐQ½EÀ-Ñ<PÔ<PÐQÑQÔQÑQÔQˆØ˜_Ñ,ˆÝŒ˜ 
­E°+Ñ,>Ô,>Ñ?Ô?×DÒDÀWÑMÔMÐMÝ+¨G°XÀÑ5KÑLÔLˆ	ØÔ(Ð0¨DÐ0Ð(¨DÒ0Ð0Ð0Ð0Õ0Ô0Ð0Ð0Ð0Ð0Ð(¨DÐ0Ñ0Ô0Ð0Õ0Ô0Ñ0Ô0Ð0Ð0Õ0Ô0ˆyÑ0Ô0Ð0Õ0Ô0ˆyÑ0Ô0Ð0Ð0Õ0Ô0Ð(Ñ0Ô0Õ0Ô0¨DÑ0Ô0Ð0Ð0Ñ0Ð0Ð0Ð0Ð0Ð0Ñ0Ð0Õ0Õ0Ô0Ð0Ñ0Ô0Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0Ð0Ð0rt   c                ó   — dD ]Ê}|d|› d�z  }t          j        |d¦  «                             |¦  «         t          ||d|› �z  ¦  «        }|d         }|j        } |¦   «         }|s`dt          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }t          t          j        |¦  «        ¦  «        ‚d	x}x}}ŒËd	S )
zDTests L, P, RGB, and RGBA modes without unhandled conversion errors.)ÚLÚPÚRGBr    Úmode_r   ©é€   rˆ   r%   r'   zAassert %(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.exists
}()
})Úpy1r(   r)   N)	r   r=   r>   r
   r?   r@   rA   rD   rE   )	rQ   r   ÚmoderU   rV   r[   rX   rY   rf   s	            rg   Útest_lod_image_modesz6TestLODGeneratorAdversarialStress.test_lod_image_modesM   sý   € à-ð 	*ð 	*ˆDØÐ- 4Ð-Ð-Ð-Ñ-ˆAÝŒI�d˜JÑ'Ô'×,Ò,¨QÑ/Ô/Ð/Ý(¨¨H°}¸d°}°}Ñ,DÑEÔEˆEØ˜”=Ð)�=Ô'Ð)Ð'Ð'Ñ)Ô)Ð)Ð)Ð)Ð)Õ)Ô)�=Ñ)Ô)Õ)Ô)Ð'Ñ)Ô)Õ)Ô)Ð)Ñ)Ô)Ð)Ð)Ñ)Ð)Õ)Õ)Ô)Ð)Ñ)Ô)Ñ)Ô)Ð)Ð)Ð)Ð)Ð)Ð)Ð)Ð)ð		*ð 	*rt   c                ó  — |dz  }t          j        ddd¦  «                             |¦  «         t          ||dz  ¦  «        }|j        }d}||k    }|sªt          j        d|fd||f¦  «        d	t          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        nd	t          j
        |¦  «        t          j
        |¦  «        d
œz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}|j        d         }	d}|	|k    }
|
slt          j        d|
fd|	|f¦  «        t          j
        |	¦  «        t          j
        |¦  «        dœz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}	x}
}dS )zTDocuments empirical boundary where PNG container overhead dominates sub-16px assets.zmicro_4x4.pngr    )é   r�   )r$   r   r   r$   Ú	out_micror7   ©ú>)z6%(py2)s
{%(py2)s = %(py0)s.lod2_size_ratio
} > %(py5)sr;   r2   r5   r*   Nr'   r!   r8   )z%(py1)s <= %(py4)s©r‰   Úpy4úassert %(py6)sÚpy6)r   r=   r>   r	   rO   r@   rK   rL   rM   rN   rA   rD   rE   Ú	lod_sizes)rQ   r   rU   r;   rW   rY   re   rf   r_   r[   rX   Ú@py_format5Ú@py_format7s                rg   Ú)test_lod_micro_texture_container_boundaryzKTestLODGeneratorAdversarialStress.test_lod_micro_texture_container_boundaryU   sÕ  € à�Ñ&ˆÝŒ	�&˜&Ð"2Ñ3Ô3×8Ò8¸Ñ;Ô;Ð;Ý% a¨°KÑ)?Ñ@Ô@ˆàÔ"Ð) TÐ)Ð" TÒ)Ð)Ð)Ð)Õ)Ô)Ð)Ð)Ð)Ð)Ð" TÐ)Ñ)Ô)Ð)Õ)Ô)Ñ)Ô)Ð)Ð)Õ)Ô)ˆsÑ)Ô)Ð)Õ)Ô)ˆsÑ)Ô)Ð)Ð)Õ)Ô)Ð"Ñ)Ô)Õ)Ô) TÑ)Ô)Ð)Ð)Ñ)Ð)Ð)Ð)Ð)Ð)Ñ)Ð)Õ)Õ)Ô)Ð)Ñ)Ô)Ñ)Ô)Ð)Ð)Ð)Ð)Ð)Ð)Ð)ØŒ}˜VÔ$Ð+¨Ð+Ð$¨Ò+Ð+Ð+Ð+Õ+Ô+Ð+Ð+Ð+Ð+Ð$¨Ð+Ñ+Ô+Õ+Ô+Ð$Ñ+Ô+Õ+Ô+¨Ñ+Ô+Ð+Ð+Ñ+Ð+Ð+Ð+Ð+Ð+Ñ+Ð+Õ+Õ+Ô+Ð+Ñ+Ô+Ñ+Ô+Ð+Ð+Ð+Ð+Ð+Ð+Ð+Ð+Ð+rt   N©r   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rh   r�   r‹   r˜   © rt   rg   r   r   (   sn   € € € € € ØaÐað`ð `ð `ð `ð$1ð 1ð 1ð 1ð *ð *ð *ð *ð,ð ,ð ,ð ,ð ,ð ,rt   r   c                  ó*   — e Zd ZdZd
d„Zd
d„Zd
d„Zd	S )Ú&TestTextureCompressorAdversarialStresszSStress tests for WebP compression under noisy, empty, and out-of-bounds parameters.r   r   r   r   c                ó  — dD �]…\  }}|d|› d|› d�z  }|d|› d|› d�z  }t          j        d||fd¦  «                             |¦  «         t          ||d¬	¦  «        }|j        } |¦   «         }|s‹d
dt          j        ¦   «         v st          j        |¦  «        rt          j	        |¦  «        ndt          j	        |¦  «        t          j	        |¦  «        dœz  }	t          t          j        |	¦  «        ¦  «        ‚dx}}|j        }d}
||
k    }|sªt          j        d|fd||
f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j	        |¦  «        ndt          j	        |¦  «        t          j	        |
¦  «        dœz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}
|dk    rÁ|j        }d}
||
k    }|sªt          j        d|fd||
f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j	        |¦  «        ndt          j	        |¦  «        t          j	        |
¦  «        dœz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}
�Œ‡dS )z5Tests 1x1, 2048x2048, and 4096x2048 WebP conversions.r   Útex_r   r   ú.webpr    )éd   é–   r#   r$   r"   ©ÚqualityúAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}Údst©r3   r4   r’   Nr   r�   ©z6%(py2)s
{%(py2)s = %(py0)s.compressed_size
} > %(py5)sr;   r2   r5   r*   r   ç      à?r8   ©z9%(py2)s
{%(py2)s = %(py0)s.compression_ratio
} <= %(py5)s)r   r=   r>   r   r?   rL   rM   r@   rN   rA   rD   rE   Úcompressed_sizerK   Úcompression_ratio)rQ   r   rS   rT   Úsrcr©   r;   rW   re   r–   rY   rf   r_   s                rg   Ú test_compress_extreme_dimensionszGTestTextureCompressorAdversarialStress.test_compress_extreme_dimensionsb   s  € à8ð 	5ñ 	5‰DˆAˆqØÐ/ AÐ/Ð/¨Ð/Ð/Ð/Ñ/ˆCØÐ0 AÐ0Ð0¨Ð0Ð0Ð0Ñ0ˆCÝŒI�f˜q !˜fÐ&:Ñ;Ô;×@Ò@ÀÑEÔEÐEÝ" 3¨°RÐ8Ñ8Ô8ˆCØ”:Ð�:�:‘<”<Ð�<ÐÐÐÕÔÑÔÐÐÕÔ�3ÑÔÐÕÔ�3ÑÔÐÐÕÔ�:ÑÔÕÔ�<ÑÔÐÐÑÐÕÕÔÐÑÔÑÔÐÐÐÐÐØÔ&Ð*¨Ð*Ð&¨Ò*Ð*Ð*Ð*Õ*Ô*Ð*Ð*Ð*Ð*Ð&¨Ð*Ñ*Ô*Ð*Õ*Ô*Ñ*Ô*Ð*Ð*Õ*Ô*�3Ñ*Ô*Ð*Õ*Ô*�3Ñ*Ô*Ð*Ð*Õ*Ô*Ð&Ñ*Ô*Õ*Ô*¨Ñ*Ô*Ð*Ð*Ñ*Ð*Ð*Ð*Ð*Ð*Ñ*Ð*Õ*Õ*Ô*Ð*Ñ*Ô*Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ø�DŠyˆyØÔ,Ð4°Ð4Ð,°Ò4Ð4Ð4Ð4Õ4Ô4Ð4Ð4Ð4Ð4Ð,°Ð4Ñ4Ô4Ð4Õ4Ô4Ñ4Ô4Ð4Ð4Õ4Ô4�sÑ4Ô4Ð4Õ4Ô4�sÑ4Ô4Ð4Ð4Õ4Ô4Ð,Ñ4Ô4Õ4Ô4°Ñ4Ô4Ð4Ð4Ñ4Ð4Ð4Ð4Ð4Ð4Ñ4Ð4Õ4Õ4Ô4Ð4Ñ4Ô4Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4ùð	5ð 	5rt   c                ól  — |dz  }t          j        ddd¦  «                             |¦  «         dD �]�}|d|› d�z  }t          |||¬¦  «        }|j        } |¦   «         }|s‹d	d
t          j        ¦   «         v st          j        |¦  «        rt          j	        |¦  «        nd
t          j	        |¦  «        t          j	        |¦  «        dœz  }t          t          j        |¦  «        ¦  «        ‚dx}}|j        }d}	||	k    }|sªt          j        d|fd||	f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j	        |¦  «        ndt          j	        |¦  «        t          j	        |	¦  «        dœz  }
dd|
iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}	�ŒƒdS )zHVerifies robustness against out-of-bound quality inputs (e.g. -50, 150).zclamp_test.pngr    r‡   )r#   é2   r"   r$   )iÎÿÿÿr   r"   r¥   Úclamp_r£   r¦   r¨   r©   rª   Nr   r�   r«   r;   r2   r5   r*   )r   r=   r>   r   r?   rL   rM   r@   rN   rA   rD   rE   r®   rK   )rQ   r   r°   Úqr©   r;   rW   re   r–   rY   rf   r_   s               rg   Útest_compress_quality_clampingzETestTextureCompressorAdversarialStress.test_compress_quality_clampingn   sû  € àÐ)Ñ)ˆÝŒ	�&˜*Ð&8Ñ9Ô9×>Ò>¸sÑCÔCÐCØ"ð 	+ñ 	+ˆAØÐ. aÐ.Ð.Ð.Ñ.ˆCÝ" 3¨°QÐ7Ñ7Ô7ˆCØ”:Ð�:�:‘<”<Ð�<ÐÐÐÕÔÑÔÐÐÕÔ�3ÑÔÐÕÔ�3ÑÔÐÐÕÔ�:ÑÔÕÔ�<ÑÔÐÐÑÐÕÕÔÐÑÔÑÔÐÐÐÐÐØÔ&Ð*¨Ð*Ð&¨Ò*Ð*Ð*Ð*Õ*Ô*Ð*Ð*Ð*Ð*Ð&¨Ð*Ñ*Ô*Ð*Õ*Ô*Ñ*Ô*Ð*Ð*Õ*Ô*�3Ñ*Ô*Ð*Õ*Ô*�3Ñ*Ô*Ð*Ð*Õ*Ô*Ð&Ñ*Ô*Õ*Ô*¨Ñ*Ô*Ð*Ð*Ñ*Ð*Ð*Ð*Ð*Ð*Ñ*Ð*Õ*Õ*Ô*Ð*Ñ*Ô*Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ñ*ð		+ð 	+rt   c                óô  — t           dz  dz  dz  dz  }d„ |                     d¦  «        D ¦   «         }t          |¦  «        }d}||k    }|�st          j        d|fd	||f¦  «        d
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        t          j        |¦  «        dœz  }t          j	        dt          |¦  «        › d�¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}|D �]	}	||	j        › d�z  }
t          |	|
d¬¦  «        }|j        }d}||k    }|sÐt          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        t          j        |¦  «        dœz  }t          j	        |	j        › d|j        d›d�¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}�ŒdS )zIValidates <= 50% WebP budget on all production character textures > 10KB.ÚclientÚwebappÚassetsÚ
charactersc                óL   — g | ]!}|                      ¦   «         j        d k    ¯|‘Œ"S )i (  )ÚstatÚst_size)rp   rU   s     rg   ú
<listcomp>zbTestTextureCompressorAdversarialStress.test_compress_production_sprites_budget.<locals>.<listcomp>{   s-   € ÐNÐNÐN�a°Q·V²V±X´XÔ5EÈÒ5MÐ5M�Ð5MÐ5MÐ5Mrt   z*.pngr�   ©ú>=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)sÚlenÚpngs)r3   r‰   r(   r”   zFound z character textures > 10KBz
>assert %(py8)sÚpy8Nr£   r"   r¦   r¬   r8   r­   r;   r2   z ratio z.2fz > 0.50r<   r*   )Ú	REPO_ROOTÚglobrÂ   r@   rK   rL   rM   rN   rA   rP   rD   rE   Ústemr   r¯   Úname)rQ   r   Úchar_dirrÃ   rX   Ú@py_assert5rY   r—   Ú@py_format9rU   r©   r;   rW   re   rf   r_   s                   rg   Ú'test_compress_production_sprites_budgetzNTestTextureCompressorAdversarialStress.test_compress_production_sprites_budgetx   sË  € å˜xÑ'¨(Ñ2°XÑ=ÀÑLˆØNÐN˜8Ÿ=š=¨Ñ1Ô1ÐNÑNÔNˆÝ�4‰yŒyÐM˜AÐMˆy˜AŠ~ÐMÐMÑMÕMÔMÐMÐMÐMÐMˆy˜AÐMÑMÔMÐMÕMÔMÑMÔMÐMÐMÕMÔM�sÑMÔMÐMÕMÔM�sÑMÔMÐMÐMÐMÕMÔMÑMÔMÐMÐMÕMÔM�4ÑMÔMÐMÕMÔM�4ÑMÔMÐMÐMÕMÔMˆyÑMÔMÕMÔM˜AÑMÔMÐMÐMÑMÐMÕMÔMÐM­¨D©	¬	ÐMÐMÐMÑMÔMÐMÑMÐMÐMÐMÑMÐMÕMÕMÔMÐMÑMÔMÑMÔMÐMÐMÐMÐMÐMÐMÐMØð 	gñ 	gˆAØ ¤Ð-Ð-Ð-Ñ-ˆCÝ" 1 c°2Ð6Ñ6Ô6ˆCØÔ(Ðf¨DÐfÐ(¨DÒ0ÐfÐfÐfÕfÔfÐfÐfÐfÐfÐ(¨DÐfÑfÔfÐfÕfÔfÑfÔfÐfÐfÕfÔf�3ÑfÔfÐfÕfÔf�3ÑfÔfÐfÐfÕfÔfÐ(ÑfÔfÕfÔf¨DÑfÔfÐfÐfÑfÐfÕfÔf°Q´VÐ2fÐ2fÀCÔDYÐ2fÐ2fÐ2fÐ2fÑfÔfÐfÑfÐfÐfÐfÑfÐfÕfÕfÔfÐfÑfÔfÑfÔfÐfÐfÐfÐfÐfÐfÐfÑfð	gð 	grt   Nr™   )rš   r›   rœ   r�   r±   r¶   rÌ   rž   rt   rg   r    r    _   s\   € € € € € Ø]Ð]ð
5ð 
5ð 
5ð 
5ð+ð +ð +ð +ðgð gð gð gð gð grt   r    c                  ó:   — e Zd ZdZd
d„Zd
d„Zd
d„Zd
d„Zd
d„Zd	S )Ú$TestViewportCullingAdversarialStresszXStress tests for frustum culling at scale (10,000 entities) and geometric singularities.r   r   c                ó
  — t          dd¬¦  «        }|d         }d}||k    }|slt          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }t	          t          j        |¦  «        ¦  «        ‚d
x}x}}d}|d         }||k    }d}||k    }|r|s�t          j        d||fd|||f¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }	dd|	iz  }
t	          t          j        |
¦  «        ¦  «        ‚d
x}x}x}x}}|d         }d}||k     }|s‹t          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }t          j        d|d         › d�¦  «        dz   d	|iz  }t	          t          j        |¦  «        ¦  «        ‚d
x}x}}|d         }d}||k     }|s‹t          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }t          j        d|d         › d�¦  «        dz   d	|iz  }t	          t          j        |¦  «        ¦  «        ‚d
x}x}}d
S )zFMeasures 10,000 entity culling throughput, latency, and culling ratio.i'  ©g      ž@g     à�@)Únum_entitiesÚviewport_sizeÚtotal_entitiesr/   )z%(py1)s == %(py4)sr‘   r“   r”   Ng      N@Úculled_percentageg     @U@)r9   r9   )z%(py1)s <= %(py5)sz%(py5)s <= %(py7)s)r‰   r)   r*   zassert %(py9)sÚpy9Ú
elapsed_msg      ^@©ú<)z%(py1)s < %(py4)szElapsed zms exceeded 120ms capz
>assert %(py6)sÚper_entity_usg      .@zPer-entity latency zus too high)r   r@   rK   rA   rD   rE   rP   )rQ   r;   r[   re   rX   r–   r—   rY   rZ   r_   Ú@py_format10s              rg   Ú"test_cull_10000_entities_benchmarkzGTestViewportCullingAdversarialStress.test_cull_10000_entities_benchmark†   s:  € å¨UÐBRÐSÑSÔSˆØÐ#Ô$Ð-¨Ð-Ð$¨Ò-Ð-Ð-Ð-Õ-Ô-Ð-Ð-Ð-Ð-Ð$¨Ð-Ñ-Ô-Õ-Ô-Ð$Ñ-Ô-Õ-Ô-¨Ñ-Ô-Ð-Ð-Ñ-Ð-Ð-Ð-Ð-Ð-Ñ-Ð-Õ-Õ-Ô-Ð-Ñ-Ô-Ñ-Ô-Ð-Ð-Ð-Ð-Ð-Ð-Ð-ØÐ7�sÐ.Ô/Ð7ˆtÐ/Ò7Ð7°4Ð7Ð/°4Ò7Ð7Ð7Ð7Ð7Ð7Õ7Ô7Ð7Ð7Ð7Ð7Ð7ˆtÐ/°4Ð7Ñ7Ô7Õ7Ô7ˆtÑ7Ô7Õ7Ô7Ð/Ñ7Ô7Õ7Ô7°4Ñ7Ô7Ð7Ð7Ñ7Ð7Ð7Ð7Ð7Ð7Ñ7Ð7Õ7Õ7Ô7Ð7Ñ7Ô7Ñ7Ô7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ø�<Ô Ð] 5Ð]Ð  5Ò(Ð]Ð]Ð]Õ]Ô]Ð]Ð]Ð]Ð]Ð  5Ð]Ñ]Ô]Õ]Ô]Ð Ñ]Ô]Õ]Ô] 5Ñ]Ô]Ð]Ð]Ñ]Ð]Õ]Ô]Ð*]°S¸Ô5FÐ*]Ð*]Ð*]Ñ]Ô]Ð]Ñ]Ð]Ð]Ð]Ñ]Ð]Õ]Õ]Ô]Ð]Ñ]Ô]Ñ]Ô]Ð]Ð]Ð]Ð]Ð]Ð]Ð]Ø�?Ô#Ðc dÐcÐ# dÒ*ÐcÐcÐcÕcÔcÐcÐcÐcÐcÐ# dÐcÑcÔcÕcÔcÐ#ÑcÔcÕcÔc dÑcÔcÐcÐcÑcÐcÕcÔcÐ,cÀ#ÀoÔBVÐ,cÐ,cÐ,cÑcÔcÐcÑcÐcÐcÐcÑcÐcÕcÕcÔcÐcÑcÔcÑcÔcÐcÐcÐcÐcÐcÐcÐcÐcÐcrt   c                óà  — t          ddd¦  «        }t          dd|gd¬¦  «        }g }||k    }|s—t          j        d|fd||f¦  «        d	t	          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd	t          j        |¦  «        d
œz  }dd|iz  }t          t          j	        |¦  «        ¦  «        ‚dx}}t          ddddd¬¦  «        }t          ddddd¬¦  «        }t          dd||gd¬¦  «        }	g }t          |	¦  «        }
d}|
|k    }|}|r|	d         }|j        }d}||k    }|}|�s›t          j        d|fd|
|f¦  «        dt	          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nddt	          j        ¦   «         v st          j        |	¦  «        rt          j        |	¦  «        ndt          j        |
¦  «        t          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         |rst          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j	        |¦  «        ¦  «        ‚dx}x}x}
x}x}x}x}x}}dS ) zMTests zero-size, negative-size viewports, and negative padding without crash.Úcenterç        ©rÞ   rÞ   )g      ‰@g     À‚@g     @À)Úpaddingr/   ©z%(py0)s == %(py3)sÚculled©r3   r(   úassert %(py5)sr)   NÚ
origin_dot)Úscreen_widthÚscreen_heightÚaway_dotg      @r   r   ©z0%(py5)s
{%(py5)s = %(py2)s(%(py3)s)
} == %(py8)srÂ   Úres_zero©r4   r(   r)   rÄ   ú%(py10)sr+   ©z5%(py15)s
{%(py15)s = %(py13)s.entity_id
} == %(py18)s©Úpy13Úpy15Úpy18ú%(py20)sÚpy20úassert %(py23)sÚpy23)r   r   r@   rK   rL   rM   rN   rA   rD   rE   rÂ   Ú	entity_idrB   rC   )rQ   Úentrâ   rX   rW   Ú@py_format4rf   Ú	on_originÚ
off_originrê   rY   Ú@py_assert7rZ   r[   Ú@py_assert12Ú@py_assert14Ú@py_assert17Ú@py_assert16rË   Ú@py_format11Ú@py_format19Ú@py_format21Ú@py_format22Ú@py_format24s                           rg   Útest_cull_degenerate_viewportszCTestViewportCullingAdversarialStress.test_cull_degenerate_viewportsŽ   s  € å˜8 S¨#Ñ.Ô.ˆå˜z¨>¸C¸5È&ÐQÑQÔQˆØÐˆv˜Š|ÐÐÐÕÔÐÐÐÐˆv˜ÐÑÔÐÕÔÑÔÐÐÕÔˆvÑÔÐÕÔˆvÑÔÐÐÕÔ˜ÑÔÐÐÑÐÐÐÐÐÑÐÕÕÔÐÑÔÑÔÐÐÐÐÐõ ! ¨s°CÀcÐY\Ð]Ñ]Ô]ˆ	Ý! *¨c°3ÀSÐX[Ð\Ñ\Ô\ˆ
Ý  ¨Z¸)ÀZÐ9PÐZ]Ð^Ñ^Ô^ˆØKÐK�s�8‰}Œ}ÐK ÐKˆ} Ò!ÐKÐKÐKÐKÐK h¨q¤kÐK kÔ&;ÐK¸|ÐKÐ&;¸|Ò&KÐKÐKÐKÐKÑKÕKÔKÐKÐKÐKÐKˆ} ÐKÑKÔKÐKÕKÔKÑKÔKÐKÐKÕKÔK�sÑKÔKÐKÕKÔK�sÑKÔKÐKÐKÐKÕKÔKÑKÔKÐKÐKÕKÔK�8ÑKÔKÐKÕKÔK�8ÑKÔKÐKÐKÕKÔKˆ}ÑKÔKÕKÔK ÑKÔKÐKÐKÑKÐKÐKÐKÐKÐKÑKÐKÐK×KÒKÐKÑKÔKÐKÐKÐKÕKÔKÐKÐKÐKÐKÐ&;¸|ÐKÑKÔKÕKÔK kÑKÔKÕKÔKÐ&;ÑKÔKÕKÔK¸|ÑKÔKÐKÐKÑKÐKÐKÐKÐKÐKÑKÐKÐK×KÒKÐKÑKÔKÐKÕKÔKÐKÐKÑKÔKÐKÑKÐKÐKÐKÐKÐKÑKÐKÕKÕKÔKÐKÑKÔKÑKÔKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKÐKrt   c                ó6  — dD �]”}||f}t          d|dz   |dz   ¦  «        }t          ddd¦  «        }t          |d||g¦  «        }d„ |D ¦   «         }d}||v }|s—t          j        d|fd	||f¦  «        t          j        |¦  «        d
t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd
dœz  }	dd|	iz  }
t          t          j	        |
¦  «        ¦  «        ‚dx}}d}||v}|s—t          j        d|fd||f¦  «        t          j        |¦  «        d
t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd
dœz  }	dd|	iz  }
t          t          j	        |
¦  «        ¦  «        ‚dx}}�Œ–dS )zHVerifies culling precision with extreme floating-point camera positions.)g    €„.Ag    €„.Ág   ¢”mBÚneargš™™™™™¹?ÚfarrÞ   rÐ   c                ó   — h | ]	}|j         ’Œ
S rž   )rö   )rp   Úes     rg   ú	<setcomp>z\TestViewportCullingAdversarialStress.test_cull_extreme_camera_coordinates.<locals>.<setcomp>¢   s   € Ð4Ð4Ð4 q�q”{Ð4Ð4Ð4rt   )Úin)z%(py1)s in %(py3)sÚvis_ids)r‰   r(   rä   r)   N)únot in)z%(py1)s not in %(py3)s)
r   r   r@   rK   rA   rL   rM   rN   rD   rE   )rQ   Ú	cam_coordÚcamÚnear_entÚfar_entÚvisibler  r[   rX   rø   rf   s              rg   Ú$test_cull_extreme_camera_coordinateszITestViewportCullingAdversarialStress.test_cull_extreme_camera_coordinates›   s   € à*ð 	(ñ 	(ˆIØ˜iÐ(ˆCÝ# F¨I¸©O¸YÈ¹_ÑMÔMˆHÝ" 5¨#¨sÑ3Ô3ˆGÝ# CÐ)9¸HÀgÐ;NÑOÔOˆGØ4Ð4¨GÐ4Ñ4Ô4ˆGØÐ$�6˜WÐ$Ð$Ð$Ð$Õ$Ô$Ð$Ð$Ð$Ð$�6˜WÐ$Ñ$Ô$Õ$Ô$�6Ñ$Ô$Ð$Õ$Ô$Ñ$Ô$Ð$Ð$Õ$Ô$˜WÑ$Ô$Ð$Õ$Ô$˜WÑ$Ô$Ð$Ð$Ð$Ð$Ñ$Ð$Ð$Ð$Ð$Ð$Ñ$Ð$Õ$Õ$Ô$Ð$Ñ$Ô$Ñ$Ô$Ð$Ð$Ð$Ð$Ð$ØÐ'�5 Ð'Ð'Ð'Ð'Õ'Ô'Ð'Ð'Ð'Ð'�5 Ð'Ñ'Ô'Õ'Ô'�5Ñ'Ô'Ð'Õ'Ô'Ñ'Ô'Ð'Ð'Õ'Ô' Ñ'Ô'Ð'Õ'Ô' Ñ'Ô'Ð'Ð'Ð'Ð'Ñ'Ð'Ð'Ð'Ð'Ð'Ñ'Ð'Õ'Õ'Ô'Ð'Ñ'Ô'Ñ'Ô'Ð'Ð'Ð'Ð'Ð'Ñ'ð	(ð 	(rt   c                óÜ  — t          dt          d¦  «        d¦  «        }t          dd|g¦  «        }g }||k    }|s—t          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        d	œz  }d
d|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}}t          dt          d¦  «        d¦  «        }t          dd|g¦  «        }g }t          |¦  «        }	d}
|	|
k    }|}|r|d         }|j        }d}||k    }|}|�s›t          j        d|fd|	|
f¦  «        dt          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nddt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |	¦  «        t          j        |
¦  «        dœz  }dd|iz  }|                     |¦  «         |rst          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}x}	x}x}
x}x}x}}dS )zCDocuments IEEE 754 float behavior for infinite and NaN coordinates.Úinf_mobÚinfrÞ   rß   rÐ   r/   rá   Úvis_infrã   rä   r)   NÚnan_mobÚnanr   r   ré   rÂ   Úvis_nanrë   rì   r+   rí   rî   rò   ró   rô   rõ   )r   Úfloatr   r@   rK   rL   rM   rN   rA   rD   rE   rÂ   rö   rB   rC   )rQ   Úent_infr  rX   rW   rø   rf   Úent_nanr  rY   rû   rZ   r[   rü   rý   rþ   rÿ   rË   r   r  r  r  r  s                          rg   Ú%test_cull_nan_inf_boundary_conditionszJTestViewportCullingAdversarialStress.test_cull_nan_inf_boundary_conditions¦   s\  € å˜y­%°©,¬,¸Ñ<Ô<ˆÝ 
Ð,<¸w¸iÑHÔHˆØÐˆw˜"Š}ÐÐÐÕÔÐÐÐÐˆw˜"ÐÑÔÐÕÔÑÔÐÐÕÔˆwÑÔÐÕÔˆwÑÔÐÐÕÔ˜"ÑÔÐÐÑÐÐÐÐÐÑÐÕÕÔÐÑÔÑÔÐÐÐÐÐå˜y­%°©,¬,¸Ñ<Ô<ˆÝ 
Ð,<¸w¸iÑHÔHˆàFÐF�s�7‰|Œ|ÐF˜qÐFˆ|˜qÒ ÐFÐFÐFÐFÐF W¨Q¤ZÐF ZÔ%9ÐF¸YÐFÐ%9¸YÒ%FÐFÐFÐFÐFÑFÕFÔFÐFÐFÐFÐFˆ|˜qÐFÑFÔFÐFÕFÔFÑFÔFÐFÐFÕFÔF�sÑFÔFÐFÕFÔF�sÑFÔFÐFÐFÐFÕFÔFÑFÔFÐFÐFÕFÔF�7ÑFÔFÐFÕFÔF�7ÑFÔFÐFÐFÕFÔFˆ|ÑFÔFÕFÔF˜qÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÐFÐFÕFÔFÐFÐFÐFÐFÐ%9¸YÐFÑFÔFÕFÔF ZÑFÔFÕFÔFÐ%9ÑFÔFÕFÔF¸YÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÕFÔFÐFÐFÑFÔFÐFÑFÐFÐFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFrt   c                óÆ  — t          ddd¦  «        \  }}t          dddd¬¦  «        \  }}||k    }|sÂt          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndd	t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd	d
œz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d}d}||z
  }	||	k    }|sÕt          j        d|fd||	f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nddt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }
dd|
iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}	dS )zRVerifies vertical displacement in isometric projection with extreme Z coordinates.g      $@rÞ   g     @�@g      8@)Úz_scaler/   )z%(py0)s == %(py2)sÚiso_x0Úiso_xz)r3   r4   zassert %(py4)sr’   Ng     p×@)z%(py0)s == (%(py2)s - %(py4)s)Úiso_yzÚiso_y0rª   r5   r*   )	r   r@   rK   rL   rM   rN   rA   rD   rE   )rQ   r"  r%  r#  r$  rW   Ú@py_format3r–   re   rÊ   rf   r_   s               rg   Ú"test_cull_extreme_elevation_offsetzGTestViewportCullingAdversarialStress.test_cull_extreme_elevation_offset±   s(  € å$ T¨4°Ñ5Ô5‰ˆ�Ý$ T¨4°ÀÐFÑFÔF‰ˆ�Ø˜ÒÐÐÐÕÔÐÐÐÐˆv˜ÐÑÔÐÕÔÑÔÐÐÕÔˆvÑÔÐÕÔˆvÑÔÐÐÐÕÔÑÔÐÐÕÔ˜ÑÔÐÕÔ˜ÑÔÐÐÐÐÑÐÐÐÐÐÑÐÕÕÔÐÑÔÑÔÐÐÐØ")Ð)˜ 'Ñ)Ð)ˆvÐ)Ò)Ð)Ð)Ð)Õ)Ô)Ð)Ð)Ð)Ð)ˆvÐ)Ð)Ñ)Ô)Ð)Õ)Ô)Ñ)Ô)Ð)Ð)Õ)Ô)ˆvÑ)Ô)Ð)Õ)Ô)ˆvÑ)Ô)Ð)Ð)Ð)Õ)Ô)Ñ)Ô)Ð)Ð)Õ)Ô)˜Ñ)Ô)Ð)Õ)Ô)˜Ñ)Ô)Ð)Ð)Õ)Ô) 'Ñ)Ô)Ð)Ð)Ñ)Ð)Ð)Ð)Ð)Ð)Ñ)Ð)Õ)Õ)Ô)Ð)Ñ)Ô)Ñ)Ô)Ð)Ð)Ð)Ð)Ð)Ð)Ð)Ð)Ð)rt   N©r   r   )	rš   r›   rœ   r�   rÛ   r  r  r  r'  rž   rt   rg   rÎ   rÎ   ƒ   sŠ   € € € € € ØbÐbðdð dð dð dðLð Lð Lð Lð	(ð 	(ð 	(ð 	(ð	Gð 	Gð 	Gð 	Gð*ð *ð *ð *ð *ð *rt   rÎ   c                  óh   — e Zd ZdZej                             dg d¢¦  «        dd	„¦   «         Zdd
„ZdS )ÚTestDrawCallBudgetValidationzSValidates the AC5 constraint: For 50 on-screen entities, instanced draw calls < 30.zentity_count,num_archetypes))r³   r   )r³   é   )r³   é   )r¤   r,  Úentity_countrH   Únum_archetypesr   r   c           	     óô  — |}d}d}||z   |z   }d}||k     }|s¶t          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }	t          j        d|› d	|› d
|› d�¦  «        dz   d|	iz  }
t          t          j        |
¦  «        ¦  «        ‚dx}}d}||k    }|s—t          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }	dd|	iz  }
t          t          j        |
¦  «        ¦  «        ‚dx}}dS )zKCalculates draw calls under GPU palette instancing and asserts < 30 budget.é   r   é   r×   )z%(py0)s < %(py3)sÚtotal_instanced_draw_callsrã   zDraw calls z exceeded budget of 30 for z entities across z archetypesú
>assert %(py5)sr)   Nrn   r8   )z%(py0)s <= %(py3)srä   ©	r@   rK   rL   rM   rN   rA   rP   rD   rE   )rQ   r-  r.  Úmonster_batchesÚ
hero_callsÚshadow_callr2  rX   rW   rø   rf   s              rg   Ú%test_draw_call_instanced_budget_holdszBTestDrawCallBudgetValidation.test_draw_call_instanced_budget_holds¼   sx  € ð )ˆØˆ
ØˆØ%4°zÑ%AÀKÑ%OÐ"à,.ð 	
Ð)¨BÒ.ð 	
ð 	
ð 	
õ 	
ìð	
ð 	
ð 	
ð 	
Ð)¨Bð 	
ñ 	
ô 	
ð 	
õ 	
ô 
ñ	
ô 	
ð 	
ð 	
õ 	
ìð *ñ 	
ô 	
ð 	
õ 	
ô 
ð *ñ 	
ô 	
ð 	
ð 	
õ 	
ô 
ð -/ñ 	
ô 	
ð 	
ð 	
ñ 	
ð 	
õ 	
ìðNÐ4ð Nð NØðNð NØ2@ðNð Nð Nñ	
ô 	
ð 	
ñ 	
ð 	
ð 	
ð 	
ñ 	
ð 	
õ 	
õ 	
ìð	
ñ 	
ô 	
ñ 	
ô 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð ./Ð.Ð)¨QÒ.Ð.Ð.Ð.Õ.Ô.Ð.Ð.Ð.Ð.Ð)¨QÐ.Ñ.Ô.Ð.Õ.Ô.Ñ.Ô.Ð.Ð.Õ.Ô.Ð)Ñ.Ô.Ð.Õ.Ô.Ð)Ñ.Ô.Ð.Ð.Õ.Ô.¨QÑ.Ô.Ð.Ð.Ñ.Ð.Ð.Ð.Ð.Ð.Ñ.Ð.Õ.Õ.Ô.Ð.Ñ.Ô.Ñ.Ô.Ð.Ð.Ð.Ð.Ð.Ð.Ð.rt   c                óˆ  — d}|dz  }d}||k    }|s¬t          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }t          j        d¦  «        d	z   d
|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}dS )zQProves that a naive unbatched renderer (1 call per entity) fails the < 30 budget.r³   r   r1  rÀ   )z%(py0)s >= %(py3)sÚnaive_unbatched_draw_callsrã   z/Naive renderer must exceed the 30 draw call capr3  r)   Nr4  )rQ   Úentities_on_screenr:  rX   rW   rø   rf   s          rg   Ú0test_draw_call_unbatched_baseline_exceeds_budgetzMTestDrawCallBudgetValidation.test_draw_call_unbatched_baseline_exceeds_budgetÎ   sñ   € àÐØ%7¸!Ñ%;Ð"Ø-/ÐbÐ)¨RÒ/ÐbÐbÐbÕbÔbÐbÐbÐbÐbÐ)¨RÐbÑbÔbÐbÕbÔbÑbÔbÐbÐbÕbÔbÐ)ÑbÔbÐbÕbÔbÐ)ÑbÔbÐbÐbÕbÔb¨RÑbÔbÐbÐbÑbÐbÕbÔbÐ1bÑbÔbÐbÑbÐbÐbÐbÑbÐbÕbÕbÔbÐbÑbÔbÑbÔbÐbÐbÐbÐbÐbÐbÐbrt   N)r-  rH   r.  rH   r   r   r(  )	rš   r›   rœ   r�   ÚpytestÚmarkÚparametrizer8  r<  rž   rt   rg   r*  r*  ¹   sn   € € € € € Ø]Ð]à„[×ÒÐ:Ð<aÐ<aÐ<aÑbÔbð/ð /ð /ñ cÔbð/ð"cð cð cð cð cð crt   r*  ),r�   Ú
__future__r   ÚbuiltinsrL   Ú_pytest.assertion.rewriteÚ	assertionÚrewriter@   ÚmathÚpathlibr   rx   ÚtempfileÚtimeÚtypingr   r   r   ÚPILr   r=  Ú"tools.asset_pipeline.lod_generatorr	   r
   Ú'tools.asset_pipeline.texture_compressorr   r   Ú+tools.asset_pipeline.viewport_culling_utilsr   r   r   r   r   r   r   Ú__file__ÚresolveÚparentrÅ   r   r    rÎ   r*  rž   rt   rg   ú<module>rQ     s9  ððð ð #Ð "Ð "Ð "Ð "Ð "à  € € € € € € € € € € € € €€€€Ø Ð Ð Ð Ð Ð Ø €€€Ø €€€Ø €€€Ø $Ð $Ð $Ð $Ð $Ð $Ð $Ð $Ð $Ð $à Ð Ð Ð Ð Ð Ø €€€ðð ð ð ð ð ð ð ðð ð ð ð ð ð ð ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ˆD�‰NŒN×"Ò"Ñ$Ô$Ô+Ô2Ô9€	ð4,ð 4,ð 4,ð 4,ð 4,ñ 4,ô 4,ð 4,ðn!gð !gð !gð !gð !gñ !gô !gð !gðH3*ð 3*ð 3*ð 3*ð 3*ñ 3*ô 3*ð 3*ðlcð cð cð cð cñ cô cð cð cð crt   