Render API: shader script node for custom shaders.
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 3 Nov 2012 14:32:26 +0000 (14:32 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 3 Nov 2012 14:32:26 +0000 (14:32 +0000)
* 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.

22 files changed:
release/scripts/startup/bl_ui/space_text.py
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/text.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_intern.h
source/blender/editors/space_node/node_ops.c
source/blender/editors/space_node/node_templates.c
source/blender/makesdna/DNA_node_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_nodetree_types.h
source/blender/makesrna/intern/rna_render.c
source/blender/nodes/CMakeLists.txt
source/blender/nodes/NOD_shader.h
source/blender/nodes/shader/node_shader_tree.c
source/blender/nodes/shader/nodes/node_shader_script.c [new file with mode: 0644]
source/blender/render/extern/include/RE_engine.h
source/blender/render/intern/source/external_engine.c

index eca9bc22db985aa41d66f423bd65e20c16f2fe62..8a853a09199fb9c5fcd248a3738d95234c7de9be 100644 (file)
@@ -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:
index cd1875f848b169730036caff863e2e43e7b132a4..29e03f66bcc6f3e36bea5ad97291affba16f8f88 100644 (file)
@@ -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
index 8738251fa78daca9026e35610220965ae59767e9..cbe3b7dd23112f3b569cfbaebda011b13885f081 100644 (file)
@@ -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);
index b9ca3c9cc63b629e51f06464fb6fb854d4546a7d..5995e69a73ab9e2518dc3af800c2864027d14294 100644 (file)
 #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) {
index 8aa879a354b8073c9550e628eaaf5fc51e59c1b6..a6e95541d9c9922196da34cea6fc1f71c8d71841 100644 (file)
@@ -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);
index 2ccefad4506fec0500cbc62e46345cce19a73c1b..d7c628370086ed790a4d32396f6a2a8505bc1b94 100644 (file)
@@ -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) )
index 420f0f1c413975107c90ad3f6b8498f0c927d3b7..f25fed3f6bb97bf7c3db6bfd916774afa2fde62a 100644 (file)
@@ -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;
        }
 }
 
index f21f343ea2b8f230078adadcacd52ba6598b3eb5..95dbe7e7b46309a86a76a89a6c4313d4468901c9 100644 (file)
@@ -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;
+}
+
index 36ebddc8d221b602730542dd08b598bf5ca178eb..45509e02226a0469a29167865af2ff4e06521836 100644 (file)
@@ -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
index 560ef9e8a29885f1bec4c95f70249b6977652d51..64e5f67a3480abaf4aa13c6cda3242434777b4aa 100644 (file)
@@ -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)
index d4df449a41b0dd618e3bd9115aea759ef4c9629a..23f4e948794ac2b257d1903149fe3a2edd097c08 100644 (file)
@@ -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));
                }
index aa382632b7b13e9b2330bcacad86e1326b15e60e..bebe2ba20d5b3305bb8fe7bc2e58fe070c2ad785 100644 (file)
@@ -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 */
index a9dbbe4273fb5681823fe25bbaf8e4acad54a468..5f667db442545fd5b4a6a159c310cab088145136 100644 (file)
@@ -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;
index be9a2d8c613e64ca93a64ec436b84b3482b21757..85df288b38bcc938c2d7bb139e98a2e73657d3b5 100644 (file)
 #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)
index 6d97e959112156b2412270100061a858aef2d5c2..c45c9b714425069e5761428ee8a31dd8e1cccc51 100644 (file)
@@ -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",       ""       )
index 7a638e9e40b21d60c1dced5ad2dbad0bbcde3a3e..56497e96c672b817d3f92a10599cdfa27db160d7 100644 (file)
@@ -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");
index 19b3df8affe22e2c79cf1449318af75fd5bd104d..323a534c989a5df544851736c4be3f3c2fc2d40c 100644 (file)
@@ -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
index 7585ed0d61cc0b34d5eea954396773173570a781..66ab15ce29f3a10a24c2661a0990fe1018cc2d63 100644 (file)
@@ -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);
index 76bc3b126909afd804ce332d6b3fcb1450d97917..b7dc83d7d79d929c869ac792af644f421251dd38 100644 (file)
@@ -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 (file)
index 0000000..52d3936
--- /dev/null
@@ -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);
+}
index 2376aeca55e8d5beb076f3176c079d39d5041998..20024eab633ac09a0db9364afb1db2b0deab83e5 100644 (file)
@@ -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);
index 94146467145c61e10b5b0a46023cc659c50483b8..076cad05c84d4f2587ed7f26436eb2b70c088c15 100644 (file)
@@ -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 */