/* SPDX-FileCopyrightText: 2011-2022 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "final_engine.hh" #include "preview_engine.hh" #include "viewport_engine.hh" #include #include "RE_engine.h" #include "../generic/py_capi_utils.hh" #include "bpy_rna.hh" #include "BKE_context.hh" #include "RNA_prototypes.hh" #include "hydra/image.hh" namespace blender::render::hydra { template T *pyrna_to_pointer(PyObject *pyobject, const StructRNA *rnatype) { const PointerRNA *ptr = pyrna_struct_as_ptr_or_null(pyobject, rnatype); return (ptr) ? static_cast(ptr->data) : nullptr; } static PyObject *engine_create_func(PyObject * /*self*/, PyObject *args) { PyObject *pyengine; char *engine_type, *render_delegate_id; if (!PyArg_ParseTuple(args, "Oss", &pyengine, &engine_type, &render_delegate_id)) { return nullptr; } RenderEngine *bl_engine = pyrna_to_pointer(pyengine, &RNA_RenderEngine); CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %s", engine_type); Engine *engine = nullptr; try { if (STREQ(engine_type, "VIEWPORT")) { engine = new ViewportEngine(bl_engine, render_delegate_id); } else if (STREQ(engine_type, "PREVIEW")) { engine = new PreviewEngine(bl_engine, render_delegate_id); } else { engine = new FinalEngine(bl_engine, render_delegate_id); } } catch (std::runtime_error &e) { CLOG_ERROR(LOG_HYDRA_RENDER, "%s", e.what()); } CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine); return PyLong_FromVoidPtr(engine); } static PyObject *engine_free_func(PyObject * /*self*/, PyObject *args) { PyObject *pyengine; if (!PyArg_ParseTuple(args, "O", &pyengine)) { return nullptr; } Engine *engine = static_cast(PyLong_AsVoidPtr(pyengine)); CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine); delete engine; Py_RETURN_NONE; } static PyObject *engine_update_func(PyObject * /*self*/, PyObject *args) { PyObject *pyengine, *pydepsgraph, *pycontext; if (!PyArg_ParseTuple(args, "OOO", &pyengine, &pydepsgraph, &pycontext)) { return nullptr; } Engine *engine = static_cast(PyLong_AsVoidPtr(pyengine)); Depsgraph *depsgraph = pyrna_to_pointer(pydepsgraph, &RNA_Depsgraph); bContext *context = pyrna_to_pointer(pycontext, &RNA_Context); CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine); engine->sync(depsgraph, context); Py_RETURN_NONE; } static PyObject *engine_render_func(PyObject * /*self*/, PyObject *args) { PyObject *pyengine; if (!PyArg_ParseTuple(args, "O", &pyengine)) { return nullptr; } Engine *engine = static_cast(PyLong_AsVoidPtr(pyengine)); CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine); /* Allow Blender to execute other Python scripts. */ Py_BEGIN_ALLOW_THREADS; engine->render(); Py_END_ALLOW_THREADS; Py_RETURN_NONE; } static PyObject *engine_view_draw_func(PyObject * /*self*/, PyObject *args) { PyObject *pyengine, *pycontext; if (!PyArg_ParseTuple(args, "OO", &pyengine, &pycontext)) { return nullptr; } ViewportEngine *engine = static_cast(PyLong_AsVoidPtr(pyengine)); bContext *context = pyrna_to_pointer(pycontext, &RNA_Context); CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine); /* Allow Blender to execute other Python scripts. */ Py_BEGIN_ALLOW_THREADS; engine->render(context); Py_END_ALLOW_THREADS; Py_RETURN_NONE; } static pxr::VtValue get_setting_val(PyObject *pyval) { pxr::VtValue val; if (PyBool_Check(pyval)) { val = Py_IsTrue(pyval); } else if (PyLong_Check(pyval)) { val = PyLong_AsLong(pyval); } else if (PyFloat_Check(pyval)) { val = PyFloat_AsDouble(pyval); } else if (PyUnicode_Check(pyval)) { val = std::string(PyUnicode_AsUTF8(pyval)); } return val; } static PyObject *engine_set_render_setting_func(PyObject * /*self*/, PyObject *args) { PyObject *pyengine, *pyval; char *key; if (!PyArg_ParseTuple(args, "OsO", &pyengine, &key, &pyval)) { return nullptr; } Engine *engine = static_cast(PyLong_AsVoidPtr(pyengine)); CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p: %s", engine, key); engine->set_render_setting(key, get_setting_val(pyval)); Py_RETURN_NONE; } static PyObject *cache_or_get_image_file_func(PyObject * /*self*/, PyObject *args) { PyObject *pycontext, *pyimage; if (!PyArg_ParseTuple(args, "OO", &pycontext, &pyimage)) { return nullptr; } bContext *context = static_cast(PyLong_AsVoidPtr(pycontext)); Image *image = static_cast(PyLong_AsVoidPtr(pyimage)); std::string image_path = io::hydra::cache_or_get_image_file( CTX_data_main(context), CTX_data_scene(context), image, nullptr); return PyC_UnicodeFromStdStr(image_path); } static PyMethodDef methods[] = { {"engine_create", engine_create_func, METH_VARARGS, ""}, {"engine_free", engine_free_func, METH_VARARGS, ""}, {"engine_update", engine_update_func, METH_VARARGS, ""}, {"engine_render", engine_render_func, METH_VARARGS, ""}, {"engine_view_draw", engine_view_draw_func, METH_VARARGS, ""}, {"engine_set_render_setting", engine_set_render_setting_func, METH_VARARGS, ""}, {"cache_or_get_image_file", cache_or_get_image_file_func, METH_VARARGS, ""}, {nullptr, nullptr, 0, nullptr}, }; static PyModuleDef module = { PyModuleDef_HEAD_INIT, "_bpy_hydra", "Hydra render API", -1, methods, nullptr, nullptr, nullptr, nullptr, }; } // namespace blender::render::hydra PyObject *BPyInit_hydra(); PyObject *BPyInit_hydra() { PyObject *mod = PyModule_Create(&blender::render::hydra::module); return mod; }