Texture.set_ram_image(_as) now directly accepts buffers with right component size

This commit is contained in:
rdb 2016-10-24 21:29:43 +02:00
parent a757cb47e8
commit ef986ccfc0
5 changed files with 226 additions and 24 deletions

View File

@ -14,36 +14,47 @@
#ifndef POINTERTOARRAY_H #ifndef POINTERTOARRAY_H
#define POINTERTOARRAY_H #define POINTERTOARRAY_H
/* /*
* This file defines the classes PointerToArray and ConstPointerToArray (and * This file defines the classes PointerToArray and ConstPointerToArray (and
* their abbreviations, PTA and CPTA), which are extensions to the PointerTo * their abbreviations, PTA and CPTA), which are extensions to the PointerTo
* class that support reference-counted arrays. You may think of a * class that support reference-counted arrays.
* PointerToArray as the same thing as a traditional C-style array. However, *
* it actually stores a pointer to an STL vector, which is then reference- * You may think of a PointerToArray as the same thing as a traditional
* counted. Thus, most vector operations may be applied directly to a * C-style array. However, it actually stores a pointer to an STL vector,
* PointerToArray object, including dynamic resizing via push_back() and * which is then reference-counted. Thus, most vector operations may be
* pop_back(). Unlike the PointerTo class, the PointerToArray may store * applied directly to a PointerToArray object, including dynamic resizing via
* pointers to any kind of object, not just those derived from ReferenceCount. * push_back() and pop_back().
*
* Unlike the PointerTo class, the PointerToArray may store pointers to any
* kind of object, not just those derived from ReferenceCount.
*
* Like PointerTo and ConstPointerTo, the macro abbreviations PTA and CPTA are * Like PointerTo and ConstPointerTo, the macro abbreviations PTA and CPTA are
* defined for convenience. Some examples of syntax: instead of: * defined for convenience.
*
* Some examples of syntax: instead of:
*
* PTA(int) array(10); int *array = new int[10]; * PTA(int) array(10); int *array = new int[10];
* memset(array, 0, sizeof(int) * 10); memset(array, 0, sizeof(int) * 10); * memset(array, 0, sizeof(int) * 10); memset(array, 0, sizeof(int) * 10);
* array[i] = array[i+1]; array[i] = array[i+1]; num_elements * array[i] = array[i+1]; array[i] = array[i+1];
* = array.size(); (no equivalent) PTA(int) copy = array; * num_elements = array.size(); (no equivalent)
* int *copy = array; Note that in the above example, unlike an STL vector *
* (but like a C-style array), assigning a PointerToArray object from another * PTA(int) copy = array; int *copy = array;
* simply copies the pointer, and does not copy individual elements. (Of *
* course, reference counts are adjusted appropriately7.) If you actually * Note that in the above example, unlike an STL vector (but like a C-style
* wanted an element-by-element copy of the array, you would do this: PTA(int) * array), assigning a PointerToArray object from another simply copies the
* copy(0); Create a pointer to an empty vector. copy.v() = * pointer, and does not copy individual elements. (Of course, reference
* array.v(); v() is the STL vector itself. The (0) parameter to * counts are adjusted appropriately.) If you actually wanted an
* the constructor in the above example is crucial. When a numeric length * element-by-element copy of the array, you would do this:
* parameter, such as zero, is given to the constructor, it means to define a *
* new STL vector with that number of elements initially in it. If no * PTA(int) copy(0); // Create a pointer to an empty vector.
* parameter is given, on the other hand, it means the PointerToArray should * copy.v() = array.v(); // v() is the STL vector itself.
* point to nothing--no STL vector is created. This is equivalent to a C *
* array that points to NULL. * The (0) parameter to the constructor in the above example is crucial. When
* a numeric length parameter, such as zero, is given to the constructor, it
* means to define a new STL vector with that number of elements initially in
* it. If no parameter is given, on the other hand, it means the
* PointerToArray should point to nothing--no STL vector is created. This is
* equivalent to a C array that points to NULL.
*/ */
#include "pandabase.h" #include "pandabase.h"

View File

@ -1,3 +1,4 @@
#include "internalName_ext.cxx" #include "internalName_ext.cxx"
#include "geomVertexArrayData_ext.cxx" #include "geomVertexArrayData_ext.cxx"
#include "texture_ext.cxx"
#include "textureCollection_ext.cxx" #include "textureCollection_ext.cxx"

View File

@ -445,9 +445,15 @@ PUBLISHED:
CPTA_uchar get_ram_image_as(const string &requested_format); CPTA_uchar get_ram_image_as(const string &requested_format);
INLINE PTA_uchar modify_ram_image(); INLINE PTA_uchar modify_ram_image();
INLINE PTA_uchar make_ram_image(); INLINE PTA_uchar make_ram_image();
#ifndef CPPPARSER
INLINE void set_ram_image(CPTA_uchar image, CompressionMode compression = CM_off, INLINE void set_ram_image(CPTA_uchar image, CompressionMode compression = CM_off,
size_t page_size = 0); size_t page_size = 0);
void set_ram_image_as(CPTA_uchar image, const string &provided_format); void set_ram_image_as(CPTA_uchar image, const string &provided_format);
#else
EXTEND void set_ram_image(PyObject *image, CompressionMode compression = CM_off,
size_t page_size = 0);
EXTEND void set_ram_image_as(PyObject *image, const string &provided_format);
#endif
INLINE void clear_ram_image(); INLINE void clear_ram_image();
INLINE void set_keep_ram_image(bool keep_ram_image); INLINE void set_keep_ram_image(bool keep_ram_image);
virtual bool get_keep_ram_image() const; virtual bool get_keep_ram_image() const;

View File

@ -0,0 +1,147 @@
/**
* 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."
*
* @file texture_ext.cxx
* @author rdb
* @date 2016-08-08
*/
#include "texture_ext.h"
#ifndef CPPPARSER
extern Dtool_PyTypedObject Dtool_PointerToArray_unsigned_char;
extern Dtool_PyTypedObject Dtool_ConstPointerToArray_unsigned_char;
#endif
/**
* Replaces the current system-RAM image with the new data. If compression is
* not CM_off, it indicates that the new data is already pre-compressed in the
* indicated format.
*
* This does *not* affect keep_ram_image.
*/
void Extension<Texture>::
set_ram_image(PyObject *image, Texture::CompressionMode compression,
size_t page_size) {
nassertv(compression != Texture::CM_default);
// Check if perhaps a PointerToArray object was passed in.
if (DtoolCanThisBeAPandaInstance(image)) {
Dtool_PyInstDef *inst = (Dtool_PyInstDef *)image;
if (inst->_My_Type == &Dtool_ConstPointerToArray_unsigned_char) {
_this->set_ram_image(*(const CPTA_uchar *)inst->_ptr_to_object, compression, page_size);
return;
} else if (inst->_My_Type == &Dtool_PointerToArray_unsigned_char) {
_this->set_ram_image(*(const PTA_uchar *)inst->_ptr_to_object, compression, page_size);
return;
}
}
#if PY_VERSION_HEX >= 0x02060000
if (PyObject_CheckBuffer(image)) {
// User passed a buffer object.
Py_buffer view;
if (PyObject_GetBuffer(image, &view, PyBUF_CONTIG_RO) == -1) {
PyErr_SetString(PyExc_TypeError,
"Texture.set_ram_image() requires a contiguous buffer");
return;
}
int component_width = _this->get_component_width();
if (compression == Texture::CM_off) {
if (view.itemsize != 1 && view.itemsize != component_width) {
PyErr_SetString(PyExc_TypeError,
"buffer.itemsize does not match Texture component size");
return;
}
if (view.len % component_width != 0) {
PyErr_Format(PyExc_ValueError,
"byte buffer is not a multiple of %zu bytes",
component_width);
return;
}
} else {
if (view.itemsize != 1) {
PyErr_SetString(PyExc_TypeError,
"buffer.itemsize should be 1 for compressed images");
return;
}
}
PTA_uchar data = PTA_uchar::empty_array(view.len, Texture::get_class_type());
memcpy(data.p(), view.buf, view.len);
_this->set_ram_image(MOVE(data), compression, page_size);
PyBuffer_Release(&view);
return;
}
#endif
Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image", "CPTA_uchar or buffer");
}
/**
* Replaces the current system-RAM image with the new data, converting it
* first if necessary from the indicated component-order format. See
* get_ram_image_as() for specifications about the format. This method cannot
* support compressed image data or sub-pages; use set_ram_image() for that.
*/
void Extension<Texture>::
set_ram_image_as(PyObject *image, const string &provided_format) {
// Check if perhaps a PointerToArray object was passed in.
if (DtoolCanThisBeAPandaInstance(image)) {
Dtool_PyInstDef *inst = (Dtool_PyInstDef *)image;
if (inst->_My_Type == &Dtool_ConstPointerToArray_unsigned_char) {
_this->set_ram_image_as(*(const CPTA_uchar *)inst->_ptr_to_object, provided_format);
return;
} else if (inst->_My_Type == &Dtool_PointerToArray_unsigned_char) {
_this->set_ram_image_as(*(const PTA_uchar *)inst->_ptr_to_object, provided_format);
return;
}
}
#if PY_VERSION_HEX >= 0x02060000
if (PyObject_CheckBuffer(image)) {
// User passed a buffer object.
Py_buffer view;
if (PyObject_GetBuffer(image, &view, PyBUF_CONTIG_RO) == -1) {
PyErr_SetString(PyExc_TypeError,
"Texture.set_ram_image_as() requires a contiguous buffer");
return;
}
int component_width = _this->get_component_width();
if (view.itemsize != 1 && view.itemsize != component_width) {
PyErr_SetString(PyExc_TypeError,
"buffer.itemsize does not match Texture component size");
return;
}
if (view.len % component_width != 0) {
PyErr_Format(PyExc_ValueError,
"byte buffer is not a multiple of %zu bytes",
component_width);
return;
}
PTA_uchar data = PTA_uchar::empty_array(view.len, Texture::get_class_type());
memcpy(data.p(), view.buf, view.len);
_this->set_ram_image_as(MOVE(data), provided_format);
PyBuffer_Release(&view);
return;
}
#endif
Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image_as", "CPTA_uchar or buffer");
}

View File

@ -0,0 +1,37 @@
/**
* 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."
*
* @file texture_ext.h
* @author rdb
* @date 2016-08-08
*/
#ifndef TEXTURE_EXT_H
#define TEXTURE_EXT_H
#ifndef CPPPARSER
#include "extension.h"
#include "py_panda.h"
#include "texture.h"
/**
* This class defines the extension methods for Texture, which are
* called instead of any C++ methods with the same prototype.
*/
template<>
class Extension<Texture> : public ExtensionBase<Texture> {
public:
void set_ram_image(PyObject *image, Texture::CompressionMode compression = Texture::CM_off,
size_t page_size = 0);
void set_ram_image_as(PyObject *image, const string &provided_format);
};
#endif // CPPPARSER
#endif // TEXTURE_EXT_H