Backport 6f16239 "Implementation of struct for shaders" to 3.4

This commit is contained in:
Lyuma 2020-08-25 23:11:57 -07:00
parent 74174676b8
commit fc6bee0750
7 changed files with 651 additions and 165 deletions

View file

@ -1574,6 +1574,9 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn
pi.name = E->get(); pi.name = E->get();
switch (u.type) { switch (u.type) {
case ShaderLanguage::TYPE_STRUCT: {
pi.type = Variant::ARRAY;
} break;
case ShaderLanguage::TYPE_VOID: { case ShaderLanguage::TYPE_VOID: {
pi.type = Variant::NIL; pi.type = Variant::NIL;
} break; } break;

View file

@ -243,22 +243,22 @@ void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const Stri
r_to_add += "\n"; r_to_add += "\n";
StringBuffer<128> header; StringBuffer<128> header;
if (fnode->return_type == SL::TYPE_STRUCT) {
header += _typestr(fnode->return_type); header += _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "(";
header += " "; } else {
header += _mkid(fnode->name); header += _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
header += "("; }
for (int i = 0; i < fnode->arguments.size(); i++) { for (int i = 0; i < fnode->arguments.size(); i++) {
if (i > 0) { if (i > 0) {
header += ", "; header += ", ";
} }
header += _qualstr(fnode->arguments[i].qualifier); if (fnode->arguments[i].type == SL::TYPE_STRUCT) {
header += _prestr(fnode->arguments[i].precision); header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name);
header += _typestr(fnode->arguments[i].type); } else {
header += " "; header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
header += _mkid(fnode->arguments[i].name); }
} }
header += ")\n"; header += ")\n";
@ -311,6 +311,35 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
StringBuilder vertex_global; StringBuilder vertex_global;
StringBuilder fragment_global; StringBuilder fragment_global;
// structs
for (int i = 0; i < snode->vstructs.size(); i++) {
SL::StructNode *st = snode->vstructs[i].shader_struct;
String struct_code;
struct_code += "struct ";
struct_code += _mkid(snode->vstructs[i].name);
struct_code += " ";
struct_code += "{\n";
for (int j = 0; j < st->members.size(); j++) {
SL::MemberNode *m = st->members[j];
if (m->datatype == SL::TYPE_STRUCT) {
struct_code += _mkid(m->struct_name);
} else {
struct_code += _prestr(m->precision);
struct_code += _typestr(m->datatype);
}
struct_code += " ";
struct_code += m->name;
struct_code += ";\n";
}
struct_code += "}";
struct_code += ";\n";
vertex_global += struct_code;
fragment_global += struct_code;
}
// uniforms // uniforms
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) { for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) {
@ -370,8 +399,12 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
for (int i = 0; i < snode->vconstants.size(); i++) { for (int i = 0; i < snode->vconstants.size(); i++) {
String gcode; String gcode;
gcode += "const "; gcode += "const ";
if (snode->vconstants[i].type == SL::TYPE_STRUCT) {
gcode += _mkid(snode->vconstants[i].type_str);
} else {
gcode += _prestr(snode->vconstants[i].precision); gcode += _prestr(snode->vconstants[i].precision);
gcode += _typestr(snode->vconstants[i].type); gcode += _typestr(snode->vconstants[i].type);
}
gcode += " " + _mkid(String(snode->vconstants[i].name)); gcode += " " + _mkid(String(snode->vconstants[i].name));
gcode += "="; gcode += "=";
gcode += _dump_node_code(snode->vconstants[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); gcode += _dump_node_code(snode->vconstants[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
@ -416,7 +449,8 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
r_gen_code.fragment_global = fragment_global.as_string(); r_gen_code.fragment_global = fragment_global.as_string();
} break; } break;
case SL::Node::TYPE_STRUCT: {
} break;
case SL::Node::TYPE_FUNCTION: { case SL::Node::TYPE_FUNCTION: {
} break; } break;
@ -453,8 +487,12 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
if (var_dec_node->is_const) { if (var_dec_node->is_const) {
declaration += "const "; declaration += "const ";
} }
if (var_dec_node->datatype == SL::TYPE_STRUCT) {
declaration += _mkid(var_dec_node->struct_name);
} else {
declaration += _prestr(var_dec_node->precision); declaration += _prestr(var_dec_node->precision);
declaration += _typestr(var_dec_node->datatype); declaration += _typestr(var_dec_node->datatype);
}
for (int i = 0; i < var_dec_node->declarations.size(); i++) { for (int i = 0; i < var_dec_node->declarations.size(); i++) {
if (i > 0) { if (i > 0) {
@ -519,9 +557,12 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node;
StringBuffer<> declaration; StringBuffer<> declaration;
if (arr_dec_node->datatype == SL::TYPE_STRUCT) {
declaration += _mkid(arr_dec_node->struct_name);
} else {
declaration += _prestr(arr_dec_node->precision); declaration += _prestr(arr_dec_node->precision);
declaration += _typestr(arr_dec_node->datatype); declaration += _typestr(arr_dec_node->datatype);
}
for (int i = 0; i < arr_dec_node->declarations.size(); i++) { for (int i = 0; i < arr_dec_node->declarations.size(); i++) {
if (i > 0) { if (i > 0) {
declaration += ","; declaration += ",";
@ -640,12 +681,14 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
} break; } break;
case SL::OP_CALL: case SL::OP_CALL:
case SL::OP_STRUCT:
case SL::OP_CONSTRUCT: { case SL::OP_CONSTRUCT: {
ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String()); ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0]; SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0];
if (op_node->op == SL::OP_STRUCT) {
if (op_node->op == SL::OP_CONSTRUCT) { code += _mkid(var_node->name);
} else if (op_node->op == SL::OP_CONSTRUCT) {
code += var_node->name; code += var_node->name;
} else { } else {
if (var_node->name == "texture") { if (var_node->name == "texture") {

View file

@ -2355,6 +2355,9 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn
ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[E->get()]; ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[E->get()];
pi.name = E->get(); pi.name = E->get();
switch (u.type) { switch (u.type) {
case ShaderLanguage::TYPE_STRUCT:
pi.type = Variant::ARRAY;
break;
case ShaderLanguage::TYPE_VOID: case ShaderLanguage::TYPE_VOID:
pi.type = Variant::NIL; pi.type = Variant::NIL;
break; break;

View file

@ -112,6 +112,8 @@ static int _get_datatype_size(SL::DataType p_type) {
return 16; return 16;
case SL::TYPE_SAMPLEREXT: case SL::TYPE_SAMPLEREXT:
return 16; return 16;
case SL::TYPE_STRUCT:
return 0;
} }
ERR_FAIL_V(0); ERR_FAIL_V(0);
@ -181,6 +183,8 @@ static int _get_datatype_alignment(SL::DataType p_type) {
return 16; return 16;
case SL::TYPE_SAMPLEREXT: case SL::TYPE_SAMPLEREXT:
return 16; return 16;
case SL::TYPE_STRUCT:
return 0;
} }
ERR_FAIL_V(0); ERR_FAIL_V(0);
@ -360,13 +364,21 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri
r_to_add += "\n"; r_to_add += "\n";
String header; String header;
if (fnode->return_type == SL::TYPE_STRUCT) {
header = _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "(";
} else {
header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "("; header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
}
for (int i = 0; i < fnode->arguments.size(); i++) { for (int i = 0; i < fnode->arguments.size(); i++) {
if (i > 0) { if (i > 0) {
header += ", "; header += ", ";
} }
if (fnode->arguments[i].type == SL::TYPE_STRUCT) {
header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name);
} else {
header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name); header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
} }
}
header += ")\n"; header += ")\n";
r_to_add += header; r_to_add += header;
@ -399,6 +411,35 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
} }
} }
// structs
for (int i = 0; i < pnode->vstructs.size(); i++) {
SL::StructNode *st = pnode->vstructs[i].shader_struct;
String struct_code;
struct_code += "struct ";
struct_code += _mkid(pnode->vstructs[i].name);
struct_code += " ";
struct_code += "{\n";
for (int j = 0; j < st->members.size(); j++) {
SL::MemberNode *m = st->members[j];
if (m->datatype == SL::TYPE_STRUCT) {
struct_code += _mkid(m->struct_name);
} else {
struct_code += _prestr(m->precision);
struct_code += _typestr(m->datatype);
}
struct_code += " ";
struct_code += m->name;
struct_code += ";\n";
}
struct_code += "}";
struct_code += ";\n";
r_gen_code.vertex_global += struct_code;
r_gen_code.fragment_global += struct_code;
}
int max_texture_uniforms = 0; int max_texture_uniforms = 0;
int max_uniforms = 0; int max_uniforms = 0;
@ -494,8 +535,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
for (int i = 0; i < pnode->vconstants.size(); i++) { for (int i = 0; i < pnode->vconstants.size(); i++) {
String gcode; String gcode;
gcode += "const "; gcode += "const ";
if (pnode->vconstants[i].type == SL::TYPE_STRUCT) {
gcode += _mkid(pnode->vconstants[i].type_str);
} else {
gcode += _prestr(pnode->vconstants[i].precision); gcode += _prestr(pnode->vconstants[i].precision);
gcode += _typestr(pnode->vconstants[i].type); gcode += _typestr(pnode->vconstants[i].type);
}
gcode += " " + _mkid(String(pnode->vconstants[i].name)); gcode += " " + _mkid(String(pnode->vconstants[i].name));
gcode += "="; gcode += "=";
gcode += _dump_node_code(pnode->vconstants[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); gcode += _dump_node_code(pnode->vconstants[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
@ -541,6 +586,8 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
//code+=dump_node_code(pnode->body,p_level); //code+=dump_node_code(pnode->body,p_level);
} break; } break;
case SL::Node::TYPE_STRUCT: {
} break;
case SL::Node::TYPE_FUNCTION: { case SL::Node::TYPE_FUNCTION: {
} break; } break;
case SL::Node::TYPE_BLOCK: { case SL::Node::TYPE_BLOCK: {
@ -572,8 +619,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
if (vdnode->is_const) { if (vdnode->is_const) {
declaration += "const "; declaration += "const ";
} }
if (vdnode->datatype == SL::TYPE_STRUCT) {
declaration += _mkid(vdnode->struct_name);
} else {
declaration += _prestr(vdnode->precision); declaration += _prestr(vdnode->precision);
declaration += _typestr(vdnode->datatype); declaration += _typestr(vdnode->datatype);
}
for (int i = 0; i < vdnode->declarations.size(); i++) { for (int i = 0; i < vdnode->declarations.size(); i++) {
if (i > 0) { if (i > 0) {
declaration += ","; declaration += ",";
@ -633,8 +684,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
if (adnode->is_const) { if (adnode->is_const) {
declaration += "const "; declaration += "const ";
} }
if (adnode->datatype == SL::TYPE_STRUCT) {
declaration += _mkid(adnode->struct_name);
} else {
declaration += _prestr(adnode->precision); declaration += _prestr(adnode->precision);
declaration += _typestr(adnode->datatype); declaration += _typestr(adnode->datatype);
}
for (int i = 0; i < adnode->declarations.size(); i++) { for (int i = 0; i < adnode->declarations.size(); i++) {
if (i > 0) { if (i > 0) {
declaration += ","; declaration += ",";
@ -648,7 +703,11 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
int sz = adnode->declarations[i].initializer.size(); int sz = adnode->declarations[i].initializer.size();
if (sz > 0) { if (sz > 0) {
declaration += "="; declaration += "=";
if (adnode->datatype == SL::TYPE_STRUCT) {
declaration += _mkid(adnode->struct_name);
} else {
declaration += _typestr(adnode->datatype); declaration += _typestr(adnode->datatype);
}
declaration += "["; declaration += "[";
declaration += itos(sz); declaration += itos(sz);
declaration += "]"; declaration += "]";
@ -747,12 +806,15 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op); code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op);
break; break;
case SL::OP_CALL: case SL::OP_CALL:
case SL::OP_STRUCT:
case SL::OP_CONSTRUCT: { case SL::OP_CONSTRUCT: {
ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String()); ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0]; SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0];
if (onode->op == SL::OP_CONSTRUCT) { if (onode->op == SL::OP_STRUCT) {
code += _mkid(vnode->name);
} else if (onode->op == SL::OP_CONSTRUCT) {
code += String(vnode->name); code += String(vnode->name);
} else { } else {
if (internal_functions.has(vnode->name)) { if (internal_functions.has(vnode->name)) {

View file

@ -174,6 +174,8 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
//code+=dump_node_code(pnode->body,p_level); //code+=dump_node_code(pnode->body,p_level);
} break; } break;
case SL::Node::TYPE_STRUCT: {
} break;
case SL::Node::TYPE_FUNCTION: { case SL::Node::TYPE_FUNCTION: {
} break; } break;
case SL::Node::TYPE_BLOCK: { case SL::Node::TYPE_BLOCK: {

View file

@ -271,6 +271,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_INTERPOLATION_FLAT, "flat" }, { TK_INTERPOLATION_FLAT, "flat" },
{ TK_INTERPOLATION_SMOOTH, "smooth" }, { TK_INTERPOLATION_SMOOTH, "smooth" },
{ TK_CONST, "const" }, { TK_CONST, "const" },
{ TK_STRUCT, "struct" },
{ TK_PRECISION_LOW, "lowp" }, { TK_PRECISION_LOW, "lowp" },
{ TK_PRECISION_MID, "mediump" }, { TK_PRECISION_MID, "mediump" },
{ TK_PRECISION_HIGH, "highp" }, { TK_PRECISION_HIGH, "highp" },
@ -858,6 +859,8 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
return "samplerCube"; return "samplerCube";
case TYPE_SAMPLEREXT: case TYPE_SAMPLEREXT:
return "samplerExternalOES"; return "samplerExternalOES";
case TYPE_STRUCT:
return "struct";
} }
return ""; return "";
@ -874,6 +877,7 @@ void ShaderLanguage::clear() {
completion_block = nullptr; completion_block = nullptr;
completion_function = StringName(); completion_function = StringName();
completion_class = SubClassTag::TAG_GLOBAL; completion_class = SubClassTag::TAG_GLOBAL;
completion_struct = StringName();
error_line = 0; error_line = 0;
tk_line = 1; tk_line = 1;
@ -887,7 +891,7 @@ void ShaderLanguage::clear() {
} }
} }
bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size) { bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
if (p_builtin_types.has(p_identifier)) { if (p_builtin_types.has(p_identifier)) {
if (r_data_type) { if (r_data_type) {
*r_data_type = p_builtin_types[p_identifier].type; *r_data_type = p_builtin_types[p_identifier].type;
@ -918,6 +922,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
if (r_type) { if (r_type) {
*r_type = IDENTIFIER_LOCAL_VAR; *r_type = IDENTIFIER_LOCAL_VAR;
} }
if (r_struct_name) {
*r_struct_name = p_block->variables[p_identifier].struct_name;
}
return true; return true;
} }
@ -940,7 +947,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
if (r_type) { if (r_type) {
*r_type = IDENTIFIER_FUNCTION_ARGUMENT; *r_type = IDENTIFIER_FUNCTION_ARGUMENT;
} }
if (r_struct_name) {
*r_struct_name = function->arguments[i].type_str;
}
return true; return true;
} }
} }
@ -976,6 +985,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
if (r_type) { if (r_type) {
*r_type = IDENTIFIER_CONSTANT; *r_type = IDENTIFIER_CONSTANT;
} }
if (r_struct_name) {
*r_struct_name = shader->constants[p_identifier].type_str;
}
return true; return true;
} }
@ -1219,7 +1231,11 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
case OP_ASSIGN: { case OP_ASSIGN: {
DataType na = p_op->arguments[0]->get_datatype(); DataType na = p_op->arguments[0]->get_datatype();
DataType nb = p_op->arguments[1]->get_datatype(); DataType nb = p_op->arguments[1]->get_datatype();
if (na == TYPE_STRUCT || nb == TYPE_STRUCT) {
valid = p_op->arguments[0]->get_datatype_name() == p_op->arguments[1]->get_datatype_name();
} else {
valid = na == nb; valid = na == nb;
}
ret_type = na; ret_type = na;
} break; } break;
case OP_ASSIGN_ADD: case OP_ASSIGN_ADD:
@ -2092,10 +2108,11 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[]
{ nullptr, 0 } { nullptr, 0 }
}; };
bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type) { bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false); ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
Vector<DataType> args; Vector<DataType> args;
Vector<StringName> args2;
ERR_FAIL_COND_V(p_func->arguments[0]->type != Node::TYPE_VARIABLE, false); ERR_FAIL_COND_V(p_func->arguments[0]->type != Node::TYPE_VARIABLE, false);
@ -2103,6 +2120,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p
for (int i = 1; i < p_func->arguments.size(); i++) { for (int i = 1; i < p_func->arguments.size(); i++) {
args.push_back(p_func->arguments[i]->get_datatype()); args.push_back(p_func->arguments[i]->get_datatype());
args2.push_back(p_func->arguments[i]->get_datatype_name());
} }
int argcount = args.size(); int argcount = args.size();
@ -2285,6 +2303,10 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p
bool fail = false; bool fail = false;
for (int j = 0; j < args.size(); j++) { for (int j = 0; j < args.size(); j++) {
if (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) {
fail = true;
break;
}
if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) { if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
//all good, but it needs implicit conversion later //all good, but it needs implicit conversion later
} else if (args[j] != pfunc->arguments[j].type) { } else if (args[j] != pfunc->arguments[j].type) {
@ -2314,6 +2336,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p
if (r_ret_type) { if (r_ret_type) {
*r_ret_type = pfunc->return_type; *r_ret_type = pfunc->return_type;
if (pfunc->return_type == TYPE_STRUCT) {
*r_ret_type_str = pfunc->return_struct_name;
}
} }
return true; return true;
} }
@ -2322,6 +2347,18 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p
return false; return false;
} }
bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
if (a->get_datatype() != b->get_datatype()) {
return false;
}
if (a->get_datatype() == TYPE_STRUCT || b->get_datatype() == TYPE_STRUCT) {
if (a->get_datatype_name() != b->get_datatype_name()) {
return false;
}
}
return true;
}
bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) { bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) {
TkPos pos = _get_tkpos(); TkPos pos = _get_tkpos();
Token tk = _get_token(); Token tk = _get_token();
@ -2557,6 +2594,8 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
// Texture types, likely not relevant here. // Texture types, likely not relevant here.
break; break;
} }
case ShaderLanguage::TYPE_STRUCT:
break;
case ShaderLanguage::TYPE_VOID: case ShaderLanguage::TYPE_VOID:
break; break;
} }
@ -2897,7 +2936,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr; return nullptr;
} }
if (!_validate_function_call(p_block, func, &func->return_cache)) { if (!_validate_function_call(p_block, func, &func->return_cache, &func->struct_name)) {
_set_error("No matching constructor found for: '" + String(funcname->name) + "'"); _set_error("No matching constructor found for: '" + String(funcname->name) + "'");
return nullptr; return nullptr;
} }
@ -2909,11 +2948,63 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
StringName identifier; StringName identifier;
StructNode *pstruct = nullptr;
bool struct_init = false;
_get_completable_identifier(p_block, COMPLETION_IDENTIFIER, identifier); _get_completable_identifier(p_block, COMPLETION_IDENTIFIER, identifier);
if (shader->structs.has(identifier)) {
pstruct = shader->structs[identifier].shader_struct;
struct_init = true;
}
tk = _get_token(); tk = _get_token();
if (tk.type == TK_PARENTHESIS_OPEN) { if (tk.type == TK_PARENTHESIS_OPEN) {
//a function if (struct_init) { //a struct constructor
const StringName &name = identifier;
OperatorNode *func = alloc_node<OperatorNode>();
func->op = OP_STRUCT;
func->struct_name = name;
func->return_cache = TYPE_STRUCT;
VariableNode *funcname = alloc_node<VariableNode>();
funcname->name = name;
func->arguments.push_back(funcname);
for (int i = 0; i < pstruct->members.size(); i++) {
Node *nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
if (!nexpr) {
return nullptr;
}
Node *node = pstruct->members[i];
if (!_compare_datatypes_in_nodes(pstruct->members[i], nexpr)) {
String type_name = nexpr->get_datatype() == TYPE_STRUCT ? nexpr->get_datatype_name() : get_datatype_name(nexpr->get_datatype());
String type_name2 = node->get_datatype() == TYPE_STRUCT ? node->get_datatype_name() : get_datatype_name(node->get_datatype());
_set_error("Invalid assignment of '" + type_name + "' to '" + type_name2 + "'");
return nullptr;
}
if (i + 1 < pstruct->members.size()) {
tk = _get_token();
if (tk.type != TK_COMMA) {
_set_error("Expected ','");
return nullptr;
}
}
func->arguments.push_back(nexpr);
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
_set_error("Expected ')'");
return nullptr;
}
expr = func;
} else { //a function
const StringName &name = identifier; const StringName &name = identifier;
OperatorNode *func = alloc_node<OperatorNode>(); OperatorNode *func = alloc_node<OperatorNode>();
@ -2946,6 +3037,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
break; break;
} }
} }
function_index = i; function_index = i;
break; break;
} }
@ -2963,7 +3055,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr; return nullptr;
} }
if (!_validate_function_call(p_block, func, &func->return_cache)) { if (!_validate_function_call(p_block, func, &func->return_cache, &func->struct_name)) {
_set_error("No matching function found for: '" + String(funcname->name) + "'"); _set_error("No matching function found for: '" + String(funcname->name) + "'");
return nullptr; return nullptr;
} }
@ -3018,7 +3110,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} }
expr = func; expr = func;
}
} else { } else {
//an identifier //an identifier
@ -3028,6 +3120,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
IdentifierType ident_type; IdentifierType ident_type;
bool is_const = false; bool is_const = false;
int array_size = 0; int array_size = 0;
StringName struct_name;
if (p_block && p_block->block_tag != SubClassTag::TAG_GLOBAL) { if (p_block && p_block->block_tag != SubClassTag::TAG_GLOBAL) {
int idx = 0; int idx = 0;
@ -3045,7 +3138,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr; return nullptr;
} }
} else { } else {
if (!_find_identifier(p_block, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size)) { if (!_find_identifier(p_block, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
_set_error("Unknown identifier in expression: " + String(identifier)); _set_error("Unknown identifier in expression: " + String(identifier));
return nullptr; return nullptr;
} }
@ -3111,6 +3204,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
ArrayNode *arrname = alloc_node<ArrayNode>(); ArrayNode *arrname = alloc_node<ArrayNode>();
arrname->name = identifier; arrname->name = identifier;
arrname->datatype_cache = data_type; arrname->datatype_cache = data_type;
arrname->struct_name = struct_name;
arrname->index_expression = index_expression; arrname->index_expression = index_expression;
arrname->call_expression = call_expression; arrname->call_expression = call_expression;
arrname->is_const = is_const; arrname->is_const = is_const;
@ -3121,6 +3215,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
varname->name = identifier; varname->name = identifier;
varname->datatype_cache = data_type; varname->datatype_cache = data_type;
varname->is_const = is_const; varname->is_const = is_const;
varname->struct_name = struct_name;
expr = varname; expr = varname;
} }
} }
@ -3172,22 +3267,47 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_CURSOR) { if (tk.type == TK_CURSOR) {
//do nothing //do nothing
} else if (tk.type == TK_IDENTIFIER) {
} else if (tk.type == TK_PERIOD) { } else if (tk.type == TK_PERIOD) {
DataType dt = expr->get_datatype();
String st = expr->get_datatype_name();
StringName identifier; StringName identifier;
if (_get_completable_identifier(p_block, COMPLETION_INDEX, identifier)) { if (_get_completable_identifier(p_block, dt == TYPE_STRUCT ? COMPLETION_STRUCT : COMPLETION_INDEX, identifier)) {
completion_base = expr->get_datatype(); if (dt == TYPE_STRUCT) {
completion_struct = st;
} else {
completion_base = dt;
}
} }
if (identifier == StringName()) { if (identifier == StringName()) {
_set_error("Expected identifier as member"); _set_error("Expected identifier as member");
return nullptr; return nullptr;
} }
DataType dt = expr->get_datatype();
String ident = identifier; String ident = identifier;
bool ok = true; bool ok = true;
DataType member_type = TYPE_VOID; DataType member_type = TYPE_VOID;
StringName member_struct_name = "";
switch (dt) { switch (dt) {
case TYPE_STRUCT: {
ok = false;
String member_name = String(ident.ptr());
if (shader->structs.has(st)) {
StructNode *n = shader->structs[st].shader_struct;
for (List<MemberNode *>::Element *E = n->members.front(); E; E = E->next()) {
if (String(E->get()->name) == member_name) {
member_type = E->get()->datatype;
if (member_type == TYPE_STRUCT) {
member_struct_name = E->get()->struct_name;
}
ok = true;
break;
}
}
}
} break;
case TYPE_BVEC2: case TYPE_BVEC2:
case TYPE_IVEC2: case TYPE_IVEC2:
case TYPE_UVEC2: case TYPE_UVEC2:
@ -3300,13 +3420,15 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} }
if (!ok) { if (!ok) {
_set_error("Invalid member for " + get_datatype_name(dt) + " expression: ." + ident); _set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident);
return nullptr; return nullptr;
} }
MemberNode *mn = alloc_node<MemberNode>(); MemberNode *mn = alloc_node<MemberNode>();
mn->basetype = dt; mn->basetype = dt;
mn->datatype = member_type; mn->datatype = member_type;
mn->base_struct_name = st;
mn->struct_name = member_struct_name;
mn->name = ident; mn->name = ident;
mn->owner = expr; mn->owner = expr;
expr = mn; expr = mn;
@ -3872,8 +3994,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (i > 0) { if (i > 0) {
at += " and "; at += " and ";
} }
if (op->arguments[i]->get_datatype() == TYPE_STRUCT) {
at += op->arguments[i]->get_datatype_name();
} else {
at += get_datatype_name(op->arguments[i]->get_datatype()); at += get_datatype_name(op->arguments[i]->get_datatype());
} }
}
_set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at); _set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at);
return nullptr; return nullptr;
} }
@ -4019,6 +4145,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} }
} }
bool is_struct = shader->structs.has(tk.text);
if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block
if (p_just_one) { if (p_just_one) {
_set_error("Unexpected '}'"); _set_error("Unexpected '}'");
@ -4027,30 +4155,49 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
return OK; return OK;
} else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type)) { } else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type) || is_struct) {
String struct_name = "";
if (is_struct) {
struct_name = tk.text;
}
bool is_const = false; bool is_const = false;
if (tk.type == TK_CONST) { if (tk.type == TK_CONST) {
is_const = true; is_const = true;
tk = _get_token(); tk = _get_token();
if (!is_struct) {
is_struct = shader->structs.has(tk.text); // check again.
struct_name = tk.text;
}
} }
DataPrecision precision = PRECISION_DEFAULT; DataPrecision precision = PRECISION_DEFAULT;
if (is_token_precision(tk.type)) { if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type); precision = get_token_precision(tk.type);
tk = _get_token(); tk = _get_token();
if (!is_struct) {
is_struct = shader->structs.has(tk.text); // check again.
}
if (is_struct && precision != PRECISION_DEFAULT) {
_set_error("Precision modifier cannot be used on structs.");
return ERR_PARSE_ERROR;
}
if (!is_token_nonvoid_datatype(tk.type)) { if (!is_token_nonvoid_datatype(tk.type)) {
_set_error("Expected datatype after precision"); _set_error("Expected datatype after precision");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
} }
if (!is_struct) {
if (!is_token_variable_datatype(tk.type)) { if (!is_token_variable_datatype(tk.type)) {
_set_error("Invalid data type for variable (samplers not allowed)"); _set_error("Invalid data type for variable (samplers not allowed)");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
}
DataType type = get_token_datatype(tk.type); DataType type = is_struct ? TYPE_STRUCT : get_token_datatype(tk.type);
if (_validate_datatype(type) != OK) { if (_validate_datatype(type) != OK) {
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
@ -4081,6 +4228,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
var.line = tk_line; var.line = tk_line;
var.array_size = 0; var.array_size = 0;
var.is_const = is_const; var.is_const = is_const;
var.struct_name = struct_name;
tk = _get_token(); tk = _get_token();
@ -4093,7 +4241,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} }
ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>(); ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>();
if (is_struct) {
node->struct_name = struct_name;
node->datatype = TYPE_STRUCT;
} else {
node->datatype = type; node->datatype = type;
}
node->precision = precision; node->precision = precision;
node->is_const = is_const; node->is_const = is_const;
vardecl = (Node *)node; vardecl = (Node *)node;
@ -4145,16 +4298,29 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
if (is_token_precision(tk.type)) { if (is_token_precision(tk.type)) {
precision2 = get_token_precision(tk.type); precision2 = get_token_precision(tk.type);
tk = _get_token(); tk = _get_token();
if (shader->structs.has(tk.text)) {
_set_error("Precision modifier cannot be used on structs.");
return ERR_PARSE_ERROR;
}
if (!is_token_nonvoid_datatype(tk.type)) { if (!is_token_nonvoid_datatype(tk.type)) {
_set_error("Expected datatype after precision"); _set_error("Expected datatype after precision");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
} }
DataType type2;
String struct_name2 = "";
if (shader->structs.has(tk.text)) {
type2 = TYPE_STRUCT;
struct_name2 = tk.text;
} else {
if (!is_token_variable_datatype(tk.type)) { if (!is_token_variable_datatype(tk.type)) {
_set_error("Invalid data type for array"); _set_error("Invalid data type for array");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
DataType type2 = get_token_datatype(tk.type); type2 = get_token_datatype(tk.type);
}
int array_size2 = 0; int array_size2 = 0;
@ -4199,13 +4365,17 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
if (precision != precision2 || type != type2 || var.array_size != array_size2) { if (precision != precision2 || type != type2 || struct_name != struct_name2 || var.array_size != array_size2) {
String error_str = "Cannot convert from '"; String error_str = "Cannot convert from '";
if (precision2 != PRECISION_DEFAULT) { if (precision2 != PRECISION_DEFAULT) {
error_str += get_precision_name(precision2); error_str += get_precision_name(precision2);
error_str += " "; error_str += " ";
} }
if (type2 == TYPE_STRUCT) {
error_str += struct_name2;
} else {
error_str += get_datatype_name(type2); error_str += get_datatype_name(type2);
}
error_str += "["; error_str += "[";
error_str += itos(array_size2); error_str += itos(array_size2);
error_str += "]'"; error_str += "]'";
@ -4214,7 +4384,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
error_str += get_precision_name(precision); error_str += get_precision_name(precision);
error_str += " "; error_str += " ";
} }
if (type == TYPE_STRUCT) {
error_str += struct_name;
} else {
error_str += get_datatype_name(type); error_str += get_datatype_name(type);
}
error_str += "["; error_str += "[";
error_str += itos(var.array_size); error_str += itos(var.array_size);
error_str += "]'"; error_str += "]'";
@ -4251,8 +4425,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
if (var.type != n->get_datatype()) { if (var.type != n->get_datatype() || struct_name != n->get_datatype_name()) {
_set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(var.type) + "'"); _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? struct_name : get_datatype_name(var.type)) + "'");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
@ -4298,7 +4472,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
node->declarations.push_back(decl); node->declarations.push_back(decl);
} else if (tk.type == TK_OP_ASSIGN) { } else if (tk.type == TK_OP_ASSIGN) {
VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
if (is_struct) {
node->struct_name = struct_name;
node->datatype = TYPE_STRUCT;
} else {
node->datatype = type; node->datatype = type;
}
node->precision = precision; node->precision = precision;
node->is_const = is_const; node->is_const = is_const;
vardecl = (Node *)node; vardecl = (Node *)node;
@ -4318,8 +4497,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} }
decl.initializer = n; decl.initializer = n;
if (var.type != n->get_datatype()) { if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) {
_set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(var.type) + "'"); _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
tk = _get_token(); tk = _get_token();
@ -4331,7 +4510,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} }
VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
if (is_struct) {
node->struct_name = struct_name;
node->datatype = TYPE_STRUCT;
} else {
node->datatype = type; node->datatype = type;
}
node->precision = precision; node->precision = precision;
vardecl = (Node *)node; vardecl = (Node *)node;
@ -5001,6 +5185,107 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} }
} }
} break; } break;
case TK_STRUCT: {
ShaderNode::Struct st;
DataType type;
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
st.name = tk.text;
tk = _get_token();
if (tk.type != TK_CURLY_BRACKET_OPEN) {
_set_error("Expected '{'");
return ERR_PARSE_ERROR;
}
} else {
_set_error("Expected struct identifier!");
return ERR_PARSE_ERROR;
}
StructNode *st_node = alloc_node<StructNode>();
st.shader_struct = st_node;
int member_count = 0;
while (true) { // variables list
tk = _get_token();
if (tk.type == TK_CURLY_BRACKET_CLOSE) {
break;
}
StringName struct_name = "";
bool struct_dt = false;
bool use_precision = false;
DataPrecision precision = DataPrecision::PRECISION_DEFAULT;
if (tk.type == TK_STRUCT) {
_set_error("nested structs are not allowed!");
return ERR_PARSE_ERROR;
}
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
use_precision = true;
tk = _get_token();
}
if (shader->structs.has(tk.text)) {
struct_name = tk.text;
struct_dt = true;
if (use_precision) {
_set_error("Precision modifier cannot be used on structs.");
return ERR_PARSE_ERROR;
}
}
if (!is_token_datatype(tk.type) && !struct_dt) {
_set_error("Expected datatype.");
return ERR_PARSE_ERROR;
} else {
type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
if (is_sampler_type(type)) {
_set_error("sampler datatype not allowed here");
return ERR_PARSE_ERROR;
} else if (type == TYPE_VOID) {
_set_error("void datatype not allowed here");
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier!");
return ERR_PARSE_ERROR;
}
MemberNode *member = alloc_node<MemberNode>();
member->precision = precision;
member->datatype = type;
member->struct_name = struct_name;
member->name = tk.text;
st_node->members.push_back(member);
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
_set_error("Expected ';'");
return ERR_PARSE_ERROR;
}
member_count++;
}
}
if (member_count == 0) {
_set_error("Empty structs are not allowed!");
return ERR_PARSE_ERROR;
}
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
_set_error("Expected ';'");
return ERR_PARSE_ERROR;
}
shader->structs[st.name] = st;
shader->vstructs.push_back(st); // struct's order is important!
} break;
case TK_UNIFORM: case TK_UNIFORM:
case TK_VARYING: { case TK_VARYING: {
bool uniform = tk.type == TK_UNIFORM; bool uniform = tk.type == TK_UNIFORM;
@ -5257,6 +5542,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//function or constant variable //function or constant variable
bool is_constant = false; bool is_constant = false;
bool is_struct = false;
StringName struct_name;
DataPrecision precision = PRECISION_DEFAULT; DataPrecision precision = PRECISION_DEFAULT;
DataType type; DataType type;
StringName name; StringName name;
@ -5271,6 +5558,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token(); tk = _get_token();
} }
if (shader->structs.has(tk.text)) {
if (precision != PRECISION_DEFAULT) {
_set_error("Precision modifier cannot be used on structs.");
return ERR_PARSE_ERROR;
}
is_struct = true;
struct_name = tk.text;
} else {
if (!is_token_datatype(tk.type)) { if (!is_token_datatype(tk.type)) {
_set_error("Expected constant, function, uniform or varying"); _set_error("Expected constant, function, uniform or varying");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
@ -5280,9 +5575,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("Invalid data type for constants or function return (samplers not allowed)"); _set_error("Invalid data type for constants or function return (samplers not allowed)");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
}
if (is_struct) {
type = TYPE_STRUCT;
} else {
type = get_token_datatype(tk.type); type = get_token_datatype(tk.type);
}
TkPos prev_pos = _get_tkpos(); TkPos prev_pos = _get_tkpos();
tk = _get_token(); tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) { if (tk.type == TK_BRACKET_OPEN) {
@ -5320,7 +5619,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
while (true) { while (true) {
ShaderNode::Constant constant; ShaderNode::Constant constant;
constant.name = name; constant.name = name;
constant.type = type; constant.type = is_struct ? TYPE_STRUCT : type;
constant.type_str = struct_name;
constant.precision = precision; constant.precision = precision;
constant.initializer = nullptr; constant.initializer = nullptr;
@ -5343,7 +5643,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.initializer = static_cast<ConstantNode *>(expr); constant.initializer = static_cast<ConstantNode *>(expr);
if (type != expr->get_datatype()) { if (is_struct) {
if (expr->get_datatype_name() != struct_name) {
_set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + struct_name + "'");
return ERR_PARSE_ERROR;
}
} else if (type != expr->get_datatype()) {
_set_error("Invalid assignment of '" + get_datatype_name(expr->get_datatype()) + "' to '" + get_datatype_name(type) + "'"); _set_error("Invalid assignment of '" + get_datatype_name(expr->get_datatype()) + "' to '" + get_datatype_name(type) + "'");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
@ -5405,6 +5710,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
func_node->name = name; func_node->name = name;
func_node->return_type = type; func_node->return_type = type;
func_node->return_struct_name = struct_name;
func_node->return_precision = precision; func_node->return_precision = precision;
if (p_functions.has(name)) { if (p_functions.has(name)) {
@ -5436,28 +5742,44 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
DataType ptype; DataType ptype;
StringName pname; StringName pname;
StringName param_struct_name;
DataPrecision pprecision = PRECISION_DEFAULT; DataPrecision pprecision = PRECISION_DEFAULT;
bool use_precision = false;
if (is_token_precision(tk.type)) { if (is_token_precision(tk.type)) {
pprecision = get_token_precision(tk.type); pprecision = get_token_precision(tk.type);
tk = _get_token(); tk = _get_token();
use_precision = true;
} }
if (!is_token_datatype(tk.type)) { is_struct = false;
if (shader->structs.has(tk.text)) {
is_struct = true;
param_struct_name = tk.text;
if (use_precision) {
_set_error("Precision modifier cannot be used on structs.");
return ERR_PARSE_ERROR;
}
}
if (!is_struct && !is_token_datatype(tk.type)) {
_set_error("Expected a valid datatype for argument"); _set_error("Expected a valid datatype for argument");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
if (is_struct) {
ptype = TYPE_STRUCT;
} else {
ptype = get_token_datatype(tk.type); ptype = get_token_datatype(tk.type);
if (_validate_datatype(ptype) != OK) { if (_validate_datatype(ptype) != OK) {
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
if (ptype == TYPE_VOID) { if (ptype == TYPE_VOID) {
_set_error("void not allowed in argument"); _set_error("void not allowed in argument");
return ERR_PARSE_ERROR; return ERR_PARSE_ERROR;
} }
}
tk = _get_token(); tk = _get_token();
@ -5488,6 +5810,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
FunctionNode::Argument arg; FunctionNode::Argument arg;
arg.type = ptype; arg.type = ptype;
arg.name = pname; arg.name = pname;
arg.type_str = param_struct_name;
arg.precision = pprecision; arg.precision = pprecision;
arg.qualifier = qualifier; arg.qualifier = qualifier;
@ -5739,6 +6062,17 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
return OK; return OK;
} break; } break;
case COMPLETION_STRUCT: {
if (shader->structs.has(completion_struct)) {
StructNode *node = shader->structs[completion_struct].shader_struct;
for (int i = 0; i < node->members.size(); i++) {
ScriptCodeCompletionOption option(node->members[i]->name, ScriptCodeCompletionOption::KIND_MEMBER);
r_options->push_back(option);
}
}
return OK;
} break;
case COMPLETION_MAIN_FUNCTION: { case COMPLETION_MAIN_FUNCTION: {
for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) { for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION); ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);

View file

@ -82,6 +82,7 @@ public:
TK_INTERPOLATION_FLAT, TK_INTERPOLATION_FLAT,
TK_INTERPOLATION_SMOOTH, TK_INTERPOLATION_SMOOTH,
TK_CONST, TK_CONST,
TK_STRUCT,
TK_PRECISION_LOW, TK_PRECISION_LOW,
TK_PRECISION_MID, TK_PRECISION_MID,
TK_PRECISION_HIGH, TK_PRECISION_HIGH,
@ -201,6 +202,7 @@ public:
TYPE_USAMPLER3D, TYPE_USAMPLER3D,
TYPE_SAMPLERCUBE, TYPE_SAMPLERCUBE,
TYPE_SAMPLEREXT, TYPE_SAMPLEREXT,
TYPE_STRUCT,
}; };
enum DataPrecision { enum DataPrecision {
@ -256,6 +258,7 @@ public:
OP_POST_DECREMENT, OP_POST_DECREMENT,
OP_CALL, OP_CALL,
OP_CONSTRUCT, OP_CONSTRUCT,
OP_STRUCT,
OP_INDEX, OP_INDEX,
OP_MAX OP_MAX
}; };
@ -300,11 +303,14 @@ public:
TYPE_MEMBER, TYPE_MEMBER,
TYPE_ARRAY, TYPE_ARRAY,
TYPE_ARRAY_DECLARATION, TYPE_ARRAY_DECLARATION,
TYPE_STRUCT,
}; };
Type type; Type type;
virtual DataType get_datatype() const { return TYPE_VOID; } virtual DataType get_datatype() const { return TYPE_VOID; }
virtual String get_datatype_name() const { return ""; }
Node(Type t) : Node(Type t) :
next(nullptr), next(nullptr),
type(t) {} type(t) {}
@ -325,20 +331,25 @@ public:
DataType return_cache; DataType return_cache;
DataPrecision return_precision_cache; DataPrecision return_precision_cache;
Operator op; Operator op;
StringName struct_name;
Vector<Node *> arguments; Vector<Node *> arguments;
virtual DataType get_datatype() const { return return_cache; } virtual DataType get_datatype() const { return return_cache; }
virtual String get_datatype_name() const { return String(struct_name); }
OperatorNode() : OperatorNode() :
Node(TYPE_OPERATOR), Node(TYPE_OPERATOR),
return_cache(TYPE_VOID), return_cache(TYPE_VOID),
return_precision_cache(PRECISION_DEFAULT), return_precision_cache(PRECISION_DEFAULT),
op(OP_EQUAL) {} op(OP_EQUAL),
struct_name("") {}
}; };
struct VariableNode : public Node { struct VariableNode : public Node {
DataType datatype_cache; DataType datatype_cache;
StringName name; StringName name;
StringName struct_name;
virtual DataType get_datatype() const { return datatype_cache; } virtual DataType get_datatype() const { return datatype_cache; }
virtual String get_datatype_name() const { return String(struct_name); }
bool is_const; bool is_const;
VariableNode() : VariableNode() :
@ -350,6 +361,7 @@ public:
struct VariableDeclarationNode : public Node { struct VariableDeclarationNode : public Node {
DataPrecision precision; DataPrecision precision;
DataType datatype; DataType datatype;
String struct_name;
bool is_const; bool is_const;
struct Declaration { struct Declaration {
@ -369,12 +381,14 @@ public:
struct ArrayNode : public Node { struct ArrayNode : public Node {
DataType datatype_cache; DataType datatype_cache;
StringName struct_name;
StringName name; StringName name;
Node *index_expression; Node *index_expression;
Node *call_expression; Node *call_expression;
bool is_const; bool is_const;
virtual DataType get_datatype() const { return datatype_cache; } virtual DataType get_datatype() const { return datatype_cache; }
virtual String get_datatype_name() const { return String(struct_name); }
ArrayNode() : ArrayNode() :
Node(TYPE_ARRAY), Node(TYPE_ARRAY),
@ -387,6 +401,7 @@ public:
struct ArrayDeclarationNode : public Node { struct ArrayDeclarationNode : public Node {
DataPrecision precision; DataPrecision precision;
DataType datatype; DataType datatype;
String struct_name;
bool is_const; bool is_const;
struct Declaration { struct Declaration {
@ -441,6 +456,7 @@ public:
struct Variable { struct Variable {
DataType type; DataType type;
StringName struct_name;
DataPrecision precision; DataPrecision precision;
int line; //for completion int line; //for completion
int array_size; int array_size;
@ -472,11 +488,15 @@ public:
struct MemberNode : public Node { struct MemberNode : public Node {
DataType basetype; DataType basetype;
StringName base_struct_name;
DataPrecision precision;
DataType datatype; DataType datatype;
StringName struct_name;
StringName name; StringName name;
Node *owner; Node *owner;
virtual DataType get_datatype() const { return datatype; } virtual DataType get_datatype() const { return datatype; }
virtual String get_datatype_name() const { return String(struct_name); }
MemberNode() : MemberNode() :
Node(TYPE_MEMBER), Node(TYPE_MEMBER),
@ -485,16 +505,24 @@ public:
owner(nullptr) {} owner(nullptr) {}
}; };
struct StructNode : public Node {
List<MemberNode *> members;
StructNode() :
Node(TYPE_STRUCT) {}
};
struct FunctionNode : public Node { struct FunctionNode : public Node {
struct Argument { struct Argument {
ArgumentQualifier qualifier; ArgumentQualifier qualifier;
StringName name; StringName name;
DataType type; DataType type;
StringName type_str;
DataPrecision precision; DataPrecision precision;
}; };
StringName name; StringName name;
DataType return_type; DataType return_type;
StringName return_struct_name;
DataPrecision return_precision; DataPrecision return_precision;
Vector<Argument> arguments; Vector<Argument> arguments;
BlockNode *body; BlockNode *body;
@ -512,6 +540,7 @@ public:
struct Constant { struct Constant {
StringName name; StringName name;
DataType type; DataType type;
StringName type_str;
DataPrecision precision; DataPrecision precision;
ConstantNode *initializer; ConstantNode *initializer;
}; };
@ -523,6 +552,11 @@ public:
bool callable; bool callable;
}; };
struct Struct {
StringName name;
StructNode *shader_struct;
};
struct Varying { struct Varying {
DataType type; DataType type;
DataInterpolation interpolation; DataInterpolation interpolation;
@ -573,10 +607,12 @@ public:
Map<StringName, Constant> constants; Map<StringName, Constant> constants;
Map<StringName, Varying> varyings; Map<StringName, Varying> varyings;
Map<StringName, Uniform> uniforms; Map<StringName, Uniform> uniforms;
Map<StringName, Struct> structs;
Vector<StringName> render_modes; Vector<StringName> render_modes;
Vector<Function> functions; Vector<Function> functions;
Vector<Constant> vconstants; Vector<Constant> vconstants;
Vector<Struct> vstructs;
ShaderNode() : ShaderNode() :
Node(TYPE_SHADER) {} Node(TYPE_SHADER) {}
@ -603,6 +639,7 @@ public:
COMPLETION_FUNCTION_CALL, COMPLETION_FUNCTION_CALL,
COMPLETION_CALL_ARGUMENTS, COMPLETION_CALL_ARGUMENTS,
COMPLETION_INDEX, COMPLETION_INDEX,
COMPLETION_STRUCT,
}; };
struct Token { struct Token {
@ -718,7 +755,7 @@ private:
IDENTIFIER_CONSTANT, IDENTIFIER_CONSTANT,
}; };
bool _find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr); bool _find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr);
bool _is_operator_assign(Operator p_op) const; bool _is_operator_assign(Operator p_op) const;
bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = nullptr); bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = nullptr);
bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr);
@ -743,6 +780,7 @@ private:
DataType completion_base; DataType completion_base;
SubClassTag completion_class; SubClassTag completion_class;
StringName completion_function; StringName completion_function;
StringName completion_struct;
int completion_argument; int completion_argument;
bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier); bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier);
@ -750,8 +788,9 @@ private:
static const BuiltinFuncOutArgs builtin_func_out_args[]; static const BuiltinFuncOutArgs builtin_func_out_args[];
Error _validate_datatype(DataType p_type); Error _validate_datatype(DataType p_type);
bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type); bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = nullptr); bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = nullptr);
Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types); Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);