add BLI_strcpy_rlen, replace strcat, which was used in misleading way.
[blender.git] / intern / cycles / blender / blender_python.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <Python.h>
20
21 #include "CCL_api.h"
22
23 #include "blender_sync.h"
24 #include "blender_session.h"
25
26 #include "util_foreach.h"
27 #include "util_md5.h"
28 #include "util_opengl.h"
29 #include "util_path.h"
30
31 #ifdef WITH_OSL
32 #include "osl.h"
33
34 #include <OSL/oslquery.h>
35 #include <OSL/oslconfig.h>
36 #endif
37
38 CCL_NAMESPACE_BEGIN
39
40 static PyObject *init_func(PyObject *self, PyObject *args)
41 {
42         const char *path, *user_path;
43
44         if(!PyArg_ParseTuple(args, "ss", &path, &user_path))
45                 return NULL;
46         
47         path_init(path, user_path);
48
49         Py_RETURN_NONE;
50 }
51
52 static PyObject *create_func(PyObject *self, PyObject *args)
53 {
54         PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
55         int preview_osl;
56
57         if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d, &preview_osl))
58                 return NULL;
59
60         /* RNA */
61         PointerRNA engineptr;
62         RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
63         BL::RenderEngine engine(engineptr);
64
65         PointerRNA userprefptr;
66         RNA_pointer_create(NULL, &RNA_UserPreferences, (void*)PyLong_AsVoidPtr(pyuserpref), &userprefptr);
67         BL::UserPreferences userpref(userprefptr);
68
69         PointerRNA dataptr;
70         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr);
71         BL::BlendData data(dataptr);
72
73         PointerRNA sceneptr;
74         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
75         BL::Scene scene(sceneptr);
76
77         PointerRNA regionptr;
78         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyregion), &regionptr);
79         BL::Region region(regionptr);
80
81         PointerRNA v3dptr;
82         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyv3d), &v3dptr);
83         BL::SpaceView3D v3d(v3dptr);
84
85         PointerRNA rv3dptr;
86         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyrv3d), &rv3dptr);
87         BL::RegionView3D rv3d(rv3dptr);
88
89         /* create session */
90         BlenderSession *session;
91
92         Py_BEGIN_ALLOW_THREADS
93
94         if(rv3d) {
95                 /* interactive viewport session */
96                 int width = region.width();
97                 int height = region.height();
98
99                 session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height);
100         }
101         else {
102                 /* override some settings for preview */
103                 if(engine.is_preview()) {
104                         PointerRNA cscene = RNA_pointer_get(&sceneptr, "cycles");
105
106                         RNA_boolean_set(&cscene, "shading_system", preview_osl);
107                         RNA_boolean_set(&cscene, "use_progressive_refine", true);
108                 }
109
110                 /* offline session or preview render */
111                 session = new BlenderSession(engine, userpref, data, scene);
112         }
113
114         Py_END_ALLOW_THREADS
115
116         return PyLong_FromVoidPtr(session);
117 }
118
119 static PyObject *free_func(PyObject *self, PyObject *value)
120 {
121         delete (BlenderSession*)PyLong_AsVoidPtr(value);
122
123         Py_RETURN_NONE;
124 }
125
126 static PyObject *render_func(PyObject *self, PyObject *value)
127 {
128         Py_BEGIN_ALLOW_THREADS
129
130         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
131         session->render();
132
133         Py_END_ALLOW_THREADS
134
135         Py_RETURN_NONE;
136 }
137
138 static PyObject *draw_func(PyObject *self, PyObject *args)
139 {
140         PyObject *pysession, *pyv3d, *pyrv3d;
141
142         if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
143                 return NULL;
144         
145         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
146
147         if(PyLong_AsVoidPtr(pyrv3d)) {
148                 /* 3d view drawing */
149                 int viewport[4];
150                 glGetIntegerv(GL_VIEWPORT, viewport);
151
152                 session->draw(viewport[2], viewport[3]);
153         }
154
155         Py_RETURN_NONE;
156 }
157
158 static PyObject *reset_func(PyObject *self, PyObject *args)
159 {
160         PyObject *pysession, *pydata, *pyscene;
161
162         if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pyscene))
163                 return NULL;
164
165         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
166
167         PointerRNA dataptr;
168         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr);
169         BL::BlendData b_data(dataptr);
170
171         PointerRNA sceneptr;
172         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
173         BL::Scene b_scene(sceneptr);
174
175         Py_BEGIN_ALLOW_THREADS
176
177         session->reset_session(b_data, b_scene);
178
179         Py_END_ALLOW_THREADS
180
181         Py_RETURN_NONE;
182 }
183
184 static PyObject *sync_func(PyObject *self, PyObject *value)
185 {
186         Py_BEGIN_ALLOW_THREADS
187
188         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
189         session->synchronize();
190
191         Py_END_ALLOW_THREADS
192
193         Py_RETURN_NONE;
194 }
195
196 static PyObject *available_devices_func(PyObject *self, PyObject *args)
197 {
198         vector<DeviceInfo>& devices = Device::available_devices();
199         PyObject *ret = PyTuple_New(devices.size());
200
201         for(size_t i = 0; i < devices.size(); i++) {
202                 DeviceInfo& device = devices[i];
203                 PyTuple_SET_ITEM(ret, i, PyUnicode_FromString(device.description.c_str()));
204         }
205
206         return ret;
207 }
208
209 #ifdef WITH_OSL
210
211 static PyObject *osl_update_node_func(PyObject *self, PyObject *args)
212 {
213         PyObject *pynodegroup, *pynode;
214         const char *filepath = NULL;
215
216         if(!PyArg_ParseTuple(args, "OOs", &pynodegroup, &pynode, &filepath))
217                 return NULL;
218
219         /* RNA */
220         PointerRNA nodeptr;
221         RNA_pointer_create((ID*)PyLong_AsVoidPtr(pynodegroup), &RNA_ShaderNodeScript, (void*)PyLong_AsVoidPtr(pynode), &nodeptr);
222         BL::ShaderNodeScript b_node(nodeptr);
223
224         /* update bytecode hash */
225         string bytecode = b_node.bytecode();
226
227         if(!bytecode.empty()) {
228                 MD5Hash md5;
229                 md5.append((const uint8_t*)bytecode.c_str(), bytecode.size());
230                 b_node.bytecode_hash(md5.get_hex().c_str());
231         }
232         else
233                 b_node.bytecode_hash("");
234
235         /* query from file path */
236         OSL::OSLQuery query;
237
238         if(!OSLShaderManager::osl_query(query, filepath))
239                 Py_RETURN_FALSE;
240
241         /* add new sockets from parameters */
242         set<void*> used_sockets;
243
244         for(int i = 0; i < query.nparams(); i++) {
245                 const OSL::OSLQuery::Parameter *param = query.getparam(i);
246
247                 /* skip unsupported types */
248                 if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
249                         continue;
250
251                 /* determine socket type */
252                 std::string socket_type;
253                 BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
254                 float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
255                 float default_float = 0.0f;
256                 int default_int = 0;
257                 std::string default_string = "";
258                 
259                 if(param->isclosure) {
260                         socket_type = "NodeSocketShader";
261                         data_type = BL::NodeSocket::type_SHADER;
262                 }
263                 else if(param->type.vecsemantics == TypeDesc::COLOR) {
264                         socket_type = "NodeSocketColor";
265                         data_type = BL::NodeSocket::type_RGBA;
266
267                         if(param->validdefault) {
268                                 default_float4[0] = param->fdefault[0];
269                                 default_float4[1] = param->fdefault[1];
270                                 default_float4[2] = param->fdefault[2];
271                         }
272                 }
273                 else if(param->type.vecsemantics == TypeDesc::POINT ||
274                         param->type.vecsemantics == TypeDesc::VECTOR ||
275                         param->type.vecsemantics == TypeDesc::NORMAL) {
276                         socket_type = "NodeSocketVector";
277                         data_type = BL::NodeSocket::type_VECTOR;
278
279                         if(param->validdefault) {
280                                 default_float4[0] = param->fdefault[0];
281                                 default_float4[1] = param->fdefault[1];
282                                 default_float4[2] = param->fdefault[2];
283                         }
284                 }
285                 else if(param->type.aggregate == TypeDesc::SCALAR) {
286                         if(param->type.basetype == TypeDesc::INT) {
287                                 socket_type = "NodeSocketInt";
288                                 data_type = BL::NodeSocket::type_INT;
289                                 if(param->validdefault)
290                                         default_int = param->idefault[0];
291                         }
292                         else if(param->type.basetype == TypeDesc::FLOAT) {
293                                 socket_type = "NodeSocketFloat";
294                                 data_type = BL::NodeSocket::type_VALUE;
295                                 if(param->validdefault)
296                                         default_float = param->fdefault[0];
297                         }
298                         else if(param->type.basetype == TypeDesc::STRING) {
299                                 socket_type = "NodeSocketString";
300                                 data_type = BL::NodeSocket::type_STRING;
301                                 if(param->validdefault)
302                                         default_string = param->sdefault[0];
303                         }
304                         else
305                                 continue;
306                 }
307                 else
308                         continue;
309
310                 /* find socket socket */
311                 BL::NodeSocket b_sock(PointerRNA_NULL);
312                 if (param->isoutput) {
313                         b_sock = b_node.outputs[param->name];
314                         
315                         /* remove if type no longer matches */
316                         if(b_sock && b_sock.bl_idname() != socket_type) {
317                                 b_node.outputs.remove(b_sock);
318                                 b_sock = BL::NodeSocket(PointerRNA_NULL);
319                         }
320                 }
321                 else {
322                         b_sock = b_node.inputs[param->name];
323                         
324                         /* remove if type no longer matches */
325                         if(b_sock && b_sock.bl_idname() != socket_type) {
326                                 b_node.inputs.remove(b_sock);
327                                 b_sock = BL::NodeSocket(PointerRNA_NULL);
328                         }
329                 }
330
331                 if(!b_sock) {
332                         /* create new socket */
333                         if(param->isoutput)
334                                 b_sock = b_node.outputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
335                         else
336                                 b_sock = b_node.inputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
337
338                         /* set default value */
339                         if(data_type == BL::NodeSocket::type_VALUE) {
340                                 set_float(b_sock.ptr, "default_value", default_float);
341                         }
342                         else if(data_type == BL::NodeSocket::type_INT) {
343                                 set_int(b_sock.ptr, "default_value", default_int);
344                         }
345                         else if(data_type == BL::NodeSocket::type_RGBA) {
346                                 set_float4(b_sock.ptr, "default_value", default_float4);
347                         }
348                         else if(data_type == BL::NodeSocket::type_VECTOR) {
349                                 set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
350                         }
351                         else if(data_type == BL::NodeSocket::type_STRING) {
352                                 set_string(b_sock.ptr, "default_value", default_string);
353                         }
354                 }
355
356                 used_sockets.insert(b_sock.ptr.data);
357         }
358
359         /* remove unused parameters */
360         bool removed;
361
362         do {
363                 BL::Node::inputs_iterator b_input;
364                 BL::Node::outputs_iterator b_output;
365
366                 removed = false;
367
368                 for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
369                         if(used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
370                                 b_node.inputs.remove(*b_input);
371                                 removed = true;
372                                 break;
373                         }
374                 }
375
376                 for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
377                         if(used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
378                                 b_node.outputs.remove(*b_output);
379                                 removed = true;
380                                 break;
381                         }
382                 }
383         } while(removed);
384
385         Py_RETURN_TRUE;
386 }
387
388 static PyObject *osl_compile_func(PyObject *self, PyObject *args)
389 {
390         const char *inputfile = NULL, *outputfile = NULL;
391
392         if(!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile))
393                 return NULL;
394         
395         /* return */
396         if(!OSLShaderManager::osl_compile(inputfile, outputfile))
397                 Py_RETURN_FALSE;
398
399         Py_RETURN_TRUE;
400 }
401 #endif
402
403 static PyMethodDef methods[] = {
404         {"init", init_func, METH_VARARGS, ""},
405         {"create", create_func, METH_VARARGS, ""},
406         {"free", free_func, METH_O, ""},
407         {"render", render_func, METH_O, ""},
408         {"draw", draw_func, METH_VARARGS, ""},
409         {"sync", sync_func, METH_O, ""},
410         {"reset", reset_func, METH_VARARGS, ""},
411 #ifdef WITH_OSL
412         {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
413         {"osl_compile", osl_compile_func, METH_VARARGS, ""},
414 #endif
415         {"available_devices", available_devices_func, METH_NOARGS, ""},
416         {NULL, NULL, 0, NULL},
417 };
418
419 static struct PyModuleDef module = {
420         PyModuleDef_HEAD_INIT,
421         "_cycles",
422         "Blender cycles render integration",
423         -1,
424         methods,
425         NULL, NULL, NULL, NULL
426 };
427
428 static CCLDeviceInfo *compute_device_list(DeviceType type)
429 {
430         /* device list stored static */
431         static ccl::vector<CCLDeviceInfo> device_list;
432         static ccl::DeviceType device_type = DEVICE_NONE;
433
434         /* create device list if it's not already done */
435         if(type != device_type) {
436                 ccl::vector<DeviceInfo>& devices = ccl::Device::available_devices();
437
438                 device_type = type;
439                 device_list.clear();
440
441                 /* add devices */
442                 int i = 0;
443
444                 foreach(DeviceInfo& info, devices) {
445                         if(info.type == type ||
446                            (info.type == DEVICE_MULTI && info.multi_devices[0].type == type))
447                         {
448                                 CCLDeviceInfo cinfo;
449
450                                 strncpy(cinfo.identifier, info.id.c_str(), sizeof(cinfo.identifier));
451                                 cinfo.identifier[info.id.length()] = '\0';
452
453                                 strncpy(cinfo.name, info.description.c_str(), sizeof(cinfo.name));
454                                 cinfo.name[info.description.length()] = '\0';
455
456                                 cinfo.value = i++;
457
458                                 device_list.push_back(cinfo);
459                         }
460                 }
461
462                 /* null terminate */
463                 if(!device_list.empty()) {
464                         CCLDeviceInfo cinfo = {"", "", 0};
465                         device_list.push_back(cinfo);
466                 }
467         }
468
469         return (device_list.empty())? NULL: &device_list[0];
470 }
471
472
473 CCL_NAMESPACE_END
474
475 void *CCL_python_module_init()
476 {
477         PyObject *mod = PyModule_Create(&ccl::module);
478
479 #ifdef WITH_OSL
480         PyModule_AddObject(mod, "with_osl", Py_True);
481         Py_INCREF(Py_True);
482 #else
483         PyModule_AddObject(mod, "with_osl", Py_False);
484         Py_INCREF(Py_False);
485 #endif
486
487         return (void*)mod;
488 }
489
490 CCLDeviceInfo *CCL_compute_device_list(int opencl)
491 {
492         ccl::DeviceType type = (opencl)? ccl::DEVICE_OPENCL: ccl::DEVICE_CUDA;
493         return ccl::compute_device_list(type);
494 }
495