diff --git a/Keishiki/Graphics.cpp b/Keishiki/Graphics.cpp index b290676..9efbc81 100644 --- a/Keishiki/Graphics.cpp +++ b/Keishiki/Graphics.cpp @@ -225,10 +225,10 @@ namespace K::Graphics { mmaker = Graphics::GetImageTextureFromFile("mmaker.png"); bx::mtxTranslate(composite_view, 0.f, 0.f, 1.0f); - composite_A = bgfx::createUniform("v_A", bgfx::UniformType::Sampler); - composite_B = bgfx::createUniform("v_B", bgfx::UniformType::Sampler); + composite_A = bgfx::createUniform("s_A", bgfx::UniformType::Sampler); + composite_B = bgfx::createUniform("s_B", bgfx::UniformType::Sampler); composite_pg = load_shader_program("BinaryComposite"); - composite_mode = bgfx::createUniform("f_mode", bgfx::UniformType::Vec4); + composite_mode = bgfx::createUniform("u_mode", bgfx::UniformType::Vec4); return true; } @@ -427,24 +427,23 @@ namespace K::Graphics { return pos_x; } - void Composite(bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]) { + void Composite(u32 view_id, bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]) { static f32 pack[4]{}; - pack[0] = static_cast(mode); + pack[3] = pack[2] = pack[1] = pack[0] = static_cast(mode); - bgfx::touch(K::Graphics::K_VIEW_COMP_COMPOSITE); - bgfx::setViewMode(K::Graphics::K_VIEW_COMP_COMPOSITE, bgfx::ViewMode::Sequential); - bgfx::setViewClear(K::Graphics::K_VIEW_COMP_COMPOSITE, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); - bgfx::setViewFrameBuffer(K::Graphics::K_VIEW_COMP_COMPOSITE, fb); - bgfx::setViewTransform(K::Graphics::K_VIEW_COMP_COMPOSITE, composite_view, proj); - bgfx::setViewRect(K::Graphics::K_VIEW_COMP_COMPOSITE, 0, 0, w, h); + bgfx::setViewMode(view_id, bgfx::ViewMode::Sequential); + bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL); + bgfx::setViewFrameBuffer(view_id, fb); + bgfx::setViewTransform(view_id, composite_view, proj); + bgfx::setViewRect(view_id, 0, 0, w, h); bgfx::setTransform(transform); bgfx::setVertexBuffer(0, vbh); bgfx::setIndexBuffer(ibh); - bgfx::setTexture(0, composite_A, composite); - bgfx::setTexture(1, composite_B, from); - bgfx::setUniform(composite_mode, pack); - bgfx::setState((BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ALPHA) & ~(BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS)); - bgfx::submit(K::Graphics::K_VIEW_COMP_COMPOSITE, composite_pg); + bgfx::setTexture(0, composite_A, from); // A + bgfx::setTexture(1, composite_B, composite); // B + bgfx::setUniform(composite_mode, pack); // A over B + bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A); + bgfx::submit(view_id, composite_pg); } } diff --git a/Keishiki/Keishiki.cpp b/Keishiki/Keishiki.cpp index 6563fb9..5c69be6 100644 --- a/Keishiki/Keishiki.cpp +++ b/Keishiki/Keishiki.cpp @@ -13,19 +13,13 @@ #include namespace { - SDL_Window *window; - u16 window_width = 1920; - u16 window_height = 1080; - - u64 init_time, last_time, current_time, delta_t; - u32 frame; - bool running = false; - K::CompState state; K::Graphics::ImageTexture *logo; } namespace K { + K::AppState app_state; + PlugboardGraph::T_Map::type FetchCompFrame(const CompState& s, const PlugboardGraph::NodeInstance& n) { return PlugboardGraph::T_Map::type{static_cast(s.current_frame)}; } @@ -42,28 +36,28 @@ namespace K { return false; } - window = SDL_CreateWindow("Keishiki", + app_state.window = SDL_CreateWindow("Keishiki", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - window_width, window_height, + app_state.window_width, app_state.window_height, SDL_WINDOW_SHOWN); - if (window == nullptr) { + if (app_state.window == nullptr) { LogError(SDL_GetError()); return false; } bgfx::Init bgfxInit; bgfxInit.type = bgfx::RendererType::Count; // Automatically choose a renderer. - bgfxInit.resolution.width = window_width; - bgfxInit.resolution.height = window_height; + bgfxInit.resolution.width = app_state.window_width; + bgfxInit.resolution.height = app_state.window_height; bgfxInit.resolution.reset = BGFX_RESET_VSYNC; #if !BX_PLATFORM_EMSCRIPTEN SDL_SysWMinfo wmi; SDL_VERSION(&wmi.version); - if (!SDL_GetWindowWMInfo(window, &wmi)) { + if (!SDL_GetWindowWMInfo(app_state.window, &wmi)) { LogError(SDL_GetError()); } #endif @@ -85,16 +79,16 @@ namespace K { } bgfx::setDebug(BGFX_DEBUG_TEXT); - bgfx::setViewRect(K::Graphics::K_VIEW_LOGO, 0, 0, window_width, window_height); + bgfx::setViewRect(K::Graphics::K_VIEW_LOGO, 0, 0, app_state.window_width, app_state.window_height); float view[16]; bx::mtxTranslate(view, 0.f, 0.f, 1.0f); float proj[16]; - bx::mtxOrtho(proj, 0.0f, window_width, 0.0f, window_height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); + bx::mtxOrtho(proj, 0.0f, app_state.window_width, 0.0f, app_state.window_height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); bgfx::setViewTransform(K::Graphics::K_VIEW_LOGO, view, proj); - K::UI::Init(window); + K::UI::Init(app_state.window); - if (!K::Graphics::Init(window_width, window_height)) { + if (!K::Graphics::Init(app_state.window_width, app_state.window_height)) { LogError("Graphics init failed"); return false; } @@ -105,7 +99,7 @@ namespace K { state.height = 550; state.current_frame = 0; state.fps = 30.0f; - state.frame_max = 50; + state.frame_max = 200; state.plugboard.comp_in = PlugboardGraph::Node{ "Composition In", {}, @@ -128,46 +122,47 @@ namespace K { } void Render() { - K::Graphics::DrawTextureImageAlpha(K::Graphics::K_VIEW_LOGO, *logo, window_width - logo->w + 10, 0, .4f); + K::Graphics::DrawTextureImageAlpha(K::Graphics::K_VIEW_LOGO, *logo, app_state.window_width - logo->w + 10, 0, .4f); - UI::Draw(frame, state); + UI::Draw(app_state.bgfx_frame, state); const bgfx::Stats *stat = bgfx::getStats(); const bgfx::Caps *caps = bgfx::getCaps(); bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, window_height/16 - 4, 0xf8, + bgfx::dbgTextPrintf(0, app_state.window_height/16 - 4, 0xf8, " lachrymal.net :: %s Renderer :: Max Views %u :: Max FBs %u :: Max Texture Samplers %u :: Blitting %s :: %u FPS", caps->supported & BGFX_CAPS_RENDERER_MULTITHREADED ? "Multithreaded" : "Singlethreaded", caps->limits.maxViews, caps->limits.maxFrameBuffers, caps->limits.maxTextureSamplers, caps->supported & BGFX_CAPS_TEXTURE_BLIT ? "OK" : "NO", stat->cpuTimerFreq / stat->cpuTimeFrame); - bgfx::dbgTextPrintf(0, window_height/16 - 3, 0xf8, + bgfx::dbgTextPrintf(0, app_state.window_height/16 - 3, 0xf8, " Project Keishiki :: %s :: Build %s %s :: SDL %i.%i.%i :: bgfx 1.%i :: Dear ImGui %s :: %s", BX_COMPILER_NAME, __DATE__, __TIME__, SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL, BGFX_API_VERSION, ImGui::GetVersion(), bgfx::getRendererName(bgfx::getRendererType())); - frame = bgfx::frame(); + app_state.bgfx_frame = bgfx::frame(); } void Run() { - last_time = init_time = SDL_GetTicks64(); + app_state.init_time = SDL_GetTicks64(); + app_state.last_time = app_state.init_time; - running = true; - while (running) { - current_time = SDL_GetTicks64(); - delta_t = current_time - last_time; + app_state.running = true; + while (app_state.running) { + app_state.current_time = SDL_GetTicks64(); + app_state.delta_t = app_state.current_time - app_state.last_time; for (SDL_Event current_event; SDL_PollEvent(¤t_event) != 0;) { ImGui_ImplSDL2_ProcessEvent(¤t_event); if (current_event.type == SDL_QUIT) { - running = false; + app_state.running = false; break; } } Render(); - last_time = current_time; + app_state.last_time = app_state.current_time; } } @@ -175,7 +170,7 @@ namespace K { K::Graphics::Shutdown(); K::UI::Shutdown(state); bgfx::shutdown(); - SDL_DestroyWindow(window); + SDL_DestroyWindow(app_state.window); SDL_Quit(); } } diff --git a/Keishiki/UI.cpp b/Keishiki/UI.cpp index 95b6263..d658d85 100644 --- a/Keishiki/UI.cpp +++ b/Keishiki/UI.cpp @@ -29,11 +29,12 @@ namespace { const f32 row_height = 20.0f; // Viewport - bgfx::TextureHandle composite = BGFX_INVALID_HANDLE, - composite_blit = BGFX_INVALID_HANDLE, + bool playing; + u64 last_frame_tick; + bgfx::TextureHandle composite[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE }, render = BGFX_INVALID_HANDLE, save = BGFX_INVALID_HANDLE; - bgfx::FrameBufferHandle composite_fb = BGFX_INVALID_HANDLE, + bgfx::FrameBufferHandle composite_fb[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE }, render_fb = BGFX_INVALID_HANDLE; K::VisualTrack bg{}; f32 proj[16], transform[16], view[16]; @@ -55,6 +56,53 @@ namespace ImGui { } namespace K::UI { + + void AddTransformLayer(CompState& s, const std::string& name) { + auto l = Layer{ + VisualTrack{}, + name, + Graphics::K_V_AlphaOver, + 0UL, + s.frame_max + }; + l.track.add_uniform("aspect_ratio", ShaderGraph::expand_type(ShaderGraph::T_XY)); + if (s.width > s.height) + l.track.uniforms["aspect_ratio"].val = ShaderGraph::T_Map::type(static_cast(s.width)/static_cast(s.height), 1.0f); + else + l.track.uniforms["aspect_ratio"].val = ShaderGraph::T_Map::type(1.0f, static_cast(s.height)/static_cast(s.width)); + + l.track.add_uniform("opacity", ShaderGraph::expand_type(ShaderGraph::T_Float)); + l.track.uniforms["opacity"].val = ShaderGraph::T_Map::type(1.0f); + + l.track.add_uniform("rot", ShaderGraph::expand_type(ShaderGraph::T_Float)); + l.track.uniforms["rot"].val = ShaderGraph::T_Map::type(.0f); + + l.track.add_uniform("scale", ShaderGraph::expand_type(ShaderGraph::T_XY)); + l.track.uniforms["scale"].val = ShaderGraph::T_Map::type(1.0f, 1.0f); + + l.track.add_uniform("translate", ShaderGraph::expand_type(ShaderGraph::T_XY)); + l.track.uniforms["translate"].val = ShaderGraph::T_Map::type(.0f, .0f); + + l.track.shader = "void main() {\n" + "\tfloat angle = -rot * M_PI / 180.0f;\n" + "\tvec2 uv = vec2(v_texcoord0.x, 1.0f - v_texcoord0.y) - .5f;\n" + "\tuv = uv * aspect_ratio;\n" + "\tuv = uv - translate;\n" + "\tuv = vec2(cos(angle)*uv.x - sin(angle)*uv.y, sin(angle)*uv.x + cos(angle)*uv.y);\n" + "\tuv = uv / scale;\n" + "\tuv = uv + .5f;\n\n" + "\tvec4 tx = texture2D(s_texColor, uv);\n" + "\tgl_FragColor = vec4(tx.rgb, tx.a * opacity);\n" + "}\n"; + l.track.compile(); + l.track.expose_uniform(s, "aspect_ratio"); + l.track.expose_uniform(s, "opacity"); + l.track.expose_uniform(s, "rot"); + l.track.expose_uniform(s, "scale"); + l.track.expose_uniform(s, "translate"); + s.layers.push_back(std::move(l)); + } + void MainMenuBar(const CompState& s) { if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("Edit")) { @@ -78,13 +126,15 @@ namespace K::UI { } void SetupViewport(CompState& s) { - composite = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT); - composite_blit = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_BLIT_DST); + composite[0] = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT); + composite[1] = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT); render = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT); - bgfx::Attachment comp{}, ren{}; - comp.init(composite, bgfx::Access::Write); // DX 11 requires Write only + bgfx::Attachment comp{}, comp2{}, ren{}; + comp.init(composite[0], bgfx::Access::Write); // DX 11 requires Write only + comp2.init(composite[1], bgfx::Access::Write); // DX 11 requires Write only ren.init(render, bgfx::Access::ReadWrite); - composite_fb = bgfx::createFrameBuffer(1, &comp); + composite_fb[0] = bgfx::createFrameBuffer(1, &comp); + composite_fb[1] = bgfx::createFrameBuffer(1, &comp2); render_fb = bgfx::createFrameBuffer(1, &ren); save = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_READ_BACK | BGFX_TEXTURE_BLIT_DST); @@ -104,9 +154,10 @@ namespace K::UI { } void DestroyViewport(CompState& s) { - bgfx::destroy(composite_fb); - bgfx::destroy(composite); - bgfx::destroy(composite_blit); + bgfx::destroy(composite_fb[0]); + bgfx::destroy(composite_fb[1]); + bgfx::destroy(composite[0]); + bgfx::destroy(composite[1]); bgfx::destroy(render_fb); bgfx::destroy(render); @@ -268,29 +319,64 @@ namespace K::UI { } void Viewport(CompState& s) { - if (ImGui::Begin("Viewport", &draw_viewport)) { - ImTextureID idx; + if (playing) { + if (static_cast(app_state.current_time - last_frame_tick) >= 1000.0f / s.fps) { + f32 delta = static_cast(app_state.current_time - last_frame_tick); + f32 frames_passed = delta / (1000.0f / s.fps); + s.current_frame = (s.current_frame + static_cast(std::floor(frames_passed))) % (s.frame_max + 1); + last_frame_tick = app_state.current_time - static_cast(std::fmod(delta, 1000.0f / s.fps)); + } + } + + if (ImGui::Begin("Viewport", &draw_viewport)) { + u32 view_count = 0, layers_done = 0; + bgfx::setViewFrameBuffer(Graphics::K_VIEW_COMP_COMPOSITE + view_count, composite_fb[0]); // the other fb will be cleared in composite + bgfx::setViewClear(Graphics::K_VIEW_COMP_COMPOSITE + view_count, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL, 0x00000000); + bgfx::setViewRect(Graphics::K_VIEW_COMP_COMPOSITE + view_count, 0, 0, s.width, s.height); + bgfx::touch(Graphics::K_VIEW_COMP_COMPOSITE + view_count); + view_count++; - bg.get_frame(s, composite_fb, s.width, s.height, proj, view, transform); - bgfx::blit(Graphics::K_VIEW_COMP_COMPOSITE, composite_blit, 0, 0, composite); for (u32 i = s.layers.size() - 1; i != u32(-1); i--) { if (s.disabled.contains(i)) continue; if (s.current_frame > s.layers[i].out || s.current_frame < s.layers[i].in) continue; - Graphics::Composite( composite_fb, composite_blit, s.layers[i].track.get_frame(s, render_fb, s.width, s.height, proj, view, transform), - i == s.layers.size() - 1 ? Graphics::K_V_AlphaOver : s.layers[i].mode, s.width, s.height, proj, transform); - bgfx::blit(Graphics::K_VIEW_COMP_COMPOSITE, composite_blit, 0, 0, composite); + + s.layers[i].track.get_frame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, render_fb, s.width, s.height, proj, view, transform); + Graphics::Composite(Graphics::K_VIEW_COMP_COMPOSITE + view_count++, composite_fb[(layers_done + 1) % 2], composite[layers_done % 2], render, s.layers[i].mode, s.width, s.height, proj, transform); + layers_done++; } - idx = ImGui::toId(composite, 0, 0); + if (layers_done != 0) { + bg.get_frame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, render_fb, s.width, s.height, proj, view, + transform); + Graphics::Composite(Graphics::K_VIEW_COMP_COMPOSITE + view_count++, composite_fb[(layers_done + 1) % 2], + render, composite[layers_done % 2], Graphics::K_V_AlphaOver, s.width, s.height, + proj, transform); + layers_done++; + } + else { + bg.get_frame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, composite_fb[0], s.width, s.height, proj, view, + transform); + } + + Vector views; + for (u32 i = 0; i < view_count; i++) + views.push_back(Graphics::K_VIEW_COMP_COMPOSITE + i); + views.push_back(Graphics::K_VIEW_COMP_SAVE); + views.push_back(Graphics::K_VIEW_UI); + views.push_back(Graphics::K_VIEW_LOGO); + bgfx::setViewOrder(0, views.size(), views.data()); + + ImTextureID idx = ImGui::toId(composite[layers_done % 2], 0, 0); if (idx != nullptr) ImGui::Image(idx, ImVec2{ static_cast(s.width), static_cast(s.height) }); ImGui::Text("Composition Size: %ux%u", s.width, s.height); - + ImGui::SameLine(); + ImGui::DragFloat("FPS", &s.fps, 1.0f, 1.0f, 120.0f); ImGui::SameLine(); ImGui::BeginDisabled(save_called); if (ImGui::Button("Save to frame.png")) { - bgfx::blit(Graphics::K_VIEW_COMP_SAVE, save, 0, 0, composite); + bgfx::blit(Graphics::K_VIEW_COMP_SAVE, save, 0, 0, composite[layers_done % 2]); ready_frame = bgfx::readTexture(save, save_buffer); save_called = true; } @@ -339,6 +425,13 @@ namespace K::UI { ImGui::EndCombo(); } + ImGui::SameLine(); + bool playing_cp = playing; + ImGui::Checkbox("Playing", &playing); + if (!playing_cp && playing) { + last_frame_tick = app_state.current_time; + } + ImGui::SameLine(); ImGui::Text("%lu / %lu Frames", s.current_frame, s.frame_max); ImGui::SameLine(); @@ -347,49 +440,7 @@ namespace K::UI { static String name{}; if (ImGui::Button("Add Layer") && !name.empty()) { - auto l = Layer{ - VisualTrack{}, - name, - Graphics::K_V_AlphaOver, - 0UL, - s.frame_max - }; - l.track.add_uniform("aspect_ratio", ShaderGraph::expand_type(ShaderGraph::T_XY)); - if (s.width > s.height) - l.track.uniforms["aspect_ratio"].val = ShaderGraph::T_Map::type(static_cast(s.width)/static_cast(s.height), 1.0f); - else - l.track.uniforms["aspect_ratio"].val = ShaderGraph::T_Map::type(1.0f, static_cast(s.height)/static_cast(s.width)); - - l.track.add_uniform("opacity", ShaderGraph::expand_type(ShaderGraph::T_Float)); - l.track.uniforms["opacity"].val = ShaderGraph::T_Map::type(1.0f); - - l.track.add_uniform("rot", ShaderGraph::expand_type(ShaderGraph::T_Float)); - l.track.uniforms["rot"].val = ShaderGraph::T_Map::type(.0f); - - l.track.add_uniform("scale", ShaderGraph::expand_type(ShaderGraph::T_XY)); - l.track.uniforms["scale"].val = ShaderGraph::T_Map::type(1.0f, 1.0f); - - l.track.add_uniform("translate", ShaderGraph::expand_type(ShaderGraph::T_XY)); - l.track.uniforms["translate"].val = ShaderGraph::T_Map::type(.0f, .0f); - - l.track.shader = "void main() {\n" - "\tfloat angle = -rot * M_PI / 180.0f;\n" - "\tvec2 uv = vec2(v_texcoord0.x, 1.0f - v_texcoord0.y) - .5f;\n" - "\tuv = uv * aspect_ratio;\n" - "\tuv = uv - translate;\n" - "\tuv = vec2(cos(angle)*uv.x - sin(angle)*uv.y, sin(angle)*uv.x + cos(angle)*uv.y);\n" - "\tuv = uv / scale;\n" - "\tuv = uv + .5f;\n\n" - "\tvec4 tx = texture2D(s_texColor, uv);\n" - "\tgl_FragColor = vec4(tx.rgb, tx.a * opacity);\n" - "}\n"; - l.track.compile(); - l.track.expose_uniform(s, "aspect_ratio"); - l.track.expose_uniform(s, "opacity"); - l.track.expose_uniform(s, "rot"); - l.track.expose_uniform(s, "scale"); - l.track.expose_uniform(s, "translate"); - s.layers.push_back(std::move(l)); + AddTransformLayer(s, name); } ImGui::SameLine(); ImGui::SetNextItemWidth(-100.0f); @@ -869,7 +920,8 @@ namespace K::UI { f32 x = i.begin + (i.end - i.begin) * static_cast(idx) / static_cast(i.samples); CompState ss = i.s; ss.current_frame = static_cast(std::round(x)); - return {x, std::get::type>(PlugboardGraph::Eval(ss, i.connected_v))}; + bool good; + return {x, std::get::type>(PlugboardGraph::ConvertValue(PlugboardGraph::Eval(ss, i.connected_v), PlugboardGraph::T_Float, good))}; }, &info, info.samples); ImPlot::EndPlot(); } diff --git a/Keishiki/VisualTrack.cpp b/Keishiki/VisualTrack.cpp index c952ae7..4758d39 100644 --- a/Keishiki/VisualTrack.cpp +++ b/Keishiki/VisualTrack.cpp @@ -36,15 +36,13 @@ namespace K { },val); } - bgfx::TextureHandle - VisualTrack::get_frame(const CompState& s, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 *proj, f32 *view, f32 *transform) const { - bgfx::touch(K::Graphics::K_VIEW_COMP_COMPOSITE); - bgfx::setViewMode(K::Graphics::K_VIEW_COMP_COMPOSITE, bgfx::ViewMode::Sequential); - bgfx::setViewClear(K::Graphics::K_VIEW_COMP_COMPOSITE, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); - bgfx::setViewFrameBuffer(K::Graphics::K_VIEW_COMP_COMPOSITE, fb); + void VisualTrack::get_frame(const CompState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 *proj, f32 *view, f32 *transform) const { + bgfx::setViewMode(view_id, bgfx::ViewMode::Sequential); + bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL); + bgfx::setViewFrameBuffer(view_id, fb); - bgfx::setViewTransform(K::Graphics::K_VIEW_COMP_COMPOSITE, view, proj); - bgfx::setViewRect(K::Graphics::K_VIEW_COMP_COMPOSITE, 0, 0, w, h); + bgfx::setViewTransform(view_id, view, proj); + bgfx::setViewRect(view_id, 0, 0, w, h); for (auto& [_name, u] : uniforms) { f32 pack[4]{}; @@ -87,10 +85,8 @@ namespace K { bgfx::setUniform(u.handle, pack); } - Graphics::DrawTextureWithTransform(K::Graphics::K_VIEW_COMP_COMPOSITE, Graphics::mmaker->tx, transform, - (BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ALPHA) & - ~(BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS), pg); - return bgfx::getTexture(fb); + Graphics::DrawTextureWithTransform(view_id, Graphics::mmaker->tx, transform, + BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A, pg); } void VisualTrack::compile() { diff --git a/Keishiki/include/Graphics.h b/Keishiki/include/Graphics.h index 05dff3f..bc13323 100644 --- a/Keishiki/include/Graphics.h +++ b/Keishiki/include/Graphics.h @@ -7,11 +7,11 @@ namespace K::Graphics { enum VIEW_ID { - K_VIEW_COMP_COMPOSITE, K_VIEW_COMP_SAVE, - K_VIEW_DRAW, K_VIEW_UI, K_VIEW_LOGO, + + K_VIEW_COMP_COMPOSITE, // Remember to call setViewOrder! }; bool Init(u16 width, u16 height); @@ -120,7 +120,7 @@ namespace K::Graphics { "Invalid" }; - void Composite(bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]); + void Composite(u32 view_id, bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]); extern Graphics::ImageTexture *mmaker; } diff --git a/Keishiki/include/Keishiki.h b/Keishiki/include/Keishiki.h index 217bec2..4d446e1 100644 --- a/Keishiki/include/Keishiki.h +++ b/Keishiki/include/Keishiki.h @@ -34,4 +34,14 @@ namespace K { PlugboardGraph::PlugboardGraph plugboard; }; + + extern struct AppState { + SDL_Window *window = nullptr; + u16 window_width = 1920; + u16 window_height = 1080; + + u64 init_time{}, last_time{}, current_time{}, delta_t{}; + u32 bgfx_frame{}; + bool running = false; + } app_state; // global ! } diff --git a/Keishiki/include/VisualTrack.h b/Keishiki/include/VisualTrack.h index 354ce72..18acc31 100644 --- a/Keishiki/include/VisualTrack.h +++ b/Keishiki/include/VisualTrack.h @@ -37,7 +37,7 @@ namespace K { String shader; Dict uniforms; // Vector samplers; - bgfx::TextureHandle get_frame(const CompState& s, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], f32 view[16], f32 transform[16]) const; + void get_frame(const CompState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], f32 view[16], f32 transform[16]) const; void expose_uniform(CompState& s, const String& u); void hide_uniform(CompState& s, const String& u); diff --git a/Keishiki/shader.py b/Keishiki/shader.py index 9d65541..915ff7d 100644 --- a/Keishiki/shader.py +++ b/Keishiki/shader.py @@ -12,7 +12,7 @@ P = lambda location, platform, frag, vert: { 'location': location, 'platform': p plats = [ P('glsl', 'windows', '140', '140'), # P('dx11', 'windows', 's_5_0', 's_5_0'), - P('spirv', 'windows', 'spirv', 'spirv'), + P('spirv', 'linux', 'spirv', 'spirv'), P('metal', 'osx', 'metal', 'metal') ] diff --git a/Keishiki/shaders/BinaryComposite/BinaryComposite.frag b/Keishiki/shaders/BinaryComposite/BinaryComposite.frag index c0b8ea2..e2bc28e 100644 --- a/Keishiki/shaders/BinaryComposite/BinaryComposite.frag +++ b/Keishiki/shaders/BinaryComposite/BinaryComposite.frag @@ -1,146 +1,113 @@ +/* Reference: https://drafts.fxtf.org/compositing-1 */ + $input v_texcoord0 #include #include -uniform vec4 f_mode; -SAMPLER2D(v_A, 0); -SAMPLER2D(v_B, 1); +uniform vec4 u_mode; +SAMPLER2D(s_A, 0); +SAMPLER2D(s_B, 1); -void main() -{ +void main() { vec2 uv = vec2(v_texcoord0.x, 1.0f - v_texcoord0.y); - vec4 _A = texture2D(v_A, uv); - vec4 _B = texture2D(v_B, uv); + vec4 _A = texture2D(s_A, uv); + vec4 _B = texture2D(s_B, uv); + // Premult + _A.xyz = _A.xyz * _A.w; + _B.xyz = _B.xyz * _B.w; - if (f_mode.x == 0.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + // Porter-Duff Source Over + gl_FragColor.w = _A.w + _B.w * (1 - _A.w); + vec3 blend = vec3(0.0f, 0.0f, 0.0f); + + int mode = round(u_mode.x); + + if (mode == 0) { // Normal + blend = _A.xyz; } - else if (f_mode.x == 1.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 1) { // Dissolve + blend = _A.w > random(uv) ? _A.xyz : _B.xyz; } - else if (f_mode.x == 2.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 2) { // Add + blend = _A.xyz + _B.xyz; } - else if (f_mode.x == 3.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 3) { // Subtract + blend = _A.xyz - _B.xyz; } - else if (f_mode.x == 4.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 4) { // Difference + blend = abs(_A.xyz - _B.xyz); } - else if (f_mode.x == 5.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 5) { // Exclusion + blend = _B.xyz + _A.xyz - 2.0f * _B.xyz * _A.xyz; } - else if (f_mode.x == 6.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 6) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 7.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 7) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 8.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 8) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 9.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 9) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 10.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 10) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 11.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 11) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 12.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 12) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 13.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 13) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 14.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 14) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 15.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 15) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 16.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 16) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 17.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 17) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 18.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 18) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 19.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 19) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 20.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 20) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 21.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 21) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 22.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 22) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 23.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 23) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 24.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 24) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } - else if (f_mode.x == 25.0f) { - float alpha_b = _A.a * (1.0f - _B.a); - float alpha = _A.a + alpha_b; - gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha); + else if (mode == 25) { + gl_FragColor = vec4(50.0f, 0.0f, 0.0f, 1.0f); } + else { + gl_FragColor = vec4(uv, 0.0f, 1.0f); + } + + // Porter-Duff Source Over + gl_FragColor.xyz = blend + _B.xyz * (1.0f - _A.w); + + // Unmult + gl_FragColor.xyz = gl_FragColor.xyz / gl_FragColor.w; } diff --git a/TODO.md b/TODO.md index b3575aa..8a8f4e8 100644 --- a/TODO.md +++ b/TODO.md @@ -4,22 +4,23 @@ - Node groups ## Compositor -- Playback... - Manage Samplers -- (Resources in general) - Blender previews (important !) -- Data model for comps - Dump and read back state, (de)serialization!!! - Non-negotiables: - Text (idea: index-based evaluation in plugboard) - Shapes (idea: embed glisp :mmtroll:, need to inquire -- still a lot of friction for simple shapes if we don't also get the glisp gizmos) - External data driving (csv, json or something else?) -- use a node to select source -- Pre-compose/Layer Groups (jokes -- can be completely UI side) +- Data model for comps + - Pre-compose/Layer Groups (jokes -- can be completely UI side) - Motion blur ## UI - Viewport gizmos (Layer-specific & nodes -- can separate into different tools?) -- Not sure how to go about this - Node loop detection (separate DFS (extra work) or be smart in recursion) - detect time-sensitive nodes in tree and display on timeline +- Key selection in comp panel +- Graph editor # Later ## Compositor