You can now set a shader for a slide.

master
Zed A. Shaw 2 days ago
parent 2c3c105ca7
commit 6e1d8e6c6f
  1. 2
      Makefile
  2. 4
      assets/layouts.json
  3. 16
      assets/shaders.json
  4. 79
      assets/shaders/flame_trash.frag
  5. 79
      assets/shaders/lightning_attack.frag
  6. 25
      assets/shaders/rayview_sprites.frag
  7. 12
      sample/about-bezos.md
  8. 16
      src/backend.cpp
  9. 3
      src/backend.hpp
  10. 27
      src/main.cpp
  11. 33
      src/slides_ui.cpp
  12. 15
      src/slides_ui.hpp

@ -1,4 +1,4 @@
SAMPLE=./sample/about-bezos.md SAMPLE=./no-stream.md
ROOT_DIR=$(dir $(firstword $(MAKEFILE_LIST))) ROOT_DIR=$(dir $(firstword $(MAKEFILE_LIST)))
all: build all: build

@ -30,11 +30,11 @@
"[_|_|_|_|_]" "[_|_|_|_|_]"
], ],
"centered": [ "centered": [
"[=*%(300,200)title|_|_|_|_]", "[=*%(300,400)title|_|_|_|_]",
"[_|_|_]", "[_|_|_]",
"[=*%(300,600)content]",
"[_|_|_]", "[_|_|_]",
"[_|_|_]", "[_|_|_]",
"[=*%(300,400)content]",
"[_|_|_]", "[_|_|_]",
"[_|_|_]", "[_|_|_]",
"[_|_|_]" "[_|_|_]"

@ -6,5 +6,21 @@
"ERROR": { "ERROR": {
"file_name": "assets/shaders/ui_error.frag", "file_name": "assets/shaders/ui_error.frag",
"type": "fragment" "type": "fragment"
},
"rayview_sprites": {
"file_name": "assets/shaders/rayview_sprites.frag",
"type": "fragment"
},
"flame": {
"file_name": "assets/shaders/flame_trash.frag",
"type": "fragment"
},
"lightning": {
"file_name": "assets/shaders/lightning_attack.frag",
"type": "fragment"
},
"boss_hit": {
"file_name": "assets/shaders/flame_trash.frag",
"type": "fragment"
} }
} }

@ -0,0 +1,79 @@
#version 120
uniform vec2 u_resolution;
uniform float u_time;
uniform sampler2D source;
uniform float u_mouse;
uniform float value = 0.2;
uniform int octaves=8;
float random (in vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))*
43758.5453123);
}
float noise(in vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) +
(c - a) * u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
float fbm(in vec2 st) {
float v = 0.0;
float a = 0.5;
vec2 shift = vec2(100.0);
mat2 rot = mat2(cos(0.5), sin(0.5),
-sin(0.5), cos(0.5));
for(int i = 0; i < octaves; i++) {
v += a * noise(st);
st = rot * st * 2.0 + shift;
a *= 0.5;
}
return v;
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy * 3.0;
vec3 color = vec3(0.0);
float speed = u_time * 10.0;
float value = 0.8; // cos(u_time) * cos(u_time);
vec2 q = vec2(0.0);
q.x = fbm(st + 0.00 * speed);
q.y = fbm(st + vec2(1.0));
vec2 r = vec2(0,0);
r.x += fbm( st + 1.0*q + vec2(1.0, 0.0)+ 0.15* speed );
r.y += fbm( st + 1.0*q + vec2(-1.0, 0.0)+ 0.126* speed);
float f = fbm(st * r);
color = mix(vec3(0.666667,0.619608, 0.122777),
vec3(0.666667,0.666667,0.498039),
clamp((f*f)*4.0,0.0,1.0));
color = mix(color,
vec3(0.666667, 0.122222, 0.0666667),
clamp(length(r.x), 0.0, 1.0));
color *= (f*f*f+0.5*f*f+0.6*f) * value;
vec4 pixel = texture2D(source, gl_TexCoord[0].xy);
float mask = color.r * pixel.a;
gl_FragColor = gl_Color * vec4(color, mask) + pixel;
}

@ -0,0 +1,79 @@
#version 120
uniform vec2 u_resolution;
uniform float u_time;
uniform sampler2D source;
uniform float u_mouse;
uniform float value = 0.2;
uniform int octaves=8;
float random (in vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))*
43758.5453123);
}
float noise(in vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) +
(c - a) * u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
float fbm(in vec2 st) {
float v = 0.0;
float a = 0.5;
vec2 shift = vec2(100.0);
mat2 rot = mat2(cos(0.5), sin(0.5),
-sin(0.5), cos(0.5));
for(int i = 0; i < octaves; i++) {
v += a * noise(st);
st = rot * st * 2.0 + shift;
a *= 0.5;
}
return v;
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy * 3.0;
vec3 color = vec3(0.0);
float speed = u_time * 40.0;
float value = cos(u_time) * cos(u_time);
vec2 q = vec2(0.0);
q.x = fbm(st + 0.00 * speed);
q.y = fbm(st + vec2(1.0));
vec2 r = vec2(0,0);
r.x += fbm( st + 1.0*q + vec2(1.0, 0.0)+ 0.15* speed );
r.y += fbm( st + 1.0*q + vec2(-1.0, 0.0)+ 0.126* speed);
float f = fbm(st / r);
color = mix(vec3(0.122777,0.619608, 0.666667),
vec3(0.498039,0.666667,0.666667),
clamp((f*f)*4.0,0.0,1.0));
color = mix(color,
vec3(0.0666667, 0.122222, 0.666667),
clamp(length(r.x), 0.0, 1.0));
color *= (f*f*f+0.5*f*f+0.6*f) * value;
vec4 pixel = texture2D(source, gl_TexCoord[0].xy);
float mask = color.r * pixel.a;
gl_FragColor = gl_Color * vec4(color, mask) + pixel;
}

@ -0,0 +1,25 @@
uniform sampler2D source;
uniform sampler2D bloom;
uniform vec2 offsetFactor;
uniform float darkness;
void main()
{
vec2 textureCoordinates = gl_TexCoord[0].xy;
vec4 color = vec4(0.0);
color += texture2D(source, textureCoordinates - 4.0 * offsetFactor) * 0.0162162162;
color += texture2D(source, textureCoordinates - 3.0 * offsetFactor) * 0.0540540541;
color += texture2D(source, textureCoordinates - 2.0 * offsetFactor) * 0.1216216216;
color += texture2D(source, textureCoordinates - offsetFactor) * 0.1945945946;
color += texture2D(source, textureCoordinates) * 0.2270270270;
color += texture2D(source, textureCoordinates + offsetFactor) * 0.1945945946;
color += texture2D(source, textureCoordinates + 2.0 * offsetFactor) * 0.1216216216;
color += texture2D(source, textureCoordinates + 3.0 * offsetFactor) * 0.0540540541;
color += texture2D(source, textureCoordinates + 4.0 * offsetFactor) * 0.0162162162;
vec4 sourceFragment = texture2D(source, gl_TexCoord[0].xy);
vec4 bloomFragment = texture2D(bloom, gl_TexCoord[0].xy);
float alpha = color.a;
gl_FragColor = (color + sourceFragment - bloomFragment) * darkness;
gl_FragColor.a = alpha;
}

@ -40,6 +40,14 @@ Bare content like this
* { "bg_image": "file_path" } * { "bg_image": "file_path" }
* You don't even need text * You don't even need text
--- ---
{
"shader": "flame",
"bg_color": [100, 20, 10, 255]
}
# Shaders
* Use "shader": "flame"
* Shaders configured in assets/shaders.json
---
{ {
"bg_color": [10, 10, 25, 255], "bg_color": [10, 10, 25, 255],
"font_color": [255, 146, 0, 255], "font_color": [255, 146, 0, 255],
@ -68,14 +76,14 @@ One Word
{ {
"layout": "image_left", "layout": "image_left",
"image_stretch": false, "image_stretch": false,
"title_size": 100, "title_size": 150,
"font_size": 50 "font_size": 50
} }
# Specific Positions # Specific Positions
![image](assets/sample_bg.jpg) ![image](assets/sample_bg.jpg)
* ![image](assets/sample_bg.jpg) * ![image](assets/sample_bg.jpg)
* Places in image cell in layout. * Places in image cell in layout.
* Can combine with can combine with
image_stretch and layout image_stretch and layout
to place it anywhere. to place it anywhere.
--- ---

@ -1,6 +1,7 @@
#include "backend.hpp" #include "backend.hpp"
#include "dbc.hpp" #include "dbc.hpp"
#include <string> #include <string>
#include <guecs/sfml/shaders.hpp>
using std::string; using std::string;
@ -31,13 +32,20 @@ namespace gui {
} }
std::shared_ptr<sf::Shader> Backend::get_shader(const std::string& name) { std::shared_ptr<sf::Shader> Backend::get_shader(const std::string& name) {
dbc::log("Backend::get_shader not implemented"); return shaders::get(name);
return nullptr;
} }
bool Backend::shader_updated() { bool Backend::shader_updated() {
dbc::log("Backend::shader_updated not implemented"); if(shaders::updated($shaders_version)) {
return false; $shaders_version = shaders::version();
return true;
} else {
return false;
}
}
Backend::Backend() {
shaders::init();
} }
guecs::Theme Backend::theme() { guecs::Theme Backend::theme() {

@ -5,9 +5,12 @@
namespace gui { namespace gui {
class Backend : public guecs::Backend { class Backend : public guecs::Backend {
int $shaders_version = 0;
public: public:
std::string $font_file = "assets/text.otf"; std::string $font_file = "assets/text.otf";
Backend();
guecs::SpriteTexture get_sprite(const std::string& name); guecs::SpriteTexture get_sprite(const std::string& name);
guecs::SpriteTexture get_icon(const std::string& name); guecs::SpriteTexture get_icon(const std::string& name);
void sound_play(const std::string& name); void sound_play(const std::string& name);

@ -9,10 +9,11 @@
#include <filesystem> #include <filesystem>
#include <chrono> #include <chrono>
#include <SFML/System/Clock.hpp> #include <SFML/System/Clock.hpp>
#include <memory>
using namespace std::chrono_literals; using namespace std::chrono_literals;
std::optional<SlidesUI> load_slides(const std::string& input_md, std::shared_ptr<gui::Backend> backend) { std::shared_ptr<SlidesUI> load_slides(const std::string& input_md, std::shared_ptr<gui::Backend> backend) {
try { try {
auto data = parse_slides(input_md, [&](nlohmann::json& config) { auto data = parse_slides(input_md, [&](nlohmann::json& config) {
backend->set_font(config["font_file"]); backend->set_font(config["font_file"]);
@ -21,13 +22,13 @@ std::optional<SlidesUI> load_slides(const std::string& input_md, std::shared_ptr
fmt::println("FONT FILE: {}", backend->$font_file); fmt::println("FONT FILE: {}", backend->$font_file);
SlidesUI slides(data); auto slides = std::make_shared<SlidesUI>(data, sf::Vector2u{WINDOW_WIDTH, WINDOW_HEIGHT});
slides.init(); slides->init();
return slides; return slides;
} catch(...) { } catch(...) {
fmt::println("ERROR!"); fmt::println("ERROR!");
return std::nullopt; return nullptr;
} }
} }
@ -76,43 +77,45 @@ int main(int argc, char *argv[]) {
auto backend = std::make_shared<gui::Backend>(); auto backend = std::make_shared<gui::Backend>();
auto new_slides = load_slides(argv[1], backend); auto slides = load_slides(argv[1], backend);
if(!new_slides) { if(!slides) {
fmt::println("ERROR in your .md file"); fmt::println("ERROR in your .md file");
return 1; return 1;
} }
SlidesUI slides = *new_slides;
ControlUI control_ui(presenter); ControlUI control_ui(presenter);
control_ui.init(); control_ui.init();
dbc::check(control_ui.$status != nullptr, "bad ptr"); dbc::check(control_ui.$status != nullptr, "bad ptr");
ChangeDetector slides_reloader{argv[1]}; ChangeDetector slides_reloader{argv[1]};
ChangeDetector layout_reloader{slides.$deck->config["layouts"]}; ChangeDetector layout_reloader{slides->$deck->config["layouts"]};
while(controller.isOpen()) { while(controller.isOpen()) {
while (const auto event = presenter.pollEvent()) { while (const auto event = presenter.pollEvent()) {
if(event) slides.handle_events(presenter, *event); if(event) slides->handle_events(presenter, *event);
} }
while (const auto event = controller.pollEvent()) { while (const auto event = controller.pollEvent()) {
if(event) control_ui.handle_events(controller, *event); if(event) control_ui.handle_events(controller, *event);
} }
slides.render(presenter); slides->render(presenter);
control_ui.render(controller); control_ui.render(controller);
presenter.display(); presenter.display();
controller.display(); controller.display();
if(slides_reloader.changed() || layout_reloader.changed()) { if(slides_reloader.changed() || layout_reloader.changed()) {
// save the current slide
auto current_slide = slides->$current;
// load the new one
auto new_slides = load_slides(argv[1], backend); auto new_slides = load_slides(argv[1], backend);
if(new_slides) { if(new_slides) {
new_slides->set_slide(slides.$current); new_slides->set_slide(current_slide);
slides = *new_slides; slides = new_slides;
} }
} }
} }

@ -68,12 +68,15 @@ void Slide::config_text(guecs::Text &result, nlohmann::json& config, std::string
if(config.contains(prefix + "_centered")) result.centered = config[prefix + "_centered"]; if(config.contains(prefix + "_centered")) result.centered = config[prefix + "_centered"];
} }
void Slide::render(sf::RenderWindow& window) { void Slide::render(sf::RenderTarget& view) {
$gui.render(window); $gui.render(view);
// $gui.debug_layout(window); // $gui.debug_layout(view);
} }
SlidesUI::SlidesUI(shared_ptr<SlideDeck> deck) { SlidesUI::SlidesUI(shared_ptr<SlideDeck> deck, sf::Vector2u size) :
$view_texture{size},
$view_sprite($view_texture.getTexture())
{
dbc::check(deck != nullptr, "deck is null"); dbc::check(deck != nullptr, "deck is null");
dbc::check(deck->slides.size() > 0, "slide deck is empy"); dbc::check(deck->slides.size() > 0, "slide deck is empy");
$deck = deck; $deck = deck;
@ -156,6 +159,13 @@ void SlidesUI::show_slide() {
color = {color_conf[0], color_conf[1], color_conf[2], color_conf[3]}; color = {color_conf[0], color_conf[1], color_conf[2], color_conf[3]};
} }
if(slide.$config.contains("shader")) {
$view_shader = shaders::get(slide.$config["shader"]);
$view_shader->setUniform("u_resolution", sf::Vector2f{WINDOW_WIDTH, WINDOW_HEIGHT});
} else {
$view_shader = nullptr;
}
std::string layout_name{"default_slide"}; std::string layout_name{"default_slide"};
if(slide.$config.contains("layout")) { if(slide.$config.contains("layout")) {
@ -168,13 +178,22 @@ void SlidesUI::show_slide() {
bg.init(); bg.init();
auto& cell = $gui.cell_for("slide"); auto& cell = $gui.cell_for("slide");
slide.init(cell, layout); slide.init(cell, layout);
} }
void SlidesUI::render(sf::RenderWindow& window) { void SlidesUI::render(sf::RenderTarget& window) {
$gui.render(window); $gui.render($view_texture);
auto& slide = current(); auto& slide = current();
slide.render(window); slide.render($view_texture);
$view_texture.display();
if($view_shader) {
$view_shader->setUniform("u_time", $clock.getElapsedTime().asSeconds());
window.draw($view_sprite, $view_shader.get());
} else {
window.draw($view_sprite);
}
// $gui.debug_layout(window); // $gui.debug_layout(window);
} }

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "guecs/sfml/components.hpp" #include <guecs/sfml/components.hpp>
#include "guecs/ui.hpp" #include <guecs/sfml/shaders.hpp>
#include <guecs/ui.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <memory> #include <memory>
#include "constants.hpp" #include "constants.hpp"
@ -22,7 +23,7 @@ struct Slide {
Slide() {} Slide() {}
void init(lel::Cell& cell, const std::string& layout); void init(lel::Cell& cell, const std::string& layout);
void render(sf::RenderWindow& window); void render(sf::RenderTarget& view);
void config_text(guecs::Text &result, nlohmann::json& config, std::string prefix); void config_text(guecs::Text &result, nlohmann::json& config, std::string prefix);
}; };
@ -37,9 +38,13 @@ struct SlidesUI {
guecs::UI $gui; guecs::UI $gui;
std::shared_ptr<SlideDeck> $deck = nullptr; std::shared_ptr<SlideDeck> $deck = nullptr;
std::unordered_map<std::string, std::string> $layouts; std::unordered_map<std::string, std::string> $layouts;
sf::RenderTexture $view_texture;
sf::Sprite $view_sprite;
std::shared_ptr<sf::Shader> $view_shader = nullptr;
sf::Clock $clock;
size_t $current = 0; size_t $current = 0;
SlidesUI(std::shared_ptr<SlideDeck> deck); SlidesUI(std::shared_ptr<SlideDeck> deck, sf::Vector2u size);
void init(); void init();
Slide& current(); Slide& current();
@ -47,7 +52,7 @@ struct SlidesUI {
void prev_slide(); void prev_slide();
void show_slide(); void show_slide();
void set_slide(size_t index); void set_slide(size_t index);
void render(sf::RenderWindow& window); void render(sf::RenderTarget& window);
void mouse(float x, float y, guecs::Modifiers mods); void mouse(float x, float y, guecs::Modifiers mods);
void set_text(const std::string& name); void set_text(const std::string& name);
void handle_events(sf::RenderWindow& presenter, const sf::Event& event); void handle_events(sf::RenderWindow& presenter, const sf::Event& event);

Loading…
Cancel
Save