/* pygame - Python Game Library Copyright (C) 2000-2001 Pete Shinners This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Pete Shinners pete@shinners.org*/#include "pygame.h"#include "pgcompat.h"#include "doc/time_doc.h"#define WORST_CLOCK_ACCURACY 12staticSDL_TimerIDevent_timers[SDL_NUMEVENTS]={NULL};staticUint32timer_callback(Uint32interval,void*param){if(SDL_WasInit(SDL_INIT_VIDEO)){SDL_Eventevent;memset(&event,0,sizeof(event));event.type=(intptr_t)param;SDL_PushEvent(&event);}returninterval;}staticintaccurate_delay(intticks){intfuncstart,delay;if(ticks<=0)return0;if(!SDL_WasInit(SDL_INIT_TIMER)){if(SDL_InitSubSystem(SDL_INIT_TIMER)){RAISE(PyExc_SDLError,SDL_GetError());return-1;}}funcstart=SDL_GetTicks();if(ticks>=WORST_CLOCK_ACCURACY){delay=(ticks-2)-(ticks%WORST_CLOCK_ACCURACY);if(delay>=WORST_CLOCK_ACCURACY){Py_BEGIN_ALLOW_THREADS;SDL_Delay(delay);Py_END_ALLOW_THREADS;}}do{delay=ticks-(SDL_GetTicks()-funcstart);}while(delay>0);returnSDL_GetTicks()-funcstart;}staticPyObject*time_get_ticks(PyObject*self){if(!SDL_WasInit(SDL_INIT_TIMER))returnPyInt_FromLong(0);returnPyInt_FromLong(SDL_GetTicks());}staticPyObject*time_delay(PyObject*self,PyObject*arg){intticks;PyObject*arg0;/*for some reason PyArg_ParseTuple is puking on -1's! BLARG!*/if(PyTuple_Size(arg)!=1)returnRAISE(PyExc_ValueError,"delay requires one integer argument");arg0=PyTuple_GET_ITEM(arg,0);if(!PyInt_Check(arg0))returnRAISE(PyExc_TypeError,"delay requires one integer argument");ticks=PyInt_AsLong(arg0);if(ticks<0)ticks=0;ticks=accurate_delay(ticks);if(ticks==-1)returnNULL;returnPyInt_FromLong(ticks);}staticPyObject*time_wait(PyObject*self,PyObject*arg){intticks,start;PyObject*arg0;/*for some reason PyArg_ParseTuple is puking on -1's! BLARG!*/if(PyTuple_Size(arg)!=1)returnRAISE(PyExc_ValueError,"delay requires one integer argument");arg0=PyTuple_GET_ITEM(arg,0);if(!PyInt_Check(arg0))returnRAISE(PyExc_TypeError,"delay requires one integer argument");if(!SDL_WasInit(SDL_INIT_TIMER)){if(SDL_InitSubSystem(SDL_INIT_TIMER)){RAISE(PyExc_SDLError,SDL_GetError());returnNULL;}}ticks=PyInt_AsLong(arg0);if(ticks<0)ticks=0;start=SDL_GetTicks();Py_BEGIN_ALLOW_THREADS;SDL_Delay(ticks);Py_END_ALLOW_THREADS;returnPyInt_FromLong(SDL_GetTicks()-start);}staticPyObject*time_set_timer(PyObject*self,PyObject*arg){SDL_TimerIDnewtimer;intticks=0;intptr_tevent=SDL_NOEVENT;if(!PyArg_ParseTuple(arg,"ii",&event,&ticks))returnNULL;if(event<=SDL_NOEVENT||event>=SDL_NUMEVENTS)returnRAISE(PyExc_ValueError,"Event id must be between NOEVENT(0) and NUMEVENTS(32)");/*stop original timer*/if(event_timers[event]){SDL_RemoveTimer(event_timers[event]);event_timers[event]=NULL;}if(ticks<=0)Py_RETURN_NONE;/*just doublecheck that timer is initialized*/if(!SDL_WasInit(SDL_INIT_TIMER)){if(SDL_InitSubSystem(SDL_INIT_TIMER))returnRAISE(PyExc_SDLError,SDL_GetError());}newtimer=SDL_AddTimer(ticks,timer_callback,(void*)event);if(!newtimer)returnRAISE(PyExc_SDLError,SDL_GetError());event_timers[event]=newtimer;Py_RETURN_NONE;}/*clock object interface*/typedefstruct{PyObject_HEADintlast_tick;intfps_count,fps_tick;floatfps;inttimepassed,rawpassed;PyObject*rendered;}PyClockObject;// to be called by the other tick functions.staticPyObject*clock_tick_base(PyObject*self,PyObject*arg,intuse_accurate_delay){PyClockObject*_clock=(PyClockObject*)self;floatframerate=0.0f;intnowtime;if(!PyArg_ParseTuple(arg,"|f",&framerate))returnNULL;if(framerate){intdelay,endtime=(int)((1.0f/framerate)*1000.0f);_clock->rawpassed=SDL_GetTicks()-_clock->last_tick;delay=endtime-_clock->rawpassed;/*just doublecheck that timer is initialized*/if(!SDL_WasInit(SDL_INIT_TIMER)){if(SDL_InitSubSystem(SDL_INIT_TIMER)){RAISE(PyExc_SDLError,SDL_GetError());returnNULL;}}if(use_accurate_delay)delay=accurate_delay(delay);else{// this uses sdls delay, which can be inaccurate.if(delay<0)delay=0;Py_BEGIN_ALLOW_THREADS;SDL_Delay((Uint32)delay);Py_END_ALLOW_THREADS;}if(delay==-1)returnNULL;}nowtime=SDL_GetTicks();_clock->timepassed=nowtime-_clock->last_tick;_clock->fps_count+=1;_clock->last_tick=nowtime;if(!framerate)_clock->rawpassed=_clock->timepassed;if(!_clock->fps_tick){_clock->fps_count=0;_clock->fps_tick=nowtime;}elseif(_clock->fps_count>=10){_clock->fps=_clock->fps_count/((nowtime-_clock->fps_tick)/1000.0f);_clock->fps_count=0;_clock->fps_tick=nowtime;Py_XDECREF(_clock->rendered);}returnPyInt_FromLong(_clock->timepassed);}staticPyObject*clock_tick(PyObject*self,PyObject*arg){returnclock_tick_base(self,arg,0);}staticPyObject*clock_tick_busy_loop(PyObject*self,PyObject*arg){returnclock_tick_base(self,arg,1);}staticPyObject*clock_get_fps(PyObject*self,PyObject*args){PyClockObject*_clock=(PyClockObject*)self;returnPyFloat_FromDouble(_clock->fps);}staticPyObject*clock_get_time(PyObject*self){PyClockObject*_clock=(PyClockObject*)self;returnPyInt_FromLong(_clock->timepassed);}staticPyObject*clock_get_rawtime(PyObject*self){PyClockObject*_clock=(PyClockObject*)self;returnPyInt_FromLong(_clock->rawpassed);}/* clock object internals */staticstructPyMethodDefclock_methods[]={{"tick",clock_tick,METH_VARARGS,DOC_CLOCKTICK},{"get_fps",(PyCFunction)clock_get_fps,METH_NOARGS,DOC_CLOCKGETFPS},{"get_time",(PyCFunction)clock_get_time,METH_NOARGS,DOC_CLOCKGETTIME},{"get_rawtime",(PyCFunction)clock_get_rawtime,METH_NOARGS,DOC_CLOCKGETRAWTIME},{"tick_busy_loop",clock_tick_busy_loop,METH_VARARGS,DOC_CLOCKTICKBUSYLOOP},{NULL,NULL,0,NULL}};staticvoidclock_dealloc(PyObject*self){PyClockObject*_clock=(PyClockObject*)self;Py_XDECREF(_clock->rendered);PyObject_DEL(self);}PyObject*clock_str(PyObject*self){charstr[1024];PyClockObject*_clock=(PyClockObject*)self;sprintf(str,"<Clock(fps=%.2f)>",(float)_clock->fps);returnText_FromUTF8(str);}staticPyTypeObjectPyClock_Type={TYPE_HEAD(NULL,0)"Clock",/* name */sizeof(PyClockObject),/* basic size */0,/* itemsize */clock_dealloc,/* dealloc */0,/* print */0,/* getattr */0,/* setattr */0,/* compare */clock_str,/* repr */0,/* as_number */0,/* as_sequence */0,/* as_mapping */(hashfunc)0,/* hash */(ternaryfunc)0,/* call */clock_str,/* str */0,/* tp_getattro */0,/* tp_setattro */0,/* tp_as_buffer */0,/* flags */DOC_PYGAMETIMECLOCK,/* Documentation string */0,/* tp_traverse */0,/* tp_clear */0,/* tp_richcompare */0,/* tp_weaklistoffset */0,/* tp_iter */0,/* tp_iternext */clock_methods,/* tp_methods */0,/* tp_members */0,/* tp_getset */0,/* tp_base */0,/* tp_dict */0,/* tp_descr_get */0,/* tp_descr_set */0,/* tp_dictoffset */0,/* tp_init */0,/* tp_alloc */0,/* tp_new */};PyObject*ClockInit(PyObject*self){PyClockObject*_clock=PyObject_NEW(PyClockObject,&PyClock_Type);if(!_clock){returnNULL;}/*just doublecheck that timer is initialized*/if(!SDL_WasInit(SDL_INIT_TIMER)){if(SDL_InitSubSystem(SDL_INIT_TIMER))returnRAISE(PyExc_SDLError,SDL_GetError());}_clock->fps_tick=0;_clock->timepassed=0;_clock->rawpassed=0;_clock->last_tick=SDL_GetTicks();_clock->fps=0.0f;_clock->fps_count=0;_clock->rendered=NULL;return(PyObject*)_clock;}staticPyMethodDef_time_methods[]={{"get_ticks",(PyCFunction)time_get_ticks,METH_NOARGS,DOC_PYGAMETIMEGETTICKS},{"delay",time_delay,METH_VARARGS,DOC_PYGAMETIMEDELAY},{"wait",time_wait,METH_VARARGS,DOC_PYGAMETIMEWAIT},{"set_timer",time_set_timer,METH_VARARGS,DOC_PYGAMETIMESETTIMER},{"Clock",(PyCFunction)ClockInit,METH_NOARGS,DOC_PYGAMETIMECLOCK},{NULL,NULL,0,NULL}};#ifdef __SYMBIAN32__PYGAME_EXPORTvoidinitpygame_time(void)#elseMODINIT_DEFINE(time)#endif {PyObject*module;#if PY3staticstructPyModuleDef_module={PyModuleDef_HEAD_INIT,"time",DOC_PYGAMETIME,-1,_time_methods,NULL,NULL,NULL,NULL};#endif/* need to import base module, just so SDL is happy. Do this first so if the module is there is an error the module is not loaded. */import_pygame_base();if(PyErr_Occurred()){MODINIT_ERROR;}/* type preparation */if(PyType_Ready(&PyClock_Type)<0){MODINIT_ERROR;}/* create the module */#if PY3module=PyModule_Create(&_module);#elsemodule=Py_InitModule3(MODPREFIX"time",_time_methods,DOC_PYGAMETIME);#endifMODINIT_RETURN(module);}