Skip to content

Commit

Permalink
Add basic import shader support
Browse files Browse the repository at this point in the history
Co-authored-by: bitsawer <sawerduster@gmail.com>
  • Loading branch information
2 people authored and lyuma committed Dec 23, 2020
1 parent 187be73 commit c6b72f1
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 2 deletions.
18 changes: 18 additions & 0 deletions editor/plugins/shader_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,24 @@ void ShaderEditor::apply_shaders() {
shader->set_code(editor_code);
shader->set_edited(true);
}
refresh_shader_dependencies();
}
}

void ShaderEditor::refresh_shader_dependencies() {
//We could use the arguments to find exactly what shaders we should update that depend on the argument shader.
//For now go through cached shaders, which are usually(?) all shaders that are currently used in editor
//Best solution would be to create a dependency graph about all #includes and use it

List<RES> cached;
ResourceCache::get_cached_resources(&cached);

for (int i = 0; i < cached.size(); i++) {
Shader *shader = Object::cast_to<Shader>(*cached[i]);
if (shader) {
// Workaround to refreshing code
shader->set_code(shader->get_code());
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions editor/plugins/shader_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class ShaderEditor : public PanelContainer {
public:
void apply_shaders();

static void refresh_shader_dependencies();

void ensure_select_current();
void edit(const Ref<Shader> &p_shader);

Expand Down
92 changes: 90 additions & 2 deletions servers/rendering/shader_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@
/*************************************************************************/

#include "shader_language.h"

#include "core/config/engine.h"
#include "core/io/resource_loader.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "scene/resources/shader.h"
#include "servers/rendering/shader_language.h"
#include "servers/rendering_server.h"

static bool _is_text_char(char32_t c) {
Expand Down Expand Up @@ -216,6 +221,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"REPEAT_ENABLE",
"REPEAT_DISABLE",
"SHADER_TYPE",
"IMPORT_SHADER",
"CURSOR",
"ERROR",
"EOF",
Expand Down Expand Up @@ -330,6 +336,9 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_REPEAT_ENABLE, "repeat_enable" },
{ TK_REPEAT_DISABLE, "repeat_disable" },
{ TK_SHADER_TYPE, "shader_type" },
{ TK_IMPORT, "import" },
{ TK_QUOTE, "\"" },

{ TK_ERROR, nullptr }
};

Expand Down Expand Up @@ -449,8 +458,13 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
return _make_token(TK_OP_NOT);

} break;
//case '"' //string - no strings in shader
//case '\'' //string - no strings in shader
case '"': {
int end_quote = code.find_char('"', char_idx);
String quoted = code.substr(char_idx, end_quote - char_idx);
char_idx = end_quote + 1;
char_idx++;
return _make_token(TK_QUOTE, quoted);
}
case '{':
return _make_token(TK_CURLY_BRACKET_OPEN);
case '}':
Expand Down Expand Up @@ -5912,9 +5926,83 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;

stages = &p_functions;
Set<String> includes;
int include_depth = 0;

while (tk.type != TK_EOF) {
switch (tk.type) {
case TK_IMPORT: {
tk = _get_token();

if (tk.type != TK_QUOTE) {
_set_error("Expected quote.");
return ERR_PARSE_ERROR;
}

String path = tk.text;

if (path.empty()) {
_set_error("Invalid path");
return ERR_PARSE_ERROR;
}

RES res = ResourceLoader::load(path);
if (res.is_null()) {
_set_error("Shader include load failed");
return ERR_PARSE_ERROR;
}

String replacement = String("import \"") + tk.text + String("\"");
String empty;
for (int i = 0; i < replacement.size(); i++) {
empty += " ";
}
code = code.replace_first(replacement, empty);

tk = _get_token();
if (tk.type != TK_SEMICOLON) {
_set_error("Expected semicolon.");
return ERR_PARSE_ERROR;
}

Ref<Shader> shader = res;
if (shader.is_null()) {
_set_error("Shader include resource type is wrong");
return ERR_PARSE_ERROR;
}

String included = shader->get_code();
if (included.empty()) {
_set_error("Shader include not found");
return ERR_PARSE_ERROR;
}

int type_end = included.find(";");
if (type_end == -1) {
_set_error("Shader include shader_type not found");
return ERR_PARSE_ERROR;
}

const String real_path = shader->get_path();
if (includes.has(real_path)) {
//Already included, skip.
return ERR_PARSE_ERROR;
}

//Mark as included
includes.insert(real_path);

include_depth++;
if (include_depth > 25) {
_set_error("Shader max include depth exceeded");
return ERR_PARSE_ERROR;
}

//Remove "shader_type xyz;" prefix from included files
included = included.substr(type_end + 1, included.length());

code = code.insert(char_idx, included);
} break;
case TK_RENDER_MODE: {
while (true) {
StringName mode;
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/shader_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class ShaderLanguage {
TK_ARG_OUT,
TK_ARG_INOUT,
TK_RENDER_MODE,
TK_IMPORT,
TK_QUOTE,
TK_HINT_WHITE_TEXTURE,
TK_HINT_BLACK_TEXTURE,
TK_HINT_NORMAL_TEXTURE,
Expand Down

0 comments on commit c6b72f1

Please sign in to comment.