b2120bd63c604841c3ab60dfcb7aaee7bcfdf7b7
[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 ) {
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, i );
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                         makeknots( nurb, 1, nurb->flagu >> 1 );
573
574                 } else {
575                         return EXPP_ReturnPyObjError( PyExc_TypeError,
576                                         "expected a sequence of 4 or 5 floats" );
577                 }
578
579         } else {
580                 /* bail with error */
581                 return EXPP_ReturnPyObjError( PyExc_TypeError,
582                                         "expected a sequence of 4 or 5 floats" );
583
584         }
585
586         Py_RETURN_NONE;
587 }
588
589
590 /*
591  *  CurNurb_setMatIndex
592  *
593  *  set index into material list
594  */
595
596 static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args )
597 {
598         printf ("%d\n", self->nurb->mat_nr);
599         return EXPP_setIValueRange( args, &self->nurb->mat_nr, 0, 15, 'h' );
600 }
601
602 /*
603  * CurNurb_getMatIndex
604  *
605  * returns index into material list
606  */
607
608 static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self )
609 {
610         PyObject *index = PyInt_FromLong( ( long ) self->nurb->mat_nr );
611
612         if( index )
613                 return index;
614
615         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
616                         "could not get material index" );
617 }
618
619 /*
620  * CurNurb_getFlagU
621  *
622  * returns curve's flagu
623  */
624
625 static PyObject *CurNurb_getFlagU( BPy_CurNurb * self )
626 {
627         PyObject *flagu = PyInt_FromLong( ( long ) self->nurb->flagu );
628
629         if( flagu )
630                 return flagu;
631
632         return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
633                                         "could not get CurNurb.flagu index" ) );
634 }
635
636 /*
637  *  CurNurb_setFlagU
638  *
639  *  set curve's flagu and recalculate the knots
640  *
641  *  Possible values: 0 - uniform, 2 - endpoints, 4 - bezier
642  *    bit 0 controls CU_CYCLIC
643  */
644
645 static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args )
646 {
647         PyObject* integer = PyNumber_Int( args );
648         short value;
649
650         if( !integer )
651                 return EXPP_ReturnIntError( PyExc_TypeError,
652                                 "expected integer argument" );
653
654         value = ( short )PyInt_AS_LONG( integer );
655         Py_DECREF( integer );
656
657         if( value < 0 || value > 5 )
658                 return EXPP_ReturnIntError( PyExc_ValueError,
659                                 "expected integer argument in range [0,5]" );
660
661         if( self->nurb->flagu != value ) {
662                 self->nurb->flagu = (short)value;
663                 makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
664         }
665
666         return 0;
667 }
668
669 /*
670  * CurNurb_getFlagV
671  *
672  * returns curve's flagu
673  */
674
675 static PyObject *CurNurb_getFlagV( BPy_CurNurb * self )
676 {
677         PyObject *flagv = PyInt_FromLong( ( long ) self->nurb->flagv );
678
679         if( flagv )
680                 return flagv;
681
682         return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
683                                         "could not get CurNurb.flagv" ) );
684 }
685
686 /*
687  *  CurNurb_setFlagV
688  *
689  *  set curve's flagu and recalculate the knots
690  *
691  *  Possible values: 0 - uniform, 1 - endpoints, 2 - bezier
692  */
693
694 static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args )
695 {
696         PyObject* integer = PyNumber_Int( args );
697         short value;
698
699         if( !integer )
700                 return EXPP_ReturnIntError( PyExc_TypeError,
701                                 "expected integer argument" );
702
703         value = ( short )PyInt_AS_LONG( integer );
704         Py_DECREF( integer );
705
706         if( value < 0 || value > 5 )
707                 return EXPP_ReturnIntError( PyExc_ValueError,
708                                 "expected integer argument in range [0,5]" );
709
710         if( self->nurb->flagv != value ) {
711                 self->nurb->flagv = (short)value;
712                 makeknots( self->nurb, 2, self->nurb->flagv >> 1 );
713         }
714
715         return 0;
716 }
717
718 static PyObject *CurNurb_getOrderU( BPy_CurNurb * self )
719 {
720         return PyInt_FromLong( ( long ) self->nurb->orderu );
721 }
722
723 static int CurNurb_setOrderU( BPy_CurNurb * self, PyObject * args )
724 {
725         int order;
726
727         args = PyNumber_Int( args );
728         if( !args )
729                 return EXPP_ReturnIntError( PyExc_TypeError,
730                            "expected integer argument" );
731
732         order = ( int )PyInt_AS_LONG( args );
733         Py_DECREF( args );
734
735         if( order < 2 ) order = 2;
736         else if( order > 6 ) order = 6;
737
738         if( self->nurb->pntsu < order )
739                 order = self->nurb->pntsu;
740
741         self->nurb->orderu = (short)order;
742         makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
743
744         return 0;
745 }
746
747 /*
748  * CurNurb_getIter
749  *
750  * create an iterator for our CurNurb.
751  * this iterator returns the points for this CurNurb.
752  */
753
754 static PyObject *CurNurb_getIter( BPy_CurNurb * self )
755 {
756         self->bp = self->nurb->bp;
757         self->bezt = self->nurb->bezt;
758         self->atEnd = 0;
759         self->nextPoint = 0;
760
761         /* set exhausted flag if both bp and bezt are zero */
762         if( ( !self->bp ) && ( !self->bezt ) )
763                 self->atEnd = 1;
764
765         Py_INCREF( self );
766         return ( PyObject * ) self;
767 }
768
769
770 static PyObject *CurNurb_iterNext( BPy_CurNurb * self )
771 {
772         PyObject *po;           /* return value */
773         Nurb *pnurb = self->nurb;
774         int npoints = pnurb->pntsu;
775
776         /* are we at end already? */
777         if( self->atEnd )
778                 return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
779                                                 "iterator at end" ) );
780
781         if( self->nextPoint < npoints ) {
782
783                 po = CurNurb_pointAtIndex( self->nurb, self->nextPoint );
784                 self->nextPoint++;
785
786                 return po;
787
788         } else {
789                 self->atEnd = 1;        /* set flag true */
790         }
791
792         return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
793                                         "iterator at end" ) );
794 }
795
796
797
798 /*
799  * CurNurb_isNurb()
800  * test whether spline nurb or bezier
801  */
802
803 static PyObject *CurNurb_isNurb( BPy_CurNurb * self )
804 {
805         /* NOTE: a Nurb has bp and bezt pointers
806          * depending on type.
807          * It is possible both are NULL if no points exist.
808          * in that case, we return False
809          */
810
811         if( self->nurb->bp ) {
812                 Py_RETURN_TRUE;
813         } else {
814                 Py_RETURN_FALSE;
815         }
816 }
817
818 /*
819  * CurNurb_isCyclic()
820  * test whether spline cyclic (closed) or not (open)
821  */
822
823 static PyObject *CurNurb_isCyclic( BPy_CurNurb * self )
824 {
825         /* supposing that the flagu is always set */ 
826
827         if( self->nurb->flagu & CU_CYCLIC ) {
828                 Py_RETURN_TRUE;
829         } else {
830                 Py_RETURN_FALSE;
831         }
832 }
833
834 /*
835  * CurNurb_length
836  * returns the number of points in a Nurb
837  * this is a tp_as_sequence method, not a regular instance method.
838  */
839
840 static int CurNurb_length( PyInstanceObject * inst )
841 {
842         Nurb *nurb;
843         int len;
844
845         if( BPy_CurNurb_Check( ( PyObject * ) inst ) ) {
846                 nurb = ( ( BPy_CurNurb * ) inst )->nurb;
847                 len = nurb->pntsu;
848                 return len;
849         }
850
851         return EXPP_ReturnIntError( PyExc_RuntimeError,
852                                     "arg is not a BPy_CurNurb" );
853 }
854
855 /*
856  * CurNurb_getPoint
857  * returns the Nth point in a Nurb
858  * this is one of the tp_as_sequence methods, hence the int N argument.
859  * it is called via the [] operator, not as a usual instance method.
860  */
861
862 PyObject *CurNurb_getPoint( BPy_CurNurb * self, int index )
863 {
864         Nurb *myNurb;
865
866         int npoints;
867
868         /* for convenince */
869         myNurb = self->nurb;
870         npoints = myNurb->pntsu;
871
872         /* DELETED: bail if index < 0 */
873         /* actually, this check is not needed since python treats */
874         /* negative indices as starting from the right end of a sequence */
875         /* 
876         THAT IS WRONG, when passing a negative index, python adjusts it to be positive
877         BUT it can still overflow in the negatives if the index is too small.
878         For example, list[-6] when list contains 5 items means index = -1 in here.
879         (theeth)
880         */
881
882         /* bail if no Nurbs in Curve */
883         if( npoints == 0 )
884                 return ( EXPP_ReturnPyObjError( PyExc_IndexError,
885                                                 "no points in this CurNurb" ) );
886
887         /* check index limits */
888         if( index >= npoints || index < 0 )
889                 return ( EXPP_ReturnPyObjError( PyExc_IndexError,
890                                                 "index out of range" ) );
891
892         return CurNurb_pointAtIndex( myNurb, index );
893 }
894
895 /*
896  * CurNurb_setPoint
897  * modifies the Nth point in a Nurb
898  * this is one of the tp_as_sequence methods, hence the int N argument.
899  * it is called via the [] = operator, not as a usual instance method.
900  */
901 static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * pyOb )
902 {
903         Nurb *nurb = self->nurb;
904         int size;
905
906         /* check index limits */
907         if( index < 0 || index >= nurb->pntsu )
908                 return EXPP_ReturnIntError( PyExc_IndexError,
909                                             "array assignment index out of range" );
910
911
912         /* branch by curve type */
913         if ((nurb->type & 7)==CU_BEZIER) {      /* BEZIER */
914                 /* check parameter type */
915                 if( !BPy_BezTriple_Check( pyOb ) )
916                         return EXPP_ReturnIntError( PyExc_TypeError,
917                                                         "expected a BezTriple" );
918
919                 /* copy bezier in array */
920                 memcpy( nurb->bezt + index,
921                         BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) );
922
923                 return 0;       /* finished correctly */
924         }
925         else {  /* NURBS or POLY */
926                 int i;
927
928                 /* check parameter type */
929                 if (!PySequence_Check( pyOb ))
930                         return EXPP_ReturnIntError( PyExc_TypeError,
931                                                         "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
932
933                 size = PySequence_Size( pyOb );
934
935                 /* check sequence size */
936                 if( size != 4 && size != 5 ) 
937                         return EXPP_ReturnIntError( PyExc_TypeError,
938                                                         "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
939
940                 /* copy x, y, z, w */
941                 for( i = 0; i < 4; ++i ) {
942                         PyObject *item = PySequence_GetItem( pyOb, i );
943
944                         if (item == NULL)
945                                 return -1;
946
947                         nurb->bp[index].vec[i] = ( float ) PyFloat_AsDouble( item );
948                         Py_DECREF( item );
949                 }
950
951                 if (size == 5) {        /* set tilt, if present */
952                         PyObject *item = PySequence_GetItem( pyOb, i );
953
954                         if (item == NULL)
955                                 return -1;
956
957                         nurb->bp[index].alfa = ( float ) PyFloat_AsDouble( item );
958                         Py_DECREF( item );
959                 }
960                 else {                          /* if not, set default  */
961                         nurb->bp[index].alfa = 0.0f;
962                 }
963
964                 return 0;       /* finished correctly */
965         }
966 }
967
968
969 /* 
970  * this is an internal routine.  not callable directly from python
971  */
972
973 PyObject *CurNurb_pointAtIndex( Nurb * nurb, int index )
974 {
975         PyObject *pyo;
976
977         if( nurb->bp ) {        /* we have a nurb curve */
978                 int i;
979
980                 /* add Tilt only if curve is 3D */
981                 if (nurb->flag & CU_3D)
982                         pyo = PyList_New( 5 );
983                 else
984                         pyo = PyList_New( 4 );
985
986                 for( i = 0; i < 4; i++ ) {
987                         PyList_SetItem( pyo, i,
988                                         PyFloat_FromDouble( nurb->bp[index].vec[i] ) );
989                 }
990
991                 /* add Tilt only if curve is 3D */
992                 if (nurb->flag & CU_3D)
993                         PyList_SetItem( pyo, 4, PyFloat_FromDouble( nurb->bp[index].alfa ) );
994
995         } else if( nurb->bezt ) {       /* we have a bezier */
996                 /* if an error occurs, we just pass it on */
997                 pyo = BezTriple_CreatePyObject( &( nurb->bezt[index] ) );
998
999         } else                  /* something is horribly wrong */
1000                 /* neither bp or bezt is set && pntsu != 0 */
1001                 return EXPP_ReturnPyObjError( PyExc_SystemError,
1002                                                 "inconsistant structure found" );
1003
1004         return pyo;
1005 }
1006
1007 /*
1008   dump nurb
1009 */
1010
1011 PyObject *CurNurb_dump( BPy_CurNurb * self )
1012 {
1013         BPoint *bp = NULL;
1014         BezTriple *bezt = NULL;
1015         Nurb *nurb = self->nurb;
1016         int npoints = 0;
1017
1018         if( !self->nurb )
1019                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1020                                 "no Nurb in this CurNurb");
1021
1022         printf(" type: %d, mat_nr: %d hide: %d flag: %d",
1023                    nurb->type, nurb->mat_nr, nurb->hide, nurb->flag);
1024         printf("\n pntsu: %d, pntsv: %d, resolu: %d resolv: %d",
1025                    nurb->pntsu, nurb->pntsv, nurb->resolu, nurb->resolv );
1026         printf("\n orderu: %d  orderv: %d", nurb->orderu, nurb->orderv );
1027         printf("\n flagu: %d flagv: %d",
1028                    nurb->flagu, nurb->flagv );
1029
1030         npoints = nurb->pntsu;
1031
1032         if( nurb->bp ) { /* we have a BPoint  */
1033                 int n;
1034                 for( n = 0, bp = nurb->bp;
1035                          n < npoints;
1036                          n++, bp++ )
1037                 {
1038                         /* vec[4] */
1039                         printf( "\ncoords[%d]: ", n);
1040                         {
1041                                 int i;
1042                                 for( i = 0; i < 4; i++){
1043                                         printf("%10.3f ", bp->vec[i] );
1044                                 }
1045                         }
1046                 
1047                         /* alfa, s[2] */
1048                         printf("\n alpha: %5.2f", bp->alfa);
1049                         /* f1, hide */
1050                         printf(" f1 %d  hide %d", bp->f1, bp->hide );
1051                         printf("\n");
1052                 }
1053         }
1054         else { /* we have a BezTriple */
1055                 int n;
1056                 for( n = 0, bezt = nurb->bezt;
1057                          n < npoints;
1058                          n++, bezt++ )
1059                 {
1060                         int i, j;
1061                         printf("\npoint %d: ", n);
1062                         for( i = 0; i < 3; i++ ) {
1063                                 printf("\nvec[%i] ",i );
1064                                 for( j = 0; j < 3; j++ ) {
1065                                         printf(" %5.2f ", bezt->vec[i][j] );
1066                                 }
1067                         }
1068                                 
1069
1070                 }
1071                 printf("\n");
1072         }
1073
1074         Py_RETURN_NONE;
1075 }
1076
1077 /*
1078   recalc nurb
1079 */
1080
1081 static PyObject *CurNurb_recalc( BPy_CurNurb * self )
1082 {
1083         calchandlesNurb ( self->nurb );
1084         Py_RETURN_NONE;
1085 }
1086
1087 PyObject *CurNurb_switchDirection( BPy_CurNurb * self )
1088 {
1089         if( !self->nurb )
1090                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1091                                 "no Nurb in this CurNurb");
1092         
1093         switchdirectionNurb( self->nurb );
1094         
1095         Py_RETURN_NONE;
1096 }
1097
1098 PyObject *CurNurb_Init( void )
1099 {
1100         if( PyType_Ready( &CurNurb_Type ) < 0)
1101                 return NULL;
1102
1103         return Py_InitModule3( "Blender.CurNurb", M_CurNurb_methods,
1104                                 M_CurNurb_doc );
1105 }
1106
1107 /* #####DEPRECATED###### */
1108
1109 static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args )
1110 {
1111         return EXPP_setterWrapper( (void *)self, args,
1112                         (setter)CurNurb_setType );
1113 }
1114
1115 static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args )
1116 {
1117         return EXPP_setterWrapper( (void *)self, args,
1118                         (setter)CurNurb_setMatIndex );
1119 }
1120
1121 static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args )
1122 {
1123         return EXPP_setterWrapper( (void *)self, args,
1124                         (setter)CurNurb_setFlagU );
1125 }
1126
1127 static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args )
1128 {
1129         return EXPP_setterWrapper( (void *)self, args,
1130                         (setter)CurNurb_setFlagV );
1131 }