From 1b93b8fbb309ece001579f25c56f9eb165a64379 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 9 Mar 2014 01:05:34 +0000 Subject: [PATCH] Add methods to efficiently access PfmFile data from Python --- makepanda/makepanda.py | 2 + panda/src/pnmimage/Sources.pp | 2 + panda/src/pnmimage/pfmFile.h | 5 +- panda/src/pnmimage/pfmFile_ext.cxx | 132 +++++++++++++++++++++++++++++ panda/src/pnmimage/pfmFile_ext.h | 44 ++++++++++ 5 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 panda/src/pnmimage/pfmFile_ext.cxx create mode 100644 panda/src/pnmimage/pfmFile_ext.h diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index b9bf4ee274..5f15299514 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3116,6 +3116,7 @@ if (not RUNTIME): TargetAdd('libp3pnmimage.in', opts=OPTS, input=IGATEFILES) TargetAdd('libp3pnmimage.in', opts=['IMOD:core', 'ILIB:libp3pnmimage', 'SRCDIR:panda/src/pnmimage']) TargetAdd('libp3pnmimage_igate.obj', input='libp3pnmimage.in', opts=["DEPENDENCYONLY"]) + TargetAdd('p3pnmimage_pfmFile_ext.obj', opts=OPTS, input='pfmFile_ext.cxx') # # DIRECTORY: panda/src/nativenet/ @@ -3540,6 +3541,7 @@ if (not RUNTIME): TargetAdd('libpanda.dll', input='libp3dtool.dll') TargetAdd('libpanda.dll', input='p3putil_typedWritable_ext.obj') + TargetAdd('libpanda.dll', input='p3pnmimage_pfmFile_ext.obj') TargetAdd('libpanda.dll', input='p3gobj_geomVertexArrayData_ext.obj') TargetAdd('libpanda.dll', input='p3pgraph_nodePath_ext.obj') TargetAdd('libpanda.dll', input='p3pgraph_nodePathCollection_ext.obj') diff --git a/panda/src/pnmimage/Sources.pp b/panda/src/pnmimage/Sources.pp index 76f67ed774..8ab8efb55b 100644 --- a/panda/src/pnmimage/Sources.pp +++ b/panda/src/pnmimage/Sources.pp @@ -12,6 +12,7 @@ #define SOURCES \ config_pnmimage.h \ pfmFile.I pfmFile.h \ + pfmFile_ext.cxx pfmFile_ext.h \ pnmbitio.h \ pnmBrush.h pnmBrush.I \ pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \ @@ -36,6 +37,7 @@ #define INSTALL_HEADERS \ config_pnmimage.h \ pfmFile.I pfmFile.h \ + pfmFile_ext.cxx pfmFile_ext.h \ pnmBrush.h pnmBrush.I \ pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \ pnmImage.h pnmImageHeader.I pnmImageHeader.h \ diff --git a/panda/src/pnmimage/pfmFile.h b/panda/src/pnmimage/pfmFile.h index 9a3cd444c4..1a212fbfb1 100644 --- a/panda/src/pnmimage/pfmFile.h +++ b/panda/src/pnmimage/pfmFile.h @@ -95,7 +95,7 @@ PUBLISHED: BLOCKING bool calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const; BLOCKING INLINE bool calc_autocrop(LVecBase4f &range) const; BLOCKING INLINE bool calc_autocrop(LVecBase4d &range) const; - + bool is_row_empty(int y, int x_begin, int x_end) const; bool is_column_empty(int x, int y_begin, int y_end) const; @@ -140,6 +140,9 @@ PUBLISHED: void output(ostream &out) const; + EXTENSION(PyObject *get_points() const); + EXTENSION(int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const); + public: INLINE const vector_float &get_table() const; INLINE void swap_table(vector_float &table); diff --git a/panda/src/pnmimage/pfmFile_ext.cxx b/panda/src/pnmimage/pfmFile_ext.cxx new file mode 100644 index 0000000000..c28ed79b57 --- /dev/null +++ b/panda/src/pnmimage/pfmFile_ext.cxx @@ -0,0 +1,132 @@ +// Filename: pfmFile_ext.I +// Created by: rdb (26Feb14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "pfmFile_ext.h" + +#ifdef HAVE_PYTHON + +#ifndef CPPPARSER +IMPORT_THIS struct Dtool_PyTypedObject Dtool_LPoint2f; +IMPORT_THIS struct Dtool_PyTypedObject Dtool_LPoint3f; +IMPORT_THIS struct Dtool_PyTypedObject Dtool_LPoint4f; +#endif + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::get_points +// Access: Published +// Description: Returns a list of all of the points. +//////////////////////////////////////////////////////////////////// +PyObject *Extension:: +get_points() const { + int num_points = _this->get_x_size() * _this->get_y_size(); + PyObject *list = PyList_New(num_points); + const vector_float &table = _this->get_table(); + + switch (_this->get_num_channels()) { + case 1: + for (int i = 0; i < num_points; ++i) { + PyList_SET_ITEM(list, i, PyFloat_FromDouble(table[i])); + } + break; + + case 2: + for (int i = 0; i < num_points; ++i) { + LPoint2f *point = (LPoint2f *) &(table[i * 2]); + PyObject *item = DTool_CreatePyInstance((void *)point, Dtool_LPoint2f, false, true); + PyList_SET_ITEM(list, i, item); + } + break; + + case 3: + for (int i = 0; i < num_points; ++i) { + LPoint3f *point = (LPoint3f *) &(table[i * 3]); + PyObject *item = DTool_CreatePyInstance((void *)point, Dtool_LPoint3f, false, true); + PyList_SET_ITEM(list, i, item); + } + break; + + case 4: + for (int i = 0; i < num_points; ++i) { + LPoint4f *point = (LPoint4f *) &(table[i * 4]); + PyObject *item = DTool_CreatePyInstance((void *)point, Dtool_LPoint4f, false, true); + PyList_SET_ITEM(list, i, item); + } + break; + + default: + Py_DECREF(list); + Py_INCREF(Py_None); + return Py_None; + } + + return list; +} + +#if PY_VERSION_HEX >= 0x02060000 +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::__getbuffer__ +// Access: Published +// Description: This is a very low-level function that returns a +// read-only multiview into the internal table of +// floating-point numbers. Use this method at your own +// risk. +//////////////////////////////////////////////////////////////////// +int Extension:: +__getbuffer__(PyObject *self, Py_buffer *view, int flags) const { + + if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { + PyErr_SetString(PyExc_BufferError, + "Object is not writable."); + return -1; + } + + // Since we have absolutely no guarantees about the lifetime + // of this object or the continued validity of the data pointer, + // we should arguably make a copy of the data. However, since + // the whole point of this method is to provide fast access to + // the underlying data, perhaps we can trust the user to handle + // the copy operation himself if he needs to. + const vector_float &table = _this->get_table(); + int channels = _this->get_num_channels(); + int num_pixels = _this->get_x_size() * _this->get_y_size(); + + if (self != NULL) { + Py_INCREF(self); + } + view->obj = self; + view->buf = (void *) &(table[0]); + view->len = 4 * table.size(); + view->readonly = 1; + view->itemsize = 4; + view->format = NULL; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) { + view->format = (char *) "f"; + } + view->ndim = 2; + view->shape = NULL; + if ((flags & PyBUF_ND) == PyBUF_ND) { + // If you're leaking and you know it, clap your hands! + view->shape = new Py_ssize_t[2]; + view->shape[0] = num_pixels; + view->shape[1] = channels; + } + view->strides = NULL; + view->suboffsets = NULL; + + return 0; +} + +#endif // PY_VERSION_HEX >= 0x02060000 + +#endif // HAVE_PYTHON diff --git a/panda/src/pnmimage/pfmFile_ext.h b/panda/src/pnmimage/pfmFile_ext.h new file mode 100644 index 0000000000..2018d8e394 --- /dev/null +++ b/panda/src/pnmimage/pfmFile_ext.h @@ -0,0 +1,44 @@ +// Filename: pfmFile_ext.h +// Created by: rdb (26Feb14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PFMFILE_EXT_H +#define PFMFILE_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "pfmFile.h" +#include "py_panda.h" + +//////////////////////////////////////////////////////////////////// +// Class : Extension +// Description : This class defines the extension methods for +// PfmFile, which are called instead of +// any C++ methods with the same prototype. +//////////////////////////////////////////////////////////////////// +template<> +class Extension : public ExtensionBase { +public: + PyObject *get_points() const; + +#if PY_VERSION_HEX >= 0x02060000 + int __getbuffer__(PyObject *self, Py_buffer *view, int flags) const; +#endif +}; + +#endif // HAVE_PYTHON + +#endif // PFMFILE_EXT_H