fix for [#17895] Python-generated Curves can't be beveled
[blender-staging.git] / source / blender / python / api2_2x / CurNurb.c
1 /*
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * This is a new part of Blender.
23  *
24  * Contributor(s): Stephen Swaney, Campbell Barton, Ken Hughes
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include "CurNurb.h" /*This must come first */
30
31 #include "BKE_curve.h"
32 #include "BDR_editcurve.h"      /* for convertspline */
33 #include "MEM_guardedalloc.h"
34 #include "gen_utils.h"
35 #include "BezTriple.h"
36
37 #include "BKE_utildefines.h"
38
39 /* Only for ME_SMOOTH */
40 #include "DNA_meshdata_types.h"
41
42 /*
43  * forward declarations go here
44  */
45
46 static PyObject *M_CurNurb_New( PyObject * self, PyObject * args );
47 static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args );
48 static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args );
49 static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self );
50 static PyObject *CurNurb_getFlagU( BPy_CurNurb * self );
51 static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args );
52 static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args );
53 static PyObject *CurNurb_getFlagV( BPy_CurNurb * self );
54 static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args );
55 static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args );
56 static PyObject *CurNurb_getOrderU( BPy_CurNurb * self );
57 static int CurNurb_setOrderU( BPy_CurNurb * self, PyObject * args );
58 static PyObject *CurNurb_getType( BPy_CurNurb * self );
59 static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args );
60 static int CurNurb_setType( BPy_CurNurb * self, PyObject * args );
61 static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self );
62 static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self );
63 static PyObject *CurNurb_getPoints( BPy_CurNurb * self );
64 /* static PyObject* CurNurb_setXXX( BPy_CurNurb* self, PyObject* args ); */
65 static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * ob );
66 static int CurNurb_length( PyInstanceObject * inst );
67 static PyObject *CurNurb_getIter( BPy_CurNurb * self );
68 static PyObject *CurNurb_iterNext( BPy_CurNurb * self );
69 PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value );
70
71 static PyObject *CurNurb_isNurb( BPy_CurNurb * self );
72 static PyObject *CurNurb_isCyclic( BPy_CurNurb * self );
73 static PyObject *CurNurb_dump( BPy_CurNurb * self );
74 static PyObject *CurNurb_switchDirection( BPy_CurNurb * self );
75 static PyObject *CurNurb_recalc( BPy_CurNurb * self );
76 static PyObject *CurNurb_getFlagBits( BPy_CurNurb * self, void *type );
77 static int CurNurb_setFlagBits( BPy_CurNurb * self, PyObject *value, void *type );
78 char M_CurNurb_doc[] = "CurNurb";
79
80
81 /*      
82   CurNurb_Type callback function prototypes:                          
83 */
84
85 static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b );
86 static PyObject *CurNurb_repr( BPy_CurNurb * self );
87
88 /*
89    table of module methods
90    these are the equivalent of class or static methods.
91    you do not need an object instance to call one.
92   
93 */
94
95 static PyMethodDef M_CurNurb_methods[] = {
96 /*   name, method, flags, doc_string                */
97         {"New", ( PyCFunction ) M_CurNurb_New, METH_VARARGS | METH_KEYWORDS,
98          " () - doc string"},
99 /*  {"Get", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */
100 /*   {"method", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */
101
102         {NULL, NULL, 0, NULL}
103 };
104
105
106
107 /*
108  * method table
109  * table of instance methods
110  * these methods are invoked on an instance of the type.
111 */
112
113 static PyMethodDef BPy_CurNurb_methods[] = {
114 /*   name,     method,                    flags,         doc               */
115 /*  {"method", (PyCFunction) CurNurb_method, METH_NOARGS, " () - doc string"} */
116         {"setMatIndex", ( PyCFunction ) CurNurb_oldsetMatIndex, METH_VARARGS,
117          "( index ) - set index into materials list"},
118         {"getMatIndex", ( PyCFunction ) CurNurb_getMatIndex, METH_NOARGS,
119          "( ) - get current material index"},
120         {"setFlagU", ( PyCFunction ) CurNurb_oldsetFlagU, METH_VARARGS,
121          "( index ) - set flagU and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"},
122         {"getFlagU", ( PyCFunction ) CurNurb_getFlagU, METH_NOARGS,
123          "( ) - get flagU of the knots"},
124         {"setFlagV", ( PyCFunction ) CurNurb_oldsetFlagV, METH_VARARGS,
125          "( index ) - set flagV and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"},
126         {"getFlagV", ( PyCFunction ) CurNurb_getFlagV, METH_NOARGS,
127          "( ) - get flagV of the knots"},
128         {"setType", ( PyCFunction ) CurNurb_oldsetType, METH_VARARGS,
129          "( type ) - change the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"},
130         {"getType", ( PyCFunction ) CurNurb_getType, METH_NOARGS,
131          "( ) - get the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"},
132         {"append", ( PyCFunction ) CurNurb_append, METH_O,
133          "( point ) - add a new point.  arg is BezTriple or list of x,y,z,w floats"},
134         {"isNurb", ( PyCFunction ) CurNurb_isNurb, METH_NOARGS,
135          "( ) - boolean function tests if this spline is type nurb or bezier"},
136         {"isCyclic", ( PyCFunction ) CurNurb_isCyclic, METH_NOARGS,
137          "( ) - boolean function tests if this spline is cyclic (closed) or not (open)"},
138         {"dump", ( PyCFunction ) CurNurb_dump, METH_NOARGS,
139          "( ) - dumps Nurb data)"},
140         {"switchDirection", ( PyCFunction ) CurNurb_switchDirection, METH_NOARGS,
141          "( ) - swaps curve beginning and end)"},
142         {"recalc", ( PyCFunction ) CurNurb_recalc, METH_NOARGS,
143          "( ) - recalc Nurb data)"},
144         {NULL, NULL, 0, NULL}
145 };
146
147 /* 
148  *   methods for CurNurb as sequece
149  */
150
151 static PySequenceMethods CurNurb_as_sequence = {
152         ( inquiry ) CurNurb_length,     /* sq_length   */
153         ( binaryfunc ) 0,       /* sq_concat */
154         ( intargfunc ) 0,       /* sq_repeat */
155         ( intargfunc ) CurNurb_getPoint,        /* sq_item */
156         ( intintargfunc ) 0,    /* sq_slice */
157         ( intobjargproc ) CurNurb_setPoint,     /* sq_ass_item */
158         0,                      /* sq_ass_slice */
159         ( objobjproc ) 0,       /* sq_contains */
160         0,
161         0
162 };
163
164 static PyGetSetDef BPy_CurNurb_getseters[] = {
165         {"mat_index",
166          (getter)CurNurb_getMatIndex, (setter)CurNurb_setMatIndex,
167          "CurNurb's material index",
168          NULL},
169         {"points",
170          (getter)CurNurb_getPoints, (setter)NULL,
171          "The number of curve points",
172          NULL},
173         {"flagU",
174          (getter)CurNurb_getFlagU, (setter)CurNurb_setFlagU,
175          "The knot type in the U direction",
176          NULL},
177         {"flagV",
178          (getter)CurNurb_getFlagV, (setter)CurNurb_setFlagV,
179          "The knot type in the V direction",
180          NULL},
181         {"orderU",
182          (getter)CurNurb_getOrderU, (setter)CurNurb_setOrderU,
183          "order setting for U direction", NULL},
184         {"type",
185          (getter)CurNurb_getType, (setter)CurNurb_setType,
186          "The curve type (poly: bezier, or NURBS)",
187          NULL},
188         {"knotsU",
189          (getter)CurNurb_getKnotsU, (setter)NULL,
190          "The The knot vector in the U direction",
191          NULL},
192         {"knotsV",
193          (getter)CurNurb_getKnotsV, (setter)NULL,
194          "The The knot vector in the V direction",
195          NULL},
196         {"smooth",
197          (getter)CurNurb_getFlagBits, (setter)CurNurb_setFlagBits,
198          "The smooth bool setting",
199          (void *)ME_SMOOTH},
200         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
201 };
202
203 /*
204   Object Type definition
205   full blown 2.3 struct
206   if you are having trouble building with an earlier version of python,
207    this is why.
208 */
209
210 PyTypeObject CurNurb_Type = {
211         PyObject_HEAD_INIT( NULL ) /* required py macro */
212         0,      /* ob_size */
213         /*  For printing, in format "<module>.<name>" */
214         "CurNurb",              /* char *tp_name; */
215         sizeof( CurNurb_Type ), /* int tp_basicsize, */
216         0,                      /* tp_itemsize;  For allocation */
217
218         /* Methods to implement standard operations */
219
220         NULL,                                   /*    destructor tp_dealloc; */
221         NULL,                                   /*    printfunc tp_print; */
222         NULL,                                   /*    getattrfunc tp_getattr; */
223         NULL,                                   /*    setattrfunc tp_setattr; */
224         ( cmpfunc ) CurNurb_compare,    /*    cmpfunc tp_compare; */
225         ( reprfunc ) CurNurb_repr,      /*    reprfunc tp_repr; */
226
227         /* Method suites for standard classes */
228
229         0,                      /*    PyNumberMethods *tp_as_number; */
230         &CurNurb_as_sequence,   /*    PySequenceMethods *tp_as_sequence; */
231         0,                      /*    PyMappingMethods *tp_as_mapping; */
232
233         /* More standard operations (here for binary compatibility) */
234
235         0,                      /*    hashfunc tp_hash; */
236         0,                      /*    ternaryfunc tp_call; */
237         0,                      /*    reprfunc tp_str; */
238         0,                      /*    getattrofunc tp_getattro; */
239         0,                      /*    setattrofunc tp_setattro; */
240
241         /* Functions to access object as input/output buffer */
242         0,                      /*    PyBufferProcs *tp_as_buffer; */
243
244   /*** Flags to define presence of optional/expanded features ***/
245         Py_TPFLAGS_DEFAULT,     /*    long tp_flags; */
246
247         0,                      /*  char *tp_doc;  Documentation string */
248   /*** Assigned meaning in release 2.0 ***/
249         /* call function for all accessible objects */
250         0,                      /*    traverseproc tp_traverse; */
251
252         /* delete references to contained objects */
253         0,                      /*    inquiry tp_clear; */
254
255   /***  Assigned meaning in release 2.1 ***/
256   /*** rich comparisons ***/
257         0,                      /*  richcmpfunc tp_richcompare; */
258
259   /***  weak reference enabler ***/
260         0,                      /* long tp_weaklistoffset; */
261
262   /*** Added in release 2.2 ***/
263         /*   Iterators */
264         ( getiterfunc ) CurNurb_getIter,        /*    getiterfunc tp_iter; */
265         ( iternextfunc ) CurNurb_iterNext,      /*    iternextfunc tp_iternext; */
266
267   /*** Attribute descriptor and subclassing stuff ***/
268         BPy_CurNurb_methods,    /*    struct PyMethodDef *tp_methods; */
269         0,                      /*    struct PyMemberDef *tp_members; */
270         BPy_CurNurb_getseters,                  /*    struct PyGetSetDef *tp_getset; */
271         0,                      /*    struct _typeobject *tp_base; */
272         0,                      /*    PyObject *tp_dict; */
273         0,                      /*    descrgetfunc tp_descr_get; */
274         0,                      /*    descrsetfunc tp_descr_set; */
275         0,                      /*    long tp_dictoffset; */
276         0,                      /*    initproc tp_init; */
277         0,                      /*    allocfunc tp_alloc; */
278         0,                      /*    newfunc tp_new; */
279         /*  Low-level free-memory routine */
280         0,                      /*    freefunc tp_free;  */
281         /* For PyObject_IS_GC */
282         0,                      /*    inquiry tp_is_gc;  */
283         0,                      /*    PyObject *tp_bases; */
284         /* method resolution order */
285         0,                      /*    PyObject *tp_mro;  */
286         0,                      /*    PyObject *tp_cache; */
287         0,                      /*    PyObject *tp_subclasses; */
288         0,                      /*    PyObject *tp_weaklist; */
289         0
290 };
291
292 /*
293   compare
294   in this case, we consider two CurNurbs equal, if they point to the same
295   blender data.
296 */
297
298 static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b )
299 {
300         Nurb *pa = a->nurb;
301         Nurb *pb = b->nurb;
302
303         return ( pa == pb ) ? 0 : -1;
304 }
305
306
307 /*
308   factory method to create a BPy_CurNurb from a Blender Nurb
309 */
310
311 PyObject *CurNurb_CreatePyObject( Nurb * blen_nurb )
312 {
313         BPy_CurNurb *pyNurb;
314
315         pyNurb = ( BPy_CurNurb * ) PyObject_NEW( BPy_CurNurb, &CurNurb_Type );
316
317         if( !pyNurb )
318                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
319                                               "could not create BPy_CurNurb PyObject" );
320
321         pyNurb->nurb = blen_nurb;
322         return ( PyObject * ) pyNurb;
323 }
324
325
326 /*
327  *  CurNurb_repr
328  */
329 static PyObject *CurNurb_repr( BPy_CurNurb * self )
330 {                               /* used by 'repr' */
331
332         return PyString_FromFormat( "[CurNurb \"%d\"]", self->nurb->type );
333 }
334
335 /* XXX Can't this be simply removed? */
336 static PyObject *M_CurNurb_New( PyObject * self, PyObject * args )
337 {
338         return ( PyObject * ) 0;
339
340 }
341
342 /*
343  *      Curve.getType
344  */
345 static PyObject *CurNurb_getType( BPy_CurNurb * self )
346 {
347         /* type is on 3 first bits only */
348         return PyInt_FromLong( self->nurb->type & 7 );
349 }
350
351 /*
352  *      Curve.setType
353  *
354  *      Convert the curve using Blender's convertspline fonction
355  */
356 static int CurNurb_setType( BPy_CurNurb * self, PyObject * args )
357 {
358         PyObject* integer = PyNumber_Int( args );
359         short value;
360
361         if( !integer )
362                 return EXPP_ReturnIntError( PyExc_TypeError,
363                                 "expected integer argument" );
364
365         value = ( short )PyInt_AS_LONG( integer );
366         Py_DECREF( integer );
367
368         /* parameter value checking */
369         if (value != CU_POLY && value != CU_BEZIER && value != CU_NURBS)
370                 return EXPP_ReturnIntError( PyExc_ValueError,
371                                 "expected integer argument" );
372
373         /* convert and raise error if impossible */
374         if (convertspline(value, self->nurb))
375                 return EXPP_ReturnIntError( PyExc_ValueError,
376                                 "Conversion Impossible" );
377
378         return 0;
379 }
380
381 /*
382  * CurNurb_getKnotsU
383  *
384  * returns curve's knotsU in a tuple. Empty tuple is returned if curve
385  * isn't Nurbs or it doesn't have knots in U
386  */
387
388 static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self )
389 {
390         if(self->nurb->knotsu) {
391                 int len = KNOTSU(self->nurb);
392                 int i;
393                 PyObject *knotsu = PyTuple_New(len);
394                 if( !knotsu )
395                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
396                                         "could not get CurNurb.knotsU attribute" );
397
398                 for(i = 0; i < len; ++i)
399                         PyTuple_SetItem(knotsu, i,
400                                         PyFloat_FromDouble(self->nurb->knotsu[i]));
401
402                 return knotsu;
403         }
404         return PyTuple_New(0);
405 }
406
407 /*
408  * CurNurb_getKnotsV
409  *
410  * returns curve's knotsV in a tuple. Empty tuple is returned if curve doesn't have knots in V
411  */
412
413 static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self )
414 {
415         if(self->nurb->knotsv) {
416                 int len = KNOTSV(self->nurb);
417                 int i;
418                 PyObject *knotsv = PyTuple_New(len);
419                 if( !knotsv )
420                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
421                                         "could not get CurNurb.knotsV index" );
422
423                 for(i = 0; i < len; ++i)
424                         PyTuple_SetItem(knotsv, i,
425                                         PyFloat_FromDouble(self->nurb->knotsv[i] ));
426         
427                 return knotsv;
428         }
429         return PyTuple_New(0);
430 }
431
432 static PyObject *CurNurb_getPoints( BPy_CurNurb * self )
433 {
434         return PyInt_FromLong( ( long ) self->nurb->pntsu );
435 }
436
437 static PyObject *CurNurb_getFlagBits( BPy_CurNurb * self, void *type )
438 {
439         return EXPP_getBitfield( (void *)&self->nurb->flag,
440                                                           GET_INT_FROM_POINTER(type), 'h' );
441 }
442
443 static int CurNurb_setFlagBits( BPy_CurNurb * self, PyObject *value,
444                                                                         void *type )
445 {
446         return EXPP_setBitfield( value, (void *)&self->nurb->flag,
447                                                          GET_INT_FROM_POINTER(type), 'h' );
448 }
449
450 /*
451  * CurNurb_append( point )
452  * append a new point to a nurb curve.
453  * arg is BezTriple or list of xyzw floats 
454  */
455
456 PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value )
457 {
458         return CurNurb_appendPointToNurb( self->nurb, value );
459 }
460
461
462 /*
463  * CurNurb_appendPointToNurb
464  * this is a non-bpy utility func to add a point to a given nurb.
465  * notice the first arg is Nurb*.
466  */
467
468 PyObject *CurNurb_appendPointToNurb( Nurb * nurb, PyObject * value )
469 {
470
471         int i;
472         int size;
473         int npoints = nurb->pntsu;
474
475         /*
476            do we have a list of four floats or a BezTriple?
477         */
478         
479         /* if curve is empty, adjust type depending on input type */
480         if (nurb->bezt==NULL && nurb->bp==NULL) {
481                 if (BPy_BezTriple_Check( value ))
482                         nurb->type |= CU_BEZIER;
483                 else if (PySequence_Check( value ))
484                         nurb->type |= CU_NURBS;
485                 else
486                         return( EXPP_ReturnPyObjError( PyExc_TypeError,
487                                           "Expected a BezTriple or a Sequence of 4 (or 5) floats" ) );
488         }
489
490
491
492         if ((nurb->type & 7)==CU_BEZIER) {
493                 BezTriple *tmp;
494
495                 if( !BPy_BezTriple_Check( value ) )
496                         return( EXPP_ReturnPyObjError( PyExc_TypeError,
497                                           "Expected a BezTriple\n" ) );
498
499 /*              printf("\ndbg: got a BezTriple\n"); */
500                 tmp = nurb->bezt;       /* save old points */
501                 nurb->bezt =
502                         ( BezTriple * ) MEM_mallocN( sizeof( BezTriple ) *
503                                                      ( npoints + 1 ),
504                                                      "CurNurb_append2" );
505
506                 if( !nurb->bezt )
507                         return ( EXPP_ReturnPyObjError
508                                  ( PyExc_MemoryError, "allocation failed" ) );
509
510                 /* copy old points to new */
511                 if( tmp ) {
512                         memmove( nurb->bezt, tmp, sizeof( BezTriple ) * npoints );
513                         MEM_freeN( tmp );
514                 }
515
516                 nurb->pntsu++;
517                 /* add new point to end of list */
518                 memcpy( nurb->bezt + npoints,
519                         BezTriple_FromPyObject( value ), sizeof( BezTriple ) );
520
521         }
522         else if( PySequence_Check( value ) ) {
523                 size = PySequence_Size( value );
524 /*              printf("\ndbg: got a sequence of size %d\n", size );  */
525                 if( size == 4 || size == 5 || size == 6) {
526                         BPoint *tmp;
527
528                         tmp = nurb->bp; /* save old pts */
529
530                         nurb->bp =
531                                 ( BPoint * ) MEM_mallocN( sizeof( BPoint ) *
532                                                           ( npoints + 1 ),
533                                                           "CurNurb_append1" );
534                         if( !nurb->bp )
535                                 return ( EXPP_ReturnPyObjError
536                                          ( PyExc_MemoryError,
537                                            "allocation failed" ) );
538
539                         memmove( nurb->bp, tmp, sizeof( BPoint ) * npoints );
540                         if( tmp )
541                                 MEM_freeN( tmp );
542
543                         ++nurb->pntsu;
544                         /* initialize new BPoint from old */
545                         memcpy( nurb->bp + npoints, nurb->bp,
546                                 sizeof( BPoint ) );
547
548                         for( i = 0; i < 4; ++i ) {
549                                 PyObject *item = PySequence_GetItem( value, i );
550
551                                 if (item == NULL)
552                                         return NULL;
553
554
555                                 nurb->bp[npoints].vec[i] = ( float ) PyFloat_AsDouble( item );
556                                 Py_DECREF( item );
557                         }
558
559                         if (size >= 5) {
560                                 PyObject *item = PySequence_GetItem( value, 4 );
561
562                                 if (item == NULL)
563                                         return NULL;
564
565                                 nurb->bp[npoints].alfa = ( float ) PyFloat_AsDouble( item );
566                                 Py_DECREF( item );
567                         }
568                         else {
569                                 nurb->bp[npoints].alfa = 0.0f;
570                         }
571                         
572                         if (size == 6) {
573                                 PyObject *item = PySequence_GetItem( value, 5 );
574
575                                 if (item == NULL)
576                                         return NULL;
577
578                                 nurb->bp[npoints].radius = ( float ) PyFloat_AsDouble( item );
579                                 Py_DECREF( item );
580                         }
581                         else {
582                                 nurb->bp[npoints].radius = 1.0f;
583                         }
584                         
585                         nurb->bp[npoints].weight = 0.0; /* softbody weight TODO - add access to this, is zero elsewhere but through blender is 1.0 by default */
586                         
587                         makeknots( nurb, 1, nurb->flagu >> 1 );
588
589                 } else {
590                         return EXPP_ReturnPyObjError( PyExc_TypeError,
591                                         "expected a sequence of 4 or 6 floats" );
592                 }
593
594         } else {
595                 /* bail with error */
596                 return EXPP_ReturnPyObjError( PyExc_TypeError,
597                                         "expected a sequence of 4 to 6 floats" );
598
599         }
600
601         Py_RETURN_NONE;
602 }
603
604
605 /*
606  *  CurNurb_setMatIndex
607  *
608  *  set index into material list
609  */
610
611 static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args )
612 {
613         printf ("%d\n", self->nurb->mat_nr);
614         return EXPP_setIValueRange( args, &self->nurb->mat_nr, 0, 15, 'h' );
615 }
616
617 /*
618  * CurNurb_getMatIndex
619  *
620  * returns index into material list
621  */
622
623 static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self )
624 {
625         PyObject *index = PyInt_FromLong( ( long ) self->nurb->mat_nr );
626
627         if( index )
628                 return index;
629
630         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
631                         "could not get material index" );
632 }
633
634 /*
635  * CurNurb_getFlagU
636  *
637  * returns curve's flagu
638  */
639
640 static PyObject *CurNurb_getFlagU( BPy_CurNurb * self )
641 {
642         PyObject *flagu = PyInt_FromLong( ( long ) self->nurb->flagu );
643
644         if( flagu )
645                 return flagu;
646
647         return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
648                                         "could not get CurNurb.flagu index" ) );
649 }
650
651 /*
652  *  CurNurb_setFlagU
653  *
654  *  set curve's flagu and recalculate the knots
655  *
656  *  Possible values: 0 - uniform, 2 - endpoints, 4 - bezier
657  *    bit 0 controls CU_CYCLIC
658  */
659
660 static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args )
661 {
662         PyObject* integer = PyNumber_Int( args );
663         short value;
664
665         if( !integer )
666                 return EXPP_ReturnIntError( PyExc_TypeError,
667                                 "expected integer argument" );
668
669         value = ( short )PyInt_AS_LONG( integer );
670         Py_DECREF( integer );
671
672         if( value < 0 || value > 5 )
673                 return EXPP_ReturnIntError( PyExc_ValueError,
674                                 "expected integer argument in range [0,5]" );
675
676         if( self->nurb->flagu != value ) {
677                 self->nurb->flagu = (short)value;
678                 makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
679         }
680
681         return 0;
682 }
683
684 /*
685  * CurNurb_getFlagV
686  *
687  * returns curve's flagu
688  */
689
690 static PyObject *CurNurb_getFlagV( BPy_CurNurb * self )
691 {
692         PyObject *flagv = PyInt_FromLong( ( long ) self->nurb->flagv );
693
694         if( flagv )
695                 return flagv;
696
697         return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
698                                         "could not get CurNurb.flagv" ) );
699 }
700
701 /*
702  *  CurNurb_setFlagV
703  *
704  *  set curve's flagu and recalculate the knots
705  *
706  *  Possible values: 0 - uniform, 1 - endpoints, 2 - bezier
707  */
708
709 static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args )
710 {
711         PyObject* integer = PyNumber_Int( args );
712         short value;
713
714         if( !integer )
715                 return EXPP_ReturnIntError( PyExc_TypeError,
716                                 "expected integer argument" );
717
718         value = ( short )PyInt_AS_LONG( integer );
719         Py_DECREF( integer );
720
721         if( value < 0 || value > 5 )
722                 return EXPP_ReturnIntError( PyExc_ValueError,
723                                 "expected integer argument in range [0,5]" );
724
725         if( self->nurb->flagv != value ) {
726                 self->nurb->flagv = (short)value;
727                 makeknots( self->nurb, 2, self->nurb->flagv >> 1 );
728         }
729
730         return 0;
731 }
732
733 static PyObject *CurNurb_getOrderU( BPy_CurNurb * self )
734 {
735         return PyInt_FromLong( ( long ) self->nurb->orderu );
736 }
737
738 static int CurNurb_setOrderU( BPy_CurNurb * self, PyObject * args )
739 {
740         int order;
741
742         args = PyNumber_Int( args );
743         if( !args )
744                 return EXPP_ReturnIntError( PyExc_TypeError,
745                            "expected integer argument" );
746
747         order = ( int )PyInt_AS_LONG( args );
748         Py_DECREF( args );
749
750         if( order < 2 ) order = 2;
751         else if( order > 6 ) order = 6;
752
753         if( self->nurb->pntsu < order )
754                 order = self->nurb->pntsu;
755
756         self->nurb->orderu = (short)order;
757         makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
758
759         return 0;
760 }
761
762 /*
763  * CurNurb_getIter
764  *
765  * create an iterator for our CurNurb.
766  * this iterator returns the points for this CurNurb.
767  */
768
769 static PyObject *CurNurb_getIter( BPy_CurNurb * self )
770 {
771         self->bp = self->nurb->bp;
772         self->bezt = self->nurb->bezt;
773         self->atEnd = 0;
774         self->nextPoint = 0;
775
776         /* set exhausted flag if both bp and bezt are zero */
777         if( ( !self->bp ) && ( !self->bezt ) )
778                 self->atEnd = 1;
779
780         Py_INCREF( self );
781         return ( PyObject * ) self;
782 }
783
784
785 static PyObject *CurNurb_iterNext( BPy_CurNurb * self )
786 {
787         PyObject *po;           /* return value */
788         Nurb *pnurb = self->nurb;
789         int npoints = pnurb->pntsu;
790
791         /* are we at end already? */
792         if( self->atEnd )
793                 return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
794                                                 "iterator at end" ) );
795
796         if( self->nextPoint < npoints ) {
797
798                 po = CurNurb_pointAtIndex( self->nurb, self->nextPoint );
799                 self->nextPoint++;
800
801                 return po;
802
803         } else {
804                 self->atEnd = 1;        /* set flag true */
805         }
806
807         return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
808                                         "iterator at end" ) );
809 }
810
811
812
813 /*
814  * CurNurb_isNurb()
815  * test whether spline nurb or bezier
816  */
817
818 static PyObject *CurNurb_isNurb( BPy_CurNurb * self )
819 {
820         /* NOTE: a Nurb has bp and bezt pointers
821          * depending on type.
822          * It is possible both are NULL if no points exist.
823          * in that case, we return False
824          */
825
826         if( self->nurb->bp ) {
827                 Py_RETURN_TRUE;
828         } else {
829                 Py_RETURN_FALSE;
830         }
831 }
832
833 /*
834  * CurNurb_isCyclic()
835  * test whether spline cyclic (closed) or not (open)
836  */
837
838 static PyObject *CurNurb_isCyclic( BPy_CurNurb * self )
839 {
840         /* supposing that the flagu is always set */ 
841
842         if( self->nurb->flagu & CU_CYCLIC ) {
843                 Py_RETURN_TRUE;
844         } else {
845                 Py_RETURN_FALSE;
846         }
847 }
848
849 /*
850  * CurNurb_length
851  * returns the number of points in a Nurb
852  * this is a tp_as_sequence method, not a regular instance method.
853  */
854
855 static int CurNurb_length( PyInstanceObject * inst )
856 {
857         Nurb *nurb;
858         int len;
859
860         if( BPy_CurNurb_Check( ( PyObject * ) inst ) ) {
861                 nurb = ( ( BPy_CurNurb * ) inst )->nurb;
862                 len = nurb->pntsu;
863                 return len;
864         }
865
866         return EXPP_ReturnIntError( PyExc_RuntimeError,
867                                     "arg is not a BPy_CurNurb" );
868 }
869
870 /*
871  * CurNurb_getPoint
872  * returns the Nth point in a Nurb
873  * this is one of the tp_as_sequence methods, hence the int N argument.
874  * it is called via the [] operator, not as a usual instance method.
875  */
876
877 PyObject *CurNurb_getPoint( BPy_CurNurb * self, int index )
878 {
879         Nurb *myNurb;
880
881         int npoints;
882
883         /* for convenince */
884         myNurb = self->nurb;
885         npoints = myNurb->pntsu;
886
887         /* DELETED: bail if index < 0 */
888         /* actually, this check is not needed since python treats */
889         /* negative indices as starting from the right end of a sequence */
890         /* 
891         THAT IS WRONG, when passing a negative index, python adjusts it to be positive
892         BUT it can still overflow in the negatives if the index is too small.
893         For example, list[-6] when list contains 5 items means index = -1 in here.
894         (theeth)
895         */
896
897         /* bail if no Nurbs in Curve */
898         if( npoints == 0 )
899                 return ( EXPP_ReturnPyObjError( PyExc_IndexError,
900                                                 "no points in this CurNurb" ) );
901
902         /* check index limits */
903         if( index >= npoints || index < 0 )
904                 return ( EXPP_ReturnPyObjError( PyExc_IndexError,
905                                                 "index out of range" ) );
906
907         return CurNurb_pointAtIndex( myNurb, index );
908 }
909
910 /*
911  * CurNurb_setPoint
912  * modifies the Nth point in a Nurb
913  * this is one of the tp_as_sequence methods, hence the int N argument.
914  * it is called via the [] = operator, not as a usual instance method.
915  */
916 static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * pyOb )
917 {
918         Nurb *nurb = self->nurb;
919         int size;
920
921         /* check index limits */
922         if( index < 0 || index >= nurb->pntsu )
923                 return EXPP_ReturnIntError( PyExc_IndexError,
924                                             "array assignment index out of range" );
925
926
927         /* branch by curve type */
928         if ((nurb->type & 7)==CU_BEZIER) {      /* BEZIER */
929                 /* check parameter type */
930                 if( !BPy_BezTriple_Check( pyOb ) )
931                         return EXPP_ReturnIntError( PyExc_TypeError,
932                                                         "expected a BezTriple" );
933
934                 /* copy bezier in array */
935                 memcpy( nurb->bezt + index,
936                         BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) );
937
938                 return 0;       /* finished correctly */
939         }
940         else {  /* NURBS or POLY */
941                 int i;
942
943                 /* check parameter type */
944                 if (!PySequence_Check( pyOb ))
945                         return EXPP_ReturnIntError( PyExc_TypeError,
946                                                         "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
947
948                 size = PySequence_Size( pyOb );
949
950                 /* check sequence size */
951                 if( size != 4 && size != 5 ) 
952                         return EXPP_ReturnIntError( PyExc_TypeError,
953                                                         "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
954
955                 /* copy x, y, z, w */
956                 for( i = 0; i < 4; ++i ) {
957                         PyObject *item = PySequence_GetItem( pyOb, i );
958
959                         if (item == NULL)
960                                 return -1;
961
962                         nurb->bp[index].vec[i] = ( float ) PyFloat_AsDouble( item );
963                         Py_DECREF( item );
964                 }
965
966                 if (size == 5) {        /* set tilt, if present */
967                         PyObject *item = PySequence_GetItem( pyOb, i );
968
969                         if (item == NULL)
970                                 return -1;
971
972                         nurb->bp[index].alfa = ( float ) PyFloat_AsDouble( item );
973                         Py_DECREF( item );
974                 }
975                 else {                          /* if not, set default  */
976                         nurb->bp[index].alfa = 0.0f;
977                 }
978
979                 return 0;       /* finished correctly */
980         }
981 }
982
983
984 /* 
985  * this is an internal routine.  not callable directly from python
986  */
987
988 PyObject *CurNurb_pointAtIndex( Nurb * nurb, int index )
989 {
990         PyObject *pyo;
991
992         if( nurb->bp ) {        /* we have a nurb curve */
993                 int i;
994
995                 /* add Tilt only if curve is 3D */
996                 if (nurb->flag & CU_3D)
997                         pyo = PyList_New( 5 );
998                 else
999                         pyo = PyList_New( 4 );
1000
1001                 for( i = 0; i < 4; i++ ) {
1002                         PyList_SetItem( pyo, i,
1003                                         PyFloat_FromDouble( nurb->bp[index].vec[i] ) );
1004                 }
1005
1006                 /* add Tilt only if curve is 3D */
1007                 if (nurb->flag & CU_3D)
1008                         PyList_SetItem( pyo, 4, PyFloat_FromDouble( nurb->bp[index].alfa ) );
1009
1010         } else if( nurb->bezt ) {       /* we have a bezier */
1011                 /* if an error occurs, we just pass it on */
1012                 pyo = BezTriple_CreatePyObject( &( nurb->bezt[index] ) );
1013
1014         } else                  /* something is horribly wrong */
1015                 /* neither bp or bezt is set && pntsu != 0 */
1016                 return EXPP_ReturnPyObjError( PyExc_SystemError,
1017                                                 "inconsistant structure found" );
1018
1019         return pyo;
1020 }
1021
1022 /*
1023   dump nurb
1024 */
1025
1026 PyObject *CurNurb_dump( BPy_CurNurb * self )
1027 {
1028         BPoint *bp = NULL;
1029         BezTriple *bezt = NULL;
1030         Nurb *nurb = self->nurb;
1031         int npoints = 0;
1032
1033         if( !self->nurb )
1034                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1035                                 "no Nurb in this CurNurb");
1036
1037         printf(" type: %d, mat_nr: %d hide: %d flag: %d",
1038                    nurb->type, nurb->mat_nr, nurb->hide, nurb->flag);
1039         printf("\n pntsu: %d, pntsv: %d, resolu: %d resolv: %d",
1040                    nurb->pntsu, nurb->pntsv, nurb->resolu, nurb->resolv );
1041         printf("\n orderu: %d  orderv: %d", nurb->orderu, nurb->orderv );
1042         printf("\n flagu: %d flagv: %d",
1043                    nurb->flagu, nurb->flagv );
1044
1045         npoints = nurb->pntsu;
1046
1047         if( nurb->bp ) { /* we have a BPoint  */
1048                 int n;
1049                 for( n = 0, bp = nurb->bp;
1050                          n < npoints;
1051                          n++, bp++ )
1052                 {
1053                         /* vec[4] */
1054                         printf( "\ncoords[%d]: ", n);
1055                         {
1056                                 int i;
1057                                 for( i = 0; i < 4; i++){
1058                                         printf("%10.3f ", bp->vec[i] );
1059                                 }
1060                         }
1061                 
1062                         /* alfa, s[2] */
1063                         printf("\n alpha: %5.2f", bp->alfa);
1064                         /* f1, hide */
1065                         printf(" f1 %d  hide %d", bp->f1, bp->hide );
1066                         printf("\n");
1067                 }
1068         }
1069         else { /* we have a BezTriple */
1070                 int n;
1071                 for( n = 0, bezt = nurb->bezt;
1072                          n < npoints;
1073                          n++, bezt++ )
1074                 {
1075                         int i, j;
1076                         printf("\npoint %d: ", n);
1077                         for( i = 0; i < 3; i++ ) {
1078                                 printf("\nvec[%i] ",i );
1079                                 for( j = 0; j < 3; j++ ) {
1080                                         printf(" %5.2f ", bezt->vec[i][j] );
1081                                 }
1082                         }
1083                                 
1084
1085                 }
1086                 printf("\n");
1087         }
1088
1089         Py_RETURN_NONE;
1090 }
1091
1092 /*
1093   recalc nurb
1094 */
1095
1096 static PyObject *CurNurb_recalc( BPy_CurNurb * self )
1097 {
1098         calchandlesNurb ( self->nurb );
1099         Py_RETURN_NONE;
1100 }
1101
1102 PyObject *CurNurb_switchDirection( BPy_CurNurb * self )
1103 {
1104         if( !self->nurb )
1105                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1106                                 "no Nurb in this CurNurb");
1107         
1108         switchdirectionNurb( self->nurb );
1109         
1110         Py_RETURN_NONE;
1111 }
1112
1113 PyObject *CurNurb_Init( void )
1114 {
1115         if( PyType_Ready( &CurNurb_Type ) < 0)
1116                 return NULL;
1117
1118         return Py_InitModule3( "Blender.CurNurb", M_CurNurb_methods,
1119                                 M_CurNurb_doc );
1120 }
1121
1122 /* #####DEPRECATED###### */
1123
1124 static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args )
1125 {
1126         return EXPP_setterWrapper( (void *)self, args,
1127                         (setter)CurNurb_setType );
1128 }
1129
1130 static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args )
1131 {
1132         return EXPP_setterWrapper( (void *)self, args,
1133                         (setter)CurNurb_setMatIndex );
1134 }
1135
1136 static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args )
1137 {
1138         return EXPP_setterWrapper( (void *)self, args,
1139                         (setter)CurNurb_setFlagU );
1140 }
1141
1142 static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args )
1143 {
1144         return EXPP_setterWrapper( (void *)self, args,
1145                         (setter)CurNurb_setFlagV );
1146 }