Add basic support to evaluate operator value in shader language
This commit is contained in:
parent
d0dc3896ad
commit
af92fdb0ac
|
@ -348,7 +348,7 @@ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_
|
|||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
|
||||
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::Scalar> &value, uint8_t *data) {
|
||||
switch (type) {
|
||||
case ShaderLanguage::TYPE_BOOL: {
|
||||
uint32_t *gui = (uint32_t *)data;
|
||||
|
@ -572,7 +572,7 @@ void ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_t
|
|||
Variant ShaderData::get_default_parameter(const StringName &p_parameter) const {
|
||||
if (uniforms.has(p_parameter)) {
|
||||
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
|
||||
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
|
||||
Vector<ShaderLanguage::Scalar> default_value = uniform.default_value;
|
||||
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
|
||||
}
|
||||
return Variant();
|
||||
|
|
|
@ -342,7 +342,7 @@ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_
|
|||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
|
||||
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::Scalar> &value, uint8_t *data) {
|
||||
switch (type) {
|
||||
case ShaderLanguage::TYPE_BOOL: {
|
||||
uint32_t *gui = (uint32_t *)data;
|
||||
|
@ -566,7 +566,7 @@ void MaterialStorage::ShaderData::set_default_texture_parameter(const StringName
|
|||
Variant MaterialStorage::ShaderData::get_default_parameter(const StringName &p_parameter) const {
|
||||
if (uniforms.has(p_parameter)) {
|
||||
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
|
||||
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
|
||||
Vector<ShaderLanguage::Scalar> default_value = uniform.default_value;
|
||||
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
|
||||
}
|
||||
return Variant();
|
||||
|
|
|
@ -185,7 +185,7 @@ static String f2sp0(float p_float) {
|
|||
return num;
|
||||
}
|
||||
|
||||
static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) {
|
||||
static String get_constant_text(SL::DataType p_type, const Vector<SL::Scalar> &p_values) {
|
||||
switch (p_type) {
|
||||
case SL::TYPE_BOOL:
|
||||
return p_values[0].boolean ? "true" : "false";
|
||||
|
|
|
@ -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) {
|
||||
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) {
|
||||
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 {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
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,46 +5327,31 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &
|
|||
*r_unknown_size = true;
|
||||
}
|
||||
} else {
|
||||
int array_size = 0;
|
||||
|
||||
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;
|
||||
|
||||
_find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v);
|
||||
int array_size = 0;
|
||||
Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
|
||||
|
||||
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;
|
||||
if (expr) {
|
||||
Vector<Scalar> values = _get_node_values(p_block, expr);
|
||||
|
||||
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 (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;
|
||||
*r_size_expression = expr;
|
||||
}
|
||||
}
|
||||
} else if (((int)tk.constant) > 0) {
|
||||
array_size = (uint32_t)tk.constant;
|
||||
}
|
||||
|
||||
if (array_size <= 0) {
|
||||
_set_error(RTR("Expected a positive integer constant."));
|
||||
|
@ -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 {
|
||||
|
|
|
@ -355,6 +355,13 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
union Scalar {
|
||||
bool boolean = false;
|
||||
float real;
|
||||
int32_t sint;
|
||||
uint32_t uint;
|
||||
};
|
||||
|
||||
struct Node {
|
||||
Node *next = nullptr;
|
||||
|
||||
|
@ -379,6 +386,7 @@ public:
|
|||
virtual String get_datatype_name() const { return ""; }
|
||||
virtual int get_array_size() const { return 0; }
|
||||
virtual bool is_indexed() const { return false; }
|
||||
virtual Vector<Scalar> get_values() const { return Vector<Scalar>(); }
|
||||
|
||||
Node(Type t) :
|
||||
type(t) {}
|
||||
|
@ -402,11 +410,13 @@ public:
|
|||
Operator op = OP_EQUAL;
|
||||
StringName struct_name;
|
||||
Vector<Node *> arguments;
|
||||
Vector<Scalar> values;
|
||||
|
||||
virtual DataType get_datatype() const override { return return_cache; }
|
||||
virtual String get_datatype_name() const override { return String(struct_name); }
|
||||
virtual int get_array_size() const override { return return_array_size; }
|
||||
virtual bool is_indexed() const override { return op == OP_INDEX; }
|
||||
virtual Vector<Scalar> get_values() const override { return values; }
|
||||
|
||||
OperatorNode() :
|
||||
Node(NODE_TYPE_OPERATOR) {}
|
||||
|
@ -485,19 +495,15 @@ public:
|
|||
String struct_name = "";
|
||||
int array_size = 0;
|
||||
|
||||
union Value {
|
||||
bool boolean = false;
|
||||
float real;
|
||||
int32_t sint;
|
||||
uint32_t uint;
|
||||
};
|
||||
|
||||
Vector<Value> values;
|
||||
Vector<Scalar> values;
|
||||
Vector<VariableDeclarationNode::Declaration> array_declarations;
|
||||
|
||||
virtual DataType get_datatype() const override { return datatype; }
|
||||
virtual String get_datatype_name() const override { return struct_name; }
|
||||
virtual int get_array_size() const override { return array_size; }
|
||||
virtual Vector<Scalar> get_values() const override {
|
||||
return values;
|
||||
}
|
||||
|
||||
ConstantNode() :
|
||||
Node(NODE_TYPE_CONSTANT) {}
|
||||
|
@ -529,13 +535,14 @@ public:
|
|||
int line; //for completion
|
||||
int array_size;
|
||||
bool is_const;
|
||||
ConstantNode::Value value;
|
||||
Vector<Scalar> values;
|
||||
};
|
||||
|
||||
HashMap<StringName, Variable> variables;
|
||||
List<Node *> statements;
|
||||
bool single_statement = false;
|
||||
bool use_comma_between_statements = false;
|
||||
bool use_op_eval = true;
|
||||
|
||||
BlockNode() :
|
||||
Node(NODE_TYPE_BLOCK) {}
|
||||
|
@ -657,7 +664,7 @@ public:
|
|||
DataType type = TYPE_VOID;
|
||||
DataPrecision precision = PRECISION_DEFAULT;
|
||||
int array_size = 0;
|
||||
Vector<ConstantNode::Value> default_value;
|
||||
Vector<Scalar> default_value;
|
||||
Scope scope = SCOPE_LOCAL;
|
||||
Hint hint = HINT_NONE;
|
||||
bool use_color = false;
|
||||
|
@ -803,15 +810,16 @@ public:
|
|||
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, Scalar *p_value = nullptr);
|
||||
static DataType get_scalar_type(DataType p_type);
|
||||
static int get_cardinality(DataType p_type);
|
||||
static bool is_scalar_type(DataType p_type);
|
||||
static bool is_float_type(DataType p_type);
|
||||
static bool is_sampler_type(DataType p_type);
|
||||
static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
|
||||
static Variant constant_value_to_variant(const Vector<Scalar> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
|
||||
static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
|
||||
static uint32_t get_datatype_size(DataType p_type);
|
||||
static uint32_t get_datatype_component_count(DataType p_type);
|
||||
|
||||
static void get_keyword_list(List<String> *r_keywords);
|
||||
static bool is_control_flow_keyword(String p_keyword);
|
||||
|
@ -1070,13 +1078,21 @@ private:
|
|||
|
||||
IdentifierType last_type = IDENTIFIER_MAX;
|
||||
|
||||
bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, 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 _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, 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, Vector<Scalar> *r_constant_values = nullptr);
|
||||
#ifdef DEBUG_ENABLED
|
||||
void _parse_used_identifier(const StringName &p_identifier, IdentifierType p_type, const StringName &p_function);
|
||||
#endif // DEBUG_ENABLED
|
||||
bool _is_operator_assign(Operator p_op) const;
|
||||
bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr);
|
||||
bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr);
|
||||
bool _validate_operator(const BlockNode *p_block, OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr);
|
||||
|
||||
Vector<Scalar> _get_node_values(const BlockNode *p_block, Node *p_node);
|
||||
bool _eval_operator(const BlockNode *p_block, OperatorNode *p_op);
|
||||
Scalar _eval_unary_scalar(const Scalar &p_a, Operator p_op, DataType p_ret_type);
|
||||
Scalar _eval_scalar(const Scalar &p_a, const Scalar &p_b, Operator p_op, DataType p_ret_type, bool &r_is_valid);
|
||||
Vector<Scalar> _eval_unary_vector(const Vector<Scalar> &p_va, DataType p_ret_type, Operator p_op);
|
||||
Vector<Scalar> _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);
|
||||
Vector<Scalar> _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);
|
||||
|
||||
struct BuiltinEntry {
|
||||
const char *name;
|
||||
|
|
Loading…
Reference in New Issue