
XTc           @   sT   d  Z  d Z d Z d Z  d d l Z d e f d     YZ d e f d	     YZ d S(
   s   Clock to manage frame/cpu rate.s   $Id: gameclock.py$s   Gummbum, (c) 2011-2012s  

GameClock is a fixed time-step clock that keeps time in terms of game
time. It will attempt to keep game time close to real time, so if an
interval takes one second of game time then the user experiences one
second of real time. In the worst case where the CPU cannot keep up with
the game load, game time will subjectively take longer but still remain
accurate enough to keep game elements in synchronization.

GameClock manages time in the following ways:

    1.  Register special callback functions that will be run when they
        are due.
    2.  Schedule game logic updates at a constant speed, independent of
        frame rate.
    3.  Schedule frames at capped frames-per-second, or uncapped.
    4.  Invoke a pre-emptive pause callback when paused.
    5.  Schedule miscellaneous items at user-configurable intervals.
    6.  Optionally sleep between schedules to conserve CPU cycles.
    7.  Gracefully handles corner cases.

Note the Python Library docs mention that not all computer platforms'
time functions return time fractions of a second. This module will not
work on such platforms.

USAGE

Callback:

    clock = GameClock(
        update_callback=update_world,
        frame_callback=draw_scene,
        pause_callback=pause_game)
    while 1:
        clock.tick()

Special callbacks can be directly set and cleared at any time:

    clock.update_callback = my_new_update
    clock.frame_callback = my_new_draw
    clock.pause_callback = my_new_pause

    clock.update_callback = None
    clock.frame_callback = None
    clock.pause_callback = None

Scheduling miscellanous callbacks:

    def every_second_of_every_day(dt):
        "..."
    clock.schedule_interval(every_second_of_every_day, 1.0)

The update_callback receives a single DT argument, which is the time-step
in seconds since the last update.

The frame_callback receives a single INTERPOLATION argument, which is the
fractional position in time of the frame within the current update time-
step. It is a float in the range 0.0 to 1.0.

The pause_callback receives no arguments.

User-defined interval callbacks accept at least a DT argument, which is
the scheduled item's interval, and optional user-defined arguments. See
GameClock.schedule_interval.

iNt   _IntervalItemc           B   s,   e  Z d  Z d d d d d g Z d   Z RS(   s0   An interval item runs after an elapsed interval.t   funct   intervalt   lasttimet   lifet   argsc         C   s7   | |  _  t |  |  _ | |  _ | |  _ | |  _ d  S(   N(   R   t   floatR   R   R   R   (   t   selfR   R   t   curtimeR   R   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   __init__v   s
    			(   t   __name__t
   __module__t   __doc__t	   __slots__R	   (    (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR    s   s   t	   GameClockc           B   s   e  Z d  Z d d e e j d d d d  Z e d    Z e j	 d    Z e d    Z
 e
 j	 d    Z
 e d    Z e d	    Z e d
    Z d   Z d   Z d   Z d g  d  Z d   Z e d    Z d   Z d   Z RS(   sO  
    GameClock is an implementation of fixed-timestep clocks used for
    running the game.

    =============== ============
    Attribute       Description
    =============== ============
    get_ticks       The time source for the game. Should support at least
                    subsecond accuracy.
    max_ups         The maximum number of updates per second. The clock
                    will prioritize trying to keep the number of
                    updates per second at this level, at the cost of
                    frames per second
    max_fps         The maximum number of frames per second.
    use_wait        Boolean which represents whether the clock should
                    try to sleep when possible. Setting this to False
                    will give better game performance on lower end
                    hardware, but take more CPU power
    update_callback The function which should be called when for
                    updates
    frame_callback  The function which should be called for frame
                    rendering
    game_time       Virtual elapsed time in milliseconds
    paused          The game time at which the clock was paused
    =============== ============

    In addition to these attributes, the following read-only attributes
    provide some useful metrics on performance of the program.

    =============== ============
    Attribute       Description
    =============== ============
    num_updates     The number of updates run in the current one-second
                    interval
    num_frames      The number of frames run in the current one-second
                    interval
    dt_update       Duration of the previous update
    dt_frame        Duration of the previous update
    cost_of_update  How much real time the update callback takes
    cost_of_frame   How much real time the frame callback takes
    ups             Average number of updates per second over the last
                    five seconds
    fps             Average number of frames per second over the last
                    five seconds
    =============== ============
    i   i    c   	      C   s  | |  _  | |  _ | |  _ | |  _ | |  _ | |  _ | |  _ |  j    } | |  _ | |  _ | |  _	 | |  _
 | |  _ | |  _ | |  _ | |  _ t |  _ t |  _ d |  _ t |  _ g  |  _ g  |  _ d |  _ d |  _ d |  _ d |  _ d |  _ d |  _ d |  _ d |  _ d  S(   Ni    g        (   t	   get_tickst   max_upst   max_fpst   use_waitt   update_callbackt   frame_callbackt   paused_callbackt
   _real_timet
   _game_timet   _last_updatet   _last_update_realt   _next_updatet   _last_framet   _next_framet   _next_secondt   Falset   _update_readyt   _frame_readyt   _pausedt
   _need_sortt
   _schedulest   _unschedulest   num_updatest
   num_framest	   dt_updatet   dt_framet   cost_of_updatet   cost_of_framet   upst   fps(	   R   R   R   R   t   time_sourceR   R   R   t   CURRENT_TIME(    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR	      s<    
																												c         C   s   |  j  S(   N(   t   _max_ups(   R   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR      s    c         C   s   | |  _  d | |  _ d  S(   Ng      ?(   R/   t   _update_interval(   R   t   val(    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR      s    	c         C   s   |  j  S(   N(   t   _max_fps(   R   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR      s    c         C   s,   | |  _  | d k r d | n d |  _ d  S(   Ni    g      ?(   R2   t   _frame_interval(   R   R1   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR      s    	c         C   s   |  j  S(   N(   R   (   R   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt	   game_time   s    c         C   s   |  j  S(   N(   R!   (   R   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   paused   s    c         C   s1   |  j  |  j } | |  j } | d k r- | Sd S(   Ng      ?(   R   R   R0   (   R   t   interp(    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   interpolate   s    c         C   sp  |  j    } | |  _ |  j r8 |  j r4 |  j   n  d S|  j } |  j } | |  j k r | |  j |  _ | |  _ | | 7} | |  _ | |  _	 | | |  _ |  j
 d 7_
 |  j r t |  _ q n  | |  j k rt } | |  j |  j k r t } n3 |  j d k rt } n |  j |  _ |  j d 7_ | rd |  _ | |  j |  _ | |  _ | |  j |  _ |  j d 7_ |  j rt |  _ qqn  | |  j |  j k s| |  j |  j k  r| |  j k r| |  j |  _ | |  _ | |  j |  _ |  j d 7_ |  j rt |  _ qn  t } d } |  j r`|  j d } | j | j } | | k r`t } q`n  |  j so| r||  j   n  |  j r|  j r|  j  } |   }	 |  j |  j  |   |	 |  _ t |  _ n  | |  j k r|  j |  n  |  j rl|  j |  j |  j g }
 | d k r(|
 j  |  n  t! t" |
  } |  j    }	 | |	 } | d k rlt# j$ |  qln  d S(   sI   
        Should be called in a loop, will run and handle timers.
        Ni   i    gMb`?(%   R   R   R!   R   R0   R   R   R   R'   R   R%   R   t   TrueR   R   R   R*   t   _frame_skipR   R(   R3   R&   R   R    R#   R   R   t   _run_schedulesR7   R   t   _flipR   t   appendt   reducet   mint   timet   sleep(   R   t	   real_timet   update_intervalR4   t   do_framet   sched_readyt	   sched_duet   schedR   t   tickst   upcoming_eventst   nextt   time_to_sleep(    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   tick   s    						
														
c         C   s   |  j    |  _ d S(   s   Pause the clock so that time does not elapse.

        While the clock is paused, no schedules will fire and tick() returns
        immediately without progressing internal counters. Game loops that
        completely rely on the clock will need to take over timekeeping and
        handling events; otherwise, the game will appear to deadlock. There are
        many ways to solve this scenario. For instance, another clock can be
        created and used temporarily, and the original swapped back in and
        resumed when needed.
        N(   R   R!   (   R   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   pausek  s    c         C   sm   |  j    } |  j } x+ |  j D]  } | | j } | | | _ q W| | |  j |  _ d |  _ | |  _ d S(   s3   Resume the clock from the point that it was paused.i    N(   R   R!   R#   R   R   R   (   R   RA   R5   t   itemt   delta(    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   resumex  s    		c         C   sU   |  j  |  t | | |  j   | | g t |   } |  j j |  t |  _ d S(   sT  

        Schedule an item to be called back each time an interval elapses.

        While the clock is paused time does not pass.

        | *func*: The callback function.
        | *interval*: The time in seconds (float) between calls.
        | *life*: The number of times the callback will fire, after which the
          schedule will be removed. If the value 0 is specified, the event
          will persist until manually unscheduled.
        | *args*: A list that will be passed to the callback as an unpacked
          sequence, like so: item.func(\*[item.interval]+item.args).

        N(   t
   unscheduleR    R   t   listR#   R<   R8   R"   (   R   R   R   R   R   RM   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   schedule_interval  s
    (c         C   sC   |  j  } x3 t |  D]% } | j | k r | j |  q q Wd S(   s   Unschedule a managed function.N(   R#   RQ   R   t   remove(   R   R   RF   RM   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyRP     s    	c         C   s   |  j  |  j S(   N(   R   R   (   RM   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   _interval_item_sort_key  s    c   	      C   sy  |  j  } |  j rP |  j rP |   } |  j |  j  |   | |  _ t |  _ n  |  j r{ |  j j d |  j	  t |  _ n  |  j
 } x |  j D] } | j } | j | } | | k r<| j | j   | j | 7_ t } | j d k r'| j d k r|  j j | j  t } q'| j d 8_ n  | r=t |  _ q=q Pq W|  j rux |  j D] } |  j |  qTW|  j 2n  d  S(   Nt   keyi    i   (   R   R   R   R'   R)   R   R"   R#   t   sortRT   R   R   R   R   R   R8   R   R$   R<   RP   (	   R   R   t   tRA   RF   R   t   duet	   need_sortR   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR:     s:    							c         C   sF   |  j  |  _ |  j |  _ d |  _  d |  _ | |  _ |  j d 7_ d  S(   Ni    g      ?(   R%   R+   R&   R,   t   _last_secondR   (   R   RA   (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR;     s    			N(   R
   R   R   R   R?   t   NoneR	   t   propertyR   t   setterR   R4   R5   R7   RK   RL   RO   RR   RP   t   staticmethodRT   R:   R;   (    (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyR   ~   s.   ..	l				%(   R   t   __version__t
   __author__R?   t   objectR    R   (    (    (    s0   /usr/lib/python2.7/site-packages/spyral/clock.pyt   <module>   s   (D