diff --git a/bin/tests/test_shader_lang.cpp b/bin/tests/test_shader_lang.cpp index 6c8132122ce..1a677bcbe2e 100644 --- a/bin/tests/test_shader_lang.cpp +++ b/bin/tests/test_shader_lang.cpp @@ -39,7 +39,7 @@ #include "servers/visual/shader_language.h" //#include "drivers/gles2/shader_compiler_gles2.h" -#if 0 + typedef ShaderLanguage SL; namespace TestShaderLang { @@ -57,50 +57,54 @@ static String _mktab(int p_level) { static String _typestr(SL::DataType p_type) { - switch(p_type) { - - case SL::TYPE_VOID: return "void"; - case SL::TYPE_BOOL: return "bool"; - case SL::TYPE_FLOAT: return "float"; - case SL::TYPE_VEC2: return "vec2"; - case SL::TYPE_VEC3: return "vec3"; - case SL::TYPE_VEC4: return "vec4"; - case SL::TYPE_MAT3: return "mat3"; - case SL::TYPE_MAT4: return "mat4"; - case SL::TYPE_TEXTURE: return "texture"; - case SL::TYPE_CUBEMAP: return "cubemap"; - default: {} - } + return ShaderLanguage::get_datatype_name(p_type); return ""; } + +static String _prestr(SL::DataPrecision p_pres) { + + + switch(p_pres) { + case SL::PRECISION_LOWP: return "lowp "; + case SL::PRECISION_MEDIUMP: return "mediump "; + case SL::PRECISION_HIGHP: return "highp "; + case SL::PRECISION_DEFAULT: return ""; + } + return ""; +} + + static String _opstr(SL::Operator p_op) { - switch(p_op) { - case SL::OP_ASSIGN: return "="; - case SL::OP_ADD: return "+"; - case SL::OP_SUB: return "-"; - case SL::OP_MUL: return "*"; - case SL::OP_DIV: return "/"; - case SL::OP_ASSIGN_ADD: return "+="; - case SL::OP_ASSIGN_SUB: return "-="; - case SL::OP_ASSIGN_MUL: return "*="; - case SL::OP_ASSIGN_DIV: return "/="; - case SL::OP_NEG: return "-"; - case SL::OP_NOT: return "!"; - case SL::OP_CMP_EQ: return "=="; - case SL::OP_CMP_NEQ: return "!="; - case SL::OP_CMP_LEQ: return "<="; - case SL::OP_CMP_GEQ: return ">="; - case SL::OP_CMP_LESS: return "<"; - case SL::OP_CMP_GREATER: return ">"; - case SL::OP_CMP_OR: return "||"; - case SL::OP_CMP_AND: return "&&"; - default: return ""; - } + return ShaderLanguage::get_operator_text(p_op); - return ""; + +} + + +static String get_constant_text(SL::DataType p_type, const Vector& p_values) { + + switch(p_type) { + case SL::TYPE_BOOL: return p_values[0].boolean?"true":"false"; + case SL::TYPE_BVEC2: return String()+"bvec2("+(p_values[0].boolean?"true":"false")+(p_values[1].boolean?"true":"false")+")"; + case SL::TYPE_BVEC3: return String()+"bvec3("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+")"; + case SL::TYPE_BVEC4: return String()+"bvec4("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+","+(p_values[3].boolean?"true":"false")+")"; + case SL::TYPE_INT: return rtos(p_values[0].sint); + case SL::TYPE_IVEC2: return String()+"ivec2("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+")"; + case SL::TYPE_IVEC3: return String()+"ivec3("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+")"; + case SL::TYPE_IVEC4: return String()+"ivec4("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+","+rtos(p_values[3].sint)+")"; + case SL::TYPE_UINT: return rtos(p_values[0].real); + case SL::TYPE_UVEC2: return String()+"uvec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")"; + case SL::TYPE_UVEC3: return String()+"uvec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")"; + case SL::TYPE_UVEC4: return String()+"uvec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")"; + case SL::TYPE_FLOAT: return rtos(p_values[0].real); + case SL::TYPE_VEC2: return String()+"vec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")"; + case SL::TYPE_VEC3: return String()+"vec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")"; + case SL::TYPE_VEC4: return String()+"vec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")"; + default: ERR_FAIL_V(String()); + } } static String dump_node_code(SL::Node *p_node,int p_level) { @@ -109,18 +113,48 @@ static String dump_node_code(SL::Node *p_node,int p_level) { switch(p_node->type) { - case SL::Node::TYPE_PROGRAM: { + case SL::Node::TYPE_SHADER: { - SL::ProgramNode *pnode=(SL::ProgramNode*)p_node; + SL::ShaderNode *pnode=(SL::ShaderNode*)p_node; - for(Map::Element *E=pnode->uniforms.front();E;E=E->next()) { + for(Map::Element *E=pnode->uniforms.front();E;E=E->next()) { String ucode="uniform "; - ucode+=_typestr(E->get().type)+"="+String(E->get().default_value)+"\n"; - code+=ucode; + ucode+=_prestr(E->get().precission); + ucode+=_typestr(E->get().type); + ucode+=" "+String(E->key()); + + if (E->get().default_value.size()) { + ucode+=" = "+get_constant_text(E->get().type,E->get().default_value); + } + + static const char*hint_name[SL::ShaderNode::Uniform::HINT_MAX]={ + "", + "color", + "range", + "albedo", + "normal", + "black", + "white" + }; + + if (E->get().hint) + ucode+=" : "+String(hint_name[E->get().hint]); + + code+=ucode+"\n"; } + for(Map::Element *E=pnode->varyings.front();E;E=E->next()) { + + String vcode="varying "; + vcode+=_prestr(E->get().precission); + vcode+=_typestr(E->get().type); + vcode+=" "+String(E->key()); + + code+=vcode+"\n"; + + } for(int i=0;ifunctions.size();i++) { SL::FunctionNode *fnode=pnode->functions[i].function; @@ -131,16 +165,15 @@ static String dump_node_code(SL::Node *p_node,int p_level) { if (i>0) header+=", "; - header+=_typestr(fnode->arguments[i].type)+" "+fnode->arguments[i].name; + header+=_prestr(fnode->arguments[i].precision)+_typestr(fnode->arguments[i].type)+" "+fnode->arguments[i].name; } - header+=") {\n"; + header+=")\n"; code+=header; code+=dump_node_code(fnode->body,p_level+1); - code+="}\n"; } - code+=dump_node_code(pnode->body,p_level); + //code+=dump_node_code(pnode->body,p_level); } break; case SL::Node::TYPE_FUNCTION: { @@ -149,15 +182,23 @@ static String dump_node_code(SL::Node *p_node,int p_level) { SL::BlockNode *bnode=(SL::BlockNode*)p_node; //variables - for(Map::Element *E=bnode->variables.front();E;E=E->next()) { + code+=_mktab(p_level-1)+"{\n"; + for(Map::Element *E=bnode->variables.front();E;E=E->next()) { - code+=_mktab(p_level)+_typestr(E->value())+" "+E->key()+";\n"; + code+=_mktab(p_level)+_prestr(E->get().precision)+_typestr(E->get().type)+" "+E->key()+";\n"; } for(int i=0;istatements.size();i++) { - code+=_mktab(p_level)+dump_node_code(bnode->statements[i],p_level)+";\n"; + String scode = dump_node_code(bnode->statements[i],p_level); + + if (bnode->statements[i]->type==SL::Node::TYPE_CONTROL_FLOW || bnode->statements[i]->type==SL::Node::TYPE_CONTROL_FLOW) { + code+=scode; //use directly + } else { + code+=_mktab(p_level)+scode+";\n"; + } } + code+=_mktab(p_level-1)+"}\n"; } break; @@ -168,18 +209,7 @@ static String dump_node_code(SL::Node *p_node,int p_level) { } break; case SL::Node::TYPE_CONSTANT: { SL::ConstantNode *cnode=(SL::ConstantNode*)p_node; - switch(cnode->datatype) { - - - case SL::TYPE_BOOL: code=cnode->value.operator bool()?"true":"false"; break; - case SL::TYPE_FLOAT: code=cnode->value; break; - case SL::TYPE_VEC2: { Vector2 v = cnode->value; code="vec2("+rtos(v.x)+", "+rtos(v.y)+")"; } break; - case SL::TYPE_VEC3: { Vector3 v = cnode->value; code="vec3("+rtos(v.x)+", "+rtos(v.y)+", "+rtos(v.z)+")"; } break; - case SL::TYPE_VEC4: { Plane v = cnode->value; code="vec4("+rtos(v.normal.x)+", "+rtos(v.normal.y)+", "+rtos(v.normal.z)+", "+rtos(v.d)+")"; } break; - case SL::TYPE_MAT3: { Matrix3 x = cnode->value; code="mat3( vec3("+rtos(x.get_axis(0).x)+", "+rtos(x.get_axis(0).y)+", "+rtos(x.get_axis(0).z)+"), vec3("+rtos(x.get_axis(1).x)+", "+rtos(x.get_axis(1).y)+", "+rtos(x.get_axis(1).z)+"), vec3("+rtos(x.get_axis(2).x)+", "+rtos(x.get_axis(2).y)+", "+rtos(x.get_axis(2).z)+"))"; } break; - case SL::TYPE_MAT4: { Transform x = cnode->value; code="mat4( vec3("+rtos(x.basis.get_axis(0).x)+", "+rtos(x.basis.get_axis(0).y)+", "+rtos(x.basis.get_axis(0).z)+"), vec3("+rtos(x.basis.get_axis(1).x)+", "+rtos(x.basis.get_axis(1).y)+", "+rtos(x.basis.get_axis(1).z)+"), vec3("+rtos(x.basis.get_axis(2).x)+", "+rtos(x.basis.get_axis(2).y)+", "+rtos(x.basis.get_axis(2).z)+"), vec3("+rtos(x.origin.x)+", "+rtos(x.origin.y)+", "+rtos(x.origin.z)+"))"; } break; - default: code="value.get_type())+" ("+itos(cnode->datatype)+">"; - } + return get_constant_text(cnode->datatype,cnode->values); } break; case SL::Node::TYPE_OPERATOR: { @@ -193,28 +223,25 @@ static String dump_node_code(SL::Node *p_node,int p_level) { case SL::OP_ASSIGN_SUB: case SL::OP_ASSIGN_MUL: case SL::OP_ASSIGN_DIV: + case SL::OP_ASSIGN_SHIFT_LEFT: + case SL::OP_ASSIGN_SHIFT_RIGHT: + case SL::OP_ASSIGN_MOD: + case SL::OP_ASSIGN_BIT_AND: + case SL::OP_ASSIGN_BIT_OR: + case SL::OP_ASSIGN_BIT_XOR: code=dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op)+dump_node_code(onode->arguments[1],p_level); break; - - case SL::OP_ADD: - case SL::OP_SUB: - case SL::OP_MUL: - case SL::OP_DIV: - case SL::OP_CMP_EQ: - case SL::OP_CMP_NEQ: - case SL::OP_CMP_LEQ: - case SL::OP_CMP_GEQ: - case SL::OP_CMP_LESS: - case SL::OP_CMP_GREATER: - case SL::OP_CMP_OR: - case SL::OP_CMP_AND: - - code="("+dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op)+dump_node_code(onode->arguments[1],p_level)+")"; - break; - case SL::OP_NEG: + case SL::OP_BIT_INVERT: + case SL::OP_NEGATE: case SL::OP_NOT: + case SL::OP_DECREMENT: + case SL::OP_INCREMENT: code=_opstr(onode->op)+dump_node_code(onode->arguments[0],p_level); break; + case SL::OP_POST_DECREMENT: + case SL::OP_POST_INCREMENT: + code=dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op); + break; case SL::OP_CALL: case SL::OP_CONSTRUCT: code=dump_node_code(onode->arguments[0],p_level)+"("; @@ -225,7 +252,12 @@ static String dump_node_code(SL::Node *p_node,int p_level) { } code+=")"; break; - default: {} + default: { + + code="("+dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op)+dump_node_code(onode->arguments[1],p_level)+")"; + break; + + } } } break; @@ -233,20 +265,19 @@ static String dump_node_code(SL::Node *p_node,int p_level) { SL::ControlFlowNode *cfnode=(SL::ControlFlowNode*)p_node; if (cfnode->flow_op==SL::FLOW_OP_IF) { - code+="if ("+dump_node_code(cfnode->statements[0],p_level)+") {\n"; - code+=dump_node_code(cfnode->statements[1],p_level+1); - if (cfnode->statements.size()==3) { + code+=_mktab(p_level)+"if ("+dump_node_code(cfnode->expressions[0],p_level)+")\n"; + code+=dump_node_code(cfnode->blocks[0],p_level+1); + if (cfnode->blocks.size()==2) { - code+="} else {\n"; - code+=dump_node_code(cfnode->statements[2],p_level+1); + code+=_mktab(p_level)+"else\n"; + code+=dump_node_code(cfnode->blocks[1],p_level+1); } - code+="}\n"; } else if (cfnode->flow_op==SL::FLOW_OP_RETURN) { - if (cfnode->statements.size()) { - code="return "+dump_node_code(cfnode->statements[0],p_level); + if (cfnode->blocks.size()) { + code="return "+dump_node_code(cfnode->blocks[0],p_level); } else { code="return"; } @@ -264,16 +295,14 @@ static String dump_node_code(SL::Node *p_node,int p_level) { } -static Error recreate_code(void *p_str,SL::ProgramNode *p_program) { +static Error recreate_code(void *p_str,SL::ShaderNode *p_program) { + - print_line("recr"); String *str=(String*)p_str; *str=dump_node_code(p_program,0); return OK; - - } @@ -283,6 +312,7 @@ MainLoop* test() { if (cmdlargs.empty()) { //try editor! + print_line("usage: godot -test shader_lang "); return NULL; } @@ -303,50 +333,29 @@ MainLoop* test() { code+=c; } - int errline; - int errcol; - String error; - print_line(SL::lex_debug(code)); - Error err = SL::compile(code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,NULL,NULL,&error,&errline,&errcol); + SL sl; + print_line("tokens:\n\n"+sl.token_debug(code)); + + Map > dt; + dt["fragment"]["ALBEDO"]=SL::TYPE_VEC3; + + Set rm; + rm.insert("popo"); + + Error err = sl.compile(code,dt,rm); if (err) { - print_line("Error: "+itos(errline)+":"+itos(errcol)+" "+error); + print_line("Error at line: "+rtos(sl.get_error_line())+": "+sl.get_error_text()); return NULL; + } else { + String code; + recreate_code(&code,sl.get_shader()); + print_line("code:\n\n"+code); } - print_line("Compile OK! - pretty printing"); - - String rcode; - err = SL::compile(code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,recreate_code,&rcode,&error,&errline,&errcol); - - if (!err) { - print_line(rcode); - } -#if 0 - ShaderCompilerGLES2 comp; - String codeline,globalsline; - SL::VarInfo vi; - vi.name="mongs"; - vi.type=SL::TYPE_VEC3; - - - ShaderCompilerGLES2::Flags fl; - comp.compile(code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,codeline,globalsline,fl); -#endif - return NULL; -} - -} -#endif - -typedef ShaderLanguage SL; - -namespace TestShaderLang { - -MainLoop* test() { - return NULL; } + } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 1bff6801fe5..ad845555a46 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -548,7 +548,7 @@ void register_scene_types() { // ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); // ObjectTypeDB::register_type(); - ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::add_compatibility_type("Shader","MaterialShader"); ObjectTypeDB::add_compatibility_type("ParticleSystemMaterial","FixedMaterial"); ObjectTypeDB::add_compatibility_type("UnshadedMaterial","FixedMaterial"); diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index b6c8fcf7a17..8889d1b6f87 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -131,7 +131,7 @@ void Shader::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::STRING, "code",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("set_code"), _SCS("get_code") ); - BIND_CONSTANT( MODE_MATERIAL ); + BIND_CONSTANT( MODE_SPATIAL); BIND_CONSTANT( MODE_CANVAS_ITEM ); BIND_CONSTANT( MODE_POST_PROCESS ); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 988305b6540..eddb98333d0 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -42,7 +42,7 @@ class Shader : public Resource { public: enum Mode { - MODE_MATERIAL, + MODE_SPATIAL, MODE_CANVAS_ITEM, MODE_POST_PROCESS, MODE_MAX @@ -100,13 +100,13 @@ public: VARIANT_ENUM_CAST( Shader::Mode ); -class MaterialShader : public Shader { +class SpatialShader : public Shader { - OBJ_TYPE(MaterialShader,Shader); + OBJ_TYPE(SpatialShader,Shader); public: - MaterialShader() : Shader(MODE_MATERIAL) {}; + SpatialShader() : Shader(MODE_SPATIAL) {}; }; class CanvasItemShader : public Shader { diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 06eaa4d1224..19ee3a48c79 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -36,7 +36,7 @@ #include "spatial_sound_server.h" #include "spatial_sound_2d_server.h" #include "script_debugger_remote.h" - +#include "visual/shader_types.h" static void _debugger_get_resource_usage(List* r_usage) { List tinfo; @@ -55,6 +55,8 @@ static void _debugger_get_resource_usage(Listadd_singleton( Globals::Singleton("VisualServer",VisualServer::get_singleton()) ); @@ -70,6 +72,8 @@ void register_server_types() { Globals::get_singleton()->add_singleton( Globals::Singleton("SpatialSound2DServer",SpatialSound2DServer::get_singleton()) ); Globals::get_singleton()->add_singleton( Globals::Singleton("SS2D",SpatialSound2DServer::get_singleton()) ); + shader_types = memnew( ShaderTypes ); + ObjectTypeDB::register_virtual_type(); ObjectTypeDB::register_virtual_type(); @@ -87,5 +91,5 @@ void register_server_types() { void unregister_server_types(){ - + memdelete( shader_types ); } diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 287293a4379..1a9912e3fb7 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 tokens; - String error; - int errline,errcol; - if (tokenize(p_code,&tokens,&error,&errline,&errcol)!=OK) - return error; - String ret; - for(int i=0;iarguments[i+1]->type==Node::TYPE_CONSTANT && convert_constant(static_cast(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;i0) + err+=","; + + if (p_func->arguments[i+1]->type==Node::TYPE_CONSTANT && p_func->arguments[i+1]->get_datatype()==TYPE_INT && static_cast(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;ifunctions.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;iarguments[i].type) { + + if (get_scalar_type(args[i])==args[i] && p_func->arguments[i+1]->type==Node::TYPE_CONSTANT && convert_constant(static_cast(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 &p_builtin_types,OperatorNode* p_func) { +bool ShaderLanguage::_parse_function_arguments(BlockNode* p_block,const Map &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;ivalues.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 *r_keywords) { + + Set 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::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 &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(); - 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(); - 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(); - 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(); - 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(); 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(); func->op=OP_CALL; @@ -2003,9 +2338,22 @@ 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)+"'"); @@ -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(op->arguments[0]); - StringName name=vn->name; + // StringName name=vn->name; - if (name=="vec2" || name=="vec3" || name=="vec4") { - Vector values; + DataType base=get_scalar_type(op->get_datatype()); - for(int i=1;iarguments.size();i++) { + Vector values; - op->arguments[i]=_reduce_expression(p_block,op->arguments[i]); - if (op->arguments[i]->type==Node::TYPE_CONSTANT) { - ConstantNode *cn = static_cast(op->arguments[i]); - values.push_back(cn->value); + for(int i=1;iarguments.size();i++) { + + + op->arguments[i]=_reduce_expression(p_block,op->arguments[i]); + if (op->arguments[i]->type==Node::TYPE_CONSTANT) { + ConstantNode *cn = static_cast(op->arguments[i]); + + if (get_scalar_type(cn->datatype)==base) { + + for(int j=0;jvalues.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; } - } - ConstantNode *cn=alloc_node(); - - 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); + return p_node; + } + } + + + ConstantNode *cn=alloc_node(); + 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(op->arguments[0]); + + DataType base=get_scalar_type(cn->datatype); + + Vector values; + + for(int i=0;ivalues.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 Mapvariables[name]=var; tk = _get_token(); @@ -2670,6 +3068,7 @@ Error ShaderLanguage::_parse_block(BlockNode* p_block,const Map(); 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(); 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(); 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, Mapuniforms[name]=uniform; //todo parse default value tk = _get_token(); @@ -2835,19 +3241,35 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map(expr)->value; + ConstantNode* cn = static_cast(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, Mapuniforms[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(),name)) { _set_error("Redefinition of '"+String(name)+"'"); @@ -3113,7 +3540,6 @@ Error ShaderLanguage::compile(const String& p_code, const Map< StringName, Map(); Error err = _parse_shader(p_functions,p_render_modes); @@ -3122,6 +3548,268 @@ Error ShaderLanguage::compile(const String& p_code, const Map< StringName, Map > &p_functions,const Set& p_render_modes,List* r_options,String& r_call_hint) { + + clear(); + + code=p_code; + + nodes=NULL; + + shader = alloc_node(); + 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::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 >::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 matches; + + StringName skip_function; + + BlockNode *block=completion_block; + + + while(block) { + + if (comp_ident) { + for (const Map::Element *E=block->variables.front();E;E=E->next()) { + + if (E->get().linekey()); + } + } + } + + + if (block->parent_function) { + if (comp_ident) { + for(int i=0;iparent_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::Element *E=p_functions[skip_function].front();E;E=E->next()) { + matches.insert(E->key()); + } + } + + if (comp_ident) { + for (const Map::Element *E=shader->varyings.front();E;E=E->next()) { + matches.insert(E->key()); + + } + for (const Map::Element *E=shader->uniforms.front();E;E=E->next()) { + matches.insert(E->key()); + } + + + } + + for(int i=0;ifunctions.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::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;ifunctions.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;jfunctions[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;ipush_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 b37853c77ee..45dc5561159 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 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 variables; @@ -316,6 +328,7 @@ public: struct ControlFlowNode : public Node { FlowOperation flow_op; + Vector expressions; Vector 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 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 *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 &p_builtin_types, OperatorNode* p_func); + bool _parse_function_arguments(BlockNode *p_block, const Map &p_builtin_types, OperatorNode* p_func, int *r_complete_arg=NULL); Node* _parse_expression(BlockNode *p_block, const Map &p_builtin_types); @@ -516,10 +568,16 @@ public: void clear(); Error compile(const String& p_code,const Map< StringName, Map > &p_functions,const Set& p_render_modes); + Error complete(const String& p_code,const Map< StringName, Map > &p_functions,const Set& p_render_modes,List* 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 00000000000..675be3458c1 --- /dev/null +++ b/servers/visual/shader_types.cpp @@ -0,0 +1,99 @@ +#include "shader_types.h" + + +const Map< StringName, Map >& ShaderTypes::get_functions(VS::ShaderMode p_mode) { + + return shader_modes[p_mode].functions; +} + +const Set& 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 00000000000..411d5790a94 --- /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 > functions; + Set modes; + }; + + Map shader_modes; + + static ShaderTypes *singleton; +public: + static ShaderTypes *get_singleton() { return singleton; } + + const Map< StringName, Map >& get_functions(VS::ShaderMode p_mode); + const Set& get_modes(VS::ShaderMode p_mode); + + ShaderTypes(); +}; + +#endif // SHADERTYPES_H diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 9b5ed422c5a..a4ee102aed5 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -6540,9 +6540,10 @@ EditorNode::EditorNode() { //more visually meaningful to have this later raise_bottom_panel_item(AnimationPlayerEditor::singleton); + add_editor_plugin( memnew( ShaderEditorPlugin(this) ) ); /* add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,true) ) ); add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,false) ) ); - add_editor_plugin( memnew( ShaderEditorPlugin(this,true) ) ); + add_editor_plugin( memnew( ShaderEditorPlugin(this,false) ) );*/ add_editor_plugin( memnew( CameraEditorPlugin(this) ) ); add_editor_plugin( memnew( SampleEditorPlugin(this) ) ); diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp index 5541ae987f9..9c8aa3c85d9 100644 --- a/tools/editor/plugins/shader_editor_plugin.cpp +++ b/tools/editor/plugins/shader_editor_plugin.cpp @@ -37,8 +37,8 @@ #include "tools/editor/editor_node.h" #include "tools/editor/property_editor.h" #include "os/os.h" +#include "servers/visual/shader_types.h" -#if 0 /*** SETTINGS EDITOR ****/ @@ -51,19 +51,14 @@ Ref ShaderTextEditor::get_edited_shader() const { return shader; } -void ShaderTextEditor::set_edited_shader(const Ref& p_shader,ShaderLanguage::ShaderType p_type) { +void ShaderTextEditor::set_edited_shader(const Ref& p_shader) { shader=p_shader; - type=p_type; + _load_theme_settings(); - if (p_type==ShaderLanguage::SHADER_MATERIAL_LIGHT || p_type==ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT) - get_text_edit()->set_text(shader->get_light_code()); - else if (p_type==ShaderLanguage::SHADER_MATERIAL_VERTEX || p_type==ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX) - get_text_edit()->set_text(shader->get_vertex_code()); - else - get_text_edit()->set_text(shader->get_fragment_code()); + get_text_edit()->set_text(p_shader->get_code()); _line_col_changed(); @@ -104,7 +99,25 @@ void ShaderTextEditor::_load_theme_settings() { List keywords; - ShaderLanguage::get_keyword_list(type,&keywords); + ShaderLanguage::get_keyword_list(&keywords); + + if (shader.is_valid()) { + + + for(const Map< StringName, Map >::Element *E=ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())).front();E;E=E->next()) { + + for (const Map::Element *F=E->get().front();F;F=F->next()) { + keywords.push_back(F->key()); + } + + } + + for(const Set::Element *E =ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())).front();E;E=E->next()) { + + keywords.push_back(E->get()); + + } + } for(List::Element *E=keywords.front();E;E=E->next()) { @@ -142,22 +155,34 @@ void ShaderTextEditor::_load_theme_settings() { } +void ShaderTextEditor::_code_complete_script(const String& p_code, List* r_options) { + + print_line("code complete"); + + ShaderLanguage sl; + String calltip; + + Error err = sl.complete(p_code,ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())),ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())),r_options,calltip); + + if (calltip!="") { + get_text_edit()->set_code_hint(calltip); + } +} void ShaderTextEditor::_validate_script() { - String errortxt; - int line,col; - String code=get_text_edit()->get_text(); //List params; //shader->get_param_list(¶ms); - Error err = ShaderLanguage::compile(code,type,NULL,NULL,&errortxt,&line,&col); + ShaderLanguage sl; + + Error err = sl.compile(code,ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())),ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode()))); if (err!=OK) { - String error_text="error("+itos(line+1)+","+itos(col)+"): "+errortxt; + String error_text="error("+itos(sl.get_error_line())+"): "+sl.get_error_text(); set_error(error_text); - get_text_edit()->set_line_as_marked(line,true); + get_text_edit()->set_line_as_marked(sl.get_error_line(),true); } else { for(int i=0;iget_line_count();i++) @@ -187,9 +212,7 @@ ShaderTextEditor::ShaderTextEditor() { void ShaderEditor::_menu_option(int p_option) { - ShaderTextEditor *current = tab_container->get_current_tab_control()->cast_to(); - if (!current) - return; + ShaderTextEditor *current = shader_editor; switch(p_option) { case EDIT_UNDO: { @@ -245,24 +268,11 @@ void ShaderEditor::_menu_option(int p_option) { } } -void ShaderEditor::_tab_changed(int p_which) { - - ShaderTextEditor *shader_editor = tab_container->get_tab_control(p_which)->cast_to(); - - if (shader_editor && is_inside_tree()) - shader_editor->get_text_edit()->grab_focus(); - - ensure_select_current(); -} void ShaderEditor::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { - close->set_normal_texture( get_icon("Close","EditorIcons")); - close->set_hover_texture( get_icon("CloseHover","EditorIcons")); - close->set_pressed_texture( get_icon("Close","EditorIcons")); - close->connect("pressed",this,"_close_callback"); } if (p_what==NOTIFICATION_DRAW) { @@ -365,57 +375,31 @@ void ShaderEditor::clear() { void ShaderEditor::_params_changed() { - fragment_editor->_validate_script(); - vertex_editor->_validate_script(); - light_editor->_validate_script(); + shader_editor->_validate_script(); } void ShaderEditor::_editor_settings_changed() { - vertex_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); - vertex_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); - vertex_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); - vertex_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); - vertex_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); - vertex_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); - vertex_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); - vertex_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); - vertex_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); - vertex_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/line_spacing")); - vertex_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); + shader_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); + shader_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); + shader_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); + shader_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); + shader_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); + shader_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); + shader_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + shader_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + shader_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); + shader_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/line_spacing")); + shader_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); - fragment_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); - fragment_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); - fragment_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); - fragment_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); - fragment_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); - fragment_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); - fragment_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); - fragment_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); - fragment_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); - fragment_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/line_spacing")); - fragment_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); - - light_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); - light_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); - light_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); - light_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); - light_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); - light_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); - light_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); - light_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); - light_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); - light_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/line_spacing")); - light_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); } void ShaderEditor::_bind_methods() { ObjectTypeDB::bind_method("_editor_settings_changed",&ShaderEditor::_editor_settings_changed); - ObjectTypeDB::bind_method("_tab_changed",&ShaderEditor::_tab_changed); + ObjectTypeDB::bind_method("_menu_option",&ShaderEditor::_menu_option); ObjectTypeDB::bind_method("_params_changed",&ShaderEditor::_params_changed); - ObjectTypeDB::bind_method("_close_callback",&ShaderEditor::_close_callback); ObjectTypeDB::bind_method("apply_shaders",&ShaderEditor::apply_shaders); // ObjectTypeDB::bind_method("_close_current_tab",&ShaderEditor::_close_current_tab); } @@ -441,16 +425,7 @@ void ShaderEditor::edit(const Ref& p_shader) { shader=p_shader; - if (shader->get_mode()==Shader::MODE_MATERIAL) { - vertex_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_MATERIAL_VERTEX); - fragment_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_MATERIAL_FRAGMENT); - light_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_LIGHT); - } else if (shader->get_mode()==Shader::MODE_CANVAS_ITEM) { - - vertex_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX); - fragment_editor->set_edited_shader(p_shader,ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT); - light_editor->set_edited_shader(shader,ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT); - } + shader_editor->set_edited_shader(p_shader); //vertex_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_VERTEX); // see if already has it @@ -474,35 +449,21 @@ void ShaderEditor::apply_shaders() { if (shader.is_valid()) { - shader->set_code(vertex_editor->get_text_edit()->get_text(),fragment_editor->get_text_edit()->get_text(),light_editor->get_text_edit()->get_text(),0,0); + shader->set_code(shader_editor->get_text_edit()->get_text()); shader->set_edited(true); } } -void ShaderEditor::_close_callback() { - - hide(); -} - ShaderEditor::ShaderEditor() { - tab_container = memnew( TabContainer ); - add_child(tab_container); - tab_container->set_area_as_parent_rect(); - tab_container->set_begin(Point2(0,0)); - //tab_container->set_begin(Point2(0,0)); - - close = memnew( TextureButton ); - close->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,20); - close->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,4); - close->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,2); - add_child(close); + HBoxContainer *hbc = memnew( HBoxContainer); + add_child(hbc); edit_menu = memnew( MenuButton ); - add_child(edit_menu); + hbc->add_child(edit_menu); edit_menu->set_pos(Point2(5,-1)); edit_menu->set_text(TTR("Edit")); edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/undo", TTR("Undo"), KEY_MASK_CMD|KEY_Z), EDIT_UNDO); @@ -517,7 +478,7 @@ ShaderEditor::ShaderEditor() { search_menu = memnew( MenuButton ); - add_child(search_menu); + hbc->add_child(search_menu); search_menu->set_pos(Point2(38,-1)); search_menu->set_text(TTR("Search")); search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find.."), KEY_MASK_CMD|KEY_F), SEARCH_FIND); @@ -530,34 +491,15 @@ ShaderEditor::ShaderEditor() { search_menu->get_popup()->connect("item_pressed", this,"_menu_option"); - tab_container->connect("tab_changed", this,"_tab_changed"); - - erase_tab_confirm = memnew( ConfirmationDialog ); - add_child(erase_tab_confirm); - erase_tab_confirm->connect("confirmed", this,"_close_current_tab"); - - goto_line_dialog = memnew(GotoLineDialog); add_child(goto_line_dialog); - vertex_editor = memnew( ShaderTextEditor ); - tab_container->add_child(vertex_editor); - vertex_editor->set_name(TTR("Vertex")); - - fragment_editor = memnew( ShaderTextEditor ); - tab_container->add_child(fragment_editor); - fragment_editor->set_name(TTR("Fragment")); - - light_editor = memnew( ShaderTextEditor ); - tab_container->add_child(light_editor); - light_editor->set_name(TTR("Lighting")); - - tab_container->set_current_tab(1); + shader_editor = memnew( ShaderTextEditor ); + add_child(shader_editor); + shader_editor->set_v_size_flags(SIZE_EXPAND_FILL); - vertex_editor->connect("script_changed", this,"apply_shaders"); - fragment_editor->connect("script_changed", this,"apply_shaders"); - light_editor->connect("script_changed", this,"apply_shaders"); + shader_editor->connect("script_changed", this,"apply_shaders"); EditorSettings::get_singleton()->connect("settings_changed",this,"_editor_settings_changed"); _editor_settings_changed(); @@ -567,15 +509,7 @@ ShaderEditor::ShaderEditor() { void ShaderEditorPlugin::edit(Object *p_object) { Shader* s = p_object->cast_to(); - if (!s || s->cast_to()) { - shader_editor->hide(); //Dont edit ShaderGraph - return; - } - - if (_2d && s->get_mode()==Shader::MODE_CANVAS_ITEM) - shader_editor->edit(s); - else if (!_2d && s->get_mode()==Shader::MODE_MATERIAL) - shader_editor->edit(s); + shader_editor->edit(s); } @@ -583,24 +517,25 @@ bool ShaderEditorPlugin::handles(Object *p_object) const { bool handles = true; Shader *shader=p_object->cast_to(); - if (!shader || shader->cast_to()) // Dont handle ShaderGraph's - handles = false; - if (handles && _2d) - handles = shader->get_mode()==Shader::MODE_CANVAS_ITEM; - else if (handles && !_2d) - return shader->get_mode()==Shader::MODE_MATERIAL; + //if (!shader || shader->cast_to()) // Dont handle ShaderGraph's + // handles = false; - if (!handles) - shader_editor->hide(); - return handles; + return shader!=NULL; } void ShaderEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - shader_editor->show(); + button->show(); + editor->make_bottom_panel_item_visible(shader_editor); + } else { + + button->hide(); + if (shader_editor->is_visible()) + editor->hide_bottom_panel(); shader_editor->apply_shaders(); + } } @@ -634,19 +569,14 @@ void ShaderEditorPlugin::apply_changes() { shader_editor->apply_shaders(); } -ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node, bool p_2d) { +ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) { + editor=p_node; shader_editor = memnew( ShaderEditor ); - _2d=p_2d; - if (p_2d) - add_control_to_container(CONTAINER_CANVAS_EDITOR_BOTTOM,shader_editor); - else - add_control_to_container(CONTAINER_SPATIAL_EDITOR_BOTTOM,shader_editor); -// editor->get_viewport()->add_child(shader_editor); -// shader_editor->set_area_as_parent_rect(); - shader_editor->hide(); + shader_editor->set_custom_minimum_size(Size2(0,300)); + button=editor->add_bottom_panel_item("Shader",shader_editor); } @@ -654,4 +584,4 @@ ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node, bool p_2d) { ShaderEditorPlugin::~ShaderEditorPlugin() { } -#endif + diff --git a/tools/editor/plugins/shader_editor_plugin.h b/tools/editor/plugins/shader_editor_plugin.h index ef7cc6772ec..ffe6a42e888 100644 --- a/tools/editor/plugins/shader_editor_plugin.h +++ b/tools/editor/plugins/shader_editor_plugin.h @@ -38,33 +38,34 @@ #include "scene/resources/shader.h" #include "servers/visual/shader_language.h" -#if 0 class ShaderTextEditor : public CodeTextEditor { OBJ_TYPE( ShaderTextEditor, CodeTextEditor ); Ref shader; - ShaderLanguage::ShaderType type; protected: static void _bind_methods(); virtual void _load_theme_settings(); + + virtual void _code_complete_script(const String& p_code, List* r_options); + public: virtual void _validate_script(); Ref get_edited_shader() const; - void set_edited_shader(const Ref& p_shader,ShaderLanguage::ShaderType p_type); + void set_edited_shader(const Ref& p_shader); ShaderTextEditor(); }; -class ShaderEditor : public Control { +class ShaderEditor : public VBoxContainer { - OBJ_TYPE(ShaderEditor, Control ); + OBJ_TYPE(ShaderEditor, VBoxContainer ); enum { @@ -88,22 +89,17 @@ class ShaderEditor : public Control { MenuButton *settings_menu; uint64_t idle; - TabContainer *tab_container; GotoLineDialog *goto_line_dialog; ConfirmationDialog *erase_tab_confirm; - TextureButton *close; - ShaderTextEditor *vertex_editor; - ShaderTextEditor *fragment_editor; - ShaderTextEditor *light_editor; + ShaderTextEditor *shader_editor; + - void _tab_changed(int p_which); void _menu_option(int p_optin); void _params_changed(); mutable Ref shader; - void _close_callback(); void _editor_settings_changed(); @@ -134,6 +130,8 @@ class ShaderEditorPlugin : public EditorPlugin { bool _2d; ShaderEditor *shader_editor; EditorNode *editor; + Button *button; + public: virtual String get_name() const { return "Shader"; } @@ -150,10 +148,9 @@ public: virtual void save_external_data(); virtual void apply_changes(); - ShaderEditorPlugin(EditorNode *p_node,bool p_2d); + ShaderEditorPlugin(EditorNode *p_node); ~ShaderEditorPlugin(); }; #endif -#endif