Backport 6f16239
"Implementation of struct for shaders" to 3.4
This commit is contained in:
parent
74174676b8
commit
fc6bee0750
7 changed files with 651 additions and 165 deletions
|
@ -1574,6 +1574,9 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn
|
|||
pi.name = E->get();
|
||||
|
||||
switch (u.type) {
|
||||
case ShaderLanguage::TYPE_STRUCT: {
|
||||
pi.type = Variant::ARRAY;
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VOID: {
|
||||
pi.type = Variant::NIL;
|
||||
} break;
|
||||
|
|
|
@ -243,22 +243,22 @@ void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const Stri
|
|||
r_to_add += "\n";
|
||||
|
||||
StringBuffer<128> header;
|
||||
|
||||
header += _typestr(fnode->return_type);
|
||||
header += " ";
|
||||
header += _mkid(fnode->name);
|
||||
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) + "(";
|
||||
}
|
||||
|
||||
for (int i = 0; i < fnode->arguments.size(); i++) {
|
||||
if (i > 0) {
|
||||
header += ", ";
|
||||
}
|
||||
|
||||
header += _qualstr(fnode->arguments[i].qualifier);
|
||||
header += _prestr(fnode->arguments[i].precision);
|
||||
header += _typestr(fnode->arguments[i].type);
|
||||
header += " ";
|
||||
header += _mkid(fnode->arguments[i].name);
|
||||
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 += ")\n";
|
||||
|
@ -311,6 +311,35 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
|
|||
StringBuilder vertex_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
|
||||
|
||||
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++) {
|
||||
String gcode;
|
||||
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 += _typestr(snode->vconstants[i].type);
|
||||
}
|
||||
gcode += " " + _mkid(String(snode->vconstants[i].name));
|
||||
gcode += "=";
|
||||
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();
|
||||
|
||||
} break;
|
||||
|
||||
case SL::Node::TYPE_STRUCT: {
|
||||
} break;
|
||||
case SL::Node::TYPE_FUNCTION: {
|
||||
} break;
|
||||
|
||||
|
@ -453,8 +487,12 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
|
|||
if (var_dec_node->is_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 += _typestr(var_dec_node->datatype);
|
||||
}
|
||||
|
||||
for (int i = 0; i < var_dec_node->declarations.size(); i++) {
|
||||
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;
|
||||
|
||||
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 += _typestr(arr_dec_node->datatype);
|
||||
|
||||
}
|
||||
for (int i = 0; i < arr_dec_node->declarations.size(); i++) {
|
||||
if (i > 0) {
|
||||
declaration += ",";
|
||||
|
@ -640,12 +681,14 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
|
|||
} break;
|
||||
|
||||
case SL::OP_CALL:
|
||||
case SL::OP_STRUCT:
|
||||
case SL::OP_CONSTRUCT: {
|
||||
ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
|
||||
|
||||
SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0];
|
||||
|
||||
if (op_node->op == SL::OP_CONSTRUCT) {
|
||||
if (op_node->op == SL::OP_STRUCT) {
|
||||
code += _mkid(var_node->name);
|
||||
} else if (op_node->op == SL::OP_CONSTRUCT) {
|
||||
code += var_node->name;
|
||||
} else {
|
||||
if (var_node->name == "texture") {
|
||||
|
|
|
@ -2355,6 +2355,9 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn
|
|||
ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[E->get()];
|
||||
pi.name = E->get();
|
||||
switch (u.type) {
|
||||
case ShaderLanguage::TYPE_STRUCT:
|
||||
pi.type = Variant::ARRAY;
|
||||
break;
|
||||
case ShaderLanguage::TYPE_VOID:
|
||||
pi.type = Variant::NIL;
|
||||
break;
|
||||
|
|
|
@ -112,6 +112,8 @@ static int _get_datatype_size(SL::DataType p_type) {
|
|||
return 16;
|
||||
case SL::TYPE_SAMPLEREXT:
|
||||
return 16;
|
||||
case SL::TYPE_STRUCT:
|
||||
return 0;
|
||||
}
|
||||
|
||||
ERR_FAIL_V(0);
|
||||
|
@ -181,6 +183,8 @@ static int _get_datatype_alignment(SL::DataType p_type) {
|
|||
return 16;
|
||||
case SL::TYPE_SAMPLEREXT:
|
||||
return 16;
|
||||
case SL::TYPE_STRUCT:
|
||||
return 0;
|
||||
}
|
||||
|
||||
ERR_FAIL_V(0);
|
||||
|
@ -360,13 +364,21 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri
|
|||
r_to_add += "\n";
|
||||
|
||||
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) + "(";
|
||||
}
|
||||
for (int i = 0; i < fnode->arguments.size(); i++) {
|
||||
if (i > 0) {
|
||||
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 += ")\n";
|
||||
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_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++) {
|
||||
String gcode;
|
||||
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 += _typestr(pnode->vconstants[i].type);
|
||||
}
|
||||
gcode += " " + _mkid(String(pnode->vconstants[i].name));
|
||||
gcode += "=";
|
||||
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);
|
||||
} break;
|
||||
case SL::Node::TYPE_STRUCT: {
|
||||
} break;
|
||||
case SL::Node::TYPE_FUNCTION: {
|
||||
} break;
|
||||
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) {
|
||||
declaration += "const ";
|
||||
}
|
||||
if (vdnode->datatype == SL::TYPE_STRUCT) {
|
||||
declaration += _mkid(vdnode->struct_name);
|
||||
} else {
|
||||
declaration += _prestr(vdnode->precision);
|
||||
declaration += _typestr(vdnode->datatype);
|
||||
}
|
||||
for (int i = 0; i < vdnode->declarations.size(); i++) {
|
||||
if (i > 0) {
|
||||
declaration += ",";
|
||||
|
@ -633,8 +684,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
|
|||
if (adnode->is_const) {
|
||||
declaration += "const ";
|
||||
}
|
||||
if (adnode->datatype == SL::TYPE_STRUCT) {
|
||||
declaration += _mkid(adnode->struct_name);
|
||||
} else {
|
||||
declaration += _prestr(adnode->precision);
|
||||
declaration += _typestr(adnode->datatype);
|
||||
}
|
||||
for (int i = 0; i < adnode->declarations.size(); i++) {
|
||||
if (i > 0) {
|
||||
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();
|
||||
if (sz > 0) {
|
||||
declaration += "=";
|
||||
if (adnode->datatype == SL::TYPE_STRUCT) {
|
||||
declaration += _mkid(adnode->struct_name);
|
||||
} else {
|
||||
declaration += _typestr(adnode->datatype);
|
||||
}
|
||||
declaration += "[";
|
||||
declaration += itos(sz);
|
||||
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);
|
||||
break;
|
||||
case SL::OP_CALL:
|
||||
case SL::OP_STRUCT:
|
||||
case SL::OP_CONSTRUCT: {
|
||||
ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
|
||||
|
||||
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);
|
||||
} else {
|
||||
if (internal_functions.has(vnode->name)) {
|
||||
|
|
|
@ -174,6 +174,8 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
|
|||
|
||||
//code+=dump_node_code(pnode->body,p_level);
|
||||
} break;
|
||||
case SL::Node::TYPE_STRUCT: {
|
||||
} break;
|
||||
case SL::Node::TYPE_FUNCTION: {
|
||||
} break;
|
||||
case SL::Node::TYPE_BLOCK: {
|
||||
|
|
|
@ -271,6 +271,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
|
|||
{ TK_INTERPOLATION_FLAT, "flat" },
|
||||
{ TK_INTERPOLATION_SMOOTH, "smooth" },
|
||||
{ TK_CONST, "const" },
|
||||
{ TK_STRUCT, "struct" },
|
||||
{ TK_PRECISION_LOW, "lowp" },
|
||||
{ TK_PRECISION_MID, "mediump" },
|
||||
{ TK_PRECISION_HIGH, "highp" },
|
||||
|
@ -858,6 +859,8 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
|
|||
return "samplerCube";
|
||||
case TYPE_SAMPLEREXT:
|
||||
return "samplerExternalOES";
|
||||
case TYPE_STRUCT:
|
||||
return "struct";
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -874,6 +877,7 @@ void ShaderLanguage::clear() {
|
|||
completion_block = nullptr;
|
||||
completion_function = StringName();
|
||||
completion_class = SubClassTag::TAG_GLOBAL;
|
||||
completion_struct = StringName();
|
||||
|
||||
error_line = 0;
|
||||
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 (r_data_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) {
|
||||
*r_type = IDENTIFIER_LOCAL_VAR;
|
||||
}
|
||||
if (r_struct_name) {
|
||||
*r_struct_name = p_block->variables[p_identifier].struct_name;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -940,7 +947,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
|
|||
if (r_type) {
|
||||
*r_type = IDENTIFIER_FUNCTION_ARGUMENT;
|
||||
}
|
||||
|
||||
if (r_struct_name) {
|
||||
*r_struct_name = function->arguments[i].type_str;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -976,6 +985,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
|
|||
if (r_type) {
|
||||
*r_type = IDENTIFIER_CONSTANT;
|
||||
}
|
||||
if (r_struct_name) {
|
||||
*r_struct_name = shader->constants[p_identifier].type_str;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1219,7 +1231,11 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
|
|||
case OP_ASSIGN: {
|
||||
DataType na = p_op->arguments[0]->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;
|
||||
}
|
||||
ret_type = na;
|
||||
} break;
|
||||
case OP_ASSIGN_ADD:
|
||||
|
@ -2092,10 +2108,11 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[]
|
|||
{ 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);
|
||||
|
||||
Vector<DataType> args;
|
||||
Vector<StringName> args2;
|
||||
|
||||
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++) {
|
||||
args.push_back(p_func->arguments[i]->get_datatype());
|
||||
args2.push_back(p_func->arguments[i]->get_datatype_name());
|
||||
}
|
||||
|
||||
int argcount = args.size();
|
||||
|
@ -2285,6 +2303,10 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p
|
|||
bool fail = false;
|
||||
|
||||
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)) {
|
||||
//all good, but it needs implicit conversion later
|
||||
} 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) {
|
||||
*r_ret_type = pfunc->return_type;
|
||||
if (pfunc->return_type == TYPE_STRUCT) {
|
||||
*r_ret_type_str = pfunc->return_struct_name;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2322,6 +2347,18 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p
|
|||
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) {
|
||||
TkPos pos = _get_tkpos();
|
||||
Token tk = _get_token();
|
||||
|
@ -2557,6 +2594,8 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C
|
|||
// Texture types, likely not relevant here.
|
||||
break;
|
||||
}
|
||||
case ShaderLanguage::TYPE_STRUCT:
|
||||
break;
|
||||
case ShaderLanguage::TYPE_VOID:
|
||||
break;
|
||||
}
|
||||
|
@ -2897,7 +2936,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
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) + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2909,11 +2948,63 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
|
||||
StringName identifier;
|
||||
|
||||
StructNode *pstruct = nullptr;
|
||||
bool struct_init = false;
|
||||
|
||||
_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();
|
||||
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;
|
||||
|
||||
OperatorNode *func = alloc_node<OperatorNode>();
|
||||
|
@ -2946,6 +3037,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function_index = i;
|
||||
break;
|
||||
}
|
||||
|
@ -2963,7 +3055,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
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) + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3018,7 +3110,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
}
|
||||
|
||||
expr = func;
|
||||
|
||||
}
|
||||
} else {
|
||||
//an identifier
|
||||
|
||||
|
@ -3028,6 +3120,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
IdentifierType ident_type;
|
||||
bool is_const = false;
|
||||
int array_size = 0;
|
||||
StringName struct_name;
|
||||
|
||||
if (p_block && p_block->block_tag != SubClassTag::TAG_GLOBAL) {
|
||||
int idx = 0;
|
||||
|
@ -3045,7 +3138,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
return nullptr;
|
||||
}
|
||||
} 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));
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3111,6 +3204,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
ArrayNode *arrname = alloc_node<ArrayNode>();
|
||||
arrname->name = identifier;
|
||||
arrname->datatype_cache = data_type;
|
||||
arrname->struct_name = struct_name;
|
||||
arrname->index_expression = index_expression;
|
||||
arrname->call_expression = call_expression;
|
||||
arrname->is_const = is_const;
|
||||
|
@ -3121,6 +3215,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
varname->name = identifier;
|
||||
varname->datatype_cache = data_type;
|
||||
varname->is_const = is_const;
|
||||
varname->struct_name = struct_name;
|
||||
expr = varname;
|
||||
}
|
||||
}
|
||||
|
@ -3172,22 +3267,47 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
|
||||
if (tk.type == TK_CURSOR) {
|
||||
//do nothing
|
||||
} else if (tk.type == TK_IDENTIFIER) {
|
||||
} else if (tk.type == TK_PERIOD) {
|
||||
DataType dt = expr->get_datatype();
|
||||
String st = expr->get_datatype_name();
|
||||
StringName identifier;
|
||||
if (_get_completable_identifier(p_block, COMPLETION_INDEX, identifier)) {
|
||||
completion_base = expr->get_datatype();
|
||||
if (_get_completable_identifier(p_block, dt == TYPE_STRUCT ? COMPLETION_STRUCT : COMPLETION_INDEX, identifier)) {
|
||||
if (dt == TYPE_STRUCT) {
|
||||
completion_struct = st;
|
||||
} else {
|
||||
completion_base = dt;
|
||||
}
|
||||
}
|
||||
|
||||
if (identifier == StringName()) {
|
||||
_set_error("Expected identifier as member");
|
||||
return nullptr;
|
||||
}
|
||||
DataType dt = expr->get_datatype();
|
||||
String ident = identifier;
|
||||
|
||||
bool ok = true;
|
||||
DataType member_type = TYPE_VOID;
|
||||
StringName member_struct_name = "";
|
||||
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_IVEC2:
|
||||
case TYPE_UVEC2:
|
||||
|
@ -3300,13 +3420,15 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MemberNode *mn = alloc_node<MemberNode>();
|
||||
mn->basetype = dt;
|
||||
mn->datatype = member_type;
|
||||
mn->base_struct_name = st;
|
||||
mn->struct_name = member_struct_name;
|
||||
mn->name = ident;
|
||||
mn->owner = expr;
|
||||
expr = mn;
|
||||
|
@ -3872,8 +3994,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
if (i > 0) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
_set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at);
|
||||
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 (p_just_one) {
|
||||
_set_error("Unexpected '}'");
|
||||
|
@ -4027,30 +4155,49 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
|
||||
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;
|
||||
|
||||
if (tk.type == TK_CONST) {
|
||||
is_const = true;
|
||||
tk = _get_token();
|
||||
|
||||
if (!is_struct) {
|
||||
is_struct = shader->structs.has(tk.text); // check again.
|
||||
struct_name = tk.text;
|
||||
}
|
||||
}
|
||||
|
||||
DataPrecision precision = PRECISION_DEFAULT;
|
||||
if (is_token_precision(tk.type)) {
|
||||
precision = get_token_precision(tk.type);
|
||||
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)) {
|
||||
_set_error("Expected datatype after precision");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_struct) {
|
||||
if (!is_token_variable_datatype(tk.type)) {
|
||||
_set_error("Invalid data type for variable (samplers not allowed)");
|
||||
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) {
|
||||
return ERR_PARSE_ERROR;
|
||||
|
@ -4081,6 +4228,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
var.line = tk_line;
|
||||
var.array_size = 0;
|
||||
var.is_const = is_const;
|
||||
var.struct_name = struct_name;
|
||||
|
||||
tk = _get_token();
|
||||
|
||||
|
@ -4093,7 +4241,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
}
|
||||
|
||||
ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>();
|
||||
if (is_struct) {
|
||||
node->struct_name = struct_name;
|
||||
node->datatype = TYPE_STRUCT;
|
||||
} else {
|
||||
node->datatype = type;
|
||||
}
|
||||
node->precision = precision;
|
||||
node->is_const = is_const;
|
||||
vardecl = (Node *)node;
|
||||
|
@ -4145,16 +4298,29 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
if (is_token_precision(tk.type)) {
|
||||
precision2 = get_token_precision(tk.type);
|
||||
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)) {
|
||||
_set_error("Expected datatype after precision");
|
||||
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)) {
|
||||
_set_error("Invalid data type for array");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
DataType type2 = get_token_datatype(tk.type);
|
||||
type2 = get_token_datatype(tk.type);
|
||||
}
|
||||
|
||||
int array_size2 = 0;
|
||||
|
||||
|
@ -4199,13 +4365,17 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
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 '";
|
||||
if (precision2 != PRECISION_DEFAULT) {
|
||||
error_str += get_precision_name(precision2);
|
||||
error_str += " ";
|
||||
}
|
||||
if (type2 == TYPE_STRUCT) {
|
||||
error_str += struct_name2;
|
||||
} else {
|
||||
error_str += get_datatype_name(type2);
|
||||
}
|
||||
error_str += "[";
|
||||
error_str += itos(array_size2);
|
||||
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 += " ";
|
||||
}
|
||||
if (type == TYPE_STRUCT) {
|
||||
error_str += struct_name;
|
||||
} else {
|
||||
error_str += get_datatype_name(type);
|
||||
}
|
||||
error_str += "[";
|
||||
error_str += itos(var.array_size);
|
||||
error_str += "]'";
|
||||
|
@ -4251,8 +4425,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (var.type != n->get_datatype()) {
|
||||
_set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(var.type) + "'");
|
||||
if (var.type != n->get_datatype() || struct_name != n->get_datatype_name()) {
|
||||
_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;
|
||||
}
|
||||
|
||||
|
@ -4298,7 +4472,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
node->declarations.push_back(decl);
|
||||
} else if (tk.type == TK_OP_ASSIGN) {
|
||||
VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
|
||||
if (is_struct) {
|
||||
node->struct_name = struct_name;
|
||||
node->datatype = TYPE_STRUCT;
|
||||
} else {
|
||||
node->datatype = type;
|
||||
}
|
||||
node->precision = precision;
|
||||
node->is_const = is_const;
|
||||
vardecl = (Node *)node;
|
||||
|
@ -4318,8 +4497,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
}
|
||||
decl.initializer = n;
|
||||
|
||||
if (var.type != n->get_datatype()) {
|
||||
_set_error("Invalid assignment of '" + get_datatype_name(n->get_datatype()) + "' to '" + get_datatype_name(var.type) + "'");
|
||||
if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) {
|
||||
_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;
|
||||
}
|
||||
tk = _get_token();
|
||||
|
@ -4331,7 +4510,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|||
}
|
||||
|
||||
VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
|
||||
if (is_struct) {
|
||||
node->struct_name = struct_name;
|
||||
node->datatype = TYPE_STRUCT;
|
||||
} else {
|
||||
node->datatype = type;
|
||||
}
|
||||
node->precision = precision;
|
||||
vardecl = (Node *)node;
|
||||
|
||||
|
@ -5001,6 +5185,107 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
}
|
||||
}
|
||||
} 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_VARYING: {
|
||||
bool uniform = tk.type == TK_UNIFORM;
|
||||
|
@ -5257,6 +5542,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
//function or constant variable
|
||||
|
||||
bool is_constant = false;
|
||||
bool is_struct = false;
|
||||
StringName struct_name;
|
||||
DataPrecision precision = PRECISION_DEFAULT;
|
||||
DataType type;
|
||||
StringName name;
|
||||
|
@ -5271,6 +5558,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
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)) {
|
||||
_set_error("Expected constant, function, uniform or varying");
|
||||
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)");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_struct) {
|
||||
type = TYPE_STRUCT;
|
||||
} else {
|
||||
type = get_token_datatype(tk.type);
|
||||
|
||||
}
|
||||
TkPos prev_pos = _get_tkpos();
|
||||
tk = _get_token();
|
||||
if (tk.type == TK_BRACKET_OPEN) {
|
||||
|
@ -5320,7 +5619,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
while (true) {
|
||||
ShaderNode::Constant constant;
|
||||
constant.name = name;
|
||||
constant.type = type;
|
||||
constant.type = is_struct ? TYPE_STRUCT : type;
|
||||
constant.type_str = struct_name;
|
||||
constant.precision = precision;
|
||||
constant.initializer = nullptr;
|
||||
|
||||
|
@ -5343,7 +5643,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
|
||||
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) + "'");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
@ -5405,6 +5710,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
|
||||
func_node->name = name;
|
||||
func_node->return_type = type;
|
||||
func_node->return_struct_name = struct_name;
|
||||
func_node->return_precision = precision;
|
||||
|
||||
if (p_functions.has(name)) {
|
||||
|
@ -5436,28 +5742,44 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
|
||||
DataType ptype;
|
||||
StringName pname;
|
||||
StringName param_struct_name;
|
||||
DataPrecision pprecision = PRECISION_DEFAULT;
|
||||
bool use_precision = false;
|
||||
|
||||
if (is_token_precision(tk.type)) {
|
||||
pprecision = get_token_precision(tk.type);
|
||||
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");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (is_struct) {
|
||||
ptype = TYPE_STRUCT;
|
||||
} else {
|
||||
ptype = get_token_datatype(tk.type);
|
||||
|
||||
if (_validate_datatype(ptype) != OK) {
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (ptype == TYPE_VOID) {
|
||||
_set_error("void not allowed in argument");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
tk = _get_token();
|
||||
|
||||
|
@ -5488,6 +5810,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
FunctionNode::Argument arg;
|
||||
arg.type = ptype;
|
||||
arg.name = pname;
|
||||
arg.type_str = param_struct_name;
|
||||
arg.precision = pprecision;
|
||||
arg.qualifier = qualifier;
|
||||
|
||||
|
@ -5739,6 +6062,17 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
|||
|
||||
return OK;
|
||||
} 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: {
|
||||
for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
|
||||
ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
|
||||
|
|
|
@ -82,6 +82,7 @@ public:
|
|||
TK_INTERPOLATION_FLAT,
|
||||
TK_INTERPOLATION_SMOOTH,
|
||||
TK_CONST,
|
||||
TK_STRUCT,
|
||||
TK_PRECISION_LOW,
|
||||
TK_PRECISION_MID,
|
||||
TK_PRECISION_HIGH,
|
||||
|
@ -201,6 +202,7 @@ public:
|
|||
TYPE_USAMPLER3D,
|
||||
TYPE_SAMPLERCUBE,
|
||||
TYPE_SAMPLEREXT,
|
||||
TYPE_STRUCT,
|
||||
};
|
||||
|
||||
enum DataPrecision {
|
||||
|
@ -256,6 +258,7 @@ public:
|
|||
OP_POST_DECREMENT,
|
||||
OP_CALL,
|
||||
OP_CONSTRUCT,
|
||||
OP_STRUCT,
|
||||
OP_INDEX,
|
||||
OP_MAX
|
||||
};
|
||||
|
@ -300,11 +303,14 @@ public:
|
|||
TYPE_MEMBER,
|
||||
TYPE_ARRAY,
|
||||
TYPE_ARRAY_DECLARATION,
|
||||
TYPE_STRUCT,
|
||||
};
|
||||
|
||||
Type type;
|
||||
|
||||
virtual DataType get_datatype() const { return TYPE_VOID; }
|
||||
virtual String get_datatype_name() const { return ""; }
|
||||
|
||||
Node(Type t) :
|
||||
next(nullptr),
|
||||
type(t) {}
|
||||
|
@ -325,20 +331,25 @@ public:
|
|||
DataType return_cache;
|
||||
DataPrecision return_precision_cache;
|
||||
Operator op;
|
||||
StringName struct_name;
|
||||
Vector<Node *> arguments;
|
||||
virtual DataType get_datatype() const { return return_cache; }
|
||||
virtual String get_datatype_name() const { return String(struct_name); }
|
||||
|
||||
OperatorNode() :
|
||||
Node(TYPE_OPERATOR),
|
||||
return_cache(TYPE_VOID),
|
||||
return_precision_cache(PRECISION_DEFAULT),
|
||||
op(OP_EQUAL) {}
|
||||
op(OP_EQUAL),
|
||||
struct_name("") {}
|
||||
};
|
||||
|
||||
struct VariableNode : public Node {
|
||||
DataType datatype_cache;
|
||||
StringName name;
|
||||
StringName struct_name;
|
||||
virtual DataType get_datatype() const { return datatype_cache; }
|
||||
virtual String get_datatype_name() const { return String(struct_name); }
|
||||
bool is_const;
|
||||
|
||||
VariableNode() :
|
||||
|
@ -350,6 +361,7 @@ public:
|
|||
struct VariableDeclarationNode : public Node {
|
||||
DataPrecision precision;
|
||||
DataType datatype;
|
||||
String struct_name;
|
||||
bool is_const;
|
||||
|
||||
struct Declaration {
|
||||
|
@ -369,12 +381,14 @@ public:
|
|||
|
||||
struct ArrayNode : public Node {
|
||||
DataType datatype_cache;
|
||||
StringName struct_name;
|
||||
StringName name;
|
||||
Node *index_expression;
|
||||
Node *call_expression;
|
||||
bool is_const;
|
||||
|
||||
virtual DataType get_datatype() const { return datatype_cache; }
|
||||
virtual String get_datatype_name() const { return String(struct_name); }
|
||||
|
||||
ArrayNode() :
|
||||
Node(TYPE_ARRAY),
|
||||
|
@ -387,6 +401,7 @@ public:
|
|||
struct ArrayDeclarationNode : public Node {
|
||||
DataPrecision precision;
|
||||
DataType datatype;
|
||||
String struct_name;
|
||||
bool is_const;
|
||||
|
||||
struct Declaration {
|
||||
|
@ -441,6 +456,7 @@ public:
|
|||
|
||||
struct Variable {
|
||||
DataType type;
|
||||
StringName struct_name;
|
||||
DataPrecision precision;
|
||||
int line; //for completion
|
||||
int array_size;
|
||||
|
@ -472,11 +488,15 @@ public:
|
|||
|
||||
struct MemberNode : public Node {
|
||||
DataType basetype;
|
||||
StringName base_struct_name;
|
||||
DataPrecision precision;
|
||||
DataType datatype;
|
||||
StringName struct_name;
|
||||
StringName name;
|
||||
Node *owner;
|
||||
|
||||
virtual DataType get_datatype() const { return datatype; }
|
||||
virtual String get_datatype_name() const { return String(struct_name); }
|
||||
|
||||
MemberNode() :
|
||||
Node(TYPE_MEMBER),
|
||||
|
@ -485,16 +505,24 @@ public:
|
|||
owner(nullptr) {}
|
||||
};
|
||||
|
||||
struct StructNode : public Node {
|
||||
List<MemberNode *> members;
|
||||
StructNode() :
|
||||
Node(TYPE_STRUCT) {}
|
||||
};
|
||||
|
||||
struct FunctionNode : public Node {
|
||||
struct Argument {
|
||||
ArgumentQualifier qualifier;
|
||||
StringName name;
|
||||
DataType type;
|
||||
StringName type_str;
|
||||
DataPrecision precision;
|
||||
};
|
||||
|
||||
StringName name;
|
||||
DataType return_type;
|
||||
StringName return_struct_name;
|
||||
DataPrecision return_precision;
|
||||
Vector<Argument> arguments;
|
||||
BlockNode *body;
|
||||
|
@ -512,6 +540,7 @@ public:
|
|||
struct Constant {
|
||||
StringName name;
|
||||
DataType type;
|
||||
StringName type_str;
|
||||
DataPrecision precision;
|
||||
ConstantNode *initializer;
|
||||
};
|
||||
|
@ -523,6 +552,11 @@ public:
|
|||
bool callable;
|
||||
};
|
||||
|
||||
struct Struct {
|
||||
StringName name;
|
||||
StructNode *shader_struct;
|
||||
};
|
||||
|
||||
struct Varying {
|
||||
DataType type;
|
||||
DataInterpolation interpolation;
|
||||
|
@ -573,10 +607,12 @@ public:
|
|||
Map<StringName, Constant> constants;
|
||||
Map<StringName, Varying> varyings;
|
||||
Map<StringName, Uniform> uniforms;
|
||||
Map<StringName, Struct> structs;
|
||||
Vector<StringName> render_modes;
|
||||
|
||||
Vector<Function> functions;
|
||||
Vector<Constant> vconstants;
|
||||
Vector<Struct> vstructs;
|
||||
|
||||
ShaderNode() :
|
||||
Node(TYPE_SHADER) {}
|
||||
|
@ -603,6 +639,7 @@ public:
|
|||
COMPLETION_FUNCTION_CALL,
|
||||
COMPLETION_CALL_ARGUMENTS,
|
||||
COMPLETION_INDEX,
|
||||
COMPLETION_STRUCT,
|
||||
};
|
||||
|
||||
struct Token {
|
||||
|
@ -718,7 +755,7 @@ private:
|
|||
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 _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);
|
||||
|
@ -743,6 +780,7 @@ private:
|
|||
DataType completion_base;
|
||||
SubClassTag completion_class;
|
||||
StringName completion_function;
|
||||
StringName completion_struct;
|
||||
int completion_argument;
|
||||
|
||||
bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier);
|
||||
|
@ -750,8 +788,9 @@ private:
|
|||
static const BuiltinFuncOutArgs builtin_func_out_args[];
|
||||
|
||||
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);
|
||||
|
||||
Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
|
||||
|
|
Loading…
Reference in a new issue