forked from bartvdbraak/blender
D545: Freestyle Python API: new methods for Stroke and StrokeVertexIterator.
This revision extends the Freestyle Python API to make for style module writing easier. - freestyle.types.Stroke: A proper support for reversed() is implemented. It works the same with other Python sequence objects (returns an iterator starting from the end). This is in effect equivalent to Stroke.stroke_vertices_end(). - freestyle.types.StrokeVertexIterator: An incremented, decremented and reversed method are added. The first two methods return a new StrokeVertexIterator object that has been incremented and decremented, respectively. The reversed method returns a new StrokeVertexIterator object that will traverse stroke vertices in the opposite direction. - freestyle.types.Interface0DIterator: Its constructor now accepts a Stroke object to create an Interface0DIterator that traverses stroke vertices. This is in effect equivalent to Stroke.vertices_begin(). The new API makes stroke shaders involving function calls much simpler as illustrated below: # in the old API it = stroke.stroke_vertices_begin() for vert in it: result = somefunc(Interface0DIterator(it)) # in the new API it = Interface0DIterator(stroke) for vert in it: result = somefunc(it) Differential Revision: https://developer.blender.org/D545 Reviewers: kjym3
This commit is contained in:
parent
ea3bca75d9
commit
840891e22a
@ -286,6 +286,21 @@ static PyObject *Stroke_stroke_vertices_end(BPy_Stroke *self)
|
|||||||
return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, true);
|
return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(Stroke_reversed_doc,
|
||||||
|
".. method:: __reversed__()\n"
|
||||||
|
"\n"
|
||||||
|
" Returns a StrokeVertexIterator iterating over the vertices of the Stroke\n"
|
||||||
|
" in the reversed order (from the last to the first).\n"
|
||||||
|
"\n"
|
||||||
|
" :return: A StrokeVertexIterator pointing after the last StrokeVertex.\n"
|
||||||
|
" :rtype: :class:`StrokeVertexIterator`");
|
||||||
|
|
||||||
|
static PyObject *Stroke_reversed(BPy_Stroke *self)
|
||||||
|
{
|
||||||
|
StrokeInternal::StrokeVertexIterator sv_it(self->s->strokeVerticesEnd());
|
||||||
|
return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, true);
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(Stroke_stroke_vertices_size_doc,
|
PyDoc_STRVAR(Stroke_stroke_vertices_size_doc,
|
||||||
".. method:: stroke_vertices_size()\n"
|
".. method:: stroke_vertices_size()\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -310,6 +325,7 @@ static PyMethodDef BPy_Stroke_methods[] = {
|
|||||||
{"stroke_vertices_begin", (PyCFunction)Stroke_stroke_vertices_begin, METH_VARARGS | METH_KEYWORDS,
|
{"stroke_vertices_begin", (PyCFunction)Stroke_stroke_vertices_begin, METH_VARARGS | METH_KEYWORDS,
|
||||||
Stroke_stroke_vertices_begin_doc},
|
Stroke_stroke_vertices_begin_doc},
|
||||||
{"stroke_vertices_end", (PyCFunction)Stroke_stroke_vertices_end, METH_NOARGS, Stroke_stroke_vertices_end_doc},
|
{"stroke_vertices_end", (PyCFunction)Stroke_stroke_vertices_end, METH_NOARGS, Stroke_stroke_vertices_end_doc},
|
||||||
|
{"__reversed__", (PyCFunction)Stroke_reversed, METH_NOARGS, Stroke_reversed_doc},
|
||||||
{"stroke_vertices_size", (PyCFunction)Stroke_stroke_vertices_size, METH_NOARGS, Stroke_stroke_vertices_size_doc},
|
{"stroke_vertices_size", (PyCFunction)Stroke_stroke_vertices_size, METH_NOARGS, Stroke_stroke_vertices_size_doc},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "BPy_Interface0DIterator.h"
|
#include "BPy_Interface0DIterator.h"
|
||||||
|
|
||||||
#include "../BPy_Convert.h"
|
#include "../BPy_Convert.h"
|
||||||
|
#include "../BPy_Interface1D.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -70,9 +71,10 @@ static int convert_nested_it(PyObject *obj, void *v)
|
|||||||
static int Interface0DIterator_init(BPy_Interface0DIterator *self, PyObject *args, PyObject *kwds)
|
static int Interface0DIterator_init(BPy_Interface0DIterator *self, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
static const char *kwlist_1[] = {"it", NULL};
|
static const char *kwlist_1[] = {"it", NULL};
|
||||||
static const char *kwlist_2[] = {"brother", NULL};
|
static const char *kwlist_2[] = {"inter", NULL};
|
||||||
|
static const char *kwlist_3[] = {"brother", NULL};
|
||||||
Interface0DIteratorNested *nested_it;
|
Interface0DIteratorNested *nested_it;
|
||||||
PyObject *brother;
|
PyObject *brother, *inter;
|
||||||
|
|
||||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "O&", (char **)kwlist_1, convert_nested_it, &nested_it)) {
|
if (PyArg_ParseTupleAndKeywords(args, kwds, "O&", (char **)kwlist_1, convert_nested_it, &nested_it)) {
|
||||||
self->if0D_it = new Interface0DIterator(nested_it->copy());
|
self->if0D_it = new Interface0DIterator(nested_it->copy());
|
||||||
@ -80,7 +82,14 @@ static int Interface0DIterator_init(BPy_Interface0DIterator *self, PyObject *arg
|
|||||||
self->reversed = false;
|
self->reversed = false;
|
||||||
}
|
}
|
||||||
else if (PyErr_Clear(),
|
else if (PyErr_Clear(),
|
||||||
PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &Interface0DIterator_Type, &brother))
|
PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &Interface1D_Type, &inter))
|
||||||
|
{
|
||||||
|
self->if0D_it = new Interface0DIterator(((BPy_Interface1D *)inter)->if1D->verticesBegin());
|
||||||
|
self->at_start = true;
|
||||||
|
self->reversed = false;
|
||||||
|
}
|
||||||
|
else if (PyErr_Clear(),
|
||||||
|
PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_3, &Interface0DIterator_Type, &brother))
|
||||||
{
|
{
|
||||||
self->if0D_it = new Interface0DIterator(*(((BPy_Interface0DIterator *)brother)->if0D_it));
|
self->if0D_it = new Interface0DIterator(*(((BPy_Interface0DIterator *)brother)->if0D_it));
|
||||||
self->at_start = ((BPy_Interface0DIterator *)brother)->at_start;
|
self->at_start = ((BPy_Interface0DIterator *)brother)->at_start;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "BPy_StrokeVertexIterator.h"
|
#include "BPy_StrokeVertexIterator.h"
|
||||||
|
|
||||||
#include "../BPy_Convert.h"
|
#include "../BPy_Convert.h"
|
||||||
|
#include "../Interface1D/BPy_Stroke.h"
|
||||||
#include "BPy_Interface0DIterator.h"
|
#include "BPy_Interface0DIterator.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -63,20 +64,27 @@ PyDoc_STRVAR(StrokeVertexIterator_doc,
|
|||||||
|
|
||||||
static int StrokeVertexIterator_init(BPy_StrokeVertexIterator *self, PyObject *args, PyObject *kwds)
|
static int StrokeVertexIterator_init(BPy_StrokeVertexIterator *self, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
static const char *kwlist[] = {"brother", NULL};
|
static const char *kwlist_1[] = {"brother", NULL};
|
||||||
PyObject *brother = 0;
|
static const char *kwlist_2[] = {"stroke", NULL};
|
||||||
|
PyObject *brother = 0, *stroke = 0;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &StrokeVertexIterator_Type, &brother))
|
if (PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist_1, &StrokeVertexIterator_Type, &brother)) {
|
||||||
return -1;
|
self->sv_it = new StrokeInternal::StrokeVertexIterator(*(((BPy_StrokeVertexIterator *)brother)->sv_it));
|
||||||
if (!brother) {
|
self->reversed = ((BPy_StrokeVertexIterator *)brother)->reversed;
|
||||||
self->sv_it = new StrokeInternal::StrokeVertexIterator();
|
self->at_start = ((BPy_StrokeVertexIterator *)brother)->at_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (PyErr_Clear(),
|
||||||
|
PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist_2, &Stroke_Type, &stroke))
|
||||||
|
{
|
||||||
|
self->sv_it = new StrokeInternal::StrokeVertexIterator(((BPy_Stroke *)stroke)->s->strokeVerticesBegin());
|
||||||
self->reversed = false;
|
self->reversed = false;
|
||||||
self->at_start = true;
|
self->at_start = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self->sv_it = new StrokeInternal::StrokeVertexIterator(*(((BPy_StrokeVertexIterator *)brother)->sv_it));
|
self->sv_it = new StrokeInternal::StrokeVertexIterator();
|
||||||
self->reversed = ((BPy_StrokeVertexIterator *)brother)->reversed;
|
self->reversed = false;
|
||||||
self->at_start = ((BPy_StrokeVertexIterator *)brother)->at_start;
|
self->at_start = true;
|
||||||
}
|
}
|
||||||
self->py_it.it = self->sv_it;
|
self->py_it.it = self->sv_it;
|
||||||
return 0;
|
return 0;
|
||||||
@ -91,6 +99,12 @@ static PyObject *StrokeVertexIterator_iter(BPy_StrokeVertexIterator *self)
|
|||||||
|
|
||||||
static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
|
static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
|
||||||
{
|
{
|
||||||
|
/* Because Freestyle iterators for which it.isEnd() holds true have no valid object
|
||||||
|
* (referencing it.object in this case leads to a crash), we must check if it.object
|
||||||
|
* is valid after incrementing, to prevent crashes in Python.
|
||||||
|
* Additionally, the at_start attribute is used to keep Freestyle iterator objects
|
||||||
|
* and Python for loops in sync. */
|
||||||
|
|
||||||
if (self->reversed) {
|
if (self->reversed) {
|
||||||
if (self->sv_it->isBegin()) {
|
if (self->sv_it->isBegin()) {
|
||||||
PyErr_SetNone(PyExc_StopIteration);
|
PyErr_SetNone(PyExc_StopIteration);
|
||||||
@ -121,6 +135,44 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
|
|||||||
return BPy_StrokeVertex_from_StrokeVertex(*sv);
|
return BPy_StrokeVertex_from_StrokeVertex(*sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------StrokeVertexIterator methods ----------------------------*/
|
||||||
|
|
||||||
|
static PyObject *StrokeVertexIterator_incremented(BPy_StrokeVertexIterator *self)
|
||||||
|
{
|
||||||
|
if (self->sv_it->isEnd()) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "cannot increment any more");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
StrokeInternal::StrokeVertexIterator *copy = new StrokeInternal::StrokeVertexIterator(*self->sv_it);
|
||||||
|
copy->increment();
|
||||||
|
return BPy_StrokeVertexIterator_from_StrokeVertexIterator(*copy, self->reversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *StrokeVertexIterator_decremented(BPy_StrokeVertexIterator *self)
|
||||||
|
{
|
||||||
|
if (self->sv_it->isBegin()) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "cannot decrement any more");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StrokeInternal::StrokeVertexIterator *copy = new StrokeInternal::StrokeVertexIterator(*self->sv_it);
|
||||||
|
copy->decrement();
|
||||||
|
return BPy_StrokeVertexIterator_from_StrokeVertexIterator(*copy, self->reversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *StrokeVertexIterator_reversed(BPy_StrokeVertexIterator *self)
|
||||||
|
{
|
||||||
|
StrokeInternal::StrokeVertexIterator *copy = new StrokeInternal::StrokeVertexIterator(*self->sv_it);
|
||||||
|
return BPy_StrokeVertexIterator_from_StrokeVertexIterator(*copy, !self->reversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef BPy_StrokeVertexIterator_methods[] = {
|
||||||
|
{"incremented", (PyCFunction) StrokeVertexIterator_incremented, METH_NOARGS, NULL},
|
||||||
|
{"decremented", (PyCFunction) StrokeVertexIterator_decremented, METH_NOARGS, NULL},
|
||||||
|
{"reversed", (PyCFunction) StrokeVertexIterator_reversed, METH_NOARGS, NULL},
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
/*----------------------StrokeVertexIterator get/setters ----------------------------*/
|
/*----------------------StrokeVertexIterator get/setters ----------------------------*/
|
||||||
|
|
||||||
PyDoc_STRVAR(StrokeVertexIterator_object_doc,
|
PyDoc_STRVAR(StrokeVertexIterator_object_doc,
|
||||||
@ -130,7 +182,7 @@ PyDoc_STRVAR(StrokeVertexIterator_object_doc,
|
|||||||
|
|
||||||
static PyObject *StrokeVertexIterator_object_get(BPy_StrokeVertexIterator *self, void *UNUSED(closure))
|
static PyObject *StrokeVertexIterator_object_get(BPy_StrokeVertexIterator *self, void *UNUSED(closure))
|
||||||
{
|
{
|
||||||
if (!self->reversed && self->sv_it->isEnd()) {
|
if (self->sv_it->isEnd()) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "iteration has stopped");
|
PyErr_SetString(PyExc_RuntimeError, "iteration has stopped");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -198,7 +250,7 @@ PyTypeObject StrokeVertexIterator_Type = {
|
|||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)StrokeVertexIterator_iter, /* tp_iter */
|
(getiterfunc)StrokeVertexIterator_iter, /* tp_iter */
|
||||||
(iternextfunc)StrokeVertexIterator_iternext, /* tp_iternext */
|
(iternextfunc)StrokeVertexIterator_iternext, /* tp_iternext */
|
||||||
0, /* tp_methods */
|
BPy_StrokeVertexIterator_methods, /* tp_methods */
|
||||||
0, /* tp_members */
|
0, /* tp_members */
|
||||||
BPy_StrokeVertexIterator_getseters, /* tp_getset */
|
BPy_StrokeVertexIterator_getseters, /* tp_getset */
|
||||||
&Iterator_Type, /* tp_base */
|
&Iterator_Type, /* tp_base */
|
||||||
|
Loading…
Reference in New Issue
Block a user