
This expose the capability of handling offscreen drawing. The initial support lays the barebones for addons to work with framebuffer objects and implement 3d viewport offscreen drawing. This can be used by script writers to make fisheye lens preview, head mounted display support, ... The complete documentation is here: http://www.blender.org/api/blender_python_api_2_76_1/gpu.offscreen.html Review and many changes by Campbell Barton (thank you :) https://developer.blender.org/D1533
334 lines
10 KiB
C
334 lines
10 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2006 Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): Benoit Bolsee.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/python/intern/gpu.c
|
|
* \ingroup pythonintern
|
|
*
|
|
* This file defines the 'gpu' module, used to get GLSL shader code and data
|
|
* from blender materials.
|
|
*/
|
|
|
|
#include <Python.h>
|
|
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_material_types.h"
|
|
#include "DNA_ID.h"
|
|
#include "DNA_customdata_types.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "bpy_rna.h"
|
|
|
|
#include "../generic/py_capi_utils.h"
|
|
|
|
#include "GPU_material.h"
|
|
|
|
#include "gpu.h"
|
|
|
|
#define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, # name, name)
|
|
|
|
PyDoc_STRVAR(M_gpu_doc,
|
|
"This module provides access to the GLSL shader and Offscreen rendering functionalities."
|
|
);
|
|
static struct PyModuleDef gpumodule = {
|
|
PyModuleDef_HEAD_INIT,
|
|
"gpu", /* name of module */
|
|
M_gpu_doc, /* module documentation */
|
|
-1, /* size of per-interpreter state of the module,
|
|
* or -1 if the module keeps state in global variables. */
|
|
NULL, NULL, NULL, NULL, NULL
|
|
};
|
|
|
|
static PyObject *PyInit_gpu(void)
|
|
{
|
|
PyObject *m;
|
|
|
|
m = PyModule_Create(&gpumodule);
|
|
if (m == NULL)
|
|
return NULL;
|
|
|
|
|
|
/* Take care to update docs when editing: 'doc/python_api/rst/gpu.rst' */
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* GPUDynamicType */
|
|
|
|
/* device constant groups */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MISC);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_LAMP);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_OBJECT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_SAMPLER);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MIST);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_WORLD);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MAT);
|
|
|
|
/* device constants */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_NONE);
|
|
/* GPU_DYNAMIC_GROUP_OBJECT */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWMAT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_MAT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWIMAT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_IMAT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_COLOR);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE);
|
|
/* GPU_DYNAMIC_GROUP_LAMP */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNVEC);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCO);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNIMAT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNPERSMAT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNENERGY);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCOL);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT1);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT2);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSCALE);
|
|
/* GPU_DYNAMIC_GROUP_SAMPLER */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DSHADOW);
|
|
/* GPU_DYNAMIC_GROUP_MIST */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_ENABLE);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_START);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_DISTANCE);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_INTENSITY);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_TYPE);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_COLOR);
|
|
/* GPU_DYNAMIC_GROUP_WORLD */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR);
|
|
/* GPU_DYNAMIC_GROUP_MAT */
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPECRGB);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPEC);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_HARD);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA);
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* GPUDataType */
|
|
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1I);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1F);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_2F);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_3F);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_4F);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_9F);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_16F);
|
|
PY_MODULE_ADD_CONSTANT(m, GPU_DATA_4UB);
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* CustomDataType
|
|
*
|
|
* Intentionally only include the subset used by the GPU API.
|
|
*/
|
|
PY_MODULE_ADD_CONSTANT(m, CD_MTFACE);
|
|
PY_MODULE_ADD_CONSTANT(m, CD_ORCO);
|
|
PY_MODULE_ADD_CONSTANT(m, CD_TANGENT);
|
|
PY_MODULE_ADD_CONSTANT(m, CD_MCOL);
|
|
return m;
|
|
}
|
|
|
|
#define PY_DICT_ADD_STRING(d, s, f) \
|
|
val = PyUnicode_FromString(s->f); \
|
|
PyDict_SetItemString(d, # f, val); \
|
|
Py_DECREF(val)
|
|
|
|
#define PY_DICT_ADD_LONG(d, s, f) \
|
|
val = PyLong_FromLong(s->f); \
|
|
PyDict_SetItemString(d, # f, val); \
|
|
Py_DECREF(val)
|
|
|
|
#define PY_DICT_ADD_ID(d, s, f) \
|
|
RNA_id_pointer_create((struct ID *)s->f, &tptr); \
|
|
val = pyrna_struct_CreatePyObject(&tptr); \
|
|
PyDict_SetItemString(d, # f, val); \
|
|
Py_DECREF(val)
|
|
|
|
#if 0 /* UNUSED */
|
|
#define PY_OBJ_ADD_ID(d, s, f) \
|
|
val = PyUnicode_FromString(&s->f->id.name[2]); \
|
|
PyObject_SetAttrString(d, # f, val); \
|
|
Py_DECREF(val)
|
|
|
|
#define PY_OBJ_ADD_LONG(d, s, f) \
|
|
val = PyLong_FromLong(s->f); \
|
|
PyObject_SetAttrString(d, # f, val); \
|
|
Py_DECREF(val)
|
|
|
|
#define PY_OBJ_ADD_STRING(d, s, f) \
|
|
val = PyUnicode_FromString(s->f); \
|
|
PyObject_SetAttrString(d, # f, val); \
|
|
Py_DECREF(val)
|
|
#endif
|
|
|
|
PyDoc_STRVAR(GPU_export_shader_doc,
|
|
"export_shader(scene, material)\n"
|
|
"\n"
|
|
" Returns the GLSL shader that produces the visual effect of material in scene.\n"
|
|
"\n"
|
|
" :return: Dictionary defining the shader, uniforms and attributes.\n"
|
|
" :rtype: Dict"
|
|
);
|
|
static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
|
|
{
|
|
PyObject *pyscene;
|
|
PyObject *pymat;
|
|
PyObject *result;
|
|
PyObject *dict;
|
|
PyObject *val;
|
|
PyObject *seq;
|
|
|
|
int i;
|
|
Scene *scene;
|
|
PointerRNA tptr;
|
|
Material *material;
|
|
GPUShaderExport *shader;
|
|
GPUInputUniform *uniform;
|
|
GPUInputAttribute *attribute;
|
|
|
|
static const char *kwlist[] = {"scene", "material", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:export_shader", (char **)(kwlist), &pyscene, &pymat))
|
|
return NULL;
|
|
|
|
scene = (Scene *)PyC_RNA_AsPointer(pyscene, "Scene");
|
|
if (scene == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
material = (Material *)PyC_RNA_AsPointer(pymat, "Material");
|
|
if (material == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* we can call our internal function at last: */
|
|
shader = GPU_shader_export(scene, material);
|
|
if (!shader) {
|
|
PyErr_SetString(PyExc_RuntimeError, "cannot export shader");
|
|
return NULL;
|
|
}
|
|
/* build a dictionary */
|
|
result = PyDict_New();
|
|
if (shader->fragment) {
|
|
PY_DICT_ADD_STRING(result, shader, fragment);
|
|
}
|
|
if (shader->vertex) {
|
|
PY_DICT_ADD_STRING(result, shader, vertex);
|
|
}
|
|
seq = PyList_New(BLI_listbase_count(&shader->uniforms));
|
|
for (i = 0, uniform = shader->uniforms.first; uniform; uniform = uniform->next, i++) {
|
|
dict = PyDict_New();
|
|
PY_DICT_ADD_STRING(dict, uniform, varname);
|
|
PY_DICT_ADD_LONG(dict, uniform, datatype);
|
|
PY_DICT_ADD_LONG(dict, uniform, type);
|
|
if (uniform->lamp) {
|
|
PY_DICT_ADD_ID(dict, uniform, lamp);
|
|
}
|
|
if (uniform->image) {
|
|
PY_DICT_ADD_ID(dict, uniform, image);
|
|
}
|
|
if (uniform->type == GPU_DYNAMIC_SAMPLER_2DBUFFER ||
|
|
uniform->type == GPU_DYNAMIC_SAMPLER_2DIMAGE ||
|
|
uniform->type == GPU_DYNAMIC_SAMPLER_2DSHADOW)
|
|
{
|
|
PY_DICT_ADD_LONG(dict, uniform, texnumber);
|
|
}
|
|
if (uniform->texpixels) {
|
|
val = PyByteArray_FromStringAndSize((const char *)uniform->texpixels, uniform->texsize * 4);
|
|
PyDict_SetItemString(dict, "texpixels", val);
|
|
Py_DECREF(val);
|
|
PY_DICT_ADD_LONG(dict, uniform, texsize);
|
|
}
|
|
PyList_SET_ITEM(seq, i, dict);
|
|
}
|
|
PyDict_SetItemString(result, "uniforms", seq);
|
|
Py_DECREF(seq);
|
|
|
|
seq = PyList_New(BLI_listbase_count(&shader->attributes));
|
|
for (i = 0, attribute = shader->attributes.first; attribute; attribute = attribute->next, i++) {
|
|
dict = PyDict_New();
|
|
PY_DICT_ADD_STRING(dict, attribute, varname);
|
|
PY_DICT_ADD_LONG(dict, attribute, datatype);
|
|
PY_DICT_ADD_LONG(dict, attribute, type);
|
|
PY_DICT_ADD_LONG(dict, attribute, number);
|
|
if (attribute->name) {
|
|
if (attribute->name[0] != 0) {
|
|
PY_DICT_ADD_STRING(dict, attribute, name);
|
|
}
|
|
else {
|
|
val = PyLong_FromLong(0);
|
|
PyDict_SetItemString(dict, "name", val);
|
|
Py_DECREF(val);
|
|
}
|
|
}
|
|
PyList_SET_ITEM(seq, i, dict);
|
|
}
|
|
PyDict_SetItemString(result, "attributes", seq);
|
|
Py_DECREF(seq);
|
|
|
|
GPU_free_shader_export(shader);
|
|
|
|
return result;
|
|
}
|
|
|
|
static PyMethodDef meth_export_shader[] = {
|
|
{"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc}
|
|
};
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize Module */
|
|
|
|
PyObject *GPU_initPython(void)
|
|
{
|
|
PyObject *module;
|
|
PyObject *submodule;
|
|
PyObject *sys_modules = PyThreadState_GET()->interp->modules;
|
|
|
|
module = PyInit_gpu();
|
|
|
|
PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL));
|
|
|
|
/* gpu.offscreen */
|
|
PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen()));
|
|
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
|
|
Py_INCREF(submodule);
|
|
|
|
PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module);
|
|
return module;
|
|
}
|
|
|