Add stencil support for spatial materials

This commit is contained in:
Apples
2023-02-17 15:20:26 -06:00
parent 7574a5dbb3
commit d674c9e289
29 changed files with 1335 additions and 141 deletions

View File

@ -1715,6 +1715,41 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
_queue_update();
return true;
} else if (prop_name == "stencil/enabled") {
stencil_enabled = bool(p_value);
_queue_update();
notify_property_list_changed();
return true;
} else if (prop_name == "stencil/reference") {
stencil_reference = int(p_value);
_queue_update();
return true;
} else if (prop_name.begins_with("stencil_flags/")) {
StringName flag = prop_name.get_slicec('/', 1);
bool enable = p_value;
if (enable) {
stencil_flags.insert(flag);
if (flag == "read") {
stencil_flags.erase("write");
stencil_flags.erase("write_depth_fail");
} else if (flag == "write" || flag == "write_depth_fail") {
stencil_flags.erase("read");
}
} else {
stencil_flags.erase(flag);
}
_queue_update();
return true;
} else if (prop_name.begins_with("stencil_modes/")) {
String mode_name = prop_name.get_slicec('/', 1);
int value = p_value;
if (value == 0) {
stencil_modes.erase(mode_name); // It's default anyway, so don't store it.
} else {
stencil_modes[mode_name] = value;
}
_queue_update();
return true;
} else if (prop_name.begins_with("varyings/")) {
String var_name = prop_name.get_slicec('/', 1);
Varying value = Varying();
@ -1798,6 +1833,24 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = 0;
}
return true;
} else if (prop_name == "stencil/enabled") {
r_ret = stencil_enabled;
return true;
} else if (prop_name == "stencil/reference") {
r_ret = stencil_reference;
return true;
} else if (prop_name.begins_with("stencil_flags/")) {
StringName flag = prop_name.get_slicec('/', 1);
r_ret = stencil_flags.has(flag);
return true;
} else if (prop_name.begins_with("stencil_modes/")) {
String mode_name = prop_name.get_slicec('/', 1);
if (stencil_modes.has(mode_name)) {
r_ret = stencil_modes[mode_name];
} else {
r_ret = 0;
}
return true;
} else if (prop_name.begins_with("varyings/")) {
String var_name = prop_name.get_slicec('/', 1);
if (varyings.has(var_name)) {
@ -1934,6 +1987,45 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("flags"), E)));
}
const Vector<ShaderLanguage::ModeInfo> &smodes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(shader_mode));
if (smodes.size() > 0) {
p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("stencil"), PNAME("enabled"))));
uint32_t stencil_prop_usage = stencil_enabled ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE;
p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("stencil"), PNAME("reference")), PROPERTY_HINT_RANGE, "0,255,1", stencil_prop_usage));
HashMap<String, String> stencil_enums;
HashSet<String> stencil_toggles;
for (const ShaderLanguage::ModeInfo &info : smodes) {
if (!info.options.is_empty()) {
const String begin = String(info.name);
for (int j = 0; j < info.options.size(); j++) {
const String option = String(info.options[j]).capitalize();
if (!stencil_enums.has(begin)) {
stencil_enums[begin] = option;
} else {
stencil_enums[begin] += "," + option;
}
}
} else {
stencil_toggles.insert(String(info.name));
}
}
for (const KeyValue<String, String> &E : stencil_enums) {
p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("stencil_modes"), E.key), PROPERTY_HINT_ENUM, E.value, stencil_prop_usage));
}
for (const String &E : stencil_toggles) {
p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("stencil_flags"), E), PROPERTY_HINT_NONE, "", stencil_prop_usage));
}
}
for (const KeyValue<String, Varying> &E : varyings) {
p_list->push_back(PropertyInfo(Variant::STRING, vformat("%s/%s", "varyings", E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
@ -2621,6 +2713,46 @@ void VisualShader::_update_shader() const {
global_code += "render_mode " + render_mode + ";\n\n";
}
const Vector<ShaderLanguage::ModeInfo> &smodes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(shader_mode));
if (stencil_enabled && smodes.size() > 0 && (stencil_flags.has("read") || stencil_flags.has("write") || stencil_flags.has("write_depth_fail"))) {
String stencil_mode;
Vector<String> flag_names;
// Add enum modes first.
for (const ShaderLanguage::ModeInfo &info : smodes) {
const String temp = String(info.name);
if (!info.options.is_empty()) {
if (stencil_modes.has(temp) && stencil_modes[temp] < info.options.size()) {
if (!stencil_mode.is_empty()) {
stencil_mode += ", ";
}
stencil_mode += temp + "_" + info.options[stencil_modes[temp]];
}
} else if (stencil_flags.has(temp)) {
flag_names.push_back(temp);
}
}
// Add flags afterward.
for (const String &flag_name : flag_names) {
if (!stencil_mode.is_empty()) {
stencil_mode += ", ";
}
stencil_mode += flag_name;
}
// Add reference value.
if (!stencil_mode.is_empty()) {
stencil_mode += ", ";
}
stencil_mode += itos(stencil_reference);
global_code += "stencil_mode " + stencil_mode + ";\n\n";
}
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" };
String global_expressions;