summaryrefslogtreecommitdiff
path: root/servers/visual
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2016-10-07 11:31:18 -0300
committerJuan Linietsky <reduzio@gmail.com>2016-10-07 11:31:18 -0300
commit850eaf7ed796d2f2d9a35c6bc4ba9a4e69f5ca1d (patch)
tree052ed86d4a0eafb2373e65b78b14b6eccba0f707 /servers/visual
parentcf5778e51a883936ffc896231da8259e5ebabc0a (diff)
-the new shader language seems to work
-shader editor plugin can edit shaders -code completion in shader editor plugin
Diffstat (limited to 'servers/visual')
-rw-r--r--servers/visual/shader_language.cpp1051
-rw-r--r--servers/visual/shader_language.h88
-rw-r--r--servers/visual/shader_types.cpp99
-rw-r--r--servers/visual/shader_types.h27
4 files changed, 1071 insertions, 194 deletions
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 287293a437..1a9912e3fb 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -44,14 +44,71 @@ static bool _is_hex(CharType c) {
return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F');
}
+
+String ShaderLanguage::get_operator_text(Operator p_op) {
+
+ static const char* op_names[OP_MAX]={"==",
+ "!=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "&&",
+ "||",
+ "!",
+ "-",
+ "+",
+ "-",
+ "*",
+ "/",
+ "%",
+ "<<",
+ ">>",
+ "=",
+ "+=",
+ "-=",
+ "*=",
+ "/=",
+ "%=",
+ "<<=",
+ ">>=",
+ "&=",
+ "|=",
+ "^=",
+ "&",
+ "|",
+ "^",
+ "~",
+ "++"
+ "--",
+ "()",
+ "construct"};
+
+ return op_names[p_op];
+
+}
+
+
const char * ShaderLanguage::token_names[TK_MAX]={
"EMPTY",
"IDENTIFIER",
"TRUE",
"FALSE",
"REAL_CONSTANT",
+ "INT_CONSTANT",
"TYPE_VOID",
"TYPE_BOOL",
+ "TYPE_BVEC2",
+ "TYPE_BVEC3",
+ "TYPE_BVEC4",
+ "TYPE_INT",
+ "TYPE_IVEC2",
+ "TYPE_IVEC3",
+ "TYPE_IVEC4",
+ "TYPE_UINT",
+ "TYPE_UVEC2",
+ "TYPE_UVEC3",
+ "TYPE_UVEC4",
"TYPE_FLOAT",
"TYPE_VEC2",
"TYPE_VEC3",
@@ -59,9 +116,13 @@ const char * ShaderLanguage::token_names[TK_MAX]={
"TYPE_MAT2",
"TYPE_MAT3",
"TYPE_MAT4",
- "TYPE_TEXTURE",
- "TYPE_CUBEMAP",
- "TYPE_COLOR",
+ "TYPE_SAMPLER2D",
+ "TYPE_ISAMPLER2D",
+ "TYPE_USAMPLER2D",
+ "TYPE_SAMPLERCUBE",
+ "PRECISION_LOW",
+ "PRECISION_MID",
+ "PRECISION_HIGH",
"OP_EQUAL",
"OP_NOT_EQUAL",
"OP_LESS",
@@ -75,14 +136,35 @@ const char * ShaderLanguage::token_names[TK_MAX]={
"OP_SUB",
"OP_MUL",
"OP_DIV",
- "OP_NEG",
+ "OP_MOD",
+ "OP_SHIFT_LEFT",
+ "OP_SHIFT_RIGHT",
"OP_ASSIGN",
"OP_ASSIGN_ADD",
"OP_ASSIGN_SUB",
"OP_ASSIGN_MUL",
"OP_ASSIGN_DIV",
+ "OP_ASSIGN_MOD",
+ "OP_ASSIGN_SHIFT_LEFT",
+ "OP_ASSIGN_SHIFT_RIGHT",
+ "OP_ASSIGN_BIT_AND",
+ "OP_ASSIGN_BIT_OR",
+ "OP_ASSIGN_BIT_XOR",
+ "OP_BIT_AND",
+ "OP_BIT_OR",
+ "OP_BIT_XOR",
+ "OP_BIT_INVERT",
+ "OP_INCREMENT",
+ "OP_DECREMENT",
"CF_IF",
"CF_ELSE",
+ "CF_FOR",
+ "CF_WHILE",
+ "CF_DO",
+ "CF_SWITCH",
+ "CF_CASE",
+ "CF_BREAK",
+ "CF_CONTINUE",
"CF_RETURN",
"BRACKET_OPEN",
"BRACKET_CLOSE",
@@ -90,11 +172,23 @@ const char * ShaderLanguage::token_names[TK_MAX]={
"CURLY_BRACKET_CLOSE",
"PARENTHESIS_OPEN",
"PARENTHESIS_CLOSE",
+ "QUESTION",
"COMMA",
+ "COLON",
"SEMICOLON",
"PERIOD",
"UNIFORM",
+ "VARYING",
+ "RENDER_MODE",
+ "HINT_WHITE_TEXTURE",
+ "HINT_BLACK_TEXTURE",
+ "HINT_NORMAL_TEXTURE",
+ "HINT_ALBEDO_TEXTURE",
+ "HINT_COLOR",
+ "HINT_RANGE",
+ "CURSOR",
"ERROR",
+ "EOF",
};
String ShaderLanguage::get_token_text(Token p_token) {
@@ -104,6 +198,8 @@ String ShaderLanguage::get_token_text(Token p_token) {
name+="("+rtos(p_token.constant)+")";
} else if (p_token.type==TK_IDENTIFIER) {
name+="("+String(p_token.text)+")";
+ } else if (p_token.type==TK_ERROR) {
+ name+="("+String(p_token.text)+")";
}
return name;
@@ -115,18 +211,79 @@ ShaderLanguage::Token ShaderLanguage::_make_token(TokenType p_type,const StringN
tk.type=p_type;
tk.text=p_text;
tk.line=tk_line;
+ if (tk.type==TK_ERROR) {
+ _set_error(p_text);
+ }
return tk;
}
+const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[]={
+ {TK_TRUE,"true"},
+ {TK_FALSE,"false"},
+ {TK_TYPE_VOID,"void"},
+ {TK_TYPE_BOOL,"bool"},
+ {TK_TYPE_BVEC2,"bvec2"},
+ {TK_TYPE_BVEC3,"bvec3"},
+ {TK_TYPE_BVEC4,"bvec4"},
+ {TK_TYPE_INT,"int"},
+ {TK_TYPE_IVEC2,"ivec2"},
+ {TK_TYPE_IVEC3,"ivec3"},
+ {TK_TYPE_IVEC4,"ivec4"},
+ {TK_TYPE_UINT,"uint"},
+ {TK_TYPE_UVEC2,"uvec2"},
+ {TK_TYPE_UVEC3,"uvec3"},
+ {TK_TYPE_UVEC4,"uvec4"},
+ {TK_TYPE_FLOAT,"float"},
+ {TK_TYPE_VEC2,"vec2"},
+ {TK_TYPE_VEC3,"vec3"},
+ {TK_TYPE_VEC4,"vec4"},
+ {TK_TYPE_MAT2,"mat2"},
+ {TK_TYPE_MAT3,"mat3"},
+ {TK_TYPE_MAT4,"mat4"},
+ {TK_TYPE_SAMPLER2D,"sampler2D"},
+ {TK_TYPE_ISAMPLER2D,"isampler2D"},
+ {TK_TYPE_USAMPLER2D,"usampler2D"},
+ {TK_TYPE_SAMPLERCUBE,"samplerCube"},
+ {TK_PRECISION_LOW,"lowp"},
+ {TK_PRECISION_MID,"mediump"},
+ {TK_PRECISION_HIGH,"highp"},
+ {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_CASE,"case"},
+ {TK_CF_BREAK,"break"},
+ {TK_CF_CONTINUE,"continue"},
+ {TK_CF_RETURN,"return"},
+ {TK_UNIFORM,"uniform"},
+ {TK_VARYING,"varying"},
+ {TK_RENDER_MODE,"render_mode"},
+ {TK_HINT_WHITE_TEXTURE,"white"},
+ {TK_HINT_BLACK_TEXTURE,"black"},
+ {TK_HINT_NORMAL_TEXTURE,"normal"},
+ {TK_HINT_ALBEDO_TEXTURE,"albedo"},
+ {TK_HINT_COLOR,"color"},
+ {TK_HINT_RANGE,"hint_range"},
+
+ {TK_ERROR,NULL}
+};
+
+
ShaderLanguage::Token ShaderLanguage::_get_token() {
-#define GETCHAR(m_idx) ((char_idx<code.length())?code[char_idx]:CharType(0))
+#define GETCHAR(m_idx) (((char_idx+m_idx)<code.length())?code[char_idx+m_idx]:CharType(0))
while(true) {
char_idx++;
switch(GETCHAR(-1)) {
+ case 0:
+ return _make_token(TK_EOF);
+ case 0xFFFF:
+ return _make_token(TK_CURSOR); //for completion
case '\t':
case '\r':
case ' ':
@@ -146,7 +303,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
} if (GETCHAR(0)=='*' && GETCHAR(1)=='/') {
char_idx+=2;
break;
- } if (GETCHAR(r_chars+1)=='\n') {
+ } if (GETCHAR(0)=='\n') {
tk_line++;
}
@@ -373,7 +530,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
if (!_is_number(str[str.length()-1]))
return _make_token(TK_ERROR,"Invalid numeric constant");
- char_idx+=str.length()-1;
+ char_idx+=str.length();
Token tk;
if (period_found || minus_exponent_found)
tk.type=TK_REAL_CONSTANT;
@@ -393,82 +550,29 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
if (GETCHAR(0)=='.') {
//parse period
+ char_idx++;
return _make_token(TK_PERIOD);
}
if (_is_text_char(GETCHAR(0))) {
// parse identifier
String str;
- str+=CharType(GETCHAR(0));
+ while(_is_text_char(GETCHAR(0))) {
- while(_is_text_char(GETCHAR(1))) {
-
- str+=CharType(GETCHAR(1));
+ str+=CharType(GETCHAR(0));
char_idx++;
}
//see if keyword
//should be converted to a static map
- 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_BVEC2,"bvec2"},
- {TK_TYPE_BVEC3,"bvec3"},
- {TK_TYPE_BVEC4,"bvec4"},
- {TK_TYPE_INT,"int"},
- {TK_TYPE_IVEC2,"ivec2"},
- {TK_TYPE_IVEC3,"ivec3"},
- {TK_TYPE_IVEC4,"ivec4"},
- {TK_TYPE_UINT,"uint"},
- {TK_TYPE_UVEC2,"uvec2"},
- {TK_TYPE_UVEC3,"uvec3"},
- {TK_TYPE_UVEC4,"uvec4"},
- {TK_TYPE_FLOAT,"float"},
- {TK_TYPE_VEC2,"vec2"},
- {TK_TYPE_VEC3,"vec3"},
- {TK_TYPE_VEC4,"vec4"},
- {TK_TYPE_MAT2,"mat2"},
- {TK_TYPE_MAT3,"mat3"},
- {TK_TYPE_MAT4,"mat4"},
- {TK_TYPE_SAMPLER2D,"sampler2D"},
- {TK_TYPE_ISAMPLER2D,"isampler2D"},
- {TK_TYPE_USAMPLER2D,"usampler2D"},
- {TK_TYPE_SAMPLERCUBE,"samplerCube"},
- {TK_PRECISION_LOW,"lowp"},
- {TK_PRECISION_MID,"mediump"},
- {TK_PRECISION_HIGH,"highp"},
- {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_CASE,"case"},
- {TK_CF_BREAK,"break"},
- {TK_CF_CONTINUE,"continue"},
- {TK_CF_RETURN,"return"},
- {TK_UNIFORM,"uniform"},
- {TK_VARYING,"varying"},
- {TK_RENDER_MODE,"render_mode"},
- {TK_HINT_WHITE_TEXTURE,"hint_white"},
- {TK_HINT_BLACK_TEXTURE,"hint_black"},
- {TK_HINT_NORMAL_TEXTURE,"hint_normal"},
- {TK_HINT_RANGE,"hint_range"},
-
- {TK_ERROR,NULL}
- };
-
int idx=0;
while(keyword_list[idx].text) {
if (str==keyword_list[idx].text) {
- _make_token(keyword_list[idx].token);
+ return _make_token(keyword_list[idx].token);
}
idx++;
}
@@ -490,22 +594,22 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
}
-String ShaderLanguage::lex_debug(const String& p_code) {
+String ShaderLanguage::token_debug(const String& p_code) {
-#if 0
- 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";
+ clear();
+
+ code=p_code;
+
+ String output;
+
+ Token tk = _get_token();
+ while(tk.type!=TK_EOF && tk.type!=TK_ERROR) {
+ print_line(get_token_text(tk));
+ output+=itos(tk_line)+": "+get_token_text(tk)+"\n";
+ tk = _get_token();
}
- return ret;
-#endif
- return String();
+ return output;
}
@@ -585,7 +689,7 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
case TYPE_FLOAT: return "float";
case TYPE_VEC2: return "vec2";
case TYPE_VEC3: return "vec3";
- case TYPE_VEC4: return "vec5";
+ case TYPE_VEC4: return "vec4";
case TYPE_MAT2: return "mat2";
case TYPE_MAT3: return "mat3";
case TYPE_MAT4: return "mat4";
@@ -608,7 +712,12 @@ bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
void ShaderLanguage::clear() {
- tk_line=0;
+ completion_type=COMPLETION_NONE;
+ completion_block=NULL;
+ completion_function=StringName();
+
+ error_line=0;
+ tk_line=1;
char_idx=0;
error_set=false;
error_str="";
@@ -1064,7 +1173,7 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op,DataType *r_ret_type)
}
-const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
+const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[]={
//constructors
{"bool",TYPE_BOOL,{TYPE_BOOL,TYPE_VOID}},
{"bvec2",TYPE_BVEC2,{TYPE_BOOL,TYPE_VOID}},
@@ -1223,7 +1332,7 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"bvec4",TYPE_BVEC4,{TYPE_UVEC4,TYPE_VOID}},
{"bvec4",TYPE_BVEC4,{TYPE_VEC4,TYPE_VOID}},
- //intrinsics - trigonometry
+ //builtins - trigonometry
{"sin",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
{"cos",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
{"tan",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
@@ -1234,7 +1343,7 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"sinh",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
{"cosh",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
{"tanh",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
- //intrinsics - exponential
+ //builtins - 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}},
@@ -1254,7 +1363,7 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"sqrt",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}},
{"sqrt",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}},
{"sqrt",TYPE_VEC4,{TYPE_VEC4,TYPE_VOID}},
- //intrinsics - common
+ //builtins - common
{"abs",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
{"abs",TYPE_VEC2,{TYPE_VEC2,TYPE_VOID}},
{"abs",TYPE_VEC3,{TYPE_VEC3,TYPE_VOID}},
@@ -1373,12 +1482,20 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"clamp",TYPE_UVEC4,{TYPE_UVEC4,TYPE_UINT,TYPE_UINT,TYPE_VOID}},
{"mix",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
+ {"mix",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_BOOL,TYPE_VOID}},
{"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}},
+ {"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_BOOL,TYPE_VOID}},
+ {"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_BVEC2,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_BOOL,TYPE_VOID}},
+ {"mix",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_BVEC3,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_BOOL,TYPE_VOID}},
+ {"mix",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_BVEC3,TYPE_VOID}},
{"mix",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}},
+
{"step",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
{"step",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
{"step",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VOID}},
@@ -1424,7 +1541,7 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"uintBitsToFloat",TYPE_VEC3,{TYPE_UVEC3,TYPE_VOID}},
{"uintBitsToFloat",TYPE_VEC4,{TYPE_UVEC4,TYPE_VOID}},
- //intrinsics - geometric
+ //builtins - geometric
{"length",TYPE_FLOAT,{TYPE_VEC2,TYPE_VOID}},
{"length",TYPE_FLOAT,{TYPE_VEC3,TYPE_VOID}},
{"length",TYPE_FLOAT,{TYPE_VEC4,TYPE_VOID}},
@@ -1558,7 +1675,7 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
{"not",TYPE_BOOL,{TYPE_BVEC3,TYPE_VOID}},
{"not",TYPE_BOOL,{TYPE_BVEC4,TYPE_VOID}},
- //intrinsics - texture
+ //builtins - texture
{"textureSize",TYPE_VEC2,{TYPE_SAMPLER2D,TYPE_INT,TYPE_VOID}},
{"textureSize",TYPE_VEC2,{TYPE_ISAMPLER2D,TYPE_INT,TYPE_VOID}},
{"textureSize",TYPE_VEC2,{TYPE_USAMPLER2D,TYPE_INT,TYPE_VOID}},
@@ -1664,32 +1781,36 @@ bool ShaderLanguage::_validate_function_call(BlockNode* p_block, OperatorNode *p
int argcount=args.size();
- bool found_intrinsic=false;
+ bool failed_builtin=false;
+
if (argcount<=4) {
- // test intrinsics
+ // test builtins
int idx=0;
- while (intrinsic_func_defs[idx].name) {
+ while (builtin_func_defs[idx].name) {
- if (name==intrinsic_func_defs[idx].name) {
+ if (name==builtin_func_defs[idx].name) {
+ failed_builtin=true;
bool fail=false;
for(int i=0;i<argcount;i++) {
- if (args[i]!=intrinsic_func_defs[idx].args[i]) {
+ if (get_scalar_type(args[i])==args[i] && p_func->arguments[i+1]->type==Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode*>(p_func->arguments[i+1]),builtin_func_defs[idx].args[i])) {
+ //all good
+ } else if (args[i]!=builtin_func_defs[idx].args[i]) {
fail=true;
break;
}
}
- if (!fail && argcount<4 && intrinsic_func_defs[idx].args[argcount]!=TYPE_VOID)
+ if (!fail && argcount<4 && builtin_func_defs[idx].args[argcount]!=TYPE_VOID)
fail=true; //make sure the number of arguments matches
if (!fail) {
- found_intrinsic=true;
+
if (r_ret_type)
- *r_ret_type=intrinsic_func_defs[idx].rettype;
+ *r_ret_type=builtin_func_defs[idx].rettype;
return true;
}
@@ -1700,8 +1821,24 @@ bool ShaderLanguage::_validate_function_call(BlockNode* p_block, OperatorNode *p
}
}
+ if (failed_builtin) {
+ String err ="Invalid arguments for built-in function: "+String(name)+"(";
+ for(int i=0;i<argcount;i++) {
+ if (i>0)
+ err+=",";
+
+ if (p_func->arguments[i+1]->type==Node::TYPE_CONSTANT && p_func->arguments[i+1]->get_datatype()==TYPE_INT && static_cast<ConstantNode*>(p_func->arguments[i+1])->values[0].sint<0) {
+ err+="-";
+ }
+ err+=get_datatype_name(args[i]);
+ }
+ err+=")";
+ _set_error(err);
+ return false;
+ }
+
#if 0
- if (found_intrinsic) {
+ if (found_builtin) {
if (p_func->op==OP_CONSTRUCT && all_const) {
@@ -1769,22 +1906,22 @@ bool ShaderLanguage::_validate_function_call(BlockNode* p_block, OperatorNode *p
block=block->parent_block;
}
+ if (name==exclude_function) {
+ _set_error("Recursion is not allowed");
+ return false;
+ }
for(int i=0;i<shader->functions.size();i++) {
- if (shader->functions[i].name==exclude_function) {
- _set_error("Recursion is not allowed");
- return false;
- }
+
+ if (name != shader->functions[i].name)
+ continue;
if (!shader->functions[i].callable) {
_set_error("Function '"+String(name)+" can't be called from source code.");
return false;
}
- if (name != shader->functions[i].name)
- continue;
-
FunctionNode *pfunc = shader->functions[i].function;
@@ -1795,7 +1932,10 @@ bool ShaderLanguage::_validate_function_call(BlockNode* p_block, OperatorNode *p
for(int i=0;i<args.size();i++) {
- if (args[i]!=pfunc->arguments[i].type) {
+
+ if (get_scalar_type(args[i])==args[i] && p_func->arguments[i+1]->type==Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode*>(p_func->arguments[i+1]),pfunc->arguments[i].type)) {
+ //all good
+ } else if (args[i]!=pfunc->arguments[i].type) {
fail=true;
break;
}
@@ -1811,35 +1951,57 @@ bool ShaderLanguage::_validate_function_call(BlockNode* p_block, OperatorNode *p
}
-bool ShaderLanguage::_parse_function_arguments(BlockNode* p_block,const Map<StringName,DataType> &p_builtin_types,OperatorNode* p_func) {
+bool ShaderLanguage::_parse_function_arguments(BlockNode* p_block,const Map<StringName,DataType> &p_builtin_types,OperatorNode* p_func,int *r_complete_arg) {
+ TkPos pos = _get_tkpos();
Token tk = _get_token();
+ if (tk.type==TK_PARENTHESIS_CLOSE) {
+ return true;
+ }
+
+ _set_tkpos(pos);;
+
while(true) {
- if (tk.type==TK_PARENTHESIS_CLOSE) {
- return true;
+
+ if (r_complete_arg) {
+ pos = _get_tkpos();
+ tk = _get_token();
+
+ if (tk.type==TK_CURSOR) {
+
+ *r_complete_arg=p_func->arguments.size()-1;
+ } else {
+
+ _set_tkpos(pos);
+ }
}
- Node *arg= _parse_expression(p_block,p_builtin_types);
- if (!arg)
+ Node *arg= _parse_and_reduce_expression(p_block,p_builtin_types);
+
+ if (!arg) {
+
return false;
+ }
+
p_func->arguments.push_back(arg);
tk = _get_token();
+
if (tk.type==TK_PARENTHESIS_CLOSE) {
- //none
- } else if (tk.type==TK_COMMA) {
- tk = _get_token(); //next
- } else {
+
+ return true;
+ } else if (tk.type!=TK_COMMA) {
// something is broken
_set_error("Expected ',' or ')' after argument");
return false;
}
+
}
return true;
@@ -1886,6 +2048,149 @@ bool ShaderLanguage::is_token_operator(TokenType p_type) {
}
+bool ShaderLanguage::convert_constant(ConstantNode* p_constant, DataType p_to_type,ConstantNode::Value *p_value) {
+
+ if (p_constant->datatype==p_to_type) {
+ if (p_value) {
+ for(int i=0;i<p_constant->values.size();i++) {
+ p_value[i]=p_constant->values[i];
+ }
+ }
+ return true;
+ } else if (p_constant->datatype==TYPE_INT && p_to_type==TYPE_FLOAT) {
+
+ if (p_value) {
+ p_value->real=p_constant->values[0].sint;
+ }
+ return true;
+ } else if (p_constant->datatype==TYPE_UINT && p_to_type==TYPE_FLOAT) {
+
+ if (p_value) {
+ p_value->real=p_constant->values[0].uint;
+ }
+ return true;
+ } else if (p_constant->datatype==TYPE_INT && p_to_type==TYPE_UINT) {
+ if (p_constant->values[0].sint<0) {
+ return false;
+ }
+ if (p_value) {
+ p_value->uint=p_constant->values[0].sint;
+ }
+ return true;
+ } else if (p_constant->datatype==TYPE_UINT && p_to_type==TYPE_INT) {
+
+ if (p_constant->values[0].uint>0x7FFFFFFF) {
+ return false;
+ }
+ if (p_value) {
+ p_value->sint=p_constant->values[0].uint;
+ }
+ return true;
+ } else
+ return false;
+
+}
+
+bool ShaderLanguage::is_scalar_type(DataType p_type) {
+
+ return p_type==TYPE_BOOL || p_type==TYPE_INT || p_type==TYPE_UINT || p_type==TYPE_FLOAT;
+}
+
+void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
+
+ Set<String> kws;
+
+ int idx=0;
+
+ while(keyword_list[idx].text) {
+
+ kws.insert(keyword_list[idx].text);
+ idx++;
+ }
+
+ idx=0;
+
+ while (builtin_func_defs[idx].name) {
+
+ kws.insert(builtin_func_defs[idx].name);
+
+ idx++;
+ }
+
+ for(Set<String>::Element *E=kws.front();E;E=E->next()) {
+ r_keywords->push_back(E->get());
+ }
+}
+
+ShaderLanguage::DataType ShaderLanguage::get_scalar_type(DataType p_type) {
+
+ static const DataType scalar_types[]={
+ TYPE_VOID,
+ TYPE_BOOL,
+ TYPE_BOOL,
+ TYPE_BOOL,
+ TYPE_BOOL,
+ TYPE_INT,
+ TYPE_INT,
+ TYPE_INT,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_UINT,
+ TYPE_UINT,
+ TYPE_UINT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_FLOAT,
+ };
+
+ return scalar_types[p_type];
+}
+
+
+bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block,CompletionType p_type,StringName& identifier) {
+
+ identifier=StringName();
+
+ TkPos pos;
+
+ Token tk = _get_token();
+
+ if (tk.type==TK_IDENTIFIER) {
+ identifier=tk.text;
+ pos = _get_tkpos();
+ tk = _get_token();
+ }
+
+ if (tk.type==TK_CURSOR) {
+
+ completion_type=p_type;
+ completion_line=tk_line;
+ completion_block=p_block;
+
+ pos = _get_tkpos();
+ tk = _get_token();
+
+ if (tk.type==TK_IDENTIFIER) {
+ identifier=identifier.operator String() + tk.text.operator String();
+ } else {
+ _set_tkpos(pos);
+ }
+ return true;
+ } else if (identifier!=StringName()){
+ _set_tkpos(pos);
+ }
+
+ return false;
+}
+
ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const Map<StringName,DataType> &p_builtin_types) {
@@ -1896,14 +2201,17 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
while(true) {
Node *expr=NULL;
- int pos = char_idx;
+ TkPos prepos = _get_tkpos();
Token tk = _get_token();
+ TkPos pos = _get_tkpos();
+
+ print_line("in expr: "+get_token_text(tk));
if (tk.type==TK_PARENTHESIS_OPEN) {
//handle subexpression
- expr = _parse_expression(p_block,p_builtin_types);
+ expr = _parse_and_reduce_expression(p_block,p_builtin_types);
if (!expr)
return NULL;
@@ -1919,15 +2227,19 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
ConstantNode *constant = alloc_node<ConstantNode>();
- constant->value=tk.constant;
+ ConstantNode::Value v;
+ v.real=tk.constant;
+ constant->values.push_back(v);
constant->datatype=TYPE_FLOAT;
expr=constant;
- } else if (tk.type==TK_REAL_CONSTANT) {
+ } else if (tk.type==TK_INT_CONSTANT) {
ConstantNode *constant = alloc_node<ConstantNode>();
- constant->value=int(tk.constant);
+ ConstantNode::Value v;
+ v.sint=tk.constant;
+ constant->values.push_back(v);
constant->datatype=TYPE_INT;
expr=constant;
@@ -1936,7 +2248,9 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
//handle true constant
ConstantNode *constant = alloc_node<ConstantNode>();
- constant->value=true;
+ ConstantNode::Value v;
+ v.boolean=true;
+ constant->values.push_back(v);
constant->datatype=TYPE_BOOL;
expr=constant;
@@ -1944,7 +2258,9 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
//handle false constant
ConstantNode *constant = alloc_node<ConstantNode>();
- constant->value=false;
+ ConstantNode::Value v;
+ v.boolean=false;
+ constant->values.push_back(v);
constant->datatype=TYPE_BOOL;
expr=constant;
@@ -1953,9 +2269,11 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
//make sure void is not used in expression
_set_error("Void value not allowed in Expression");
return NULL;
- } else if (is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type)) {
+ } else if (is_token_nonvoid_datatype(tk.type)) {
//basic type constructor
+ print_line("parse constructor");
+
OperatorNode *func = alloc_node<OperatorNode>();
func->op=OP_CONSTRUCT;
@@ -1976,9 +2294,20 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
return NULL;
}
- if (!_parse_function_arguments(p_block,p_builtin_types,func))
- return NULL;
+ int carg=-1;
+ bool ok = _parse_function_arguments(p_block,p_builtin_types,func,&carg);
+
+ if (carg>=0) {
+ completion_type=COMPLETION_CALL_ARGUMENTS;
+ completion_line=tk_line;
+ completion_block=p_block;
+ completion_function=funcname->name;
+ completion_argument=carg;
+ }
+
+ if (!ok)
+ return NULL;
if (!_validate_function_call(p_block,func,&func->return_cache)) {
_set_error("No matching constructor found for: '"+String(funcname->name)+"'");
@@ -1986,16 +2315,22 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
}
//validate_Function_call()
- expr=func;
+ expr=_reduce_expression(p_block,func);
} else if (tk.type==TK_IDENTIFIER) {
+ _set_tkpos(prepos);
+
+ StringName identifier;
+
+ _get_completable_identifier(p_block,COMPLETION_IDENTIFIER,identifier);
+
tk=_get_token();
if (tk.type==TK_PARENTHESIS_OPEN) {
//a function
- StringName name = tk.text;
+ StringName name = identifier;
OperatorNode *func = alloc_node<OperatorNode>();
func->op=OP_CALL;
@@ -2003,10 +2338,23 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
funcname->name=name;
func->arguments.push_back(funcname);
- if (!_parse_function_arguments(p_block,p_builtin_types,func))
- return NULL;
+ int carg=-1;
+
+ bool ok =_parse_function_arguments(p_block,p_builtin_types,func,&carg);
+
+ if (carg>=0) {
+ completion_type=COMPLETION_CALL_ARGUMENTS;
+ completion_line=tk_line;
+ completion_block=p_block;
+ completion_function=funcname->name;
+ completion_argument=carg;
+ }
+
+ if (!ok)
+ return NULL;
+
if (!_validate_function_call(p_block,func,&func->return_cache)) {
_set_error("No matching function found for: '"+String(funcname->name)+"'");
return NULL;
@@ -2016,9 +2364,8 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
} else {
//an identifier
- char_idx=pos; //rollback
- StringName identifier = tk.text;
+ _set_tkpos(pos);
DataType data_type;
IdentifierType ident_type;
@@ -2044,7 +2391,7 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
} else if (tk.type==TK_OP_ADD) {
continue; //this one does nothing
- } if (tk.type==TK_OP_SUB || tk.type==TK_OP_NOT || tk.type==TK_OP_BIT_INVERT || tk.type==TK_OP_INCREMENT || tk.type==TK_OP_DECREMENT) {
+ } else if (tk.type==TK_OP_SUB || tk.type==TK_OP_NOT || tk.type==TK_OP_BIT_INVERT || tk.type==TK_OP_INCREMENT || tk.type==TK_OP_DECREMENT) {
Expression e;
@@ -2077,19 +2424,23 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
/* OK now see what's NEXT to the operator.. */
while(true) {
- int pos = char_idx;
+ TkPos pos = _get_tkpos();
tk=_get_token();
if (tk.type==TK_PERIOD) {
- tk=_get_token();
- if (tk.type!=TK_IDENTIFIER) {
+ StringName identifier;
+ if (_get_completable_identifier(p_block,COMPLETION_INDEX,identifier)) {
+ completion_base=expr->get_datatype();
+ }
+
+ if (identifier==StringName()) {
_set_error("Expected identifier as member");
return NULL;
}
DataType dt = expr->get_datatype();
- String ident = tk.text;
+ String ident = identifier;
bool ok=true;
DataType member_type;
@@ -2242,7 +2593,8 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
}
expr=op;
} else {
- char_idx=pos; //rollback
+
+ _set_tkpos(pos);
break;
}
}
@@ -2252,7 +2604,7 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
e.node=expr;
expression.push_back(e);
- pos = char_idx;
+ pos = _get_tkpos();
tk = _get_token();
if (is_token_operator(tk.type)) {
@@ -2297,12 +2649,12 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
_set_error("Invalid token for operator: "+get_token_text(tk));
return NULL;
}
- } break;
+ }
expression.push_back(o);
} else {
- char_idx=pos; //something else, so rollback and end
+ _set_tkpos(pos); //something else, so rollback and end
break;
}
}
@@ -2419,7 +2771,7 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
at+=get_datatype_name(op->arguments[i]->get_datatype());
}
- _set_error("Invalid argument to unary operator: "+at);
+ _set_error("Invalid arguments to unary operator '"+get_operator_text(op->op)+"' :" +at);
return NULL;
}
expression.remove(i+1);
@@ -2506,7 +2858,7 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
at+=get_datatype_name(op->arguments[i]->get_datatype());
}
- _set_error("Invalid arguments to operator: "+at);
+ _set_error("Invalid arguments to operator '"+get_operator_text(op->op)+"' :" +at);
return NULL;
}
@@ -2530,45 +2882,88 @@ ShaderLanguage::Node* ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
if (op->op==OP_CONSTRUCT) {
+
ERR_FAIL_COND_V(op->arguments[0]->type!=Node::TYPE_VARIABLE,p_node);
VariableNode *vn = static_cast<VariableNode*>(op->arguments[0]);
- StringName name=vn->name;
+ // StringName name=vn->name;
+
+ DataType base=get_scalar_type(op->get_datatype());
+
+ Vector<ConstantNode::Value> values;
+
- if (name=="vec2" || name=="vec3" || name=="vec4") {
- Vector<Variant> values;
+ for(int i=1;i<op->arguments.size();i++) {
- for(int i=1;i<op->arguments.size();i++) {
- op->arguments[i]=_reduce_expression(p_block,op->arguments[i]);
- if (op->arguments[i]->type==Node::TYPE_CONSTANT) {
- ConstantNode *cn = static_cast<ConstantNode*>(op->arguments[i]);
- values.push_back(cn->value);
+ op->arguments[i]=_reduce_expression(p_block,op->arguments[i]);
+ if (op->arguments[i]->type==Node::TYPE_CONSTANT) {
+ ConstantNode *cn = static_cast<ConstantNode*>(op->arguments[i]);
+ if (get_scalar_type(cn->datatype)==base) {
+
+ for(int j=0;j<cn->values.size();j++) {
+ values.push_back(cn->values[j]);
+ }
+ } else if (get_scalar_type(cn->datatype)==cn->datatype) {
+
+ ConstantNode::Value v;
+ if (!convert_constant(cn,base,&v)) {
+ return p_node;
+ }
+ values.push_back(v);
} else {
- return p_node; //do not bother, not reducible
+ return p_node;
}
+
+ } else {
+ return p_node;
}
+ }
- ConstantNode *cn=alloc_node<ConstantNode>();
- if (name=="vec2") {
- cn->datatype=TYPE_VEC2;
- cn->value=Vector2(values[0],values[1]);
- } else if (name=="vec3") {
- cn->datatype=TYPE_VEC3;
- cn->value=Vector3(values[0],values[1],values[2]);
- } else if (name=="vec4") {
- cn->datatype=TYPE_VEC4;
- cn->value=Plane(values[0],values[1],values[2],values[3]);
- } else {
- ERR_FAIL_V(p_node);
+ ConstantNode *cn=alloc_node<ConstantNode>();
+ cn->datatype=op->get_datatype();
+ cn->values=values;
+ return cn;
+ } else if (op->op==OP_NEGATE) {
+
+ op->arguments[0]=_reduce_expression(p_block,op->arguments[0]);
+ if (op->arguments[0]->type==Node::TYPE_CONSTANT) {
+
+ ConstantNode *cn = static_cast<ConstantNode*>(op->arguments[0]);
+
+ DataType base=get_scalar_type(cn->datatype);
+
+ Vector<ConstantNode::Value> values;
+
+ for(int i=0;i<cn->values.size();i++) {
+
+ ConstantNode::Value nv;
+ switch(base) {
+ case TYPE_BOOL: {
+ nv.boolean=!cn->values[i].boolean;
+ } break;
+ case TYPE_INT: {
+ nv.sint=-cn->values[i].sint;
+ } break;
+ case TYPE_UINT: {
+ nv.uint=-cn->values[i].uint;
+ } break;
+ case TYPE_FLOAT: {
+ nv.real=-cn->values[i].real;
+ } break;
+ default: {}
+ }
+
+ values.push_back(nv);
}
+
+ cn->values=values;
return cn;
}
}
-
return p_node;
@@ -2579,6 +2974,8 @@ ShaderLanguage::Node* ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_
ShaderLanguage::Node* expr = _parse_expression(p_block,p_builtin_types);
+ if (!expr) //errored
+ return NULL;
expr = _reduce_expression(p_block,expr);
@@ -2592,7 +2989,7 @@ Error ShaderLanguage::_parse_block(BlockNode* p_block,const Map<StringName,DataT
while(true) {
- int pos = char_idx;
+ TkPos pos = _get_tkpos();
Token tk = _get_token();
if (tk.type==TK_CURLY_BRACKET_CLOSE) { //end of block
@@ -2634,6 +3031,7 @@ Error ShaderLanguage::_parse_block(BlockNode* p_block,const Map<StringName,DataT
BlockNode::Variable var;
var.type=type;
var.precision=precision;
+ var.line=tk_line;
p_block->variables[name]=var;
tk = _get_token();
@@ -2670,6 +3068,7 @@ Error ShaderLanguage::_parse_block(BlockNode* p_block,const Map<StringName,DataT
BlockNode* block = alloc_node<BlockNode>();
block->parent_block=p_block;
_parse_block(block,p_builtin_types,false,p_can_break,p_can_continue);
+ p_block->statements.push_back(block);
} else if (tk.type==TK_CF_IF) {
//if () {}
tk = _get_token();
@@ -2692,29 +3091,34 @@ Error ShaderLanguage::_parse_block(BlockNode* p_block,const Map<StringName,DataT
BlockNode* block = alloc_node<BlockNode>();
block->parent_block=p_block;
+ cf->expressions.push_back(n);
cf->blocks.push_back(block);
+ p_block->statements.push_back(cf);
- Error err=_parse_block(p_block,p_builtin_types,true,p_can_break,p_can_continue);
+ Error err=_parse_block(block,p_builtin_types,true,p_can_break,p_can_continue);
- pos=char_idx;
+ pos=_get_tkpos();
tk = _get_token();
if (tk.type==TK_CF_ELSE) {
block = alloc_node<BlockNode>();
block->parent_block=p_block;
cf->blocks.push_back(block);
- err=_parse_block(p_block,p_builtin_types,true,p_can_break,p_can_continue);
+ err=_parse_block(block,p_builtin_types,true,p_can_break,p_can_continue);
} else {
- char_idx=pos; //rollback
+ _set_tkpos(pos); //rollback
}
} else {
//nothng else, so expression
- char_idx=pos; //rollback
- _parse_and_reduce_expression(p_block,p_builtin_types);
+ _set_tkpos(pos); //rollback
+ Node*expr = _parse_and_reduce_expression(p_block,p_builtin_types);
+ if (!expr)
+ return ERR_PARSE_ERROR;
+ p_block->statements.push_back(expr);
tk = _get_token();
if (tk.type!=TK_SEMICOLON) {
@@ -2742,8 +3146,11 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
case TK_RENDER_MODE: {
while(true) {
- tk = _get_token();
- if (tk.type!=TK_IDENTIFIER) {
+
+ StringName mode;
+ _get_completable_identifier(NULL,COMPLETION_RENDER_MODE,mode);
+
+ if (mode==StringName()) {
_set_error("Expected identifier for render mode");
return ERR_PARSE_ERROR;
}
@@ -2821,7 +3228,6 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
uniform.type=type;
uniform.precission=precision;
- shader->uniforms[name]=uniform;
//todo parse default value
tk = _get_token();
@@ -2835,19 +3241,35 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
return ERR_PARSE_ERROR;
}
- uniform.default_value=static_cast<ConstantNode*>(expr)->value;
+ ConstantNode* cn = static_cast<ConstantNode*>(expr);
+
+ uniform.default_value.resize(cn->values.size());
+
+ if (!convert_constant(cn,uniform.type,uniform.default_value.ptr())) {
+ _set_error("Can't convert constant to "+get_datatype_name(uniform.type));
+ return ERR_PARSE_ERROR;
+ }
tk = _get_token();
}
if (tk.type==TK_COLON) {
//hint
+
tk = _get_token();
if (tk.type==TK_HINT_WHITE_TEXTURE) {
- uniform.hint=ShaderNode::Uniform::HINT_WHITE_TEXTURE;
+ uniform.hint=ShaderNode::Uniform::HINT_WHITE;
} else if (tk.type==TK_HINT_BLACK_TEXTURE) {
- uniform.hint=ShaderNode::Uniform::HINT_BLACK_TEXTURE;
+ uniform.hint=ShaderNode::Uniform::HINT_BLACK;
} else if (tk.type==TK_HINT_NORMAL_TEXTURE) {
- uniform.hint=ShaderNode::Uniform::HINT_NORMAL_TEXTURE;
+ uniform.hint=ShaderNode::Uniform::HINT_NORMAL;
+ } else if (tk.type==TK_HINT_ALBEDO_TEXTURE) {
+ uniform.hint=ShaderNode::Uniform::HINT_ALBEDO;
+ } else if (tk.type==TK_HINT_COLOR) {
+ if (type!=TYPE_VEC4) {
+ _set_error("Color hint is for vec4 only");
+ return ERR_PARSE_ERROR;
+ }
+ uniform.hint=ShaderNode::Uniform::HINT_COLOR;
} else if (tk.type==TK_HINT_RANGE) {
uniform.hint=ShaderNode::Uniform::HINT_RANGE;
@@ -2913,17 +3335,23 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
}
+ } else {
+ _set_error("Expected valid type hint after ':'.");
}
- if (uniform.hint!=ShaderNode::Uniform::HINT_RANGE && uniform.hint!=ShaderNode::Uniform::HINT_NONE && type <=TYPE_MAT4) {
+ if (uniform.hint!=ShaderNode::Uniform::HINT_RANGE && uniform.hint!=ShaderNode::Uniform::HINT_NONE && uniform.hint!=ShaderNode::Uniform::HINT_COLOR && type <=TYPE_MAT4) {
_set_error("This hint is only for sampler types");
return ERR_PARSE_ERROR;
}
+ print_line("assigning name: "+String(name));
+ tk = _get_token();
}
+ shader->uniforms[name]=uniform;
+
if (tk.type!=TK_SEMICOLON) {
_set_error("Expected ';'");
return ERR_PARSE_ERROR;
@@ -2965,15 +3393,14 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
type = get_token_datatype(tk.type);
+ _get_completable_identifier(NULL,COMPLETION_MAIN_FUNCTION,name);
- tk = _get_token();
- if (tk.type!=TK_IDENTIFIER) {
+ if (name==StringName()) {
_set_error("Expected function name after datatype");
return ERR_PARSE_ERROR;
}
- name=tk.text;
if (_find_identifier(NULL,Map<StringName,DataType>(),name)) {
_set_error("Redefinition of '"+String(name)+"'");
@@ -3113,7 +3540,6 @@ Error ShaderLanguage::compile(const String& p_code, const Map< StringName, Map<S
nodes=NULL;
-
shader = alloc_node<ShaderNode>();
Error err = _parse_shader(p_functions,p_render_modes);
@@ -3122,6 +3548,268 @@ Error ShaderLanguage::compile(const String& p_code, const Map< StringName, Map<S
}
return OK;
}
+
+Error ShaderLanguage::complete(const String& p_code,const Map< StringName, Map<StringName,DataType> > &p_functions,const Set<String>& p_render_modes,List<String>* r_options,String& r_call_hint) {
+
+ clear();
+
+ code=p_code;
+
+ nodes=NULL;
+
+ shader = alloc_node<ShaderNode>();
+ Error err = _parse_shader(p_functions,p_render_modes);
+
+ switch(completion_type) {
+
+ case COMPLETION_NONE: {
+ //do none
+ return ERR_PARSE_ERROR;
+ } break;
+ case COMPLETION_RENDER_MODE: {
+ for(const Set<String>::Element *E=p_render_modes.front();E;E=E->next()) {
+
+ r_options->push_back(E->get());
+ }
+
+ return OK;
+ } break;
+ case COMPLETION_MAIN_FUNCTION: {
+ print_line("complete main func");
+ for(const Map< StringName, Map<StringName,DataType> >::Element *E=p_functions.front();E;E=E->next()) {
+
+ r_options->push_back(E->key());
+ }
+
+ return OK;
+ } break;
+ case COMPLETION_IDENTIFIER:
+ case COMPLETION_FUNCTION_CALL: {
+
+ print_line("complete identifier");
+ bool comp_ident=completion_type==COMPLETION_IDENTIFIER;
+ Set<String> matches;
+
+ StringName skip_function;
+
+ BlockNode *block=completion_block;
+
+
+ while(block) {
+
+ if (comp_ident) {
+ for (const Map<StringName,BlockNode::Variable>::Element *E=block->variables.front();E;E=E->next()) {
+
+ if (E->get().line<completion_line) {
+ matches.insert(E->key());
+ }
+ }
+ }
+
+
+ if (block->parent_function) {
+ if (comp_ident) {
+ for(int i=0;i<block->parent_function->arguments.size();i++) {
+ matches.insert(block->parent_function->arguments[i].name);
+ }
+ }
+ skip_function=block->parent_function->name;
+ }
+ block=block->parent_block;
+ }
+
+ if (comp_ident && skip_function!=StringName() && p_functions.has(skip_function)) {
+
+ for (Map<StringName,DataType>::Element *E=p_functions[skip_function].front();E;E=E->next()) {
+ matches.insert(E->key());
+ }
+ }
+
+ if (comp_ident) {
+ for (const Map<StringName,ShaderNode::Varying>::Element *E=shader->varyings.front();E;E=E->next()) {
+ matches.insert(E->key());
+
+ }
+ for (const Map<StringName,ShaderNode::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
+ matches.insert(E->key());
+ }
+
+
+ }
+
+ for(int i=0;i<shader->functions.size();i++) {
+ if (!shader->functions[i].callable || shader->functions[i].name==skip_function)
+ continue;
+ matches.insert(String(shader->functions[i].name)+"(");
+ }
+
+ int idx=0;
+
+ while (builtin_func_defs[idx].name) {
+
+ matches.insert(String(builtin_func_defs[idx].name)+"(");
+ idx++;
+ }
+
+ for(Set<String>::Element *E=matches.front();E;E=E->next()) {
+ r_options->push_back(E->get());
+ }
+
+ return OK;
+
+ } break;
+ case COMPLETION_CALL_ARGUMENTS: {
+
+ print_line("complete callargs");
+ for(int i=0;i<shader->functions.size();i++) {
+ if (!shader->functions[i].callable)
+ continue;
+ if (shader->functions[i].name==completion_function) {
+
+ String calltip;
+
+ calltip+=get_datatype_name( shader->functions[i].function->return_type );
+ calltip+=" ";
+ calltip+=shader->functions[i].name;
+ calltip+="(";
+
+ for(int j=0;j<shader->functions[i].function->arguments.size();j++) {
+
+ if (j>0)
+ calltip+=", ";
+ else
+ calltip+=" ";
+
+ if (j==completion_argument) {
+ calltip+=CharType(0xFFFF);
+ }
+
+ calltip+=get_datatype_name(shader->functions[i].function->arguments[j].type);
+ calltip+=" ";
+ calltip+=shader->functions[i].function->arguments[j].name;
+
+ if (j==completion_argument) {
+ calltip+=CharType(0xFFFF);
+ }
+
+ }
+
+ if (shader->functions[i].function->arguments.size())
+ calltip+=" ";
+ calltip+=")";
+
+ r_call_hint=calltip;
+ return OK;
+ }
+
+ }
+
+ int idx=0;
+
+ String calltip;
+
+ while (builtin_func_defs[idx].name) {
+
+ if (completion_function==builtin_func_defs[idx].name) {
+
+ if (calltip.length())
+ calltip+="\n";
+
+ calltip+=get_datatype_name( builtin_func_defs[idx].rettype );
+ calltip+=" ";
+ calltip+=builtin_func_defs[idx].name;
+ calltip+="(";
+
+ bool found_arg=false;
+ for(int i=0;i<4;i++) {
+
+ if (builtin_func_defs[idx].args[i]==TYPE_VOID)
+ break;
+
+ if (i>0)
+ calltip+=", ";
+ else
+ calltip+=" ";
+
+ if (i==completion_argument) {
+ calltip+=CharType(0xFFFF);
+ }
+
+ calltip+=get_datatype_name(builtin_func_defs[idx].args[i]);
+
+ if (i==completion_argument) {
+ calltip+=CharType(0xFFFF);
+ }
+
+ found_arg=true;
+
+ }
+
+ if (found_arg)
+ calltip+=" ";
+ calltip+=")";
+
+
+ }
+ idx++;
+ }
+
+ r_call_hint=calltip;
+
+ return OK;
+
+ } break;
+ case COMPLETION_INDEX: {
+
+ const char colv[4]={'r','g','b','a'};
+ const char coordv[4]={'x','y','z','w'};
+
+
+ int limit=0;
+
+ switch(completion_base) {
+ case TYPE_BVEC2:
+ case TYPE_IVEC2:
+ case TYPE_UVEC2:
+ case TYPE_VEC2: {
+ limit=2;
+
+ } break;
+ case TYPE_BVEC3:
+ case TYPE_IVEC3:
+ case TYPE_UVEC3:
+ case TYPE_VEC3: {
+
+ limit=3;
+
+ } break;
+ case TYPE_BVEC4:
+ case TYPE_IVEC4:
+ case TYPE_UVEC4:
+ case TYPE_VEC4: {
+
+ limit=4;
+
+ } break;
+ case TYPE_MAT2: limit=2; break;
+ case TYPE_MAT3: limit=3; break;
+ case TYPE_MAT4: limit=4; break;
+ default: {}
+ }
+
+ for(int i=0;i<limit;i++) {
+ r_options->push_back(String::chr(colv[i]));
+ r_options->push_back(String::chr(coordv[i]));
+ }
+
+ } break;
+
+
+ }
+
+ return ERR_PARSE_ERROR;
+}
+
String ShaderLanguage::get_error_text() {
return error_str;
@@ -3132,6 +3820,11 @@ int ShaderLanguage::get_error_line() {
return error_line;
}
+ShaderLanguage::ShaderNode *ShaderLanguage::get_shader() {
+
+ return shader;
+}
+
ShaderLanguage::ShaderLanguage() {
nodes=NULL;
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index b37853c77e..45dc556115 100644
--- a/servers/visual/shader_language.h
+++ b/servers/visual/shader_language.h
@@ -138,7 +138,10 @@ public:
TK_HINT_WHITE_TEXTURE,
TK_HINT_BLACK_TEXTURE,
TK_HINT_NORMAL_TEXTURE,
+ TK_HINT_ALBEDO_TEXTURE,
+ TK_HINT_COLOR,
TK_HINT_RANGE,
+ TK_CURSOR,
TK_ERROR,
TK_EOF,
TK_MAX
@@ -291,7 +294,15 @@ public:
struct ConstantNode : public Node {
DataType datatype;
- Variant value;
+
+ union Value {
+ bool boolean;
+ float real;
+ int32_t sint;
+ uint32_t uint;
+ };
+
+ Vector<Value> values;
virtual DataType get_datatype() const { return datatype; }
ConstantNode() { type=TYPE_CONSTANT; }
@@ -306,6 +317,7 @@ public:
struct Variable {
DataType type;
DataPrecision precision;
+ int line; //for completion
};
Map<StringName,Variable> variables;
@@ -316,6 +328,7 @@ public:
struct ControlFlowNode : public Node {
FlowOperation flow_op;
+ Vector<Node*> expressions;
Vector<BlockNode*> blocks;
ControlFlowNode() { type=TYPE_CONTROL_FLOW; flow_op=FLOW_OP_IF;}
};
@@ -368,16 +381,19 @@ public:
struct Uniform {
enum Hint {
HINT_NONE,
- HINT_WHITE_TEXTURE,
- HINT_BLACK_TEXTURE,
- HINT_NORMAL_TEXTURE,
+ HINT_COLOR,
HINT_RANGE,
+ HINT_ALBEDO,
+ HINT_NORMAL,
+ HINT_BLACK,
+ HINT_WHITE,
+ HINT_MAX
};
int order;
DataType type;
DataPrecision precission;
- Variant default_value;
+ Vector<ConstantNode::Value> default_value;
Hint hint;
float hint_range[3];
@@ -414,15 +430,12 @@ public:
enum CompletionType {
COMPLETION_NONE,
- COMPLETION_BUILT_IN_TYPE_CONSTANT,
- COMPLETION_FUNCTION,
+ COMPLETION_RENDER_MODE,
+ COMPLETION_MAIN_FUNCTION,
COMPLETION_IDENTIFIER,
- COMPLETION_PARENT_FUNCTION,
- COMPLETION_METHOD,
+ COMPLETION_FUNCTION_CALL,
COMPLETION_CALL_ARGUMENTS,
COMPLETION_INDEX,
- COMPLETION_VIRTUAL_FUNC,
- COMPLETION_YIELD,
};
struct Token {
@@ -433,7 +446,10 @@ public:
uint16_t line;
};
+
+ static String get_operator_text(Operator p_op);
static String get_token_text(Token p_token);
+
static bool is_token_datatype(TokenType p_type);
static DataType get_token_datatype(TokenType p_type);
static bool is_token_precision(TokenType p_type);
@@ -442,8 +458,16 @@ public:
static bool is_token_nonvoid_datatype(TokenType p_type);
static bool is_token_operator(TokenType p_type);
+ static bool convert_constant(ConstantNode* p_constant, DataType p_to_type,ConstantNode::Value *p_value=NULL);
+ static DataType get_scalar_type(DataType p_type);
+ static bool is_scalar_type(DataType p_type);
+
+ static void get_keyword_list(List<String> *r_keywords);
private:
+ struct KeyWord { TokenType token; const char *text;};
+ static const KeyWord keyword_list[];
+
bool error_set;
String error_str;
int error_line;
@@ -452,10 +476,29 @@ private:
int char_idx;
int tk_line;
+ struct TkPos {
+ int char_idx;
+ int tk_line;
+ };
+
+ TkPos _get_tkpos() {
+ TkPos tkp;
+ tkp.char_idx=char_idx;
+ tkp.tk_line=tk_line;
+ return tkp;
+ }
+
+
+ void _set_tkpos(TkPos p_pos) {
+ char_idx=p_pos.char_idx;
+ tk_line=p_pos.tk_line;
+ }
void _set_error(const String& p_str) {
if (error_set)
return;
+
+ error_line=tk_line;
error_set=true;
error_str=p_str;
}
@@ -485,7 +528,7 @@ private:
bool _validate_operator(OperatorNode *p_op,DataType *r_ret_type=NULL);
- struct IntrinsicFuncDef {
+ struct BuiltinFuncDef {
enum { MAX_ARGS=5 };
const char* name;
@@ -494,11 +537,20 @@ private:
};
+ CompletionType completion_type;
+ int completion_line;
+ BlockNode *completion_block;
+ DataType completion_base;
+ StringName completion_function;
+ int completion_argument;
+
- static const IntrinsicFuncDef intrinsic_func_defs[];
+ bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName& identifier);
+
+ static const BuiltinFuncDef builtin_func_defs[];
bool _validate_function_call(BlockNode* p_block, OperatorNode *p_func,DataType *r_ret_type);
- bool _parse_function_arguments(BlockNode *p_block, const Map<StringName,DataType> &p_builtin_types, OperatorNode* p_func);
+ bool _parse_function_arguments(BlockNode *p_block, const Map<StringName,DataType> &p_builtin_types, OperatorNode* p_func, int *r_complete_arg=NULL);
Node* _parse_expression(BlockNode *p_block, const Map<StringName,DataType> &p_builtin_types);
@@ -516,10 +568,16 @@ public:
void clear();
Error compile(const String& p_code,const Map< StringName, Map<StringName,DataType> > &p_functions,const Set<String>& p_render_modes);
+ Error complete(const String& p_code,const Map< StringName, Map<StringName,DataType> > &p_functions,const Set<String>& p_render_modes,List<String>* r_options,String& r_call_hint);
+
+
+
String get_error_text();
int get_error_line();
- static String lex_debug(const String& p_code);
+ ShaderNode *get_shader();
+
+ String token_debug(const String& p_code);
ShaderLanguage();
~ShaderLanguage();
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
new file mode 100644
index 0000000000..675be3458c
--- /dev/null
+++ b/servers/visual/shader_types.cpp
@@ -0,0 +1,99 @@
+#include "shader_types.h"
+
+
+const Map< StringName, Map<StringName,ShaderLanguage::DataType> >& ShaderTypes::get_functions(VS::ShaderMode p_mode) {
+
+ return shader_modes[p_mode].functions;
+}
+
+const Set<String>& ShaderTypes::get_modes(VS::ShaderMode p_mode) {
+
+ return shader_modes[p_mode].modes;
+}
+
+
+ShaderTypes *ShaderTypes::singleton=NULL;
+
+ShaderTypes::ShaderTypes()
+{
+ singleton=this;
+
+
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["SRC_VERTEX"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["SRC_NORMAL"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["SRC_TANGENT"]=ShaderLanguage::TYPE_VEC4;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["SRC_BONES"]=ShaderLanguage::TYPE_IVEC4;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["SRC_WEIGHTS"]=ShaderLanguage::TYPE_VEC4;
+
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["POSITION"]=ShaderLanguage::TYPE_VEC4 ;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["VERTEX"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["NORMAL"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["TANGENT"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["BINORMAL"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["UV"]=ShaderLanguage::TYPE_VEC2;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["UV2"]=ShaderLanguage::TYPE_VEC2;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["COLOR"]=ShaderLanguage::TYPE_VEC4;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["POINT_SIZE"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["INSTANCE_ID"]=ShaderLanguage::TYPE_INT;
+
+ //builtins
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["WORLD_MATRIX"]=ShaderLanguage::TYPE_MAT4;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["INV_CAMERA_MATRIX"]=ShaderLanguage::TYPE_MAT4;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["PROJECTION_MATRIX"]=ShaderLanguage::TYPE_MAT4;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["TIME"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["VIEWPORT_SIZE"]=ShaderLanguage::TYPE_VEC2;
+
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["VERTEX"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["FRAGCOORD"]=ShaderLanguage::TYPE_VEC4;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["FRONT_FACING"]=ShaderLanguage::TYPE_BOOL;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["NORMAL"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["TANGENT"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["BINORMAL"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["NORMALMAP"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["NORMALMAP_DEPTH"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["UV"]=ShaderLanguage::TYPE_VEC2;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["UV2"]=ShaderLanguage::TYPE_VEC2;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["COLOR"]=ShaderLanguage::TYPE_VEC4;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["NORMAL"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ALBEDO"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ALPHA"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["METAL"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["ROUGH"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["EMISSION"]=ShaderLanguage::TYPE_VEC3;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["DISCARD"]=ShaderLanguage::TYPE_BOOL;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["POINT_COORD"]=ShaderLanguage::TYPE_VEC2;
+
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["WORLD_MATRIX"]=ShaderLanguage::TYPE_MAT4;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["INV_CAMERA_MATRIX"]=ShaderLanguage::TYPE_MAT4;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["PROJECTION_MATRIX"]=ShaderLanguage::TYPE_MAT4;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["TIME"]=ShaderLanguage::TYPE_FLOAT;
+ shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["VIEWPORT_SIZE"]=ShaderLanguage::TYPE_VEC2;
+
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mix");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_add");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_sub");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mul");
+
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("special_glow");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("special_subsurf");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("special_specular");
+
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_opaque");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_always");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_never");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("depth_draw_alpha_prepass");
+
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_front");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_back");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("cull_disable");
+
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("lightmap_on_uv2");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("ontop");
+
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_model_space");
+ shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_camera_space");
+
+}
diff --git a/servers/visual/shader_types.h b/servers/visual/shader_types.h
new file mode 100644
index 0000000000..411d5790a9
--- /dev/null
+++ b/servers/visual/shader_types.h
@@ -0,0 +1,27 @@
+#ifndef SHADERTYPES_H
+#define SHADERTYPES_H
+
+#include "shader_language.h"
+#include "servers/visual_server.h"
+class ShaderTypes {
+
+
+ struct Type {
+
+ Map< StringName, Map<StringName,ShaderLanguage::DataType> > functions;
+ Set<String> modes;
+ };
+
+ Map<VS::ShaderMode,Type> shader_modes;
+
+ static ShaderTypes *singleton;
+public:
+ static ShaderTypes *get_singleton() { return singleton; }
+
+ const Map< StringName, Map<StringName,ShaderLanguage::DataType> >& get_functions(VS::ShaderMode p_mode);
+ const Set<String>& get_modes(VS::ShaderMode p_mode);
+
+ ShaderTypes();
+};
+
+#endif // SHADERTYPES_H