Project file update for elbeem
[blender-staging.git] / source / blender / python / api2_2x / rgbTuple.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): Willian P. Germano
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31 */
32
33 #include "rgbTuple.h" /*This must come first */
34
35 #include "gen_utils.h"
36
37 /* This file is heavily based on the old bpython Constant object code in
38    Blender */
39
40 /*****************************************************************************/
41 /* Python rgbTuple_Type callback function prototypes:                        */
42 /*****************************************************************************/
43 static void rgbTuple_dealloc( BPy_rgbTuple * self );
44 static PyObject *rgbTuple_getAttr( BPy_rgbTuple * self, char *name );
45 static int rgbTuple_setAttr( BPy_rgbTuple * self, char *name, PyObject * v );
46 static PyObject *rgbTuple_repr( BPy_rgbTuple * self );
47
48 static int rgbTupleLength( void );
49
50 static PyObject *rgbTupleSubscript( BPy_rgbTuple * self, PyObject * key );
51 static int rgbTupleAssSubscript( BPy_rgbTuple * self, PyObject * who,
52                                  PyObject * cares );
53
54 static PyObject *rgbTupleItem( BPy_rgbTuple * self, int i );
55 static int rgbTupleAssItem( BPy_rgbTuple * self, int i, PyObject * ob );
56 static PyObject *rgbTupleSlice( BPy_rgbTuple * self, int begin, int end );
57 static int rgbTupleAssSlice( BPy_rgbTuple * self, int begin, int end,
58                              PyObject * seq );
59
60 /*****************************************************************************/
61 /* Python rgbTuple_Type Mapping Methods table:                               */
62 /*****************************************************************************/
63 static PyMappingMethods rgbTupleAsMapping = {
64         ( inquiry ) rgbTupleLength,     /* mp_length        */
65         ( binaryfunc ) rgbTupleSubscript,       /* mp_subscript     */
66         ( objobjargproc ) rgbTupleAssSubscript, /* mp_ass_subscript */
67 };
68
69 /*****************************************************************************/
70 /* Python rgbTuple_Type Sequence Methods table:                              */
71 /*****************************************************************************/
72 static PySequenceMethods rgbTupleAsSequence = {
73         ( inquiry ) rgbTupleLength,     /* sq_length */
74         ( binaryfunc ) 0,       /* sq_concat */
75         ( intargfunc ) 0,       /* sq_repeat */
76         ( intargfunc ) rgbTupleItem,    /* sq_item */
77         ( intintargfunc ) rgbTupleSlice,        /* sq_slice */
78         ( intobjargproc ) rgbTupleAssItem,      /* sq_ass_item */
79         ( intintobjargproc ) rgbTupleAssSlice,  /* sq_ass_slice       */
80 };
81
82 /*****************************************************************************/
83 /* Python rgbTuple_Type structure definition:                                */
84 /*****************************************************************************/
85 PyTypeObject rgbTuple_Type = {
86         PyObject_HEAD_INIT( NULL ) 
87         0,      /* ob_size */
88         "rgbTuple",             /* tp_name */
89         sizeof( BPy_rgbTuple ), /* tp_basicsize */
90         0,                      /* tp_itemsize */
91         /* methods */
92         ( destructor ) rgbTuple_dealloc,        /* tp_dealloc */
93         0,                      /* tp_print */
94         ( getattrfunc ) rgbTuple_getAttr,       /* tp_getattr */
95         ( setattrfunc ) rgbTuple_setAttr,       /* tp_setattr */
96         0,                      /* tp_compare */
97         ( reprfunc ) rgbTuple_repr,     /* tp_repr */
98         0,                      /* tp_as_number */
99         &rgbTupleAsSequence,    /* tp_as_sequence */
100         &rgbTupleAsMapping,     /* tp_as_mapping */
101         0,                      /* tp_as_hash */
102         0, 0, 0, 0, 0, 0,
103         0,                      /* tp_doc */
104         0, 0, 0, 0, 0, 0,
105         0,                      /* tp_methods */
106         0,                      /* tp_members */
107 };
108
109 /*****************************************************************************/
110 /* Function:              rgbTuple_New                                       */
111 /*****************************************************************************/
112 PyObject *rgbTuple_New( float *rgb[3] )
113 {
114         BPy_rgbTuple *rgbTuple;
115
116         rgbTuple_Type.ob_type = &PyType_Type;
117
118         rgbTuple =
119                 ( BPy_rgbTuple * ) PyObject_NEW( BPy_rgbTuple,
120                                                  &rgbTuple_Type );
121
122         if( rgbTuple == NULL )
123                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
124                                               "couldn't create rgbTuple object" );
125
126         rgbTuple->rgb[0] = rgb[0];
127         rgbTuple->rgb[1] = rgb[1];
128         rgbTuple->rgb[2] = rgb[2];
129
130         return ( PyObject * ) rgbTuple;
131 }
132
133 /*****************************************************************************/
134 /* Functions:      rgbTuple_getCol and rgbTuple_setCol                       */
135 /* Description:    These functions get/set rgb color triplet values.  The    */
136 /*                 get function returns a tuple, the set one accepts three   */
137 /*                 floats (separated or in a tuple) as arguments.            */
138 /*****************************************************************************/
139 PyObject *rgbTuple_getCol( BPy_rgbTuple * self )
140 {
141         PyObject *attr = Py_BuildValue( "[fff]", *(self->rgb[0]),
142                                                 *(self->rgb[1]), *(self->rgb[2]));
143         if( !attr )
144                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
145                                               "Py_BuildValue() failed" );
146         return attr;
147 }
148
149 int rgbTuple_setCol( BPy_rgbTuple * self, PyObject * args )
150 {
151         int ok = 0;
152         float r = 0, g = 0, b = 0;
153
154         /*
155          * since rgbTuple_getCol() returns a list, be sure we accept a list
156          * as valid input
157          */
158
159         if( PyObject_Length( args ) == 3 ) {
160                 if ( PyList_Check ( args ) &&
161                                 PyNumber_Check( PySequence_Fast_GET_ITEM( args, 0 ) ) &&
162                                 PyNumber_Check( PySequence_Fast_GET_ITEM( args, 1 ) ) &&
163                                 PyNumber_Check( PySequence_Fast_GET_ITEM( args, 2 ) ) ) {
164                         r = (float)PyFloat_AsDouble( PySequence_Fast_GET_ITEM( args, 0 ) );
165                         g = (float)PyFloat_AsDouble( PySequence_Fast_GET_ITEM( args, 1 ) );
166                         b = (float)PyFloat_AsDouble( PySequence_Fast_GET_ITEM( args, 2 ) );
167                         ok = 1;
168                 } else
169                         ok = PyArg_ParseTuple( args, "fff", &r, &g, &b );
170         } else
171                 ok = PyArg_ParseTuple( args, "|(fff)", &r, &g, &b );
172
173         if( !ok )
174                 return EXPP_ReturnIntError( PyExc_TypeError,
175                                               "expected [f,f,f], (f,f,f) or f,f,f as arguments (or nothing)" );
176
177         *( self->rgb[0] ) = EXPP_ClampFloat( r, 0.0, 1.0 );
178         *( self->rgb[1] ) = EXPP_ClampFloat( g, 0.0, 1.0 );
179         *( self->rgb[2] ) = EXPP_ClampFloat( b, 0.0, 1.0 );
180
181         return 0;
182 }
183
184 /*****************************************************************************/
185 /* Function:    rgbTuple_dealloc                                             */
186 /* Description: This is a callback function for the BPy_rgbTuple type. It is */
187 /*              the destructor function.                                     */
188 /*****************************************************************************/
189 static void rgbTuple_dealloc( BPy_rgbTuple * self )
190 {
191         PyObject_DEL( self );
192 }
193
194 /*****************************************************************************/
195 /* Function:    rgbTuple_getAttr                                             */
196 /* Description: This is a callback function for the BPy_rgbTuple type. It is */
197 /*              the function that accesses BPy_rgbTuple member variables and */
198 /*              methods.                                                     */
199 /*****************************************************************************/
200 static PyObject *rgbTuple_getAttr( BPy_rgbTuple * self, char *name )
201 {
202         int i;
203
204         if( strcmp( name, "__members__" ) == 0 )
205                 return Py_BuildValue( "[s,s,s]", "R", "G", "B" );
206
207         else if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
208                 i = 0;
209         else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
210                 i = 1;
211         else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
212                 i = 2;
213         else
214                 return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
215                                                 "attribute not found" ) );
216
217         return Py_BuildValue( "f", *( self->rgb[i] ) );
218 }
219
220 /*****************************************************************************/
221 /* Function:    rgbTuple_setAttr                                             */
222 /* Description: This is a callback function for the BPy_rgbTuple type. It is */
223 /*              the function that changes BPy_rgbTuple member variables.     */
224 /*****************************************************************************/
225 static int rgbTuple_setAttr( BPy_rgbTuple * self, char *name, PyObject * v )
226 {
227         float value;
228
229         if( !PyArg_Parse( v, "f", &value ) )
230                 return EXPP_ReturnIntError( PyExc_TypeError,
231                                             "expected float argument" );
232
233         value = EXPP_ClampFloat( value, 0.0, 1.0 );
234
235         if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
236                 *( self->rgb[0] ) = value;
237
238         else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
239                 *( self->rgb[1] ) = value;
240
241         else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
242                 *( self->rgb[2] ) = value;
243
244         else
245                 return ( EXPP_ReturnIntError( PyExc_AttributeError,
246                                               "attribute not found" ) );
247
248         return 0;
249 }
250
251 /*****************************************************************************/
252 /* Section:    rgbTuple as Mapping                                           */
253 /*             These functions provide code to access rgbTuple objects as    */
254 /*             mappings.                                                     */
255 /*****************************************************************************/
256 static int rgbTupleLength( void )
257 {
258         return 3;
259 }
260
261 static PyObject *rgbTupleSubscript( BPy_rgbTuple * self, PyObject * key )
262 {
263         char *name = NULL;
264         int i;
265
266         if( PyNumber_Check( key ) )
267                 return rgbTupleItem( self, ( int ) PyInt_AsLong( key ) );
268
269         if( !PyArg_ParseTuple( key, "s", &name ) )
270                 return EXPP_ReturnPyObjError( PyExc_TypeError,
271                                               "expected int or string argument" );
272
273         if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
274                 i = 0;
275         else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
276                 i = 1;
277         else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
278                 i = 2;
279         else
280                 return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
281
282         return Py_BuildValue( "f", *( self->rgb[i] ) );
283 }
284
285 static int rgbTupleAssSubscript( BPy_rgbTuple * self, PyObject * key,
286                                  PyObject * v )
287 {
288         char *name = NULL;
289         int i;
290
291         if( !PyNumber_Check( v ) )
292                 return EXPP_ReturnIntError( PyExc_TypeError,
293                                             "value to assign must be a number" );
294
295         if( PyNumber_Check( key ) )
296                 return rgbTupleAssItem( self, ( int ) PyInt_AsLong( key ), v );
297
298         if( !PyArg_Parse( key, "s", &name ) )
299                 return EXPP_ReturnIntError( PyExc_TypeError,
300                                             "expected int or string argument" );
301
302         if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
303                 i = 0;
304         else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
305                 i = 1;
306         else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
307                 i = 2;
308         else
309                 return EXPP_ReturnIntError( PyExc_AttributeError, name );
310
311         *( self->rgb[i] ) = EXPP_ClampFloat( (float)PyFloat_AsDouble( v ), 0.0, 1.0 );
312
313         return 0;
314 }
315
316 /*****************************************************************************/
317 /* Section:    rgbTuple as Sequence                                          */
318 /*             These functions provide code to access rgbTuple objects as    */
319 /*             sequences.                                                    */
320 /*****************************************************************************/
321 static PyObject *rgbTupleItem( BPy_rgbTuple * self, int i )
322 {
323         if( i < 0 || i >= 3 )
324                 return EXPP_ReturnPyObjError( PyExc_IndexError,
325                                               "array index out of range" );
326
327         return Py_BuildValue( "f", *( self->rgb[i] ) );
328 }
329
330 static PyObject *rgbTupleSlice( BPy_rgbTuple * self, int begin, int end )
331 {
332         PyObject *list;
333         int count;
334
335         if( begin < 0 )
336                 begin = 0;
337         if( end > 3 )
338                 end = 3;
339         if( begin > end )
340                 begin = end;
341
342         list = PyList_New( end - begin );
343
344         for( count = begin; count < end; count++ )
345                 PyList_SetItem( list, count - begin,
346                                 PyFloat_FromDouble( *( self->rgb[count] ) ) );
347
348         return list;
349 }
350
351 static int rgbTupleAssItem( BPy_rgbTuple * self, int i, PyObject * ob )
352 {
353         if( i < 0 || i >= 3 )
354                 return EXPP_ReturnIntError( PyExc_IndexError,
355                                             "array assignment index out of range" );
356
357         if( !PyNumber_Check( ob ) )
358                 return EXPP_ReturnIntError( PyExc_IndexError,
359                                             "color component must be a number" );
360 /* XXX this check above is probably ... */
361         *( self->rgb[i] ) =
362                 EXPP_ClampFloat( (float)PyFloat_AsDouble( ob ), 0.0, 1.0 );
363
364         return 0;
365 }
366
367 static int rgbTupleAssSlice( BPy_rgbTuple * self, int begin, int end,
368                              PyObject * seq )
369 {
370         int count;
371
372         if( begin < 0 )
373                 begin = 0;
374         if( end > 3 )
375                 end = 3;
376         if( begin > end )
377                 begin = end;
378
379         if( !PySequence_Check( seq ) )
380                 return EXPP_ReturnIntError( PyExc_TypeError,
381                                             "illegal argument type for built-in operation" );
382
383         if( PySequence_Length( seq ) != ( end - begin ) )
384                 return EXPP_ReturnIntError( PyExc_TypeError,
385                                             "size mismatch in slice assignment" );
386
387         for( count = begin; count < end; count++ ) {
388                 float value;
389                 PyObject *ob = PySequence_GetItem( seq, count );
390
391                 if( !PyArg_Parse( ob, "f", &value ) ) {
392                         Py_DECREF( ob );
393                         return -1;
394                 }
395
396                 *( self->rgb[count] ) = EXPP_ClampFloat( value, 0.0, 1.0 );
397
398                 Py_DECREF( ob );
399         }
400
401         return 0;
402 }
403
404 /*****************************************************************************/
405 /* Function:    rgbTuple_repr                                                */
406 /* Description: This is a callback function for the BPy_rgbTuple type. It    */
407 /*              builds a meaninful string to represent rgbTuple objects.     */
408 /*****************************************************************************/
409 static PyObject *rgbTuple_repr( BPy_rgbTuple * self )
410 {
411         float r, g, b;
412
413         r = *( self->rgb[0] );
414         g = *( self->rgb[1] );
415         b = *( self->rgb[2] );
416
417         return PyString_FromFormat( "[%f, %f, %f]", r, g, b );
418 }