Implement shader uniform groups/subgroups
This commit is contained in:
parent
c3dc887c41
commit
886c2d9681
|
@ -2900,7 +2900,22 @@ void CanvasShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
@ -3123,7 +3138,22 @@ void SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
@ -3433,7 +3463,22 @@ void SceneShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
|
|
@ -202,7 +202,98 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
|
|||
|
||||
void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
if (!shader.is_null()) {
|
||||
shader->get_param_list(p_list);
|
||||
List<PropertyInfo> list;
|
||||
shader->get_param_list(&list, true);
|
||||
|
||||
HashMap<String, HashMap<String, List<PropertyInfo>>> groups;
|
||||
{
|
||||
HashMap<String, List<PropertyInfo>> none_subgroup;
|
||||
none_subgroup.insert("<None>", List<PropertyInfo>());
|
||||
groups.insert("<None>", none_subgroup);
|
||||
}
|
||||
|
||||
String last_group = "<None>";
|
||||
String last_subgroup = "<None>";
|
||||
|
||||
bool is_none_group_undefined = true;
|
||||
bool is_none_group = true;
|
||||
|
||||
for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
|
||||
if (E->get().usage == PROPERTY_USAGE_GROUP) {
|
||||
if (!E->get().name.is_empty()) {
|
||||
Vector<String> vgroup = E->get().name.split("::");
|
||||
last_group = vgroup[0];
|
||||
if (vgroup.size() > 1) {
|
||||
last_subgroup = vgroup[1];
|
||||
} else {
|
||||
last_subgroup = "<None>";
|
||||
}
|
||||
is_none_group = false;
|
||||
|
||||
if (!groups.has(last_group)) {
|
||||
PropertyInfo info;
|
||||
info.usage = PROPERTY_USAGE_GROUP;
|
||||
info.name = last_group;
|
||||
|
||||
List<PropertyInfo> none_subgroup;
|
||||
none_subgroup.push_back(info);
|
||||
|
||||
HashMap<String, List<PropertyInfo>> subgroup_map;
|
||||
subgroup_map.insert("<None>", none_subgroup);
|
||||
|
||||
groups.insert(last_group, subgroup_map);
|
||||
}
|
||||
|
||||
if (!groups[last_group].has(last_subgroup)) {
|
||||
PropertyInfo info;
|
||||
info.usage = PROPERTY_USAGE_SUBGROUP;
|
||||
info.name = last_subgroup;
|
||||
|
||||
List<PropertyInfo> subgroup;
|
||||
subgroup.push_back(info);
|
||||
|
||||
groups[last_group].insert(last_subgroup, subgroup);
|
||||
}
|
||||
} else {
|
||||
last_group = "<None>";
|
||||
last_subgroup = "<None>";
|
||||
is_none_group = true;
|
||||
}
|
||||
continue; // Pass group.
|
||||
}
|
||||
|
||||
if (is_none_group_undefined && is_none_group) {
|
||||
is_none_group_undefined = false;
|
||||
|
||||
PropertyInfo info;
|
||||
info.usage = PROPERTY_USAGE_GROUP;
|
||||
info.name = "Shader Param";
|
||||
groups["<None>"]["<None>"].push_back(info);
|
||||
}
|
||||
|
||||
PropertyInfo info = E->get();
|
||||
info.name = info.name;
|
||||
groups[last_group][last_subgroup].push_back(info);
|
||||
}
|
||||
|
||||
// Sort groups alphabetically.
|
||||
List<UniformProp> props;
|
||||
for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
|
||||
for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) {
|
||||
for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) {
|
||||
if (subgroup->key == "<None>") {
|
||||
props.push_back({ group->key, item->get() });
|
||||
} else {
|
||||
props.push_back({ group->key + "::" + subgroup->key, item->get() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
props.sort_custom<UniformPropComparator>();
|
||||
|
||||
for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) {
|
||||
p_list->push_back(E->get().info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,17 @@ class ShaderMaterial : public Material {
|
|||
|
||||
HashMap<StringName, Variant> param_cache;
|
||||
|
||||
struct UniformProp {
|
||||
String str;
|
||||
PropertyInfo info;
|
||||
};
|
||||
|
||||
struct UniformPropComparator {
|
||||
bool operator()(const UniformProp &p_a, const UniformProp &p_b) const {
|
||||
return p_a.str.naturalnocasecmp_to(p_b.str) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
|
|
|
@ -103,7 +103,7 @@ String Shader::get_code() const {
|
|||
return code;
|
||||
}
|
||||
|
||||
void Shader::get_param_list(List<PropertyInfo> *p_params) const {
|
||||
void Shader::get_param_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
|
||||
_update_shader();
|
||||
|
||||
List<PropertyInfo> local;
|
||||
|
@ -112,12 +112,16 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const {
|
|||
params_cache_dirty = false;
|
||||
|
||||
for (PropertyInfo &pi : local) {
|
||||
if (default_textures.has(pi.name)) { //do not show default textures
|
||||
bool is_group = pi.usage == PROPERTY_USAGE_GROUP || pi.usage == PROPERTY_USAGE_SUBGROUP;
|
||||
if (!p_get_groups && is_group) {
|
||||
continue;
|
||||
}
|
||||
String original_name = pi.name;
|
||||
pi.name = "shader_param/" + pi.name;
|
||||
params_cache[pi.name] = original_name;
|
||||
if (!is_group) {
|
||||
if (default_textures.has(pi.name)) { //do not show default textures
|
||||
continue;
|
||||
}
|
||||
params_cache[pi.name] = pi.name;
|
||||
}
|
||||
if (p_params) {
|
||||
//small little hack
|
||||
if (pi.type == Variant::RID) {
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
void set_code(const String &p_code);
|
||||
String get_code() const;
|
||||
|
||||
void get_param_list(List<PropertyInfo> *p_params) const;
|
||||
void get_param_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
|
||||
bool has_param(const StringName &p_param) const;
|
||||
|
||||
void set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index = 0);
|
||||
|
|
|
@ -393,7 +393,22 @@ void Fog::FogShaderData::get_param_list(List<PropertyInfo> *p_param_list) const
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
|
|
@ -178,8 +178,22 @@ void SkyRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) cons
|
|||
order[E.value.order] = E.key;
|
||||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
|
|
@ -407,7 +407,22 @@ void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo>
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
|
|
@ -364,7 +364,22 @@ void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
|
|
@ -2185,7 +2185,22 @@ void RendererCanvasRenderRD::CanvasShaderData::get_param_list(List<PropertyInfo>
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
|
|
@ -1612,7 +1612,22 @@ void ParticlesStorage::ParticlesShaderData::get_param_list(List<PropertyInfo> *p
|
|||
}
|
||||
}
|
||||
|
||||
String last_group;
|
||||
for (const KeyValue<int, StringName> &E : order) {
|
||||
String group = uniforms[E.value].group;
|
||||
if (!uniforms[E.value].subgroup.is_empty()) {
|
||||
group += "::" + uniforms[E.value].subgroup;
|
||||
}
|
||||
|
||||
if (group != last_group) {
|
||||
PropertyInfo pi;
|
||||
pi.usage = PROPERTY_USAGE_GROUP;
|
||||
pi.name = group;
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
|
||||
pi.name = E.value;
|
||||
p_param_list->push_back(pi);
|
||||
|
|
|
@ -310,6 +310,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
|
|||
// global space keywords
|
||||
|
||||
{ TK_UNIFORM, "uniform", CF_GLOBAL_SPACE | CF_UNIFORM_KEYWORD, {}, {} },
|
||||
{ TK_UNIFORM_GROUP, "group_uniforms", CF_GLOBAL_SPACE, {}, {} },
|
||||
{ TK_VARYING, "varying", CF_GLOBAL_SPACE, { "particles", "sky", "fog" }, {} },
|
||||
{ TK_CONST, "const", CF_BLOCK | CF_GLOBAL_SPACE | CF_CONST_KEYWORD, {}, {} },
|
||||
{ TK_STRUCT, "struct", CF_GLOBAL_SPACE, {}, {} },
|
||||
|
@ -1146,6 +1147,8 @@ void ShaderLanguage::clear() {
|
|||
current_function = StringName();
|
||||
last_name = StringName();
|
||||
last_type = IDENTIFIER_MAX;
|
||||
current_uniform_group_name = "";
|
||||
current_uniform_subgroup_name = "";
|
||||
|
||||
completion_type = COMPLETION_NONE;
|
||||
completion_block = nullptr;
|
||||
|
@ -8298,6 +8301,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
|
|||
uniform.scope = uniform_scope;
|
||||
uniform.precision = precision;
|
||||
uniform.array_size = array_size;
|
||||
uniform.group = current_uniform_group_name;
|
||||
uniform.subgroup = current_uniform_subgroup_name;
|
||||
|
||||
tk = _get_token();
|
||||
if (tk.type == TK_BRACKET_OPEN) {
|
||||
|
@ -8724,6 +8729,45 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
|
|||
}
|
||||
|
||||
} break;
|
||||
case TK_UNIFORM_GROUP: {
|
||||
tk = _get_token();
|
||||
if (tk.type == TK_IDENTIFIER) {
|
||||
current_uniform_group_name = tk.text;
|
||||
tk = _get_token();
|
||||
if (tk.type == TK_PERIOD) {
|
||||
tk = _get_token();
|
||||
if (tk.type == TK_IDENTIFIER) {
|
||||
current_uniform_subgroup_name = tk.text;
|
||||
tk = _get_token();
|
||||
if (tk.type != TK_SEMICOLON) {
|
||||
_set_expected_error(";");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
} else {
|
||||
_set_error(RTR("Expected an uniform subgroup identifier."));
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
} else if (tk.type != TK_SEMICOLON) {
|
||||
_set_expected_error(";", ".");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (tk.type != TK_SEMICOLON) {
|
||||
if (current_uniform_group_name.is_empty()) {
|
||||
_set_error(RTR("Expected an uniform group identifier."));
|
||||
} else {
|
||||
_set_error(RTR("Expected an uniform group identifier or `;`."));
|
||||
}
|
||||
return ERR_PARSE_ERROR;
|
||||
} else if (tk.type == TK_SEMICOLON && current_uniform_group_name.is_empty()) {
|
||||
_set_error(RTR("Group needs to be opened before."));
|
||||
return ERR_PARSE_ERROR;
|
||||
} else {
|
||||
current_uniform_group_name = "";
|
||||
current_uniform_subgroup_name = "";
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case TK_SHADER_TYPE: {
|
||||
_set_error(RTR("Shader type is already defined."));
|
||||
return ERR_PARSE_ERROR;
|
||||
|
|
|
@ -154,6 +154,7 @@ public:
|
|||
TK_SEMICOLON,
|
||||
TK_PERIOD,
|
||||
TK_UNIFORM,
|
||||
TK_UNIFORM_GROUP,
|
||||
TK_INSTANCE,
|
||||
TK_GLOBAL,
|
||||
TK_VARYING,
|
||||
|
@ -687,6 +688,8 @@ public:
|
|||
TextureRepeat repeat = REPEAT_DEFAULT;
|
||||
float hint_range[3];
|
||||
int instance_index = 0;
|
||||
String group;
|
||||
String subgroup;
|
||||
|
||||
Uniform() {
|
||||
hint_range[0] = 0.0f;
|
||||
|
@ -938,6 +941,9 @@ private:
|
|||
StringName last_name;
|
||||
bool is_shader_inc = false;
|
||||
|
||||
String current_uniform_group_name;
|
||||
String current_uniform_subgroup_name;
|
||||
|
||||
VaryingFunctionNames varying_function_names;
|
||||
|
||||
TkPos _get_tkpos() {
|
||||
|
|
Loading…
Reference in New Issue