summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/tests/test_shader_lang.cpp261
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/shader.cpp2
-rw-r--r--scene/resources/shader.h8
-rw-r--r--servers/register_server_types.cpp8
-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
-rw-r--r--tools/editor/editor_node.cpp3
-rw-r--r--tools/editor/plugins/shader_editor_plugin.cpp238
-rw-r--r--tools/editor/plugins/shader_editor_plugin.h25
12 files changed, 1315 insertions, 497 deletions
diff --git a/bin/tests/test_shader_lang.cpp b/bin/tests/test_shader_lang.cpp
index 6c8132122c..1a677bcbe2 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) {
+ return ShaderLanguage::get_datatype_name(p_type);
+
+ return "";
+}
+
+
+static String _prestr(SL::DataPrecision p_pres) {
- 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: {}
- }
+ 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<SL::ConstantNode::Value>& 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<StringName,SL::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
+ for(Map<StringName,SL::ShaderNode::Uniform>::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<StringName,SL::ShaderNode::Varying>::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;i<pnode->functions.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<StringName,SL::DataType>::Element *E=bnode->variables.front();E;E=E->next()) {
+ code+=_mktab(p_level-1)+"{\n";
+ for(Map<StringName,SL::BlockNode::Variable>::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;i<bnode->statements.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="<error: "+Variant::get_type_name(cnode->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 <shader>");
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));
- if (err) {
+ Map<StringName,Map<StringName,SL::DataType> > dt;
+ dt["fragment"]["ALBEDO"]=SL::TYPE_VEC3;
- print_line("Error: "+itos(errline)+":"+itos(errcol)+" "+error);
- return NULL;
- }
+ Set<String> rm;
+ rm.insert("popo");
- print_line("Compile OK! - pretty printing");
+ Error err = sl.compile(code,dt,rm);
- String rcode;
- err = SL::compile(code,ShaderLanguage::SHADER_MATERIAL_FRAGMENT,recreate_code,&rcode,&error,&errline,&errcol);
+ if (err) {
- if (!err) {
- print_line(rcode);
+ 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);
}
-#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 1bff6801fe..ad845555a4 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -548,7 +548,7 @@ void register_scene_types() {
// ObjectTypeDB::register_type<ShaderMaterial>();
ObjectTypeDB::register_type<RoomBounds>();
// ObjectTypeDB::register_type<MaterialShaderGraph>();
- ObjectTypeDB::register_type<MaterialShader>();
+ ObjectTypeDB::register_type<SpatialShader>();
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 b6c8fcf7a1..8889d1b6f8 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 988305b654..eddb98333d 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 06eaa4d122..19ee3a48c7 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<ScriptDebuggerRemote::ResourceUsage>* r_usage) {
List<VS::TextureInfo> tinfo;
@@ -55,6 +55,8 @@ static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsag
}
+ShaderTypes *shader_types=NULL;
+
void register_server_types() {
Globals::get_singleton()->add_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<Physics2DDirectBodyState>();
ObjectTypeDB::register_virtual_type<Physics2DDirectSpaceState>();
@@ -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 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
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index 9b5ed422c5..a4ee102aed 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 5541ae987f..9c8aa3c85d 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<Shader> ShaderTextEditor::get_edited_shader() const {
return shader;
}
-void ShaderTextEditor::set_edited_shader(const Ref<Shader>& p_shader,ShaderLanguage::ShaderType p_type) {
+void ShaderTextEditor::set_edited_shader(const Ref<Shader>& 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<String> keywords;
- ShaderLanguage::get_keyword_list(type,&keywords);
+ ShaderLanguage::get_keyword_list(&keywords);
+
+ if (shader.is_valid()) {
+
+
+ for(const Map< StringName, Map<StringName,ShaderLanguage::DataType> >::Element *E=ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())).front();E;E=E->next()) {
+
+ for (const Map<StringName,ShaderLanguage::DataType>::Element *F=E->get().front();F;F=F->next()) {
+ keywords.push_back(F->key());
+ }
+
+ }
+
+ for(const Set<String>::Element *E =ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())).front();E;E=E->next()) {
+
+ keywords.push_back(E->get());
+
+ }
+ }
for(List<String>::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<String>* r_options) {
-void ShaderTextEditor::_validate_script() {
+ print_line("code complete");
- String errortxt;
- int line,col;
+ 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 code=get_text_edit()->get_text();
//List<StringName> params;
//shader->get_param_list(&params);
- 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;i<get_text_edit()->get_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<ShaderTextEditor>();
- 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<ShaderTextEditor>();
-
- 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"));
-
- 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"));
+ 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"));
+
}
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<Shader>& 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"));
+ shader_editor = memnew( ShaderTextEditor );
+ add_child(shader_editor);
+ shader_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- light_editor = memnew( ShaderTextEditor );
- tab_container->add_child(light_editor);
- light_editor->set_name(TTR("Lighting"));
- tab_container->set_current_tab(1);
-
-
- 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<Shader>();
- if (!s || s->cast_to<ShaderGraph>()) {
- 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<Shader>();
- if (!shader || shader->cast_to<ShaderGraph>()) // 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 (!handles)
- shader_editor->hide();
- return handles;
+ //if (!shader || shader->cast_to<ShaderGraph>()) // Dont handle ShaderGraph's
+ // handles = false;
+
+ 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 ef7cc6772e..ffe6a42e88 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> shader;
- ShaderLanguage::ShaderType type;
protected:
static void _bind_methods();
virtual void _load_theme_settings();
+
+ virtual void _code_complete_script(const String& p_code, List<String>* r_options);
+
public:
virtual void _validate_script();
Ref<Shader> get_edited_shader() const;
- void set_edited_shader(const Ref<Shader>& p_shader,ShaderLanguage::ShaderType p_type);
+ void set_edited_shader(const Ref<Shader>& 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> 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