Merge pull request #56794 from Chaosus/shader_fixes_3.x
This commit is contained in:
commit
cb9854df52
3 changed files with 355 additions and 240 deletions
|
@ -212,7 +212,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
|
||||||
|
|
||||||
String ShaderLanguage::get_token_text(Token p_token) {
|
String ShaderLanguage::get_token_text(Token p_token) {
|
||||||
String name = token_names[p_token.type];
|
String name = token_names[p_token.type];
|
||||||
if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) {
|
if (p_token.is_integer_constant() || p_token.type == TK_REAL_CONSTANT) {
|
||||||
name += "(" + rtos(p_token.constant) + ")";
|
name += "(" + rtos(p_token.constant) + ")";
|
||||||
} else if (p_token.type == TK_IDENTIFIER) {
|
} else if (p_token.type == TK_IDENTIFIER) {
|
||||||
name += "(" + String(p_token.text) + ")";
|
name += "(" + String(p_token.text) + ")";
|
||||||
|
@ -515,51 +515,100 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
||||||
|
|
||||||
if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
|
if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
|
||||||
// parse number
|
// parse number
|
||||||
|
bool hexa_found = false;
|
||||||
bool period_found = false;
|
bool period_found = false;
|
||||||
bool exponent_found = false;
|
bool exponent_found = false;
|
||||||
bool hexa_found = false;
|
|
||||||
bool sign_found = false;
|
|
||||||
bool float_suffix_found = false;
|
bool float_suffix_found = false;
|
||||||
|
bool uint_suffix_found = false;
|
||||||
|
bool end_suffix_found = false;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CASE_ALL,
|
||||||
|
CASE_HEXA_PERIOD,
|
||||||
|
CASE_EXPONENT,
|
||||||
|
CASE_SIGN_AFTER_EXPONENT,
|
||||||
|
CASE_NONE,
|
||||||
|
CASE_MAX,
|
||||||
|
} lut_case = CASE_ALL;
|
||||||
|
|
||||||
|
static bool suffix_lut[CASE_MAX][127];
|
||||||
|
|
||||||
|
if (!is_const_suffix_lut_initialized) {
|
||||||
|
is_const_suffix_lut_initialized = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
char t = char(i);
|
||||||
|
|
||||||
|
suffix_lut[CASE_ALL][i] = t == '.' || t == 'x' || t == 'e' || t == 'f' || t == 'u' || t == '-' || t == '+';
|
||||||
|
suffix_lut[CASE_HEXA_PERIOD][i] = t == 'e' || t == 'f';
|
||||||
|
suffix_lut[CASE_EXPONENT][i] = t == 'f' || t == '-' || t == '+';
|
||||||
|
suffix_lut[CASE_SIGN_AFTER_EXPONENT][i] = t == 'f';
|
||||||
|
suffix_lut[CASE_NONE][i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (GETCHAR(i) == '.') {
|
const CharType symbol = String::char_lowercase(GETCHAR(i));
|
||||||
if (period_found || exponent_found || hexa_found || float_suffix_found) {
|
bool error = false;
|
||||||
return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
||||||
}
|
if (_is_number(symbol)) {
|
||||||
period_found = true;
|
if (end_suffix_found) {
|
||||||
} else if (GETCHAR(i) == 'x') {
|
error = true;
|
||||||
if (hexa_found || str.length() != 1 || str[0] != '0') {
|
|
||||||
return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (symbol < 0x7F && suffix_lut[lut_case][symbol]) {
|
||||||
|
if (symbol == 'x') {
|
||||||
hexa_found = true;
|
hexa_found = true;
|
||||||
} else if (GETCHAR(i) == 'e' && !hexa_found) {
|
lut_case = CASE_HEXA_PERIOD;
|
||||||
if (exponent_found || float_suffix_found) {
|
} else if (symbol == '.') {
|
||||||
return _make_token(TK_ERROR, "Invalid numeric constant");
|
period_found = true;
|
||||||
}
|
lut_case = CASE_HEXA_PERIOD;
|
||||||
|
} else if (symbol == 'e' && !hexa_found) {
|
||||||
exponent_found = true;
|
exponent_found = true;
|
||||||
} else if (GETCHAR(i) == 'f' && !hexa_found) {
|
lut_case = CASE_EXPONENT;
|
||||||
if (exponent_found) {
|
} else if (symbol == 'f' && !hexa_found) {
|
||||||
return _make_token(TK_ERROR, "Invalid numeric constant");
|
if (!period_found && !exponent_found) {
|
||||||
|
error = true;
|
||||||
}
|
}
|
||||||
float_suffix_found = true;
|
float_suffix_found = true;
|
||||||
} else if (_is_number(GETCHAR(i))) {
|
end_suffix_found = true;
|
||||||
if (float_suffix_found) {
|
lut_case = CASE_NONE;
|
||||||
return _make_token(TK_ERROR, "Invalid numeric constant");
|
} else if (symbol == 'u') {
|
||||||
}
|
uint_suffix_found = true;
|
||||||
} else if (hexa_found && _is_hex(GETCHAR(i))) {
|
end_suffix_found = true;
|
||||||
} else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
|
lut_case = CASE_NONE;
|
||||||
if (sign_found) {
|
} else if (symbol == '-' || symbol == '+') {
|
||||||
return _make_token(TK_ERROR, "Invalid numeric constant");
|
if (exponent_found) {
|
||||||
}
|
lut_case = CASE_SIGN_AFTER_EXPONENT;
|
||||||
sign_found = true;
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else if (!hexa_found || !_is_hex(symbol)) {
|
||||||
|
if (_is_text_char(symbol)) {
|
||||||
|
error = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
str += CharType(GETCHAR(i));
|
if (error) {
|
||||||
|
if (hexa_found) {
|
||||||
|
return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant");
|
||||||
|
}
|
||||||
|
if (period_found || exponent_found || float_suffix_found) {
|
||||||
|
return _make_token(TK_ERROR, "Invalid (float) numeric constant");
|
||||||
|
}
|
||||||
|
if (uint_suffix_found) {
|
||||||
|
return _make_token(TK_ERROR, "Invalid (unsigned integer) numeric constant");
|
||||||
|
}
|
||||||
|
return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
|
||||||
|
}
|
||||||
|
str += symbol;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,6 +621,9 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
||||||
}
|
}
|
||||||
} else if (period_found || exponent_found || float_suffix_found) {
|
} else if (period_found || exponent_found || float_suffix_found) {
|
||||||
//floats
|
//floats
|
||||||
|
if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+"
|
||||||
|
return _make_token(TK_ERROR, "Invalid (float) numeric constant");
|
||||||
|
}
|
||||||
if (period_found) {
|
if (period_found) {
|
||||||
if (float_suffix_found) {
|
if (float_suffix_found) {
|
||||||
//checks for eg "1.f" or "1.99f" notations
|
//checks for eg "1.f" or "1.99f" notations
|
||||||
|
@ -603,11 +655,18 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//integers
|
//integers
|
||||||
if (!_is_number(last_char)) {
|
if (uint_suffix_found) {
|
||||||
return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
|
// Strip the suffix.
|
||||||
|
str = str.left(str.length() - 1);
|
||||||
|
// Compensate reading cursor position.
|
||||||
|
char_idx += 1;
|
||||||
}
|
}
|
||||||
if (!str.is_valid_integer()) {
|
if (!str.is_valid_integer()) {
|
||||||
return _make_token(TK_ERROR, "Invalid numeric constant");
|
if (uint_suffix_found) {
|
||||||
|
return _make_token(TK_ERROR, "Invalid (usigned integer) numeric constant");
|
||||||
|
} else {
|
||||||
|
return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,6 +674,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
||||||
Token tk;
|
Token tk;
|
||||||
if (period_found || exponent_found || float_suffix_found) {
|
if (period_found || exponent_found || float_suffix_found) {
|
||||||
tk.type = TK_REAL_CONSTANT;
|
tk.type = TK_REAL_CONSTANT;
|
||||||
|
} else if (uint_suffix_found) {
|
||||||
|
tk.type = TK_UINT_CONSTANT;
|
||||||
} else {
|
} else {
|
||||||
tk.type = TK_INT_CONSTANT;
|
tk.type = TK_INT_CONSTANT;
|
||||||
}
|
}
|
||||||
|
@ -880,8 +941,9 @@ void ShaderLanguage::clear() {
|
||||||
completion_type = COMPLETION_NONE;
|
completion_type = COMPLETION_NONE;
|
||||||
completion_block = nullptr;
|
completion_block = nullptr;
|
||||||
completion_function = StringName();
|
completion_function = StringName();
|
||||||
completion_class = SubClassTag::TAG_GLOBAL;
|
completion_class = TAG_GLOBAL;
|
||||||
completion_struct = StringName();
|
completion_struct = StringName();
|
||||||
|
completion_base = TYPE_VOID;
|
||||||
|
|
||||||
error_line = 0;
|
error_line = 0;
|
||||||
tk_line = 1;
|
tk_line = 1;
|
||||||
|
@ -896,7 +958,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, StringName *r_struct_name) {
|
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, ConstantNode::Value *r_constant_value) {
|
||||||
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;
|
||||||
|
@ -993,12 +1055,17 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
|
||||||
if (r_array_size) {
|
if (r_array_size) {
|
||||||
*r_array_size = shader->constants[p_identifier].array_size;
|
*r_array_size = shader->constants[p_identifier].array_size;
|
||||||
}
|
}
|
||||||
if (r_type) {
|
|
||||||
*r_type = IDENTIFIER_CONSTANT;
|
|
||||||
}
|
|
||||||
if (r_struct_name) {
|
if (r_struct_name) {
|
||||||
*r_struct_name = shader->constants[p_identifier].type_str;
|
*r_struct_name = shader->constants[p_identifier].type_str;
|
||||||
}
|
}
|
||||||
|
if (r_constant_value) {
|
||||||
|
if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) {
|
||||||
|
*r_constant_value = shader->constants[p_identifier].initializer->values[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r_type) {
|
||||||
|
*r_type = IDENTIFIER_CONSTANT;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2119,6 +2186,8 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[]
|
||||||
{ nullptr, 0 }
|
{ nullptr, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool ShaderLanguage::is_const_suffix_lut_initialized = false;
|
||||||
|
|
||||||
bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
|
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);
|
||||||
|
|
||||||
|
@ -2471,6 +2540,10 @@ bool ShaderLanguage::is_token_operator_assign(TokenType p_type) {
|
||||||
p_type == TK_OP_ASSIGN_BIT_XOR);
|
p_type == TK_OP_ASSIGN_BIT_XOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShaderLanguage::is_token_hint(TokenType p_type) {
|
||||||
|
return int(p_type) > int(TK_RENDER_MODE) && int(p_type) < int(TK_SHADER_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
|
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
|
||||||
if (p_constant->datatype == p_to_type) {
|
if (p_constant->datatype == p_to_type) {
|
||||||
if (p_value) {
|
if (p_value) {
|
||||||
|
@ -2898,6 +2971,69 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error ShaderLanguage::_parse_array_size(BlockNode *p_block, int *r_array_size) {
|
||||||
|
if (r_array_size != nullptr && *r_array_size > 0) {
|
||||||
|
_set_error("Array size is already defined!");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
TkPos pos = _get_tkpos();
|
||||||
|
Token tk = _get_token();
|
||||||
|
|
||||||
|
int array_size = 0;
|
||||||
|
|
||||||
|
if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) {
|
||||||
|
_set_tkpos(pos);
|
||||||
|
Node *n = _parse_and_reduce_expression(p_block, Map<StringName, BuiltInInfo>());
|
||||||
|
if (n) {
|
||||||
|
if (n->type == Node::TYPE_VARIABLE) {
|
||||||
|
VariableNode *vn = static_cast<VariableNode *>(n);
|
||||||
|
if (vn) {
|
||||||
|
ConstantNode::Value v;
|
||||||
|
DataType data_type;
|
||||||
|
bool is_const = false;
|
||||||
|
|
||||||
|
_find_identifier(p_block, Map<StringName, BuiltInInfo>(), vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v);
|
||||||
|
|
||||||
|
if (is_const) {
|
||||||
|
if (data_type == TYPE_INT) {
|
||||||
|
int32_t value = v.sint;
|
||||||
|
if (value > 0) {
|
||||||
|
array_size = value;
|
||||||
|
}
|
||||||
|
} else if (data_type == TYPE_UINT) {
|
||||||
|
uint32_t value = v.uint;
|
||||||
|
if (value > 0U) {
|
||||||
|
array_size = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (n->type == Node::TYPE_OPERATOR) {
|
||||||
|
_set_error("Array size expressions are not yet implemented.");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (((int)tk.constant) > 0) {
|
||||||
|
array_size = (uint32_t)tk.constant;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_size <= 0) {
|
||||||
|
_set_error("Expected single integer constant > 0");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
tk = _get_token();
|
||||||
|
if (tk.type != TK_BRACKET_CLOSE) {
|
||||||
|
_set_error("Expected ']'");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r_array_size) {
|
||||||
|
*r_array_size = array_size;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size) {
|
ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size) {
|
||||||
DataType type = TYPE_VOID;
|
DataType type = TYPE_VOID;
|
||||||
String struct_name = "";
|
String struct_name = "";
|
||||||
|
@ -3071,6 +3207,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
||||||
constant->datatype = TYPE_INT;
|
constant->datatype = TYPE_INT;
|
||||||
expr = constant;
|
expr = constant;
|
||||||
|
|
||||||
|
} else if (tk.type == TK_UINT_CONSTANT) {
|
||||||
|
ConstantNode *constant = alloc_node<ConstantNode>();
|
||||||
|
ConstantNode::Value v;
|
||||||
|
v.uint = tk.constant;
|
||||||
|
constant->values.push_back(v);
|
||||||
|
constant->datatype = TYPE_UINT;
|
||||||
|
expr = constant;
|
||||||
|
|
||||||
} else if (tk.type == TK_TRUE) {
|
} else if (tk.type == TK_TRUE) {
|
||||||
//handle true constant
|
//handle true constant
|
||||||
ConstantNode *constant = alloc_node<ConstantNode>();
|
ConstantNode *constant = alloc_node<ConstantNode>();
|
||||||
|
@ -3174,141 +3318,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
||||||
if (!nexpr) {
|
if (!nexpr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType type = pstruct->members[i]->get_datatype();
|
|
||||||
String struct_name = pstruct->members[i]->struct_name;
|
|
||||||
int array_size = pstruct->members[i]->array_size;
|
|
||||||
|
|
||||||
DataType type2;
|
|
||||||
String struct_name2 = "";
|
|
||||||
int array_size2 = 0;
|
|
||||||
|
|
||||||
bool auto_size = false;
|
|
||||||
|
|
||||||
tk = _get_token();
|
|
||||||
|
|
||||||
if (tk.type == TK_CURLY_BRACKET_OPEN) {
|
|
||||||
auto_size = true;
|
|
||||||
} else {
|
|
||||||
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 nullptr;
|
|
||||||
}
|
|
||||||
type2 = get_token_datatype(tk.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
tk = _get_token();
|
|
||||||
if (tk.type == TK_BRACKET_OPEN) {
|
|
||||||
TkPos pos2 = _get_tkpos();
|
|
||||||
tk = _get_token();
|
|
||||||
if (tk.type == TK_BRACKET_CLOSE) {
|
|
||||||
array_size2 = array_size;
|
|
||||||
tk = _get_token();
|
|
||||||
} else {
|
|
||||||
_set_tkpos(pos2);
|
|
||||||
|
|
||||||
Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
|
|
||||||
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
|
|
||||||
_set_error("Expected single integer constant > 0");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstantNode *cnode = (ConstantNode *)n;
|
|
||||||
if (cnode->values.size() == 1) {
|
|
||||||
array_size2 = cnode->values[0].sint;
|
|
||||||
if (array_size2 <= 0) {
|
|
||||||
_set_error("Expected single integer constant > 0");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_set_error("Expected single integer constant > 0");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
tk = _get_token();
|
|
||||||
if (tk.type != TK_BRACKET_CLOSE) {
|
|
||||||
_set_error("Expected ']'");
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
tk = _get_token();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_set_error("Expected '['");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type != type2 || struct_name != struct_name2 || array_size != array_size2) {
|
|
||||||
String error_str = "Cannot convert from '";
|
|
||||||
if (type2 == TYPE_STRUCT) {
|
|
||||||
error_str += struct_name2;
|
|
||||||
} else {
|
|
||||||
error_str += get_datatype_name(type2);
|
|
||||||
}
|
|
||||||
error_str += "[";
|
|
||||||
error_str += itos(array_size2);
|
|
||||||
error_str += "]'";
|
|
||||||
error_str += " to '";
|
|
||||||
if (type == TYPE_STRUCT) {
|
|
||||||
error_str += struct_name;
|
|
||||||
} else {
|
|
||||||
error_str += get_datatype_name(type);
|
|
||||||
}
|
|
||||||
error_str += "[";
|
|
||||||
error_str += itos(array_size);
|
|
||||||
error_str += "]'";
|
|
||||||
_set_error(error_str);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
|
|
||||||
an->datatype = type;
|
|
||||||
an->struct_name = struct_name;
|
|
||||||
|
|
||||||
if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
|
|
||||||
while (true) {
|
|
||||||
Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
|
|
||||||
if (!n) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (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 '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
tk = _get_token();
|
|
||||||
if (tk.type == TK_COMMA) {
|
|
||||||
an->initializer.push_back(n);
|
|
||||||
continue;
|
|
||||||
} else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) {
|
|
||||||
an->initializer.push_back(n);
|
|
||||||
break;
|
|
||||||
} else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) {
|
|
||||||
an->initializer.push_back(n);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (auto_size) {
|
|
||||||
_set_error("Expected '}' or ','");
|
|
||||||
} else {
|
|
||||||
_set_error("Expected ')' or ','");
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (an->initializer.size() != array_size) {
|
|
||||||
_set_error("Array size mismatch");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_set_error("Expected array initialization!");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
|
nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
|
||||||
if (!nexpr) {
|
if (!nexpr) {
|
||||||
|
@ -4771,7 +4780,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
||||||
if (tk.type == TK_BRACKET_CLOSE) {
|
if (tk.type == TK_BRACKET_CLOSE) {
|
||||||
unknown_size = true;
|
unknown_size = true;
|
||||||
} else {
|
} else {
|
||||||
if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
|
if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) {
|
||||||
_set_error("Expected integer constant > 0 or ']'");
|
_set_error("Expected integer constant > 0 or ']'");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -5219,7 +5228,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tk.type != TK_INT_CONSTANT) {
|
if (!tk.is_integer_constant()) {
|
||||||
_set_error("Expected integer constant");
|
_set_error("Expected integer constant");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -5638,17 +5647,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
tk = _get_token();
|
StringName shader_type_identifier;
|
||||||
|
_get_completable_identifier(nullptr, COMPLETION_SHADER_TYPE, shader_type_identifier);
|
||||||
|
|
||||||
if (tk.type != TK_IDENTIFIER) {
|
if (shader_type_identifier == StringName()) {
|
||||||
_set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
|
_set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
String shader_type_identifier;
|
|
||||||
|
|
||||||
shader_type_identifier = tk.text;
|
|
||||||
|
|
||||||
if (!p_shader_types.has(shader_type_identifier)) {
|
if (!p_shader_types.has(shader_type_identifier)) {
|
||||||
_set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
|
_set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
@ -5770,7 +5775,31 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
bool fixed_array_size = false;
|
||||||
|
int array_size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
|
||||||
|
_set_error("Expected identifier or '['.");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tk.type == TK_BRACKET_OPEN) {
|
||||||
|
Error error = _parse_array_size(nullptr, &array_size);
|
||||||
|
if (error != OK) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
fixed_array_size = true;
|
||||||
|
tk = _get_token();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tk.type != TK_IDENTIFIER) {
|
if (tk.type != TK_IDENTIFIER) {
|
||||||
_set_error("Expected identifier!");
|
_set_error("Expected identifier!");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
@ -5781,42 +5810,35 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
member->datatype = type;
|
member->datatype = type;
|
||||||
member->struct_name = struct_name;
|
member->struct_name = struct_name;
|
||||||
member->name = tk.text;
|
member->name = tk.text;
|
||||||
|
member->array_size = array_size;
|
||||||
|
|
||||||
if (member_names.has(member->name)) {
|
if (member_names.has(member->name)) {
|
||||||
_set_error("Redefinition of '" + String(member->name) + "'");
|
_set_error("Redefinition of '" + String(member->name) + "'");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
member_names.insert(member->name);
|
member_names.insert(member->name);
|
||||||
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
|
||||||
if (tk.type == TK_BRACKET_OPEN) {
|
if (tk.type == TK_BRACKET_OPEN) {
|
||||||
|
Error error = _parse_array_size(nullptr, &member->array_size);
|
||||||
|
if (error != OK) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
|
}
|
||||||
member->array_size = (int)tk.constant;
|
|
||||||
|
|
||||||
tk = _get_token();
|
if (!fixed_array_size) {
|
||||||
if (tk.type == TK_BRACKET_CLOSE) {
|
array_size = 0;
|
||||||
tk = _get_token();
|
}
|
||||||
if (tk.type != TK_SEMICOLON) {
|
|
||||||
_set_error("Expected ';'");
|
if (tk.type != TK_SEMICOLON && tk.type != TK_COMMA) {
|
||||||
|
_set_error("Expected ',' or ';' after struct member.");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
_set_error("Expected ']'");
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_set_error("Expected single integer constant > 0");
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
st_node->members.push_back(member);
|
st_node->members.push_back(member);
|
||||||
|
|
||||||
if (tk.type != TK_SEMICOLON) {
|
|
||||||
_set_error("Expected ']' or ';'");
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
member_count++;
|
member_count++;
|
||||||
|
} while (tk.type == TK_COMMA); // another member
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (member_count == 0) {
|
if (member_count == 0) {
|
||||||
|
@ -5934,9 +5956,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
|
||||||
if (tk.type == TK_COLON) {
|
if (tk.type == TK_COLON) {
|
||||||
|
completion_type = COMPLETION_HINT;
|
||||||
|
completion_base = type;
|
||||||
|
|
||||||
//hint
|
//hint
|
||||||
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
completion_line = tk.line;
|
||||||
|
|
||||||
|
if (!is_token_hint(tk.type)) {
|
||||||
|
_set_error("Expected valid type hint after ':'.");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (tk.type == TK_HINT_WHITE_TEXTURE) {
|
if (tk.type == TK_HINT_WHITE_TEXTURE) {
|
||||||
uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
|
uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
|
||||||
} else if (tk.type == TK_HINT_BLACK_TEXTURE) {
|
} else if (tk.type == TK_HINT_BLACK_TEXTURE) {
|
||||||
|
@ -5977,7 +6009,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
|
if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) {
|
||||||
_set_error("Expected integer constant");
|
_set_error("Expected integer constant");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -6001,7 +6033,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
|
if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) {
|
||||||
_set_error("Expected integer constant after ','");
|
_set_error("Expected integer constant after ','");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -6014,7 +6046,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
if (tk.type == TK_COMMA) {
|
if (tk.type == TK_COMMA) {
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
|
||||||
if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
|
if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) {
|
||||||
_set_error("Expected integer constant after ','");
|
_set_error("Expected integer constant after ','");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -6033,10 +6065,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
_set_error("Expected ','");
|
_set_error("Expected ','");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
_set_error("Expected valid type hint after ':'.");
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) {
|
if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) {
|
||||||
|
@ -6074,6 +6102,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
_set_error("Expected ';'");
|
_set_error("Expected ';'");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
completion_type = COMPLETION_NONE;
|
||||||
} else { // varying
|
} else { // varying
|
||||||
ShaderNode::Varying varying;
|
ShaderNode::Varying varying;
|
||||||
varying.type = type;
|
varying.type = type;
|
||||||
|
@ -6094,7 +6124,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
|
if (tk.is_integer_constant() && tk.constant > 0) {
|
||||||
varying.array_size = (int)tk.constant;
|
varying.array_size = (int)tk.constant;
|
||||||
|
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
|
@ -6118,6 +6148,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
case TK_SHADER_TYPE: {
|
||||||
|
_set_error("Shader type is already defined.");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
} break;
|
||||||
default: {
|
default: {
|
||||||
//function or constant variable
|
//function or constant variable
|
||||||
|
|
||||||
|
@ -6216,7 +6250,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
if (tk.type == TK_BRACKET_CLOSE) {
|
if (tk.type == TK_BRACKET_CLOSE) {
|
||||||
unknown_size = true;
|
unknown_size = true;
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
} else if (tk.type == TK_INT_CONSTANT && ((int)tk.constant) > 0) {
|
} else if (tk.is_integer_constant() && ((int)tk.constant) > 0) {
|
||||||
constant.array_size = (int)tk.constant;
|
constant.array_size = (int)tk.constant;
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
if (tk.type != TK_BRACKET_CLOSE) {
|
if (tk.type != TK_BRACKET_CLOSE) {
|
||||||
|
@ -6493,6 +6527,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < shader->functions.size(); i++) {
|
||||||
|
if (!shader->functions[i].callable && shader->functions[i].name == name) {
|
||||||
|
_set_error("Redefinition of '" + String(name) + "'");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ShaderNode::Function function;
|
ShaderNode::Function function;
|
||||||
|
|
||||||
function.callable = !p_functions.has(name);
|
function.callable = !p_functions.has(name);
|
||||||
|
@ -6865,9 +6906,17 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
||||||
//do nothing
|
//do nothing
|
||||||
return OK;
|
return OK;
|
||||||
} break;
|
} break;
|
||||||
|
case COMPLETION_SHADER_TYPE: {
|
||||||
|
for (const Set<String>::Element *E = p_shader_types.front(); E; E = E->next()) {
|
||||||
|
ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
||||||
|
r_options->push_back(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
} break;
|
||||||
case COMPLETION_RENDER_MODE: {
|
case COMPLETION_RENDER_MODE: {
|
||||||
for (int i = 0; i < p_render_modes.size(); i++) {
|
for (int i = 0; i < p_render_modes.size(); i++) {
|
||||||
ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_ENUM);
|
ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
||||||
r_options->push_back(option);
|
r_options->push_back(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6886,6 +6935,19 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
||||||
} break;
|
} 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()) {
|
||||||
|
if (!E->get().main_function) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool found = false;
|
||||||
|
for (int i = 0; i < shader->functions.size(); i++) {
|
||||||
|
if (shader->functions[i].name == E->key()) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
|
ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
|
||||||
r_options->push_back(option);
|
r_options->push_back(option);
|
||||||
}
|
}
|
||||||
|
@ -6940,7 +7002,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
||||||
matches.insert(E->key(), kind);
|
matches.insert(E->key(), kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (Map<StringName, ShaderNode::Constant>::Element *E = shader->constants.front(); E; E = E->next()) {
|
||||||
|
matches.insert(E->key(), ScriptCodeCompletionOption::KIND_CONSTANT);
|
||||||
|
}
|
||||||
for (OrderedHashMap<StringName, ShaderNode::Varying>::Element E = shader->varyings.front(); E; E = E.next()) {
|
for (OrderedHashMap<StringName, ShaderNode::Varying>::Element E = shader->varyings.front(); E; E = E.next()) {
|
||||||
matches.insert(E.key(), ScriptCodeCompletionOption::KIND_VARIABLE);
|
matches.insert(E.key(), ScriptCodeCompletionOption::KIND_VARIABLE);
|
||||||
}
|
}
|
||||||
|
@ -7143,6 +7207,38 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
case COMPLETION_HINT: {
|
||||||
|
if (completion_base == DataType::TYPE_VEC4) {
|
||||||
|
ScriptCodeCompletionOption option("hint_color", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
||||||
|
r_options->push_back(option);
|
||||||
|
} else if ((completion_base == DataType::TYPE_INT || completion_base == DataType::TYPE_FLOAT)) {
|
||||||
|
ScriptCodeCompletionOption option("hint_range", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
||||||
|
|
||||||
|
if (completion_base == DataType::TYPE_INT) {
|
||||||
|
option.insert_text = "hint_range(0, 100, 1)";
|
||||||
|
} else {
|
||||||
|
option.insert_text = "hint_range(0.0, 1.0, 0.1)";
|
||||||
|
}
|
||||||
|
|
||||||
|
r_options->push_back(option);
|
||||||
|
} else if ((int(completion_base) > int(TYPE_MAT4) && int(completion_base) < int(TYPE_STRUCT))) {
|
||||||
|
static Vector<String> options;
|
||||||
|
|
||||||
|
if (options.empty()) {
|
||||||
|
options.push_back("hint_albedo");
|
||||||
|
options.push_back("hint_aniso");
|
||||||
|
options.push_back("hint_black");
|
||||||
|
options.push_back("hint_black_albedo");
|
||||||
|
options.push_back("hint_normal");
|
||||||
|
options.push_back("hint_white");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < options.size(); i++) {
|
||||||
|
ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
||||||
|
r_options->push_back(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
TK_FALSE,
|
TK_FALSE,
|
||||||
TK_REAL_CONSTANT,
|
TK_REAL_CONSTANT,
|
||||||
TK_INT_CONSTANT,
|
TK_INT_CONSTANT,
|
||||||
|
TK_UINT_CONSTANT,
|
||||||
TK_TYPE_VOID,
|
TK_TYPE_VOID,
|
||||||
TK_TYPE_BOOL,
|
TK_TYPE_BOOL,
|
||||||
TK_TYPE_BVEC2,
|
TK_TYPE_BVEC2,
|
||||||
|
@ -695,6 +696,7 @@ public:
|
||||||
|
|
||||||
enum CompletionType {
|
enum CompletionType {
|
||||||
COMPLETION_NONE,
|
COMPLETION_NONE,
|
||||||
|
COMPLETION_SHADER_TYPE,
|
||||||
COMPLETION_RENDER_MODE,
|
COMPLETION_RENDER_MODE,
|
||||||
COMPLETION_MAIN_FUNCTION,
|
COMPLETION_MAIN_FUNCTION,
|
||||||
COMPLETION_IDENTIFIER,
|
COMPLETION_IDENTIFIER,
|
||||||
|
@ -702,6 +704,7 @@ public:
|
||||||
COMPLETION_CALL_ARGUMENTS,
|
COMPLETION_CALL_ARGUMENTS,
|
||||||
COMPLETION_INDEX,
|
COMPLETION_INDEX,
|
||||||
COMPLETION_STRUCT,
|
COMPLETION_STRUCT,
|
||||||
|
COMPLETION_HINT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
|
@ -709,6 +712,9 @@ public:
|
||||||
StringName text;
|
StringName text;
|
||||||
double constant;
|
double constant;
|
||||||
uint16_t line;
|
uint16_t line;
|
||||||
|
bool is_integer_constant() const {
|
||||||
|
return type == TK_INT_CONSTANT || type == TK_UINT_CONSTANT;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static String get_operator_text(Operator p_op);
|
static String get_operator_text(Operator p_op);
|
||||||
|
@ -726,6 +732,7 @@ public:
|
||||||
static bool is_token_nonvoid_datatype(TokenType p_type);
|
static bool is_token_nonvoid_datatype(TokenType p_type);
|
||||||
static bool is_token_operator(TokenType p_type);
|
static bool is_token_operator(TokenType p_type);
|
||||||
static bool is_token_operator_assign(TokenType p_type);
|
static bool is_token_operator_assign(TokenType p_type);
|
||||||
|
static bool is_token_hint(TokenType p_type);
|
||||||
|
|
||||||
static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr);
|
static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr);
|
||||||
static DataType get_scalar_type(DataType p_type);
|
static DataType get_scalar_type(DataType p_type);
|
||||||
|
@ -754,6 +761,11 @@ public:
|
||||||
struct FunctionInfo {
|
struct FunctionInfo {
|
||||||
Map<StringName, BuiltInInfo> built_ins;
|
Map<StringName, BuiltInInfo> built_ins;
|
||||||
bool can_discard;
|
bool can_discard;
|
||||||
|
bool main_function;
|
||||||
|
|
||||||
|
FunctionInfo() :
|
||||||
|
can_discard(false), main_function(false) {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
|
static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
|
||||||
|
|
||||||
|
@ -817,7 +829,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, StringName *r_struct_name = 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, ConstantNode::Value *r_constant_value = 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);
|
||||||
|
@ -849,6 +861,8 @@ private:
|
||||||
static const BuiltinFuncDef builtin_func_defs[];
|
static const BuiltinFuncDef builtin_func_defs[];
|
||||||
static const BuiltinFuncOutArgs builtin_func_out_args[];
|
static const BuiltinFuncOutArgs builtin_func_out_args[];
|
||||||
|
|
||||||
|
static bool is_const_suffix_lut_initialized;
|
||||||
|
|
||||||
Error _validate_datatype(DataType p_type);
|
Error _validate_datatype(DataType p_type);
|
||||||
bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
|
bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
|
||||||
|
|
||||||
|
@ -857,6 +871,7 @@ private:
|
||||||
bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message);
|
bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message);
|
||||||
|
|
||||||
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);
|
||||||
|
Error _parse_array_size(BlockNode *p_block, int *r_array_size);
|
||||||
Node *_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size);
|
Node *_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size);
|
||||||
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
|
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,6 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT);
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
|
|
||||||
|
|
||||||
//builtins
|
//builtins
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4;
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4;
|
||||||
|
@ -82,6 +81,7 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
|
||||||
|
shader_modes[VS::SHADER_SPATIAL].functions["vertex"].main_function = true;
|
||||||
|
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
|
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
|
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
|
||||||
|
@ -130,6 +130,7 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
|
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
|
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].can_discard = true;
|
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].can_discard = true;
|
||||||
|
shader_modes[VS::SHADER_SPATIAL].functions["fragment"].main_function = true;
|
||||||
|
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
|
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
|
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
|
||||||
|
@ -155,6 +156,7 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
|
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
|
shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
|
||||||
shader_modes[VS::SHADER_SPATIAL].functions["light"].can_discard = true;
|
shader_modes[VS::SHADER_SPATIAL].functions["light"].can_discard = true;
|
||||||
|
shader_modes[VS::SHADER_SPATIAL].functions["light"].main_function = true;
|
||||||
|
|
||||||
//order used puts first enum mode (default) first
|
//order used puts first enum mode (default) first
|
||||||
shader_modes[VS::SHADER_SPATIAL].modes.push_back("blend_mix");
|
shader_modes[VS::SHADER_SPATIAL].modes.push_back("blend_mix");
|
||||||
|
@ -218,7 +220,7 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["VERTEX_ID"] = constt(ShaderLanguage::TYPE_INT);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].main_function = true;
|
||||||
|
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
|
||||||
|
@ -236,6 +238,7 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
|
||||||
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].main_function = true;
|
||||||
|
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
|
||||||
|
@ -254,6 +257,7 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_COLOR"] = ShaderLanguage::TYPE_VEC4;
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_COLOR"] = ShaderLanguage::TYPE_VEC4;
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;
|
||||||
|
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].main_function = true;
|
||||||
|
|
||||||
shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform");
|
shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform");
|
||||||
|
|
||||||
|
@ -283,7 +287,7 @@ ShaderTypes::ShaderTypes() {
|
||||||
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
|
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
|
||||||
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
|
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
|
||||||
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
|
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
|
||||||
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].can_discard = false;
|
shader_modes[VS::SHADER_PARTICLES].functions["vertex"].main_function = true;
|
||||||
|
|
||||||
shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_force");
|
shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_force");
|
||||||
shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_velocity");
|
shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_velocity");
|
||||||
|
|
Loading…
Reference in a new issue