/*
    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
*/

	/** This header file includes all the definitions for the
	 ** base pygame extensions. This header only requires
	 ** SDL and Python includes. The reason for functions
	 ** prototyped with #define's is to allow for maximum
	 ** python portability. It also uses python as the
	 ** runtime linker, which allows for late binding. For more
	 ** information on this style of development, read the Python
	 ** docs on this subject.
	 ** http://www.python.org/doc/current/ext/using-cobjects.html
	 **
	 ** If using this to build your own derived extensions,
	 ** you'll see that the functions available here are mainly
	 ** used to help convert between python objects and SDL objects.
	 ** Since this library doesn't add a lot of functionality to
	 ** the SDL libarary, it doesn't need to offer a lot either.
	 **
	 ** When initializing your extension module, you must manually
	 ** import the modules you want to use. (this is the part about
	 ** using python as the runtime linker). Each module has its
	 ** own import_xxx() routine. You need to perform this import
	 ** after you have initialized your own module, and before
	 ** you call any routines from that module. Since every module
	 ** in pygame does this, there are plenty of examples.
	 **
	 ** The base module does include some useful conversion routines
	 ** that you are free to use in your own extension.
	 **
	 ** When making changes, it is very important to keep the
	 ** FIRSTSLOT and NUMSLOT constants up to date for each
	 ** section. Also be sure not to overlap any of the slots.
	 ** When you do make a mistake with this, it will result
	 ** is a dereferenced NULL pointer that is easier to diagnose
	 ** than it could be :]
	 **/
#include <Python.h>

#ifdef MS_WIN32 /*Python gives us MS_WIN32, SDL needs just WIN32*/
#define WIN32
#endif

#include <SDL.h>



/* macros used throughout the source */
#define RAISE(x,y) (PyErr_SetString((x), (y)), (PyObject*)NULL)
#define RETURN_NONE return (Py_INCREF(Py_None), Py_None);
#define PyType_Init(x) (((x).ob_type) = &PyType_Type)
#define PYGAMEAPI_LOCAL_ENTRY "_PYGAME_C_API"
#ifndef min
#define min(a,b) ((a)<=(b)?(a):(b))
#endif
#ifndef max
#define max(a,b) ((a)>=(b)?(a):(b))
#endif

/* test sdl initializations */
#define VIDEO_INIT_CHECK() \
	if(!SDL_WasInit(SDL_INIT_VIDEO)) \
		return RAISE(PyExc_SDLError, "video system not initialized")
#define CDROM_INIT_CHECK() \
	if(!SDL_WasInit(SDL_INIT_CDROM)) \
		return RAISE(PyExc_SDLError, "cdrom system not initialized")
#define JOYSTICK_INIT_CHECK() \
	if(!SDL_WasInit(SDL_INIT_JOYSTICK)) \
		return RAISE(PyExc_SDLError, "joystick system not initialized")




/* BASE */
#define PYGAMEAPI_BASE_FIRSTSLOT 0
#define PYGAMEAPI_BASE_NUMSLOTS 13
#ifndef PYGAMEAPI_BASE_INTERNAL
#define PyExc_SDLError ((PyObject*)PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT])
#define PyGame_RegisterQuit \
			(*(void(*)(void(*)(void)))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 1])
#define IntFromObj \
			(*(int(*)(PyObject*, int*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 2])
#define IntFromObjIndex \
			(*(int(*)(PyObject*, int, int*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 3])
#define TwoIntsFromObj \
			(*(int(*)(PyObject*, int*, int*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 4])
#define FloatFromObj \
			(*(int(*)(PyObject*, float*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 5])
#define FloatFromObjIndex \
			(*(float(*)(PyObject*, int, float*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 6])
#define TwoFloatsFromObj \
			(*(int(*)(PyObject*, float*, float*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 7])
#define UintFromObj \
			(*(int(*)(PyObject*, Uint32*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 8])
#define UintFromObjIndex \
			(*(int(*)(PyObject*, int, Uint32*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 9])
#define PyGame_Video_AutoQuit \
			(*(void(*)(void))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 10])
#define PyGame_Video_AutoInit \
			(*(int(*)(void))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 11])
#define RGBAFromObj \
			(*(int(*)(PyObject*, Uint8*))PyGAME_C_API[PYGAMEAPI_BASE_FIRSTSLOT + 12])
#define import_pygame_base() { \
	PyObject *module = PyImport_ImportModule("pygame.base"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_BASE_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_BASE_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif



/* RECT */
#define PYGAMEAPI_RECT_FIRSTSLOT (PYGAMEAPI_BASE_FIRSTSLOT + PYGAMEAPI_BASE_NUMSLOTS)
#define PYGAMEAPI_RECT_NUMSLOTS 4
typedef struct {
	int x, y;
	int w, h;
}GAME_Rect;
typedef struct {
  PyObject_HEAD
  GAME_Rect r;
  PyObject *weakreflist;
} PyRectObject;
#define PyRect_AsRect(x) (((PyRectObject*)x)->r)
#ifndef PYGAMEAPI_RECT_INTERNAL
#define PyRect_Check(x) ((x)->ob_type == (PyTypeObject*)PyGAME_C_API[PYGAMEAPI_RECT_FIRSTSLOT + 0])
#define PyRect_Type (*(PyTypeObject*)PyGAME_C_API[PYGAMEAPI_RECT_FIRSTSLOT + 0])
#define PyRect_New (*(PyObject*(*)(SDL_Rect*))PyGAME_C_API[PYGAMEAPI_RECT_FIRSTSLOT + 1])
#define PyRect_New4 \
			(*(PyObject*(*)(int,int,int,int))PyGAME_C_API[PYGAMEAPI_RECT_FIRSTSLOT + 2])
#define GameRect_FromObject \
			(*(GAME_Rect*(*)(PyObject*, GAME_Rect*))PyGAME_C_API[PYGAMEAPI_RECT_FIRSTSLOT + 3])
#define import_pygame_rect() { \
	PyObject *module = PyImport_ImportModule("pygame.rect"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_RECT_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_RECT_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif




/* CDROM */
#define PYGAMEAPI_CDROM_FIRSTSLOT (PYGAMEAPI_RECT_FIRSTSLOT + PYGAMEAPI_RECT_NUMSLOTS)
#define PYGAMEAPI_CDROM_NUMSLOTS 2
typedef struct {
	PyObject_HEAD
	int id;
} PyCDObject;
#define PyCD_AsID(x) (((PyCDObject*)x)->id)
#ifndef PYGAMEAPI_CDROM_INTERNAL
#define PyCD_Check(x) ((x)->ob_type == (PyTypeObject*)PyGAME_C_API[PYGAMEAPI_CDROM_FIRSTSLOT + 0])
#define PyCD_Type (*(PyTypeObject*)PyGAME_C_API[PYGAMEAPI_CDROM_FIRSTSLOT + 0])
#define PyCD_New (*(PyObject*(*)(int))PyGAME_C_API[PYGAMEAPI_CDROM_FIRSTSLOT + 1])
#define import_pygame_cd() { \
	PyObject *module = PyImport_ImportModule("pygame.cdrom"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_CDROM_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_CDROM_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif


/* JOYSTICK */
#define PYGAMEAPI_JOYSTICK_FIRSTSLOT (PYGAMEAPI_CDROM_FIRSTSLOT + PYGAMEAPI_CDROM_NUMSLOTS)
#define PYGAMEAPI_JOYSTICK_NUMSLOTS 2
typedef struct {
	PyObject_HEAD
	int id;
} PyJoystickObject;
#define PyJoystick_AsID(x) (((PyJoystickObject*)x)->id)
#ifndef PYGAMEAPI_JOYSTICK_INTERNAL
#define PyJoystick_Check(x) ((x)->ob_type == (PyTypeObject*)PyGAME_C_API[PYGAMEAPI_JOYSTICK_FIRSTSLOT + 0])
#define PyJoystick_Type (*(PyTypeObject*)PyGAME_C_API[PYGAMEAPI_JOYSTICK_FIRSTSLOT + 0])
#define PyJoystick_New (*(PyObject*(*)(int))PyGAME_C_API[PYGAMEAPI_JOYSTICK_FIRSTSLOT + 1])
#define import_pygame_joystick() { \
	PyObject *module = PyImport_ImportModule("pygame.joystick"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_JOYSTICK_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_JOYSTICK_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif



/* DISPLAY */
#define PYGAMEAPI_DISPLAY_FIRSTSLOT (PYGAMEAPI_JOYSTICK_FIRSTSLOT + PYGAMEAPI_JOYSTICK_NUMSLOTS)
#define PYGAMEAPI_DISPLAY_NUMSLOTS 2
typedef struct {
	PyObject_HEAD
	SDL_VideoInfo info;
} PyVidInfoObject;
#define PyVidInfo_AsVidInfo(x) (((PyVidInfoObject*)x)->info)
#ifndef PYGAMEAPI_DISPLAY_INTERNAL
#define PyVidInfo_Check(x) ((x)->ob_type == (PyTypeObject*)PyGAME_C_API[PYGAMEAPI_DISPLAY_FIRSTSLOT + 0])
#define PyVidInfo_Type (*(PyTypeObject*)PyGAME_C_API[PYGAMEAPI_SURFACE_FIRSTSLOT + 0])
#define PyVidInfo_New (*(PyObject*(*)(SDL_VideoInfo*))PyGAME_C_API[PYGAMEAPI_DISPLAY_FIRSTSLOT + 1])
#define import_pygame_display() { \
	PyObject *module = PyImport_ImportModule("pygame.display"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_DISPLAY_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_DISPLAY_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif



/* SURFACE */
#define PYGAMEAPI_SURFACE_FIRSTSLOT (PYGAMEAPI_DISPLAY_FIRSTSLOT + PYGAMEAPI_DISPLAY_NUMSLOTS)
#define PYGAMEAPI_SURFACE_NUMSLOTS 3
typedef struct {
	PyObject_HEAD
	SDL_Surface* surf;
	struct SubSurface_Data* subsurface;  /*ptr to subsurface data (if a subsurface)*/
        PyObject* weakreflist;
        PyObject *dependency;
} PySurfaceObject;
#define PySurface_AsSurface(x) (((PySurfaceObject*)x)->surf)
#ifndef PYGAMEAPI_SURFACE_INTERNAL
#define PySurface_Check(x) ((x)->ob_type == (PyTypeObject*)PyGAME_C_API[PYGAMEAPI_SURFACE_FIRSTSLOT + 0])
#define PySurface_Type (*(PyTypeObject*)PyGAME_C_API[PYGAMEAPI_SURFACE_FIRSTSLOT + 0])
#define PySurface_New (*(PyObject*(*)(SDL_Surface*))PyGAME_C_API[PYGAMEAPI_SURFACE_FIRSTSLOT + 1])
#define PySurface_Blit (*(int(*)(PyObject*,PyObject*,SDL_Rect*,SDL_Rect*))PyGAME_C_API[PYGAMEAPI_SURFACE_FIRSTSLOT + 2])
#define import_pygame_surface() { \
	PyObject *module = PyImport_ImportModule("pygame.surface"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_SURFACE_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_SURFACE_FIRSTSLOT] = localptr[i]; \
	} Py_DECREF(module); } \
	module = PyImport_ImportModule("pygame.surflock"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_SURFLOCK_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_SURFLOCK_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif



/* SURFLOCK */    /*auto import/init by surface*/
#define PYGAMEAPI_SURFLOCK_FIRSTSLOT (PYGAMEAPI_SURFACE_FIRSTSLOT + PYGAMEAPI_SURFACE_NUMSLOTS)
#define PYGAMEAPI_SURFLOCK_NUMSLOTS 5
struct SubSurface_Data
{
	PyObject* owner;
	int pixeloffset;
	int offsetx, offsety;
};
#ifndef PYGAMEAPI_SURFLOCK_INTERNAL
#define PySurface_Prep(x) if(((PySurfaceObject*)x)->subsurface)(*(*(void(*)(PyObject*))PyGAME_C_API[PYGAMEAPI_SURFLOCK_FIRSTSLOT + 0]))(x)
#define PySurface_Unprep(x) if(((PySurfaceObject*)x)->subsurface)(*(*(void(*)(PyObject*))PyGAME_C_API[PYGAMEAPI_SURFLOCK_FIRSTSLOT + 1]))(x)
#define PySurface_Lock (*(int(*)(PyObject*))PyGAME_C_API[PYGAMEAPI_SURFLOCK_FIRSTSLOT + 2])
#define PySurface_Unlock (*(int(*)(PyObject*))PyGAME_C_API[PYGAMEAPI_SURFLOCK_FIRSTSLOT + 3])
#define PySurface_LockLifetime (*(PyObject*(*)(PyObject*))PyGAME_C_API[PYGAMEAPI_SURFLOCK_FIRSTSLOT + 4])
#endif



/* EVENT */
#define PYGAMEAPI_EVENT_FIRSTSLOT (PYGAMEAPI_SURFLOCK_FIRSTSLOT + PYGAMEAPI_SURFLOCK_NUMSLOTS)
#define PYGAMEAPI_EVENT_NUMSLOTS 4
typedef struct {
	PyObject_HEAD
	int type;
	PyObject* dict;
} PyEventObject;
#ifndef PYGAMEAPI_EVENT_INTERNAL
#define PyEvent_Check(x) ((x)->ob_type == (PyTypeObject*)PyGAME_C_API[PYGAMEAPI_EVENT_FIRSTSLOT + 0])
#define PyEvent_Type (*(PyTypeObject*)PyGAME_C_API[PYGAMEAPI_EVENT_FIRSTSLOT + 0])
#define PyEvent_New (*(PyObject*(*)(SDL_Event*))PyGAME_C_API[PYGAMEAPI_EVENT_FIRSTSLOT + 1])
#define PyEvent_New2 (*(PyObject*(*)(int, PyObject*))PyGAME_C_API[PYGAMEAPI_EVENT_FIRSTSLOT + 2])
#define PyEvent_FillUserEvent (*(int (*)(PyEventObject*, SDL_Event*))PyGAME_C_API[PYGAMEAPI_EVENT_FIRSTSLOT + 3])
#define import_pygame_event() { \
	PyObject *module = PyImport_ImportModule("pygame.event"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_EVENT_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_EVENT_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif


/* RWOBJECT */
/*the rwobject are only needed for C side work, not accessable from python*/
#define PYGAMEAPI_RWOBJECT_FIRSTSLOT (PYGAMEAPI_EVENT_FIRSTSLOT + PYGAMEAPI_EVENT_NUMSLOTS)
#define PYGAMEAPI_RWOBJECT_NUMSLOTS 4
#ifndef PYGAMEAPI_RWOBJECT_INTERNAL
#define RWopsFromPython (*(SDL_RWops*(*)(PyObject*))PyGAME_C_API[PYGAMEAPI_RWOBJECT_FIRSTSLOT + 0])
#define RWopsCheckPython (*(int(*)(SDL_RWops*))PyGAME_C_API[PYGAMEAPI_RWOBJECT_FIRSTSLOT + 1])
#define RWopsFromPythonThreaded (*(SDL_RWops*(*)(PyObject*))PyGAME_C_API[PYGAMEAPI_RWOBJECT_FIRSTSLOT + 2])
#define RWopsCheckPythonThreaded (*(int(*)(SDL_RWops*))PyGAME_C_API[PYGAMEAPI_RWOBJECT_FIRSTSLOT + 3])
#define import_pygame_rwobject() { \
	PyObject *module = PyImport_ImportModule("pygame.rwobject"); \
	if (module != NULL) { \
		PyObject *dict = PyModule_GetDict(module); \
		PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); \
		if(PyCObject_Check(c_api)) {\
			int i; void** localptr = (void**)PyCObject_AsVoidPtr(c_api); \
			for(i = 0; i < PYGAMEAPI_RWOBJECT_NUMSLOTS; ++i) \
				PyGAME_C_API[i + PYGAMEAPI_RWOBJECT_FIRSTSLOT] = localptr[i]; \
} Py_DECREF(module); } }
#endif




#ifndef NO_PYGAME_C_API
#define PYGAMEAPI_TOTALSLOTS (PYGAMEAPI_RWOBJECT_FIRSTSLOT + PYGAMEAPI_RWOBJECT_NUMSLOTS)
static void* PyGAME_C_API[PYGAMEAPI_TOTALSLOTS] = {NULL};
#endif


/*last platform compiler stuff*/
#if defined(macintosh) && defined(__MWERKS__)
#define PYGAME_EXPORT __declspec(export)
#else
#define PYGAME_EXPORT
#endif

