diff options
Diffstat (limited to 'src/wrapper/WrapHelper.cpp')
-rw-r--r-- | src/wrapper/WrapHelper.cpp | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/src/wrapper/WrapHelper.cpp b/src/wrapper/WrapHelper.cpp new file mode 100644 index 0000000..258a094 --- /dev/null +++ b/src/wrapper/WrapHelper.cpp @@ -0,0 +1,428 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "WrapHelper.h" + +#include "../base/Logger.h" +#include "../base/Exception.h" +#include "../base/MathHelper.h" +#include "../base/ObjectCounter.h" + +#include "../player/PythonLogSink.h" +#include "../player/PublisherDefinitionRegistry.h" + +#include <boost/version.hpp> + +using namespace avg; +using namespace std; +using namespace boost::python; + +namespace Vec2Helper +{ + int len(const glm::vec2&) + { + return 2; + } + + float getX(const glm::vec2& pt) + { + return pt.x; + } + + float getY(const glm::vec2& pt) + { + return pt.y; + } + + void setX(glm::vec2& pt, float val) + { + pt.x = val; + } + + void setY(glm::vec2& pt, float val) + { + pt.y = val; + } + + void checkItemRange(int i) { + if (i != 0 && i != 1) { + throw std::out_of_range("Index out of range for Point2D. Must be 0 or 1."); + } + } + + float getItem(const glm::vec2& pt, int i) + { + checkItemRange(i); + if (i==0) { + return pt.x; + } else { + return pt.y; + } + } + + void setItem(glm::vec2& pt, int i, float val) + { + checkItemRange(i); + if (i==0) { + pt.x = val; + } else { + pt.y = val; + } + } + + string str(const glm::vec2& pt) + { + stringstream st; + st << "(" << pt.x << "," << pt.y << ")"; + return st.str(); + } + + string repr(const glm::vec2& pt) + { + stringstream st; + st << "avg.Point2D(" << pt.x << "," << pt.y << ")"; + return st.str(); + } + + long getHash(const glm::vec2& pt) + { + // Wild guess at what could constitute a good hash function. + // Will generate very bad hashes if most values are in a range < 0.1, + // but this is meant for pixel values anyway, right? ;-). + return long(pt.x*42+pt.y*23); + } + + glm::vec2 safeGetNormalized(const glm::vec2& pt) + { + if (pt.x==0 && pt.y==0) { + throw Exception(AVG_ERR_OUT_OF_RANGE, "Can't normalize (0,0)."); + } else { + float invNorm = 1/sqrt(pt.x*pt.x+pt.y*pt.y); + return glm::vec2(pt.x*invNorm, pt.y*invNorm); + } + } + + float getNorm(const glm::vec2& pt) + { + return glm::length(pt); + } + + float vecAngle(const glm::vec2& pt1, const glm::vec2& pt2) + { + float angle = fmod((atan2(pt1.y, pt1.x) - atan2(pt2.y, pt2.x)), float(2*M_PI)); + if (angle < 0) { + angle += 2*M_PI; + } + return angle; + } +} + +// The ConstVec2 stuff is there so that vec2 attributes behave sensibly. That is, +// node.pos.x = 30 causes an error instead of failing silently. +ConstVec2::ConstVec2() +{ +} + +ConstVec2::ConstVec2(const glm::vec2& other) +{ + x = other.x; + y = other.y; +} + +glm::vec2 ConstVec2::toVec2() const +{ + return glm::vec2(x,y); +} + +void checkEmptyArgs(const boost::python::tuple &args, int numArgs) +{ + if (boost::python::len(args) != numArgs) { + throw avg::Exception(AVG_ERR_INVALID_ARGS, + "Nodes must be constructed using named parameters. Positional parameters are not supported."); + } +} + +template<class VEC2> +struct Vec2_to_python_tuple +{ + static PyObject* convert (VEC2 v) + { + return boost::python::incref(boost::python::make_tuple(v.x, v.y).ptr()); + } +}; + +template<class VEC3> +struct Vec3_to_python_tuple +{ + static PyObject* convert (VEC3 v) + { + return boost::python::incref(boost::python::make_tuple(v.x, v.y, v.z).ptr()); + } +}; + +template<class VEC2, class ATTR> +struct vec2_from_python +{ + vec2_from_python() + { + boost::python::converter::registry::push_back( + &convertible, &construct, boost::python::type_id<VEC2>()); + } + + static void* convertible(PyObject* obj_ptr) + { + // Using PySequence_Check here causes infinite recursion. + if (!PyTuple_Check(obj_ptr) && !PyList_Check(obj_ptr)) { + return 0; + } + if (PySequence_Size(obj_ptr) != 2) { + return 0; + } + return obj_ptr; + } + + static void construct(PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + VEC2 pt; + PyObject * pEntry = PySequence_GetItem(obj_ptr, 0); + pt.x = (ATTR)PyFloat_AsDouble(pEntry); + Py_DECREF(pEntry); + pEntry = PySequence_GetItem(obj_ptr, 1); + pt.y = (ATTR)PyFloat_AsDouble(pEntry); + Py_DECREF(pEntry); + void* storage = ( + (boost::python::converter::rvalue_from_python_storage<VEC2>*)data) + ->storage.bytes; + new (storage) VEC2(pt); + data->convertible = storage; + } +}; + +template<class VEC3, class ATTR> +struct vec3_from_python +{ + vec3_from_python() + { + boost::python::converter::registry::push_back( + &convertible, &construct, boost::python::type_id<VEC3>()); + } + + static void* convertible(PyObject* obj_ptr) + { + if (!PySequence_Check(obj_ptr)) { + return 0; + } + if (PySequence_Size(obj_ptr) != 3) { + return 0; + } + return obj_ptr; + } + + static void construct(PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + VEC3 t; + PyObject * pEntry = PySequence_GetItem(obj_ptr, 0); + t.x = (ATTR)PyFloat_AsDouble(pEntry); + Py_DECREF(pEntry); + pEntry = PySequence_GetItem(obj_ptr, 1); + t.y = (ATTR)PyFloat_AsDouble(pEntry); + Py_DECREF(pEntry); + pEntry = PySequence_GetItem(obj_ptr, 2); + t.z = (ATTR)PyFloat_AsDouble(pEntry); + Py_DECREF(pEntry); + void* storage = ( + (boost::python::converter::rvalue_from_python_storage<VEC3>*) + data)->storage.bytes; + new (storage) VEC3(t); + data->convertible = storage; + } +}; + +struct UTF8String_to_unicode +{ + static PyObject *convert(const UTF8String & s) + { + const char * pStr = s.c_str(); + return PyUnicode_DecodeUTF8(pStr, strlen(pStr), "ignore"); + } +}; + +struct UTF8String_from_unicode +{ + UTF8String_from_unicode() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id<UTF8String>()); + } + + static void* convertible(PyObject* obj_ptr) + { + if (!PyUnicode_Check(obj_ptr)) return 0; + return obj_ptr; + } + + static void construct(PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + PyObject * pPyUTF8 = PyUnicode_AsUTF8String(obj_ptr); + char * psz = PyString_AsString(pPyUTF8); + void* storage = ( + (boost::python::converter::rvalue_from_python_storage<UTF8String>*)data) + ->storage.bytes; + new (storage) UTF8String(psz); + data->convertible = storage; + Py_DECREF(pPyUTF8); + } +}; + +struct UTF8String_from_string +{ + UTF8String_from_string() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id<UTF8String>()); + } + + static void* convertible(PyObject* obj_ptr) + { + if (!PyString_Check(obj_ptr)) return 0; + return obj_ptr; + } + + static void construct(PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + const char * psz = PyString_AsString(obj_ptr); + void* storage = ( + (boost::python::converter::rvalue_from_python_storage<UTF8String>*)data) + ->storage.bytes; + new (storage) UTF8String(psz); + data->convertible = storage; + } +}; + +void exportMessages(object& nodeClass, const string& sClassName) +{ + PublisherDefinitionPtr pPubDef = PublisherDefinitionRegistry::get() + ->getDefinition(sClassName); + const vector<MessageID>& messageIDs = pPubDef->getMessageIDs(); + for (unsigned i=0; i<messageIDs.size(); ++i) { + string sName = messageIDs[i].m_sName; + nodeClass.attr(sName.c_str()) = messageIDs[i]; + } +}; + +struct type_info_to_string{ + static PyObject* convert(const std::type_info& info) + { + boost::python::object result(ObjectCounter::get()->demangle(info.name())); + return boost::python::incref(result.ptr()); + } +}; + + +void export_base() +{ + // Exceptions + + translateException<exception>(PyExc_RuntimeError); + translateException<out_of_range>(PyExc_IndexError); + translateException<Exception>(PyExc_RuntimeError); + to_python_converter< exception, Exception_to_python_exception<exception> >(); + to_python_converter< Exception, Exception_to_python_exception<Exception> >(); + + // vec2 + to_python_converter<IntPoint, Vec2_to_python_tuple<IntPoint> >(); + vec2_from_python<IntPoint, int>(); + vec2_from_python<glm::vec2, float>(); + vec2_from_python<ConstVec2, float>(); + + // vector<vec2> + to_python_converter<vector<glm::vec2>, to_list<vector<glm::vec2> > >(); + from_python_sequence<vector<IntPoint>, variable_capacity_policy>(); + from_python_sequence<vector<glm::vec2>, variable_capacity_policy>(); + + // vec3 + to_python_converter<glm::ivec3, Vec3_to_python_tuple<glm::ivec3> >(); + to_python_converter<glm::vec3, Vec3_to_python_tuple<glm::vec3> >(); + vec3_from_python<glm::ivec3, int>(); + vec3_from_python<glm::vec3, float>(); + + // vector<vec3> + to_python_converter<vector<glm::ivec3>, to_list<vector<glm::ivec3> > >(); + to_python_converter<vector<glm::vec3>, to_list<vector<glm::vec3> > >(); + from_python_sequence<vector<glm::ivec3>, variable_capacity_policy>(); + from_python_sequence<vector<glm::vec3>, variable_capacity_policy>(); + + // string + to_python_converter<UTF8String, UTF8String_to_unicode>(); + UTF8String_from_unicode(); + UTF8String_from_string(); + + to_python_converter<vector<string>, to_list<vector<string> > >(); + from_python_sequence<vector<string>, variable_capacity_policy>(); + + from_python_sequence<vector<float>, variable_capacity_policy>(); + from_python_sequence<vector<int>, variable_capacity_policy>(); + + to_python_converter<std::type_info, type_info_to_string>(); + //Maps + to_python_converter<TypeMap, to_dict<TypeMap> >(); + to_python_converter<CatToSeverityMap, to_dict<CatToSeverityMap> >(); +} + +namespace { + std::map<PyObject *, LogSinkPtr> m_pyObjectMap; +} + +void addPythonLogger(PyObject * self, PyObject * pyLogger) +{ + Logger * logger = Logger::get(); + LogSinkPtr logSink(new PythonLogSink(pyLogger)); + logger->addLogSink(logSink); + m_pyObjectMap[pyLogger] = logSink; +} + +void removePythonLogger(PyObject * self, PyObject * pyLogger) +{ + Logger* logger = Logger::get(); + std::map<PyObject *, LogSinkPtr>::iterator it; + it = m_pyObjectMap.find(pyLogger); + if( it !=m_pyObjectMap.end() ){ + logger->removeLogSink(it->second); + m_pyObjectMap.erase(it); + } +} + +void pytrace(PyObject * self, const avg::category_t& category, const UTF8String& sMsg, + avg::severity_t severity) +{ + avgDeprecationWarning(string("1.8"), "logger.trace", + "any of the logging convenience functions"); + Logger::get()->trace(sMsg, category, severity); +} + |