From 840891e22a12c7bbb7c3b8d086ef0c6ff11a24d9 Mon Sep 17 00:00:00 2001 From: Tamito Kajiyama Date: Mon, 16 Jun 2014 09:56:58 +0900 Subject: 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 --- .../python/Iterator/BPy_StrokeVertexIterator.cpp | 74 ++++++++++++++++++---- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp') diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp index 3e5051049bd..a17ad0e39d8 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp @@ -25,6 +25,7 @@ #include "BPy_StrokeVertexIterator.h" #include "../BPy_Convert.h" +#include "../Interface1D/BPy_Stroke.h" #include "BPy_Interface0DIterator.h" #ifdef __cplusplus @@ -63,20 +64,27 @@ PyDoc_STRVAR(StrokeVertexIterator_doc, static int StrokeVertexIterator_init(BPy_StrokeVertexIterator *self, PyObject *args, PyObject *kwds) { - static const char *kwlist[] = {"brother", NULL}; - PyObject *brother = 0; + static const char *kwlist_1[] = {"brother", NULL}; + static const char *kwlist_2[] = {"stroke", NULL}; + PyObject *brother = 0, *stroke = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &StrokeVertexIterator_Type, &brother)) - return -1; - if (!brother) { - self->sv_it = new StrokeInternal::StrokeVertexIterator(); + if (PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist_1, &StrokeVertexIterator_Type, &brother)) { + self->sv_it = new StrokeInternal::StrokeVertexIterator(*(((BPy_StrokeVertexIterator *)brother)->sv_it)); + self->reversed = ((BPy_StrokeVertexIterator *)brother)->reversed; + 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->at_start = true; } else { - self->sv_it = new StrokeInternal::StrokeVertexIterator(*(((BPy_StrokeVertexIterator *)brother)->sv_it)); - self->reversed = ((BPy_StrokeVertexIterator *)brother)->reversed; - self->at_start = ((BPy_StrokeVertexIterator *)brother)->at_start; + self->sv_it = new StrokeInternal::StrokeVertexIterator(); + self->reversed = false; + self->at_start = true; } self->py_it.it = self->sv_it; return 0; @@ -91,6 +99,12 @@ static PyObject *StrokeVertexIterator_iter(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->sv_it->isBegin()) { PyErr_SetNone(PyExc_StopIteration); @@ -121,6 +135,44 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) 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 ----------------------------*/ 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)) { - if (!self->reversed && self->sv_it->isEnd()) { + if (self->sv_it->isEnd()) { PyErr_SetString(PyExc_RuntimeError, "iteration has stopped"); return NULL; } @@ -198,7 +250,7 @@ PyTypeObject StrokeVertexIterator_Type = { 0, /* tp_weaklistoffset */ (getiterfunc)StrokeVertexIterator_iter, /* tp_iter */ (iternextfunc)StrokeVertexIterator_iternext, /* tp_iternext */ - 0, /* tp_methods */ + BPy_StrokeVertexIterator_methods, /* tp_methods */ 0, /* tp_members */ BPy_StrokeVertexIterator_getseters, /* tp_getset */ &Iterator_Type, /* tp_base */ -- cgit v1.2.3