111 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			111 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|  | from bpy.props import * | ||
|  | from bpy.types import Node, NodeSocket | ||
|  | 
 | ||
|  | import lnx | ||
|  | from lnx.material.lnx_nodes.lnx_nodes import add_node | ||
|  | from lnx.material.parser_state import ParserState | ||
|  | from lnx.material.shader import Shader | ||
|  | 
 | ||
|  | if lnx.is_reload(__name__): | ||
|  |     lnx.material.lnx_nodes.lnx_nodes = lnx.reload_module(lnx.material.lnx_nodes.lnx_nodes) | ||
|  |     from lnx.material.lnx_nodes.lnx_nodes import add_node | ||
|  |     lnx.material.parser_state = lnx.reload_module(lnx.material.parser_state) | ||
|  |     from lnx.material.parser_state import ParserState | ||
|  |     lnx.material.shader = lnx.reload_module(lnx.material.shader) | ||
|  |     from lnx.material.shader import Shader | ||
|  | else: | ||
|  |     lnx.enable_reload(__name__) | ||
|  | 
 | ||
|  | 
 | ||
|  | class ShaderDataNode(Node): | ||
|  |     """Allows access to shader data such as uniforms and inputs.""" | ||
|  |     bl_idname = 'LnxShaderDataNode' | ||
|  |     bl_label = 'Shader Data' | ||
|  |     bl_icon = 'NONE' | ||
|  | 
 | ||
|  |     input_type: EnumProperty( | ||
|  |         items = [('input', 'Input', 'Shader Input'), | ||
|  |                  ('uniform', 'Uniform', 'Uniform value')], | ||
|  |         name='Input Type', | ||
|  |         default='input', | ||
|  |         description="The kind of data that should be retrieved") | ||
|  | 
 | ||
|  |     input_source: EnumProperty( | ||
|  |         items = [('frag', 'Fragment Shader', 'Take the input from the fragment shader'), | ||
|  |                  ('vert', 'Vertex Shader', 'Take the input from the vertex shader and pass it through to the fragment shader')], | ||
|  |         name='Input Source', | ||
|  |         default='vert', | ||
|  |         description="Where to take the input value from") | ||
|  | 
 | ||
|  |     variable_type: EnumProperty( | ||
|  |         items = [('int', 'int', 'int'), | ||
|  |                  ('float', 'float', 'float'), | ||
|  |                  ('vec2', 'vec2', 'vec2'), | ||
|  |                  ('vec3', 'vec3', 'vec3'), | ||
|  |                  ('vec4', 'vec4', 'vec4'), | ||
|  |                  ('sampler2D', 'sampler2D', 'sampler2D')], | ||
|  |         name='Variable Type', | ||
|  |         default='vec3', | ||
|  |         description="The type of the variable") | ||
|  | 
 | ||
|  |     variable_name: StringProperty(name="Variable Name", description="The name of the variable") | ||
|  | 
 | ||
|  |     def draw_buttons(self, context, layout): | ||
|  |         col = layout.column(align=True) | ||
|  |         col.label(text="Input Type:") | ||
|  |         # Use a row to expand horizontally | ||
|  |         col.row().prop(self, "input_type", expand=True) | ||
|  | 
 | ||
|  |         split = layout.split(factor=0.5, align=True) | ||
|  |         col_left = split.column() | ||
|  |         col_right = split.column() | ||
|  | 
 | ||
|  |         if self.input_type == "input": | ||
|  |             col_left.label(text="Input Source") | ||
|  |             col_right.prop(self, "input_source", text="") | ||
|  | 
 | ||
|  |         col_left.label(text="Variable Type") | ||
|  |         col_right.prop(self, "variable_type", text="") | ||
|  |         col_left.label(text="Variable Name") | ||
|  |         col_right.prop(self, "variable_name", text="") | ||
|  | 
 | ||
|  |     def init(self, context): | ||
|  |         self.outputs.new('NodeSocketColor', 'Color') | ||
|  |         self.outputs.new('NodeSocketVector', 'Vector') | ||
|  |         self.outputs.new('NodeSocketFloat', 'Float') | ||
|  |         self.outputs.new('NodeSocketInt', 'Int') | ||
|  | 
 | ||
|  |     def __parse(self, out_socket: NodeSocket, state: ParserState) -> str: | ||
|  |         if self.input_type == "uniform": | ||
|  |             state.frag.add_uniform(f'{self.variable_type} {self.variable_name}', link=self.variable_name) | ||
|  |             state.vert.add_uniform(f'{self.variable_type} {self.variable_name}', link=self.variable_name) | ||
|  | 
 | ||
|  |             if self.variable_type == "sampler2D": | ||
|  |                 state.frag.add_uniform('vec2 screenSize', link='_screenSize') | ||
|  |                 return f'textureLod({self.variable_name}, gl_FragCoord.xy / screenSize, 0.0).rgb' | ||
|  | 
 | ||
|  |             if self.variable_type == "vec2": | ||
|  |                 return f'vec3({self.variable_name}.xy, 0)' | ||
|  | 
 | ||
|  |             return self.variable_name | ||
|  | 
 | ||
|  |         else: | ||
|  |             if self.input_source == "frag": | ||
|  |                 state.frag.add_in(f'{self.variable_type} {self.variable_name}') | ||
|  |                 return self.variable_name | ||
|  | 
 | ||
|  |             # Reroute input from vertex shader to fragment shader (input must exist!) | ||
|  |             else: | ||
|  |                 state.vert.add_out(f'{self.variable_type} out_{self.variable_name}') | ||
|  |                 state.frag.add_in(f'{self.variable_type} out_{self.variable_name}') | ||
|  | 
 | ||
|  |                 state.vert.write(f'out_{self.variable_name} = {self.variable_name};') | ||
|  |                 return 'out_' + self.variable_name | ||
|  | 
 | ||
|  |     @staticmethod | ||
|  |     def parse(node: 'ShaderDataNode', out_socket: NodeSocket, state: ParserState) -> str: | ||
|  |         return node.__parse(out_socket, state) | ||
|  | 
 | ||
|  | 
 | ||
|  | add_node(ShaderDataNode, category='Leenkx') |