2016-01-26 14:36:55 +01:00
|
|
|
import bpy
|
|
|
|
from bpy.types import NodeTree, Node, NodeSocket
|
|
|
|
from bpy.props import *
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import json
|
2016-02-08 12:03:20 +01:00
|
|
|
import platform
|
|
|
|
import subprocess
|
2016-06-22 12:21:15 +02:00
|
|
|
import nodes_compositor
|
2016-05-18 01:34:21 +02:00
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
class CGPipelineTree(NodeTree):
|
|
|
|
'''Pipeline nodes'''
|
|
|
|
bl_idname = 'CGPipelineTreeType'
|
|
|
|
bl_label = 'CG Pipeline Node Tree'
|
|
|
|
bl_icon = 'GAME'
|
|
|
|
|
|
|
|
class CGPipelineTreeNode:
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, ntree):
|
|
|
|
return ntree.bl_idname == 'CGPipelineTreeType'
|
|
|
|
|
|
|
|
class DrawGeometryNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'DrawGeometryNodeType'
|
|
|
|
bl_label = 'Draw Geometry'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketString', "Context")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-05-18 01:34:21 +02:00
|
|
|
class DrawDecalsNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'DrawDecalsNodeType'
|
|
|
|
bl_label = 'Draw Decals'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketString', "Context")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
class ClearTargetNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'ClearTargetNodeType'
|
|
|
|
bl_label = 'Clear Target'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketBool', "Color")
|
2016-05-27 01:12:21 +02:00
|
|
|
self.inputs.new('NodeSocketColor', "Value")
|
2016-01-26 14:36:55 +01:00
|
|
|
self.inputs.new('NodeSocketBool', "Depth")
|
2016-05-27 01:12:21 +02:00
|
|
|
self.inputs.new('NodeSocketFloat', "Value")
|
|
|
|
self.inputs[4].default_value = 1.0
|
2016-04-02 00:33:19 +02:00
|
|
|
self.inputs.new('NodeSocketBool', "Stencil")
|
2016-05-27 01:12:21 +02:00
|
|
|
self.inputs.new('NodeSocketInt', "Value")
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
2016-04-18 01:16:51 +02:00
|
|
|
|
|
|
|
class BeginNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'BeginNodeType'
|
|
|
|
bl_label = 'Begin'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
class SetTargetNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'SetTargetNodeType'
|
|
|
|
bl_label = 'Set Target'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
|
|
|
class TargetNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'TargetNodeType'
|
|
|
|
bl_label = 'Target'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketString', "ID")
|
|
|
|
self.inputs.new('NodeSocketInt', "Width")
|
|
|
|
self.inputs.new('NodeSocketInt', "Height")
|
2016-06-03 17:18:38 +02:00
|
|
|
self.inputs.new('NodeSocketShader', "Depth Buffer")
|
2016-01-26 14:36:55 +01:00
|
|
|
self.inputs.new('NodeSocketString', "Format")
|
2016-04-16 03:50:51 +02:00
|
|
|
self.inputs.new('NodeSocketBool', "Ping Pong")
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Target")
|
2016-06-03 17:18:38 +02:00
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
|
|
|
class DebthBufferNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'DepthBufferNodeType'
|
|
|
|
bl_label = 'Depth Buffer'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketString', "ID")
|
|
|
|
self.inputs.new('NodeSocketBool', "Stencil")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Target")
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
2016-04-18 01:16:51 +02:00
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
class GBufferNode(Node, CGPipelineTreeNode):
|
2016-04-18 01:16:51 +02:00
|
|
|
'''A custom node'''
|
2016-05-25 00:13:44 +02:00
|
|
|
bl_idname = 'GBufferNodeType'
|
|
|
|
bl_label = 'GBuffer'
|
2016-04-18 01:16:51 +02:00
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
2016-05-25 00:13:44 +02:00
|
|
|
self.inputs.new('NodeSocketShader', "Target 0")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target 1")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target 2")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target 3")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target 4")
|
2016-05-13 00:08:11 +02:00
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
self.outputs.new('NodeSocketShader', "Targets")
|
2016-05-13 00:08:11 +02:00
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
2016-04-18 01:16:51 +02:00
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
class FramebufferNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'FramebufferNodeType'
|
|
|
|
bl_label = 'Framebuffer'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.outputs.new('NodeSocketShader', "Target")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
|
|
|
class BindTargetNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'BindTargetNodeType'
|
|
|
|
bl_label = 'Bind Target'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target")
|
|
|
|
self.inputs.new('NodeSocketString', "Constant")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-04-15 00:02:32 +02:00
|
|
|
class DrawMaterialQuadNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'DrawMaterialQuadNodeType'
|
|
|
|
bl_label = 'Draw Material Quad'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketString', "Material Context")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
class DrawQuadNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'DrawQuadNodeType'
|
|
|
|
bl_label = 'Draw Quad'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
2016-04-15 00:02:32 +02:00
|
|
|
self.inputs.new('NodeSocketString', "Shader Context")
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
2016-05-05 19:50:03 +02:00
|
|
|
|
|
|
|
class CallFunctionNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'CallFunctionNodeType'
|
|
|
|
bl_label = 'Call Function'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketString', "Function")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
|
|
|
class BranchFunctionNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'BranchFunctionNodeType'
|
|
|
|
bl_label = 'Branch Function'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketString', "Function")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "True")
|
|
|
|
self.outputs.new('NodeSocketShader', "False")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
|
|
|
class MergeStagesNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'MergeStagesNodeType'
|
|
|
|
bl_label = 'Merge Stages'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
2016-02-08 14:58:55 +01:00
|
|
|
|
|
|
|
class DrawWorldNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'DrawWorldNodeType'
|
|
|
|
bl_label = 'Draw World'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-06-22 12:21:15 +02:00
|
|
|
class DrawCompositorNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'DrawCompositorNodeType'
|
|
|
|
bl_label = 'Draw Compositor'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target")
|
|
|
|
self.inputs.new('NodeSocketShader', "Color")
|
|
|
|
self.inputs.new('NodeSocketShader', "GBuffer")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-04-20 23:11:25 +02:00
|
|
|
# Pass nodes
|
2016-04-15 20:19:39 +02:00
|
|
|
class QuadPassNode(Node, CGPipelineTreeNode):
|
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'QuadPassNodeType'
|
|
|
|
bl_label = 'Quad Pass'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.inputs.new('NodeSocketShader', "Stage")
|
|
|
|
self.inputs.new('NodeSocketShader', "Target")
|
|
|
|
self.inputs.new('NodeSocketString', "Shader Context")
|
|
|
|
self.inputs.new('NodeSocketShader', "Bind 1")
|
|
|
|
self.inputs.new('NodeSocketString', "Constant")
|
|
|
|
self.inputs.new('NodeSocketShader', "Bind 2")
|
|
|
|
self.inputs.new('NodeSocketString', "Constant")
|
|
|
|
self.inputs.new('NodeSocketShader', "Bind 3")
|
|
|
|
self.inputs.new('NodeSocketString', "Constant")
|
|
|
|
|
|
|
|
self.outputs.new('NodeSocketShader', "Stage")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-04-20 23:11:25 +02:00
|
|
|
# Constant nodes
|
2016-05-18 01:34:21 +02:00
|
|
|
class ScreenNode(Node, CGPipelineTreeNode):
|
2016-04-20 23:11:25 +02:00
|
|
|
'''A custom node'''
|
|
|
|
bl_idname = 'ScreenNodeType'
|
|
|
|
bl_label = 'Screen'
|
|
|
|
bl_icon = 'SOUND'
|
|
|
|
|
|
|
|
def init(self, context):
|
|
|
|
self.outputs.new('NodeSocketInt', "Width")
|
|
|
|
self.outputs.new('NodeSocketInt', "Height")
|
|
|
|
|
|
|
|
def copy(self, node):
|
|
|
|
print("Copying from node ", node)
|
|
|
|
|
|
|
|
def free(self):
|
|
|
|
print("Removing node ", self, ", Goodbye!")
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
### Node Categories ###
|
|
|
|
# Node categories are a python system for automatically
|
|
|
|
# extending the Add menu, toolbar panels and search operator.
|
|
|
|
# For more examples see release/scripts/startup/nodeitems_builtins.py
|
|
|
|
|
|
|
|
import nodeitems_utils
|
|
|
|
from nodeitems_utils import NodeCategory, NodeItem
|
|
|
|
|
|
|
|
class MyPipelineNodeCategory(NodeCategory):
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, context):
|
|
|
|
return context.space_data.tree_type == 'CGPipelineTreeType'
|
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
class MyTargetNodeCategory(NodeCategory):
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, context):
|
|
|
|
return context.space_data.tree_type == 'CGPipelineTreeType'
|
|
|
|
|
2016-04-15 20:19:39 +02:00
|
|
|
class MyPassNodeCategory(NodeCategory):
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, context):
|
|
|
|
return context.space_data.tree_type == 'CGPipelineTreeType'
|
2016-04-20 23:11:25 +02:00
|
|
|
|
|
|
|
class MyConstantNodeCategory(NodeCategory):
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, context):
|
|
|
|
return context.space_data.tree_type == 'CGPipelineTreeType'
|
2016-04-15 20:19:39 +02:00
|
|
|
|
2016-05-05 19:50:03 +02:00
|
|
|
class MyLogicNodeCategory(NodeCategory):
|
|
|
|
@classmethod
|
|
|
|
def poll(cls, context):
|
|
|
|
return context.space_data.tree_type == 'CGPipelineTreeType'
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
node_categories = [
|
2016-04-15 20:19:39 +02:00
|
|
|
MyPipelineNodeCategory("PIPELINENODES", "Pipeline", items=[
|
2016-04-18 01:16:51 +02:00
|
|
|
NodeItem("BeginNodeType"),
|
2016-01-26 14:36:55 +01:00
|
|
|
NodeItem("DrawGeometryNodeType"),
|
2016-05-18 01:34:21 +02:00
|
|
|
NodeItem("DrawDecalsNodeType"),
|
2016-01-26 14:36:55 +01:00
|
|
|
NodeItem("ClearTargetNodeType"),
|
|
|
|
NodeItem("SetTargetNodeType"),
|
|
|
|
NodeItem("BindTargetNodeType"),
|
2016-04-15 00:02:32 +02:00
|
|
|
NodeItem("DrawMaterialQuadNodeType"),
|
2016-01-26 14:36:55 +01:00
|
|
|
NodeItem("DrawQuadNodeType"),
|
2016-02-08 14:58:55 +01:00
|
|
|
NodeItem("DrawWorldNodeType"),
|
2016-06-22 12:21:15 +02:00
|
|
|
NodeItem("DrawCompositorNodeType"),
|
2016-05-25 00:13:44 +02:00
|
|
|
]),
|
|
|
|
MyTargetNodeCategory("TARGETNODES", "Target", items=[
|
2016-01-26 14:36:55 +01:00
|
|
|
NodeItem("TargetNodeType"),
|
2016-06-03 17:18:38 +02:00
|
|
|
NodeItem("DepthBufferNodeType"),
|
2016-05-25 00:13:44 +02:00
|
|
|
NodeItem("GBufferNodeType"),
|
2016-01-26 14:36:55 +01:00
|
|
|
NodeItem("FramebufferNodeType"),
|
2016-04-20 23:11:25 +02:00
|
|
|
]),
|
2016-04-15 20:19:39 +02:00
|
|
|
MyPassNodeCategory("PASSNODES", "Pass", items=[
|
|
|
|
NodeItem("QuadPassNodeType"),
|
2016-05-25 00:13:44 +02:00
|
|
|
# Prebuilt passes here
|
2016-04-20 23:11:25 +02:00
|
|
|
]),
|
|
|
|
MyConstantNodeCategory("CONSTANTNODES", "Constant", items=[
|
|
|
|
NodeItem("ScreenNodeType"),
|
|
|
|
]),
|
2016-05-05 19:50:03 +02:00
|
|
|
MyLogicNodeCategory("LOGICNODES", "Logic", items=[
|
|
|
|
NodeItem("CallFunctionNodeType"),
|
|
|
|
NodeItem("BranchFunctionNodeType"),
|
|
|
|
NodeItem("MergeStagesNodeType"),
|
|
|
|
]),
|
2016-04-15 20:19:39 +02:00
|
|
|
]
|
2016-05-25 00:13:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-02-08 12:03:20 +01:00
|
|
|
def reload_blend_data():
|
2016-01-27 23:40:33 +01:00
|
|
|
if bpy.data.node_groups.get('forward_pipeline') == None:
|
2016-02-08 12:03:20 +01:00
|
|
|
load_library()
|
|
|
|
pass
|
|
|
|
|
|
|
|
def load_library():
|
|
|
|
haxelib_path = "haxelib"
|
|
|
|
if platform.system() == 'Darwin':
|
|
|
|
haxelib_path = "/usr/local/bin/haxelib"
|
|
|
|
|
|
|
|
output = subprocess.check_output([haxelib_path + " path cyclesgame"], shell=True)
|
|
|
|
output = str(output).split("\\n")[0].split("'")[1]
|
|
|
|
data_path = output[:-8] + "blender/data/data.blend" # Remove 'Sources/' from haxelib path
|
|
|
|
|
|
|
|
with bpy.data.libraries.load(data_path, link=False) as (data_from, data_to):
|
2016-03-17 20:56:03 +01:00
|
|
|
data_to.node_groups = ['forward_pipeline', 'forward_pipeline_noshadow', 'deferred_pipeline', 'pathtrace_pipeline', 'PBR']
|
2016-01-28 13:21:51 +01:00
|
|
|
|
2016-02-08 12:03:20 +01:00
|
|
|
# TODO: cannot use for loop
|
|
|
|
# TODO: import pbr group separately, no need for fake user
|
|
|
|
bpy.data.node_groups['forward_pipeline'].use_fake_user = True
|
|
|
|
bpy.data.node_groups['forward_pipeline_noshadow'].use_fake_user = True
|
|
|
|
bpy.data.node_groups['deferred_pipeline'].use_fake_user = True
|
2016-03-17 20:56:03 +01:00
|
|
|
bpy.data.node_groups['pathtrace_pipeline'].use_fake_user = True
|
2016-03-08 14:45:22 +01:00
|
|
|
bpy.data.node_groups['PBR'].use_fake_user = True
|
2016-01-28 13:21:51 +01:00
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
def register():
|
|
|
|
bpy.utils.register_module(__name__)
|
|
|
|
try:
|
2016-01-27 23:40:33 +01:00
|
|
|
nodeitems_utils.register_node_categories("CG_PIPELINE_NODES", node_categories)
|
2016-02-08 12:03:20 +01:00
|
|
|
reload_blend_data()
|
2016-01-26 14:36:55 +01:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def unregister():
|
2016-01-27 23:40:33 +01:00
|
|
|
nodeitems_utils.unregister_node_categories("CG_PIPELINE_NODES")
|
2016-01-26 14:36:55 +01:00
|
|
|
bpy.utils.unregister_module(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
# Generating pipeline resources
|
|
|
|
class Object:
|
|
|
|
def to_JSON(self):
|
2016-04-20 19:35:22 +02:00
|
|
|
if bpy.data.worlds[0].CGMinimize == True:
|
|
|
|
return json.dumps(self, default=lambda o: o.__dict__, separators=(',',':'))
|
|
|
|
else:
|
|
|
|
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-03-15 11:29:53 +01:00
|
|
|
def buildNodeTrees(shader_references, asset_references):
|
2016-01-26 14:36:55 +01:00
|
|
|
s = bpy.data.filepath.split(os.path.sep)
|
|
|
|
s.pop()
|
|
|
|
fp = os.path.sep.join(s)
|
|
|
|
os.chdir(fp)
|
|
|
|
|
|
|
|
# Make sure Assets dir exists
|
|
|
|
if not os.path.exists('Assets/generated/pipelines'):
|
|
|
|
os.makedirs('Assets/generated/pipelines')
|
|
|
|
|
2016-03-15 11:29:53 +01:00
|
|
|
# Export selected pipeline
|
|
|
|
# node_group.bl_idname == 'CGPipelineTreeType'
|
|
|
|
node_group = bpy.data.node_groups[bpy.data.cameras[0].pipeline_path]
|
|
|
|
buildNodeTree(node_group, shader_references, asset_references)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-03-15 11:29:53 +01:00
|
|
|
def buildNodeTree(node_group, shader_references, asset_references):
|
2016-01-26 14:36:55 +01:00
|
|
|
output = Object()
|
|
|
|
res = Object()
|
|
|
|
output.pipeline_resources = [res]
|
|
|
|
|
|
|
|
path = 'Assets/generated/pipelines/'
|
|
|
|
node_group_name = node_group.name.replace('.', '_')
|
|
|
|
|
|
|
|
rn = getRootNode(node_group)
|
2016-01-28 14:47:46 +01:00
|
|
|
if rn == None:
|
|
|
|
return
|
2016-03-15 11:29:53 +01:00
|
|
|
|
2016-06-07 09:38:49 +02:00
|
|
|
res.id = node_group_name
|
|
|
|
res.render_targets, res.depth_buffers = get_render_targets(rn, node_group)
|
|
|
|
res.stages = []
|
|
|
|
|
2016-03-15 11:29:53 +01:00
|
|
|
# Used to merge bind target nodes into one stage
|
|
|
|
last_bind_target = None
|
|
|
|
|
2016-05-05 19:50:03 +02:00
|
|
|
buildNode(res.stages, rn, node_group, last_bind_target, shader_references, asset_references)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
with open(path + node_group_name + '.json', 'w') as f:
|
|
|
|
f.write(output.to_JSON())
|
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
def make_set_target(stage, node_group, node, currentNode=None, target_index=1):
|
|
|
|
if currentNode == None:
|
|
|
|
currentNode = node
|
|
|
|
|
2016-04-15 20:19:39 +02:00
|
|
|
stage.command = 'set_target'
|
2016-05-25 00:13:44 +02:00
|
|
|
currentNode = findNodeByLink(node_group, currentNode, currentNode.inputs[target_index])
|
2016-04-18 01:16:51 +02:00
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
if currentNode.bl_idname == 'TargetNodeType':
|
|
|
|
targetId = currentNode.inputs[0].default_value
|
|
|
|
stage.params.append(targetId)
|
2016-04-18 01:16:51 +02:00
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
elif currentNode.bl_idname == 'GBufferNodeType':
|
|
|
|
# Set all linked targets
|
|
|
|
for i in range(0, 5):
|
|
|
|
if currentNode.inputs[i].is_linked:
|
|
|
|
make_set_target(stage, node_group, node, currentNode, target_index=i)
|
2016-04-18 01:16:51 +02:00
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
elif currentNode.bl_idname == 'NodeReroute':
|
|
|
|
make_set_target(stage, node_group, node, currentNode, target_index=0)
|
2016-04-18 10:46:55 +02:00
|
|
|
|
2016-04-15 20:19:39 +02:00
|
|
|
else: # Framebuffer
|
|
|
|
targetId = ''
|
2016-05-25 00:13:44 +02:00
|
|
|
stage.params.append(targetId)
|
2016-04-15 20:19:39 +02:00
|
|
|
|
|
|
|
def make_clear_target(stage, node_group, node):
|
|
|
|
stage.command = 'clear_target'
|
|
|
|
if node.inputs[1].default_value == True:
|
|
|
|
stage.params.append('color')
|
2016-05-27 01:12:21 +02:00
|
|
|
val = node.inputs[2].default_value
|
|
|
|
hex = '#%02x%02x%02x%02x' % (int(val[3] * 255), int(val[0] * 255), int(val[1] * 255), int(val[2] * 255))
|
|
|
|
stage.params.append(str(hex))
|
2016-04-15 20:19:39 +02:00
|
|
|
if node.inputs[3].default_value == True:
|
2016-05-27 01:12:21 +02:00
|
|
|
stage.params.append('depth')
|
|
|
|
val = node.inputs[4].default_value
|
|
|
|
stage.params.append(str(val))
|
|
|
|
if node.inputs[5].default_value == True:
|
2016-04-15 20:19:39 +02:00
|
|
|
stage.params.append('stencil')
|
2016-05-27 01:12:21 +02:00
|
|
|
val = node.inputs[6].default_value
|
|
|
|
stage.params.append(str(val))
|
2016-04-15 20:19:39 +02:00
|
|
|
|
|
|
|
def make_draw_geometry(stage, node_group, node):
|
|
|
|
stage.command = 'draw_geometry'
|
|
|
|
stage.params.append(node.inputs[1].default_value) # Context
|
2016-05-18 01:34:21 +02:00
|
|
|
|
|
|
|
def make_draw_decals(stage, node_group, node, shader_references, asset_references):
|
|
|
|
stage.command = 'draw_decals'
|
|
|
|
context = node.inputs[1].default_value
|
|
|
|
stage.params.append(context) # Context
|
|
|
|
bpy.data.cameras[0].last_decal_context = context
|
2016-04-15 20:19:39 +02:00
|
|
|
|
2016-06-22 12:21:15 +02:00
|
|
|
def make_bind_target(stage, node_group, node, currentNode=None, target_index=1, constant_index=2, constant_name=None):
|
2016-05-25 00:13:44 +02:00
|
|
|
if currentNode == None:
|
|
|
|
currentNode = node
|
2016-05-13 00:08:11 +02:00
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
stage.command = 'bind_target'
|
2016-04-18 01:16:51 +02:00
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
link = findLink(node_group, currentNode, currentNode.inputs[target_index])
|
|
|
|
currentNode = link.from_node
|
|
|
|
|
2016-06-22 12:21:15 +02:00
|
|
|
if constant_name == None:
|
|
|
|
constant_name = node.inputs[constant_index].default_value
|
|
|
|
|
2016-05-25 00:13:44 +02:00
|
|
|
if currentNode.bl_idname == 'NodeReroute':
|
2016-06-22 12:21:15 +02:00
|
|
|
make_bind_target(stage, node_group, node, currentNode, target_index=0, constant_index=constant_index, constant_name=constant_name)
|
2016-05-25 00:13:44 +02:00
|
|
|
|
|
|
|
elif currentNode.bl_idname == 'GBufferNodeType':
|
|
|
|
for i in range(0, 5):
|
|
|
|
if currentNode.inputs[i].is_linked:
|
|
|
|
targetNode = findNodeByLink(node_group, currentNode, currentNode.inputs[i])
|
|
|
|
targetId = targetNode.inputs[0].default_value
|
2016-05-27 01:12:21 +02:00
|
|
|
# if i == 0 and targetNode.inputs[3].default_value == True: # Depth
|
2016-06-03 17:18:38 +02:00
|
|
|
if targetNode.inputs[3].is_linked: # Depth
|
|
|
|
db_node = findNodeByLink(node_group, targetNode, targetNode.inputs[3])
|
|
|
|
db_id = db_node.inputs[0].default_value
|
|
|
|
stage.params.append('_' + db_id)
|
2016-06-22 12:21:15 +02:00
|
|
|
stage.params.append(constant_name + 'D')
|
2016-05-25 00:13:44 +02:00
|
|
|
stage.params.append(targetId) # Color buffer
|
2016-06-22 12:21:15 +02:00
|
|
|
stage.params.append(constant_name + str(i))
|
2016-05-25 00:13:44 +02:00
|
|
|
|
|
|
|
elif currentNode.bl_idname == 'TargetNodeType':
|
2016-06-03 17:18:38 +02:00
|
|
|
targetId = currentNode.inputs[0].default_value
|
|
|
|
stage.params.append(targetId)
|
2016-06-22 12:21:15 +02:00
|
|
|
stage.params.append(constant_name)
|
2016-06-03 17:18:38 +02:00
|
|
|
|
|
|
|
elif currentNode.bl_idname == 'DepthBufferNodeType':
|
|
|
|
targetId = '_' + currentNode.inputs[0].default_value
|
2016-05-25 00:13:44 +02:00
|
|
|
stage.params.append(targetId)
|
2016-06-22 12:21:15 +02:00
|
|
|
stage.params.append(constant_name)
|
2016-04-15 20:19:39 +02:00
|
|
|
|
|
|
|
def make_draw_material_quad(stage, node_group, node, shader_references, asset_references, context_index=1):
|
|
|
|
stage.command = 'draw_material_quad'
|
|
|
|
material_context = node.inputs[context_index].default_value
|
|
|
|
stage.params.append(material_context)
|
|
|
|
# Include resource and shaders
|
2016-06-07 09:38:49 +02:00
|
|
|
shader_context = node.inputs[context_index].default_value
|
2016-06-03 17:18:38 +02:00
|
|
|
scon = shader_context.split('/')
|
2016-06-07 09:38:49 +02:00
|
|
|
dir_name = scon[2]
|
|
|
|
# No world defs for material passes
|
|
|
|
res_name = scon[2]
|
2016-06-03 17:18:38 +02:00
|
|
|
asset_references.append('compiled/ShaderResources/' + dir_name + '/' + res_name + '.json')
|
|
|
|
shader_references.append('compiled/Shaders/' + dir_name + '/' + res_name)
|
2016-04-15 20:19:39 +02:00
|
|
|
|
|
|
|
def make_draw_quad(stage, node_group, node, shader_references, asset_references, context_index=1):
|
|
|
|
stage.command = 'draw_shader_quad'
|
2016-06-03 17:18:38 +02:00
|
|
|
# Append world defs to get proper context
|
|
|
|
world_defs = bpy.data.worlds[0].world_defs
|
2016-04-15 20:19:39 +02:00
|
|
|
shader_context = node.inputs[context_index].default_value
|
2016-06-03 17:18:38 +02:00
|
|
|
scon = shader_context.split('/')
|
|
|
|
stage.params.append(scon[0] + world_defs + '/' + scon[1] + world_defs + '/' + scon[2])
|
2016-04-15 20:19:39 +02:00
|
|
|
# Include resource and shaders
|
2016-06-03 17:18:38 +02:00
|
|
|
dir_name = scon[0]
|
|
|
|
# Append world defs
|
|
|
|
res_name = scon[1] + world_defs
|
|
|
|
asset_references.append('compiled/ShaderResources/' + dir_name + '/' + res_name + '.json')
|
|
|
|
shader_references.append('compiled/Shaders/' + dir_name + '/' + res_name)
|
2016-04-15 20:19:39 +02:00
|
|
|
|
|
|
|
def make_draw_world(stage, node_group, node):
|
|
|
|
stage.command = 'draw_material_quad'
|
|
|
|
wname = bpy.data.worlds[0].name
|
|
|
|
stage.params.append(wname + '_material/' + wname + '_material/env_map') # Only one world for now
|
|
|
|
|
2016-06-22 12:21:15 +02:00
|
|
|
def make_draw_compositor(stage, node_group, node, shader_references, asset_references):
|
|
|
|
scon = 'compositor_pass'
|
|
|
|
world_defs = bpy.data.worlds[0].world_defs
|
|
|
|
compositor_defs = nodes_compositor.parse_defs(bpy.data.scenes[0].node_tree) # Thrown in scene 0 for now
|
|
|
|
defs = world_defs + compositor_defs
|
|
|
|
res_name = scon + defs
|
|
|
|
|
|
|
|
stage.command = 'draw_shader_quad'
|
|
|
|
stage.params.append(res_name + '/' + res_name + '/' + scon)
|
|
|
|
# Include resource and shaders
|
|
|
|
asset_references.append('compiled/ShaderResources/' + scon + '/' + res_name + '.json')
|
|
|
|
shader_references.append('compiled/Shaders/' + scon + '/' + res_name)
|
|
|
|
|
2016-05-05 19:50:03 +02:00
|
|
|
def make_call_function(stage, node_group, node):
|
|
|
|
stage.command = 'call_function'
|
|
|
|
stage.params.append(node.inputs[1].default_value)
|
|
|
|
|
|
|
|
def make_branch_function(stage, node_group, node):
|
|
|
|
make_call_function(stage, node_group, node)
|
|
|
|
|
|
|
|
def process_call_function(stage, stages, node, node_group, last_bind_target, shader_references, asset_references):
|
|
|
|
# Step till merge node
|
|
|
|
stage.returns_true = []
|
|
|
|
if node.outputs[0].is_linked:
|
|
|
|
stageNode = findNodeByLinkFrom(node_group, node, node.outputs[0])
|
|
|
|
buildNode(stage.returns_true, stageNode, node_group, last_bind_target, shader_references, asset_references)
|
|
|
|
|
|
|
|
stage.returns_false = []
|
|
|
|
if node.outputs[1].is_linked:
|
|
|
|
stageNode = findNodeByLinkFrom(node_group, node, node.outputs[1])
|
|
|
|
margeNode = buildNode(stage.returns_false, stageNode, node_group, last_bind_target, shader_references, asset_references)
|
|
|
|
|
|
|
|
# Continue using top level stages after merge node
|
|
|
|
afterMergeNode = findNodeByLinkFrom(node_group, margeNode, margeNode.outputs[0])
|
|
|
|
buildNode(stages, afterMergeNode, node_group, last_bind_target, shader_references, asset_references)
|
|
|
|
|
|
|
|
# Returns merge node
|
|
|
|
def buildNode(stages, node, node_group, last_bind_target, shader_references, asset_references):
|
2016-01-26 14:36:55 +01:00
|
|
|
stage = Object()
|
|
|
|
stage.params = []
|
|
|
|
|
2016-03-15 11:29:53 +01:00
|
|
|
append_stage = True
|
|
|
|
|
2016-05-05 19:50:03 +02:00
|
|
|
if node.bl_idname == 'MergeStagesNodeType':
|
|
|
|
return node
|
|
|
|
|
|
|
|
elif node.bl_idname == 'SetTargetNodeType':
|
2016-03-15 11:29:53 +01:00
|
|
|
last_bind_target = None
|
2016-04-15 20:19:39 +02:00
|
|
|
make_set_target(stage, node_group, node)
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
elif node.bl_idname == 'ClearTargetNodeType':
|
2016-04-15 20:19:39 +02:00
|
|
|
make_clear_target(stage, node_group, node)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
elif node.bl_idname == 'DrawGeometryNodeType':
|
2016-04-15 20:19:39 +02:00
|
|
|
make_draw_geometry(stage, node_group, node)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-05-18 01:34:21 +02:00
|
|
|
elif node.bl_idname == 'DrawDecalsNodeType':
|
|
|
|
make_draw_decals(stage, node_group, node, shader_references, asset_references)
|
|
|
|
|
2016-01-26 14:36:55 +01:00
|
|
|
elif node.bl_idname == 'BindTargetNodeType':
|
2016-03-15 11:29:53 +01:00
|
|
|
if last_bind_target is not None:
|
|
|
|
stage = last_bind_target
|
|
|
|
append_stage = False
|
|
|
|
last_bind_target = stage
|
2016-04-15 20:19:39 +02:00
|
|
|
make_bind_target(stage, node_group, node)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-04-15 00:02:32 +02:00
|
|
|
elif node.bl_idname == 'DrawMaterialQuadNodeType':
|
2016-04-15 20:19:39 +02:00
|
|
|
make_draw_material_quad(stage, node_group, node, shader_references, asset_references)
|
2016-04-15 00:02:32 +02:00
|
|
|
|
|
|
|
elif node.bl_idname == 'DrawQuadNodeType':
|
2016-04-15 20:19:39 +02:00
|
|
|
make_draw_quad(stage, node_group, node, shader_references, asset_references)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-02-08 14:58:55 +01:00
|
|
|
elif node.bl_idname == 'DrawWorldNodeType':
|
2016-04-15 20:19:39 +02:00
|
|
|
make_draw_world(stage, node_group, node)
|
2016-06-22 12:21:15 +02:00
|
|
|
|
|
|
|
elif node.bl_idname == 'DrawCompositorNodeType':
|
|
|
|
# Set target
|
|
|
|
if node.inputs[1].is_linked:
|
|
|
|
make_set_target(stage, node_group, node)
|
|
|
|
stages.append(stage)
|
|
|
|
# Bind targets
|
|
|
|
stage = Object()
|
|
|
|
stage.params = []
|
|
|
|
last_bind_target = stage
|
|
|
|
if node.inputs[2].is_linked:
|
|
|
|
make_bind_target(stage, node_group, node, target_index=2, constant_name='tex')
|
|
|
|
if node.inputs[3].is_linked:
|
|
|
|
make_bind_target(stage, node_group, node, target_index=3, constant_name='gbuffer')
|
|
|
|
stages.append(stage)
|
|
|
|
# Draw quad
|
|
|
|
stage = Object()
|
|
|
|
stage.params = []
|
|
|
|
make_draw_compositor(stage, node_group, node, shader_references, asset_references)
|
|
|
|
|
2016-05-05 19:50:03 +02:00
|
|
|
elif node.bl_idname == 'BranchFunctionNodeType':
|
|
|
|
make_branch_function(stage, node_group, node)
|
|
|
|
stages.append(stage)
|
|
|
|
process_call_function(stage, stages, node, node_group, last_bind_target, shader_references, asset_references)
|
|
|
|
return
|
|
|
|
|
|
|
|
elif node.bl_idname == 'CallFunctionNodeType':
|
|
|
|
make_call_function(stage, node_group, node)
|
2016-04-15 20:19:39 +02:00
|
|
|
|
|
|
|
elif node.bl_idname == 'QuadPassNodeType':
|
|
|
|
# Set target
|
2016-04-16 03:50:51 +02:00
|
|
|
if node.inputs[1].is_linked:
|
|
|
|
make_set_target(stage, node_group, node)
|
2016-05-05 19:50:03 +02:00
|
|
|
stages.append(stage)
|
2016-04-15 20:19:39 +02:00
|
|
|
# Bind targets
|
|
|
|
stage = Object()
|
|
|
|
stage.params = []
|
|
|
|
last_bind_target = stage
|
2016-06-22 12:21:15 +02:00
|
|
|
bind_target_used = False
|
|
|
|
for i in [3, 5, 7]:
|
|
|
|
if node.inputs[i].is_linked:
|
|
|
|
bind_target_used = True
|
|
|
|
make_bind_target(stage, node_group, node, target_index=i, constant_index=(i + 1))
|
2016-04-15 20:19:39 +02:00
|
|
|
if bind_target_used:
|
2016-05-05 19:50:03 +02:00
|
|
|
stages.append(stage)
|
2016-04-15 20:19:39 +02:00
|
|
|
stage = Object()
|
|
|
|
stage.params = []
|
|
|
|
# Draw quad
|
|
|
|
make_draw_quad(stage, node_group, node, shader_references, asset_references, context_index=2)
|
2016-02-08 14:58:55 +01:00
|
|
|
|
2016-03-15 11:29:53 +01:00
|
|
|
if append_stage:
|
2016-05-05 19:50:03 +02:00
|
|
|
stages.append(stage)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
# Build next stage
|
|
|
|
if node.outputs[0].is_linked:
|
2016-04-15 20:19:39 +02:00
|
|
|
stageNode = findNodeByLinkFrom(node_group, node, node.outputs[0])
|
2016-05-05 19:50:03 +02:00
|
|
|
buildNode(stages, stageNode, node_group, last_bind_target, shader_references, asset_references)
|
2016-01-26 14:36:55 +01:00
|
|
|
|
|
|
|
def findNodeByLink(node_group, to_node, inp):
|
|
|
|
for link in node_group.links:
|
|
|
|
if link.to_node == to_node and link.to_socket == inp:
|
|
|
|
return link.from_node
|
2016-05-25 00:13:44 +02:00
|
|
|
|
|
|
|
def findLink(node_group, to_node, inp):
|
|
|
|
for link in node_group.links:
|
|
|
|
if link.to_node == to_node and link.to_socket == inp:
|
|
|
|
return link
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-04-15 20:19:39 +02:00
|
|
|
def findNodeByLinkFrom(node_group, from_node, outp):
|
2016-01-26 14:36:55 +01:00
|
|
|
for link in node_group.links:
|
|
|
|
if link.from_node == from_node and link.from_socket == outp:
|
|
|
|
return link.to_node
|
|
|
|
|
|
|
|
def getRootNode(node_group):
|
2016-04-18 01:16:51 +02:00
|
|
|
# Find first node linked to begin node
|
2016-01-26 14:36:55 +01:00
|
|
|
for n in node_group.nodes:
|
2016-04-18 01:16:51 +02:00
|
|
|
if n.bl_idname == 'BeginNodeType':
|
|
|
|
return findNodeByLinkFrom(node_group, n, n.outputs[0])
|
2016-01-26 14:36:55 +01:00
|
|
|
|
2016-06-07 09:38:49 +02:00
|
|
|
def get_render_targets(root_node, node_group):
|
|
|
|
render_targets = []
|
|
|
|
depth_buffers = []
|
|
|
|
traverse_for_rt(root_node, node_group, render_targets, depth_buffers)
|
|
|
|
return render_targets, depth_buffers
|
|
|
|
|
|
|
|
def traverse_for_rt(node, node_group, render_targets, depth_buffers):
|
|
|
|
# Collect render targets
|
2016-06-21 13:29:27 +02:00
|
|
|
if node.bl_idname == 'SetTargetNodeType' or node.bl_idname == 'QuadPassNodeType':
|
2016-06-07 09:38:49 +02:00
|
|
|
if node.inputs[1].is_linked:
|
|
|
|
tnode = findNodeByLink(node_group, node, node.inputs[1])
|
|
|
|
parse_render_target(tnode, node_group, render_targets, depth_buffers)
|
|
|
|
|
|
|
|
# Next stage
|
|
|
|
if node.outputs[0].is_linked:
|
|
|
|
stagenode = findNodeByLinkFrom(node_group, node, node.outputs[0])
|
|
|
|
traverse_for_rt(stagenode, node_group, render_targets, depth_buffers)
|
|
|
|
|
|
|
|
def parse_render_target(node, node_group, render_targets, depth_buffers):
|
2016-06-18 13:58:12 +02:00
|
|
|
if node.bl_idname == 'NodeReroute':
|
|
|
|
tnode = findNodeByLink(node_group, node, node.inputs[0])
|
|
|
|
parse_render_target(tnode, node_group, render_targets, depth_buffers)
|
|
|
|
|
|
|
|
elif node.bl_idname == 'TargetNodeType':
|
2016-06-07 09:38:49 +02:00
|
|
|
# Target already exists
|
|
|
|
id = node.inputs[0].default_value
|
|
|
|
for t in render_targets:
|
|
|
|
if t.id == id:
|
|
|
|
return
|
|
|
|
|
|
|
|
depth_buffer_id = None
|
|
|
|
if node.inputs[3].is_linked:
|
|
|
|
# Find depth buffer
|
|
|
|
depth_node = findNodeByLink(node_group, node, node.inputs[3])
|
|
|
|
depth_buffer_id = depth_node.inputs[0].default_value
|
|
|
|
# Append depth buffer
|
|
|
|
found = False
|
|
|
|
for db in depth_buffers:
|
|
|
|
if db.id == depth_buffer_id:
|
|
|
|
found = True
|
|
|
|
break
|
|
|
|
if found == False:
|
|
|
|
db = Object()
|
|
|
|
db.id = depth_buffer_id
|
|
|
|
db.stencil_buffer = depth_node.inputs[1].default_value
|
|
|
|
depth_buffers.append(db)
|
|
|
|
# Append target
|
|
|
|
target = make_render_target(node, depth_buffer_id=depth_buffer_id)
|
|
|
|
render_targets.append(target)
|
2016-06-18 13:58:12 +02:00
|
|
|
|
2016-06-07 09:38:49 +02:00
|
|
|
elif node.bl_idname == 'GBufferNodeType':
|
|
|
|
for i in range(0, 5):
|
|
|
|
if node.inputs[i].is_linked:
|
|
|
|
n = findNodeByLink(node_group, node, node.inputs[i])
|
|
|
|
parse_render_target(n, node_group, render_targets, depth_buffers)
|
|
|
|
|
2016-06-03 17:18:38 +02:00
|
|
|
def make_render_target(n, depth_buffer_id=None):
|
2016-04-16 03:50:51 +02:00
|
|
|
target = Object()
|
2016-06-03 17:18:38 +02:00
|
|
|
target.id = n.inputs[0].default_value
|
2016-04-16 03:50:51 +02:00
|
|
|
target.width = n.inputs[1].default_value
|
|
|
|
target.height = n.inputs[2].default_value
|
2016-06-03 17:18:38 +02:00
|
|
|
target.format = n.inputs[4].default_value
|
|
|
|
target.ping_pong = n.inputs[5].default_value
|
|
|
|
if depth_buffer_id != None:
|
|
|
|
target.depth_buffer = depth_buffer_id
|
2016-04-16 03:50:51 +02:00
|
|
|
return target
|
2016-06-07 09:38:49 +02:00
|
|
|
|