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
#define POINTERTOARRAY_H
/*
* This file defines the classes PointerToArray and ConstPointerToArray (and
* their abbreviations, PTA and CPTA), which are extensions to the PointerTo
* class that support reference-counted arrays. You may think of a
* 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-
* counted. Thus, most vector operations may be applied directly to a
* PointerToArray object, including dynamic resizing via 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.
* class that support reference-counted arrays.
*
* You may think of a 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-counted. Thus, most vector operations may be
* applied directly to a PointerToArray object, including dynamic resizing via
* 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
* 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];
* 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.size(); (no equivalent) PTA(int) copy = array;
* 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
* simply copies the pointer, and does not copy individual elements. (Of
* course, reference counts are adjusted appropriately7.) If you actually
* wanted an element-by-element copy of the array, you would do this: PTA(int)
* copy(0); Create a pointer to an empty vector. copy.v() =
* array.v(); v() is the STL vector itself. 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.
* array[i] = array[i+1]; array[i] = array[i+1];
* num_elements = array.size(); (no equivalent)
*
* PTA(int) copy = array; 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 simply copies the
* pointer, and does not copy individual elements. (Of course, reference
* counts are adjusted appropriately.) If you actually wanted an
* element-by-element copy of the array, you would do this:
*
* PTA(int) copy(0); // Create a pointer to an empty vector.
* copy.v() = array.v(); // v() is the STL vector itself.
*
* 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"

View File

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

View File

@ -445,9 +445,15 @@ PUBLISHED:
CPTA_uchar get_ram_image_as(const string &requested_format);
INLINE PTA_uchar modify_ram_image();
INLINE PTA_uchar make_ram_image();
#ifndef CPPPARSER
INLINE void set_ram_image(CPTA_uchar image, CompressionMode compression = CM_off,
size_t page_size = 0);
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 set_keep_ram_image(bool keep_ram_image);
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