6c3b137fd52a00c0082546caf07df8375ce89510
[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_id_pointer_create((ID*)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                         if (!b_sock) {
322                                 /* create new socket */
323                                 b_sock = b_node.outputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
324                         }
325                 }
326                 else {
327                         b_sock = b_node.inputs[param->name];
328                         
329                         /* remove if type no longer matches */
330                         if(b_sock && b_sock.bl_idname() != socket_type) {
331                                 b_node.inputs.remove(b_sock);
332                                 b_sock = BL::NodeSocket(PointerRNA_NULL);
333                         }
334                         
335                         if (!b_sock) {
336                                 /* create new socket */
337                                 b_sock = b_node.inputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
338                         }
339                 }
340
341                 /* set default value */
342                 if(b_sock) {
343                         if(data_type == BL::NodeSocket::type_VALUE) {
344                                 set_float(b_sock.ptr, "default_value", default_float);
345                         }
346                         else if(data_type == BL::NodeSocket::type_INT) {
347                                 set_int(b_sock.ptr, "default_value", default_int);
348                         }
349                         else if(data_type == BL::NodeSocket::type_RGBA) {
350                                 set_float4(b_sock.ptr, "default_value", default_float4);
351                         }
352                         else if(data_type == BL::NodeSocket::type_VECTOR) {
353                                 set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
354                         }
355                         else if(data_type == BL::NodeSocket::type_STRING) {
356                                 set_string(b_sock.ptr, "default_value", default_string);
357                         }
358                 }
359
360                 used_sockets.insert(b_sock.ptr.data);
361         }
362
363         /* remove unused parameters */
364         bool removed;
365
366         do {
367                 BL::Node::inputs_iterator b_input;
368                 BL::Node::outputs_iterator b_output;
369
370                 removed = false;
371
372                 for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
373                         if(used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
374                                 b_node.inputs.remove(*b_input);
375                                 removed = true;
376                                 break;
377                         }
378                 }
379
380                 for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
381                         if(used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
382                                 b_node.outputs.remove(*b_output);
383                                 removed = true;
384                                 break;
385                         }
386                 }
387         } while(removed);
388
389         Py_RETURN_TRUE;
390 }
391
392 static PyObject *osl_compile_func(PyObject *self, PyObject *args)
393 {
394         const char *inputfile = NULL, *outputfile = NULL;
395
396         if(!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile))
397                 return NULL;
398         
399         /* return */
400         if(!OSLShaderManager::osl_compile(inputfile, outputfile))
401                 Py_RETURN_FALSE;
402
403         Py_RETURN_TRUE;
404 }
405 #endif
406
407 static PyMethodDef methods[] = {
408         {"init", init_func, METH_VARARGS, ""},
409         {"create", create_func, METH_VARARGS, ""},
410         {"free", free_func, METH_O, ""},
411         {"render", render_func, METH_O, ""},
412         {"draw", draw_func, METH_VARARGS, ""},
413         {"sync", sync_func, METH_O, ""},
414         {"reset", reset_func, METH_VARARGS, ""},
415 #ifdef WITH_OSL
416         {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
417         {"osl_compile", osl_compile_func, METH_VARARGS, ""},
418 #endif
419         {"available_devices", available_devices_func, METH_NOARGS, ""},
420         {NULL, NULL, 0, NULL},
421 };
422
423 static struct PyModuleDef module = {
424         PyModuleDef_HEAD_INIT,
425         "_cycles",
426         "Blender cycles render integration",
427         -1,
428         methods,
429         NULL, NULL, NULL, NULL
430 };
431
432 static CCLDeviceInfo *compute_device_list(DeviceType type)
433 {
434         /* device list stored static */
435         static ccl::vector<CCLDeviceInfo> device_list;
436         static ccl::DeviceType device_type = DEVICE_NONE;
437
438         /* create device list if it's not already done */
439         if(type != device_type) {
440                 ccl::vector<DeviceInfo>& devices = ccl::Device::available_devices();
441
442                 device_type = type;
443                 device_list.clear();
444
445                 /* add devices */
446                 int i = 0;
447
448                 foreach(DeviceInfo& info, devices) {
449                         if(info.type == type ||
450                            (info.type == DEVICE_MULTI && info.multi_devices[0].type == type))
451                         {
452                                 CCLDeviceInfo cinfo;
453
454                                 strncpy(cinfo.identifier, info.id.c_str(), sizeof(cinfo.identifier));
455                                 cinfo.identifier[info.id.length()] = '\0';
456
457                                 strncpy(cinfo.name, info.description.c_str(), sizeof(cinfo.name));
458                                 cinfo.name[info.description.length()] = '\0';
459
460                                 cinfo.value = i++;
461
462                                 device_list.push_back(cinfo);
463                         }
464                 }
465
466                 /* null terminate */
467                 if(!device_list.empty()) {
468                         CCLDeviceInfo cinfo = {"", "", 0};
469                         device_list.push_back(cinfo);
470                 }
471         }
472
473         return (device_list.empty())? NULL: &device_list[0];
474 }
475
476
477 CCL_NAMESPACE_END
478
479 void *CCL_python_module_init()
480 {
481         PyObject *mod = PyModule_Create(&ccl::module);
482
483 #ifdef WITH_OSL
484         PyModule_AddObject(mod, "with_osl", Py_True);
485         Py_INCREF(Py_True);
486 #else
487         PyModule_AddObject(mod, "with_osl", Py_False);
488         Py_INCREF(Py_False);
489 #endif
490
491         return (void*)mod;
492 }
493
494 CCLDeviceInfo *CCL_compute_device_list(int opencl)
495 {
496         ccl::DeviceType type = (opencl)? ccl::DEVICE_OPENCL: ccl::DEVICE_CUDA;
497         return ccl::compute_device_list(type);
498 }
499