diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-11-03 18:32:26 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-11-03 18:32:26 +0400 |
commit | e02b23b81ab05579c0ee11ee3a1acb283643e528 (patch) | |
tree | 59b14c01bcb4c274d57c89a42e5a5d80c41ff06d /source | |
parent | 615fe0295fe13c229d7376b02a50ac110b636c47 (diff) |
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.
Diffstat (limited to 'source')
21 files changed, 562 insertions, 12 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index cd1875f848b..29e03f66bcc 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -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 diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 8738251fa78..cbe3b7dd231 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -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); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index b9ca3c9cc63..5995e69a73a 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -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) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8aa879a354b..a6e95541d9c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 2ccefad4506..d7c62837008 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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) ) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 420f0f1c413..f25fed3f6bb 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -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; } } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index f21f343ea2b..95dbe7e7b46 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -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; +} + diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 36ebddc8d22..45509e02226 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -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 diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 560ef9e8a29..64e5f67a348 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -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) diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index d4df449a41b..23f4e948794 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -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)); } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index aa382632b7b..bebe2ba20d5 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -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 */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a9dbbe4273f..5f667db4425 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index be9a2d8c613..85df288b38b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -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) diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index 6d97e959112..c45c9b71442 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -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", "" ) diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 7a638e9e40b..56497e96c67 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -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"); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 19b3df8affe..323a534c989 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -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 diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 7585ed0d61c..66ab15ce29f 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -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); diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 76bc3b12690..b7dc83d7d79 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -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")); } diff --git a/source/blender/nodes/shader/nodes/node_shader_script.c b/source/blender/nodes/shader/nodes/node_shader_script.c new file mode 100644 index 00000000000..52d39363de6 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_script.c @@ -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); +} diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 2376aeca55e..20024eab633 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -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); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 94146467145..076cad05c84 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -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 */ |