Shaders now are managed by a manger that can do hot reloading and it also will detect a bad shader and use an ERROR shader so you know it's busted visually.

master
Zed A. Shaw 3 days ago
parent a5b8e411e3
commit 35ced58cc9
  1. 0
      assets/shaders/modal.frag
  2. 18
      assets/shaders/ui_error.frag
  3. 0
      assets/shaders/ui_shader.frag
  4. 0
      assets/shaders/ui_shape_shader.frag
  5. 1
      constants.hpp
  6. 17
      guecs.cpp
  7. 6
      guecs.hpp
  8. 1
      gui_fsm.cpp
  9. 2
      main.cpp
  10. 2
      meson.build
  11. 2
      raycaster.cpp
  12. 60
      shaders.cpp
  13. 26
      shaders.hpp
  14. 22
      tests/shaders.cpp

@ -0,0 +1,18 @@
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_duration;
uniform float u_time;
uniform float u_time_end;
uniform sampler2D texture;
uniform bool is_shape;
void main() {
if(is_shape) {
vec4 color = vec4(1.0, 0.0, 0.0, 1.0);
gl_FragColor = gl_Color * color;
} else {
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
vec4 color = vec4(1.0, 0.0, 0.0, 1.0);
gl_FragColor = gl_Color * color * pixel;
}
}

@ -73,7 +73,6 @@ constexpr wchar_t BG_TILE = L'█';
constexpr wchar_t UI_BASE_CHAR = L'';
constexpr int BG_BOX_OFFSET=5;
constexpr const char *FONT_FILE_NAME="assets/text.otf";
constexpr const char *DEFAULT_UI_SHADER = "shaders/ui_shader.frag";
constexpr std::array<std::wstring, 8> COMPASS{
// L"E", L"SE", L"S", L"SW", L"W", L"NW", L"N", L"NE"

@ -1,4 +1,5 @@
#include "guecs.hpp"
#include "shaders.hpp"
namespace guecs {
@ -66,31 +67,31 @@ namespace guecs {
}
void Shader::init(lel::Cell &cell) {
ptr = std::make_shared<sf::Shader>();
bool good = ptr->loadFromFile(name, sf::Shader::Type::Fragment);
dbc::check(good, fmt::format("failed to load shader {}", name));
ptr->setUniform("u_resolution", sf::Vector2f({float(cell.w), float(cell.h)}));
auto shader = shaders::get(name);
shader->setUniform("u_resolution", sf::Vector2f({float(cell.w), float(cell.h)}));
clock = std::make_shared<sf::Clock>();
}
void Shader::step() {
auto shader = shaders::get(name);
sf::Time u_time = clock->getElapsedTime();
float current_time = u_time.asSeconds();
if(current_time < u_time_end) {
ptr->setUniform("u_time", current_time);
shader->setUniform("u_time", current_time);
} else {
active = false;
}
}
void Shader::run() {
auto shader = shaders::get(name);
active = true;
sf::Time u_time = clock->getElapsedTime();
u_time_end = u_time.asSeconds() + duration;
ptr->setUniform("u_duration", duration);
ptr->setUniform("u_time_end", u_time_end);
shader->setUniform("u_duration", duration);
shader->setUniform("u_time_end", u_time_end);
}
UI::UI() {

@ -11,6 +11,7 @@
#include "constants.hpp"
#include "components.hpp"
#include <any>
#include "shaders.hpp"
namespace guecs {
using std::shared_ptr, std::make_shared, std::wstring, std::string;
@ -83,10 +84,9 @@ namespace guecs {
struct Shader {
float duration = 0.1f;
std::string name{DEFAULT_UI_SHADER};
std::string name{"ui_shader"};
float u_time_end = 0.0;
bool active = false;
std::shared_ptr<sf::Shader> ptr = nullptr;
std::shared_ptr<sf::Clock> clock = nullptr;
void init(lel::Cell &cell);
@ -199,7 +199,7 @@ namespace guecs {
auto& shader = $world.get<Shader>(ent);
if(shader.active) {
shader_ptr = shader.ptr.get();
shader_ptr = shaders::get(shader.name);
shader_ptr->setUniform("is_shape", is_shape);
}
}

@ -286,6 +286,7 @@ namespace gui {
case KEY::P:
sound::mute(false);
$debug_ui.debug();
shaders::reload();
break;
case KEY::O:
autowalking = true;

@ -5,6 +5,7 @@
#include "ai.hpp"
#include "animation.hpp"
#include <iostream>
#include "shaders.hpp"
int main(int argc, char* argv[]) {
try {
@ -12,6 +13,7 @@ int main(int argc, char* argv[]) {
sound::init();
ai::init("assets/ai.json");
animation::init();
shaders::init();
sound::mute(true);
gui::FSM main;

@ -114,6 +114,7 @@ sources = [
'ritual_ui.cpp',
'rituals.cpp',
'save.cpp',
'shaders.cpp',
'shiterator.hpp',
'sound.cpp',
'spatialmap.cpp',
@ -145,6 +146,7 @@ executable('runtests', sources + [
'tests/matrix.cpp',
'tests/pathing.cpp',
'tests/rituals.cpp',
'tests/shaders.cpp',
'tests/sound.cpp',
'tests/spatialmap.cpp',
'tests/stats.cpp',

@ -394,7 +394,7 @@ void Raycaster::update_level(GameLevel level) {
void Raycaster::init_shaders() {
// dbc::check(sf::Shader::isAvailable(), "no shaders?!");
bool good = $brightness.loadFromFile("shaders/modal.frag", sf::Shader::Type::Fragment);
bool good = $brightness.loadFromFile("assets/shaders/modal.frag", sf::Shader::Type::Fragment);
dbc::check(good, "shader could not be loaded");
$brightness.setUniform("source", sf::Shader::CurrentTexture);
}

@ -0,0 +1,60 @@
#include "shaders.hpp"
#include <SFML/Graphics/Image.hpp>
#include "dbc.hpp"
#include <fmt/core.h>
#include "config.hpp"
#include "constants.hpp"
#include <memory>
namespace shaders {
using std::shared_ptr, std::make_shared;
static ShaderManager SMGR;
static bool initialized = false;
bool load_shader(std::string name, nlohmann::json& settings) {
std::string file_name = settings["file_name"];
auto ptr = std::make_shared<sf::Shader>();
bool good = ptr->loadFromFile(file_name, sf::Shader::Type::Fragment);
if(good) SMGR.shaders.try_emplace(name, name, file_name, ptr);
return good;
}
void init() {
if(!initialized) {
initialized = true;
Config config("assets/shaders.json");
bool good = load_shader("ERROR", config["ERROR"]);
dbc::check(good, "Failed to load ERROR shader. Look in assets/shaders.json");
for(auto& [name, settings] : config.json().items()) {
if(name == "ERROR") continue;
dbc::check(!SMGR.shaders.contains(name),
fmt::format("shader name '{}' duplicated in assets/shaders.json", name));
good = load_shader(name, settings);
if(!good) {
dbc::log(fmt::format("failed to load shader {}", name));
SMGR.shaders.insert_or_assign(name, SMGR.shaders.at("ERROR"));
}
}
}
}
sf::Shader* get(std::string name) {
dbc::check(initialized, "you forgot to shaders::init()");
dbc::check(SMGR.shaders.contains(name),
fmt::format("shader name '{}' not in assets/shaders.json", name));
auto& rec = SMGR.shaders.at(name);
return rec.ptr.get();
}
void reload() {
initialized = false;
SMGR.shaders.clear();
init();
}
};

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#include <vector>
#include <string>
#include <SFML/Graphics.hpp>
#include <unordered_map>
#include <memory>
#include "matrix.hpp"
#include <nlohmann/json.hpp>
namespace shaders {
struct Record {
std::string name;
std::string file_name;
std::shared_ptr<sf::Shader> ptr = nullptr;
};
struct ShaderManager {
std::unordered_map<std::string, Record> shaders;
};
void init();
bool load_shader(std::string& name, nlohmann::json& settings);
sf::Shader* get(std::string name);
void reload();
}

@ -0,0 +1,22 @@
#include <catch2/catch_test_macros.hpp>
#include <fmt/core.h>
#include <string>
#include "shaders.hpp"
using namespace fmt;
TEST_CASE("shader loading/init works", "[shaders]") {
shaders::init();
sf::Shader* ui_shader = shaders::get("ui_shader");
auto other_test = shaders::get("ui_shader");
REQUIRE(ui_shader != nullptr);
REQUIRE(ui_shader == other_test);
shaders::reload();
// auto after_reload = shaders::get("ui_shader");
// REQUIRE(ui_shader != after_reload);
// REQUIRE(other_test != after_reload);
}
Loading…
Cancel
Save