31 # include <OSL/oslconfig.h>
32 # include <OSL/oslquery.h>
44 if (
object == Py_None)
46 return PyLong_AsVoidPtr(
object);
52 return PyUnicode_DecodeUTF8(
str, strlen(
str),
"ignore");
90 *python_thread_state = (
void *)PyEval_SaveThread();
95 PyEval_RestoreThread((PyThreadState *)*python_thread_state);
96 *python_thread_state =
NULL;
101 const char *
result = PyUnicode_AsUTF8(py_str);
110 if (PyBytes_Check(py_str)) {
111 return PyBytes_AS_STRING(py_str);
113 else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
114 return PyBytes_AS_STRING(*coerce);
128 PyObject *path, *user_path;
131 if (!PyArg_ParseTuple(args,
"OOi", &path, &user_path, &headless)) {
135 PyObject *path_coerce =
nullptr, *user_path_coerce =
nullptr;
138 Py_XDECREF(path_coerce);
139 Py_XDECREF(user_path_coerce);
158 PyObject *pyengine, *pypreferences, *pydata, *pyscreen, *pyregion, *pyv3d, *pyrv3d;
161 if (!PyArg_ParseTuple(args,
183 NULL, &RNA_Preferences, (
void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
184 BL::Preferences preferences(preferencesptr);
188 BL::BlendData
data(dataptr);
192 BL::Region region(regionptr);
196 BL::SpaceView3D v3d(v3dptr);
207 int width = region.width();
208 int height = region.height();
217 return PyLong_FromVoidPtr(session);
220 static PyObject *
free_func(PyObject * , PyObject *value)
229 PyObject *pysession, *pydepsgraph;
231 if (!PyArg_ParseTuple(args,
"OO", &pysession, &pydepsgraph))
243 session->
render(b_depsgraph);
254 if (!PyArg_ParseTuple(args,
"O", &pysession)) {
272 PyObject *py_session, *py_graph, *py_screen, *py_space_image;
274 if (!PyArg_ParseTuple(args,
"OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
280 ID *b_screen = (
ID *)PyLong_AsVoidPtr(py_screen);
284 &RNA_SpaceImageEditor,
287 BL::SpaceImageEditor b_space_image(b_space_image_ptr);
289 session->
draw(b_space_image);
297 PyObject *pysession, *pydepsgraph, *pyobject;
298 const char *pass_type;
301 if (!PyArg_ParseTuple(args,
324 session->
bake(b_depsgraph, b_object, pass_type, pass_filter,
width,
height);
333 PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
335 if (!PyArg_ParseTuple(args,
"OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d))
340 if (PyLong_AsVoidPtr(pyrv3d)) {
343 glGetIntegerv(GL_VIEWPORT, viewport);
345 session->
view_draw(viewport[2], viewport[3]);
353 PyObject *pysession, *pydata, *pydepsgraph;
355 if (!PyArg_ParseTuple(args,
"OOO", &pysession, &pydata, &pydepsgraph))
362 BL::BlendData b_data(dataptr);
379 PyObject *pysession, *pydepsgraph;
381 if (!PyArg_ParseTuple(args,
"OO", &pysession, &pydepsgraph))
401 const char *type_name;
402 if (!PyArg_ParseTuple(args,
"s", &type_name)) {
409 PyErr_Format(PyExc_ValueError,
"Device \"%s\" not known.", type_name);
419 for (
size_t i = 0; i <
devices.size(); i++) {
422 PyObject *device_tuple = PyTuple_New(4);
426 PyTuple_SET_ITEM(device_tuple, 3, PyBool_FromLong(device.
has_peer_memory));
427 PyTuple_SET_ITEM(
ret, i, device_tuple);
435 static PyObject *osl_update_node_func(PyObject * , PyObject *args)
437 PyObject *pydata, *pynodegroup, *pynode;
438 const char *filepath =
NULL;
440 if (!PyArg_ParseTuple(args,
"OOOs", &pydata, &pynodegroup, &pynode, &filepath))
446 BL::BlendData b_data(dataptr);
450 &RNA_ShaderNodeScript,
451 (
void *)PyLong_AsVoidPtr(pynode),
453 BL::ShaderNodeScript b_node(nodeptr);
456 string bytecode = b_node.bytecode();
458 if (!bytecode.empty()) {
460 md5.
append((
const uint8_t *)bytecode.c_str(), bytecode.size());
461 b_node.bytecode_hash(md5.
get_hex().c_str());
464 b_node.bytecode_hash(
"");
469 if (!OSLShaderManager::osl_query(
query, filepath))
473 set<void *> used_sockets;
475 for (
int i = 0; i <
query.nparams(); i++) {
476 const OSL::OSLQuery::Parameter *param =
query.getparam(i);
479 if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
483 bool is_bool_param =
false;
484 ustring param_label = param->name;
486 for (
const OSL::OSLQuery::Parameter &metadata : param->metadata) {
487 if (metadata.type == TypeDesc::STRING) {
488 if (metadata.name ==
"widget") {
490 if (metadata.sdefault[0] ==
"boolean" || metadata.sdefault[0] ==
"checkBox") {
491 is_bool_param =
true;
494 else if (metadata.name ==
"label") {
496 param_label = metadata.sdefault[0];
502 BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
504 float default_float = 0.0f;
506 string default_string =
"";
507 bool default_boolean =
false;
509 if (param->isclosure) {
510 socket_type =
"NodeSocketShader";
511 data_type = BL::NodeSocket::type_SHADER;
513 else if (param->type.vecsemantics == TypeDesc::COLOR) {
514 socket_type =
"NodeSocketColor";
515 data_type = BL::NodeSocket::type_RGBA;
517 if (param->validdefault) {
518 default_float4[0] = param->fdefault[0];
519 default_float4[1] = param->fdefault[1];
520 default_float4[2] = param->fdefault[2];
524 param->type.vecsemantics == TypeDesc::VECTOR ||
526 socket_type =
"NodeSocketVector";
527 data_type = BL::NodeSocket::type_VECTOR;
529 if (param->validdefault) {
530 default_float4[0] = param->fdefault[0];
531 default_float4[1] = param->fdefault[1];
532 default_float4[2] = param->fdefault[2];
535 else if (param->type.aggregate == TypeDesc::SCALAR) {
536 if (param->type.basetype == TypeDesc::INT) {
538 socket_type =
"NodeSocketBool";
539 data_type = BL::NodeSocket::type_BOOLEAN;
540 if (param->validdefault) {
541 default_boolean = (
bool)param->idefault[0];
545 socket_type =
"NodeSocketInt";
546 data_type = BL::NodeSocket::type_INT;
547 if (param->validdefault)
548 default_int = param->idefault[0];
552 socket_type =
"NodeSocketFloat";
553 data_type = BL::NodeSocket::type_VALUE;
554 if (param->validdefault)
555 default_float = param->fdefault[0];
557 else if (param->type.basetype == TypeDesc::STRING) {
558 socket_type =
"NodeSocketString";
559 data_type = BL::NodeSocket::type_STRING;
560 if (param->validdefault)
561 default_string = param->sdefault[0].string();
570 bool found_existing =
false;
571 if (param->isoutput) {
572 for (BL::NodeSocket &b_sock : b_node.outputs) {
573 if (b_sock.identifier() == param->name) {
574 if (b_sock.bl_idname() != socket_type) {
576 b_node.outputs.remove(b_data, b_sock);
580 if (b_sock.name() != param_label) {
581 b_sock.name(param_label.string());
583 used_sockets.insert(b_sock.ptr.data);
584 found_existing =
true;
591 for (BL::NodeSocket &b_sock : b_node.inputs) {
592 if (b_sock.identifier() == param->name) {
593 if (b_sock.bl_idname() != socket_type) {
595 b_node.inputs.remove(b_data, b_sock);
599 if (b_sock.name() != param_label) {
600 b_sock.name(param_label.string());
602 used_sockets.insert(b_sock.ptr.data);
603 found_existing =
true;
610 if (!found_existing) {
612 BL::NodeSocket b_sock = (param->isoutput) ? b_node.outputs.create(b_data,
615 param->name.c_str()) :
616 b_node.inputs.create(b_data,
619 param->name.c_str());
622 if (data_type == BL::NodeSocket::type_VALUE) {
623 set_float(b_sock.ptr,
"default_value", default_float);
625 else if (data_type == BL::NodeSocket::type_INT) {
626 set_int(b_sock.ptr,
"default_value", default_int);
628 else if (data_type == BL::NodeSocket::type_RGBA) {
629 set_float4(b_sock.ptr,
"default_value", default_float4);
631 else if (data_type == BL::NodeSocket::type_VECTOR) {
634 else if (data_type == BL::NodeSocket::type_STRING) {
635 set_string(b_sock.ptr,
"default_value", default_string);
637 else if (data_type == BL::NodeSocket::type_BOOLEAN) {
638 set_boolean(b_sock.ptr,
"default_value", default_boolean);
641 used_sockets.insert(b_sock.ptr.data);
651 for (BL::NodeSocket &b_input : b_node.inputs) {
652 if (used_sockets.find(b_input.ptr.data) == used_sockets.end()) {
653 b_node.inputs.remove(b_data, b_input);
659 for (BL::NodeSocket &b_output : b_node.outputs) {
660 if (used_sockets.find(b_output.ptr.data) == used_sockets.end()) {
661 b_node.outputs.remove(b_data, b_output);
671 static PyObject *osl_compile_func(PyObject * , PyObject *args)
673 const char *inputfile =
NULL, *outputfile =
NULL;
675 if (!PyArg_ParseTuple(args,
"ss", &inputfile, &outputfile))
679 if (!OSLShaderManager::osl_compile(inputfile, outputfile))
694 if (PyUnicode_Check(pyfilepaths)) {
695 const char *filepath = PyUnicode_AsUTF8(pyfilepaths);
696 filepaths.push_back(filepath);
700 PyObject *sequence = PySequence_Fast(pyfilepaths,
701 "File paths must be a string or sequence of strings");
702 if (sequence ==
NULL) {
706 for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
707 PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
708 const char *filepath = PyUnicode_AsUTF8(item);
709 if (filepath ==
NULL) {
710 PyErr_SetString(PyExc_ValueError,
"File paths must be a string or sequence of strings.");
714 filepaths.push_back(filepath);
721 static PyObject *
denoise_func(PyObject * , PyObject *args, PyObject *keywords)
724 "preferences",
"scene",
"view_layer",
"input",
"output",
NULL};
725 PyObject *pypreferences, *pyscene, *pyviewlayer;
726 PyObject *pyinput, *pyoutput =
NULL;
728 if (!PyArg_ParseTupleAndKeywords(args,
743 NULL, &RNA_Preferences, (
void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
744 BL::Preferences b_preferences(preferencesptr);
756 PyLong_AsVoidPtr(pyviewlayer),
780 PyErr_SetString(PyExc_ValueError,
"No input file paths specified.");
784 PyErr_SetString(PyExc_ValueError,
"Number of input and output file paths does not match.");
794 if (!denoiser.
run()) {
795 PyErr_SetString(PyExc_ValueError, denoiser.
error.c_str());
802 static PyObject *
merge_func(PyObject * , PyObject *args, PyObject *keywords)
805 PyObject *pyinput, *pyoutput =
NULL;
807 if (!PyArg_ParseTupleAndKeywords(
808 args, keywords,
"OO", (
char **)
keyword_list, &pyinput, &pyoutput)) {
819 if (!PyUnicode_Check(pyoutput)) {
820 PyErr_SetString(PyExc_ValueError,
"Output must be a string.");
823 string output = PyUnicode_AsUTF8(pyoutput);
831 PyErr_SetString(PyExc_ValueError, merger.
error.c_str());
841 if (!PyArg_ParseTuple(args,
"O", &pyscene)) {
874 bool has_cuda =
false, has_optix =
false, has_hip =
false, has_metal =
false, has_oneapi =
false;
875 foreach (
DeviceType device_type, device_types) {
882 PyObject *list = PyTuple_New(5);
883 PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
884 PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
885 PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
886 PyTuple_SET_ITEM(list, 3, PyBool_FromLong(has_metal));
887 PyTuple_SET_ITEM(list, 4, PyBool_FromLong(has_oneapi));
893 PyObject *override_string = PyObject_Str(arg);
894 string override = PyUnicode_AsUTF8(override_string);
895 Py_DECREF(override_string);
897 bool include_cpu =
false;
898 const string cpu_suffix =
"+CPU";
901 override =
override.substr(0,
override.
length() - cpu_suffix.length());
904 if (
override ==
"CPU") {
907 else if (
override ==
"CUDA") {
910 else if (
override ==
"OPTIX") {
913 else if (
override ==
"HIP") {
916 else if (
override ==
"METAL") {
919 else if (
override ==
"ONEAPI") {
923 printf(
"\nError: %s is not a valid Cycles device.\n",
override.c_str());
948 {
"osl_update_node", osl_update_node_func, METH_VARARGS,
""},
949 {
"osl_compile", osl_compile_func, METH_VARARGS,
""},
955 {
"denoise", (PyCFunction)
denoise_func, METH_VARARGS | METH_KEYWORDS,
""},
956 {
"merge", (PyCFunction)
merge_func, METH_VARARGS | METH_KEYWORDS,
""},
972 static struct PyModuleDef
module = {
973 PyModuleDef_HEAD_INIT,
975 "Blender cycles render integration",
996 int curversion = OSL_LIBRARY_VERSION_CODE;
997 PyModule_AddObject(
mod,
"with_osl", Py_True);
1002 Py_BuildValue(
"(iii)", curversion / 10000, (curversion / 100) % 100, curversion % 100));
1005 "osl_version_string",
1006 PyUnicode_FromFormat(
1007 "%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100));
1009 PyModule_AddObject(
mod,
"with_osl", Py_False);
1010 Py_INCREF(Py_False);
1011 PyModule_AddStringConstant(
mod,
"osl_version",
"unknown");
1012 PyModule_AddStringConstant(
mod,
"osl_version_string",
"unknown");
1016 PyModule_AddObject(
mod,
"with_embree", Py_True);
1019 PyModule_AddObject(
mod,
"with_embree", Py_False);
1020 Py_INCREF(Py_False);
1024 PyModule_AddObject(
mod,
"with_openimagedenoise", Py_True);
1028 PyModule_AddObject(
mod,
"with_openimagedenoise", Py_False);
1029 Py_INCREF(Py_False);
1032 #ifdef WITH_CYCLES_DEBUG
1033 PyModule_AddObject(
mod,
"with_debug", Py_True);
1036 PyModule_AddObject(
mod,
"with_debug", Py_False);
1037 Py_INCREF(Py_False);
struct Depsgraph Depsgraph
struct ViewLayer ViewLayer
struct RegionView3D RegionView3D
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum query
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value NORMAL
struct RenderEngine RenderEngine
DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scene, bool background)
static bool print_render_stats
void synchronize(BL::Depsgraph &b_depsgraph)
void * python_thread_state
void view_draw(int w, int h)
void reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph)
void bake(BL::Depsgraph &b_depsgrah, BL::Object &b_object, const string &pass_type, const int custom_flag, const int bake_width, const int bake_height)
void render(BL::Depsgraph &b_depsgraph)
void draw(BL::SpaceImageEditor &space_image)
void render_frame_finish()
static DeviceTypeMask device_override
static DenoiseParams get_denoise_params(BL::Scene &b_scene, BL::ViewLayer &b_view_layer, bool background)
bool running_inside_blender
static void free_memory()
static vector< DeviceInfo > available_devices(uint device_type_mask=DEVICE_MASK_ALL)
static DeviceType type_from_string(const char *name)
static string device_capabilities(uint device_type_mask=DEVICE_MASK_ALL)
static vector< DeviceType > available_types()
static string string_from_type(DeviceType type)
void append(const uint8_t *data, int size)
static void free_memory()
static void free_memory()
#define CCL_NAMESPACE_END
static void set_boolean(PointerRNA &ptr, const char *name, bool value)
static bool get_boolean(PointerRNA &ptr, const char *name)
static void set_float3(PointerRNA &ptr, const char *name, float3 value)
static int get_enum(PointerRNA &ptr, const char *name, int num_values=-1, int default_value=-1)
static void set_float4(PointerRNA &ptr, const char *name, float4 value)
static void set_int(PointerRNA &ptr, const char *name, int value)
static void set_float(PointerRNA &ptr, const char *name, float value)
static void set_string(PointerRNA &ptr, const char *name, const string &value)
DebugFlags & DebugFlags()
#define DEVICE_MASK(type)
static KeywordTokenDef keyword_list[]
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
static void debug_flags_reset()
static void debug_flags_sync_from_scene(BL::Scene b_scene)
void * pylong_as_voidptr_typesafe(PyObject *object)
PyObject * pyunicode_from_string(const char *str)
static const VertexNature POINT
Vector< CPUDevice > devices
list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
T length(const vec_base< T, Size > &a)
static CCL_NAMESPACE_BEGIN bool openimagedenoise_supported()
CCL_NAMESPACE_BEGIN typedef KernelBVHLayout BVHLayout
void path_init(const string &path, const string &user_path)
static PyObject * available_devices_func(PyObject *, PyObject *args)
CCL_NAMESPACE_END void * CCL_python_module_init()
void python_thread_state_restore(void **python_thread_state)
static PyObject * draw_func(PyObject *, PyObject *args)
static PyObject * create_func(PyObject *, PyObject *args)
static PyObject * debug_flags_reset_func(PyObject *, PyObject *)
static PyObject * view_draw_func(PyObject *, PyObject *args)
static PyObject * set_device_override_func(PyObject *, PyObject *arg)
static PyObject * sync_func(PyObject *, PyObject *args)
static struct PyModuleDef module
static PyObject * debug_flags_update_func(PyObject *, PyObject *args)
static bool image_parse_filepaths(PyObject *pyfilepaths, vector< string > &filepaths)
static PyMethodDef methods[]
static PyObject * merge_func(PyObject *, PyObject *args, PyObject *keywords)
static PyObject * render_func(PyObject *, PyObject *args)
static PyObject * enable_print_stats_func(PyObject *, PyObject *)
static PyObject * system_info_func(PyObject *, PyObject *)
static PyObject * exit_func(PyObject *, PyObject *)
static const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
void python_thread_state_save(void **python_thread_state)
static PyObject * get_device_types_func(PyObject *, PyObject *)
static PyObject * denoise_func(PyObject *, PyObject *args, PyObject *keywords)
static PyObject * free_func(PyObject *, PyObject *value)
static PyObject * reset_func(PyObject *, PyObject *args)
static PyObject * render_frame_finish_func(PyObject *, PyObject *args)
static PyObject * bake_func(PyObject *, PyObject *args)
static PyObject * init_func(PyObject *, PyObject *args)
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr)
bool string_endswith(const string_view s, const string_view end)
ccl_device_inline int mod(int x, int m)
ccl_device_inline float3 float4_to_float3(const float4 a)