summaryrefslogtreecommitdiffstats
path: root/servers/rendering/shader_preprocessor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/shader_preprocessor.cpp')
-rw-r--r--servers/rendering/shader_preprocessor.cpp76
1 files changed, 64 insertions, 12 deletions
diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp
index 27e39551ba..88ea74cdfc 100644
--- a/servers/rendering/shader_preprocessor.cpp
+++ b/servers/rendering/shader_preprocessor.cpp
@@ -393,6 +393,8 @@ void ShaderPreprocessor::process_directive(Tokenizer *p_tokenizer) {
process_else(p_tokenizer);
} else if (directive == "endif") {
process_endif(p_tokenizer);
+ } else if (directive == "error") {
+ process_error(p_tokenizer);
} else if (directive == "define") {
process_define(p_tokenizer);
} else if (directive == "undef") {
@@ -466,7 +468,7 @@ void ShaderPreprocessor::process_elif(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
if (state->current_branch == nullptr || state->current_branch->else_defined) {
- set_error(RTR("Unmatched elif."), line);
+ set_error(vformat(RTR("Unmatched '%s' directive."), "elif"), line);
return;
}
if (state->previous_region != nullptr) {
@@ -523,7 +525,7 @@ void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
if (state->current_branch == nullptr || state->current_branch->else_defined) {
- set_error(RTR("Unmatched else."), line);
+ set_error(vformat(RTR("Unmatched '%s' directive."), "else"), line);
return;
}
if (state->previous_region != nullptr) {
@@ -531,7 +533,7 @@ void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid else."), p_tokenizer->get_line());
+ set_error(vformat(RTR("Invalid '%s' directive."), "else"), line);
}
bool skip = false;
@@ -559,7 +561,7 @@ void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
state->condition_depth--;
if (state->condition_depth < 0) {
- set_error(RTR("Unmatched endif."), line);
+ set_error(vformat(RTR("Unmatched '%s' directive."), "endif"), line);
return;
}
if (state->previous_region != nullptr) {
@@ -568,13 +570,28 @@ void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid endif."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "endif"), line);
}
state->current_branch = state->current_branch->parent;
state->branches.pop_back();
}
+void ShaderPreprocessor::process_error(Tokenizer *p_tokenizer) {
+ const int line = p_tokenizer->get_line();
+
+ const String body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
+ if (body.is_empty()) {
+ set_error(" ", line);
+ } else {
+ set_error(body, line);
+ }
+
+ if (!p_tokenizer->consume_empty_line()) {
+ set_error(vformat(RTR("Invalid '%s' directive."), "error"), line);
+ }
+}
+
void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
@@ -626,7 +643,7 @@ void ShaderPreprocessor::process_ifdef(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid ifdef."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "ifdef"), line);
return;
}
@@ -648,7 +665,7 @@ void ShaderPreprocessor::process_ifndef(Tokenizer *p_tokenizer) {
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid ifndef."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "ifndef"), line);
return;
}
@@ -771,21 +788,21 @@ void ShaderPreprocessor::process_pragma(Tokenizer *p_tokenizer) {
}
if (label.is_empty()) {
- set_error(RTR("Invalid pragma directive."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "pragma"), line);
return;
}
- // Rxplicitly handle pragma values here.
+ // Explicitly handle pragma values here.
// If more pragma options are created, then refactor into a more defined structure.
if (label == "disable_preprocessor") {
state->disabled = true;
} else {
- set_error(RTR("Invalid pragma directive."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "pragma"), line);
return;
}
if (!p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid pragma directive."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "pragma"), line);
return;
}
}
@@ -794,11 +811,16 @@ void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) {
const int line = p_tokenizer->get_line();
const String label = p_tokenizer->get_identifier();
if (label.is_empty() || !p_tokenizer->consume_empty_line()) {
- set_error(RTR("Invalid undef."), line);
+ set_error(vformat(RTR("Invalid '%s' directive."), "undef"), line);
return;
}
if (state->defines.has(label)) {
+ if (state->defines[label]->is_builtin) {
+ set_error(vformat(RTR("Cannot use '%s' on built-in define."), "undef"), line);
+ return;
+ }
+
memdelete(state->defines[label]);
state->defines.erase(label);
}
@@ -1307,6 +1329,35 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen
pp_state.current_filename = p_filename;
pp_state.save_regions = r_regions != nullptr;
}
+
+ // Built-in defines.
+ {
+ static HashMap<StringName, String> defines;
+
+ if (defines.is_empty()) {
+ const String rendering_method = OS::get_singleton()->get_current_rendering_method();
+
+ if (rendering_method == "forward_plus") {
+ defines["CURRENT_RENDERER"] = _MKSTR(2);
+ } else if (rendering_method == "mobile") {
+ defines["CURRENT_RENDERER"] = _MKSTR(1);
+ } else { // gl_compatibility
+ defines["CURRENT_RENDERER"] = _MKSTR(0);
+ }
+
+ defines["RENDERER_COMPATIBILITY"] = _MKSTR(0);
+ defines["RENDERER_MOBILE"] = _MKSTR(1);
+ defines["RENDERER_FORWARD_PLUS"] = _MKSTR(2);
+ }
+
+ for (const KeyValue<StringName, String> &E : defines) {
+ Define *define = memnew(Define);
+ define->is_builtin = true;
+ define->body = E.value;
+ pp_state.defines[E.key] = define;
+ }
+ }
+
Error err = preprocess(&pp_state, p_code, r_result);
if (err != OK) {
if (r_error_text) {
@@ -1383,6 +1434,7 @@ void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_inclu
r_keywords->push_back("else");
}
r_keywords->push_back("endif");
+ r_keywords->push_back("error");
if (p_include_shader_keywords) {
r_keywords->push_back("if");
}