From 7668ff7465a3d14e8195af19be198722f72068bd Mon Sep 17 00:00:00 2001 From: Facundo Villa Date: Sun, 18 Feb 2024 01:11:52 -0300 Subject: [PATCH] Updated shader generation. --- jspd/src/lexer.rs | 470 ++++++++++++----- jspd/src/lib.rs | 16 +- jspd/src/parser.rs | 82 ++- .../src/asset/material_asset_handler.rs | 226 ++++++-- resource_management/src/asset/mod.rs | 20 +- resource_management/src/lib.rs | 2 + .../src/resource/material_resource_handler.rs | 6 +- resource_management/src/shader_generation.rs | 243 +++++++++ src/rendering/visibility_shader_generator.rs | 484 ++++++++---------- 9 files changed, 1090 insertions(+), 459 deletions(-) create mode 100644 resource_management/src/shader_generation.rs diff --git a/jspd/src/lexer.rs b/jspd/src/lexer.rs index 4744167f..d261b3c2 100644 --- a/jspd/src/lexer.rs +++ b/jspd/src/lexer.rs @@ -1,38 +1,220 @@ -use std::{rc::Rc, collections::HashMap}; +use std::{borrow::BorrowMut, cell::RefCell, collections::HashMap, mem::MaybeUninit, ops::Deref, rc::{Rc, Weak}}; +use std::hash::Hash; use super::parser; -pub(super) fn lex(node: &parser::Node, parser_program: &parser::ProgramState) -> Result { +pub type ParentNodeReference = Weak>; + +#[derive(Clone, Debug)] +pub struct NodeReference(Rc>); + +impl PartialEq for NodeReference { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.0, &other.0) + } +} + +impl Eq for NodeReference {} + +impl Hash for NodeReference { + fn hash(&self, state: &mut H) where H: std::hash::Hasher { + Rc::as_ptr(&self.0).hash(state); + } +} + +impl Deref for NodeReference { + type Target = RefCell; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub(super) fn lex(node: &parser::Node, parser_program: &parser::ProgramState) -> Result { let mut program = ProgramState { types: HashMap::new(), }; - return lex_parsed_node(node, parser_program, &mut program).map(|e| e.as_ref().clone()); + return lex_parsed_node(None, node, parser_program, &mut program); } #[derive(Clone, Debug)] pub struct Node { - pub node: Nodes, + parent: Option, + node: Nodes, } -#[derive(Clone, Debug)] +impl Node { + fn internal_new(node: Node) -> NodeReference { + NodeReference(Rc::new(RefCell::new(node))) + } + + pub fn scope(name: String, children: Vec) -> NodeReference { + Self::internal_new(Node { + parent: None, + node: Nodes::Scope{ name, children }, + }) + } + + pub fn r#struct(name: String, fields: Vec) -> NodeReference { + Self::internal_new(Node { + parent: None, + node: Nodes::Struct { + name, + template: None, + fields, + types: Vec::new(), + }, + }) + } + + pub fn member(name: String, r#type: NodeReference) -> NodeReference { + Self::internal_new(Node { + parent: None, + node: Nodes::Member { + name, + r#type, + }, + }) + } + + pub fn function(parent: Option, name: String, params: Vec, return_type: NodeReference, statements: Vec, raw: Option) -> NodeReference { + Self::internal_new(Node { + parent, + node: Nodes::Function { + name, + params, + return_type, + statements, + raw, + }, + }) + } + + pub fn expression(expression: Expressions) -> NodeReference { + Self::internal_new(Node { + parent: None, + node: Nodes::Expression(expression), + }) + } + + pub fn glsl(code: String) -> NodeReference { + Self::internal_new(Node { + parent: None, + node: Nodes::GLSL { + code, + }, + }) + } + + pub fn new(node: Nodes) -> Node { + Node { + parent: None, + node, + } + } + + pub fn with_parent(self, parent: ParentNodeReference) -> Node { + Node { + parent: Some(parent), + node: self.node, + } + } + + pub fn add_child(&mut self, child: NodeReference) { + match &mut self.node { + Nodes::Scope{ children, .. } => { + children.push(child); + } + Nodes::Function { statements, .. } => { + statements.push(child); + } + _ => {} + } + } + + pub fn add_children(&mut self, children: Vec) { + match &mut self.node { + Nodes::Scope{ children: c, .. } => { + c.extend(children); + } + Nodes::Struct { fields, .. } => { + fields.extend(children); + } + _ => {} + } + } + + pub fn parent(&self) -> Option { + self.parent.clone() + } + + pub fn node(&self) -> &Nodes { + &self.node + } + + pub fn get_child(&self, child_name: &str) -> Option { + match &self.node { + Nodes::Scope { children, .. } => { + for child in children { + if let Ok(borrowed_child) = child.try_borrow() { + match borrowed_child.node() { + Nodes::Function { name, .. } => { + if child_name == name { + return Some(child.clone()); + } + } + _ => {} + } + } + } + } + _ => {} + } + + None + } + + pub fn get_name(&self) -> Option { + match &self.node { + Nodes::Scope { name, .. } => { + Some(name.clone()) + } + Nodes::Function { name, .. } => { + Some(name.clone()) + } + Nodes::Member { name, .. } => { + Some(name.clone()) + } + Nodes::Struct { name, .. } => { + Some(name.clone()) + } + _ => { + None + } + } + } +} + +#[derive(Clone, Debug,)] pub enum Nodes { - Scope{ name: String, children: Vec> }, + Null, + Scope{ name: String, children: Vec }, Struct { name: String, - template: Option>, - fields: Vec>, - types: Vec>, + template: Option, + fields: Vec, + types: Vec, }, Member { name: String, - r#type: Rc, + r#type: NodeReference, }, Function { name: String, - params: Vec>, - return_type: Rc, - statements: Vec>, + params: Vec, + return_type: NodeReference, + statements: Vec, raw: Option, }, Expression(Expressions), @@ -57,24 +239,28 @@ pub enum Operators { Equality, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug,)] pub enum Expressions { Member{ name: String }, Literal { value: String }, - FunctionCall { name: String, parameters: Vec> }, + FunctionCall { + function: NodeReference, + name: String, + parameters: Vec + }, Operator { operator: Operators, - left: Rc, - right: Rc, + left: NodeReference, + right: NodeReference, }, VariableDeclaration { name: String, - // r#type: Rc, + // r#type: NodeReference, r#type: String, }, Accessor { - left: Rc, - right: Rc, + left: NodeReference, + right: NodeReference, } } @@ -91,7 +277,7 @@ type Lexer<'a> = fn(std::slice::Iter<'a, String>, &'a parser::ProgramState) -> L #[derive(Clone)] pub(crate) struct ProgramState { - pub(crate) types: HashMap>, + pub(crate) types: HashMap, } /// Execute a list of lexers on a stream of tokens. @@ -116,45 +302,36 @@ fn try_execute_lexers<'a>(lexers: &[Lexer<'a>], iterator: std::slice::Iter<'a, S None } -fn lex_parsed_node(parser_node: &parser::Node, parser_program: &parser::ProgramState, program: &mut ProgramState) -> Result, LexError> { - match &parser_node.node { +fn lex_parsed_node(parent_node: Option, parser_node: &parser::Node, parser_program: &parser::ProgramState, program: &mut ProgramState) -> Result { + let node = match &parser_node.node { parser::Nodes::Scope{ name, children } => { - let mut ch = Vec::new(); + let this = Node::scope(name.clone(), Vec::new()); - for child in children { - ch.push(lex_parsed_node(child, parser_program, program)?); - } + let ch = children.iter().map(|child| { + lex_parsed_node(Some(Rc::downgrade(&this.0)), child, parser_program, program) + }).collect::, LexError>>()?; + + RefCell::borrow_mut(&this).add_children(ch); - Ok(Rc::new(Node { - node: Nodes::Scope{ name: name.clone(), children: ch, } - })) + this } parser::Nodes::Struct { name, fields } => { if let Some(n) = program.types.get(name) { // If the type already exists, return it. return Ok(n.clone()); } - let mut children = Vec::new(); + let this = Node::r#struct(name.clone(), Vec::new()); - for field in fields { - children.push(lex_parsed_node(&field, parser_program, program)?); - } + let ch = fields.iter().map(|field| { + lex_parsed_node(Some(Rc::downgrade(&this.0)), &field, parser_program, program) + }).collect::, LexError>>()?; - let struct_node = Node { - node: Nodes::Struct { - name: name.clone(), - template: None, - fields: children, - types: Vec::new(), - }, - }; + RefCell::borrow_mut(&this).add_children(ch); - let node = Rc::new(struct_node); + program.types.insert(name.clone(), this.clone()); + program.types.insert(format!("{}*", name.clone()), this.clone()); - program.types.insert(name.clone(), node.clone()); - program.types.insert(format!("{}*", name.clone()), node.clone()); - - Ok(node) + this } parser::Nodes::Member { name, r#type } => { let t = if r#type.contains('<') { @@ -162,13 +339,14 @@ fn lex_parsed_node(parser_node: &parser::Node, parser_program: &parser::ProgramS let outer_type_name = s.next().ok_or(LexError::Undefined)?; - let outer_type = lex_parsed_node(parser_program.types.get(outer_type_name).ok_or(LexError::NoSuchType{ type_name: outer_type_name.to_string() })?, parser_program, program)?; + let outer_type = lex_parsed_node(None, parser_program.types.get(outer_type_name).ok_or(LexError::NoSuchType{ type_name: outer_type_name.to_string() })?, parser_program, program)?; let inner_type_name = s.next().ok_or(LexError::Undefined)?; let inner_type = if let Some(stripped) = inner_type_name.strip_suffix('*') { - let x = Rc::new( + let x = Node::internal_new( Node { + parent: None, node: Nodes::Struct { name: format!("{}*", stripped), template: Some(outer_type.clone()), @@ -182,7 +360,7 @@ fn lex_parsed_node(parser_node: &parser::Node, parser_program: &parser::ProgramS x } else { - lex_parsed_node(parser_program.types.get(inner_type_name).ok_or(LexError::NoSuchType{ type_name: inner_type_name.to_string() })?, parser_program, program)? + lex_parsed_node(parent_node.clone(), parser_program.types.get(inner_type_name).ok_or(LexError::NoSuchType{ type_name: inner_type_name.to_string() })?, parser_program, program)? }; if let Some(n) = program.types.get(r#type) { // If the type already exists, return it. @@ -196,6 +374,7 @@ fn lex_parsed_node(parser_node: &parser::Node, parser_program: &parser::ProgramS // } let struct_node = Node { + parent: None, node: Nodes::Struct { name: r#type.clone(), template: Some(outer_type.clone()), @@ -204,73 +383,66 @@ fn lex_parsed_node(parser_node: &parser::Node, parser_program: &parser::ProgramS }, }; - let node = Rc::new(struct_node); + let node = Node::internal_new(struct_node); program.types.insert(r#type.clone(), node.clone()); node } else { let t = parser_program.types.get(r#type.as_str()).ok_or(LexError::NoSuchType{ type_name: r#type.clone() })?; - lex_parsed_node(t, parser_program, program)? + lex_parsed_node(None, t, parser_program, program)? }; - Ok(Rc::new(Node { - node: Nodes::Member { - name: name.clone(), - r#type: t, - }, - })) + Node::member(name.clone(), t,) } parser::Nodes::Function { name, return_type, statements, raw, .. } => { let t = parser_program.types.get(return_type.as_str()).ok_or(LexError::NoSuchType{ type_name: return_type.clone() })?; - let t = lex_parsed_node(t, parser_program, program)?; - - return Ok(Rc::new(Node { - node: Nodes::Function { - name: name.clone(), - params: Vec::new(), - return_type: t, - statements: statements.iter().map(|e| lex_parsed_node(e, parser_program, program).unwrap()).collect(), - raw: raw.clone(), - }, - })); + let t = lex_parsed_node(None, t, parser_program, program)?; + + let this = Node::function(parent_node.clone(), name.clone(), Vec::new(), t, Vec::new(), raw.clone(),); + + let st = statements.iter().map(|statement| { + lex_parsed_node(Some(Rc::downgrade(&this.0)), statement, parser_program, program) + }).collect::, LexError>>()?; + + match RefCell::borrow_mut(&this).node { + Nodes::Function { ref mut statements, .. } => { + statements.extend(st); + } + _ => {} + } + + this } parser::Nodes::Expression(expression) => { match expression { parser::Expressions::Accessor{ left, right } => { - Ok(Rc::new(Node { - node: Nodes::Expression(Expressions::Accessor { - left: lex_parsed_node(left, parser_program, program)?, - right: lex_parsed_node(right, parser_program, program)?, - }), - })) + Node::expression(Expressions::Accessor { + left: lex_parsed_node(None, left, parser_program, program)?, + right: lex_parsed_node(None, right, parser_program, program)?, + }) } parser::Expressions::Member{ name } => { - Ok(Rc::new(Node { - node: Nodes::Expression(Expressions::Member { + Node::expression(Expressions::Member { name: name.clone(), - - }), - })) + }) } parser::Expressions::Literal{ value } => { - Ok(Rc::new(Node { - node: Nodes::Expression(Expressions::Literal { + Node::expression(Expressions::Literal { value: value.clone(), - }), - })) + }) } parser::Expressions::FunctionCall{ name, parameters } => { - Ok(Rc::new(Node { - node: Nodes::Expression(Expressions::FunctionCall { - name: name.clone(), - parameters: parameters.iter().map(|e| lex_parsed_node(e, parser_program, program).unwrap()).collect(), - }), - })) + let t = parser_program.types.get(name.as_str()).ok_or(LexError::NoSuchType{ type_name: name.clone() })?; + let function = lex_parsed_node(None, t, parser_program, program)?; + Node::expression(Expressions::FunctionCall { + function, + name: name.clone(), + parameters: parameters.iter().map(|e| lex_parsed_node(None, e, parser_program, program).unwrap()).collect(), + }) } parser::Expressions::Operator{ name, left, right } => { - Ok(Rc::new(Node { - node: Nodes::Expression(Expressions::Operator { + Node::expression(Expressions::Operator { operator: match name.as_str() { "+" => Operators::Plus, "-" => Operators::Minus, @@ -281,23 +453,22 @@ fn lex_parsed_node(parser_node: &parser::Node, parser_program: &parser::ProgramS "==" => Operators::Equality, _ => { panic!("Invalid operator") } }, - left: lex_parsed_node(left, parser_program, program)?, - right: lex_parsed_node(right, parser_program, program)?, - }), - })) + left: lex_parsed_node(None, left, parser_program, program)?, + right: lex_parsed_node(None, right, parser_program, program)?, + }) } parser::Expressions::VariableDeclaration{ name, r#type } => { - Ok(Rc::new(Node { - node: Nodes::Expression(Expressions::VariableDeclaration { + Node::expression(Expressions::VariableDeclaration { name: name.clone(), // r#type: lex_parsed_node(&r#type, parser_program, program)?, r#type: r#type.clone(), - }), - })) + }) } } } - } + }; + + Ok(node) } #[cfg(test)] @@ -308,7 +479,7 @@ mod tests { fn assert_type(node: &Node, type_name: &str) { match &node.node { - Nodes::Struct { name, fields, template, types } => { + Nodes::Struct { name, .. } => { assert_eq!(name, type_name); } _ => { panic!("Expected type"); } @@ -325,26 +496,31 @@ main: fn () -> void { let tokens = tokenizer::tokenize(source).expect("Failed to tokenize"); let (node, program) = parser::parse(tokens).expect("Failed to parse"); - let node = &lex(&node, &program).expect("Failed to lex"); + let node = lex(&node, &program).expect("Failed to lex"); + let node = node.borrow(); + + assert!(node.parent().is_none()); match &node.node { - Nodes::Scope{ name, children } => { - let main = &children[0]; + Nodes::Scope{ children, .. } => { + let main = children[0].borrow(); - match &main.node { + // assert_eq!(main.node(), node.node()); + + match main.node() { Nodes::Function { name, params: _, return_type, statements, raw: _ } => { assert_eq!(name, "main"); - assert_type(&return_type, "void"); + assert_type(&return_type.borrow(), "void"); - let position = &statements[0]; + let position = statements[0].borrow(); - match &position.node { + match position.node() { Nodes::Expression(Expressions::Operator { operator, left, right }) => { - let position = &left; + let position = left.borrow(); assert_eq!(operator, &Operators::Assignment); - match &position.node { + match position.node() { Nodes::Expression(Expressions::VariableDeclaration{ name, r#type }) => { assert_eq!(name, "position"); @@ -354,10 +530,10 @@ main: fn () -> void { _ => { panic!("Expected expression"); } } - let constructor = &right; + let constructor = right.borrow(); - match &constructor.node { - Nodes::Expression(Expressions::FunctionCall{ name, parameters }) => { + match constructor.node() { + Nodes::Expression(Expressions::FunctionCall{ name, parameters, .. }) => { assert_eq!(name, "vec4"); assert_eq!(parameters.len(), 4); } @@ -382,18 +558,19 @@ color: In; let tokens = tokenizer::tokenize(source).expect("Failed to tokenize"); let (node, program) = parser::parse(tokens).expect("Failed to parse"); - let node = &lex(&node, &program).expect("Failed to lex"); + let node = lex(&node, &program).expect("Failed to lex"); + let node = node.borrow(); - match &node.node { + match node.node() { Nodes::Scope{ name, children } => { assert_eq!(name, "root"); - let color = &children[0]; + let color = children[0].borrow(); - match &color.node { + match color.node() { Nodes::Member { name, r#type } => { assert_eq!(name, "color"); - assert_type(&r#type, "In"); + assert_type(&r#type.borrow(), "In"); } _ => { panic!("Expected feature"); } } @@ -401,4 +578,59 @@ color: In; _ => { panic!("Expected scope"); } } } + + #[test] + fn parse_script() { + let script = r#" + used: fn () -> void { + return; + } + + not_used: fn () -> void { + return; + } + + main: fn () -> void { + used(); + } + "#; + + let tokens = tokenizer::tokenize(script).expect("Failed to tokenize"); + let (node, program) = parser::parse(tokens).expect("Failed to parse"); + let node = lex(&node, &program).expect("Failed to lex"); + } + + #[test] + fn lex_struct() { + let script = r#" + Vertex: struct { + position: vec3f, + normal: vec3f, + } + "#; + + let tokens = tokenizer::tokenize(script).expect("Failed to tokenize"); + let (node, program) = parser::parse(tokens).expect("Failed to parse"); + let node = lex(&node, &program).expect("Failed to lex"); + dbg!(&node); + + let node = node.borrow(); + + match node.node() { + Nodes::Scope{ name, children } => { + assert_eq!(name, "root"); + + let vertex = children[0].borrow(); + + match vertex.node() { + Nodes::Struct { name, fields, .. } => { + assert_eq!(name, "Vertex"); + assert_eq!(fields.len(), 2); + } + _ => { panic!("Expected struct"); } + } + } + _ => { panic!("Expected scope"); } + } + } } \ No newline at end of file diff --git a/jspd/src/lib.rs b/jspd/src/lib.rs index 49287537..fe867e9f 100644 --- a/jspd/src/lib.rs +++ b/jspd/src/lib.rs @@ -1,5 +1,7 @@ //! This module contains all code related to the parsing of the BESL language and the generation of the JSPD. +#![feature(new_uninit)] + use std::{collections::HashMap, rc::Rc}; mod tokenizer; @@ -11,7 +13,13 @@ pub use lexer::Operators; pub use lexer::Node; pub use lexer::Nodes; -pub fn compile_to_jspd(source: &str) -> Result { +pub use crate::lexer::NodeReference; + +pub fn compile_to_jspd(source: &str) -> Result { + if source.split_whitespace().next() == None { + return Ok(lexer::Node::scope("".to_string(), Vec::new())); + } + let tokens = tokenizer::tokenize(source).map_err(|_e| CompilationError::Undefined)?; let (parser_root_node, parser_program) = parser::parse(tokens).map_err(|_e| CompilationError::Undefined)?; let jspd = lexer::lex(&parser_root_node, &parser_program).map_err(|_e| CompilationError::Undefined)?; @@ -25,7 +33,7 @@ pub enum CompilationError { } // Expects a JSON object, describing the program in a parsed form. -pub fn json_to_jspd(source: &json::JsonValue) -> Result { +pub fn json_to_jspd(source: &json::JsonValue) -> Result { fn process_parser_nodes(name: &str, node: &json::JsonValue, parser_program: &mut parser::ProgramState) -> Result, ()> { let parser_node = match node { json::JsonValue::Object(obj) => { @@ -191,7 +199,9 @@ mod tests { let jspd = json_to_jspd(&json).unwrap(); - if let lexer::Nodes::Scope { name, children } = jspd.node { + let jspd = jspd.borrow(); + + if let lexer::Nodes::Scope { name, children } = jspd.node() { assert_eq!(name, "root"); assert!(children.len() > 1); } else { diff --git a/jspd/src/parser.rs b/jspd/src/parser.rs index 8dd68559..5bc30bb0 100644 --- a/jspd/src/parser.rs +++ b/jspd/src/parser.rs @@ -260,8 +260,12 @@ fn try_execute_expression_parsers<'a>(parsers: &[ExpressionParser<'a>], iterator None } +fn is_identifier(c: char) -> bool { // TODO: validate number at end of identifier + c.is_alphanumeric() || c == '_' +} + fn parse_member<'a>(mut iterator: std::slice::Iter<'a, String>, program: &ProgramState) -> FeatureParserResult<'a> { - let name = iterator.next().ok_or(ParsingFailReasons::NotMine)?; + let name = iterator.next().ok_or(ParsingFailReasons::NotMine).and_then(|v| if v.chars().all(is_identifier) { Ok(v) } else { Err(ParsingFailReasons::NotMine) })?; iterator.next().and_then(|v| if v == ":" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; let mut r#type = iterator.next().ok_or(ParsingFailReasons::BadSyntax{ message: format!("Expected to find type while parsing member {}.", name) })?.clone(); @@ -295,7 +299,7 @@ fn parse_macro<'a>(iterator: std::slice::Iter<'a, String>, program: &ProgramStat } fn parse_struct<'a>(mut iterator: std::slice::Iter<'a, String>, program: &ProgramState) -> FeatureParserResult<'a> { - let name = iterator.next().ok_or(ParsingFailReasons::NotMine)?; + let name = iterator.next().ok_or(ParsingFailReasons::NotMine).and_then(|v| if v.chars().all(char::is_alphanumeric) { Ok(v) } else { Err(ParsingFailReasons::NotMine) })?; iterator.next().and_then(|v| if v == ":" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; iterator.next().and_then(|v| if v == "struct" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; iterator.next().and_then(|v| if v == "{" { Some(v) } else { None }).ok_or(ParsingFailReasons::BadSyntax{ message: format!("Expected to find {{ after struct {} declaration", name) })?; @@ -330,9 +334,9 @@ fn parse_struct<'a>(mut iterator: std::slice::Iter<'a, String>, program: &Progra } fn parse_var_decl<'a>(mut iterator: std::slice::Iter<'a, String>, program: &ProgramState, mut expressions: Vec,) -> ExpressionParserResult<'a> { - let variable_name = iterator.next().ok_or(ParsingFailReasons::NotMine)?; + let variable_name = iterator.next().ok_or(ParsingFailReasons::NotMine).and_then(|v| if v.chars().all(char::is_alphanumeric) { Ok(v) } else { Err(ParsingFailReasons::NotMine) })?; iterator.next().and_then(|v| if v == ":" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; - let variable_type = iterator.next().ok_or(ParsingFailReasons::BadSyntax{ message: format!("Expected to find a type for variable {}", variable_name) })?; + let variable_type = iterator.next().ok_or(ParsingFailReasons::BadSyntax{ message: format!("Expected to find a type for variable {}", variable_name) }).and_then(|v| if v.chars().all(char::is_alphanumeric) { Ok(v) } else { Err(ParsingFailReasons::NotMine) })?; expressions.push(Atoms::VariableDeclaration{ name: variable_name.clone(), r#type: variable_type.clone() }); @@ -347,6 +351,7 @@ fn parse_var_decl<'a>(mut iterator: std::slice::Iter<'a, String>, program: &Prog fn parse_variable<'a>(mut iterator: std::slice::Iter<'a, String>, program: &ProgramState, mut expressions: Vec,) -> ExpressionParserResult<'a> { let name = iterator.next().ok_or(ParsingFailReasons::NotMine)?; + name.chars().all(char::is_alphanumeric).then(|| ()).ok_or(ParsingFailReasons::NotMine)?; expressions.push(Atoms::Member{ name: name.clone() }); @@ -401,17 +406,17 @@ fn parse_operator<'a>(mut iterator: std::slice::Iter<'a, String>, program: &Prog } fn parse_function_call<'a>(mut iterator: std::slice::Iter<'a, String>, program: &ProgramState, mut expressions: Vec,) -> ExpressionParserResult<'a> { - let function_name = iterator.next().ok_or(ParsingFailReasons::NotMine)?; + let function_name = iterator.next().ok_or(ParsingFailReasons::NotMine).and_then(|v| if v.chars().all(is_identifier) { Ok(v) } else { Err(ParsingFailReasons::NotMine) })?; iterator.next().and_then(|v| if v == "(" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; let mut parameters = vec![]; loop { - let (expressions, new_iterator) = parse_rvalue(iterator.clone(), program, Vec::new())?; - - parameters.push(expressions); - - iterator = new_iterator; + if let Some(a) = try_execute_expression_parsers(&[parse_rvalue], iterator.clone(), program, Vec::new()) { + let (expressions, new_iterator) = a?; + parameters.push(expressions); + iterator = new_iterator; + } // Check if iter is comma if iterator.clone().peekable().peek().ok_or(ParsingFailReasons::StreamEndedPrematurely)?.as_str() == "," { iterator.next(); } @@ -433,8 +438,8 @@ fn parse_function_call<'a>(mut iterator: std::slice::Iter<'a, String>, program: fn parse_statement<'a>(iterator: std::slice::Iter<'a, String>, program: &ProgramState,) -> FeatureParserResult<'a> { let parsers = vec![ parse_var_decl, - parse_variable, parse_function_call, + parse_variable, ]; let (expressions, mut iterator) = execute_expression_parsers(&parsers, iterator, program, Vec::new())?; @@ -480,7 +485,8 @@ fn parse_statement<'a>(iterator: std::slice::Iter<'a, String>, program: &Program } fn parse_function<'a>(mut iterator: std::slice::Iter<'a, String>, program: &ProgramState) -> FeatureParserResult<'a> { - let name = iterator.next().ok_or(ParsingFailReasons::NotMine)?; + let name = iterator.next().ok_or(ParsingFailReasons::NotMine).and_then(|v| if v.chars().all(is_identifier) { Ok(v) } else { Err(ParsingFailReasons::NotMine) })?; + iterator.next().and_then(|v| if v == ":" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; iterator.next().and_then(|v| if v == "fn" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; iterator.next().and_then(|v| if v == "(" { Some(v) } else { None }).ok_or(ParsingFailReasons::NotMine)?; @@ -494,11 +500,11 @@ fn parse_function<'a>(mut iterator: std::slice::Iter<'a, String>, program: &Prog let mut statements = vec![]; loop { - let ((expression, _), new_iterator) = parse_statement(iterator.clone(), program)?; - - iterator = new_iterator; - - statements.push(expression); + if let Some(Ok(((expression, _), new_iterator))) = try_execute_parsers(&[parse_statement], iterator.clone(), program) { + iterator = new_iterator; + + statements.push(expression); + } // check if iter is close brace if iterator.clone().peekable().peek().unwrap().as_str() == "}" { @@ -507,7 +513,13 @@ fn parse_function<'a>(mut iterator: std::slice::Iter<'a, String>, program: &Prog } } - Ok(((Rc::new(make_function(name, vec![], return_type, statements, None)), program.clone()), iterator)) + let mut program = program.clone(); + + let node = Rc::new(make_function(name, vec![], return_type, statements, None)); + + program.types.insert(name.clone(), node.clone()); + + Ok(((node, program.clone()), iterator)) } use std::ops::Index; @@ -517,7 +529,7 @@ impl Index<&str> for Node { fn index(&self, index: &str) -> &Self::Output { match &self.node { - Nodes::Scope { name, children } => { + Nodes::Scope { children, .. } => { for child in children { match &child.node { Nodes::Scope { name: child_name, children: _ } => { if child_name == index { return child; } } @@ -528,9 +540,9 @@ impl Index<&str> for Node { } } } - Nodes::Struct { name, fields } => { + Nodes::Struct { fields, .. } => { for field in fields { - if let Nodes::Member { name: child_name, r#type } = &field.node { + if let Nodes::Member { name: child_name, .. } = &field.node { if child_name == index { return &field; } @@ -607,7 +619,7 @@ Light: struct { program.types.get("Light").expect("Failed to get Light type"); - if let Nodes::Struct { name, fields } = &node.node { + if let Nodes::Struct { name, .. } = &node.node { assert_eq!(name, "root"); assert_struct(&node["Light"]); } @@ -655,7 +667,7 @@ main: fn () -> void { let tokens = tokenize(source).unwrap(); let (node, _program) = parse(tokens).expect("Failed to parse"); - if let Nodes::Scope{ name, children } = &node.node { + if let Nodes::Scope{ name, .. } = &node.node { assert_eq!(name, "root"); assert_function(&node["main"]); } else { panic!("Not root node") } @@ -675,7 +687,7 @@ main: fn () -> void { let main_node = &node["main"]; - if let Nodes::Function { name, statements, raw, return_type, params } = &main_node.node { + if let Nodes::Function { name, statements, return_type, params, .. } = &main_node.node { assert_eq!(name, "main"); assert_eq!(statements.len(), 2); assert_eq!(return_type, "void"); @@ -688,13 +700,13 @@ main: fn () -> void { if let Nodes::Expression(Expressions::Operator { name, left: var_decl, right: multiply }) = &statement0.node { assert_eq!(name, "="); - if let Nodes::Expression(Expressions::VariableDeclaration { name, r#type }) = &var_decl.node { + if let Nodes::Expression(Expressions::VariableDeclaration { .. }) = &var_decl.node { } else { panic!("Not a variable declaration"); } if let Nodes::Expression(Expressions::Operator { name, left: vec4, right: literal }) = &multiply.node { assert_eq!(name, "*"); - if let Nodes::Expression(Expressions::FunctionCall { name, parameters, }) = &vec4.node { + if let Nodes::Expression(Expressions::FunctionCall { name, .. }) = &vec4.node { assert_eq!(name, "vec4"); } else { panic!("Not a function call"); } @@ -791,4 +803,22 @@ main: fn () -> void { } else { panic!("Not a feature"); } } } + + #[test] + fn test_parse_multiple_functions() { + let source = " +used: fn () -> void {} +not_used: fn () -> void {} + +main: fn () -> void { + used(); +}"; + + let tokens = tokenize(source).expect("Failed to tokenize"); + let (node, _) = parse(tokens).expect("Failed to parse"); + + if let Nodes::Scope { children, .. } = &node.node { + assert_eq!(children.len(), 3); + } + } } \ No newline at end of file diff --git a/resource_management/src/asset/material_asset_handler.rs b/resource_management/src/asset/material_asset_handler.rs index eebb8128..8145293d 100644 --- a/resource_management/src/asset/material_asset_handler.rs +++ b/resource_management/src/asset/material_asset_handler.rs @@ -1,13 +1,13 @@ -use std::ops::Deref; +use std::{borrow::Borrow, cell::RefCell, ops::Deref}; use smol::future::FutureExt; -use crate::{resource::material_resource_handler::ShaderGenerator, types::{AlphaMode, Material, Model, Property, Shader, ShaderTypes, Value, Variant, VariantVariable}, GenericResourceSerialization, ProcessedResources}; +use crate::{resource::material_resource_handler::ProgramGenerator, types::{AlphaMode, Material, Model, Property, Shader, ShaderTypes, Value, Variant, VariantVariable}, GenericResourceSerialization, ProcessedResources}; use super::{asset_handler::AssetHandler, AssetResolver, StorageBackend}; struct MaterialAssetHandler { - generator: Option>, + generator: Option>, } impl MaterialAssetHandler { @@ -17,7 +17,7 @@ impl MaterialAssetHandler { } } - pub fn set_shader_generator(&mut self, generator: G) { + pub fn set_shader_generator(&mut self, generator: G) { self.generator = Some(Box::new(generator)); } } @@ -54,20 +54,22 @@ impl AssetHandler for MaterialAssetHandler { } } - // Ok(vec![ProcessedResources::Generated((GenericResourceSerialization::new(url.to_string(), Material { - // albedo: Property::Factor(Value::Vector3([1f32, 0f32, 0f32])), - // normal: Property::Factor(Value::Vector3([0f32, 0f32, 1f32])), - // roughness: Property::Factor(Value::Scalar(0.5f32)), - // metallic: Property::Factor(Value::Scalar(0.0f32)), - // emissive: Property::Factor(Value::Vector3([0f32, 0f32, 0f32])), - // occlusion: Property::Factor(Value::Scalar(0f32)), - // double_sided: false, - // alpha_mode: AlphaMode::Opaque, - // model: Model { - // name: Self::RENDER_MODEL.to_string(), - // pass: "MaterialEvaluation".to_string(), - // }, - // }).required_resources(&required_resources), Vec::new()))]) + let resource = GenericResourceSerialization::new(url.to_string(), Material { + albedo: Property::Factor(Value::Vector3([1f32, 0f32, 0f32])), + normal: Property::Factor(Value::Vector3([0f32, 0f32, 1f32])), + roughness: Property::Factor(Value::Scalar(0.5f32)), + metallic: Property::Factor(Value::Scalar(0.0f32)), + emissive: Property::Factor(Value::Vector3([0f32, 0f32, 0f32])), + occlusion: Property::Factor(Value::Scalar(0f32)), + double_sided: false, + alpha_mode: AlphaMode::Opaque, + model: Model { + name: "Visibility".to_string(), + pass: "MaterialEvaluation".to_string(), + }, + }).required_resources(&required_resources); + + storage_backend.store(resource); } else { let variant_json = asset_json; @@ -91,16 +93,14 @@ impl AssetHandler for MaterialAssetHandler { } } -async fn produce_shader(generator: &dyn ShaderGenerator, asset_resolver: &dyn AssetResolver, domain: &str, material: &json::JsonValue, shader_json: &json::JsonValue, stage: &str) -> Option { +async fn produce_shader(generator: &dyn ProgramGenerator, asset_resolver: &dyn AssetResolver, domain: &str, material: &json::JsonValue, shader_json: &json::JsonValue, stage: &str) -> Option { let path = shader_json.as_str()?; let (arlp, format) = asset_resolver.resolve(&path).await?; let shader_code = std::str::from_utf8(&arlp).unwrap().to_string(); let shader_option = if format == "glsl" { - Some((jspd::lexer::Node { - node: jspd::lexer::Nodes::GLSL { code: shader_code }, - }, path.to_string())) + Some((jspd::lexer::Node::glsl(shader_code), path.to_string())) } else if format == "besl" { Some((jspd::compile_to_jspd(&shader_code).unwrap(), path.to_string())) } else { @@ -108,7 +108,7 @@ async fn produce_shader(generator: &dyn ShaderGenerator, asset_resolver: &dyn As }; if let Some((shader, path)) = shader_option { - Some(treat_shader(generator, &path, domain, stage, material, shader,)?.unwrap()) + Some(treat_shader(generator, &path, domain, stage, material, &shader,)?.unwrap()) } else { let default_shader = match stage { "Vertex" => default_vertex_shader(), @@ -116,18 +116,112 @@ async fn produce_shader(generator: &dyn ShaderGenerator, asset_resolver: &dyn As _ => { panic!("Invalid shader stage") } }; - let shader_node = jspd::lexer::Node { - node: jspd::lexer::Nodes::GLSL { code: default_shader.to_string() }, - }; + let shader_node = jspd::lexer::Node::glsl(default_shader.to_string()); + + Some(treat_shader(generator, "", domain, stage, material, &shader_node,)?.unwrap()) + } +} + +fn generate_shader_internal(string: &mut String, main_function_node: &jspd::Node) { + let node = main_function_node; + if let Some(parent) = node.parent() { + if let Some(parent) = parent.upgrade() { + generate_shader_internal(string, RefCell::borrow(&parent).deref()); + } + } + + match node.node() { + jspd::Nodes::Null => {} + jspd::Nodes::Scope { name: _, children } => { + for child in children { + let child = RefCell::borrow(&child); + generate_shader_internal(string, &child,); + } + } + jspd::Nodes::Function { name, params: _, return_type: _, statements, raw: _ } => { + match name.as_str() { + _ => { + for statement in statements { + let statement = RefCell::borrow(&statement); + generate_shader_internal(string, &statement,); + string.push_str(";\n"); + } + } + } + } + jspd::Nodes::Struct { fields, .. } => { + for field in fields { + let field = RefCell::borrow(&field); + generate_shader_internal(string, &field,); + } + } + jspd::Nodes::Member { .. } => { - Some(treat_shader(generator, "", domain, stage, material, shader_node,)?.unwrap()) + } + jspd::Nodes::GLSL { code } => { + string.push_str(code); + } + jspd::Nodes::Expression(expression) => { + match expression { + jspd::Expressions::Operator { operator, left: _, right } => { + if operator == &jspd::Operators::Assignment { + string.push_str(&format!("albedo = vec3(")); + let right = RefCell::borrow(&right); + generate_shader_internal(string, &right,); + string.push_str(")"); + } + } + jspd::Expressions::FunctionCall { name, parameters, .. } => { + match name.as_str() { + "sample" => { + string.push_str(&format!("textureGrad(")); + for parameter in parameters { + let parameter = RefCell::borrow(¶meter); + generate_shader_internal(string, ¶meter,); + } + string.push_str(&format!(", uv, vec2(0.5), vec2(0.5f))")); + } + _ => { + string.push_str(&format!("{}(", name)); + for parameter in parameters { + let parameter = RefCell::borrow(¶meter); + generate_shader_internal(string, ¶meter,); + } + string.push_str(&format!(")")); + } + } + } + jspd::Expressions::Member { name } => { + string.push_str(name); + } + _ => panic!("Invalid expression") + } + } } } -fn treat_shader(generator: &dyn ShaderGenerator, path: &str, domain: &str, stage: &str, material: &json::JsonValue, shader_node: jspd::lexer::Node,) -> Option> { +fn generate_shader(main_function_node: &jspd::Node) -> String { + // let mut string = shader_generator::generate_glsl_header_block(&shader_generator::ShaderGenerationSettings::new("Compute")); + let mut string = String::with_capacity(2048); + + generate_shader_internal(&mut string, main_function_node); + + string +} + +fn treat_shader(generator: &dyn ProgramGenerator, path: &str, domain: &str, stage: &str, material: &json::JsonValue, shader_node: &jspd::NodeReference,) -> Option> { let visibility = generator; - let glsl = visibility.transform(material, &shader_node, stage)?; + let main = match RefCell::borrow(&shader_node).node() { + jspd::Nodes::Scope { children, .. } => { + children[0].clone() + } + _ => { + return Some(Err("Invalid shader".to_string())); + } + }; + + let glsl = generate_shader(RefCell::borrow(&main).deref()); log::debug!("Generated shader: {}", &glsl); @@ -184,4 +278,78 @@ fn default_vertex_shader() -> &'static str { fn default_fragment_shader() -> &'static str { "void main() { out_color = get_debug_color(in_instance_index); }" +} + +#[cfg(test)] +mod tests { + use super::{MaterialAssetHandler}; + use crate::{asset::{asset_handler::AssetHandler, tests::{TestAssetResolver, TestStorageBackend}}, resource::material_resource_handler::ProgramGenerator}; + + #[test] + fn load_material() { + let asset_resolver = TestAssetResolver::new(); + let storage_backend = TestStorageBackend::new(); + let mut asset_handler = MaterialAssetHandler::new(); + + struct TestShaderGenerator { + + } + + impl TestShaderGenerator { + fn new() -> TestShaderGenerator { + TestShaderGenerator {} + } + } + + impl ProgramGenerator for TestShaderGenerator { + fn transform(&self, children: Vec>) -> (&'static str, jspd::Node) { + todo!() + } + } + + let shader_generator = TestShaderGenerator::new(); + + asset_handler.set_shader_generator(shader_generator); + + let url = "material.json"; + + let material_json = r#"{ + "domain": "World", + "type": "Surface", + "shaders": { + "Fragment": "shaders/fragment.besl" + }, + "variables": [ + { + "name": "color", + "data_type": "vec4f", + "type": "Static", + "value": "Purple" + } + ] + }"#; + + asset_resolver.add_file(url, material_json.as_bytes()); + + let shader_file = "main: fn () -> void { + out_color = color; + }"; + + asset_resolver.add_file("shaders/fragment.besl", shader_file.as_bytes()); + + let doc = json::object! { + "url": url, + }; + + let result = smol::block_on(asset_handler.load(&asset_resolver, &storage_backend, &url, &doc)).expect("Image asset handler did not handle asset"); + + let generated_resources = storage_backend.get_resources(); + + assert_eq!(generated_resources.len(), 2); + + let resource = &generated_resources[0]; + + assert_eq!(resource.url, "material.json"); + assert_eq!(resource.class, "Material"); + } } \ No newline at end of file diff --git a/resource_management/src/asset/mod.rs b/resource_management/src/asset/mod.rs index 52f25b91..e96ed509 100644 --- a/resource_management/src/asset/mod.rs +++ b/resource_management/src/asset/mod.rs @@ -75,7 +75,7 @@ pub trait StorageBackend: Sync + Send { #[cfg(test)] mod tests { - use std::sync::{Arc, Mutex}; + use std::{collections::HashMap, sync::{Arc, Mutex}}; use smol::future::FutureExt; @@ -84,20 +84,34 @@ mod tests { use super::{read_asset_from_source, AssetResolver, StorageBackend}; pub struct TestAssetResolver { - + files: Arc>>>, } impl TestAssetResolver { pub fn new() -> TestAssetResolver { TestAssetResolver { + files: Arc::new(Mutex::new(HashMap::new())), } } + + pub fn add_file(&self, name: &'static str, data: &[u8]) { + self.files.lock().unwrap().insert(name, data.into()); + } } impl AssetResolver for TestAssetResolver { fn resolve<'a>(&'a self, url: &'a str) -> std::pin::Pin, String)>> + Send + 'a>> { async move { - read_asset_from_source(url, Some(&std::path::Path::new("../assets"))).await.ok() + if let Ok(x) = read_asset_from_source(url, Some(&std::path::Path::new("../assets"))).await { + Some(x) + } else { + if let Some(f) = self.files.lock().unwrap().get(url) { + // Extract extension from url + Some((f.to_vec(), url.split('.').last().unwrap().to_string())) + } else { + None + } + } }.boxed() } } diff --git a/resource_management/src/lib.rs b/resource_management/src/lib.rs index 63e5891c..51adf11d 100644 --- a/resource_management/src/lib.rs +++ b/resource_management/src/lib.rs @@ -12,6 +12,8 @@ pub mod types; pub mod file_tracker; +pub mod shader_generation; + // https://www.yosoygames.com.ar/wp/2018/03/vertex-formats-part-1-compression/ /// This is the struct resource handlers should return when processing a resource. diff --git a/resource_management/src/resource/material_resource_handler.rs b/resource_management/src/resource/material_resource_handler.rs index bff9fc07..bd6b4a3f 100644 --- a/resource_management/src/resource/material_resource_handler.rs +++ b/resource_management/src/resource/material_resource_handler.rs @@ -7,9 +7,9 @@ use super::{resource_handler::ResourceHandler, resource_manager::ResourceManager pub struct MaterialResourcerHandler {} -pub trait ShaderGenerator: Sync + Send { - fn process(&self, children: Vec>) -> (&'static str, jspd::Node); - fn transform(&self, material: &json::JsonValue, shader_node: &jspd::lexer::Node, stage: &str) -> Option; +pub trait ProgramGenerator: Sync + Send { + /// Transforms a program. + fn transform(&self, children: Vec>) -> (&'static str, jspd::Node); } impl MaterialResourcerHandler { diff --git a/resource_management/src/shader_generation.rs b/resource_management/src/shader_generation.rs new file mode 100644 index 00000000..e6a52b10 --- /dev/null +++ b/resource_management/src/shader_generation.rs @@ -0,0 +1,243 @@ +use std::{cell::RefCell, collections::{HashMap, HashSet}, ops::Deref}; + +struct ShaderGenerator { + minified: bool, +} + +impl ShaderGenerator { + pub fn new() -> Self { + ShaderGenerator { + minified: false, + } + } + + pub fn minified(mut self, minified: bool) -> Self { + self.minified = minified; + self + } + + pub fn compilation(&self) -> ShaderCompilation { + ShaderCompilation { + minified: self.minified, + present_symbols: HashSet::new(), + } + } +} + +struct ShaderCompilation { + minified: bool, + present_symbols: HashSet, +} + +impl ShaderCompilation { + pub fn generate_shader(&mut self, main_function_node: &jspd::NodeReference) -> String { + // let mut string = shader_generator::generate_glsl_header_block(&shader_generator::ShaderGenerationSettings::new("Compute")); + let mut string = String::with_capacity(2048); + + self.generate_shader_internal(&mut string, main_function_node); + + string + } + + fn generate_shader_internal(&mut self, string: &mut String, main_function_node: &jspd::NodeReference) { + if self.present_symbols.contains(main_function_node) { return; } + + let node = RefCell::borrow(&main_function_node); + + match node.node() { + jspd::Nodes::Null => {} + jspd::Nodes::Scope { name: _, children } => { + for child in children { + self.generate_shader_internal(string, &child,); + } + } + jspd::Nodes::Function { name, statements, return_type, .. } => { + let mut l_string = String::with_capacity(128); + + self.generate_shader_internal(&mut l_string, &return_type); + + l_string.push_str("void "); + + l_string.push_str(name); + + if self.minified { l_string.push_str("(){"); } else { l_string.push_str("() {\n"); } + + for statement in statements { + if !self.minified { l_string.push('\t'); } + self.generate_shader_internal(&mut l_string, &statement,); + if !self.minified { l_string.push_str(";\n"); } else { l_string.push(';'); } + } + + l_string.push_str("}\n"); + + string.insert_str(0, &l_string); + + self.present_symbols.insert(main_function_node.clone()); + } + jspd::Nodes::Struct { name, fields, .. } => { + if name == "void" || name == "vec2f" || name == "vec3f" || name == "vec4f" || name == "mat2f" || name == "mat3f" || name == "mat4f" || name == "f32" || name == "u32" || name == "i32" { return; } + + let mut l_string = String::with_capacity(128); + + l_string.push_str("struct "); + l_string.push_str(name.as_str()); + + if self.minified { l_string.push('{'); } else { l_string.push_str(" {\n"); } + + for field in fields { + if !self.minified { l_string.push('\t'); } + self.generate_shader_internal(&mut l_string, &field,); + if self.minified { l_string.push(';') } else { l_string.push_str(";\n"); } + } + + l_string.push_str("}\n"); + + string.insert_str(0, &l_string); + + self.present_symbols.insert(main_function_node.clone()); + } + jspd::Nodes::Member { name, r#type } => { + self.generate_shader_internal(string, &r#type); // Demand the type to be present in the shader + if let Some(type_name) = r#type.borrow().get_name() { + string.push_str(type_name.as_str()); + string.push(' '); + } + string.push_str(name.as_str()); + } + jspd::Nodes::GLSL { code } => { + string.push_str(code); + } + jspd::Nodes::Expression(expression) => { + match expression { + jspd::Expressions::Operator { operator, left, right } => { + if operator == &jspd::Operators::Assignment { + self.generate_shader_internal(string, &left,); + if self.minified { string.push('=') } else { string.push_str(" = "); } + self.generate_shader_internal(string, &right,); + } + } + jspd::Expressions::FunctionCall { name, parameters, function, .. } => { + self.generate_shader_internal(string, &function); + + string.push_str(&format!("{}(", name)); + for (i, parameter) in parameters.iter().enumerate() { + if i > 0 { + if self.minified { string.push(',') } else { string.push_str(", "); } + } + + self.generate_shader_internal(string, ¶meter,); + } + string.push_str(&format!(")")); + } + jspd::Expressions::Member { name } => { + string.push_str(name); + } + jspd::Expressions::VariableDeclaration { name, r#type } => { + string.push_str(&format!("{} {}", r#type, name)); + } + jspd::Expressions::Literal { value } => { + string.push_str(&format!("{}", value)); + } + _ => panic!("Invalid expression") + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::{cell::RefCell, ops::Deref}; + + use crate::shader_generation::ShaderGenerator; + + #[test] + fn empty_script() { + let script = r#" + "#; + + let main_function_node = jspd::compile_to_jspd(&script).unwrap(); + + let shader_generator = ShaderGenerator::new(); + + let shader = shader_generator.compilation().generate_shader(&main_function_node); + + println!("{}", shader); + } + + #[test] + fn fragment_shader() { + let script = r#" + main: fn () -> void { + albedo: vec3 = vec3(1.0, 0.0, 0.0); + } + "#; + + let main_function_node = jspd::compile_to_jspd(&script).unwrap(); + + let main = RefCell::borrow(&main_function_node).get_child("main").unwrap(); + + let shader_generator = ShaderGenerator::new(); + + let shader = shader_generator.compilation().generate_shader(&main); + + assert_eq!(shader, "void main() {\n\tvec3 albedo = vec3(1.0, 0.0, 0.0);\n}\n"); + + let shader_generator = ShaderGenerator::new().minified(true); + + let shader = shader_generator.compilation().generate_shader(&main); + + assert_eq!(shader, "void main(){vec3 albedo=vec3(1.0,0.0,0.0);}\n"); + } + + #[test] + fn cull_unused_functions() { + let script = r#" + used_by_used: fn () -> void {} + used: fn() -> void { + used_by_used(); + } + not_used: fn() -> void {} + + main: fn () -> void { + used(); + } + "#; + + let main_function_node = jspd::compile_to_jspd(&script).unwrap(); + + let main = RefCell::borrow(&main_function_node).get_child("main").unwrap(); + + let shader_generator = ShaderGenerator::new(); + + let shader = shader_generator.compilation().generate_shader(&main); + + assert_eq!(shader, "void used_by_used() {\n}\nvoid used() {\n\tused_by_used();\n}\nvoid main() {\n\tused();\n}\n"); + } + + #[test] + fn structure() { + let script = r#" + Vertex: struct { + position: vec3f, + normal: vec3f, + } + + use_vertex: fn () -> Vertex {} + + main: fn () -> void { + use_vertex(); + } + "#; + + let main_function_node = jspd::compile_to_jspd(&script).unwrap(); + + let main = RefCell::borrow(&main_function_node).get_child("main").unwrap(); + + let shader_generator = ShaderGenerator::new(); + + let shader = shader_generator.compilation().generate_shader(&main); + + assert_eq!(shader, "struct Vertex {\n\tvec3f position;\n\tvec3f normal;\n}\nvoid use_vertex() {\n}\nvoid main() {\n\tuse_vertex();\n}\n"); + } +} \ No newline at end of file diff --git a/src/rendering/visibility_shader_generator.rs b/src/rendering/visibility_shader_generator.rs index 0e546a6a..8874b2df 100644 --- a/src/rendering/visibility_shader_generator.rs +++ b/src/rendering/visibility_shader_generator.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use resource_management::material_resource_handler::ShaderGenerator; +use resource_management::resource::material_resource_handler::ProgramGenerator; use crate::{rendering::{shader_strings::{CALCULATE_FULL_BARY, DISTRIBUTION_GGX, FRESNEL_SCHLICK, GEOMETRY_SMITH}, visibility_model::render_domain::{CAMERA_STRUCT_GLSL, LIGHTING_DATA_STRUCT_GLSL, LIGHT_STRUCT_GLSL, MATERIAL_STRUCT_GLSL, MESHLET_STRUCT_GLSL, MESH_STRUCT_GLSL}}, shader_generator}; @@ -12,8 +12,8 @@ impl VisibilityShaderGenerator { } } -impl ShaderGenerator for VisibilityShaderGenerator { - fn process(&self, mut parent_children: Vec>) -> (&'static str, jspd::lexer::Node) { +impl ProgramGenerator for VisibilityShaderGenerator { + fn transform(&self, mut parent_children: Vec>) -> (&'static str, jspd::lexer::Node) { let value = json::object! { "type": "scope", "camera": { @@ -84,340 +84,274 @@ impl ShaderGenerator for VisibilityShaderGenerator { children.append(&mut parent_children); }; - ("Visibility", node) - } +// string.push_str(MESH_STRUCT_GLSL); - fn transform(&self, material: &json::JsonValue, shader_node: &jspd::lexer::Node, stage: &str) -> Option { - match stage { - "Vertex" => None, - "Fragment" => Some(self.fragment_transform(material, shader_node)), - _ => panic!("Invalid stage"), - } - } -} +// string.push_str(" +// layout(set=0, binding=1, scalar) buffer readonly MeshBuffer { +// Mesh meshes[]; +// }; -impl VisibilityShaderGenerator { - /// Produce a GLSL shader string from a BESL shader node. - /// This returns an option since for a given input stage the visibility shader generator may not produce any output. +// layout(set=0, binding=2, scalar) buffer readonly Positions { +// vec3 positions[]; +// }; - fn fragment_transform(&self, material: &json::JsonValue, shader_node: &jspd::lexer::Node) -> String { - let mut string = shader_generator::generate_glsl_header_block(&shader_generator::ShaderGenerationSettings::new("Compute")); +// layout(set=0, binding=3, scalar) buffer readonly Normals { +// vec3 normals[]; +// }; - string.push_str(MESH_STRUCT_GLSL); +// layout(set=0, binding=4, scalar) buffer readonly VertexIndices { +// uint16_t vertex_indices[]; +// }; - string.push_str(" -layout(set=0, binding=1, scalar) buffer readonly MeshBuffer { - Mesh meshes[]; -}; +// layout(set=0, binding=5, scalar) buffer readonly PrimitiveIndices { +// uint8_t primitive_indices[]; +// };"); -layout(set=0, binding=2, scalar) buffer readonly Positions { - vec3 positions[]; -}; +// string.push_str(MESHLET_STRUCT_GLSL); -layout(set=0, binding=3, scalar) buffer readonly Normals { - vec3 normals[]; -}; +// string.push_str(" +// layout(set=0,binding=6,scalar) buffer readonly MeshletsBuffer { +// Meshlet meshlets[]; +// }; -layout(set=0, binding=4, scalar) buffer readonly VertexIndices { - uint16_t vertex_indices[]; -}; +// layout(set=0,binding=7) uniform sampler2D textures[1]; -layout(set=0, binding=5, scalar) buffer readonly PrimitiveIndices { - uint8_t primitive_indices[]; -};"); +// layout(set=1,binding=0,scalar) buffer MaterialCount { +// uint material_count[]; +// }; - string.push_str(MESHLET_STRUCT_GLSL); +// layout(set=1,binding=1,scalar) buffer MaterialOffset { +// uint material_offset[]; +// }; - string.push_str(" -layout(set=0,binding=6,scalar) buffer readonly MeshletsBuffer { - Meshlet meshlets[]; -}; +// layout(set=1,binding=4,scalar) buffer PixelMapping { +// u16vec2 pixel_mapping[]; +// }; -layout(set=0,binding=7) uniform sampler2D textures[1]; +// layout(set=1, binding=6, r32ui) uniform readonly uimage2D triangle_index; +// layout(set=2, binding=0, rgba16) uniform image2D out_albedo; +// layout(set=2, binding=2, rgba16) uniform image2D out_diffuse; -layout(set=1,binding=0,scalar) buffer MaterialCount { - uint material_count[]; -}; +// layout(set=2,binding=10) uniform sampler2D ao; +// layout(set=2,binding=11) uniform sampler2D depth_shadow_map; -layout(set=1,binding=1,scalar) buffer MaterialOffset { - uint material_offset[]; -}; +// layout(push_constant, scalar) uniform PushConstant { +// uint material_id; +// } pc;"); -layout(set=1,binding=4,scalar) buffer PixelMapping { - u16vec2 pixel_mapping[]; -}; +// string.push_str(CAMERA_STRUCT_GLSL); +// string.push_str(LIGHT_STRUCT_GLSL); +// string.push_str(LIGHTING_DATA_STRUCT_GLSL); +// string.push_str(MATERIAL_STRUCT_GLSL); -layout(set=1, binding=6, r32ui) uniform readonly uimage2D triangle_index; -layout(set=2, binding=0, rgba16) uniform image2D out_albedo; -layout(set=2, binding=2, rgba16) uniform image2D out_diffuse; +// string.push_str("layout(set=2,binding=1,scalar) buffer CameraBuffer { +// Camera camera; +// }; + +// layout(set=2,binding=4,scalar) buffer readonly LightingBuffer { +// LightingData lighting_data; +// }; + +// layout(set=2,binding=5,scalar) buffer readonly MaterialsBuffer { +// Material materials[]; +// };"); -layout(set=2,binding=10) uniform sampler2D ao; -layout(set=2,binding=11) uniform sampler2D depth_shadow_map; +// string.push_str(DISTRIBUTION_GGX); +// string.push_str(GEOMETRY_SMITH); +// string.push_str(FRESNEL_SCHLICK); +// string.push_str(CALCULATE_FULL_BARY); -layout(push_constant, scalar) uniform PushConstant { - uint material_id; -} pc;"); +// string.push_str(&format!("layout(local_size_x=32) in;\n")); - string.push_str(CAMERA_STRUCT_GLSL); - string.push_str(LIGHT_STRUCT_GLSL); - string.push_str(LIGHTING_DATA_STRUCT_GLSL); - string.push_str(MATERIAL_STRUCT_GLSL); +// for variable in material["variables"].members() { +// match variable["data_type"].as_str().unwrap() { +// "vec4f" => { // Since GLSL doesn't support vec4f constants, we have to split it into 4 floats. +// string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 0, "float", format!("{}_r", variable["name"]), "1.0")); +// string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 1, "float", format!("{}_g", variable["name"]), "0.0")); +// string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 2, "float", format!("{}_b", variable["name"]), "0.0")); +// string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 3, "float", format!("{}_a", variable["name"]), "1.0")); +// string.push_str(&format!("const {} {} = {};\n", "vec4", variable["name"], format!("vec4({name}_r, {name}_g, {name}_b, {name}_a)", name=variable["name"]))); +// } +// _ => {} +// } +// } - string.push_str("layout(set=2,binding=1,scalar) buffer CameraBuffer { - Camera camera; - }; - - layout(set=2,binding=4,scalar) buffer readonly LightingBuffer { - LightingData lighting_data; - }; - - layout(set=2,binding=5,scalar) buffer readonly MaterialsBuffer { - Material materials[]; - };"); - - string.push_str(DISTRIBUTION_GGX); - string.push_str(GEOMETRY_SMITH); - string.push_str(FRESNEL_SCHLICK); - string.push_str(CALCULATE_FULL_BARY); - - string.push_str(&format!("layout(local_size_x=32) in;\n")); - - for variable in material["variables"].members() { - match variable["data_type"].as_str().unwrap() { - "vec4f" => { // Since GLSL doesn't support vec4f constants, we have to split it into 4 floats. - string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 0, "float", format!("{}_r", variable["name"]), "1.0")); - string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 1, "float", format!("{}_g", variable["name"]), "0.0")); - string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 2, "float", format!("{}_b", variable["name"]), "0.0")); - string.push_str(&format!("layout(constant_id={}) const {} {} = {};", 3, "float", format!("{}_a", variable["name"]), "1.0")); - string.push_str(&format!("const {} {} = {};\n", "vec4", variable["name"], format!("vec4({name}_r, {name}_g, {name}_b, {name}_a)", name=variable["name"]))); - } - _ => {} - } - } +// string.push_str(" +// void main() { +// if (gl_GlobalInvocationID.x >= material_count[pc.material_id]) { return; } -string.push_str(" -void main() { - if (gl_GlobalInvocationID.x >= material_count[pc.material_id]) { return; } +// uint offset = material_offset[pc.material_id]; +// ivec2 pixel_coordinates = ivec2(pixel_mapping[offset + gl_GlobalInvocationID.x]); +// uint triangle_meshlet_indices = imageLoad(triangle_index, pixel_coordinates).r; +// uint meshlet_triangle_index = triangle_meshlet_indices & 0xFF; +// uint meshlet_index = triangle_meshlet_indices >> 8; - uint offset = material_offset[pc.material_id]; - ivec2 pixel_coordinates = ivec2(pixel_mapping[offset + gl_GlobalInvocationID.x]); - uint triangle_meshlet_indices = imageLoad(triangle_index, pixel_coordinates).r; - uint meshlet_triangle_index = triangle_meshlet_indices & 0xFF; - uint meshlet_index = triangle_meshlet_indices >> 8; +// Meshlet meshlet = meshlets[meshlet_index]; - Meshlet meshlet = meshlets[meshlet_index]; +// uint instance_index = meshlet.instance_index; - uint instance_index = meshlet.instance_index; +// Mesh mesh = meshes[instance_index]; - Mesh mesh = meshes[instance_index]; +// Material material = materials[pc.material_id]; - Material material = materials[pc.material_id]; +// uint primitive_indices[3] = uint[3]( +// primitive_indices[(meshlet.triangle_offset + meshlet_triangle_index) * 3 + 0], +// primitive_indices[(meshlet.triangle_offset + meshlet_triangle_index) * 3 + 1], +// primitive_indices[(meshlet.triangle_offset + meshlet_triangle_index) * 3 + 2] +// ); - uint primitive_indices[3] = uint[3]( - primitive_indices[(meshlet.triangle_offset + meshlet_triangle_index) * 3 + 0], - primitive_indices[(meshlet.triangle_offset + meshlet_triangle_index) * 3 + 1], - primitive_indices[(meshlet.triangle_offset + meshlet_triangle_index) * 3 + 2] - ); +// uint vertex_indices[3] = uint[3]( +// mesh.base_vertex_index + vertex_indices[meshlet.vertex_offset + primitive_indices[0]], +// mesh.base_vertex_index + vertex_indices[meshlet.vertex_offset + primitive_indices[1]], +// mesh.base_vertex_index + vertex_indices[meshlet.vertex_offset + primitive_indices[2]] +// ); - uint vertex_indices[3] = uint[3]( - mesh.base_vertex_index + vertex_indices[meshlet.vertex_offset + primitive_indices[0]], - mesh.base_vertex_index + vertex_indices[meshlet.vertex_offset + primitive_indices[1]], - mesh.base_vertex_index + vertex_indices[meshlet.vertex_offset + primitive_indices[2]] - ); +// vec4 vertex_positions[3] = vec4[3]( +// vec4(positions[vertex_indices[0]], 1.0), +// vec4(positions[vertex_indices[1]], 1.0), +// vec4(positions[vertex_indices[2]], 1.0) +// ); - vec4 vertex_positions[3] = vec4[3]( - vec4(positions[vertex_indices[0]], 1.0), - vec4(positions[vertex_indices[1]], 1.0), - vec4(positions[vertex_indices[2]], 1.0) - ); +// vec4 vertex_normals[3] = vec4[3]( +// vec4(normals[vertex_indices[0]], 0.0), +// vec4(normals[vertex_indices[1]], 0.0), +// vec4(normals[vertex_indices[2]], 0.0) +// ); - vec4 vertex_normals[3] = vec4[3]( - vec4(normals[vertex_indices[0]], 0.0), - vec4(normals[vertex_indices[1]], 0.0), - vec4(normals[vertex_indices[2]], 0.0) - ); +// vec2 image_extent = imageSize(triangle_index); - vec2 image_extent = imageSize(triangle_index); +// vec2 uv = pixel_coordinates / image_extent; - vec2 uv = pixel_coordinates / image_extent; +// vec2 nc = uv * 2 - 1; - vec2 nc = uv * 2 - 1; +// vec4 clip_space_vertex_positions[3] = vec4[3](camera.view_projection * mesh.model * vertex_positions[0], camera.view_projection * mesh.model * vertex_positions[1], camera.view_projection * mesh.model * vertex_positions[2]); - vec4 clip_space_vertex_positions[3] = vec4[3](camera.view_projection * mesh.model * vertex_positions[0], camera.view_projection * mesh.model * vertex_positions[1], camera.view_projection * mesh.model * vertex_positions[2]); +// BarycentricDeriv barycentric_deriv = calculate_full_bary(clip_space_vertex_positions[0], clip_space_vertex_positions[1], clip_space_vertex_positions[2], nc, image_extent); +// vec3 barycenter = barycentric_deriv.lambda; - BarycentricDeriv barycentric_deriv = calculate_full_bary(clip_space_vertex_positions[0], clip_space_vertex_positions[1], clip_space_vertex_positions[2], nc, image_extent); - vec3 barycenter = barycentric_deriv.lambda; +// vec3 vertex_position = vec3((mesh.model * vertex_positions[0]).xyz * barycenter.x + (mesh.model * vertex_positions[1]).xyz * barycenter.y + (mesh.model * vertex_positions[2]).xyz * barycenter.z); +// vec3 vertex_normal = vec3((vertex_normals[0]).xyz * barycenter.x + (vertex_normals[1]).xyz * barycenter.y + (vertex_normals[2]).xyz * barycenter.z); - vec3 vertex_position = vec3((mesh.model * vertex_positions[0]).xyz * barycenter.x + (mesh.model * vertex_positions[1]).xyz * barycenter.y + (mesh.model * vertex_positions[2]).xyz * barycenter.z); - vec3 vertex_normal = vec3((vertex_normals[0]).xyz * barycenter.x + (vertex_normals[1]).xyz * barycenter.y + (vertex_normals[2]).xyz * barycenter.z); +// vec3 N = normalize(vertex_normal); +// vec3 V = normalize(-(camera.view[3].xyz - vertex_position)); - vec3 N = normalize(vertex_normal); - vec3 V = normalize(-(camera.view[3].xyz - vertex_position)); +// vec3 albedo = vec3(1, 0, 0); +// vec3 metalness = vec3(0); +// float roughness = float(0.5); +// "); - vec3 albedo = vec3(1, 0, 0); - vec3 metalness = vec3(0); - float roughness = float(0.5); -"); +// fn visit_node(string: &mut String, shader_node: &jspd::Node, material: &json::JsonValue) { +// let variable_names = material["variables"].members().map(|variable| variable["name"].as_str().unwrap()).collect::>(); - fn visit_node(string: &mut String, shader_node: &jspd::Node, material: &json::JsonValue) { - match &shader_node.node { - jspd::Nodes::Scope { name: _, children } => { - for child in children { - visit_node(string, child, material); - } - } - jspd::Nodes::Function { name, params: _, return_type: _, statements, raw: _ } => { - match name.as_str() { - _ => { - for statement in statements { - visit_node(string, statement, material); - string.push_str(";\n"); - } - } - } - } - jspd::Nodes::Struct { name, template, fields, types } => { - for field in fields { - visit_node(string, field, material); - } - } - jspd::Nodes::Member { name, r#type } => { + // if variable_names.contains(&name.as_str()) { + // if material["variables"].members().find(|variable| variable["name"].as_str().unwrap() == name.as_str()).unwrap()["data_type"].as_str().unwrap() == "Texture2D" { + // let mut variables = material["variables"].members().filter(|variable| variable["data_type"].as_str().unwrap() == "Texture2D").collect::>(); - } - jspd::Nodes::GLSL { code } => { - string.push_str(code); - } - jspd::Nodes::Expression(expression) => { - match expression { - jspd::Expressions::Operator { operator, left: _, right } => { - if operator == &jspd::Operators::Assignment { - string.push_str(&format!("albedo = vec3(")); - visit_node(string, right, material); - string.push_str(")"); - } - } - jspd::Expressions::FunctionCall { name, parameters } => { - match name.as_str() { - "sample" => { - string.push_str(&format!("textureGrad(")); - for parameter in parameters { - visit_node(string, parameter, material); - } - string.push_str(&format!(", uv, vec2(0.5), vec2(0.5f))")); - } - _ => { - string.push_str(&format!("{}(", name)); - for parameter in parameters { - visit_node(string, parameter, material); - } - string.push_str(&format!(")")); - } - } - } - jspd::Expressions::Member { name } => { - let variable_names = material["variables"].members().map(|variable| variable["name"].as_str().unwrap()).collect::>(); - - if variable_names.contains(&name.as_str()) { - if material["variables"].members().find(|variable| variable["name"].as_str().unwrap() == name.as_str()).unwrap()["data_type"].as_str().unwrap() == "Texture2D" { - let mut variables = material["variables"].members().filter(|variable| variable["data_type"].as_str().unwrap() == "Texture2D").collect::>(); - - variables.sort_by(|a, b| a["name"].as_str().unwrap().cmp(b["name"].as_str().unwrap())); - - let index = variables.iter().position(|variable| variable["name"].as_str().unwrap() == name.as_str()).unwrap(); - - string.push_str(&format!("textures[nonuniformEXT(material.textures[{}])]", index)); - } else { - string.push_str(name); - } - } else { - string.push_str(name); - } - } - _ => panic!("Invalid expression") - } - } - } - } + // variables.sort_by(|a, b| a["name"].as_str().unwrap().cmp(b["name"].as_str().unwrap())); + + // let index = variables.iter().position(|variable| variable["name"].as_str().unwrap() == name.as_str()).unwrap(); + + // string.push_str(&format!("textures[nonuniformEXT(material.textures[{}])]", index)); + // } else { + // string.push_str(name); + // } + // } else { + // string.push_str(name); + // } +// } + +// visit_node(&mut string, shader_node, material); + +// string.push_str(&format!(" +// vec3 lo = vec3(0.0); +// vec3 diffuse = vec3(0.0); + +// float ao_factor = texture(ao, uv).r; + +// for (uint i = 0; i < lighting_data.light_count; ++i) {{ +// vec3 light_pos = lighting_data.lights[i].position; +// vec3 light_color = lighting_data.lights[i].color; +// mat4 light_matrix = lighting_data.lights[i].vp_matrix; +// uint8_t light_type = lighting_data.lights[i].light_type; - visit_node(&mut string, shader_node, material); +// vec3 L = vec3(0.0); -string.push_str(&format!(" - vec3 lo = vec3(0.0); - vec3 diffuse = vec3(0.0); +// if (light_type == 68) {{ // Infinite +// L = normalize(light_pos); +// }} else {{ +// L = normalize(light_pos - vertex_position); +// }} - float ao_factor = texture(ao, uv).r; +// float NdotL = max(dot(N, L), 0.0); - for (uint i = 0; i < lighting_data.light_count; ++i) {{ - vec3 light_pos = lighting_data.lights[i].position; - vec3 light_color = lighting_data.lights[i].color; - mat4 light_matrix = lighting_data.lights[i].vp_matrix; - uint8_t light_type = lighting_data.lights[i].light_type; +// if (NdotL <= 0.0) {{ +// continue; +// }} - vec3 L = vec3(0.0); +// float occlusion_factor = 1.0; +// float attenuation = 1.0; - if (light_type == 68) {{ // Infinite - L = normalize(light_pos); - }} else {{ - L = normalize(light_pos - vertex_position); - }} +// if (light_type == 68) {{ // Infinite +// vec4 surface_light_clip_position = light_matrix * vec4(vertex_position + N * 0.001, 1.0); +// vec3 surface_light_ndc_position = surface_light_clip_position.xyz / surface_light_clip_position.w; +// vec2 shadow_uv = surface_light_ndc_position.xy * 0.5 + 0.5; +// float z = surface_light_ndc_position.z; +// float shadow_sample_depth = texture(depth_shadow_map, shadow_uv).r; +// float occlusion_factor = z < shadow_sample_depth ? 0.0 : 1.0; - float NdotL = max(dot(N, L), 0.0); +// if (occlusion_factor == 0.0) {{ +// continue; +// }} - if (NdotL <= 0.0) {{ - continue; - }} +// attenuation = 1.0; +// }} else {{ +// float distance = length(light_pos - vertex_position); +// attenuation = 1.0 / (distance * distance); +// }} - float occlusion_factor = 1.0; - float attenuation = 1.0; +// vec3 H = normalize(V + L); - if (light_type == 68) {{ // Infinite - vec4 surface_light_clip_position = light_matrix * vec4(vertex_position + N * 0.001, 1.0); - vec3 surface_light_ndc_position = surface_light_clip_position.xyz / surface_light_clip_position.w; - vec2 shadow_uv = surface_light_ndc_position.xy * 0.5 + 0.5; - float z = surface_light_ndc_position.z; - float shadow_sample_depth = texture(depth_shadow_map, shadow_uv).r; - float occlusion_factor = z < shadow_sample_depth ? 0.0 : 1.0; +// vec3 radiance = light_color * attenuation; - if (occlusion_factor == 0.0) {{ - continue; - }} +// vec3 F0 = vec3(0.04); +// F0 = mix(F0, albedo, metalness); +// vec3 F = fresnel_schlick(max(dot(H, V), 0.0), F0); - attenuation = 1.0; - }} else {{ - float distance = length(light_pos - vertex_position); - attenuation = 1.0 / (distance * distance); - }} +// float NDF = distribution_ggx(N, H, roughness); +// float G = geometry_smith(N, V, L, roughness); +// vec3 specular = (NDF * G * F) / (4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.000001); - vec3 H = normalize(V + L); +// vec3 kS = F; +// vec3 kD = vec3(1.0) - kS; - vec3 radiance = light_color * attenuation; +// kD *= 1.0 - metalness; - vec3 F0 = vec3(0.04); - F0 = mix(F0, albedo, metalness); - vec3 F = fresnel_schlick(max(dot(H, V), 0.0), F0); +// vec3 local_diffuse = kD * albedo / PI; - float NDF = distribution_ggx(N, H, roughness); - float G = geometry_smith(N, V, L, roughness); - vec3 specular = (NDF * G * F) / (4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.000001); +// lo += (local_diffuse + specular) * radiance * NdotL * occlusion_factor; +// diffuse += local_diffuse; +// }}; - vec3 kS = F; - vec3 kD = vec3(1.0) - kS; +// lo *= ao_factor; +// ")); - kD *= 1.0 - metalness; +// string.push_str(&format!("imageStore(out_albedo, pixel_coordinates, vec4(lo, 1.0));")); +// string.push_str(&format!("imageStore(out_diffuse, pixel_coordinates, vec4(diffuse, 1.0));")); - vec3 local_diffuse = kD * albedo / PI; +// string.push_str(&format!("\n}}")); // Close main() - lo += (local_diffuse + specular) * radiance * NdotL * occlusion_factor; - diffuse += local_diffuse; - }}; + ("Visibility", node) + } +} + +impl VisibilityShaderGenerator { + /// Produce a GLSL shader string from a BESL shader node. + /// This returns an option since for a given input stage the visibility shader generator may not produce any output. - lo *= ao_factor; -")); + fn fragment_transform(&self, material: &json::JsonValue, shader_node: &jspd::lexer::Node) -> String { + let mut string = shader_generator::generate_glsl_header_block(&shader_generator::ShaderGenerationSettings::new("Compute")); - string.push_str(&format!("imageStore(out_albedo, pixel_coordinates, vec4(lo, 1.0));")); - string.push_str(&format!("imageStore(out_diffuse, pixel_coordinates, vec4(diffuse, 1.0));")); - string.push_str(&format!("\n}}")); // Close main() string } @@ -425,8 +359,6 @@ string.push_str(&format!(" #[cfg(test)] mod tests { - use resource_management::material_resource_handler::ShaderGenerator; - use crate::jspd; #[test]