From: <vo...@us...> - 2007-12-10 21:22:47
|
Revision: 439 http://opde.svn.sourceforge.net/opde/?rev=439&view=rev Author: volca Date: 2007-12-10 13:22:42 -0800 (Mon, 10 Dec 2007) Log Message: ----------- Initial prototype of binding code. Will be moved after it gets a bit more complete Added Paths: ----------- trunk/proto/python/ trunk/proto/python/CMakeLists.txt trunk/proto/python/ConfigServiceBinder.cpp trunk/proto/python/ConfigServiceBinder.h trunk/proto/python/ServiceBinder.cpp trunk/proto/python/ServiceBinder.h trunk/proto/python/bindings.cpp trunk/proto/python/bindings.h trunk/proto/python/test.cpp trunk/proto/python/test.h Added: trunk/proto/python/CMakeLists.txt =================================================================== --- trunk/proto/python/CMakeLists.txt (rev 0) +++ trunk/proto/python/CMakeLists.txt 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,38 @@ +# Nothing interesting now. Will compile the python module after finished + +INCLUDE( ${OPDE_SOURCE_DIR}/src/services/Services.cmake ) +INCLUDE( ${OPDE_SOURCE_DIR}/src/base/Base.cmake ) + +include_directories( + ${OGRE_INCLUDE_DIR} + ${OIS_INCLUDE_DIR} + ${OPDE_BINARY_DIR} + ${OPDE_BASE_INCLUDES} + ${OPDE_SERVICE_INCLUDES} + ${PYTHON_INCLUDE_PATH} +) + + +add_library(OpdePythonBindings + bindings.cpp + bindings.h + ServiceBinder.cpp + ServiceBinder.h + ConfigServiceBinder.cpp + ConfigServiceBinder.h +) + +add_executable(pytest test.cpp test.h) + +target_link_libraries(OpdePythonBindings + ${OGRE_LIBRARIES} + ${OPDE_BASE_LIBRARIES} + ${PYTHON_LIBRARIES} + ${OPDE_SERVICE_LIBRARIES} +) + +target_link_libraries(pytest + ${OPDE_BASE_LIBRARIES} + ${OPDE_SERVICE_LIBRARIES} + OpdePythonBindings +) Added: trunk/proto/python/ConfigServiceBinder.cpp =================================================================== --- trunk/proto/python/ConfigServiceBinder.cpp (rev 0) +++ trunk/proto/python/ConfigServiceBinder.cpp 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,163 @@ +#include "bindings.h" +#include "ConfigServiceBinder.h" + +namespace Opde { + + namespace Python { + + // -------------------- Config Service -------------------- + char* ConfigServiceBinder::msName = "ConfigService"; + + // ------------------------------------------ + PyTypeObject ConfigServiceBinder::msType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + msName, /* char *tp_name; */ + sizeof(ConfigServiceBinder::Object), /* int tp_basicsize; */ + 0, /* int tp_itemsize; /* not used much */ + ConfigServiceBinder::dealloc, /* destructor tp_dealloc; */ + 0, /* printfunc tp_print; */ + ConfigServiceBinder::getattr, /* getattrfunc tp_getattr; /* __getattr__ */ + 0, /* setattrfunc tp_setattr; /* __setattr__ */ + 0, /* cmpfunc tp_compare; /* __cmp__ */ + 0, /* reprfunc tp_repr; /* __repr__ */ + 0, /* PyNumberMethods *tp_as_number; */ + 0, /* PySequenceMethods *tp_as_sequence; */ + 0, /* PyMappingMethods *tp_as_mapping; */ + 0, /* hashfunc tp_hash; /* __hash__ */ + 0, /* ternaryfunc tp_call; /* __call__ */ + 0, /* reprfunc tp_str; /* __str__ */ + 0, /* getattrofunc tp_getattro; */ + 0, /* setattrofunc tp_setattro; */ + 0, /* PyBufferProcs *tp_as_buffer; */ + 0, /* long tp_flags; */ + 0, /* char *tp_doc; */ + 0, /* traverseproc tp_traverse; */ + 0, /* inquiry tp_clear; */ + 0, /* richcmpfunc tp_richcompare; */ + 0, /* long tp_weaklistoffset; */ + 0, /* getiterfunc tp_iter; */ + 0, /* iternextfunc tp_iternext; */ + msMethods, /* struct PyMethodDef *tp_methods; */ + 0, /* struct memberlist *tp_members; */ + 0, /* struct getsetlist *tp_getset; */ + }; + + // ------------------------------------------ + PyMethodDef ConfigServiceBinder::msMethods[] = { + {"setParam", setParam, METH_VARARGS}, + {"getParam", getParam, METH_VARARGS}, + {"hasParam", hasParam, METH_VARARGS}, + {"loadParams", loadParams, METH_VARARGS}, + {NULL, NULL}, + }; + + // ------------------------------------------ + void ConfigServiceBinder::dealloc(PyObject* self) { + // cast the object to ConfigServiceBinder::Object + Object* o = python_cast<Object*>(self, &msType); + + // Decreases the shared_ptr counter + o->mInstance.setNull(); + } + + // ------------------------------------------ + PyObject* ConfigServiceBinder::getattr(PyObject *self, char *name) { + return Py_FindMethod(msMethods, self, name); + } + + // ------------------------------------------ + PyObject* ConfigServiceBinder::create() { + Object* object; + + object = PyObject_New(Object, &msType); + + // At this point, the shared_ptr instance in the object is invalid (I.E. Allocated, but not initialized). + // If we try to assign into it, we'll segfault. Because of that, we have to erase the member data first + if (object != NULL) { + // Here, tidy! + object->mInstance.forceNull(); + + object->mInstance = ServiceManager::getSingleton().getService(msName).as<ConfigService>(); + } + + return (PyObject *)object; + } + + // ------------------------------------------ + PyObject* ConfigServiceBinder::setParam(PyObject* self, PyObject* args) { + PyObject *result = NULL; + Object* o = python_cast<Object*>(self, &msType); + const char* name; + const char* value; + + if (PyArg_ParseTuple(args, "ss", &name, &value)) { + o->mInstance->setParam(name, value); + result = Py_None; + Py_INCREF(result); + } + + return result; + } + + // ------------------------------------------ + PyObject* ConfigServiceBinder::getParam(PyObject* self, PyObject* args) { + PyObject *result = Py_None; + Object* o = python_cast<Object*>(self, &msType); + const char* name; + + if (PyArg_ParseTuple(args, "s", &name)) { + DVariant rv = o->mInstance->getParam(name); + + return DVariantToPyObject(rv); + } else { + // Invalid parameters + return NULL; + } + } + + // ------------------------------------------ + PyObject* ConfigServiceBinder::hasParam(PyObject* self, PyObject* args) { + PyObject *result = Py_None; + Object* o = python_cast<Object*>(self, &msType); + const char* name; + + if (PyArg_ParseTuple(args, "s", &name)) { + bool has = o->mInstance->hasParam(name); + + PyObject* ret = has ? Py_True : Py_False; + Py_INCREF(ret); + return ret; + } else { + // Invalid parameters + return NULL; + } + } + + // ------------------------------------------ + PyObject* ConfigServiceBinder::loadParams(PyObject* self, PyObject* args) { + PyObject *result = NULL; + Object* o = python_cast<Object*>(self, &msType); + const char* fname; + + if (PyArg_ParseTuple(args, "ss", &fname)) { + o->mInstance->loadParams(fname); + result = Py_None; + Py_INCREF(result); + } + + return result; + } + + PyMethodDef sOpdeMethods[] = { + {NULL, NULL}, + }; + + // ------------------------------------------ + void ConfigServiceBinder::init() { + + } + } + +} // namespace Opde + Added: trunk/proto/python/ConfigServiceBinder.h =================================================================== --- trunk/proto/python/ConfigServiceBinder.h (rev 0) +++ trunk/proto/python/ConfigServiceBinder.h 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,45 @@ +#ifndef __PYCONFIGSERVICE_H +#define __PYCONFIGSERVICE_H + +#include "ConfigService.h" + +namespace Opde { + + namespace Python { + + /// Config service python binder + class ConfigServiceBinder { + public: + static void init(); + + // --- Python type releted methods --- + + static void dealloc(PyObject *self); + static PyObject* getattr(PyObject *self, char *name); + + static PyObject* create(); + + // --- Methods --- + + static PyObject* setParam(PyObject* self, PyObject* args); + static PyObject* getParam(PyObject* self, PyObject* args); + static PyObject* hasParam(PyObject* self, PyObject* args); + static PyObject* loadParams(PyObject* self, PyObject* args); + + protected: + /// Python object instance definition + typedef ObjectBase<ConfigServicePtr> Object; + + /// Static type definition for ConfigService + static PyTypeObject msType; + + /// Name of the python type + static char* msName; + + /// Method list + static PyMethodDef msMethods[]; + }; + } +} + +#endif Added: trunk/proto/python/ServiceBinder.cpp =================================================================== --- trunk/proto/python/ServiceBinder.cpp (rev 0) +++ trunk/proto/python/ServiceBinder.cpp 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * This file is part of openDarkEngine project + * Copyright (C) 2005-2006 openDarkEngine team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * $Id:$ + * + *****************************************************************************/ + +#include "ServiceBinder.h" +#include "ConfigServiceBinder.h" + +namespace Opde { + namespace Python { + + // ---------------------- class Services -------------------- + char* ServiceBinder::msName = "Opde.Services"; + + PyMethodDef ServiceBinder::msMethods[] = { + {"ConfigService", getConfigService, METH_NOARGS}, + {NULL, NULL}, + }; + + PyObject* ServiceBinder::getConfigService(PyObject* self, PyObject* args) { + return ConfigServiceBinder::create(); + } + + PyObject* ServiceBinder::init(PyObject* container) { + PyObject* module = Py_InitModule(msName, msMethods); + + ConfigServiceBinder::init(); + + assert(module); + + // Register itself as a member of the container we got + PyObject *dir = PyModule_GetDict(container); + PyDict_SetItemString(dir, "Services", module); + + return module; + } + + } +} Added: trunk/proto/python/ServiceBinder.h =================================================================== --- trunk/proto/python/ServiceBinder.h (rev 0) +++ trunk/proto/python/ServiceBinder.h 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * This file is part of openDarkEngine project + * Copyright (C) 2005-2006 openDarkEngine team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * $Id:$ + * + *****************************************************************************/ + +#ifndef __SERVICES_H +#define __SERVICES_H + +#include "bindings.h" + +namespace Opde { + namespace Python { + + /** A Service interface for python. Manages a module "Opde.services". + * Exposes getters for services. Each getter is named exactly the same as the service itself. + * @note When creating a new service, remember to expose it here + */ + class ServiceBinder { + public: + static PyObject* init(PyObject* container); + + static PyObject* getConfigService(PyObject* self, PyObject* args); + + protected: + static PyMethodDef msMethods[]; + static char* msName; + }; + } +} + + +#endif Added: trunk/proto/python/bindings.cpp =================================================================== --- trunk/proto/python/bindings.cpp (rev 0) +++ trunk/proto/python/bindings.cpp 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,97 @@ +/****************************************************************************** + * + * This file is part of openDarkEngine project + * Copyright (C) 2005-2006 openDarkEngine team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * $Id:$ + * + *****************************************************************************/ + +#include "bindings.h" +#include "ServiceBinder.h" + +namespace Opde { + namespace Python { + + PyObject* DVariantToPyObject(const DVariant& inst) { + // Do a conversion to python object from variant + // Look for the type + switch (inst.type()) { + case DVariant::DV_INVALID: + Py_INCREF(Py_None); + return Py_None; + + case DVariant::DV_BOOL: { + PyObject* ret = inst.toBool() ? Py_True : Py_False; + Py_INCREF(ret); + return ret; + } + + case DVariant::DV_FLOAT: + return PyFloat_FromDouble(inst.toFloat()); + + case DVariant::DV_INT: + return PyInt_FromLong(inst.toInt()); + + case DVariant::DV_UINT: + return PyInt_FromLong(inst.toUInt()); + + case DVariant::DV_STRING: + return PyString_FromString(inst.toString().c_str()); + + case DVariant::DV_VECTOR: { + // Build a touple + const Ogre::Vector3& v = inst.toVector(); + return Py_BuildValue("[fff]", v.x, v.y, v.z); + } + } + } + + DVariant PyObjectToDVariant(PyObject* obj) { + // Do a conversion from python object to DVariant instance + // Look for the type of the python object + + } + + } // namespace Python + + PyMethodDef sOpdeMethods[] = { + {NULL, NULL}, + }; + + void PythonLanguage::init() { + Py_Initialize(); + + // Create an Opde module + PyObject* module = Py_InitModule("Opde", sOpdeMethods); + + // Call all the binders here. The result is initialized Python VM + PyObject *servicemod = Python::ServiceBinder::init(module); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + + } + + void PythonLanguage::term() { + Py_Finalize(); + } + +} // namespace Opde Added: trunk/proto/python/bindings.h =================================================================== --- trunk/proto/python/bindings.h (rev 0) +++ trunk/proto/python/bindings.h 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,66 @@ +/****************************************************************************** + * + * This file is part of openDarkEngine project + * Copyright (C) 2005-2006 openDarkEngine team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * $Id:$ + * + *****************************************************************************/ + +#ifndef __BINDINGS_H +#define __BINDINGS_H + +#include "DVariant.h" + +#include <Python.h> +#include <OgreVector3.h> + +namespace Opde { + namespace Python { + // Global utilities - object conversion and such + PyObject* DVariantToPyObject(const DVariant& inst); + DVariant PyObjectToDVariant(PyObject* obj); + + /// Template definition of a Python instance holding a single object + template<typename T> struct ObjectBase { + PyObject_HEAD + T mInstance; + }; + + /// helper function to get type from Object + template<typename T> T python_cast(PyObject* obj, PyTypeObject* type) { + assert(obj->ob_type == type); + + return reinterpret_cast< T >(obj); + } + + }; + + /** Central class for python bindings. Call PythonLanguage::Init() to prepare python environment */ + class PythonLanguage { + public: + /** Initializes python lang and all the bindings */ + static void init(); + + /** Finalizes python lang */ + static void term(); + }; +} + + +#endif Added: trunk/proto/python/test.cpp =================================================================== --- trunk/proto/python/test.cpp (rev 0) +++ trunk/proto/python/test.cpp 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,51 @@ +// TEMPORARY CODE FOR FUNCTIONALITY TESTING, will be ERASED! +#include "test.h" +#include <iostream> +#include "bindings.h" + +#include "logger.h" +#include "stdlog.h" +#include "OpdeServiceManager.h" +#include "ConfigService.h" + +using namespace Opde; + + +int main(void) { + Logger* logger = new Logger(); + + LogListener* stdLog = new StdLog(); + + logger->registerLogListener(stdLog); + + ServiceManager* serviceMgr = new ServiceManager(); + PythonLanguage::init(); + + // New service factory for Config service + new ConfigServiceFactory(); + + // Run a python string to test the setup + ConfigServicePtr configService = ServiceManager::getSingleton().getService("ConfigService").as<ConfigService>(); + + ServiceManager::getSingleton().bootstrapFinished(); + + // load a config file + configService->setParam("test", "Hello World!"); + + // To tidy mem... + configService.setNull(); + + PyRun_SimpleString("from Opde import *\n" + "print \"Loaded Opde module! Yay!\"\n" + "s = Services.ConfigService()\n" + "print \"Got config service! Yay Yay!\"\n" + "print \"Do we have a parameter test?: '\" + str(s.hasParam(\"test\")) + \"'\";\n" + "print \"Python read config parameter: '\" + s.getParam(\"test\") + \"'\";\n" + ); + + PythonLanguage::term(); + + delete serviceMgr; + delete logger; + +} Added: trunk/proto/python/test.h =================================================================== --- trunk/proto/python/test.h (rev 0) +++ trunk/proto/python/test.h 2007-12-10 21:22:42 UTC (rev 439) @@ -0,0 +1,6 @@ +#ifndef __test_h +#define __test_h + + + +#endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |