9a50345fb39ba0b9055357c83b3642bad3edbf4c
[blender.git] / source / blender / python / api2_2x / Ipocurve.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * This is a new part of Blender.
27  *
28  * Contributor(s): Jacques Guignot, Nathan Letwory
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include "Ipocurve.h"
34
35 #include <BKE_main.h>
36 #include <BKE_global.h>
37 #include <BKE_object.h>
38 #include <BKE_library.h>
39 #include <BKE_ipo.h>
40 #include <BLI_blenlib.h>
41 #include <BSE_editipo.h>
42
43 #include <DNA_ipo_types.h>
44
45 #include "constant.h"
46 #include "gen_utils.h"
47 #include "BezTriple.h"
48
49 /*****************************************************************************/
50 /* Python API function prototypes for the IpoCurve module.                   */
51 /*****************************************************************************/
52 static PyObject *M_IpoCurve_New( PyObject * self, PyObject * args );
53 static PyObject *M_IpoCurve_Get( PyObject * self, PyObject * args );
54
55 /*****************************************************************************/
56 /* The following string definitions are used for documentation strings.      */
57 /* In Python these will be written to the console when doing a               */
58 /* Blender.IpoCurve.__doc__                                                  */
59 /*****************************************************************************/
60 char M_IpoCurve_doc[] = "";
61 char M_IpoCurve_New_doc[] = "";
62 char M_IpoCurve_Get_doc[] = "";
63
64 /*****************************************************************************/
65 /* Python method structure definition for Blender.IpoCurve module:           */
66 /*****************************************************************************/
67
68 struct PyMethodDef M_IpoCurve_methods[] = {
69         {"New", ( PyCFunction ) M_IpoCurve_New, METH_VARARGS | METH_KEYWORDS,
70          M_IpoCurve_New_doc},
71         {"Get", M_IpoCurve_Get, METH_VARARGS, M_IpoCurve_Get_doc},
72         {"get", M_IpoCurve_Get, METH_VARARGS, M_IpoCurve_Get_doc},
73         {NULL, NULL, 0, NULL}
74 };
75
76 /*****************************************************************************/
77 /* Python C_IpoCurve methods declarations:                                   */
78 /*****************************************************************************/
79 static PyObject *IpoCurve_getName( C_IpoCurve * self );
80 static PyObject *IpoCurve_Recalc( C_IpoCurve * self );
81 static PyObject *IpoCurve_setName( C_IpoCurve * self, PyObject * args );
82 static PyObject *IpoCurve_addBezier( C_IpoCurve * self, PyObject * args );
83 static PyObject *IpoCurve_setInterpolation( C_IpoCurve * self,
84                                             PyObject * args );
85 static PyObject *IpoCurve_getInterpolation( C_IpoCurve * self );
86 static PyObject *IpoCurve_setExtrapolation( C_IpoCurve * self,
87                                             PyObject * args );
88 static PyObject *IpoCurve_getExtrapolation( C_IpoCurve * self );
89 static PyObject *IpoCurve_getPoints( C_IpoCurve * self );
90 static int IpoCurve_setPoints( C_IpoCurve * self, PyObject * value );
91 static PyObject *IpoCurve_evaluate( C_IpoCurve * self, PyObject * args );
92
93 /*****************************************************************************/
94 /* Python C_IpoCurve methods table:                                          */
95 /*****************************************************************************/
96 static PyMethodDef C_IpoCurve_methods[] = {
97         /* name, method, flags, doc */
98         {"getName", ( PyCFunction ) IpoCurve_getName, METH_NOARGS,
99          "() - Return IpoCurve Data name"},
100         {"Recalc", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS,
101          "() - Return IpoCurve Data name"},
102         {"update", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS,
103          "() - Return IpoCurve Data name"},
104         {"setName", ( PyCFunction ) IpoCurve_setName, METH_VARARGS,
105          "(str) - Change IpoCurve Data name"},
106         {"addBezier", ( PyCFunction ) IpoCurve_addBezier, METH_VARARGS,
107          "(str) - Change IpoCurve Data name"},
108         {"setInterpolation", ( PyCFunction ) IpoCurve_setInterpolation,
109          METH_VARARGS,
110          "(str) - Change IpoCurve Data name"},
111         {"getInterpolation", ( PyCFunction ) IpoCurve_getInterpolation,
112          METH_NOARGS,
113          "(str) - Change IpoCurve Data name"},
114         {"setExtrapolation", ( PyCFunction ) IpoCurve_setExtrapolation,
115          METH_VARARGS,
116          "(str) - Change IpoCurve Data name"},
117         {"getExtrapolation", ( PyCFunction ) IpoCurve_getExtrapolation,
118          METH_NOARGS,
119          "(str) - Change IpoCurve Data name"},
120         {"getPoints", ( PyCFunction ) IpoCurve_getPoints, METH_NOARGS,
121          "(str) - Change IpoCurve Data name"},
122         {"evaluate", ( PyCFunction ) IpoCurve_evaluate, METH_VARARGS,
123          "(float) - Evaluate curve at given time"},
124         {NULL, NULL, 0, NULL}
125 };
126
127 /*****************************************************************************/
128 /* Python IpoCurve_Type callback function prototypes:                        */
129 /*****************************************************************************/
130 static void IpoCurveDeAlloc( C_IpoCurve * self );
131 //static int IpoCurvePrint (C_IpoCurve *self, FILE *fp, int flags);
132 static int IpoCurveSetAttr( C_IpoCurve * self, char *name, PyObject * v );
133 static PyObject *IpoCurveGetAttr( C_IpoCurve * self, char *name );
134 static PyObject *IpoCurveRepr( C_IpoCurve * self );
135
136 /*****************************************************************************/
137 /* Python IpoCurve_Type structure definition:                                */
138 /*****************************************************************************/
139 PyTypeObject IpoCurve_Type = {
140         PyObject_HEAD_INIT( NULL ) /* required macro */ 
141         0,      /* ob_size */
142         "IpoCurve",             /* tp_name */
143         sizeof( C_IpoCurve ),   /* tp_basicsize */
144         0,                      /* tp_itemsize */
145         /* methods */
146         ( destructor ) IpoCurveDeAlloc, /* tp_dealloc */
147         0,                      /* tp_print */
148         ( getattrfunc ) IpoCurveGetAttr,        /* tp_getattr */
149         ( setattrfunc ) IpoCurveSetAttr,        /* tp_setattr */
150         0,                      /* tp_compare */
151         ( reprfunc ) IpoCurveRepr,      /* tp_repr */
152         0,                      /* tp_as_number */
153         0,                      /* tp_as_sequence */
154         0,                      /* tp_as_mapping */
155         0,                      /* tp_as_hash */
156         0, 0, 0, 0, 0, 0,
157         0,                      /* tp_doc */
158         0, 0, 0, 0, 0, 0,
159         C_IpoCurve_methods,     /* tp_methods */
160         0,                      /* tp_members */
161 };
162
163 /*****************************************************************************/
164 /* Function:       M_IpoCurve_New                                          */
165 /* Python equivalent:     Blender.IpoCurve.New                   */
166 /*****************************************************************************/
167 static PyObject *M_IpoCurve_New( PyObject * self, PyObject * args )
168 {
169         return 0;
170 }
171
172 /*****************************************************************************/
173 /* Function:              Ipo_Init                                           */
174 /*****************************************************************************/
175 PyObject *IpoCurve_Init( void )
176 {
177         PyObject *submodule;
178
179         IpoCurve_Type.ob_type = &PyType_Type;
180
181         submodule =
182                 Py_InitModule3( "Blender.IpoCurve", M_IpoCurve_methods,
183                                 M_IpoCurve_doc );
184
185         return ( submodule );
186 }
187
188 /*****************************************************************************/
189 /* Function:              M_IpoCurve_Get                                     */
190 /* Python equivalent:     Blender.IpoCurve.Get                               */
191 /* Description:           Receives a string and returns the ipo data obj     */
192 /*                        whose name matches the string.  If no argument is  */
193 /*                           passed in, a list of all ipo data names in the  */
194 /*                        current scene is returned.                         */
195 /*****************************************************************************/
196 static PyObject *M_IpoCurve_Get( PyObject * self, PyObject * args )
197 {
198         return 0;
199 }
200
201 /*****************************************************************************/
202 /* Python C_IpoCurve methods:                                                */
203 /*****************************************************************************/
204
205 static PyObject *IpoCurve_setInterpolation( C_IpoCurve * self,
206                                             PyObject * args )
207 {
208         char *interpolationtype = 0;
209         int id = -1;
210         if( !PyArg_ParseTuple( args, "s", &interpolationtype ) )
211                 return ( EXPP_ReturnPyObjError
212                          ( PyExc_TypeError, "expected string argument" ) );
213         if( !strcmp( interpolationtype, "Bezier" ) )
214                 id = IPO_BEZ;
215         if( !strcmp( interpolationtype, "Constant" ) )
216                 id = IPO_CONST;
217         if( !strcmp( interpolationtype, "Linear" ) )
218                 id = IPO_LIN;
219         if( id == -1 )
220                 return ( EXPP_ReturnPyObjError
221                          ( PyExc_TypeError, "bad interpolation type" ) );
222
223         self->ipocurve->ipo = id;
224         Py_INCREF( Py_None );
225         return Py_None;
226 }
227
228 static PyObject *IpoCurve_getInterpolation( C_IpoCurve * self )
229 {
230         char *str = 0;
231         IpoCurve *icu = self->ipocurve;
232         if( icu->ipo == IPO_BEZ )
233                 str = "Bezier";
234         if( icu->ipo == IPO_CONST )
235                 str = "Constant";
236         if( icu->ipo == IPO_LIN )
237                 str = "Linear";
238
239         if( !str )
240                 return ( EXPP_ReturnPyObjError
241                          ( PyExc_TypeError, "unknown interpolation type" ) );
242         return PyString_FromString( str );
243 }
244
245 static PyObject *IpoCurve_setExtrapolation( C_IpoCurve * self,
246                                             PyObject * args )
247 {
248
249         char *extrapolationtype = 0;
250         int id = -1;
251         if( !PyArg_ParseTuple( args, "s", &extrapolationtype ) )
252                 return ( EXPP_ReturnPyObjError
253                          ( PyExc_TypeError, "expected string argument" ) );
254         if( !strcmp( extrapolationtype, "Constant" ) )
255                 id = 0;
256         if( !strcmp( extrapolationtype, "Extrapolation" ) )
257                 id = 1;
258         if( !strcmp( extrapolationtype, "Cyclic" ) )
259                 id = 2;
260         if( !strcmp( extrapolationtype, "Cyclic_extrapolation" ) )
261                 id = 3;
262
263         if( id == -1 )
264                 return ( EXPP_ReturnPyObjError
265                          ( PyExc_TypeError, "bad interpolation type" ) );
266         self->ipocurve->extrap = id;
267         Py_INCREF( Py_None );
268         return Py_None;
269 }
270
271 static PyObject *IpoCurve_getExtrapolation( C_IpoCurve * self )
272 {
273         char *str = 0;
274         IpoCurve *icu = self->ipocurve;
275         if( icu->extrap == 0 )
276                 str = "Constant";
277         if( icu->extrap == 1 )
278                 str = "Extrapolation";
279         if( icu->extrap == 2 )
280                 str = "Cyclic";
281         if( icu->extrap == 3 )
282                 str = "Cyclic_extrapolation";
283
284         return PyString_FromString( str );
285 }
286
287 static PyObject *IpoCurve_addBezier( C_IpoCurve * self, PyObject * args )
288 {
289         short MEM_freeN( void *vmemh );
290         void *MEM_mallocN( unsigned int len, char *str );
291         float x, y;
292         int npoints;
293         IpoCurve *icu;
294         BezTriple *bzt, *tmp;
295         static char name[10] = "mlml";
296         PyObject *popo = 0;
297         if( !PyArg_ParseTuple( args, "O", &popo ) )
298                 return ( EXPP_ReturnPyObjError
299                          ( PyExc_TypeError, "expected tuple argument" ) );
300
301         x = PyFloat_AsDouble( PyTuple_GetItem( popo, 0 ) );
302         y = PyFloat_AsDouble( PyTuple_GetItem( popo, 1 ) );
303         icu = self->ipocurve;
304         npoints = icu->totvert;
305         tmp = icu->bezt;
306         icu->bezt = MEM_mallocN( sizeof( BezTriple ) * ( npoints + 1 ), name );
307         if( tmp ) {
308                 memmove( icu->bezt, tmp, sizeof( BezTriple ) * npoints );
309                 MEM_freeN( tmp );
310         }
311         memmove( icu->bezt + npoints, icu->bezt, sizeof( BezTriple ) );
312         icu->totvert++;
313         bzt = icu->bezt + npoints;
314         bzt->vec[0][0] = x - 1;
315         bzt->vec[1][0] = x;
316         bzt->vec[2][0] = x + 1;
317         bzt->vec[0][1] = y - 1;
318         bzt->vec[1][1] = y;
319         bzt->vec[2][1] = y + 1;
320         /* set handle type to Auto */
321         bzt->h1 = HD_AUTO;
322         bzt->h2 = HD_AUTO;
323
324         Py_INCREF( Py_None );
325         return Py_None;
326 }
327
328
329 static PyObject *IpoCurve_setName( C_IpoCurve * self, PyObject * args )
330 {
331         return 0;
332 }
333
334
335 static PyObject *IpoCurve_Recalc( C_IpoCurve * self )
336 {
337         IpoCurve *icu = self->ipocurve;
338
339         /* testhandles_ipocurve (icu); */
340         /* call calchandles_* instead of testhandles_*  */
341         /* I'm not sure this is a complete solution but since we do not */
342         /* deal with curve handles right now, it seems ok */
343         calchandles_ipocurve( icu );
344
345         Py_INCREF( Py_None );
346         return Py_None;
347 }
348
349 static PyObject *IpoCurve_getName( C_IpoCurve * self )
350 {
351         switch ( self->ipocurve->blocktype ) {
352         case ID_OB:
353                 return PyString_FromString( getname_ob_ei( self->ipocurve->adrcode, 1 ) );      /* solve: what if EffX/Y/Z are wanted? */
354         case ID_TE:
355                 return PyString_FromString( getname_tex_ei
356                                             ( self->ipocurve->adrcode ) );
357         case ID_LA:
358                 return PyString_FromString( getname_la_ei
359                                             ( self->ipocurve->adrcode ) );
360         case ID_MA:
361                 return PyString_FromString( getname_mat_ei
362                                             ( self->ipocurve->adrcode ) );
363         case ID_CA:
364                 return PyString_FromString( getname_cam_ei
365                                             ( self->ipocurve->adrcode ) );
366         case ID_WO:
367                 return PyString_FromString( getname_world_ei
368                                             ( self->ipocurve->adrcode ) );
369         case ID_AC:
370                 return PyString_FromString( getname_ac_ei
371                                             ( self->ipocurve->adrcode ) );
372         case ID_CU:
373                 return PyString_FromString( getname_cu_ei
374                                             ( self->ipocurve->adrcode ) );
375         case ID_KE:
376                 return PyString_FromString( getname_key_ei
377                                             ( self->ipocurve->adrcode ) );
378         case ID_SEQ:
379                 return PyString_FromString( getname_seq_ei
380                                             ( self->ipocurve->adrcode ) );
381         case IPO_CO:
382                 return PyString_FromString( getname_co_ei
383                                             ( self->ipocurve->adrcode ) );
384         default:
385                 return EXPP_ReturnPyObjError( PyExc_TypeError,
386                                               "This function doesn't support this ipocurve type yet" );
387         }
388
389         return PyString_FromString( "" );
390 }
391
392 static void IpoCurveDeAlloc( C_IpoCurve * self )
393 {
394         PyObject_DEL( self );
395 }
396
397 static PyObject *IpoCurve_getPoints( C_IpoCurve * self )
398 {
399         struct BezTriple *bezt;
400         PyObject *po;
401
402         PyObject *list = PyList_New( 0 );
403         int i;
404
405         for( i = 0; i < self->ipocurve->totvert; i++ ) {
406                 bezt = self->ipocurve->bezt + i;
407                 po = BezTriple_CreatePyObject( bezt );
408 #if 0
409                 if( BezTriple_CheckPyObject( po ) )
410                         printf( "po is ok\n" );
411                 else
412                         printf( "po is hosed\n" );
413 #endif
414                 PyList_Append( list, po );
415                 /*
416                    PyList_Append( list, BezTriple_CreatePyObject(bezt));
417                  */
418         }
419         return list;
420 }
421
422
423 int IpoCurve_setPoints( C_IpoCurve * self, PyObject * value )
424 {
425         struct BezTriple *bezt;
426         PyObject *l = PyList_New( 0 );
427         int i;
428         for( i = 0; i < self->ipocurve->totvert; i++ ) {
429                 bezt = self->ipocurve->bezt + i;
430                 PyList_Append( l, BezTriple_CreatePyObject( bezt ) );
431         }
432         return 0;
433 }
434
435
436 /*****************************************************************************/
437 /* Function:    IpoCurveGetAttr                                         */
438 /* Description: This is a callback function for the C_IpoCurve type. It is   */
439 /*              the function that accesses C_IpoCurve "member variables" and */
440 /*              methods.                                                     */
441 /*****************************************************************************/
442 static PyObject *IpoCurveGetAttr( C_IpoCurve * self, char *name )
443 {
444         if( strcmp( name, "bezierPoints" ) == 0 )
445                 return IpoCurve_getPoints( self );
446         if( strcmp( name, "name" ) == 0 )
447                 return IpoCurve_getName( self );
448         return Py_FindMethod( C_IpoCurve_methods, ( PyObject * ) self, name );
449 }
450
451 /*****************************************************************************/
452 /* Function:    IpoCurveSetAttr                                    */
453 /* Description: This is a callback function for the C_IpoCurve type. It  */
454 /*               sets IpoCurve Data attributes (member variables).*/
455 /*****************************************************************************/
456 static int IpoCurveSetAttr( C_IpoCurve * self, char *name, PyObject * value )
457 {
458         if( strcmp( name, "bezierPoints" ) == 0 )
459                 return IpoCurve_setPoints( self, value );
460         return 0;               /* normal exit */
461 }
462
463 /*****************************************************************************/
464 /* Function:    IpoCurveRepr                                             */
465 /* Description: This is a callback function for the C_IpoCurve type. It      */
466 /*              builds a meaninful string to represent ipo objects.          */
467 /*****************************************************************************/
468 static PyObject *IpoCurveRepr( C_IpoCurve * self )
469 {
470         void GetIpoCurveName( IpoCurve * icu, char *s );
471         char s[100], s1[100];
472         GetIpoCurveName( self->ipocurve, s1 );
473         sprintf( s, "IpoCurve %s \n", s1 );
474         return PyString_FromString( s );
475 }
476
477 /* Three Python IpoCurve_Type helper functions needed by the Object module: */
478
479 /*****************************************************************************/
480 /* Function:    IpoCurve_CreatePyObject                                     */
481 /* Description: This function will create a new C_IpoCurve from an existing  */
482 /*              Blender ipo structure.                                       */
483 /*****************************************************************************/
484 PyObject *IpoCurve_CreatePyObject( IpoCurve * ipo )
485 {
486         C_IpoCurve *pyipo;
487
488         pyipo = ( C_IpoCurve * ) PyObject_NEW( C_IpoCurve, &IpoCurve_Type );
489
490         if( !pyipo )
491                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
492                                               "couldn't create C_IpoCurve object" );
493
494         pyipo->ipocurve = ipo;
495
496         return ( PyObject * ) pyipo;
497 }
498
499 /*****************************************************************************/
500 /* Function:    IpoCurve_CheckPyObject                                      */
501 /* Description: This function returns true when the given PyObject is of the */
502 /*              type IpoCurve. Otherwise it will return false.               */
503 /*****************************************************************************/
504 int IpoCurve_CheckPyObject( PyObject * pyobj )
505 {
506         return ( pyobj->ob_type == &IpoCurve_Type );
507 }
508
509 /*****************************************************************************/
510 /* Function:    IpoCurve_FromPyObject                                       */
511 /* Description: This function returns the Blender ipo from the given         */
512 /*              PyObject.                                                    */
513 /*****************************************************************************/
514 IpoCurve *IpoCurve_FromPyObject( PyObject * pyobj )
515 {
516         return ( ( C_IpoCurve * ) pyobj )->ipocurve;
517 }
518
519 /***************************************************************************/
520 /* Function:      IpoCurve_evaluate( time )                                */
521 /* Description:   Evaluates IPO curve at the given time.                   */
522 /***************************************************************************/
523
524 static PyObject *IpoCurve_evaluate( C_IpoCurve * self, PyObject * args )
525 {
526
527         float time = 0;
528         double eval = 0;
529
530         /* expecting float */
531         if( !PyArg_ParseTuple( args, "f", &time ) )
532                 return ( EXPP_ReturnPyObjError
533                          ( PyExc_TypeError, "expected float argument" ) );
534
535         eval = ( double ) eval_icu( self->ipocurve, time );
536
537         return PyFloat_FromDouble( eval );
538
539 }