5f3a857920e2ff62f8df3cfbe66254fe0aeeeccf
[blender.git] / source / blender / python / api2_2x / Blender.c
1 /* 
2  *
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): Michel Selten, Willian P. Germano, Joseph Gilbert
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30 */
31
32 #include <Python.h>
33 #include <stdio.h>
34
35 #include <BIF_usiblender.h>
36 #include <BLI_blenlib.h>
37 #include <BKE_global.h>
38 #include <BPI_script.h>
39 #include <BSE_headerbuttons.h>
40 #include <DNA_ID.h>
41 #include <DNA_object_types.h>
42 #include <DNA_scene_types.h>
43 #include <DNA_screen_types.h> /* for SPACE_VIEW3D */
44 #include <DNA_space_types.h> /* for SPACE_VIEW3D */
45 #include <DNA_userdef_types.h>
46 #include <BKE_ipo.h>
47
48 #include "gen_utils.h"
49 #include "modules.h"
50 #include "../BPY_extern.h" /* for bpy_gethome() */
51
52 /* From Window.h, used here by Blender_Redraw */
53 PyObject *M_Window_Redraw(PyObject *self, PyObject *args);
54
55 /**********************************************************/
56 /* Python API function prototypes for the Blender module.       */
57 /**********************************************************/
58 static PyObject *Blender_Set (PyObject *self, PyObject *args);
59 static PyObject *Blender_Get (PyObject *self, PyObject *args);
60 static PyObject *Blender_Redraw(PyObject *self, PyObject *args);
61 static PyObject *Blender_ReleaseGlobalDict(PyObject *self, PyObject *args);
62 static PyObject *Blender_Quit(PyObject *self);
63 static PyObject *Blender_Load(PyObject *self, PyObject *args);
64
65 /*****************************************************************************/
66 /* The following string definitions are used for documentation strings.                  */
67 /* In Python these will be written to the console when doing a                                                   */
68 /* Blender.__doc__                                                                                                                                                                                                                                       */
69 /*****************************************************************************/
70 static char Blender_Set_doc[] =
71 "(request, data) - Update settings in Blender\n\
72 \n\
73 (request) A string identifying the setting to change\n\
74         'curframe'      - Sets the current frame using the number in data";
75
76 static char Blender_Get_doc[] =
77 "(request) - Retrieve settings from Blender\n\
78 \n\
79 (request) A string indentifying the data to be returned\n\
80         'curframe'      - Returns the current animation frame\n\
81         'curtime'       - Returns the current animation time\n\
82         'staframe'      - Returns the start frame of the animation\n\
83         'endframe'      - Returns the end frame of the animation\n\
84         'filename'      - Returns the name of the last file read or written\n\
85         'datadir' - Returns the dir where scripts can save their data, if available\n\
86         'version'       - Returns the Blender version number";
87
88 static char Blender_Redraw_doc[] = "() - Redraw all 3D windows";
89
90 static char Blender_ReleaseGlobalDict_doc[] =
91 "Deprecated, please use the Blender.Registry module solution instead.";
92
93 static char Blender_Quit_doc[] =
94 "() - Quit Blender.  The current data is saved as 'quit.blend' before leaving.";
95
96 static char Blender_Load_doc[] =
97 "(filename) - Load the given .blend file.  If succesful, the script is ended\n\
98 immediately.\n\
99 Notes:\n\
100 1 - () - an empty argument loads the default .B.blend file;\n\
101 2 - if the substring '.B.blend' occurs inside 'filename', the default\n\
102 .B.blend file is loaded;\n\
103 3 - The current data is always preserved as an autosave file, for safety;\n\
104 4 - This function only works if the script where it's executed is the\n\
105 only one running.";
106
107 /*****************************************************************************/
108 /* Python method structure definition.                                                                                                                                                   */
109 /*****************************************************************************/
110 static struct PyMethodDef Blender_methods[] = {
111         {"Set",          Blender_Set, METH_VARARGS, Blender_Set_doc},
112         {"Get",          Blender_Get, METH_VARARGS, Blender_Get_doc},
113         {"Redraw", Blender_Redraw, METH_VARARGS, Blender_Redraw_doc},
114         {"Quit",         (PyCFunction)Blender_Quit, METH_NOARGS, Blender_Quit_doc},
115         {"Load", Blender_Load, METH_VARARGS, Blender_Load_doc},
116         {"ReleaseGlobalDict", &Blender_ReleaseGlobalDict,
117                 METH_VARARGS, Blender_ReleaseGlobalDict_doc},
118         {NULL, NULL, 0, NULL}
119 };
120
121 /*****************************************************************************/
122 /* Global variables                                                                                                                                                                                                                                      */
123 /*****************************************************************************/
124 PyObject *g_blenderdict;
125
126 /*****************************************************************************/
127 /* Function:                                                    Blender_Set                                                                                                                                                              */
128 /* Python equivalent:                   Blender.Set                                                                                                                                                              */
129 /*****************************************************************************/
130 static PyObject *Blender_Set (PyObject *self, PyObject *args)
131 {
132         char                    * name;
133         PyObject        * arg;
134         int                                     framenum;
135                         
136         if (!PyArg_ParseTuple(args, "sO", &name, &arg))
137         {
138                 /* TODO: Do we need to generate a nice error message here? */
139                 return (NULL);
140         }
141
142         if (StringEqual (name, "curframe"))
143         {
144                 if (!PyArg_Parse(arg, "i", &framenum))
145                 {
146                 /* TODO: Do we need to generate a nice error message here? */
147                         return (NULL);
148                 }
149
150                 G.scene->r.cfra = framenum;
151
152                 update_for_newframe();
153         }
154         else
155         {
156                 return (EXPP_ReturnPyObjError (PyExc_AttributeError,
157                                                                                                                                                         "bad request identifier"));
158         }
159         return ( EXPP_incr_ret (Py_None) );
160 }
161
162 /*****************************************************************************/
163 /* Function:                                                    Blender_Get                                                                                                                                                              */
164 /* Python equivalent:                   Blender.Get                                                                                                                                                              */
165 /*****************************************************************************/
166 static PyObject *Blender_Get (PyObject *self, PyObject *args)
167 {
168         PyObject        * object;
169         PyObject        * dict;
170         char                    * str;
171                                 
172         if (!PyArg_ParseTuple (args, "O", &object))
173         {
174         /* TODO: Do we need to generate a nice error message here? */
175                 return (NULL);
176         }
177
178         if (PyString_Check (object))
179         {
180                 str = PyString_AsString (object);
181
182                 if (StringEqual (str, "curframe"))
183                 {
184                         return ( PyInt_FromLong (G.scene->r.cfra) );
185                 }
186                 if (StringEqual (str, "curtime"))
187                 {
188                         return ( PyFloat_FromDouble (frame_to_float (G.scene->r.cfra) ) );
189                 }
190                 if (StringEqual (str, "staframe"))
191                 {
192                         return ( PyInt_FromLong (G.scene->r.sfra) );
193                 }
194                 if (StringEqual (str, "endframe"))
195                 {
196                         return ( PyInt_FromLong (G.scene->r.efra) );
197                 }
198                 if (StringEqual (str, "filename"))
199                 {
200                         return ( PyString_FromString (G.sce) );
201                 }
202                 if (StringEqual (str, "datadir"))
203                 {
204                         char datadir[FILE_MAXDIR];
205                         BLI_make_file_string("/", datadir, bpy_gethome(), "bpydata/");
206                         if (BLI_exists(datadir)) return PyString_FromString(datadir);
207                         else return EXPP_incr_ret (Py_None);
208                 }
209                 /* According to the old file (opy_blender.c), the following if
210                          statement is a quick hack and needs some clean up. */
211                 if (StringEqual (str, "vrmloptions"))
212                 {
213                         dict = PyDict_New ();
214
215                         PyDict_SetItemString (dict, "twoside",
216                                                                         PyInt_FromLong (U.vrmlflag & USER_VRML_TWOSIDED));
217
218                         PyDict_SetItemString (dict, "layers",
219                                                                         PyInt_FromLong (U.vrmlflag & USER_VRML_LAYERS));
220
221                         PyDict_SetItemString (dict, "autoscale",
222                                                                         PyInt_FromLong (U.vrmlflag & USER_VRML_AUTOSCALE));
223
224                         return (dict);
225                 } /* End 'quick hack' part. */
226                 if (StringEqual (str, "version"))
227                 {
228                         return ( PyInt_FromLong (G.version) );
229                 }
230                 /* TODO: Do we want to display a usefull message here that the
231                                                                  requested data is unknown?
232                 else
233                 {
234                         return (EXPP_ReturnPyObjError (..., "message") );
235                 }
236                 */
237         }
238         else
239         {
240                 return (EXPP_ReturnPyObjError (PyExc_AttributeError,
241                                                                                                                                                 "expected string argument"));
242         }
243
244         return (EXPP_ReturnPyObjError (PyExc_AttributeError,
245                                                                                                                                 "bad request identifier"));
246 }
247
248 /*****************************************************************************/
249 /* Function:                                                    Blender_Redraw                                                                                                                                           */
250 /* Python equivalent:                   Blender.Redraw                                                                                                                                           */
251 /*****************************************************************************/
252 static PyObject *Blender_Redraw(PyObject *self, PyObject *args)
253 {
254         int wintype = SPACE_VIEW3D;
255
256         if (!PyArg_ParseTuple (args, "|i", &wintype))
257         {
258                 return EXPP_ReturnPyObjError (PyExc_TypeError,
259                                                                                                 "expected int argument (or nothing)");
260         }
261
262         return M_Window_Redraw(self, Py_BuildValue("(i)", wintype));
263 }
264
265 /*****************************************************************************/
266 /* Function:                                                    Blender_ReleaseGlobalDict                                                                                                        */
267 /* Python equivalent:                   Blender.ReleaseGlobalDict                                                                                                        */
268 /* Description:                                         Deprecated function.                                                                                                                     */
269 /*****************************************************************************/
270 static PyObject *Blender_ReleaseGlobalDict(PyObject *self, PyObject *args)
271 {
272         Py_INCREF(Py_None);
273         return Py_None;
274 }
275
276 /*****************************************************************************/
277 /* Function:                                                    Blender_Quit                                                                                                                                                     */
278 /* Python equivalent:                   Blender.Quit                                                                                                                                                     */
279 /*****************************************************************************/
280 static PyObject *Blender_Quit(PyObject *self)
281 {
282         BIF_write_autosave(); /* save the current data first */
283
284         exit_usiblender(); /* renames last autosave to quit.blend */
285
286         Py_INCREF(Py_None);
287         return Py_None;
288 }
289
290 static PyObject *Blender_Load(PyObject *self, PyObject *args)
291 {
292         char *fname = NULL;
293         Script *script = NULL;
294
295         if (!PyArg_ParseTuple(args, "|s", &fname))
296                 return EXPP_ReturnPyObjError(PyExc_TypeError,
297                         "expected filename string or nothing (for default file) as argument");
298
299         if (fname && !BLI_exists(fname))
300                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
301                         "requested file doesn't exist!");
302
303         /* We won't let a new .blend file be loaded if there are still other
304          * scripts running, since loading a new file will close and remove them. */
305
306         if (G.main->script.first != G.main->script.last)
307                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
308                         "there are other scripts running at the Scripts win, close them first!");
309
310         /* trick: mark the script so that its script struct won't be freed after
311          * the script is executed (to avoid a double free warning on exit): */
312         script = G.main->script.first;
313         script->flags |= SCRIPT_GUI;
314
315         BIF_write_autosave(); /* for safety let's preserve the current data */
316
317         /* for safety, any filename with .B.blend is considered the default one.
318          * It doesn't seem necessary to compare file attributes (like st_ino and
319          * st_dev, according to the glibc info pages) to find out if the given
320          * filename, that may have been given with a twisted misgiving path, is the
321          * default one for sure.  Taking any .B.blend file as the default is good
322          * enough here.  Note: the default file requires extra clean-up done by
323          * BIF_read_homefile: freeing the user theme data. */
324         if (!fname || strstr(fname, ".B.blend"))
325                 BIF_read_homefile();
326         else
327                 BIF_read_file(fname);
328
329         Py_INCREF(Py_None);
330         return Py_None;
331 }
332
333 /*****************************************************************************/
334 /* Function:                                                    initBlender                                                                                                                                                              */
335 /*****************************************************************************/
336 void M_Blender_Init (void)
337 {
338         PyObject                                * module;
339         PyObject                                * dict;
340
341         g_blenderdict = NULL;
342
343         /* TODO: create a docstring for the Blender module */
344         module = Py_InitModule3("Blender", Blender_methods, NULL);
345
346         types_InitAll(); /* set all our pytypes to &PyType_Type*/
347
348         dict = PyModule_GetDict (module);
349         g_blenderdict = dict;
350
351         Py_INCREF(Py_False);
352         PyDict_SetItemString(dict, "bylink", Py_False);
353         Py_INCREF(Py_None);
354         PyDict_SetItemString(dict, "link", Py_None);
355         PyDict_SetItemString(dict, "event", PyString_FromString(""));
356
357         PyDict_SetItemString (dict, "Types",            Types_Init());
358         PyDict_SetItemString (dict, "sys",                      sys_Init());
359         PyDict_SetItemString (dict, "Registry", Registry_Init());
360         PyDict_SetItemString (dict, "Scene",            Scene_Init());
361         PyDict_SetItemString (dict, "Object",           Object_Init());
362         PyDict_SetItemString (dict, "Material", Material_Init());
363         PyDict_SetItemString (dict, "Camera",           Camera_Init());
364         PyDict_SetItemString (dict, "Lamp",                     Lamp_Init());
365         PyDict_SetItemString (dict, "Lattice",  Lattice_Init());
366         PyDict_SetItemString (dict, "Curve",            Curve_Init());
367         PyDict_SetItemString (dict, "Armature", Armature_Init());
368         PyDict_SetItemString (dict, "Ipo",                      Ipo_Init());
369         PyDict_SetItemString (dict, "IpoCurve", IpoCurve_Init());
370         PyDict_SetItemString (dict, "Metaball", Metaball_Init());
371         PyDict_SetItemString (dict, "Image",            Image_Init());
372         PyDict_SetItemString (dict, "Window",           Window_Init());
373         PyDict_SetItemString (dict, "Draw",                     Draw_Init());
374         PyDict_SetItemString (dict, "BGL",                      BGL_Init());
375         PyDict_SetItemString (dict, "Effect",           Effect_Init());
376         PyDict_SetItemString (dict, "Text",                     Text_Init());
377         PyDict_SetItemString (dict, "World",            World_Init());
378         PyDict_SetItemString (dict, "Texture",  Texture_Init());
379         PyDict_SetItemString (dict, "NMesh",            NMesh_Init());
380         PyDict_SetItemString (dict, "Noise",            Noise_Init());
381         PyDict_SetItemString (dict, "Mathutils",Mathutils_Init());
382         PyDict_SetItemString (dict, "Library",  Library_Init());
383
384         PyModule_AddIntConstant(module, "TRUE",  1);
385         PyModule_AddIntConstant(module, "FALSE",  0);
386 }