1 # SPDX-FileCopyrightText: 2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """"Nodes based User interface for shaders exported to POV textures."""
8 from bpy
.utils
import register_class
, unregister_class
9 from bpy
.types
import Menu
, Operator
10 from bpy
.props
import (
14 # def find_node_input(node, name):
15 # for input in node.inputs:
16 # if input.name == name:
19 # def panel_node_draw(layout, id_data, output_type, input_name):
20 # if not id_data.use_nodes:
21 # #layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
22 # #layout.operator("pov.use_shading_nodes", icon='NODETREE')
23 # layout.operator("WM_OT_context_toggle", icon='NODETREE').data_path = \
24 # "material.pov.material_use_nodes"
27 # ntree = id_data.node_tree
29 # node = find_node(id_data, output_type)
31 # layout.label(text="No output node")
33 # input = find_node_input(node, input_name)
34 # layout.template_node_view(ntree, node, input)
39 class NODE_MT_POV_map_create(Menu
):
42 bl_idname
= "POVRAY_MT_node_map_create"
43 bl_label
= "Create map"
45 def draw(self
, context
):
47 layout
.operator("node.map_create")
50 def menu_func_nodes(self
, context
):
52 if hasattr(ob
, "active_material"):
53 mat
= context
.object.active_material
54 if mat
and context
.space_data
.tree_type
== "ObjectNodeTree":
55 self
.layout
.prop(mat
.pov
, "material_use_nodes")
56 self
.layout
.menu(NODE_MT_POV_map_create
.bl_idname
)
57 self
.layout
.operator("wm.updatepreviewkey")
58 if hasattr(mat
, "active_texture") and context
.scene
.render
.engine
== "POVRAY_RENDER":
59 tex
= mat
.active_texture
60 if tex
and context
.space_data
.tree_type
== "TextureNodeTree":
61 self
.layout
.prop(tex
.pov
, "texture_use_nodes")
64 # ------------------------------------------------------------------------------ #
65 # --------------------------------- Operators ---------------------------------- #
66 # ------------------------------------------------------------------------------ #
69 class NODE_OT_iso_add(Operator
):
70 bl_idname
= "pov.nodeisoadd"
71 bl_label
= "Create iso props"
73 def execute(self
, context
):
74 ob
= bpy
.context
.object
75 if not bpy
.context
.scene
.use_nodes
:
76 bpy
.context
.scene
.use_nodes
= True
77 tree
= bpy
.context
.scene
.node_tree
78 for node
in tree
.nodes
:
79 if node
.bl_idname
== "IsoPropsNode" and node
.label
== ob
.name
:
80 tree
.nodes
.remove(node
)
81 isonode
= tree
.nodes
.new("IsoPropsNode")
82 isonode
.location
= (0, 0)
83 isonode
.label
= ob
.name
87 class NODE_OT_map_create(Operator
):
88 bl_idname
= "node.map_create"
89 bl_label
= "Create map"
91 def execute(self
, context
):
93 space
= context
.space_data
94 tree
= space
.edit_tree
95 for node
in tree
.nodes
:
99 tmap
= tree
.nodes
.new("ShaderTextureMapNode")
100 tmap
.location
= (x
- 200, y
)
103 def invoke(self
, context
, event
):
104 wm
= context
.window_manager
105 return wm
.invoke_props_dialog(self
)
107 def draw(self
, context
):
109 mat
= context
.object.active_material
110 layout
.prop(mat
.pov
, "inputs_number")
113 class NODE_OT_povray_node_texture_map_add(Operator
):
114 bl_idname
= "pov.nodetexmapadd"
115 bl_label
= "Texture map"
117 def execute(self
, context
):
118 tree
= bpy
.context
.object.active_material
.node_tree
119 tmap
= tree
.nodes
.active
120 mtl
= context
.object.active_material
121 mtl
.node_tree
.nodes
.active
= tmap
122 el
= tmap
.color_ramp
.elements
.new(0.5)
123 for el
in tmap
.color_ramp
.elements
:
124 el
.color
= (0, 0, 0, 1)
125 for inp
in tmap
.inputs
:
126 tmap
.inputs
.remove(inp
)
127 for outp
in tmap
.outputs
:
128 tmap
.outputs
.remove(outp
)
129 pattern
= tmap
.inputs
.new("NodeSocketVector", "Pattern")
130 pattern
.hide_value
= True
132 tmap
.inputs
.new("NodeSocketColor", "Shader")
133 tmap
.outputs
.new("NodeSocketShader", "BSDF")
134 tmap
.label
= "Texture Map"
138 class NODE_OT_povray_node_output_add(Operator
):
139 bl_idname
= "pov.nodeoutputadd"
142 def execute(self
, context
):
143 tree
= bpy
.context
.object.active_material
.node_tree
144 tmap
= tree
.nodes
.new("ShaderNodeOutputMaterial")
145 mtl
= context
.object.active_material
146 mtl
.node_tree
.nodes
.active
= tmap
147 for inp
in tmap
.inputs
:
148 tmap
.inputs
.remove(inp
)
149 tmap
.inputs
.new("NodeSocketShader", "Surface")
150 tmap
.label
= "Output"
154 class NODE_OT_povray_node_layered_add(Operator
):
155 bl_idname
= "pov.nodelayeredadd"
156 bl_label
= "Layered material"
158 def execute(self
, context
):
159 tree
= bpy
.context
.object.active_material
.node_tree
160 tmap
= tree
.nodes
.new("ShaderNodeAddShader")
161 mtl
= context
.object.active_material
162 mtl
.node_tree
.nodes
.active
= tmap
163 tmap
.label
= "Layered material"
167 class NODE_OT_povray_input_add(Operator
):
168 bl_idname
= "pov.nodeinputadd"
169 bl_label
= "Add entry"
171 def execute(self
, context
):
172 mtl
= context
.object.active_material
173 node
= mtl
.node_tree
.nodes
.active
174 if node
.type == "VALTORGB":
176 for inp
in node
.inputs
:
177 if inp
.type == "SHADER":
179 node
.inputs
.new("NodeSocketShader", "%s" % number
)
180 els
= node
.color_ramp
.elements
181 pos1
= els
[len(els
) - 1].position
182 pos2
= els
[len(els
) - 2].position
183 pos
= (pos1
- pos2
) / 2 + pos2
186 if node
.bl_idname
== "PovraySlopeNode":
187 number
= len(node
.inputs
)
188 node
.inputs
.new("PovraySocketSlope", "%s" % number
)
193 class NODE_OT_povray_input_remove(Operator
):
194 bl_idname
= "pov.nodeinputremove"
195 bl_label
= "Remove input"
197 def execute(self
, context
):
198 mtl
= context
.object.active_material
199 node
= mtl
.node_tree
.nodes
.active
200 if node
.type in {"VALTORGB", "ADD_SHADER"}:
201 number
= len(node
.inputs
) - 1
203 inp
= node
.inputs
[number
]
204 node
.inputs
.remove(inp
)
205 if node
.type == "VALTORGB":
206 els
= node
.color_ramp
.elements
207 number
= len(els
) - 2
213 class NODE_OT_povray_image_open(Operator
):
214 bl_idname
= "pov.imageopen"
217 filepath
: StringProperty(
218 name
="File Path", description
="Open image", maxlen
=1024, subtype
="FILE_PATH"
221 def invoke(self
, context
, event
):
222 context
.window_manager
.fileselect_add(self
)
223 return {"RUNNING_MODAL"}
225 def execute(self
, context
):
226 im
= bpy
.data
.images
.load(self
.filepath
)
227 mtl
= context
.object.active_material
228 node
= mtl
.node_tree
.nodes
.active
233 # class TEXTURE_OT_povray_open_image(Operator):
234 # bl_idname = "pov.openimage"
235 # bl_label = "Open Image"
237 # filepath = StringProperty(
239 # description="Open image",
241 # subtype='FILE_PATH',
244 # def invoke(self, context, event):
245 # context.window_manager.fileselect_add(self)
246 # return {'RUNNING_MODAL'}
248 # def execute(self, context):
249 # im=bpy.data.images.load(self.filepath)
250 # tex = context.texture
251 # tex.pov.image = im.name
252 # view_layer = context.view_layer
253 # view_layer.update()
254 # return {'FINISHED'}
258 NODE_MT_POV_map_create
,
261 NODE_OT_povray_node_texture_map_add
,
262 NODE_OT_povray_node_output_add
,
263 NODE_OT_povray_node_layered_add
,
264 NODE_OT_povray_input_add
,
265 NODE_OT_povray_input_remove
,
266 NODE_OT_povray_image_open
,
271 bpy
.types
.NODE_HT_header
.append(menu_func_nodes
)
277 for cls
in reversed(classes
):
278 unregister_class(cls
)
279 bpy
.types
.NODE_HT_header
.remove(menu_func_nodes
)