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