diff options
Diffstat (limited to 'servers/visual/shader_language.cpp')
-rw-r--r-- | servers/visual/shader_language.cpp | 2385 |
1 files changed, 2385 insertions, 0 deletions
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp new file mode 100644 index 0000000000..3061c2ddff --- /dev/null +++ b/servers/visual/shader_language.cpp @@ -0,0 +1,2385 @@ +/*************************************************************************/ +/* shader_language.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "shader_language.h" +#include "print_string.h" +#include "os/os.h" +static bool _is_text_char(CharType c) { + + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; +} + +static bool _is_number(CharType c) { + + return (c>='0' && c<='9'); +} + +static bool _is_hex(CharType c) { + + return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'); +} + +const char * ShaderLanguage::token_names[TK_MAX]={ + "EMPTY", + "INDENTIFIER", + "TRUE", + "FALSE", + "REAL_CONSTANT", + "TYPE_VOID", + "TYPE_BOOL", + "TYPE_FLOAT", + "TYPE_VEC2", + "TYPE_VEC3", + "TYPE_VEC4", + "TYPE_MAT3", + "TYPE_MAT4", + "TYPE_TEXTURE", + "TYPE_CUBEMAP", + "TYPE_COLOR", + "OP_EQUAL", + "OP_NOT_EQUAL", + "OP_LESS", + "OP_LESS_EQUAL", + "OP_GREATER", + "OP_GREATER_EQUAL", + "OP_AND", + "OP_OR", + "OP_NOT", + "OP_ADD", + "OP_SUB", + "OP_MUL", + "OP_DIV", + "OP_NEG", + "OP_ASSIGN", + "OP_ASSIGN_ADD", + "OP_ASSIGN_SUB", + "OP_ASSIGN_MUL", + "OP_ASSIGN_DIV", + "CF_IF", + "CF_ELSE", + "CF_RETURN", + "BRACKET_OPEN", + "BRACKET_CLOSE", + "CURLY_BRACKET_OPEN", + "CURLY_BRACKET_CLOSE", + "PARENTHESIS_OPEN", + "PARENTHESIS_CLOSE", + "COMMA", + "SEMICOLON", + "PERIOD", + "UNIFORM", + "ERROR", +}; + +ShaderLanguage::Token ShaderLanguage::read_token(const CharType* p_text,int p_len,int &r_line,int &r_chars) { + +#define GETCHAR(m_idx) ((m_idx<p_len)?p_text[m_idx]:CharType(0)) + + r_chars=1; //by default everything eats one char + switch(GETCHAR(0)) { + + case '\t': + case '\r': + case ' ': + return Token(); + case '\n': + r_line++; + return Token(); + case '/': { + + switch(GETCHAR(1)) { + case '*': { // block comment + + + while(true) { + if (GETCHAR(r_chars+1)=='0') + break; + if (GETCHAR(r_chars+1)=='*' && GETCHAR(r_chars+2)=='/') + break; + if (GETCHAR(r_chars+1)=='\n') + r_line++; + r_chars++; + } + + return Token(); + + } break; + case '/': { // line comment skip + + while(GETCHAR(r_chars+1)!='\n' && GETCHAR(r_chars+1)!=0) { + r_chars++; + } + + return Token(); + + } break; + case '=': { // diveq + + r_chars=2; + return Token(TK_OP_ASSIGN_DIV); + + } break; + default: + return Token(TK_OP_DIV); + + } + } break; + case '=': { + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_EQUAL); + } + + return Token(TK_OP_ASSIGN); + + } break; + case '<': { + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_LESS_EQUAL); + } /*else if (GETCHAR(1)=='<') { + r_chars++; + if (GETCHAR(2)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_SHIFT_LEFT); + } + + return Token(TK_OP_SHIFT_LEFT); + }*/ + + return Token(TK_OP_LESS); + + } break; + case '>': { + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_GREATER_EQUAL); + }/* else if (GETCHAR(1)=='<') { + r_chars++; + if (GETCHAR(2)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_SHIFT_RIGHT); + } + + return Token(TK_OP_SHIFT_RIGHT); + }*/ + + return Token(TK_OP_GREATER); + + } break; + case '!': { + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_NOT_EQUAL); + } + + return Token(TK_OP_NOT); + + } break; + //case '"' //string - no strings in shader + //case '\'' //string - no strings in shader + case '{': + return Token(TK_CURLY_BRACKET_OPEN); + case '}': + return Token(TK_CURLY_BRACKET_CLOSE); + //case '[': + // return Token(TK_BRACKET_OPEN); + //case ']': + // return Token(TK_BRACKET_CLOSE); + case '(': + return Token(TK_PARENTHESIS_OPEN); + case ')': + return Token(TK_PARENTHESIS_CLOSE); + case ',': + return Token(TK_COMMA); + case ';': + return Token(TK_SEMICOLON); + //case '?': + // return Token(TK_QUESTION_MARK); + //case ':': + // return Token(TK_COLON); //for methods maybe but now useless. + //case '^': + // return Token(TK_OP_BIT_XOR); + //case '~': + // return Token(TK_OP_BIT_INVERT); + case '&': { + + if (GETCHAR(1)=='&') { + + r_chars++; + return Token(TK_OP_AND); + } + + return Token(TK_ERROR,"Unknown character"); + +/* + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_BIT_AND); + } else if (GETCHAR(1)=='&') { + r_chars++; + return Token(TK_OP_AND); + } + return TK_OP_BIT_AND;*/ + } break; + case '|': { + + if (GETCHAR(1)=='|') { + + r_chars++; + return Token(TK_OP_OR); + } + + return Token(TK_ERROR,"Unknown character"); + + /* + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_BIT_OR); + } else if (GETCHAR(1)=='|') { + r_chars++; + return Token(TK_OP_OR); + } + return TK_OP_BIT_OR; + */ + } break; + case '*': { + + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_MUL); + } + return TK_OP_MUL; + } break; + case '+': { + + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_ADD); + } /*else if (GETCHAR(1)=='+') { + + r_chars++; + return Token(TK_OP_PLUS_PLUS); + }*/ + + return TK_OP_ADD; + } break; + case '-': { + + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_SUB); + }/* else if (GETCHAR(1)=='-') { + + r_chars++; + return Token(TK_OP_MINUS_MINUS); + }*/ + + return TK_OP_SUB; + } break; + /*case '%': { + + if (GETCHAR(1)=='=') { + r_chars++; + return Token(TK_OP_ASSIGN_MOD); + } + + return TK_OP_MOD; + } break;*/ + default: { + + if (_is_number(GETCHAR(0)) || (GETCHAR(0)=='.' && _is_number(GETCHAR(1)))) { + // parse number + bool period_found=false; + bool exponent_found=false; + bool hexa_found=false; + bool sign_found=false; + + String str; + int i=0; + + while(true) { + if (GETCHAR(i)=='.') { + if (period_found || exponent_found) + return Token(TK_ERROR,"Invalid numeric constant"); + period_found=true; + } else if (GETCHAR(i)=='x') { + if (hexa_found || str.length()!=1 || str[0]!='0') + return Token(TK_ERROR,"Invalid numeric constant"); + hexa_found=true; + } else if (GETCHAR(i)=='e') { + if (hexa_found || exponent_found) + return Token(TK_ERROR,"Invalid numeric constant"); + exponent_found=true; + } else if (_is_number(GETCHAR(i))) { + //all ok + } else if (hexa_found && _is_hex(GETCHAR(i))) { + + } else if ((GETCHAR(i)=='-' || GETCHAR(i)=='+') && exponent_found) { + if (sign_found) + return Token(TK_ERROR,"Invalid numeric constant"); + sign_found=true; + } else + break; + + str+=CharType(GETCHAR(i)); + i++; + } + + if (!_is_number(str[str.length()-1])) + return Token(TK_ERROR,"Invalid numeric constant"); + + r_chars+=str.length()-1; + return Token(TK_REAL_CONSTANT,str); + /* + if (period_found) + return Token(TK_NUMBER_REAL,str); + else + return Token(TK_NUMBER_INTEGER,str);*/ + + } + + if (GETCHAR(0)=='.') { + //parse period + return Token(TK_PERIOD); + } + + if (_is_text_char(GETCHAR(0))) { + // parse identifier + String str; + str+=CharType(GETCHAR(0)); + + while(_is_text_char(GETCHAR(r_chars))) { + + str+=CharType(GETCHAR(r_chars)); + r_chars++; + } + + //see if keyword + struct _kws { TokenType token; const char *text;}; + static const _kws keyword_list[]={ + {TK_TRUE,"true"}, + {TK_FALSE,"false"}, + {TK_TYPE_VOID,"void"}, + {TK_TYPE_BOOL,"bool"}, + /*{TK_TYPE_INT,"int"}, + {TK_TYPE_INT2,"int2"}, + {TK_TYPE_INT3,"int3"}, + {TK_TYPE_INT4,"int4"},*/ + {TK_TYPE_FLOAT,"float"}, + /*{TK_TYPE_FLOAT2,"float2"}, + {TK_TYPE_FLOAT3,"float3"}, + {TK_TYPE_FLOAT4,"float4"},*/ + {TK_TYPE_VEC2,"vec2"}, + {TK_TYPE_VEC3,"vec3"}, + {TK_TYPE_VEC4,"vec4"}, + {TK_TYPE_TEXTURE,"texture"}, + {TK_TYPE_CUBEMAP,"cubemap"}, + {TK_TYPE_COLOR,"color"}, + /* + {TK_TYPE_MAT2,"mat2"}, + {TK_TYPE_MAT3,"mat3"}, + {TK_TYPE_MAT4,"mat3"},*/ + {TK_TYPE_MAT3,"mat3"}, + {TK_TYPE_MAT4,"mat4"}, + {TK_CF_IF,"if"}, + {TK_CF_ELSE,"else"}, + /* + {TK_CF_FOR,"for"}, + {TK_CF_WHILE,"while"}, + {TK_CF_DO,"do"}, + {TK_CF_SWITCH,"switch"}, + {TK_CF_BREAK,"break"}, + {TK_CF_CONTINUE,"continue"},*/ + {TK_CF_RETURN,"return"}, + {TK_UNIFORM,"uniform"}, + {TK_ERROR,NULL} + }; + + int idx=0; + + while(keyword_list[idx].text) { + + if (str==keyword_list[idx].text) + return Token(keyword_list[idx].token); + idx++; + } + + + return Token(TK_INDENTIFIER,str); + } + + return Token(TK_ERROR,"Unknown character"); + + } break; + } + + ERR_PRINT("BUG"); + return Token(); +} + +Error ShaderLanguage::tokenize(const String& p_text,Vector<Token> *p_tokens,String *r_error,int *r_err_line,int *r_err_column) { + + + int len =p_text.length(); + int pos=0; + + int line=0; + + while(pos<len) { + + int advance=0; + int prev_line=line; + Token t = read_token(&p_text[pos],len-pos,line,advance); + t.line=prev_line; + + if (t.type==TK_ERROR) { + + if (r_error) { + return ERR_COMPILATION_FAILED; + *r_error=t.text; + *r_err_line=line; + } + } + + if (t.type!=TK_EMPTY) + p_tokens->push_back(t); + //if (prev_line!=line) + // p_tokens->push_back(Token(TK_LINE,itos(line))); + + pos+=advance; + + } + + return OK; + +} + +String ShaderLanguage::lex_debug(const String& p_code) { + + Vector<Token> tokens; + String error; + int errline,errcol; + if (tokenize(p_code,&tokens,&error,&errline,&errcol)!=OK) + return error; + String ret; + for(int i=0;i<tokens.size();i++) { + ret+=String(token_names[tokens[i].type])+":"+itos(tokens[i].line)+":"+itos(tokens[i].col)+":"+tokens[i].text+"\n"; + } + + return ret; + +} + +bool ShaderLanguage::is_token_datatype(TokenType p_type) { + + return + (p_type==TK_TYPE_VOID) || + (p_type==TK_TYPE_BOOL) || + (p_type==TK_TYPE_FLOAT) || + (p_type==TK_TYPE_VEC2) || + (p_type==TK_TYPE_VEC3) || + (p_type==TK_TYPE_VEC4) || + (p_type==TK_TYPE_COLOR) || + (p_type==TK_TYPE_MAT3) || + (p_type==TK_TYPE_MAT4) || + (p_type==TK_TYPE_CUBEMAP) || + (p_type==TK_TYPE_TEXTURE); + +} + +ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) { + + switch(p_type) { + + case TK_TYPE_VOID: return TYPE_VOID; + case TK_TYPE_BOOL: return TYPE_BOOL; + case TK_TYPE_FLOAT: return TYPE_FLOAT; + case TK_TYPE_VEC2: return TYPE_VEC2; + case TK_TYPE_VEC3: return TYPE_VEC3; + case TK_TYPE_VEC4: return TYPE_VEC4; + case TK_TYPE_COLOR: return TYPE_VEC4; + case TK_TYPE_MAT3: return TYPE_MAT3; + case TK_TYPE_MAT4: return TYPE_MAT4; + case TK_TYPE_TEXTURE: return TYPE_TEXTURE; + case TK_TYPE_CUBEMAP: return TYPE_CUBEMAP; + default: return TYPE_VOID; + } + + return TYPE_VOID; +} + + +String ShaderLanguage::get_datatype_name(DataType p_type) { + + switch(p_type) { + + case TYPE_VOID: return "void"; + case TYPE_BOOL: return "bool"; + case TYPE_FLOAT: return "float"; + case TYPE_VEC2: return "vec2"; + case TYPE_VEC3: return "vec3"; + case TYPE_VEC4: return "vec4"; + case TYPE_MAT3: return "mat3"; + case TYPE_MAT4: return "mat4"; + case TYPE_TEXTURE: return "texture"; + case TYPE_CUBEMAP: return "cubemap"; + default: return ""; + } + + return ""; +} + + +bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) { + + return + (p_type==TK_TYPE_BOOL) || + (p_type==TK_TYPE_FLOAT) || + (p_type==TK_TYPE_VEC2) || + (p_type==TK_TYPE_VEC3) || + (p_type==TK_TYPE_VEC4) || + (p_type==TK_TYPE_COLOR) || + (p_type==TK_TYPE_MAT3) || + (p_type==TK_TYPE_MAT4) || + (p_type==TK_TYPE_TEXTURE) || + (p_type==TK_TYPE_CUBEMAP); + +} + + +bool ShaderLanguage::parser_is_at_function(Parser& parser) { + + return (is_token_datatype(parser.get_token_type(0)) && parser.get_token_type(1)==TK_INDENTIFIER && parser.get_token_type(2)==TK_PARENTHESIS_OPEN); +} + + + +bool ShaderLanguage::test_existing_identifier(Node *p_node,const StringName p_identifier,bool p_func,bool p_var,bool p_builtin) { + + Node *node = p_node; + + while(node) { + + if (node->type==Node::TYPE_BLOCK) { + + BlockNode *block = (BlockNode*)node; + if (block->variables.has(p_identifier)) + return true; + } else if (node->type==Node::TYPE_PROGRAM) { + + ProgramNode *program = (ProgramNode*)node; + for(int i=0;i<program->functions.size();i++) { + + if (program->functions[i].name==p_identifier) { + return true; + } + } + + if(program->builtin_variables.has(p_identifier)) { + return true; + } + if(program->uniforms.has(p_identifier)) { + return true; + } + + } else if (node->type==Node::TYPE_FUNCTION) { + + FunctionNode *func=(FunctionNode*)node; + for(int i=0;i<func->arguments.size();i++) + if (func->arguments[i].name==p_identifier) + return true; + } + + node=node->parent; + } + + // try keywords + + int idx=0; + + //todo optimize + while(intrinsic_func_defs[idx].name) { + + if (p_identifier.operator String()==intrinsic_func_defs[idx].name) + return true; + idx++; + } + + + return false; + +} + + +Error ShaderLanguage::parse_function(Parser& parser,BlockNode *p_block) { + + if (!p_block->parent || p_block->parent->type!=Node::TYPE_PROGRAM) { + parser.set_error("Misplaced function"); + return ERR_PARSE_ERROR; + + } + + + ProgramNode *program = (ProgramNode*)p_block->parent; + + StringName name = parser.get_token(1).text; + + if (test_existing_identifier(p_block,name)) { + + parser.set_error("Duplicate Identifier (existing variable/builtin/function): "+name); + return ERR_PARSE_ERROR; + + } + + + FunctionNode *function = parser.create_node<FunctionNode>(program); + function->body = parser.create_node<BlockNode>(function); + + function->name=name; + + function->return_type=get_token_datatype(parser.get_token_type(0)); + + { //add to programnode + ProgramNode::Function f; + f.name=name; + f.function=function; + program->functions.push_back(f); + } + + int ofs=3; + + while(true) { + + //end of arguments + if (parser.get_token_type(ofs)==TK_PARENTHESIS_CLOSE) { + ofs++; + break; + } + //next argument awaits + if (parser.get_token_type(ofs)==TK_COMMA) { + if (!is_token_nonvoid_datatype(parser.get_token_type(ofs+1))) { + parser.set_error("Expected Identifier or ')' following ','"); + return ERR_PARSE_ERROR; + } + ofs++; + continue; + } + + + + if (!is_token_nonvoid_datatype(parser.get_token_type(ofs+0))) { + parser.set_error("Invalid Argument Type"); + return ERR_PARSE_ERROR; + } + + DataType identtype=get_token_datatype(parser.get_token_type(ofs+0)); + + if (parser.get_token_type(ofs+1)!=TK_INDENTIFIER) { + parser.set_error("Expected Argument Identifier"); + return ERR_PARSE_ERROR; + } + + StringName identname=parser.get_token(ofs+1).text; + + if (test_existing_identifier(function,identname)) { + parser.set_error("Duplicate Argument Identifier: "+identname); + return ERR_DUPLICATE_SYMBOL; + } + + FunctionNode::Argument arg; + arg.name=identname; + arg.type=identtype; + //function->body->variables[arg.name]=arg.type; + function->arguments.push_back(arg); + + ofs+=2; + } + + parser.advance(ofs); + // match { + if (parser.get_token_type()!=TK_CURLY_BRACKET_OPEN) { + parser.set_error("Expected '{'"); + return ERR_PARSE_ERROR; + } + + parser.advance(); + Error err = parse_block(parser,function->body); + + if (err) + return err; + + // make sure that if the function has a return type, it does return something.. + if (function->return_type!=TYPE_VOID) { + bool found=false; + for(int i=0;i<function->body->statements.size();i++) { + if (function->body->statements[i]->type==Node::TYPE_CONTROL_FLOW) { + + ControlFlowNode *cf = (ControlFlowNode*)function->body->statements[i]; + if (cf->flow_op==FLOW_OP_RETURN) { + // type of return was already checked when inserted + // no need to check here + found=true; + } + } + } + + if (!found) { + parser.set_error("Function must return a value (use the main block)"); + return ERR_PARSE_ERROR; + } + } + + return OK; +} + + +const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={ + //constructors + {"bool",TYPE_BOOL,{TYPE_BOOL,TYPE_VOID}}, + {"float",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"vec2",TYPE_VEC2,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"vec3",TYPE_VEC3,{TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}}, + {"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_VEC2,TYPE_VOID}}, + {"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}}, + {"vec4",TYPE_VEC4,{TYPE_VEC2,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VEC2,TYPE_VOID}}, + {"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC3,TYPE_VOID}}, + {"vec4",TYPE_VEC4,{TYPE_VEC3,TYPE_FLOAT,TYPE_VOID}}, + {"mat3",TYPE_MAT3,{TYPE_VEC3,TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"mat4",TYPE_MAT4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + //intrinsics - trigonometry + {"sin",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"cos",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"tan",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"asin",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"acos",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"atan",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"atan2",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"sinh",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"cosh",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"tanh",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + //intrinsics - exponential + {"pow",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"pow",TYPE_VEC2,{TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}}, + {"pow",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"pow",TYPE_VEC3,{TYPE_VEC3,TYPE_FLOAT,TYPE_VOID}}, + {"pow",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"pow",TYPE_VEC4,{TYPE_VEC4,TYPE_FLOAT,TYPE_VOID}}, + {"pow",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"exp",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"exp",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"exp",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"exp",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"log",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"log",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"log",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"log",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"sqrt",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"sqrt",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"sqrt",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"sqrt",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + //intrinsics - common + {"abs",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"abs",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"abs",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"abs",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"sign",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"sign",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"sign",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"sign",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"floor",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"floor",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"floor",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"floor",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"trunc",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"trunc",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"trunc",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"trunc",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"round",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"round",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"round",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"round",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"ceil",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"ceil",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"ceil",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"ceil",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"fract",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {"fract",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"fract",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"fract",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"mod",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"mod",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"mod",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"mod",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"min",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"min",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"min",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"min",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"max",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"max",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"max",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"max",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"clamp",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"clamp",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"clamp",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"clamp",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"mix",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}}, + {"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"mix",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_FLOAT,TYPE_VOID}}, + {"mix",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"mix",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_FLOAT,TYPE_VOID}}, + {"mix",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"step",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}}, + {"step",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + //intrinsics - geometric + {"length",TYPE_FLOAT,{TYPE_VEC2,TYPE_VOID}}, + {"length",TYPE_FLOAT,{TYPE_VEC3,TYPE_VOID}}, + {"length",TYPE_FLOAT,{TYPE_VEC4,TYPE_VOID}}, + {"distance",TYPE_FLOAT,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"distance",TYPE_FLOAT,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"distance",TYPE_FLOAT,{TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"dot",TYPE_FLOAT,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}}, + {"dot",TYPE_FLOAT,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"dot",TYPE_FLOAT,{TYPE_VEC4,TYPE_VEC4,TYPE_VOID}}, + {"cross",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + {"normalize",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {"normalize",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {"normalize",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {"reflect",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}}, + //intrinsics - texture + {"tex",TYPE_VEC4,{TYPE_TEXTURE,TYPE_VEC2,TYPE_VOID}}, + {"texcube",TYPE_VEC4,{TYPE_CUBEMAP,TYPE_VEC3,TYPE_VOID}}, + {"texscreen",TYPE_VEC3,{TYPE_VEC2,TYPE_VOID}}, + {"texpos",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + + {NULL,TYPE_VOID,{TYPE_VOID}} + +}; + +const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={ + + {OP_ASSIGN,TYPE_VOID,{TYPE_BOOL,TYPE_BOOL}}, + {OP_ASSIGN,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_ASSIGN,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}}, + {OP_ASSIGN,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}}, + {OP_ASSIGN,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}}, + {OP_ASSIGN,TYPE_VOID,{TYPE_MAT3,TYPE_MAT3}}, + {OP_ASSIGN,TYPE_VOID,{TYPE_MAT4,TYPE_MAT4}}, + {OP_ADD,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_ADD,TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2}}, + {OP_ADD,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}}, + {OP_ADD,TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4}}, + {OP_SUB,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_SUB,TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2}}, + {OP_SUB,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}}, + {OP_SUB,TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4}}, + {OP_MUL,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2}}, + {OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_FLOAT}}, + {OP_MUL,TYPE_VEC2,{TYPE_FLOAT,TYPE_VEC2}}, + {OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_MAT3}}, + {OP_MUL,TYPE_VEC2,{TYPE_MAT3,TYPE_VEC2}}, + {OP_MUL,TYPE_VEC2,{TYPE_VEC2,TYPE_MAT4}}, + {OP_MUL,TYPE_VEC2,{TYPE_MAT4,TYPE_VEC2}}, + {OP_MUL,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}}, + {OP_MUL,TYPE_VEC3,{TYPE_VEC3,TYPE_FLOAT}}, + {OP_MUL,TYPE_VEC3,{TYPE_FLOAT,TYPE_VEC3}}, + {OP_MUL,TYPE_VEC3,{TYPE_MAT3,TYPE_VEC3}}, + {OP_MUL,TYPE_VEC3,{TYPE_MAT4,TYPE_VEC3}}, + {OP_MUL,TYPE_VEC3,{TYPE_VEC3,TYPE_MAT3}}, + {OP_MUL,TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4}}, + {OP_MUL,TYPE_VEC4,{TYPE_VEC4,TYPE_FLOAT}}, + {OP_MUL,TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC4}}, + {OP_MUL,TYPE_VEC4,{TYPE_MAT4,TYPE_VEC4}}, + {OP_MUL,TYPE_VEC4,{TYPE_VEC4,TYPE_MAT4}}, + {OP_MUL,TYPE_MAT3,{TYPE_MAT3,TYPE_MAT3}}, + {OP_MUL,TYPE_MAT4,{TYPE_MAT4,TYPE_MAT4}}, + {OP_DIV,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_DIV,TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2}}, + {OP_DIV,TYPE_VEC2,{TYPE_VEC2,TYPE_FLOAT}}, + {OP_DIV,TYPE_VEC2,{TYPE_FLOAT,TYPE_VEC2}}, + {OP_DIV,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}}, + {OP_DIV,TYPE_VEC3,{TYPE_VEC3,TYPE_FLOAT}}, + {OP_DIV,TYPE_VEC3,{TYPE_FLOAT,TYPE_VEC3}}, + {OP_DIV,TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4}}, + {OP_DIV,TYPE_VEC4,{TYPE_VEC4,TYPE_FLOAT}}, + {OP_DIV,TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC4}}, + {OP_ASSIGN_ADD,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}}, + {OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}}, + {OP_ASSIGN_ADD,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}}, + {OP_ASSIGN_SUB,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}}, + {OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}}, + {OP_ASSIGN_SUB,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT3,TYPE_VEC2}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_VEC2}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC3,TYPE_FLOAT}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT3,TYPE_VEC3}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_VEC3}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_VEC4,TYPE_FLOAT}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_VEC4}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT3,TYPE_MAT3}}, + {OP_ASSIGN_MUL,TYPE_VOID,{TYPE_MAT4,TYPE_MAT4}}, + {OP_ASSIGN_DIV,TYPE_VOID,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_ASSIGN_DIV,TYPE_VOID,{TYPE_VEC2,TYPE_VEC2}}, + {OP_ASSIGN_DIV,TYPE_VOID,{TYPE_VEC2,TYPE_FLOAT}}, + {OP_ASSIGN_DIV,TYPE_VOID,{TYPE_VEC3,TYPE_VEC3}}, + {OP_ASSIGN_DIV,TYPE_VOID,{TYPE_VEC3,TYPE_FLOAT}}, + {OP_ASSIGN_DIV,TYPE_VOID,{TYPE_VEC4,TYPE_VEC4}}, + {OP_ASSIGN_DIV,TYPE_VOID,{TYPE_VEC4,TYPE_FLOAT}}, + {OP_NEG,TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}}, + {OP_NEG,TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}}, + {OP_NEG,TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}}, + {OP_NEG,TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}}, + {OP_NOT,TYPE_BOOL,{TYPE_BOOL,TYPE_VOID}}, + {OP_CMP_EQ,TYPE_BOOL,{TYPE_BOOL,TYPE_BOOL}}, + {OP_CMP_EQ,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_CMP_EQ,TYPE_VEC2,{TYPE_VEC3,TYPE_VEC2}}, + {OP_CMP_EQ,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}}, + {OP_CMP_EQ,TYPE_VEC4,{TYPE_VEC3,TYPE_VEC4}}, + //{OP_CMP_EQ,TYPE_MAT3,{TYPE_MAT4,TYPE_MAT3}}, ?? + //{OP_CMP_EQ,TYPE_MAT4,{TYPE_MAT4,TYPE_MAT4}}, ?? + {OP_CMP_NEQ,TYPE_BOOL,{TYPE_BOOL,TYPE_BOOL}}, + {OP_CMP_NEQ,TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_CMP_NEQ,TYPE_VEC3,{TYPE_VEC2,TYPE_VEC2}}, + {OP_CMP_NEQ,TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3}}, + {OP_CMP_NEQ,TYPE_VEC3,{TYPE_VEC4,TYPE_VEC4}}, + //{OP_CMP_NEQ,TYPE_MAT4,{TYPE_MAT4,TYPE_MAT4}}, //? + {OP_CMP_LEQ,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_CMP_GEQ,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_CMP_LESS,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_CMP_GREATER,TYPE_BOOL,{TYPE_FLOAT,TYPE_FLOAT}}, + {OP_CMP_OR,TYPE_BOOL,{TYPE_BOOL,TYPE_BOOL}}, + {OP_CMP_AND,TYPE_BOOL,{TYPE_BOOL,TYPE_BOOL}}, + {OP_MAX,TYPE_VOID,{TYPE_VOID,TYPE_VOID}} +}; + + +const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={ + + { "VERTEX", TYPE_VEC3}, + { "NORMAL", TYPE_VEC3}, + { "TANGENT", TYPE_VEC3}, + { "BINORMAL", TYPE_VEC3}, + { "UV", TYPE_VEC2}, + { "UV2", TYPE_VEC2}, + { "COLOR", TYPE_VEC4}, + { "BONES", TYPE_VEC4}, + { "WEIGHTS", TYPE_VEC4}, + { "VAR1", TYPE_VEC4}, + { "VAR2", TYPE_VEC4}, + { "SPEC_EXP", TYPE_FLOAT}, + { "POINT_SIZE", TYPE_FLOAT}, + + //builtins + { "WORLD_MATRIX", TYPE_MAT4}, + { "INV_CAMERA_MATRIX", TYPE_MAT4}, + { "PROJECTION_MATRIX", TYPE_MAT4}, + { "INSTANCE_ID", TYPE_FLOAT}, + { "TIME", TYPE_FLOAT}, + { NULL, TYPE_VOID}, +}; +const ShaderLanguage::BuiltinsDef ShaderLanguage::fragment_builtins_defs[]={ + + { "VERTEX", TYPE_VEC3}, + { "POSITION", TYPE_VEC3}, + { "NORMAL", TYPE_VEC3}, + { "TANGENT", TYPE_VEC3}, + { "BINORMAL", TYPE_VEC3}, + { "UV", TYPE_VEC2}, + { "UV2", TYPE_VEC2}, + { "COLOR", TYPE_VEC4}, + { "NORMAL", TYPE_VEC3}, + { "VAR1", TYPE_VEC4}, + { "VAR2", TYPE_VEC4}, + { "DIFFUSE", TYPE_VEC3}, + { "DIFFUSE_ALPHA", TYPE_VEC4}, + { "SPECULAR", TYPE_VEC3}, + { "EMISSION", TYPE_VEC3}, + { "SPEC_EXP", TYPE_FLOAT}, + { "GLOW", TYPE_FLOAT}, + { "SHADE_PARAM", TYPE_FLOAT}, + { "DISCARD", TYPE_FLOAT}, + { "SCREEN_UV", TYPE_VEC2}, + { "POINT_COORD", TYPE_VEC2}, + { "INV_CAMERA_MATRIX", TYPE_MAT4}, + +// { "SCREEN_POS", TYPE_VEC2}, +// { "SCREEN_TEXEL_SIZE", TYPE_VEC2}, + { "TIME", TYPE_FLOAT}, + { NULL, TYPE_VOID} + +}; +const ShaderLanguage::BuiltinsDef ShaderLanguage::postprocess_fragment_builtins_defs[]={ + + { "IN_COLOR", TYPE_VEC3}, + { "IN_POSITION", TYPE_VEC3}, + { "OUT_COLOR", TYPE_VEC3}, + { "SCREEN_POS", TYPE_VEC2}, + { "SCREEN_TEXEL_SIZE", TYPE_VEC2}, + { "TIME", TYPE_FLOAT}, + { NULL, TYPE_VOID} +}; + + + +ShaderLanguage::DataType ShaderLanguage::compute_node_type(Node *p_node) { + + switch(p_node->type) { + + case Node::TYPE_PROGRAM: ERR_FAIL_V(TYPE_VOID); + case Node::TYPE_FUNCTION: return static_cast<FunctionNode*>(p_node)->return_type; + case Node::TYPE_BLOCK: ERR_FAIL_V(TYPE_VOID); + case Node::TYPE_VARIABLE: return static_cast<VariableNode*>(p_node)->datatype_cache; + case Node::TYPE_CONSTANT: return static_cast<ConstantNode*>(p_node)->datatype; + case Node::TYPE_OPERATOR: return static_cast<OperatorNode*>(p_node)->return_cache; + case Node::TYPE_CONTROL_FLOW: ERR_FAIL_V(TYPE_VOID); + case Node::TYPE_MEMBER: return static_cast<MemberNode*>(p_node)->datatype; + } + + return TYPE_VOID; +} + + +ShaderLanguage::Node* ShaderLanguage::validate_function_call(Parser&parser, OperatorNode *p_func) { + + ERR_FAIL_COND_V(p_func->op!=OP_CALL && p_func->op!=OP_CONSTRUCT,NULL); + + + Vector<DataType> args; + + ERR_FAIL_COND_V( p_func->arguments[0]->type!=Node::TYPE_VARIABLE, NULL ); + + String name = static_cast<VariableNode*>(p_func->arguments[0])->name.operator String(); + + bool all_const=true; + for(int i=1;i<p_func->arguments.size();i++) { + if (p_func->arguments[i]->type!=Node::TYPE_CONSTANT) + all_const=false; + args.push_back(compute_node_type(p_func->arguments[i])); + } + + int argcount=args.size(); + + bool found_intrinsic=false; + + if (argcount<=4) { + // test intrinsics + int idx=0; + + while (intrinsic_func_defs[idx].name) { + + if (name==intrinsic_func_defs[idx].name) { + + bool fail=false; + for(int i=0;i<argcount;i++) { + + if (args[i]!=intrinsic_func_defs[idx].args[i]) { + fail=true; + break; + } + } + + if (!fail && argcount<4 && intrinsic_func_defs[idx].args[argcount]!=TYPE_VOID) + fail=true; //make sure the number of arguments matches + + if (!fail) { + p_func->return_cache=intrinsic_func_defs[idx].rettype; + found_intrinsic=true; + break; + + } + + } + + idx++; + } + } + + + if (found_intrinsic) { + + if (p_func->op==OP_CONSTRUCT && all_const) { + + bool all_const=false; + Vector<float> cdata; + for(int i=0;i<argcount;i++) { + + Variant v = static_cast<ConstantNode*>(p_func->arguments[i+1])->value; + switch(v.get_type()) { + + case Variant::REAL: cdata.push_back(v); break; + case Variant::VECTOR2: { Vector2 v2=v; cdata.push_back(v2.x); cdata.push_back(v2.y); } break; + case Variant::VECTOR3: { Vector3 v3=v; cdata.push_back(v3.x); cdata.push_back(v3.y); cdata.push_back(v3.z);} break; + case Variant::PLANE: { Plane v4=v; cdata.push_back(v4.normal.x); cdata.push_back(v4.normal.y); cdata.push_back(v4.normal.z); cdata.push_back(v4.d); } break; + default: ERR_FAIL_V(NULL); + + } + + } + + ConstantNode *cn = parser.create_node<ConstantNode>(p_func->parent); + Variant data; + switch(p_func->return_cache) { + case TYPE_FLOAT: data = cdata[0]; break; + case TYPE_VEC2: data = Vector2(cdata[0],cdata[1]); break; + case TYPE_VEC3: data = Vector3(cdata[0],cdata[1],cdata[2]); break; + case TYPE_VEC4: data = Plane(cdata[0],cdata[1],cdata[2],cdata[3]); break; + } + + cn->datatype=p_func->return_cache; + cn->value=data; + return cn; + + } + return p_func; + } + + // try existing functions.. + + FunctionNode *exclude_function=NULL; //exclude current function (in case inside one) + + + Node *node = p_func; + + while(node->parent) { + + if (node->type==Node::TYPE_FUNCTION) { + + exclude_function = (FunctionNode*)node; + } + + node=node->parent; + } + + ERR_FAIL_COND_V(node->type!=Node::TYPE_PROGRAM,NULL); + ProgramNode *program = (ProgramNode*)node; + + for(int i=0;i<program->functions.size();i++) { + + if (program->functions[i].function==exclude_function) + continue; + + FunctionNode *pfunc = program->functions[i].function; + + if (pfunc->arguments.size()!=args.size()) + continue; + + bool fail=false; + + for(int i=0;i<args.size();i++) { + if (args[i]!=pfunc->arguments[i].type) { + fail=true; + break; + } + } + + if (!fail) { + p_func->return_cache=pfunc->return_type; + return p_func; + } + } + + return NULL; +} + + +ShaderLanguage::Node * ShaderLanguage::validate_operator(Parser& parser,OperatorNode *p_func) { + + int argcount = p_func->arguments.size(); + ERR_FAIL_COND_V(argcount>2,NULL); + + DataType argtype[2]={TYPE_VOID,TYPE_VOID}; + bool all_const=true; + + for(int i=0;i<argcount;i++) { + + argtype[i]=compute_node_type(p_func->arguments[i]); + if (p_func->arguments[i]->type!=Node::TYPE_CONSTANT) + all_const=false; + + } + int idx=0; + + bool valid=false; + while(operator_defs[idx].op!=OP_MAX) { + + if (p_func->op==operator_defs[idx].op) { + + + + if (operator_defs[idx].args[0]==argtype[0] && operator_defs[idx].args[1]==argtype[1]) { + + p_func->return_cache=operator_defs[idx].rettype; + valid=true; + break; + } + } + + idx++; + } + + if (!valid) + return NULL; + +#define _RCO2(m_op,m_vop)\ +case m_op: {\ + ConstantNode *cn = parser.create_node<ConstantNode>(p_func->parent);\ + cn->datatype=p_func->return_cache; \ + Variant::evaluate(m_vop,static_cast<ConstantNode*>(p_func->arguments[0])->value,static_cast<ConstantNode*>(p_func->arguments[1])->value,cn->value,valid);\ + if (!valid)\ + return NULL;\ + return cn;\ +} break; + +#define _RCO1(m_op,m_vop)\ +case m_op: {\ + ConstantNode *cn = parser.create_node<ConstantNode>(p_func->parent);\ + cn->datatype=p_func->return_cache; \ + Variant::evaluate(m_vop,static_cast<ConstantNode*>(p_func->arguments[0])->value,Variant(),cn->value,valid);\ + if (!valid)\ + return NULL;\ + return cn;\ +} break; + + if (all_const) { + //reduce constant operator + switch(p_func->op) { + _RCO2(OP_ADD,Variant::OP_ADD); + _RCO2(OP_SUB,Variant::OP_SUBSTRACT); + _RCO2(OP_MUL,Variant::OP_MULTIPLY); + _RCO2(OP_DIV,Variant::OP_DIVIDE); + _RCO1(OP_NEG,Variant::OP_NEGATE); + _RCO1(OP_NOT,Variant::OP_NOT); + _RCO2(OP_CMP_EQ,Variant::OP_EQUAL); + _RCO2(OP_CMP_NEQ,Variant::OP_NOT_EQUAL); + _RCO2(OP_CMP_LEQ,Variant::OP_LESS_EQUAL); + _RCO2(OP_CMP_GEQ,Variant::OP_GREATER_EQUAL); + _RCO2(OP_CMP_LESS,Variant::OP_LESS); + _RCO2(OP_CMP_GREATER,Variant::OP_GREATER); + _RCO2(OP_CMP_OR,Variant::OP_OR); + _RCO2(OP_CMP_AND,Variant::OP_AND); + default: {} + } + } + + + return p_func; + +} + +bool ShaderLanguage::is_token_operator(TokenType p_type) { + + return (p_type==TK_OP_EQUAL) || + (p_type==TK_OP_NOT_EQUAL) || + (p_type==TK_OP_LESS) || + (p_type==TK_OP_LESS_EQUAL) || + (p_type==TK_OP_GREATER) || + (p_type==TK_OP_GREATER_EQUAL) || + (p_type==TK_OP_AND) || + (p_type==TK_OP_OR) || + (p_type==TK_OP_NOT) || + (p_type==TK_OP_ADD) || + (p_type==TK_OP_SUB) || + (p_type==TK_OP_MUL) || + (p_type==TK_OP_DIV) || + (p_type==TK_OP_NEG) || + (p_type==TK_OP_ASSIGN) || + (p_type==TK_OP_ASSIGN_ADD) || + (p_type==TK_OP_ASSIGN_SUB) || + (p_type==TK_OP_ASSIGN_MUL) || + (p_type==TK_OP_ASSIGN_DIV); + +} +ShaderLanguage::Operator ShaderLanguage::get_token_operator(TokenType p_type) { + + switch(p_type) { + case TK_OP_EQUAL: return OP_CMP_EQ ; + case TK_OP_NOT_EQUAL: return OP_CMP_NEQ; + case TK_OP_LESS: return OP_CMP_LESS ; + case TK_OP_LESS_EQUAL: return OP_CMP_LEQ ; + case TK_OP_GREATER: return OP_CMP_GREATER ; + case TK_OP_GREATER_EQUAL: return OP_CMP_GEQ ; + case TK_OP_AND: return OP_CMP_AND ; + case TK_OP_OR: return OP_CMP_OR ; + case TK_OP_NOT: return OP_NOT ; + case TK_OP_ADD: return OP_ADD ; + case TK_OP_SUB: return OP_SUB ; + case TK_OP_MUL: return OP_MUL ; + case TK_OP_DIV: return OP_DIV ; + case TK_OP_NEG: return OP_NEG ; + case TK_OP_ASSIGN: return OP_ASSIGN ; + case TK_OP_ASSIGN_ADD: return OP_ASSIGN_ADD ; + case TK_OP_ASSIGN_SUB: return OP_ASSIGN_SUB ; + case TK_OP_ASSIGN_MUL: return OP_ASSIGN_MUL ; + case TK_OP_ASSIGN_DIV: return OP_ASSIGN_DIV ; + default: ERR_FAIL_V(OP_MAX); + } + + return OP_MAX; +} + + +Error ShaderLanguage::parse_expression(Parser& parser,Node *p_parent,Node **r_expr) { + + Vector<Node*> expressions; + Vector<TokenType> operators; + + while(true) { + + Node *expr=NULL; + + + if (parser.get_token_type()==TK_PARENTHESIS_OPEN) { + //handle subexpression + parser.advance(); + Error err = parse_expression(parser,p_parent,&expr); + if (err) + return err; + + if (parser.get_token_type()!=TK_PARENTHESIS_CLOSE) { + + parser.set_error("Expected ')' in expression"); + return ERR_PARSE_ERROR; + } + + parser.advance(); + + } else if (parser.get_token_type()==TK_REAL_CONSTANT) { + + + ConstantNode *constant = parser.create_node<ConstantNode>(p_parent); + constant->value=parser.get_token().text.operator String().to_double(); + constant->datatype=TYPE_FLOAT; + expr=constant; + parser.advance(); + } else if (parser.get_token_type()==TK_TRUE) { + //print_line("found true"); + + //handle true constant + ConstantNode *constant = parser.create_node<ConstantNode>(p_parent); + constant->value=true; + constant->datatype=TYPE_BOOL; + expr=constant; + parser.advance(); + } else if (parser.get_token_type()==TK_FALSE) { + + //handle false constant + ConstantNode *constant = parser.create_node<ConstantNode>(p_parent); + constant->value=false; + constant->datatype=TYPE_BOOL; + expr=constant; + parser.advance(); + } else if (parser.get_token_type()==TK_TYPE_VOID) { + + //make sure void is not used in expression + parser.set_error("Void value not allowed in Expression"); + return ERR_PARSE_ERROR; + } else if (parser.get_token_type(1)==TK_PARENTHESIS_OPEN && (is_token_nonvoid_datatype(parser.get_token_type()) || parser.get_token_type()==TK_INDENTIFIER)) { + + + //function or constructor + StringName name; + DataType constructor=TYPE_VOID; + if (is_token_nonvoid_datatype(parser.get_token_type())) { + + constructor=get_token_datatype(parser.get_token_type()); + switch(get_token_datatype(parser.get_token_type())) { + case TYPE_BOOL: name="bool"; break; + case TYPE_FLOAT: name="float"; break; + case TYPE_VEC2: name="vec2"; break; + case TYPE_VEC3: name="vec3"; break; + case TYPE_VEC4: name="vec4"; break; + case TYPE_MAT3: name="mat3"; break; + case TYPE_MAT4: name="mat4"; break; + default: ERR_FAIL_V(ERR_BUG); + } + } else { + + name=parser.get_token().text; + } + + if (!test_existing_identifier(p_parent,name)) { + + parser.set_error("Unknown identifier in expression: "+name); + return ERR_PARSE_ERROR; + } + + parser.advance(2); + + OperatorNode *func = parser.create_node<OperatorNode>(p_parent); + + func->op=constructor!=TYPE_VOID?OP_CONSTRUCT:OP_CALL; + + VariableNode *funcname = parser.create_node<VariableNode>(func); + funcname->name=name; + func->arguments.push_back(funcname); + + //parse parameters + + if (parser.get_token_type()==TK_PARENTHESIS_CLOSE) { + parser.advance(); + } else { + + while(true) { + + + Node *arg=NULL; + Error err = parse_expression(parser,func,&arg); + if (err) + return err; + func->arguments.push_back(arg); + + if (parser.get_token_type()==TK_PARENTHESIS_CLOSE) { + parser.advance(); + break; + + } else if (parser.get_token_type()==TK_COMMA) { + + if (parser.get_token_type(1)==TK_PARENTHESIS_CLOSE) { + + parser.set_error("Expression expected"); + return ERR_PARSE_ERROR; + } + + parser.advance(); + } else { + // something is broken + parser.set_error("Expected ',' or ')'"); + return ERR_PARSE_ERROR; + } + + } + } + + expr=validate_function_call(parser,func); + if (!expr) { + + parser.set_error("Invalid arguments to function/constructor: "+StringName(name)); + return ERR_PARSE_ERROR; + + } + + } else if (parser.get_token_type()==TK_INDENTIFIER) { + //probably variable + + + Node *node =p_parent; + bool existing=false; + DataType datatype; + StringName identifier=parser.get_token().text; + + while(node) { + + if (node->type==Node::TYPE_BLOCK) { + + BlockNode *block = (BlockNode*)node; + + if (block->variables.has(identifier)) { + existing=true; + datatype=block->variables[identifier]; + break; + } + } + + if (node->type==Node::TYPE_FUNCTION) { + + FunctionNode *function=(FunctionNode*)node; + for(int i=0;i<function->arguments.size();i++) { + if (function->arguments[i].name==identifier) { + existing=true; + datatype=function->arguments[i].type; + break; + } + } + + if (existing) + break; + + } + + if (node->type==Node::TYPE_PROGRAM) { + + ProgramNode *program = (ProgramNode*)node; + if (program->builtin_variables.has(identifier)) { + datatype = program->builtin_variables[identifier]; + existing=true; + break; + } + if (program->uniforms.has(identifier)) { + datatype = program->uniforms[identifier].type; + existing=true; + break; + } + + } + + node=node->parent; + } + + if (!existing) { + + parser.set_error("Unexisting identifier in expression: "+identifier); + return ERR_PARSE_ERROR; + + } + + VariableNode *varname = parser.create_node<VariableNode>(p_parent); + varname->name=identifier; + varname->datatype_cache=datatype; + parser.advance(); + expr=varname; + + } else if (parser.get_token_type()==TK_OP_NEG || parser.get_token_type()==TK_OP_NOT) { + + //single prefix operators + TokenType token_type=parser.get_token_type(); + parser.advance(); + Node *subexpr=NULL; + Error err = parse_expression(parser,p_parent,&subexpr); + if (err) + return err; + + OperatorNode *op = parser.create_node<OperatorNode>(p_parent); + switch(token_type) { + case TK_OP_NEG: op->op=OP_NEG; break; + case TK_OP_NOT: op->op=OP_NOT; break; + //case TK_OP_PLUS_PLUS: op->op=OP_PLUS_PLUS; break; + //case TK_OP_MINUS_MINUS: op->op=OP_MINUS_MINUS; break; + default: ERR_FAIL_V(ERR_BUG); + } + + op->arguments.push_back(subexpr); + + expr=validate_operator(parser,op); + + if (!expr) { + + parser.set_error("Invalid argument for negation operator"); + return ERR_PARSE_ERROR; + } + + } else { + print_line("found bug?"); + print_line("misplaced token: "+String(token_names[parser.get_token_type()])); + + parser.set_error("Error parsing expression, misplaced: "+String(token_names[parser.get_token_type()])); + return ERR_PARSE_ERROR; + //nothing + } + + ERR_FAIL_COND_V(!expr,ERR_BUG); + + + /* OK now see what's NEXT to the operator.. */ + /* OK now see what's NEXT to the operator.. */ + /* OK now see what's NEXT to the operator.. */ + + + if (parser.get_token_type()==TK_PERIOD) { + + if (parser.get_token_type(1)!=TK_INDENTIFIER) { + parser.set_error("Expected identifier as member"); + return ERR_PARSE_ERROR; + } + + DataType dt = compute_node_type(expr); + String ident = parser.get_token(1).text; + + bool ok=true; + DataType member_type; + switch(dt) { + case TYPE_VEC2: { + + int l = ident.length(); + if (l==1) { + member_type=TYPE_FLOAT; + } else if (l==2) { + member_type=TYPE_VEC2; + } else { + ok=false; + break; + } + + const CharType *c=ident.ptr(); + for(int i=0;i<l;i++) { + + switch(c[i]) { + case 'r': + case 'g': + case 'x': + case 'y': + break; + default: + ok=false; + break; + } + } + + } break; + case TYPE_VEC3: { + + int l = ident.length(); + if (l==1) { + member_type=TYPE_FLOAT; + } else if (l==2) { + member_type=TYPE_VEC2; + } else if (l==3) { + member_type=TYPE_VEC3; + } else { + ok=false; + break; + } + + const CharType *c=ident.ptr(); + for(int i=0;i<l;i++) { + + switch(c[i]) { + case 'r': + case 'g': + case 'b': + case 'x': + case 'y': + case 'z': + break; + default: + ok=false; + break; + } + } + + } break; + case TYPE_VEC4: { + + int l = ident.length(); + if (l==1) { + member_type=TYPE_FLOAT; + } else if (l==2) { + member_type=TYPE_VEC2; + } else if (l==3) { + member_type=TYPE_VEC3; + } else if (l==4) { + member_type=TYPE_VEC4; + } else { + ok=false; + break; + } + + const CharType *c=ident.ptr(); + for(int i=0;i<l;i++) { + + switch(c[i]) { + case 'r': + case 'g': + case 'b': + case 'a': + case 'x': + case 'y': + case 'z': + case 'w': + break; + default: + ok=false; + break; + } + } + + } break; + case TYPE_MAT3: ok=(ident=="x" || ident=="y" || ident=="z" ); member_type=TYPE_VEC3; break; + case TYPE_MAT4: ok=(ident=="x" || ident=="y" || ident=="z" || ident=="w"); member_type=TYPE_VEC4; break; + default: {} + } + + if (!ok) { + + parser.set_error("Invalid member for expression: ."+ident); + return ERR_PARSE_ERROR; + } + + MemberNode *mn = parser.create_node<MemberNode>(p_parent); + mn->basetype=dt; + mn->datatype=member_type; + mn->name=ident; + mn->owner=expr; + expr=mn; + + parser.advance(2); + //todo + //member (period) has priority over any operator + //creates a subindexing expression in place + + + } else if (parser.get_token_type()==TK_BRACKET_OPEN) { + //todo + //subindexing has priority over any operator + //creates a subindexing expression in place + + + } /*else if (parser.get_token_type()==TK_OP_PLUS_PLUS || parser.get_token_type()==TK_OP_MINUS_MINUS) { + //todo + //inc/dec operators have priority over any operator + //creates a subindexing expression in place + //return OK; //wtfs + + } */ + + + expressions.push_back(expr); + + + if (is_token_operator(parser.get_token_type())) { + + operators.push_back(parser.get_token_type()); + parser.advance(); + } else { + break; + } + } + + ERR_FAIL_COND_V(expressions.size()!=(operators.size()+1),ERR_BUG); + + /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */ + + while(expressions.size()>1) { + + int next_op=-1; + int min_priority=0xFFFFF; + + for(int i=0;i<operators.size();i++) { + + int priority; + switch(operators[i]) { + + case TK_OP_MUL: priority=0; break; + case TK_OP_DIV: priority=0; break; + + case TK_OP_ADD: priority=1; break; + case TK_OP_SUB: priority=1; break; + + // shift left/right =2 + + case TK_OP_LESS: priority=3; break; + case TK_OP_LESS_EQUAL: priority=3; break; + case TK_OP_GREATER: priority=3; break; + case TK_OP_GREATER_EQUAL: priority=3; break; + + case TK_OP_EQUAL: priority=4; break; + case TK_OP_NOT_EQUAL: priority=4; break; + + //bit and =5 + //bit xor =6 + //bit or=7 + + case TK_OP_AND: priority=8; break; + case TK_OP_OR: priority=9; break; + + // ?: = 10 + + case TK_OP_ASSIGN_ADD: priority=11; break; + case TK_OP_ASSIGN_SUB: priority=11; break; + case TK_OP_ASSIGN_MUL: priority=11; break; + case TK_OP_ASSIGN_DIV: priority=11; break; + case TK_OP_ASSIGN: priority=11; break; + + default: ERR_FAIL_V(ERR_BUG); //unexpected operator + + } + + if (priority<min_priority) { + // < is used for left to right (default) + // <= is used for right to left + next_op=i; + min_priority=priority; + } + + } + + ERR_FAIL_COND_V(next_op==-1,ERR_BUG); + + // OK! create operator.. + + OperatorNode *op = parser.create_node<OperatorNode>(p_parent); + op->op=get_token_operator(operators[next_op]); + + op->arguments.push_back(expressions[next_op]); //expression goes as left + op->arguments.push_back(expressions[next_op+1]); //next expression goes as right + + expressions[next_op]=validate_operator(parser,op); + if (!expressions[next_op]) { + + String at; + for(int i=0;i<op->arguments.size();i++) { + if (i>0) + at+=" and "; + at+=get_datatype_name(compute_node_type(op->arguments[i])); + + } + parser.set_error("Invalid arguments to operator "+String(token_names[operators[next_op]])+": "+at); + return ERR_PARSE_ERROR; + } + + + expressions.remove(next_op+1); + operators.remove(next_op); + + } + + *r_expr=expressions[0]; + + return OK; + +/* + TokenType token_type=parser.get_token_type(); + OperatorNode *op = parser.create_node<OperatorNode>(p_parent); + op->op=get_token_operator(parser.get_token_type()); + + op->arguments.push_back(*r_expr); //expression goes as left + parser.advance(); + Node *right_expr=NULL; + Error err = parse_expression(parser,p_parent,&right_expr); + if (err) + return err; + op->arguments.push_back(right_expr); + + if (!validate_operator(op)) { + + parser.set_error("Invalid arguments to operator "+String(token_names[token_type])); + return ERR_PARSE_ERROR; + } + +*/ + +} + +Error ShaderLanguage::parse_variable_declaration(Parser& parser,BlockNode *p_block) { + + bool uniform = parser.get_token(-1).type==TK_UNIFORM; + + DataType type=get_token_datatype(parser.get_token_type(0)); + bool iscolor = parser.get_token_type(0)==TK_TYPE_COLOR; + + if (type==TYPE_VOID) { + + parser.set_error("Cannot Declare a 'void' Variable"); + return ERR_PARSE_ERROR; + } + + if (type==TYPE_TEXTURE && !uniform) { + + parser.set_error("Cannot Declare a Non-Uniform Texture"); + return ERR_PARSE_ERROR; + } + if (type==TYPE_CUBEMAP && !uniform) { + + parser.set_error("Cannot Declare a Non-Uniform Cubemap"); + return ERR_PARSE_ERROR; + } + + + parser.advance(); + int found=0; + + while(true) { + + + if (found && parser.get_token_type()!=TK_COMMA) { + break; + } + + if (parser.get_token_type()!=TK_INDENTIFIER) { + + parser.set_error("Identifier Expected"); + return ERR_PARSE_ERROR; + + } + + StringName name = parser.get_token().text; + + if (test_existing_identifier(p_block,name)) { + parser.set_error("Duplicate Identifier (existing variable/function): "+name); + return ERR_PARSE_ERROR; + } + + found=true; + + parser.advance(); + //see if declaration has an initializer + if (parser.get_token_type()==TK_OP_ASSIGN) { + parser.advance(); + OperatorNode * op = parser.create_node<OperatorNode>(p_block); + VariableNode * var = parser.create_node<VariableNode>(op); + var->name=name; + var->datatype_cache=type; + var->uniform=uniform; + Node *expr; + Error err = parse_expression(parser,p_block,&expr); + + if (err) + return err; + + if (var->uniform) { + + if (expr->type!=Node::TYPE_CONSTANT) { + + parser.set_error("Uniform can only be initialized to a constant."); + return ERR_PARSE_ERROR; + } + + Uniform u; + u.order=parser.program->uniforms.size(); + u.type=type; + u.default_value=static_cast<ConstantNode*>(expr)->value; + if (iscolor && u.default_value.get_type()==Variant::PLANE) { + Color c; + Plane p = u.default_value; + c=Color(p.normal.x,p.normal.y,p.normal.z,p.d); + u.default_value=c; + } + parser.program->uniforms[var->name]=u; + } else { + op->op=OP_ASSIGN; + op->arguments.push_back(var); + op->arguments.push_back(expr); + Node *n=validate_operator(parser,op); + if (!n) { + parser.set_error("Invalid initializer for variable: "+name); + return ERR_PARSE_ERROR; + } + p_block->statements.push_back(n); + } + + } else { + //initialize it EMPTY + + OperatorNode * op = parser.create_node<OperatorNode>(p_block); + VariableNode * var = parser.create_node<VariableNode>(op); + ConstantNode * con = parser.create_node<ConstantNode>(op); + + var->name=name; + var->datatype_cache=type; + var->uniform=uniform; + con->datatype=type; + + switch(type) { + case TYPE_BOOL: con->value=false; break; + case TYPE_FLOAT: con->value=0.0; break; + case TYPE_VEC2: con->value=Vector2(); break; + case TYPE_VEC3: con->value=Vector3(); break; + case TYPE_VEC4: con->value=iscolor?Variant(Color()):Variant(Plane()); break; + case TYPE_MAT3: con->value=Matrix3(); break; + case TYPE_MAT4: con->value=Transform(); break; + case TYPE_TEXTURE: + case TYPE_CUBEMAP: con->value=RID(); break; + default: {} + } + + if (uniform) { + Uniform u; + u.type=type; + u.default_value=con->value; + u.order=parser.program->uniforms.size(); + parser.program->uniforms[var->name]=u; + + } else { + op->op=OP_ASSIGN; + op->arguments.push_back(var); + op->arguments.push_back(con); + p_block->statements.push_back(op); + } + + } + + if (!uniform) + p_block->variables[name]=type; + + } + + if (parser.get_token_type()!=TK_SEMICOLON) { + parser.set_error("Expected ';'"); + return ERR_PARSE_ERROR; + } + + + return OK; + +} + +Error ShaderLanguage::parse_flow_if(Parser& parser,Node *p_parent,Node **r_statement) { + + ControlFlowNode *cf = parser.create_node<ControlFlowNode>(p_parent); + + cf->flow_op=FLOW_OP_IF; + + parser.advance(); + + if (parser.get_token_type()!=TK_PARENTHESIS_OPEN) { + parser.set_error("Expected '(' after 'if'"); + return ERR_PARSE_ERROR; + } + parser.advance(); + + Node *expression=NULL; + Error err = parse_expression(parser,cf,&expression); + if (err) + return err; + + if (compute_node_type(expression)!=TYPE_BOOL) { + + parser.set_error("Expression for 'if' is not boolean"); + return ERR_PARSE_ERROR; + } + + cf->statements.push_back(expression); + + if (parser.get_token_type()!=TK_PARENTHESIS_CLOSE) { + parser.set_error("Expected ')' after expression"); + return ERR_PARSE_ERROR; + } + + parser.advance(); + + Node *substatement=NULL; + err = parse_statement(parser,cf,&substatement); + if (err) + return err; + + + cf->statements.push_back(substatement); + + + + if (parser.get_token_type()==TK_CF_ELSE) { + + parser.advance(); + substatement=NULL; + err = parse_statement(parser,cf,&substatement); + if (err) + return err; + + cf->statements.push_back(substatement); + } + + + + *r_statement=cf; + + return OK; +} + +Error ShaderLanguage::parse_flow_return(Parser& parser,Node *p_parent,Node **r_statement) { + + + FunctionNode *function=NULL; + + Node *parent=p_parent; + + while(parent) { + + if (parent->type==Node::TYPE_FUNCTION) { + + function=(FunctionNode*)parent; + break; + } + + parent=parent->parent; + } + + if (!function) { + + parser.set_error("'return' must be inside a function"); + return ERR_PARSE_ERROR; + } + + ControlFlowNode *cf = parser.create_node<ControlFlowNode>(p_parent); + + cf->flow_op=FLOW_OP_RETURN; + + parser.advance(); + + if (function->return_type!=TYPE_VOID) { + // should expect a return expression. + + Node *expr=NULL; + Error err = parse_expression(parser,cf,&expr); + if (err) + return err; + + if (compute_node_type(expr)!=function->return_type) { + parser.set_error("Invalid type for 'return' expression"); + return ERR_PARSE_ERROR; + } + cf->statements.push_back(expr); + } + + *r_statement=cf; + + + if (parser.get_token_type()!=TK_SEMICOLON) { + parser.set_error("Expected ';'"); + return ERR_PARSE_ERROR; + } + + return OK; +} + +Error ShaderLanguage::parse_statement(Parser& parser,Node *p_parent,Node **r_statement) { + + *r_statement=NULL; + + TokenType token_type = parser.get_token_type(); + + if (token_type==TK_CURLY_BRACKET_OPEN) { + //sub-block + parser.advance(); + BlockNode *block = parser.create_node<BlockNode>(p_parent); + + *r_statement=block; + return parse_block(parser,block); + } else if (token_type==TK_SEMICOLON) { + // empty ; + parser.advance(); + return OK; + } else if (token_type==TK_CF_IF) { + return parse_flow_if(parser,p_parent,r_statement); + + } else if (token_type==TK_CF_RETURN) { + return parse_flow_return(parser,p_parent,r_statement); + } else { + Error err=parse_expression(parser,p_parent,r_statement); + + if (err) + return err; + + if (parser.get_token_type()!=TK_SEMICOLON) { + parser.set_error("Expected ';'"); + return ERR_PARSE_ERROR; + } + + } + + return OK; +} + +Error ShaderLanguage::parse_block(Parser& parser,BlockNode *p_block) { + + while(true) { + + if (parser.is_at_end()) { + if (p_block->parent->type!=Node::TYPE_PROGRAM) { + parser.set_error("Unexpected End of File"); + return ERR_PARSE_ERROR; + } + return OK; //bye + } + + TokenType token_type = parser.get_token_type(); + + if (token_type==TK_CURLY_BRACKET_CLOSE) { + if (p_block->parent->type==Node::TYPE_PROGRAM) { + parser.set_error("Unexpected '}'"); + return ERR_PARSE_ERROR; + } + parser.advance(); + return OK; // exit block + + } else if (token_type==TK_UNIFORM) { + + if (p_block!=parser.program->body) { + + parser.set_error("Uniform only allowed in main program body."); + return ERR_PARSE_ERROR; + } + parser.advance(); + Error err=parse_variable_declaration(parser,p_block); + if (err) + return err; + + } else if (is_token_datatype(token_type)) { + + Error err=OK; + if (parser_is_at_function(parser)) + err = parse_function(parser,p_block); + else { + err = parse_variable_declaration(parser,p_block); + } + + if (err) + return err; + + } else { + // must be a statement + Node *statement=NULL; + + Error err = parse_statement(parser,p_block,&statement); + if (err) + return err; + if (statement) { + p_block->statements.push_back(statement); + } + + } + } + + return OK; +} + + + +Error ShaderLanguage::parse(const Vector<Token>& p_tokens,ShaderType p_type,CompileFunc p_compile_func,void *p_userdata,String *r_error,int *r_err_line,int *r_err_column) { + + + uint64_t t = OS::get_singleton()->get_ticks_usec(); + + Parser parser(p_tokens); + parser.program = parser.create_node<ProgramNode>(NULL); + parser.program->body = parser.create_node<BlockNode>(parser.program); + + + //add builtins + switch(p_type) { + case SHADER_MATERIAL_VERTEX: { + int idx=0; + while (vertex_builtins_defs[idx].name) { + parser.program->builtin_variables[vertex_builtins_defs[idx].name]=vertex_builtins_defs[idx].type; + idx++; + } + } break; + case SHADER_MATERIAL_FRAGMENT: { + int idx=0; + while (fragment_builtins_defs[idx].name) { + parser.program->builtin_variables[fragment_builtins_defs[idx].name]=fragment_builtins_defs[idx].type; + idx++; + } + } break; + case SHADER_POST_PROCESS: { + int idx=0; + while (postprocess_fragment_builtins_defs[idx].name) { + parser.program->builtin_variables[postprocess_fragment_builtins_defs[idx].name]=postprocess_fragment_builtins_defs[idx].type; + idx++; + } + } break; + } + + Error err = parse_block(parser,parser.program->body); + if (err) { + parser.get_error(r_error,r_err_line,r_err_column); + return err; + } + + double tf = (OS::get_singleton()->get_ticks_usec()-t)/1000.0; + //print_line("parse time: "+rtos(tf)); + + t = OS::get_singleton()->get_ticks_usec(); + + if (p_compile_func) + p_compile_func(p_userdata,parser.program); + + tf = (OS::get_singleton()->get_ticks_usec()-t)/1000.0; + //print_line("compile time: "+rtos(tf)); + + //clean up nodes created + while(parser.nodegc.size()) { + + memdelete( parser.nodegc.front()->get() ); + parser.nodegc.pop_front(); + } + return OK; +} + +Error ShaderLanguage::compile(const String& p_code,ShaderType p_type,CompileFunc p_compile_func,void *p_userdata,String *r_error,int *r_err_line,int *r_err_column) { + + *r_error=""; + *r_err_line=0; + *r_err_column=0; + Vector<Token> tokens; + + uint64_t t = OS::get_singleton()->get_ticks_usec(); + + Error err = tokenize(p_code,&tokens,r_error,r_err_line,r_err_column); + + double tf = (OS::get_singleton()->get_ticks_usec()-t)/1000.0; + //print_line("tokenize time: "+rtos(tf)); + + if (err!=OK) { + return err; + } + err = parse(tokens,p_type,p_compile_func,p_userdata,r_error,r_err_line,r_err_column); + if (err!=OK) { + //print_line("LDEBUG: "+lex_debug(p_code)); + return err; + } + return OK; +} + + +void ShaderLanguage::get_keyword_list(ShaderType p_type, List<String> *p_keywords) { + + int idx=0; + + while(intrinsic_func_defs[idx].name) { + + p_keywords->push_back(intrinsic_func_defs[idx].name); + idx++; + } + + switch(p_type) { + case SHADER_MATERIAL_VERTEX: { + idx=0; + while (vertex_builtins_defs[idx].name) { + p_keywords->push_back(vertex_builtins_defs[idx].name); + idx++; + } + } break; + case SHADER_MATERIAL_FRAGMENT: { + idx=0; + while (fragment_builtins_defs[idx].name) { + p_keywords->push_back(fragment_builtins_defs[idx].name); + idx++; + } + } break; + case SHADER_POST_PROCESS: { + idx=0; + while (postprocess_fragment_builtins_defs[idx].name) { + p_keywords->push_back(postprocess_fragment_builtins_defs[idx].name); + idx++; + } + } break; + + } + +} |