diff --git a/src/app.cpp b/src/app.cpp index 90b2575..381d3a7 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -505,6 +505,7 @@ void App::update(float dt) { static std::mutex mutex; static float rec_timer = 0.f; + static float reload_timer = 0.f; // avoid multiple threads to update the scene std::lock_guard lock(mutex); @@ -524,17 +525,18 @@ void App::update(float dt) //glClear(GL_COLOR_BUFFER_BIT); //if (!canvas->m_mouse_captured) +#if _DEBUG && (_WIN32 || __OSX__) + reload_timer += dt; + if (reload_timer > 1.0) { -#if _WIN32 || __OSX__ + reload_timer = 0; + ShaderManager::reload(); layout.reload(); -#endif if (auto* main = layout[main_id]) - { main->update(width, height, zoom); - //stroke->update_controls(); - } } - +#endif + { static glm::vec4 color_button_normal{ .1, .1, .1, 1 }; static glm::vec4 color_button_hlight{ 1, .0, .0, 1 }; diff --git a/src/asset.cpp b/src/asset.cpp index ffd69fa..058cbdd 100644 --- a/src/asset.cpp +++ b/src/asset.cpp @@ -220,12 +220,15 @@ glm::uint8_t* Asset::read_all() void Asset::close() { #ifdef __ANDROID__ - AAsset_close(m_asset); + if (m_asset) + AAsset_close(m_asset); + m_asset = nullptr; #else if (m_fp) fclose(m_fp); if (m_data) delete m_data; m_data = nullptr; + m_fp = nullptr; #endif } diff --git a/src/asset.h b/src/asset.h index a129e47..a782448 100644 --- a/src/asset.h +++ b/src/asset.h @@ -19,5 +19,6 @@ public: bool open(const char* path); uint8_t* read_all(); void close(); + ~Asset() { close(); } }; diff --git a/src/pch.cpp b/src/pch.cpp index 2854122..dbeac75 100644 --- a/src/pch.cpp +++ b/src/pch.cpp @@ -7,7 +7,7 @@ #include #include -#ifdef DEBUG +#ifdef _DEBUG #pragma comment (lib, "libcurl_debug.lib") #else #pragma comment (lib, "libcurl.lib") diff --git a/src/rtt.cpp b/src/rtt.cpp index 0cf20c2..90eeb04 100644 --- a/src/rtt.cpp +++ b/src/rtt.cpp @@ -162,7 +162,7 @@ bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format) void RTT::bindFramebuffer() { -#ifdef DEBUG +#ifdef _DEBUG if (bound) { LOG("framebuffer bound twice!"); diff --git a/src/shader.cpp b/src/shader.cpp index 53b0bd9..b9a8ec5 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -13,6 +13,10 @@ std::string Shader::read(const std::string& path) std::string ret; if (a.open(path.c_str())) { + struct stat tmp_info; + if (stat(path.c_str(), &tmp_info) == 0) + m_deps[path] = tmp_info; + std::regex reg_include(R"!(#include "([^"]+)")!"); std::string data((char*)a.read_all(), a.m_len); @@ -105,18 +109,46 @@ bool Shader::load(const std::string& path) { *sections["vertex"] = SHADER_VERSION + *sections["vertex"]; *sections["fragment"] = SHADER_VERSION + *sections["fragment"]; - return create(sections["vertex"]->c_str(), sections["fragment"]->c_str()); + if (create(sections["vertex"]->c_str(), sections["fragment"]->c_str())) + { + m_path = path; + return true; + } } else { LOG("could not find [[vertex]] and [[fragment]] sections on %s", path.c_str()); } - m_path = path; - return false; } +bool Shader::reload() +{ + if (m_path.empty()) + return false; + + bool dirty = false; + struct stat tmp_info; + for (auto& d : m_deps) + { + if (stat(d.first.c_str(), &tmp_info) != 0) + continue; + if (tmp_info.st_mtime > d.second.st_mtime) + { + d.second = tmp_info; + dirty = true; + } + } + + if (dirty) + { + LOG("reload shader %s", m_path.c_str()); + destroy(); + return load(m_path); + } +} + bool Shader::create(const char* vertex, const char* fragment) { GLint status; @@ -136,7 +168,7 @@ bool Shader::create(const char* vertex, const char* fragment) glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog); if (infolen > 0) { - LOG("\nVERTEX SHADER:"); + LOG("\nVERTEX SHADER: %s", m_path.c_str()); parse_error(infolog, vertex); } if (status == 0) @@ -158,7 +190,7 @@ bool Shader::create(const char* vertex, const char* fragment) glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog); if (infolen > 0) { - LOG("\nFRAGMENT SHADER:"); + LOG("\nFRAGMENT SHADER: %s", m_path.c_str()); parse_error(infolog, fragment); } if (status == 0) @@ -200,7 +232,7 @@ bool Shader::create(const char* vertex, const char* fragment) glGetProgramiv(ps, GL_LINK_STATUS, &status); glGetProgramInfoLog(ps, sizeof(infolog), &infolen, infolog); if (infolen > 0) - LOG("LINK SHADER:\n%s", infolog); + LOG("LINK SHADER: %s\n%s", m_path.c_str(), infolog); if (status == 0) { glDeleteProgram(ps); @@ -228,6 +260,18 @@ bool Shader::create(const char* vertex, const char* fragment) return true; } + +void Shader::destroy() +{ + if (prog) + { + glUseProgram(0); + glDeleteProgram(prog); + prog = 0; + } + m_umap.clear(); +} + void Shader::use() { glUseProgram(prog); @@ -282,6 +326,14 @@ bool ShaderManager::load(kShader id, const std::string& path) return m_shaders[id].load(path); } +bool ShaderManager::reload() +{ + bool success = true; + for (auto& s : m_shaders) + success &= s.second.reload(); + return success; +} + bool ShaderManager::create(kShader id, const char* vertex, const char* fragment) { m_shaders[id].name = id; diff --git a/src/shader.h b/src/shader.h index ad47747..7152994 100644 --- a/src/shader.h +++ b/src/shader.h @@ -74,6 +74,7 @@ enum class kShader : uint16_t class Shader { + std::map m_deps; std::string m_path; std::map m_umap; GLuint prog; @@ -82,7 +83,9 @@ public: kShader name; void parse_error(const char* msg, const char* code); bool load(const std::string& path); + bool reload(); bool create(const char* vertex, const char* fragment); + void destroy(); void use(); void u_vec4(kShaderUniform id, const glm::vec4& v); void u_vec3(kShaderUniform id, const glm::vec3& v); @@ -100,6 +103,7 @@ class ShaderManager public: static bool ext_framebuffer_fetch; static bool load(kShader id, const std::string& path); + static bool reload(); static bool create(kShader id, const char* vertex, const char* fragment); static void use(kShader id); static void use(const char* name);