Render API: shader script node for custom shaders.
* Shader script node added, which stores either a link to a text datablock or file on disk, and has functions to add and remove sockets. * Callback RenderEngine.update_script_node(self, node) added for render engines to compile the shader and update the node with new sockets. Thanks to Thomas, Lukas and Dalai for the implementation.
This commit is contained in:
@@ -56,12 +56,17 @@ class TEXT_HT_header(Header):
|
||||
row.prop(st, "show_syntax_highlight", text="")
|
||||
|
||||
if text:
|
||||
row = layout.row()
|
||||
row.operator("text.run_script")
|
||||
osl = text.name.endswith(".osl") or text.name.endswith(".oso")
|
||||
|
||||
row = layout.row()
|
||||
row.active = text.name.endswith(".py")
|
||||
row.prop(text, "use_module")
|
||||
if osl:
|
||||
row = layout.row()
|
||||
row.operator("node.shader_script_update")
|
||||
else:
|
||||
row = layout.row()
|
||||
row.operator("text.run_script")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(text, "use_module")
|
||||
|
||||
row = layout.row()
|
||||
if text.filepath:
|
||||
|
@@ -245,6 +245,7 @@ typedef struct bNodeType {
|
||||
#define NODE_CLASS_PARTICLES 25
|
||||
#define NODE_CLASS_TRANSFORM 30
|
||||
#define NODE_CLASS_COMBINE 31
|
||||
#define NODE_CLASS_SCRIPT 32
|
||||
#define NODE_CLASS_SHADER 40
|
||||
#define NODE_CLASS_LAYOUT 100
|
||||
|
||||
@@ -551,6 +552,7 @@ struct ShadeResult;
|
||||
#define SH_NODE_PARTICLE_INFO 168
|
||||
#define SH_NODE_TEX_BRICK 169
|
||||
#define SH_NODE_BUMP 170
|
||||
#define SH_NODE_SCRIPT 171
|
||||
|
||||
/* custom defines options for Material node */
|
||||
#define SH_NODE_MAT_DIFF 1
|
||||
|
@@ -2288,6 +2288,7 @@ static void registerShaderNodes(bNodeTreeType *ttype)
|
||||
register_node_type_sh_tex_coord(ttype);
|
||||
register_node_type_sh_particle_info(ttype);
|
||||
register_node_type_sh_bump(ttype);
|
||||
register_node_type_sh_script(ttype);
|
||||
|
||||
register_node_type_sh_background(ttype);
|
||||
register_node_type_sh_bsdf_anisotropic(ttype);
|
||||
|
@@ -55,12 +55,15 @@
|
||||
#include "DNA_text_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_text.h"
|
||||
#include "BKE_node.h"
|
||||
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
@@ -531,6 +534,9 @@ void BKE_text_unlink(Main *bmain, Text *text)
|
||||
bController *cont;
|
||||
bActuator *act;
|
||||
bConstraint *con;
|
||||
bNodeTree *ntree;
|
||||
bNode *node;
|
||||
Material *mat;
|
||||
short update;
|
||||
|
||||
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||
@@ -582,6 +588,26 @@ void BKE_text_unlink(Main *bmain, Text *text)
|
||||
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
||||
}
|
||||
|
||||
/* nodes */
|
||||
for (mat = bmain->mat.first; mat; mat = mat->id.next) {
|
||||
ntree = mat->nodetree;
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == SH_NODE_SCRIPT) {
|
||||
Text *ntext = (Text *)node->id;
|
||||
if (ntext == text) node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
|
||||
for (node = ntree->nodes.first; node; node = node->next) {
|
||||
if (node->type == SH_NODE_SCRIPT) {
|
||||
Text *ntext = (Text *)node->id;
|
||||
if (ntext == text) node->id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* text space */
|
||||
for (scr = bmain->screen.first; scr; scr = scr->id.next) {
|
||||
for (area = scr->areabase.first; area; area = area->next) {
|
||||
|
@@ -2429,8 +2429,18 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
|
||||
|
||||
if (node->storage) {
|
||||
/* could be handlerized at some point */
|
||||
if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
|
||||
direct_link_curvemapping(fd, node->storage);
|
||||
if (ntree->type==NTREE_SHADER) {
|
||||
if (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB) {
|
||||
direct_link_curvemapping(fd, node->storage);
|
||||
}
|
||||
else if (node->type==SH_NODE_SCRIPT) {
|
||||
NodeShaderScript *nss = (NodeShaderScript *) node->storage;
|
||||
nss->bytecode = newdataadr(fd, nss->bytecode);
|
||||
nss->prop = newdataadr(fd, nss->prop);
|
||||
if (nss->prop)
|
||||
IDP_DirectLinkProperty(nss->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
|
||||
}
|
||||
}
|
||||
else if (ntree->type==NTREE_COMPOSIT) {
|
||||
if (ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
|
||||
direct_link_curvemapping(fd, node->storage);
|
||||
|
@@ -728,6 +728,16 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
|
||||
/* could be handlerized at some point, now only 1 exception still */
|
||||
if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
|
||||
write_curvemapping(wd, node->storage);
|
||||
else if (ntree->type==NTREE_SHADER && node->type==SH_NODE_SCRIPT) {
|
||||
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
|
||||
if (nss->bytecode)
|
||||
writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode);
|
||||
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
|
||||
* of library blocks that implement this.*/
|
||||
if (nss->prop)
|
||||
IDP_WriteProperty(nss->prop, wd);
|
||||
writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
|
||||
}
|
||||
else if (ntree->type==NTREE_COMPOSIT && ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
|
||||
write_curvemapping(wd, node->storage);
|
||||
else if (ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) )
|
||||
|
@@ -1384,6 +1384,34 @@ static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), Point
|
||||
uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||
{
|
||||
uiLayout *row;
|
||||
|
||||
row = uiLayoutRow(layout, FALSE);
|
||||
uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
|
||||
|
||||
row = uiLayoutRow(layout, TRUE);
|
||||
|
||||
if(RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL)
|
||||
uiItemR(row, ptr, "script", 0, "", ICON_NONE);
|
||||
else
|
||||
uiItemR(row, ptr, "filepath", 0,"", ICON_NONE);
|
||||
|
||||
uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
|
||||
}
|
||||
|
||||
static void node_shader_buts_script_details(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
uiItemS(layout);
|
||||
|
||||
node_shader_buts_script(layout, C, ptr);
|
||||
|
||||
/* not implemented yet
|
||||
if(RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL)
|
||||
uiItemR(layout, ptr, "use_auto_update", 0, NULL, ICON_NONE);*/
|
||||
}
|
||||
|
||||
/* only once called */
|
||||
static void node_shader_set_butfunc(bNodeType *ntype)
|
||||
{
|
||||
@@ -1467,6 +1495,10 @@ static void node_shader_set_butfunc(bNodeType *ntype)
|
||||
case SH_NODE_BSDF_GLASS:
|
||||
ntype->uifunc = node_shader_buts_glossy;
|
||||
break;
|
||||
case SH_NODE_SCRIPT:
|
||||
ntype->uifunc = node_shader_buts_script;
|
||||
ntype->uifuncbut = node_shader_buts_script_details;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_text_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
@@ -54,6 +55,7 @@
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_texture.h"
|
||||
|
||||
#include "RE_engine.h"
|
||||
#include "RE_pipeline.h"
|
||||
|
||||
|
||||
@@ -2137,3 +2139,119 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot)
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ********************** Shader Script Update ******************/
|
||||
|
||||
typedef struct ScriptUpdateData {
|
||||
RenderEngine *engine;
|
||||
RenderEngineType *type;
|
||||
|
||||
Text *text;
|
||||
int found;
|
||||
} ScriptUpdateData;
|
||||
|
||||
static int node_shader_script_update_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RenderEngineType *type = RE_engines_find(scene->r.engine);
|
||||
bNode *node;
|
||||
Text *text;
|
||||
|
||||
/* test if we have a render engine that supports shaders scripts */
|
||||
if(!(type && type->update_script_node))
|
||||
return 0;
|
||||
|
||||
/* see if we have a shader script node in context */
|
||||
node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data;
|
||||
if(node && node->type == SH_NODE_SCRIPT) {
|
||||
NodeShaderScript *nss = node->storage;
|
||||
|
||||
if(node->id || nss->filepath[0])
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* see if we have a text datablock in context */
|
||||
text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
|
||||
if(text)
|
||||
return 1;
|
||||
|
||||
/* we don't check if text datablock is actually in use, too slow for poll */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void node_shader_script_update_text(void *data_, ID *UNUSED(id), bNodeTree *ntree)
|
||||
{
|
||||
ScriptUpdateData *data = (ScriptUpdateData *)data_;
|
||||
bNode *node;
|
||||
|
||||
/* update each script that is using this text datablock */
|
||||
for (node=ntree->nodes.first; node; node=node->next) {
|
||||
if (node->type == NODE_GROUP){
|
||||
node_shader_script_update_text(data_, NULL, (bNodeTree *)node->id);
|
||||
}
|
||||
else if (node->type == SH_NODE_SCRIPT && node->id == &data->text->id) {
|
||||
data->type->update_script_node(data->engine, ntree, node);
|
||||
data->found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int node_shader_script_update_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ScriptUpdateData data;
|
||||
PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript);
|
||||
|
||||
/* setup render engine */
|
||||
data.type = RE_engines_find(scene->r.engine);
|
||||
data.engine = RE_engine_create(data.type);
|
||||
data.engine->reports = op->reports;
|
||||
data.text = NULL;
|
||||
data.found = FALSE;
|
||||
|
||||
if (nodeptr.data) {
|
||||
/* update single node */
|
||||
bNodeTree *ntree = nodeptr.id.data;
|
||||
bNode *node = nodeptr.data;
|
||||
|
||||
data.type->update_script_node(data.engine, ntree, node);
|
||||
|
||||
data.found = TRUE;
|
||||
}
|
||||
else {
|
||||
/* update all nodes using text datablock */
|
||||
data.text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
|
||||
|
||||
if (data.text) {
|
||||
bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER);
|
||||
|
||||
if (ntreetype && ntreetype->foreach_nodetree)
|
||||
ntreetype->foreach_nodetree(bmain, &data, node_shader_script_update_text);
|
||||
|
||||
if (!data.found)
|
||||
BKE_report(op->reports, RPT_INFO, "Text not used by any node, no update done.");
|
||||
}
|
||||
}
|
||||
|
||||
RE_engine_free(data.engine);
|
||||
|
||||
return (data.found)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void NODE_OT_shader_script_update(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Script Node Update";
|
||||
ot->description = "Update shader script node with new sockets and options from the script";
|
||||
ot->idname = "NODE_OT_shader_script_update";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = node_shader_script_update_exec;
|
||||
ot->poll = node_shader_script_update_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
|
@@ -206,6 +206,8 @@ void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot);
|
||||
void NODE_OT_clipboard_copy(struct wmOperatorType *ot);
|
||||
void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
|
||||
|
||||
void NODE_OT_shader_script_update(struct wmOperatorType *ot);
|
||||
|
||||
extern const char *node_context_dir[];
|
||||
|
||||
// XXXXXX
|
||||
|
@@ -117,6 +117,8 @@ void node_operatortypes(void)
|
||||
|
||||
WM_operatortype_append(NODE_OT_clipboard_copy);
|
||||
WM_operatortype_append(NODE_OT_clipboard_paste);
|
||||
|
||||
WM_operatortype_append(NODE_OT_shader_script_update);
|
||||
}
|
||||
|
||||
void ED_operatormacros_node(void)
|
||||
|
@@ -292,8 +292,7 @@ static void ui_node_sock_name(bNodeSocket *sock, char name[UI_MAX_NAME_STR])
|
||||
BLI_strncpy(node_name, node->typeinfo->name, UI_MAX_NAME_STR);
|
||||
|
||||
if (node->inputs.first == NULL &&
|
||||
node->outputs.first != node->outputs.last &&
|
||||
!(node->typeinfo->flag & NODE_OPTIONS))
|
||||
node->outputs.first != node->outputs.last)
|
||||
{
|
||||
BLI_snprintf(name, UI_MAX_NAME_STR, "%s | %s", IFACE_(node_name), IFACE_(sock->link->fromsock->name));
|
||||
}
|
||||
|
@@ -703,6 +703,26 @@ typedef struct NodeTrackPosData {
|
||||
char track_name[64];
|
||||
} NodeTrackPosData;
|
||||
|
||||
typedef struct NodeShaderScript {
|
||||
int mode;
|
||||
int flag;
|
||||
|
||||
char filepath[1024]; /* 1024 = FILE_MAX */
|
||||
|
||||
char bytecode_hash[64];
|
||||
char *bytecode;
|
||||
|
||||
IDProperty *prop;
|
||||
} NodeShaderScript;
|
||||
|
||||
/* script node mode */
|
||||
#define NODE_SCRIPT_INTERNAL 0
|
||||
#define NODE_SCRIPT_EXTERNAL 1
|
||||
|
||||
/* script node flag */
|
||||
#define NODE_SCRIPT_AUTO_UPDATE 1
|
||||
|
||||
|
||||
/* frame node flags */
|
||||
#define NODE_FRAME_SHRINK 1 /* keep the bounding box minimal */
|
||||
#define NODE_FRAME_RESIZEABLE 2 /* test flag, if frame can be resized by user */
|
||||
|
@@ -457,6 +457,7 @@ extern StructRNA RNA_ShaderNodeMath;
|
||||
extern StructRNA RNA_ShaderNodeMixRGB;
|
||||
extern StructRNA RNA_ShaderNodeNormal;
|
||||
extern StructRNA RNA_ShaderNodeOutput;
|
||||
extern StructRNA RNA_ShaderNodeScript;
|
||||
extern StructRNA RNA_ShaderNodeRGB;
|
||||
extern StructRNA RNA_ShaderNodeRGBCurve;
|
||||
extern StructRNA RNA_ShaderNodeRGBToBW;
|
||||
|
@@ -35,12 +35,16 @@
|
||||
#include "rna_internal_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_text_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
@@ -48,9 +52,9 @@
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_texture.h"
|
||||
#include "BKE_idprop.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "IMB_imbuf.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
|
||||
@@ -206,6 +210,8 @@ EnumPropertyItem prop_wave_items[] = {
|
||||
|
||||
#include "BLI_linklist.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "ED_node.h"
|
||||
|
||||
#include "RE_pipeline.h"
|
||||
@@ -995,6 +1001,125 @@ static void rna_NodeOutputFileSlotLayer_name_set(PointerRNA *ptr, const char *va
|
||||
}
|
||||
}
|
||||
|
||||
static bNodeSocket *rna_ShaderNodeScript_find_socket(bNode *node, const char *name, int is_output)
|
||||
{
|
||||
bNodeSocket *sock;
|
||||
|
||||
if (is_output) {
|
||||
for (sock = node->outputs.first; sock; sock = sock->next)
|
||||
if (strcmp(sock->name, name)==0)
|
||||
return sock;
|
||||
}
|
||||
else {
|
||||
for (sock = node->inputs.first; sock; sock = sock->next)
|
||||
if (strcmp(sock->name, name)==0)
|
||||
return sock;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rna_ShaderNodeScript_remove_socket(ID *id, bNode *node, bNodeSocket *sock)
|
||||
{
|
||||
bNodeTree *ntree = (bNodeTree *)id;
|
||||
|
||||
nodeRemoveSocket(ntree, node, sock);
|
||||
|
||||
ED_node_generic_update(G.main, ntree, node);
|
||||
}
|
||||
|
||||
static bNodeSocket *rna_ShaderNodeScript_add_socket(ID *id, bNode *node, const char *name, int type, int is_output)
|
||||
{
|
||||
bNodeTree *ntree = (bNodeTree *)id;
|
||||
bNodeSocket *sock;
|
||||
|
||||
/* replace existing socket with the same name, to keep it unique */
|
||||
sock = rna_ShaderNodeScript_find_socket(node, name, is_output);
|
||||
if (sock)
|
||||
nodeRemoveSocket(ntree, node, sock);
|
||||
sock = nodeAddSocket(ntree, node, (is_output ? SOCK_OUT : SOCK_IN), name, type);
|
||||
|
||||
ED_node_generic_update(G.main, ntree, node);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeShaderScript *nss = node->storage;
|
||||
|
||||
if (nss->mode != value) {
|
||||
nss->mode = value;
|
||||
nss->filepath[0] = '\0';
|
||||
nss->flag &= ~NODE_SCRIPT_AUTO_UPDATE;
|
||||
|
||||
/* replace text datablock by filepath */
|
||||
if (node->id) {
|
||||
Text *text = (Text*)node->id;
|
||||
|
||||
if(value == NODE_SCRIPT_EXTERNAL && text->name) {
|
||||
BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath));
|
||||
BLI_path_rel(nss->filepath, G.main->name);
|
||||
}
|
||||
|
||||
id_us_min(node->id);
|
||||
node->id = NULL;
|
||||
}
|
||||
|
||||
/* remove any bytecode */
|
||||
if(nss->bytecode) {
|
||||
MEM_freeN(nss->bytecode);
|
||||
nss->bytecode = NULL;
|
||||
}
|
||||
|
||||
nss->bytecode_hash[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_ShaderNodeScript_bytecode_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeShaderScript *nss = node->storage;
|
||||
|
||||
strcpy(value, (nss->bytecode)? nss->bytecode: "");
|
||||
}
|
||||
|
||||
static int rna_ShaderNodeScript_bytecode_length(PointerRNA *ptr)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeShaderScript *nss = node->storage;
|
||||
|
||||
return (nss->bytecode) ? strlen(nss->bytecode) : 0;
|
||||
}
|
||||
|
||||
static void rna_ShaderNodeScript_bytecode_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeShaderScript *nss = node->storage;
|
||||
|
||||
if (nss->bytecode)
|
||||
MEM_freeN(nss->bytecode);
|
||||
|
||||
if (value && value[0])
|
||||
nss->bytecode = BLI_strdup(value);
|
||||
else
|
||||
nss->bytecode = NULL;
|
||||
}
|
||||
|
||||
static IDProperty *rna_ShaderNodeScript_idprops(PointerRNA *ptr, int create)
|
||||
{
|
||||
bNode *node = (bNode *)ptr->data;
|
||||
NodeShaderScript *nss = node->storage;
|
||||
|
||||
if (create && !nss->prop) {
|
||||
IDPropertyTemplate val = {0};
|
||||
nss->prop = IDP_New(IDP_GROUP, &val, "RNA_ShaderNodeScript ID properties");
|
||||
}
|
||||
|
||||
return nss->prop;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static EnumPropertyItem prop_image_layer_items[] = {
|
||||
@@ -1035,6 +1160,12 @@ static EnumPropertyItem node_glossy_items[] = {
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static EnumPropertyItem node_script_mode_items[] = {
|
||||
{NODE_SCRIPT_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text datablock"},
|
||||
{NODE_SCRIPT_EXTERNAL, "EXTERNAL", 0, "External", "Use external .osl or oso file"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
#define MaxNodes 50000
|
||||
|
||||
enum
|
||||
@@ -1707,6 +1838,76 @@ static void def_glossy(StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_sh_script(StructRNA *srna)
|
||||
{
|
||||
FunctionRNA *func;
|
||||
PropertyRNA *prop, *parm;
|
||||
|
||||
prop = RNA_def_property(srna, "script", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "id");
|
||||
RNA_def_property_struct_type(prop, "Text");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Script", "Internal shader script to define the shader");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeShaderScript", "storage");
|
||||
RNA_def_struct_idprops_func(srna, "rna_ShaderNodeScript_idprops");
|
||||
|
||||
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
|
||||
RNA_def_property_ui_text(prop, "File Path", "Shader script path");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_ShaderNodeScript_mode_set", NULL);
|
||||
RNA_def_property_enum_items(prop, node_script_mode_items);
|
||||
RNA_def_property_ui_text(prop, "Script Source", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_auto_update", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_SCRIPT_AUTO_UPDATE);
|
||||
RNA_def_property_ui_text(prop, "Auto Update", "Automatically updates the shader when the .osl file changes - external scripts only");
|
||||
|
||||
prop = RNA_def_property(srna, "bytecode", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop, "rna_ShaderNodeScript_bytecode_get",
|
||||
"rna_ShaderNodeScript_bytecode_length", "rna_ShaderNodeScript_bytecode_set");
|
||||
RNA_def_property_ui_text(prop, "Bytecode", "Compile bytecode for shader script node");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "bytecode_hash", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Bytecode Hash", "Hash of compile bytecode, for quick equality checking");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
/* needs to be reset to avoid bad pointer type in API functions below */
|
||||
RNA_def_struct_sdna_from(srna, "bNode", NULL);
|
||||
|
||||
/* API functions */
|
||||
|
||||
func = RNA_def_function(srna, "find_socket", "rna_ShaderNodeScript_find_socket");
|
||||
RNA_def_function_ui_description(func, "Find a socket by name");
|
||||
parm = RNA_def_string(func, "name", "", 0, "Socket name", "");
|
||||
RNA_def_property_flag(parm, PROP_REQUIRED);
|
||||
/*parm =*/ RNA_def_boolean(func, "is_output", FALSE, "Output", "Whether the socket is an output");
|
||||
parm = RNA_def_pointer(func, "result", "NodeSocket", "", "");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "add_socket", "rna_ShaderNodeScript_add_socket");
|
||||
RNA_def_function_ui_description(func, "Add a socket socket");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
|
||||
parm = RNA_def_string(func, "name", "", 0, "Name", "");
|
||||
RNA_def_property_flag(parm, PROP_REQUIRED);
|
||||
parm = RNA_def_enum(func, "type", node_socket_type_items, SOCK_FLOAT, "Type", "");
|
||||
RNA_def_property_flag(parm, PROP_REQUIRED);
|
||||
/*parm =*/ RNA_def_boolean(func, "is_output", FALSE, "Output", "Whether the socket is an output");
|
||||
parm = RNA_def_pointer(func, "result", "NodeSocket", "", "");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "remove_socket", "rna_ShaderNodeScript_remove_socket");
|
||||
RNA_def_function_ui_description(func, "Remove a socket socket");
|
||||
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
|
||||
parm = RNA_def_pointer(func, "sock", "NodeSocket", "Socket", "");
|
||||
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
|
||||
}
|
||||
|
||||
/* -- Compositor Nodes ------------------------------------------------------ */
|
||||
|
||||
static void def_cmp_alpha_over(StructRNA *srna)
|
||||
|
@@ -82,7 +82,8 @@ DefNode( ShaderNode, SH_NODE_LIGHT_PATH, 0, "LI
|
||||
DefNode( ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "" )
|
||||
DefNode( ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "" )
|
||||
DefNode( ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "" )
|
||||
DefNode( ShaderNode, SH_NODE_BUMP, 0, "BUMP", BumpNode, "Bump", "" )
|
||||
DefNode( ShaderNode, SH_NODE_BUMP, 0, "BUMP", BumpNode, "Bump", "" )
|
||||
DefNode( ShaderNode, SH_NODE_SCRIPT, def_sh_script, "SCRIPT", Script, "Script", "" )
|
||||
DefNode( ShaderNode, SH_NODE_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "" )
|
||||
DefNode( ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","" )
|
||||
DefNode( ShaderNode, SH_NODE_TEX_SKY, def_sh_tex_sky, "TEX_SKY", TexSky, "Sky Texture", "" )
|
||||
|
@@ -129,6 +129,24 @@ static void engine_view_draw(RenderEngine *engine, const struct bContext *contex
|
||||
RNA_parameter_list_free(&list);
|
||||
}
|
||||
|
||||
static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node)
|
||||
{
|
||||
extern FunctionRNA rna_RenderEngine_update_script_node_func;
|
||||
PointerRNA ptr, nodeptr;
|
||||
ParameterList list;
|
||||
FunctionRNA *func;
|
||||
|
||||
RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
|
||||
RNA_pointer_create((ID*)ntree, &RNA_Node, node, &nodeptr);
|
||||
func = &rna_RenderEngine_update_script_node_func;
|
||||
|
||||
RNA_parameter_list_create(&list, &ptr, func);
|
||||
RNA_parameter_set_lookup(&list, "node", &nodeptr);
|
||||
engine->type->ext.call(NULL, &ptr, func, &list);
|
||||
|
||||
RNA_parameter_list_free(&list);
|
||||
}
|
||||
|
||||
/* RenderEngine registration */
|
||||
|
||||
static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type)
|
||||
@@ -149,7 +167,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
|
||||
RenderEngineType *et, dummyet = {NULL};
|
||||
RenderEngine dummyengine = {NULL};
|
||||
PointerRNA dummyptr;
|
||||
int have_function[4];
|
||||
int have_function[5];
|
||||
|
||||
/* setup dummy engine & engine type to store static properties in */
|
||||
dummyengine.type = &dummyet;
|
||||
@@ -188,6 +206,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
|
||||
et->render = (have_function[1]) ? engine_render : NULL;
|
||||
et->view_update = (have_function[2]) ? engine_view_update : NULL;
|
||||
et->view_draw = (have_function[3]) ? engine_view_draw : NULL;
|
||||
et->update_script_node = (have_function[4]) ? engine_update_script_node : NULL;
|
||||
|
||||
BLI_addtail(&R_engines, et);
|
||||
|
||||
@@ -300,6 +319,13 @@ static void rna_def_render_engine(BlenderRNA *brna)
|
||||
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
|
||||
RNA_def_pointer(func, "context", "Context", "", "");
|
||||
|
||||
/* shader script callbacks */
|
||||
func = RNA_def_function(srna, "update_script_node", NULL);
|
||||
RNA_def_function_ui_description(func, "Compile shader script node");
|
||||
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
|
||||
prop = RNA_def_pointer(func, "node", "Node", "", "");
|
||||
RNA_def_property_flag(prop, PROP_RNAPTR);
|
||||
|
||||
/* tag for redraw */
|
||||
RNA_def_function(srna, "tag_redraw", "engine_tag_redraw");
|
||||
RNA_def_function_ui_description(func, "Request redraw for viewport rendering");
|
||||
|
@@ -165,6 +165,7 @@ set(SRC
|
||||
shader/nodes/node_shader_light_path.c
|
||||
shader/nodes/node_shader_light_falloff.c
|
||||
shader/nodes/node_shader_object_info.c
|
||||
shader/nodes/node_shader_script.c
|
||||
shader/nodes/node_shader_particle_info.c
|
||||
shader/nodes/node_shader_mix_shader.c
|
||||
shader/nodes/node_shader_add_shader.c
|
||||
|
@@ -80,6 +80,7 @@ void register_node_type_sh_fresnel(struct bNodeTreeType *ttype);
|
||||
void register_node_type_sh_layer_weight(struct bNodeTreeType *ttype);
|
||||
void register_node_type_sh_tex_coord(struct bNodeTreeType *ttype);
|
||||
void register_node_type_sh_particle_info(struct bNodeTreeType *ttype);
|
||||
void register_node_type_sh_script(struct bNodeTreeType *ttype);
|
||||
|
||||
void register_node_type_sh_background(struct bNodeTreeType *ttype);
|
||||
void register_node_type_sh_bsdf_diffuse(struct bNodeTreeType *ttype);
|
||||
|
@@ -87,10 +87,11 @@ static void foreach_nodeclass(Scene *scene, void *calldata, bNodeClassCallback f
|
||||
func(calldata, NODE_CLASS_SHADER, N_("Shader"));
|
||||
func(calldata, NODE_CLASS_TEXTURE, N_("Texture"));
|
||||
}
|
||||
|
||||
|
||||
func(calldata, NODE_CLASS_OP_COLOR, N_("Color"));
|
||||
func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector"));
|
||||
func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor"));
|
||||
func(calldata, NODE_CLASS_SCRIPT, N_("Script"));
|
||||
func(calldata, NODE_CLASS_GROUP, N_("Group"));
|
||||
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
|
||||
}
|
||||
|
85
source/blender/nodes/shader/nodes/node_shader_script.c
Normal file
85
source/blender/nodes/shader/nodes/node_shader_script.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* ***** 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) 2005 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/nodes/shader/nodes/node_shader_script.c
|
||||
* \ingroup shdnodes
|
||||
*/
|
||||
|
||||
#include "BKE_idprop.h"
|
||||
|
||||
#include "node_shader_util.h"
|
||||
|
||||
/* **************** Script ******************** */
|
||||
|
||||
static void init(bNodeTree *UNUSED(ntree), bNode *node, bNodeTemplate *UNUSED(ntemp))
|
||||
{
|
||||
NodeShaderScript *nss = MEM_callocN(sizeof(NodeShaderScript), "shader script node");
|
||||
node->storage = nss;
|
||||
}
|
||||
|
||||
static void node_free_script(bNode *node)
|
||||
{
|
||||
NodeShaderScript *nss = node->storage;
|
||||
|
||||
if (nss) {
|
||||
if (nss->bytecode)
|
||||
MEM_freeN(nss->bytecode);
|
||||
|
||||
MEM_freeN(nss);
|
||||
}
|
||||
|
||||
if (nss->prop) {
|
||||
IDP_FreeProperty(nss->prop);
|
||||
MEM_freeN(nss->prop);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_copy_script(bNode *orig_node, bNode *new_node)
|
||||
{
|
||||
NodeShaderScript *orig_nss = orig_node->storage;
|
||||
NodeShaderScript *new_nss = MEM_dupallocN(orig_nss);
|
||||
|
||||
if(orig_nss->bytecode)
|
||||
new_nss->bytecode = MEM_dupallocN(orig_nss->bytecode);
|
||||
|
||||
if (orig_nss->prop)
|
||||
new_nss->prop = IDP_CopyProperty(orig_nss->prop);
|
||||
|
||||
new_node->storage = new_nss;
|
||||
}
|
||||
|
||||
void register_node_type_sh_script(bNodeTreeType *ttype)
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
node_type_base(ttype, &ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT, NODE_OPTIONS);
|
||||
node_type_compatibility(&ntype, NODE_NEW_SHADING);
|
||||
node_type_init(&ntype, init);
|
||||
node_type_storage(&ntype, "NodeShaderScript", node_free_script, node_copy_script);
|
||||
|
||||
nodeRegisterType(ttype, &ntype);
|
||||
}
|
@@ -35,6 +35,8 @@
|
||||
#include "DNA_listBase.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
struct bNode;
|
||||
struct bNodeTree;
|
||||
struct Object;
|
||||
struct Render;
|
||||
struct RenderEngine;
|
||||
@@ -75,6 +77,8 @@ typedef struct RenderEngineType {
|
||||
void (*view_update)(struct RenderEngine *engine, const struct bContext *context);
|
||||
void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
|
||||
|
||||
void (*update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node);
|
||||
|
||||
/* RNA integration */
|
||||
ExtensionRNA ext;
|
||||
} RenderEngineType;
|
||||
@@ -94,6 +98,8 @@ typedef struct RenderEngine {
|
||||
char *text;
|
||||
|
||||
int resolution_x, resolution_y;
|
||||
|
||||
struct ReportList *reports;
|
||||
} RenderEngine;
|
||||
|
||||
RenderEngine *RE_engine_create(RenderEngineType *type);
|
||||
|
@@ -64,7 +64,7 @@
|
||||
static RenderEngineType internal_render_type = {
|
||||
NULL, NULL,
|
||||
"BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ static RenderEngineType internal_render_type = {
|
||||
static RenderEngineType internal_game_type = {
|
||||
NULL, NULL,
|
||||
"BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -292,7 +292,12 @@ void RE_engine_update_progress(RenderEngine *engine, float progress)
|
||||
|
||||
void RE_engine_report(RenderEngine *engine, int type, const char *msg)
|
||||
{
|
||||
BKE_report(engine->re->reports, type, msg);
|
||||
Render *re = engine->re;
|
||||
|
||||
if (re)
|
||||
BKE_report(engine->re->reports, type, msg);
|
||||
else if(engine->reports)
|
||||
BKE_report(engine->reports, type, msg);
|
||||
}
|
||||
|
||||
/* Render */
|
||||
|
Reference in New Issue
Block a user