Преглед изворни кода

Support old Python 2 buffer protocol in PTA and Texture ram_image
This enables passing eg. str and array.array objects in Python 2

rdb пре 8 година
родитељ
комит
f0b21ee969
2 измењених фајлова са 43 додато и 17 уклоњено
  1. 20 17
      panda/src/express/pointerToArray_ext.I
  2. 23 0
      panda/src/gobj/texture_ext.cxx

+ 20 - 17
panda/src/express/pointerToArray_ext.I

@@ -203,34 +203,37 @@ set_data(PyObject *data) {
     }
 
     PyBuffer_Release(&view);
-  } else {
-    Dtool_Raise_TypeError("PointerToArray.set_data() requires a buffer object");
+    return;
   }
-#else
-  // In Python 2.5 we didn't have the new buffer protocol, only str.
-  if (PyString_CheckExact(data)) {
-    int size = PyString_Size(data);
-    if (size % sizeof(Element) != 0) {
+#endif
+
+  // In Python 2, there was also an older buffer protocol, supported by eg.
+  // str and array objects.
+#if PY_MAJOR_VERSION < 3
+  // The old, deprecated buffer interface, as used by eg. the array module.
+  const void *buffer;
+  Py_ssize_t buffer_len;
+  if (!PyUnicode_CheckExact(data) &&
+      PyObject_AsReadBuffer(data, &buffer, &buffer_len) == 0) {
+    if (buffer_len % sizeof(Element) != 0) {
       PyErr_Format(PyExc_ValueError,
-                   "str object is not a multiple of %zu bytes",
+                   "byte buffer is not a multiple of %zu bytes",
                    sizeof(Element));
       return;
     }
 
-    int num_elements = size / sizeof(Element);
-    this->_this->insert(this->_this->begin(), num_elements, Element());
-
-    // Hope there aren't any constructors or destructors involved here.
-    if (size != 0) {
-      const char *ptr = PyString_AsString(data);
-      memcpy(this->_this->p(), ptr, size);
+    if (buffer_len > 0) {
+      this->_this->resize(buffer_len / sizeof(Element));
+      memcpy(this->_this->p(), buffer, buffer_len);
     } else {
       this->_this->clear();
     }
-  } else {
-    Dtool_Raise_TypeError("PointerToArray.set_data() requires a str");
+
+    return;
   }
 #endif
+
+  Dtool_Raise_TypeError("PointerToArray.set_data() requires a buffer object");
 }
 
 /**

+ 23 - 0
panda/src/gobj/texture_ext.cxx

@@ -84,6 +84,29 @@ set_ram_image(PyObject *image, Texture::CompressionMode compression,
   }
 #endif
 
+#if PY_MAJOR_VERSION < 3
+  // The old, deprecated buffer interface, as used by eg. the array module.
+  const void *buffer;
+  Py_ssize_t buffer_len;
+  if (!PyUnicode_CheckExact(image) &&
+      PyObject_AsReadBuffer(image, &buffer, &buffer_len) == 0) {
+    if (compression == Texture::CM_off) {
+      int component_width = _this->get_component_width();
+      if (buffer_len % component_width != 0) {
+        PyErr_Format(PyExc_ValueError,
+                    "byte buffer is not a multiple of %d bytes",
+                    component_width);
+        return;
+      }
+    }
+
+    PTA_uchar data = PTA_uchar::empty_array(buffer_len, Texture::get_class_type());
+    memcpy(data.p(), buffer, buffer_len);
+    _this->set_ram_image(MOVE(data), compression, page_size);
+    return;
+  }
+#endif
+
   Dtool_Raise_ArgTypeError(image, 0, "Texture.set_ram_image", "CPTA_uchar or buffer");
 }