Python API: new GPUVertFormat constructor and vbo.fill_attribute method
Reviewer: fclem Differential Revision: https://developer.blender.org/D3760
This commit is contained in:
parent
1aae42aa88
commit
564d37c4b6
|
@ -87,6 +87,7 @@ uint GPU_vertformat_attr_add(
|
|||
GPUVertFormat *, const char *name,
|
||||
GPUVertCompType, uint comp_len, GPUVertFetchMode);
|
||||
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
|
||||
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
|
||||
|
||||
/* format conversion */
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#define PACK_DEBUG 0
|
||||
|
||||
#if PACK_DEBUG
|
||||
|
@ -204,6 +206,19 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
|
|||
attrib->name[attrib->name_len++] = copy_attrib_name(format, alias);
|
||||
}
|
||||
|
||||
int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
|
||||
{
|
||||
for (int i = 0; i < format->attr_len; i++) {
|
||||
const GPUVertAttr *attrib = format->attribs + i;
|
||||
for (int j = 0; j < attrib->name_len; j++) {
|
||||
if (STREQ(name, attrib->name[j])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint padding(uint offset, uint alignment)
|
||||
{
|
||||
const uint mod = offset % alignment;
|
||||
|
|
|
@ -188,20 +188,28 @@ finally:
|
|||
return ok;
|
||||
}
|
||||
|
||||
/* handy, but not used just now */
|
||||
#if 0
|
||||
static int bpygpu_find_id(const GPUVertFormat *fmt, const char *id)
|
||||
static int bpygpu_fill_attribute(GPUVertBuf *buf, int id, PyObject *py_seq_data)
|
||||
{
|
||||
for (int i = 0; i < fmt->attr_len; i++) {
|
||||
for (uint j = 0; j < fmt->name_len; j++) {
|
||||
if (STREQ(fmt->attribs[i].name[j], id)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if (id < 0 || id >= buf->format.attr_len) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Format id %d out of range",
|
||||
id);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
|
||||
if (buf->data == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Can't fill, static buffer already in use");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bpygpu_vertbuf_fill_impl(buf, (uint)id, py_seq_data)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@ -218,12 +226,12 @@ static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args,
|
|||
uint len;
|
||||
} params;
|
||||
|
||||
static const char *_keywords[] = {"len", "format", NULL};
|
||||
static _PyArg_Parser _parser = {"$IO!:GPUVertBuf.__new__", _keywords, 0};
|
||||
static const char *_keywords[] = {"format", "len", NULL};
|
||||
static _PyArg_Parser _parser = {"O!I:GPUVertBuf.__new__", _keywords, 0};
|
||||
if (!_PyArg_ParseTupleAndKeywordsFast(
|
||||
args, kwds, &_parser,
|
||||
¶ms.len,
|
||||
&BPyGPUVertFormat_Type, ¶ms.py_fmt))
|
||||
&BPyGPUVertFormat_Type, ¶ms.py_fmt,
|
||||
¶ms.len))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -235,48 +243,62 @@ static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args,
|
|||
return BPyGPUVertBuf_CreatePyObject(vbo);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bpygpu_VertBuf_fill_doc,
|
||||
"TODO"
|
||||
PyDoc_STRVAR(bpygpu_VertBuf_fill_attribute_doc,
|
||||
"fill_attribute(identifier, data)\n"
|
||||
"\n"
|
||||
" Insert data into the buffer for a single attribute.\n"
|
||||
"\n"
|
||||
" :param identifier: Either the name or the id of the attribute.\n"
|
||||
" :type identifier: int or str\n"
|
||||
" :param data: Sequence of data that should be stored in the buffer\n"
|
||||
" :type data: sequence of individual values or tuples\n"
|
||||
);
|
||||
static PyObject *bpygpu_VertBuf_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds)
|
||||
static PyObject *bpygpu_VertBuf_fill_attribute(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
struct {
|
||||
uint id;
|
||||
PyObject *py_seq_data;
|
||||
} params;
|
||||
PyObject *data;
|
||||
PyObject *identifier;
|
||||
|
||||
static const char *_keywords[] = {"id", "data", NULL};
|
||||
static _PyArg_Parser _parser = {"$IO:fill", _keywords, 0};
|
||||
static const char *_keywords[] = {"identifier", "data", NULL};
|
||||
static _PyArg_Parser _parser = {"OO:fill_attribute", _keywords, 0};
|
||||
if (!_PyArg_ParseTupleAndKeywordsFast(
|
||||
args, kwds, &_parser,
|
||||
¶ms.id,
|
||||
¶ms.py_seq_data))
|
||||
&identifier, &data))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (params.id >= self->buf->format.attr_len) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"Format id %d out of range",
|
||||
params.id);
|
||||
int id;
|
||||
|
||||
if (PyLong_Check(identifier)) {
|
||||
id = PyLong_AsLong(identifier);
|
||||
}
|
||||
else if (PyUnicode_Check(identifier)) {
|
||||
const char *name = PyUnicode_AsUTF8(identifier);
|
||||
id = GPU_vertformat_attr_id_get(&self->buf->format, name);
|
||||
if (id == -1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Unknown attribute name");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"expected int or str type as identifier");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (self->buf->data == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Can't fill, static buffer already in use");
|
||||
|
||||
if (!bpygpu_fill_attribute(self->buf, id, data)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!bpygpu_vertbuf_fill_impl(self->buf, params.id, params.py_seq_data)) {
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static struct PyMethodDef bpygpu_VertBuf_methods[] = {
|
||||
{"fill", (PyCFunction) bpygpu_VertBuf_fill,
|
||||
METH_VARARGS | METH_KEYWORDS, bpygpu_VertBuf_fill_doc},
|
||||
{"fill_attribute", (PyCFunction) bpygpu_VertBuf_fill_attribute,
|
||||
METH_VARARGS | METH_KEYWORDS, bpygpu_VertBuf_fill_attribute_doc},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -55,79 +55,104 @@
|
|||
* Use with PyArg_ParseTuple's "O&" formatting.
|
||||
* \{ */
|
||||
|
||||
static int bpygpu_parse_component_type(const char *str, int length)
|
||||
{
|
||||
if (length == 2) {
|
||||
switch (*((ushort *)str)) {
|
||||
case MAKE_ID2('I', '8'): return GPU_COMP_I8;
|
||||
case MAKE_ID2('U', '8'): return GPU_COMP_U8;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if (length == 3) {
|
||||
switch (*((uint *)str)) {
|
||||
case MAKE_ID3('I', '1', '6'): return GPU_COMP_I16;
|
||||
case MAKE_ID3('U', '1', '6'): return GPU_COMP_U16;
|
||||
case MAKE_ID3('I', '3', '2'): return GPU_COMP_I32;
|
||||
case MAKE_ID3('U', '3', '2'): return GPU_COMP_U32;
|
||||
case MAKE_ID3('F', '3', '2'): return GPU_COMP_F32;
|
||||
case MAKE_ID3('I', '1', '0'): return GPU_COMP_I10;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bpygpu_parse_fetch_mode(const char *str, int length)
|
||||
{
|
||||
#define MATCH_ID(id) \
|
||||
if (length == strlen(STRINGIFY(id))) { \
|
||||
if (STREQ(str, STRINGIFY(id))) { \
|
||||
return GPU_FETCH_##id; \
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
MATCH_ID(FLOAT);
|
||||
MATCH_ID(INT);
|
||||
MATCH_ID(INT_TO_FLOAT_UNIT);
|
||||
MATCH_ID(INT_TO_FLOAT);
|
||||
#undef MATCH_ID
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bpygpu_ParseVertCompType(PyObject *o, void *p)
|
||||
{
|
||||
Py_ssize_t comp_type_id_len;
|
||||
const char *comp_type_id = _PyUnicode_AsStringAndSize(o, &comp_type_id_len);
|
||||
if (comp_type_id == NULL) {
|
||||
Py_ssize_t length;
|
||||
const char *str = _PyUnicode_AsStringAndSize(o, &length);
|
||||
|
||||
if (str == NULL) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"expected a string, got %s",
|
||||
Py_TYPE(o)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GPUVertCompType comp_type;
|
||||
if (comp_type_id_len == 2) {
|
||||
switch (*((ushort *)comp_type_id)) {
|
||||
case MAKE_ID2('I', '8'): { comp_type = GPU_COMP_I8; goto success; }
|
||||
case MAKE_ID2('U', '8'): { comp_type = GPU_COMP_U8; goto success; }
|
||||
}
|
||||
}
|
||||
else if (comp_type_id_len == 3) {
|
||||
switch (*((uint *)comp_type_id)) {
|
||||
case MAKE_ID3('I', '1', '6'): { comp_type = GPU_COMP_I16; goto success; }
|
||||
case MAKE_ID3('U', '1', '6'): { comp_type = GPU_COMP_U16; goto success; }
|
||||
case MAKE_ID3('I', '3', '2'): { comp_type = GPU_COMP_I32; goto success; }
|
||||
case MAKE_ID3('U', '3', '2'): { comp_type = GPU_COMP_U32; goto success; }
|
||||
case MAKE_ID3('F', '3', '2'): { comp_type = GPU_COMP_F32; goto success; }
|
||||
case MAKE_ID3('I', '1', '0'): { comp_type = GPU_COMP_I10; goto success; }
|
||||
}
|
||||
int comp_type = bpygpu_parse_component_type(str, length);
|
||||
if (comp_type == -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unkown component type: '%s",
|
||||
str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unknown type literal: '%s'",
|
||||
comp_type_id);
|
||||
return 0;
|
||||
|
||||
success:
|
||||
*((GPUVertCompType *)p) = comp_type;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bpygpu_ParseVertFetchMode(PyObject *o, void *p)
|
||||
{
|
||||
Py_ssize_t mode_id_len;
|
||||
const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len);
|
||||
if (mode_id == NULL) {
|
||||
Py_ssize_t length;
|
||||
const char *str = _PyUnicode_AsStringAndSize(o, &length);
|
||||
|
||||
if (str == NULL) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"expected a string, got %s",
|
||||
Py_TYPE(o)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
#define MATCH_ID(id) \
|
||||
if (mode_id_len == strlen(STRINGIFY(id))) { \
|
||||
if (STREQ(mode_id, STRINGIFY(id))) { \
|
||||
mode = GPU_FETCH_##id; \
|
||||
goto success; \
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
GPUVertFetchMode mode;
|
||||
MATCH_ID(FLOAT);
|
||||
MATCH_ID(INT);
|
||||
MATCH_ID(INT_TO_FLOAT_UNIT);
|
||||
MATCH_ID(INT_TO_FLOAT);
|
||||
#undef MATCH_ID
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unknown type literal: '%s'",
|
||||
mode_id);
|
||||
return 0;
|
||||
int fetch_mode = bpygpu_parse_fetch_mode(str, length);
|
||||
if (fetch_mode == -1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"unknown type literal: '%s'",
|
||||
str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
success:
|
||||
(*(GPUVertFetchMode *)p) = mode;
|
||||
(*(GPUVertFetchMode *)p) = fetch_mode;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_default_fetch_mode(GPUVertCompType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GPU_COMP_F32: return GPU_FETCH_FLOAT;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
|
@ -136,16 +161,71 @@ success:
|
|||
/** \name VertFormat Type
|
||||
* \{ */
|
||||
|
||||
static int add_attribute_simple(GPUVertFormat *format, char *name, GPUVertCompType comp_type, int length)
|
||||
{
|
||||
if (length <= 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"length of an attribute must greater than 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fetch_mode = get_default_fetch_mode(comp_type);
|
||||
if (fetch_mode == -1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"no default fetch mode found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
GPU_vertformat_attr_add(format, name, comp_type, length, fetch_mode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int add_attribute_from_tuple(GPUVertFormat *format, PyObject *data)
|
||||
{
|
||||
char *name;
|
||||
GPUVertCompType comp_type;
|
||||
int length;
|
||||
|
||||
if (!PyArg_ParseTuple(data, "sO&i", &name, bpygpu_ParseVertCompType, &comp_type, &length)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return add_attribute_simple(format, name, comp_type, length);
|
||||
}
|
||||
|
||||
static int insert_attributes_from_list(GPUVertFormat *format, PyObject *list)
|
||||
{
|
||||
Py_ssize_t amount = PyList_Size(list);
|
||||
|
||||
for (Py_ssize_t i = 0; i < amount; i++) {
|
||||
PyObject *element = PyList_GET_ITEM(list, i);
|
||||
if (!PyTuple_Check(element)) {
|
||||
PyErr_SetString(PyExc_TypeError, "expected a list of tuples");
|
||||
return 0;
|
||||
}
|
||||
if (!add_attribute_from_tuple(format, element)) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyObject *bpygpu_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
|
||||
{
|
||||
if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"VertFormat(): takes no arguments");
|
||||
|
||||
PyObject *format_list;
|
||||
|
||||
static const char *keywords[] = {"format", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char**)keywords, &PyList_Type, &format_list)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL);
|
||||
|
||||
if (!insert_attributes_from_list(&ret->fmt, format_list)) {
|
||||
Py_DecRef((PyObject *)ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue