diff --git a/Makefile b/Makefile index 99d5518..3c7d450 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SAMPLE=./sample/about-bezos.md +SAMPLE=./no-stream.md ROOT_DIR=$(dir $(firstword $(MAKEFILE_LIST))) all: build diff --git a/assets/layouts.json b/assets/layouts.json index 2481dfd..31ca803 100644 --- a/assets/layouts.json +++ b/assets/layouts.json @@ -30,11 +30,11 @@ "[_|_|_|_|_]" ], "centered": [ - "[=*%(300,200)title|_|_|_|_]", + "[=*%(300,400)title|_|_|_|_]", "[_|_|_]", - "[=*%(300,600)content]", "[_|_|_]", "[_|_|_]", + "[=*%(300,400)content]", "[_|_|_]", "[_|_|_]", "[_|_|_]" diff --git a/assets/shaders.json b/assets/shaders.json index 825dbba..4e13d67 100644 --- a/assets/shaders.json +++ b/assets/shaders.json @@ -6,5 +6,21 @@ "ERROR": { "file_name": "assets/shaders/ui_error.frag", "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" } } diff --git a/assets/shaders/flame_trash.frag b/assets/shaders/flame_trash.frag new file mode 100644 index 0000000..092e4fd --- /dev/null +++ b/assets/shaders/flame_trash.frag @@ -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; +} diff --git a/assets/shaders/lightning_attack.frag b/assets/shaders/lightning_attack.frag new file mode 100644 index 0000000..eb41295 --- /dev/null +++ b/assets/shaders/lightning_attack.frag @@ -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; +} diff --git a/assets/shaders/rayview_sprites.frag b/assets/shaders/rayview_sprites.frag new file mode 100644 index 0000000..fcffabf --- /dev/null +++ b/assets/shaders/rayview_sprites.frag @@ -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; +} diff --git a/sample/about-bezos.md b/sample/about-bezos.md index 1c8e6d4..b20cc80 100644 --- a/sample/about-bezos.md +++ b/sample/about-bezos.md @@ -40,6 +40,14 @@ Bare content like this * { "bg_image": "file_path" } * 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], "font_color": [255, 146, 0, 255], @@ -68,14 +76,14 @@ One Word { "layout": "image_left", "image_stretch": false, -"title_size": 100, +"title_size": 150, "font_size": 50 } # Specific Positions ![image](assets/sample_bg.jpg) * ![image](assets/sample_bg.jpg) * Places in image cell in layout. -* Can combine with + can combine with image_stretch and layout to place it anywhere. --- diff --git a/src/backend.cpp b/src/backend.cpp index 824861d..c7f1519 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -1,6 +1,7 @@ #include "backend.hpp" #include "dbc.hpp" #include +#include using std::string; @@ -31,13 +32,20 @@ namespace gui { } std::shared_ptr Backend::get_shader(const std::string& name) { - dbc::log("Backend::get_shader not implemented"); - return nullptr; + return shaders::get(name); } bool Backend::shader_updated() { - dbc::log("Backend::shader_updated not implemented"); - return false; + if(shaders::updated($shaders_version)) { + $shaders_version = shaders::version(); + return true; + } else { + return false; + } + } + + Backend::Backend() { + shaders::init(); } guecs::Theme Backend::theme() { diff --git a/src/backend.hpp b/src/backend.hpp index 80a2493..c434ce3 100644 --- a/src/backend.hpp +++ b/src/backend.hpp @@ -5,9 +5,12 @@ namespace gui { class Backend : public guecs::Backend { + int $shaders_version = 0; + public: std::string $font_file = "assets/text.otf"; + Backend(); guecs::SpriteTexture get_sprite(const std::string& name); guecs::SpriteTexture get_icon(const std::string& name); void sound_play(const std::string& name); diff --git a/src/main.cpp b/src/main.cpp index b669ec1..7927913 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,10 +9,11 @@ #include #include #include +#include using namespace std::chrono_literals; -std::optional load_slides(const std::string& input_md, std::shared_ptr backend) { +std::shared_ptr load_slides(const std::string& input_md, std::shared_ptr backend) { try { auto data = parse_slides(input_md, [&](nlohmann::json& config) { backend->set_font(config["font_file"]); @@ -21,13 +22,13 @@ std::optional load_slides(const std::string& input_md, std::shared_ptr fmt::println("FONT FILE: {}", backend->$font_file); - SlidesUI slides(data); - slides.init(); + auto slides = std::make_shared(data, sf::Vector2u{WINDOW_WIDTH, WINDOW_HEIGHT}); + slides->init(); return slides; } catch(...) { fmt::println("ERROR!"); - return std::nullopt; + return nullptr; } } @@ -76,43 +77,45 @@ int main(int argc, char *argv[]) { auto backend = std::make_shared(); - 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"); return 1; } - SlidesUI slides = *new_slides; ControlUI control_ui(presenter); control_ui.init(); dbc::check(control_ui.$status != nullptr, "bad ptr"); ChangeDetector slides_reloader{argv[1]}; - ChangeDetector layout_reloader{slides.$deck->config["layouts"]}; + ChangeDetector layout_reloader{slides->$deck->config["layouts"]}; while(controller.isOpen()) { 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()) { if(event) control_ui.handle_events(controller, *event); } - slides.render(presenter); + slides->render(presenter); control_ui.render(controller); presenter.display(); controller.display(); 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); if(new_slides) { - new_slides->set_slide(slides.$current); - slides = *new_slides; + new_slides->set_slide(current_slide); + slides = new_slides; } } } diff --git a/src/slides_ui.cpp b/src/slides_ui.cpp index 55d64d5..a30ba9e 100644 --- a/src/slides_ui.cpp +++ b/src/slides_ui.cpp @@ -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"]; } -void Slide::render(sf::RenderWindow& window) { - $gui.render(window); - // $gui.debug_layout(window); +void Slide::render(sf::RenderTarget& view) { + $gui.render(view); + // $gui.debug_layout(view); } -SlidesUI::SlidesUI(shared_ptr deck) { +SlidesUI::SlidesUI(shared_ptr deck, sf::Vector2u size) : + $view_texture{size}, + $view_sprite($view_texture.getTexture()) +{ dbc::check(deck != nullptr, "deck is null"); dbc::check(deck->slides.size() > 0, "slide deck is empy"); $deck = deck; @@ -156,6 +159,13 @@ void SlidesUI::show_slide() { 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"}; if(slide.$config.contains("layout")) { @@ -168,13 +178,22 @@ void SlidesUI::show_slide() { bg.init(); auto& cell = $gui.cell_for("slide"); + slide.init(cell, layout); } -void SlidesUI::render(sf::RenderWindow& window) { - $gui.render(window); +void SlidesUI::render(sf::RenderTarget& window) { + $gui.render($view_texture); 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); } diff --git a/src/slides_ui.hpp b/src/slides_ui.hpp index 3f7254a..1273477 100644 --- a/src/slides_ui.hpp +++ b/src/slides_ui.hpp @@ -1,7 +1,8 @@ #pragma once -#include "guecs/sfml/components.hpp" -#include "guecs/ui.hpp" +#include +#include +#include #include #include #include "constants.hpp" @@ -22,7 +23,7 @@ struct Slide { Slide() {} 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); }; @@ -37,9 +38,13 @@ struct SlidesUI { guecs::UI $gui; std::shared_ptr $deck = nullptr; std::unordered_map $layouts; + sf::RenderTexture $view_texture; + sf::Sprite $view_sprite; + std::shared_ptr $view_shader = nullptr; + sf::Clock $clock; size_t $current = 0; - SlidesUI(std::shared_ptr deck); + SlidesUI(std::shared_ptr deck, sf::Vector2u size); void init(); Slide& current(); @@ -47,7 +52,7 @@ struct SlidesUI { void prev_slide(); void show_slide(); 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 set_text(const std::string& name); void handle_events(sf::RenderWindow& presenter, const sf::Event& event);