
    \
jg                         d Z ddlZddlmZ ddlmZmZmZ ddlm	Z	 ddl
mZ  G d d          Z G d	 d
          Z G d d          Z e            ad Zd ZddZd Zd Zd Zd Zd Zd Zd ZdS )a  Precise framerate calculation function scheduling.

Measuring time
==============

The `tick` and `get_fps` functions can be used in conjunction to fulfil most
games' basic requirements::

    from pyglet import clock
    while True:
        dt = clock.tick()
        # ... update and render ...
        print(f"FPS is {clock.get_fps()}")

The ``dt`` value returned gives the number of seconds (as a float) since the
last "tick".

The `get_fps` function averages the framerate over a sliding window of
approximately 1 second.  (You can calculate the instantaneous framerate by
taking the reciprocal of ``dt``).

Always remember to `tick` the clock!

Scheduling
==========

You can schedule a function to be called every time the clock is ticked::

    def callback(dt):
        print(f"{dt} seconds since last callback")

    clock.schedule(callback)

The `schedule_interval` method causes a function to be called every "n"
seconds::

    clock.schedule_interval(callback, .5)   # called twice a second

The `schedule_once` method causes a function to be called once "n" seconds
in the future::

    clock.schedule_once(callback, 5)        # called in 5 seconds

All of the `schedule` methods will pass on any additional args or keyword args
you specify to the callback function::

    def move(dt, velocity, sprite):
       sprite.position += dt * velocity

    clock.schedule(move, velocity=5.0, sprite=alien)

You can cancel a function scheduled with any of these methods using
`unschedule`::

    clock.unschedule(move)

Using multiple clocks
=====================

The clock functions are all relayed to an instance of
:py:class:`~pyglet.clock.Clock` which is initialised with the module.  You can
get this instance to use directly::

    clk = clock.get_default()

You can also replace the default clock with your own:

    myclk = clock.Clock()
    clock.set_default(myclk)

Each clock maintains its own set of scheduled functions and FPS
measurement.  Each clock must be "ticked" separately.

Multiple and derived clocks potentially allow you to separate "game-time" and
"wall-time", or to synchronise your clock to an audio or video stream instead
of the system clock.
    N)
attrgetter)heappushheappopheappushpop)deque)compat_platformc                       e Zd Zg dZd ZdS )_ScheduledItemfuncargskwargsc                 0    || _         || _        || _        d S Nr   )selfr   r   r   s       F/DATA/AppData/hermes/venv/lib/python3.11/site-packages/pyglet/clock.py__init__z_ScheduledItem.__init__~   s    		    N)__name__
__module____qualname__	__slots__r    r   r   r
   r
   {   s.        ***I    r   r
   c                   "    e Zd Zg dZd Zd ZdS )_ScheduledIntervalItemr   intervallast_tsnext_tsr   r   c                 Z    || _         || _        || _        || _        || _        || _        d S r   r   )r   r   r   r   r   r   r   s          r   r   z_ScheduledIntervalItem.__init__   s0    	 	r   c                 Z    	 | j         |j         k     S # t          $ r | j         |k     cY S w xY wr   )r   AttributeError)r   others     r   __lt__z_ScheduledIntervalItem.__lt__   sD    	(<%-// 	( 	( 	(<%''''	(s    **N)r   r   r   r   r   r$   r   r   r   r   r      s=        LLLI  ( ( ( ( (r   r   c                        e Zd ZdZedv rdndZedz
  ZdZdZdZ	e
j        f fd	Zed	             Zd
 Zd ZddZd Zd Zd Zd Zd Zd Zd Zd Zd Z xZS )ClockzhClass for calculating and limiting framerate.

    It is also used for calling scheduled functions.
    )win32cygwingMb?g{Gzt?gMbP?NFc                    t          t          |                                            || _        |                                 | _        d| _        t                      | _        d| _        d| _	        g | _
        g | _        d| _        dS )aW  Initialise a Clock, with optional custom time function.

        :Parameters:
            `time_function` : function
                Function to return the elapsed time of the application,
                in seconds.  Defaults to time.time, but can be replaced
                to allow for easy time dilation effects or game pausing.

        Nr   <   )superr&   r   timer   r   r   timescumulative_timewindow_size_schedule_items_schedule_interval_items_current_interval_item)r   time_function	__class__s     r   r   zClock.__init__   sy     	eT##%%%!	yy{{ WW
 !(*%&*###r   c                 4    t          j        | dz             d S )Ngư>)r,   sleep)microsecondss    r   r6   zClock.sleep   s    
<$&'''''r   c                 @   |                                  }| j        d}nh|| j        z
  }| j                            |           t	          | j                  | j        k    r'| xj        | j                                        z  c_        | xj        |z  c_        || _        |S )a  Get the elapsed time since the last call to `update_time`.

        This updates the clock's internal measure of time and returns
        the difference since the last update (or since the clock was created).

        .. versionadded:: 1.2

        :rtype: float
        :return: The number of seconds since the last `update_time`, or 0
                 if this was the first time it was called.
        Nr   )r,   r   r-   
appendleftlenr/   r.   pop)r   tsdelta_ts      r   update_timezClock.update_time   s     YY[[<GG4<'GJ!!'***4:!111$$
(8(88$$'r   c                    | j         }d}| j        r4d}t          | j                  D ]} |j        |g|j        R i |j         | j        }	 |d         j        |k    r|S n# t          $ r |cY S w xY wdx| _	        }| j
        }|r|t          |          }nt          ||          }|| _	        |j        |k    rn |j        ||j         z
  g|j        R i |j         |j        ro|j         |j        z   |_        ||_         |j        |k    rH||j        z
  dk     r||j        z   |_        n4 |||j                  |_        |j        |j        z
  |_         n	dx| _	        }||t          ||           dS )a  Call scheduled functions that elapsed on the last `update_time`.

        .. versionadded:: 1.2

        :Parameters:
            dt : float
                The elapsed time since the last update to pass to each
                scheduled function.  This is *not* used to calculate which
                functions have elapsed.

        :rtype: bool
        :return: True if any functions were called, otherwise False.
        FTr   Ng?)r   r0   listr   r   r   r1   r   
IndexErrorr2   _get_soft_next_tsr   r   r   r   )r   dtnowresultiteminterval_itemsget_soft_next_tss          r   call_scheduled_functionszClock.call_scheduled_functions   s     l  	9FT122 9 9	"8ty888DK8888 6	a (3.. /  	 	 	MMM	
 .21#d1 /	:
 |~..">488
 +/D' |c!! DIcDL(D49DDDDDD} :
  $|dm;" <3&& T\)D00 (+T]': (8'7T]'K'K'+|dm'C 6:9+d_  /	:b ^T***ts   A! !A0/A0c                     |s| j         r|                     d           |                                 }|                     |           |S )a9  Signify that one frame has passed.

        This will call any scheduled functions that have elapsed.

        :Parameters:
            `poll` : bool
                If True, the function will call any scheduled functions
                but will not sleep or busy-wait for any reason.  Recommended
                for advanced applications managing their own sleep timers
                only.

                Since pyglet 1.1.

        :rtype: float
        :return: The number of seconds since the last "tick", or 0 if this was
            the first frame.
        r   )_force_sleepr6   r>   rI   )r   pollr=   s      r   tickz
Clock.tickF  sO    $  	) 	JJqMMM""$$%%g...r   c                     | j         s|sdS | j        r5t          | j        d         j        |                                 z
  d          S dS )a  Get the time until the next item is scheduled.

        Applications can choose to continue receiving updates at the
        maximum framerate during idle time (when no functions are scheduled),
        or they can sleep through their idle time and allow the CPU to
        switch to other processes or run in low-power mode.

        If `sleep_idle` is ``True`` the latter behaviour is selected, and
        ``None`` will be returned if there are no scheduled items.

        Otherwise, if `sleep_idle` is ``False``, or if any scheduled items
        exist, a value of 0 is returned.

        :Parameters:
            `sleep_idle` : bool
                If True, the application intends to sleep through its idle
                time; otherwise it will continue ticking at the maximum
                frame rate allowed.

        :rtype: float
        :return: Time until the next scheduled event in seconds, or ``None``
                 if there is no event scheduled.

        .. versionadded:: 1.1
        g        r   N)r0   r1   maxr   r,   )r   
sleep_idles     r   get_sleep_timezClock.get_sleep_time_  sT    4  	z 	3( 	Tt4Q7?$))++MsSSStr   c                 L    | j         sdS t          | j                  | j         z  S )aV  Get the average clock update frequency of recent history.

        The result is the average of a sliding window of the last "n" updates,
        where "n" is some number designed to cover approximately 1 second.
        This is **not** the Window redraw rate.

        :rtype: float
        :return: The measured updates per second.
        r   )r.   r:   r-   )r   s    r   get_fpszClock.get_fps  s*     # 	14:!555r   c                 `    | j         p| j        }|                                 }||z
  dk    r|S |S )a  Get the nearest timestamp.

        Schedule from now, unless now is sufficiently close to last_ts, in
        which case use last_ts.  This clusters together scheduled items that
        probably want to be scheduled together.  The old (pre 1.1.1)
        behaviour was to always use self.last_ts, and not look at ts.  The
        new behaviour is needed because clock ticks can now be quite
        irregular, and span several seconds.
        g?)r   r   r,   )r   r   r<   s      r   _get_nearest_tszClock._get_nearest_ts  s8     ,.$,YY[[<#Ir   c                      fd} j                             t          d                     ||z   } |||dz            s|S |}d}	 |}t          |dz
            D ]}||z  } |||dz            s|c S |dz  }|dz  }|dk    r|S B)	Nc                 z    j         D ]1}t          |j        | z
            |k    r dS |j        | |z   k    r dS 2dS )z7Check if `ts` has already got an item scheduled nearby.TF)r1   absr   )r<   erF   r   s      r   takenz&Clock._get_soft_next_ts.<locals>.taken  s\     5 ! !t|b())Q..44\BF** 55 + 5r   r   )key      T      )r1   sortr   range)r   r   r   rZ   r   rC   divsis   `       r   rB   zClock._get_soft_next_ts  s    
	 
	 
	 
	 
	" 	%**z)/D/D*EEE" H$uWhl++ 	N	G4!8__ # #2uWb1f-- #"NNN#!GBAID byy	r   c                 \    t          |||          }| j                            |           dS )a  Schedule a function to be called every frame.

        The function should have a prototype that includes ``dt`` as the
        first argument, which gives the elapsed time, in seconds, since the
        last clock tick.  Any additional arguments given to this function
        are passed on to the callback::

            def callback(dt, *args, **kwargs):
                pass

        :Parameters:
            `func` : callable
                The function to call each frame.
        N)r
   r0   append)r   r   r   r   rF   s        r   schedulezClock.schedule  s2     dD&11##D)))))r   c                     |                                  }||z   }t          |d||||          }t          | j        |           dS )a`  Schedule a function to be called once after `delay` seconds.

        The callback function prototype is the same as for `schedule`.

        :Parameters:
            `func` : callable
                The function to call when the timer lapses.
            `delay` : float
                The number of seconds to wait before the timer lapses.
        r   NrU   r   r   r1   )r   r   delayr   r   r   r   rF   s           r   schedule_oncezClock.schedule_once  sN     &&((E/%dAwvNN.55555r   c                     |                                  }||z   }t          ||||||          }t          | j        |           dS )a  Schedule a function to be called every `interval` seconds.

        Specifying an interval of 0 prevents the function from being
        called again (see `schedule` to call a function as often as possible).

        The callback function prototype is the same as for `schedule`.

        :Parameters:
            `func` : callable
                The function to call when the timer lapses.
            `interval` : float
                The number of seconds to wait between each call.

        Nrh   )r   r   r   r   r   r   r   rF   s           r   schedule_intervalzClock.schedule_interval  sO     &&((H$%dHgwfUU.55555r   c                     |                      |                                 |          }||z
  }t          ||||||          }t          | j        |           dS )a  Schedule a function to be called every ``interval`` seconds.

        This method is similar to `schedule_interval`, except that the
        clock will move the interval out of phase with other scheduled
        functions so as to distribute CPU more load evenly over time.

        This is useful for functions that need to be called regularly,
        but not relative to the initial start time.  :py:mod:`pyglet.media`
        does this for scheduling audio buffer updates, which need to occur
        regularly -- if all audio updates are scheduled at the same time
        (for example, mixing several tracks of a music score, or playing
        multiple videos back simultaneously), the resulting load on the
        CPU is excessive for those intervals but idle outside.  Using
        the soft interval scheduling, the load is more evenly distributed.

        Soft interval scheduling can also be used as an easy way to schedule
        graphics animations out of phase; for example, multiple flags
        waving in the wind.

        .. versionadded:: 1.1

        :Parameters:
            `func` : callable
                The function to call when the timer lapses.
            `interval` : float
                The number of seconds to wait between each call.

        N)rB   rU   r   r   r1   )r   r   r   r   r   r   r   rF   s           r   schedule_interval_softzClock.schedule_interval_soft  s_    : (()=)=)?)?JJH$%dHgwfUU.55555r   c                    t          fd| j        D                       }| j        r*| j        j        k    r|                    | j                   |D ]}d|_        d |_        fd| j        D             | _        dS )a:  Remove a function from the schedule.

        If the function appears in the schedule more than once, all occurrences
        are removed.  If the function was not scheduled, no error is raised.

        :Parameters:
            `func` : callable
                The function to remove from the schedule.

        c              3   2   K   | ]}|j         k    |V  d S r   r   ).0rF   r   s     r   	<genexpr>z#Clock.unschedule.<locals>.<genexpr>;  s<       0 0"!Y$.. ....0 0r   r   c                     | S r   r   )xr   r   s      r   <lambda>z"Clock.unschedule.<locals>.<lambda>E  s    1 r   c                 *    g | ]}|j         k    |S r   rq   )rr   rc   r   s     r   
<listcomp>z$Clock.unschedule.<locals>.<listcomp>G  s     RRRa16T>>>>>r   N)setr1   r2   r   addr   r0   )r   r   valid_itemsrF   s    `  r   
unschedulezClock.unschedule-  s      0 0 0 0&*&C0 0 0 0 0 & 	=*/477 ;<<< 	5 	5DDM44DIIRRRR4+?RRRr   F)r   r   r   __doc__r   	MIN_SLEEPSLEEP_UNDERSHOOTr0   r1   rK   r,   perf_counterr   staticmethodr6   r>   rI   rM   rQ   rS   rU   rB   rf   rj   rl   rn   r|   __classcell__)r4   s   @r   r&   r&      sh         ),???UI !5( O  $ L%)%6 + + + + + +0 ( ( \(  2[ [ [z   2     D6 6 6   4 4 4l* * *$6 6 6 6 6 6( 6  6  6DS S S S S S Sr   r&   c                 
    | a dS )zSet the default clock to use for all module-level functions.

    By default an instance of :py:class:`~pyglet.clock.Clock` is used.

    :Parameters:
        `default` : `Clock`
            The default clock to use.
    N_default)defaults    r   set_defaultr   N  s     HHHr   c                      t           S )zGet the pyglet default Clock.

    Return the :py:class:`~pyglet.clock.Clock` instance that is used by all
    module-level clock functions.

    :rtype: `Clock`
    :return: The default clock.
    r   r   r   r   get_defaultr   [  s	     Or   Fc                 6    t                               |           S )a  Signify that one frame has passed on the default clock.

    This will call any scheduled functions that have elapsed.

    :Parameters:
        `poll` : bool
            If True, the function will call any scheduled functions
            but will not sleep or busy-wait for any reason.  Recommended
            for advanced applications managing their own sleep timers
            only.

            Since pyglet 1.1.

    :rtype: float
    :return: The number of seconds since the last "tick", or 0 if this was the
        first frame.
    )r   rM   )rL   s    r   rM   rM   g  s    $ ==r   c                 6    t                               |           S )a  Get the time until the next item is scheduled on the default clock.

    See `Clock.get_sleep_time` for details.

    :Parameters:
        `sleep_idle` : bool
            If True, the application intends to sleep through its idle
            time; otherwise it will continue ticking at the maximum
            frame rate allowed.

    :rtype: float
    :return: Time until the next scheduled event in seconds, or ``None``
        if there is no event scheduled.

    .. versionadded:: 1.1
    )r   rQ   )rP   s    r   rQ   rQ   |  s    " "":...r   c                  4    t                                           S )a  Get the average clock update frequency.

    The result is the sliding average of the last "n" updates,
    where "n" is some number designed to cover approximately 1
    second. This is the internal clock update rate, **not** the
    Window redraw rate. Platform events, such as moving the
    mouse rapidly, will cause the clock to refresh more often.

    :rtype: float
    :return: The measured updates per second.
    )r   rS   r   r   r   rS   rS     s     r   c                 0    t          j        | g|R i | dS )a  Schedule 'func' to be called every frame on the default clock.

    The arguments passed to func are ``dt``, followed by any ``*args`` and
    ``**kwargs`` given here.

    :Parameters:
        `func` : callable
            The function to call each frame.
    N)r   rf   r   s      r   rf   rf     s+     d,T,,,V,,,,,r   c                 2    t          j        | |g|R i | dS )a  Schedule ``func`` on the default clock every interval seconds.

    The arguments passed to ``func`` are ``dt`` (time since last function
    call), followed by any ``*args`` and ``**kwargs`` given here.

    :Parameters:
        `func` : callable
            The function to call when the timer lapses.
        `interval` : float
            The number of seconds to wait between each call.
    N)r   rl   r   r   r   r   s       r   rl   rl     s-     tX?????????r   c                 2    t          j        | |g|R i | dS )a\  Schedule ``func`` on the default clock every interval seconds.

    The clock will move the interval out of phase with other scheduled
    functions so as to distribute CPU more load evenly over time.

    The arguments passed to ``func`` are ``dt`` (time since last function
    call), followed by any ``*args`` and ``**kwargs`` given here.

    :see: `Clock.schedule_interval_soft`

    .. versionadded:: 1.1

    :Parameters:
        `func` : callable
            The function to call when the timer lapses.
        `interval` : float
            The number of seconds to wait between each call.

    N)r   rn   r   s       r   rn   rn     s-    ( #D(DTDDDVDDDDDr   c                 2    t          j        | |g|R i | dS )aN  Schedule ``func`` to be called once after ``delay`` seconds.

    This function uses the default clock. ``delay`` can be a float. The
    arguments passed to ``func`` are ``dt`` (time since last function call),
    followed by any ``*args`` and ``**kwargs`` given here.

    If no default clock is set, the func is queued and will be scheduled
    on the default clock as soon as it is created.

    :Parameters:
        `func` : callable
            The function to call when the timer lapses.
        `delay` : float
            The number of seconds to wait before the timer lapses.
    N)r   rj   )r   ri   r   r   s       r   rj   rj     s-      4888888888r   c                 :    t                               |            dS )zRemove ``func`` from the default clock's schedule.

    No error is raised if the ``func`` was never scheduled.

    :Parameters:
        `func` : callable
            The function to remove from the schedule.
    N)r   r|   rq   s    r   r|   r|     s     r   r}   )r~   r,   operatorr   heapqr   r   r   collectionsr   pygletr   r
   r   r&   r   r   r   rM   rQ   rS   rf   rl   rn   rj   r|   r   r   r   <module>r      s  HL L\        0 0 0 0 0 0 0 0 0 0       " " " " " "       ( ( ( ( ( ( ( ($qS qS qS qS qS qS qS qSj 577
 
 
	 	 	   */ / /(  
- 
- 
-@ @ @E E E.9 9 9&	 	 	 	 	r   