Add basic support to evaluate operator value in shader language

This commit is contained in:
Yuri Rubinsky 2024-07-01 16:39:49 +03:00 committed by Chaosus
parent d0dc3896ad
commit af92fdb0ac
5 changed files with 540 additions and 121 deletions

View file

@ -1362,7 +1362,7 @@ void ShaderLanguage::_parse_used_identifier(const StringName &p_identifier, Iden
}
#endif // DEBUG_ENABLED
bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, 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) {
bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, Vector<Scalar> *r_constant_values) {
if (is_shader_inc) {
for (int i = 0; i < RenderingServer::SHADER_MAX; i++) {
for (const KeyValue<StringName, FunctionInfo> &E : ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(i))) {
@ -1424,8 +1424,8 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_struct_name) {
*r_struct_name = p_block->variables[p_identifier].struct_name;
}
if (r_constant_value) {
*r_constant_value = p_block->variables[p_identifier].value;
if (r_constant_values && !p_block->variables[p_identifier].values.is_empty()) {
*r_constant_values = p_block->variables[p_identifier].values;
}
if (r_type) {
*r_type = IDENTIFIER_LOCAL_VAR;
@ -1507,13 +1507,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_struct_name) {
*r_struct_name = shader->constants[p_identifier].struct_name;
}
if (r_constant_value) {
if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->type == Node::NODE_TYPE_CONSTANT) {
ConstantNode *cnode = static_cast<ConstantNode *>(shader->constants[p_identifier].initializer);
if (cnode->values.size() == 1) {
*r_constant_value = cnode->values[0];
}
if (r_constant_values) {
if (shader->constants[p_identifier].initializer && !shader->constants[p_identifier].initializer->get_values().is_empty()) {
*r_constant_values = shader->constants[p_identifier].initializer->get_values();
}
}
if (r_type) {
@ -1544,7 +1540,7 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
return false;
}
bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type, int *r_ret_size) {
bool ShaderLanguage::_validate_operator(const BlockNode *p_block, OperatorNode *p_op, DataType *r_ret_type, int *r_ret_size) {
bool valid = false;
DataType ret_type = TYPE_VOID;
int ret_size = 0;
@ -2007,9 +2003,384 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
if (r_ret_size) {
*r_ret_size = ret_size;
}
if (valid && (!p_block || p_block->use_op_eval)) {
// Need to be placed here and not in the `_reduce_expression` because otherwise expressions like `1 + 2 / 2` will not work correctly.
valid = _eval_operator(p_block, p_op);
}
return valid;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_get_node_values(const BlockNode *p_block, Node *p_node) {
Vector<Scalar> result;
switch (p_node->type) {
case Node::NODE_TYPE_VARIABLE: {
_find_identifier(p_block, false, FunctionInfo(), static_cast<VariableNode *>(p_node)->name, nullptr, nullptr, nullptr, nullptr, nullptr, &result);
} break;
default: {
result = p_node->get_values();
} break;
}
return result;
}
bool ShaderLanguage::_eval_operator(const BlockNode *p_block, OperatorNode *p_op) {
bool is_valid = true;
switch (p_op->op) {
case OP_EQUAL:
case OP_NOT_EQUAL:
case OP_LESS:
case OP_LESS_EQUAL:
case OP_GREATER:
case OP_GREATER_EQUAL:
case OP_AND:
case OP_OR:
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_DIV:
case OP_MOD:
case OP_SHIFT_LEFT:
case OP_SHIFT_RIGHT:
case OP_BIT_AND:
case OP_BIT_OR:
case OP_BIT_XOR: {
DataType a = p_op->arguments[0]->get_datatype();
DataType b = p_op->arguments[1]->get_datatype();
bool is_op_vec_transform = false;
if (p_op->op == OP_MUL) {
DataType ta = a;
DataType tb = b;
if (ta > tb) {
SWAP(ta, tb);
}
if (ta == TYPE_VEC2 && tb == TYPE_MAT2) {
is_op_vec_transform = true;
} else if (ta == TYPE_VEC3 && tb == TYPE_MAT3) {
is_op_vec_transform = true;
} else if (ta == TYPE_VEC4 && tb == TYPE_MAT4) {
is_op_vec_transform = true;
}
}
Vector<Scalar> va = _get_node_values(p_block, p_op->arguments[0]);
Vector<Scalar> vb = _get_node_values(p_block, p_op->arguments[1]);
if (is_op_vec_transform) {
p_op->values = _eval_vector_transform(va, vb, a, b, p_op->get_datatype());
} else {
p_op->values = _eval_vector(va, vb, a, b, p_op->get_datatype(), p_op->op, is_valid);
}
} break;
case OP_NOT:
case OP_NEGATE:
case OP_BIT_INVERT: {
p_op->values = _eval_unary_vector(_get_node_values(p_block, p_op->arguments[0]), p_op->get_datatype(), p_op->op);
} break;
default: {
} break;
}
return is_valid;
}
ShaderLanguage::Scalar ShaderLanguage::_eval_unary_scalar(const Scalar &p_a, Operator p_op, DataType p_ret_type) {
Scalar scalar;
switch (p_op) {
case OP_NOT: {
scalar.boolean = !p_a.boolean;
} break;
case OP_NEGATE: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = -p_a.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
// Intentionally wrap the unsigned int value, because GLSL does.
scalar.uint = 0 - p_a.uint;
} else { // float types
scalar.real = -scalar.real;
}
} break;
case OP_BIT_INVERT: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = ~p_a.sint;
} else { // uint types
scalar.uint = ~p_a.uint;
}
} break;
default: {
} break;
}
return scalar;
}
ShaderLanguage::Scalar ShaderLanguage::_eval_scalar(const Scalar &p_a, const Scalar &p_b, Operator p_op, DataType p_ret_type, bool &r_is_valid) {
Scalar scalar;
switch (p_op) {
case OP_EQUAL: {
scalar.boolean = p_a.boolean == p_b.boolean;
} break;
case OP_NOT_EQUAL: {
scalar.boolean = p_a.boolean != p_b.boolean;
} break;
case OP_LESS: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint < p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint < p_b.uint;
} else { // float type
scalar.boolean = p_a.real < p_b.real;
}
} break;
case OP_LESS_EQUAL: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint <= p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint <= p_b.uint;
} else { // float type
scalar.boolean = p_a.real <= p_b.real;
}
} break;
case OP_GREATER: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint > p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint > p_b.uint;
} else { // float type
scalar.boolean = p_a.real > p_b.real;
}
} break;
case OP_GREATER_EQUAL: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint >= p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint >= p_b.uint;
} else { // float type
scalar.boolean = p_a.real >= p_b.real;
}
} break;
case OP_AND: {
scalar.boolean = p_a.boolean && p_b.boolean;
} break;
case OP_OR: {
scalar.boolean = p_a.boolean || p_b.boolean;
} break;
case OP_ADD: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint + p_b.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
scalar.uint = p_a.uint + p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real + p_b.real;
}
} break;
case OP_SUB: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint - p_b.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
scalar.uint = p_a.uint - p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real - p_b.real;
}
} break;
case OP_MUL: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint * p_b.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
scalar.uint = p_a.uint * p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real * p_b.real;
}
} break;
case OP_DIV: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
if (p_b.sint == 0) {
_set_error(RTR("Division by zero error."));
r_is_valid = false;
break;
}
scalar.sint = p_a.sint / p_b.sint;
} else if (p_ret_type == TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
if (p_b.uint == 0U) {
_set_error(RTR("Division by zero error."));
r_is_valid = false;
break;
}
scalar.uint = p_a.uint / p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real / p_b.real;
}
} break;
case OP_MOD: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
if (p_b.sint == 0) {
_set_error(RTR("Modulo by zero error."));
r_is_valid = false;
break;
}
scalar.sint = p_a.sint % p_b.sint;
} else { // uint types
if (p_b.uint == 0U) {
_set_error(RTR("Modulo by zero error."));
r_is_valid = false;
break;
}
scalar.uint = p_a.uint % p_b.uint;
}
} break;
case OP_SHIFT_LEFT: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint << p_b.sint;
} else { // uint types
scalar.uint = p_a.uint << p_b.uint;
}
} break;
case OP_SHIFT_RIGHT: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint >> p_b.sint;
} else { // uint types
scalar.uint = p_a.uint >> p_b.uint;
}
} break;
case OP_BIT_AND: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint & p_b.sint;
} else { // uint types
scalar.uint = p_a.uint & p_b.uint;
}
} break;
case OP_BIT_OR: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint | p_b.sint;
} else { // uint types
scalar.uint = p_a.uint | p_b.uint;
}
} break;
case OP_BIT_XOR: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint ^ p_b.sint;
} else { // uint types
scalar.uint = p_a.uint ^ p_b.uint;
}
} break;
default: {
} break;
}
return scalar;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_eval_unary_vector(const Vector<Scalar> &p_va, DataType p_ret_type, Operator p_op) {
uint32_t size = get_datatype_component_count(p_ret_type);
if (p_va.size() != p_ret_type) {
return Vector<Scalar>(); // Non-evaluable values should not be parsed further.
}
Vector<Scalar> value;
value.resize(size);
Scalar *w = value.ptrw();
for (uint32_t i = 0U; i < size; i++) {
w[i] = _eval_unary_scalar(p_va[i], p_op, p_ret_type);
}
return value;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_eval_vector(const Vector<Scalar> &p_va, const Vector<Scalar> &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type, Operator p_op, bool &r_is_valid) {
uint32_t left_size = get_datatype_component_count(p_left_type);
uint32_t right_size = get_datatype_component_count(p_right_type);
if (p_va.size() != left_size || p_vb.size() != right_size) {
return Vector<Scalar>(); // Non-evaluable values should not be parsed further.
}
uint32_t ret_size = get_datatype_component_count(p_ret_type);
Vector<Scalar> value;
value.resize(ret_size);
Scalar *w = value.ptrw();
for (uint32_t i = 0U; i < ret_size; i++) {
w[i] = _eval_scalar(p_va[MIN(i, left_size - 1)], p_vb[MIN(i, right_size - 1)], p_op, p_ret_type, r_is_valid);
if (!r_is_valid) {
return value;
}
}
return value;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_eval_vector_transform(const Vector<Scalar> &p_va, const Vector<Scalar> &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type) {
uint32_t left_size = get_datatype_component_count(p_left_type);
uint32_t right_size = get_datatype_component_count(p_right_type);
if (p_va.size() != left_size || p_vb.size() != right_size) {
return Vector<Scalar>(); // Non-evaluable values should not be parsed further.
}
uint32_t ret_size = get_datatype_component_count(p_ret_type);
Vector<Scalar> value;
value.resize_zeroed(ret_size);
Scalar *w = value.ptrw();
switch (p_ret_type) {
case TYPE_VEC2: {
if (left_size == 2) { // v * m
Vector2 v = Vector2(p_va[0].real, p_va[1].real);
w[0].real = (p_vb[0].real * v.x + p_vb[1].real * v.y);
w[1].real = (p_vb[2].real * v.x + p_vb[3].real * v.y);
} else { // m * v
Vector2 v = Vector2(p_vb[0].real, p_vb[1].real);
w[0].real = (p_va[0].real * v.x + p_va[2].real * v.y);
w[1].real = (p_va[1].real * v.x + p_va[3].real * v.y);
}
} break;
case TYPE_VEC3: {
if (left_size == 3) { // v * m
Vector3 v = Vector3(p_va[0].real, p_va[1].real, p_va[2].real);
w[0].real = (p_vb[0].real * v.x + p_vb[1].real * v.y + p_vb[2].real * v.z);
w[1].real = (p_vb[3].real * v.x + p_vb[4].real * v.y + p_vb[5].real * v.z);
w[2].real = (p_vb[6].real * v.x + p_vb[7].real * v.y + p_vb[8].real * v.z);
} else { // m * v
Vector3 v = Vector3(p_vb[0].real, p_vb[1].real, p_vb[2].real);
w[0].real = (p_va[0].real * v.x + p_va[3].real * v.y + p_va[6].real * v.z);
w[1].real = (p_va[1].real * v.x + p_va[4].real * v.y + p_va[7].real * v.z);
w[2].real = (p_va[2].real * v.x + p_va[5].real * v.y + p_va[8].real * v.z);
}
} break;
case TYPE_VEC4: {
if (left_size == 4) { // v * m
Vector4 v = Vector4(p_va[0].real, p_va[1].real, p_va[2].real, p_va[3].real);
w[0].real = (p_vb[0].real * v.x + p_vb[1].real * v.y + p_vb[2].real * v.z + p_vb[3].real * v.w);
w[1].real = (p_vb[4].real * v.x + p_vb[5].real * v.y + p_vb[6].real * v.z + p_vb[7].real * v.w);
w[2].real = (p_vb[8].real * v.x + p_vb[9].real * v.y + p_vb[10].real * v.z + p_vb[11].real * v.w);
w[3].real = (p_vb[12].real * v.x + p_vb[13].real * v.y + p_vb[14].real * v.z + p_vb[15].real * v.w);
} else { // m * v
Vector4 v = Vector4(p_vb[0].real, p_vb[1].real, p_vb[2].real, p_vb[3].real);
w[0].real = (p_vb[0].real * v.x + p_vb[4].real * v.y + p_vb[8].real * v.z + p_vb[12].real * v.w);
w[1].real = (p_vb[1].real * v.x + p_vb[5].real * v.y + p_vb[9].real * v.z + p_vb[13].real * v.w);
w[2].real = (p_vb[2].real * v.x + p_vb[6].real * v.y + p_vb[10].real * v.z + p_vb[14].real * v.w);
w[3].real = (p_vb[3].real * v.x + p_vb[7].real * v.y + p_vb[11].real * v.z + p_vb[15].real * v.w);
}
} break;
default: {
} break;
}
return value;
}
const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
// Constructors.
@ -3271,34 +3642,15 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
int max = builtin_func_const_args[constarg_idx].max;
bool error = false;
if (p_func->arguments[arg]->type == Node::NODE_TYPE_VARIABLE) {
const VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg]);
bool is_const = false;
ConstantNode::Value value;
value.sint = -1;
_find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, &is_const, nullptr, nullptr, &value);
if (!is_const || value.sint < min || value.sint > max) {
Vector<Scalar> values = _get_node_values(p_block, p_func->arguments[arg]);
if (p_func->arguments[arg]->get_datatype() == TYPE_INT && !values.is_empty()) {
if (values[0].sint < min || values[0].sint > max) {
error = true;
}
} else {
if (p_func->arguments[arg]->type == Node::NODE_TYPE_CONSTANT) {
const ConstantNode *cn = static_cast<ConstantNode *>(p_func->arguments[arg]);
if (cn->get_datatype() == TYPE_INT && cn->values.size() == 1) {
int value = cn->values[0].sint;
if (value < min || value > max) {
error = true;
}
} else {
error = true;
}
} else {
error = true;
}
error = true;
}
if (error) {
_set_error(vformat(RTR("Expected integer constant within [%d..%d] range."), min, max));
return false;
@ -3760,7 +4112,7 @@ 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, Scalar *p_value) {
if (p_constant->datatype == p_to_type) {
if (p_value) {
for (int i = 0; i < p_constant->values.size(); i++) {
@ -3828,7 +4180,7 @@ bool ShaderLanguage::is_sampler_type(DataType p_type) {
return p_type > TYPE_MAT4 && p_type < TYPE_STRUCT;
}
Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
Variant ShaderLanguage::constant_value_to_variant(const Vector<Scalar> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
int array_size = p_array_size;
if (p_value.size() > 0) {
@ -4437,6 +4789,52 @@ uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) {
ERR_FAIL_V(0);
}
uint32_t ShaderLanguage::get_datatype_component_count(ShaderLanguage::DataType p_type) {
switch (p_type) {
case TYPE_BOOL:
return 1U;
case TYPE_BVEC2:
return 2U;
case TYPE_BVEC3:
return 3U;
case TYPE_BVEC4:
return 4U;
case TYPE_INT:
return 1U;
case TYPE_IVEC2:
return 2U;
case TYPE_IVEC3:
return 3U;
case TYPE_IVEC4:
return 4U;
case TYPE_UINT:
return 1U;
case TYPE_UVEC2:
return 2U;
case TYPE_UVEC3:
return 3U;
case TYPE_UVEC4:
return 4U;
case TYPE_FLOAT:
return 1U;
case TYPE_VEC2:
return 2U;
case TYPE_VEC3:
return 3U;
case TYPE_VEC4:
return 4U;
case TYPE_MAT2:
return 4U;
case TYPE_MAT3:
return 9U;
case TYPE_MAT4:
return 16U;
default:
break;
}
return 0U;
}
void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
HashSet<String> kws;
@ -4929,45 +5327,30 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &
*r_unknown_size = true;
}
} else {
_set_tkpos(pos);
int array_size = 0;
Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) {
_set_tkpos(pos);
Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (n) {
if (n->type == Node::NODE_TYPE_VARIABLE) {
VariableNode *vn = static_cast<VariableNode *>(n);
if (vn) {
ConstantNode::Value v;
DataType data_type;
bool is_const = false;
if (expr) {
Vector<Scalar> values = _get_node_values(p_block, expr);
_find_identifier(p_block, false, p_function_info, 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::NODE_TYPE_OPERATOR) {
_set_error(vformat(RTR("Array size expressions are not supported.")));
return ERR_PARSE_ERROR;
}
if (r_size_expression != nullptr) {
*r_size_expression = n;
if (!values.is_empty()) {
switch (expr->get_datatype()) {
case TYPE_INT: {
array_size = values[0].sint;
} break;
case TYPE_UINT: {
array_size = (int)values[0].uint;
} break;
default: {
} break;
}
}
} else if (((int)tk.constant) > 0) {
array_size = (uint32_t)tk.constant;
if (r_size_expression != nullptr) {
*r_size_expression = expr;
}
}
if (array_size <= 0) {
@ -5064,7 +5447,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
idx++;
}
if (!auto_size && !undefined_size && an->initializer.size() != array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), array_size, an->initializer.size()));
return nullptr;
}
} else {
@ -5185,7 +5568,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
}
}
if (an->initializer.size() != p_array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), p_array_size, an->initializer.size()));
return nullptr;
}
} else {
@ -5230,7 +5613,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_FLOAT_CONSTANT) {
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.real = tk.constant;
constant->values.push_back(v);
constant->datatype = TYPE_FLOAT;
@ -5238,7 +5621,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_INT_CONSTANT) {
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.sint = tk.constant;
constant->values.push_back(v);
constant->datatype = TYPE_INT;
@ -5246,7 +5629,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_UINT_CONSTANT) {
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.uint = tk.constant;
constant->values.push_back(v);
constant->datatype = TYPE_UINT;
@ -5255,7 +5638,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_TRUE) {
//handle true constant
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.boolean = true;
constant->values.push_back(v);
constant->datatype = TYPE_BOOL;
@ -5264,7 +5647,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_FALSE) {
//handle false constant
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.boolean = false;
constant->values.push_back(v);
constant->datatype = TYPE_BOOL;
@ -6527,7 +6910,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
op->op = tk.type == TK_OP_DECREMENT ? OP_POST_DECREMENT : OP_POST_INCREMENT;
op->arguments.push_back(expr);
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
_set_error(RTR("Invalid base type for increment/decrement operator."));
return nullptr;
}
@ -6876,7 +7259,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[i].is_op = false;
expression.write[i].node = op;
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
if (error_set) {
return nullptr;
}
String at;
for (int j = 0; j < op->arguments.size(); j++) {
if (j > 0) {
@ -6914,7 +7301,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[next_op - 1].is_op = false;
expression.write[next_op - 1].node = op;
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
if (error_set) {
return nullptr;
}
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
@ -6950,6 +7341,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (_is_operator_assign(op->op)) {
if (p_block && expression[next_op - 1].node->type == Node::NODE_TYPE_VARIABLE) {
VariableNode *vn = static_cast<VariableNode *>(expression[next_op - 1].node);
p_block->use_op_eval = vn->is_const;
}
String assign_message;
if (!_validate_assign(expression[next_op - 1].node, p_function_info, &assign_message)) {
_set_error(assign_message);
@ -6972,7 +7368,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//replace all 3 nodes by this operator and make it an expression
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
if (error_set) {
return nullptr;
}
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
@ -6998,6 +7398,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
if (p_block) {
p_block->use_op_eval = true;
}
if (p_previous_expression_info != nullptr) {
p_previous_expression_info->expression->push_back(expression[0]);
}
@ -7020,7 +7424,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
DataType base = get_scalar_type(type);
int cardinality = get_cardinality(type);
Vector<ConstantNode::Value> values;
Vector<Scalar> values;
for (int i = 1; i < op->arguments.size(); i++) {
op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]);
@ -7032,7 +7436,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
values.push_back(cn->values[j]);
}
} else if (get_scalar_type(cn->datatype) == cn->datatype) {
ConstantNode::Value v;
Scalar v;
if (!convert_constant(cn, base, &v)) {
return p_node;
}
@ -7048,8 +7452,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
if (values.size() == 1) {
if (type >= TYPE_MAT2 && type <= TYPE_MAT4) {
ConstantNode::Value value = values[0];
ConstantNode::Value zero;
Scalar value = values[0];
Scalar zero;
zero.real = 0.0f;
int size = 2 + (type - TYPE_MAT2);
@ -7060,7 +7464,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
}
}
} else {
ConstantNode::Value value = values[0];
Scalar value = values[0];
for (int i = 1; i < cardinality; i++) {
values.push_back(value);
}
@ -7081,10 +7485,10 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
DataType base = get_scalar_type(cn->datatype);
Vector<ConstantNode::Value> values;
Vector<Scalar> values;
for (int i = 0; i < cn->values.size(); i++) {
ConstantNode::Value nv;
Scalar nv;
switch (base) {
case TYPE_BOOL: {
nv.boolean = !cn->values[i].boolean;
@ -7515,7 +7919,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
decl.size = decl.initializer.size();
var.array_size = decl.initializer.size();
} else if (decl.initializer.size() != var.array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), var.array_size, decl.initializer.size()));
return ERR_PARSE_ERROR;
}
tk = _get_token();
@ -7537,7 +7941,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
array_size = var.array_size;
} else if (tk.type == TK_OP_ASSIGN) {
//variable created with assignment! must parse an expression
p_block->use_op_eval = is_const;
// Variable created with assignment! Must parse an expression.
Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
@ -7552,11 +7958,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
if (n->type == Node::NODE_TYPE_CONSTANT) {
ConstantNode *const_node = static_cast<ConstantNode *>(n);
if (const_node && const_node->values.size() == 1) {
var.value = const_node->values[0];
}
if (is_const) {
var.values = n->get_values();
}
if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
@ -7734,13 +8137,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!vn) {
return ERR_PARSE_ERROR;
}
ConstantNode::Value v;
Vector<Scalar> v = { Scalar() };
_find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v);
if (constants.has(v.sint)) {
_set_error(vformat(RTR("Duplicated case label: %d."), v.sint));
if (constants.has(v[0].sint)) {
_set_error(vformat(RTR("Duplicated case label: %d."), v[0].sint));
return ERR_PARSE_ERROR;
}
constants.insert(v.sint);
constants.insert(v[0].sint);
}
} else if (flow->flow_op == FLOW_OP_DEFAULT) {
continue;
@ -7801,7 +8204,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
vn->name = tk.text;
n = vn;
} else {
ConstantNode::Value v;
Scalar v;
if (tk.type == TK_UINT_CONSTANT) {
v.uint = (uint32_t)tk.constant;
} else {
@ -9678,7 +10081,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
decl.size = decl.initializer.size();
constant.array_size = decl.initializer.size();
} else if (decl.initializer.size() != constant.array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), constant.array_size, decl.initializer.size()));
return ERR_PARSE_ERROR;
}
} else {