Browse Source

[BORKED] did stuff

main
Annwan 3 months ago
parent
commit
fcc022dfd6
  1. 84
      src/Application.cppm
  2. 117
      src/Node.cppm
  3. 18
      src/Nodes/InputNode.cpp
  4. 20
      src/Nodes/OutputNode.cpp
  5. 34
      src/Nodes/SplitterNode.cpp
  6. 2
      src/Nodes/StreamSpecConstantNode.cpp
  7. 18
      src/Port.cppm
  8. 5
      src/Ports/InputPort.cpp
  9. 10
      src/Ports/Label.cpp
  10. 13
      src/Ports/OutputPort.cpp

84
src/Application.cppm

@ -2,6 +2,7 @@ module;
#include "macros.hpp"
#include <algorithm>
#include <clopts.hh>
#include <cmath>
#include <deque>
#include <memory>
@ -16,6 +17,7 @@ export module Application;
import Node;
import Base;
import Button;
using command_line_options::detail::list;
namespace ffmpegraph {
export class Application {
public:
@ -60,11 +62,12 @@ Application::Application(std::string _title)
InitWindow(800, 600, this->title.c_str());
SetTargetFPS(60);
SetExitKey(KEY_NULL);
add_buttons.emplace_back(10, 10, 100, 20, "String Constant");
add_buttons.emplace_back(10, 35, 100, 20, "Input File");
add_buttons.emplace_back(10, 60, 100, 20, "Output File");
add_buttons.emplace_back(10, 85 , 100, 20, "Stream Spec Constant");
add_buttons.emplace_back(0, 0, 200, 20, "String Constant");
add_buttons.emplace_back(0, 0, 200, 20, "File Input");
add_buttons.emplace_back(0, 0, 200, 20, "File Output");
add_buttons.emplace_back(0, 0, 200, 20, "Stream Spec Constant");
add_buttons.emplace_back(0, 0, 200, 20, "Splitter");
AllOptions::each([&]<class T>() { add_buttons.emplace_back(0, 0, 200, 20, std::string(T::label_view)); });
run_button.width = 10 + MeasureText("Run", 10);
}
@ -83,19 +86,25 @@ void Application::ProcessEvents() {
void Application::OnLeftClick() {
if (current_state == State::ADDING) {
if (add_buttons[0].IsHovered()) {
nodes.push_back(std::make_unique<StringConstantNode>());
} else if (add_buttons[1].IsHovered()) {
nodes.push_back(std::make_unique<InputNode>());
} else if (add_buttons[2].IsHovered()) {
nodes.push_back(std::make_unique<OutputNode>());
} else if (add_buttons[3].IsHovered()) {
nodes.push_back(std::make_unique<StreamSpecConstantNode>());
}
usz i = 0;
current_state = State::DEFAULT;
list<StringConstantNode, InputNode, OutputNode, StreamSpecConstantNode, SplitterNode>::each([&]<class T>() {
if (add_buttons[i++].IsHovered()) {
nodes.push_back(std::make_unique<T>());
selected_node = nodes.back().get();
current_state = State::EDITING;
}
});
AllOptions::each([&]<class T>() {
if (add_buttons[i++].IsHovered()) {
nodes.push_back(std::make_unique<T>());
selected_node = nodes.back().get();
current_state = State::EDITING;
}
});
return;
}
auto GetPort = [&] -> Port * {
for (auto &node : nodes) {
for (auto *port : node->ports) {
@ -116,15 +125,13 @@ void Application::OnLeftClick() {
selected_port = nullptr;
current_state = State::DEFAULT;
} else if (run_button.IsHovered()) {
if (auto res = ExecuteGraph(); not res) {
message_queue.push_front(res.error());
}
if (auto res = ExecuteGraph(); not res) { message_queue.push_front(res.error()); }
} else {
i32 x = GetMouseX();
i32 y = GetMouseY();
auto port = GetPort();
auto oport = dynamic_cast<OutputPort *>(port);
if (oport) {
if (oport and oport->type != PortTypeE::GENERIC) {
if (oport->GetConnected()) {
oport->Disconnect();
} else {
@ -154,13 +161,20 @@ Result<> Application::ExecuteGraph() {
for (auto [i, node] : vws::enumerate(nodes)) {
Node *raw_node = node.get();
if (auto n = dynamic_cast<InputNode *>(raw_node)) {
if (auto c = n->output_port.GetConnected()) { adj_list[index_map[c->owner]].insert(index_map[raw_node]); }
if (auto c = n->out.GetConnected()) { adj_list[index_map[c->owner]].insert(index_map[raw_node]); }
}
if (auto n = dynamic_cast<StringConstantNode *>(raw_node)) {
if (auto c = n->out.GetConnected()) { adj_list[index_map[c->owner]].insert(index_map[raw_node]); }
}
if (auto _ = dynamic_cast<OutputNode *>(raw_node)) {}
// OutputNode doesn’t have output ports.
if (auto n = dynamic_cast<StreamSpecConstantNode *>(raw_node)) {
if (auto c = n->out.GetConnected()) { adj_list[index_map[c->owner]].insert(index_map[raw_node]); }
}
if (auto n = dynamic_cast<SplitterNode *>(raw_node)) {
if (auto c = n->out1.GetConnected()) { adj_list[index_map[c->owner]].insert(index_map[raw_node]); }
if (auto c = n->out2.GetConnected()) { adj_list[index_map[c->owner]].insert(index_map[raw_node]); }
}
}
// TODO add cases for all new types of nodes
@ -177,26 +191,20 @@ Result<> Application::ExecuteGraph() {
break;
}
}
if (not changed) {
return Error("Graph has cycle");
}
if (not changed) { return Error("Graph has cycle"); }
}
for (auto node : sorted_nodes) { Try(node->Run()); }
return{};
return {};
}
void Application::OnKeyPressed(i32 key) {
if ((key == KEY_EQUAL or key == KEY_KP_ADD) and current_state == State::DEFAULT) {
current_state = State::ADDING;
}
if ((key == KEY_EQUAL or key == KEY_KP_ADD) and current_state == State::DEFAULT) { current_state = State::ADDING; }
if (current_state != State::EDITING) return;
if (key == KEY_DELETE) {
for(auto& node : nodes) {
for (auto raw_port: node->ports) {
if (auto port = dynamic_cast<OutputPort*>(raw_port)) {
if (auto a = port->GetConnected(); a and a->owner == selected_node) {
port->Disconnect();
}
for (auto &node : nodes) {
for (auto raw_port : node->ports) {
if (auto port = dynamic_cast<OutputPort *>(raw_port)) {
if (auto a = port->GetConnected(); a and a->owner == selected_node) { port->Disconnect(); }
}
}
}
@ -257,8 +265,18 @@ void Application::Render() {
offset += 20;
}
if (current_state == State::ADDING) {
auto maxx = GetScreenWidth();
auto currentx = 10;
auto currenty = 10;
for (auto b : add_buttons) {
b.pos_x = currentx;
b.pos_y = currenty;
b.Render();
currentx += 210;
if (currentx + 200 > maxx) {
currentx = 10;
currenty += 25;
}
}
} else {
if (selected_port) { DrawLine(selected_port->pos_x, selected_port->pos_y, GetMouseX(), GetMouseY(), BLACK); }

117
src/Node.cppm

@ -1,5 +1,5 @@
module;
#include <print>
#include <clopts.hh>
#include <raylib.h>
#include <string>
#include <vector>
@ -7,6 +7,8 @@ export module Node;
export import :Port;
import Base;
using command_line_options::detail::list;
using command_line_options::detail::static_string;
export namespace ffmpegraph {
struct Node {
@ -27,14 +29,18 @@ struct Node {
std::vector<Port*> ports;
virtual Result<> Run() = 0;
virtual void OnDisconnect() {}
virtual void OnConnect() {}
protected:
i32 width = min_port_width;
};
struct InputNode : Node {
InputNode();
Label label;
InputPort filename_port;
OutputPort output_port;
InputPort prev;
InputPort opts;
InputPort filename;
OutputPort out;
Result<> Run() override;
};
@ -42,8 +48,9 @@ struct OutputNode : Node {
OutputNode();
Result<> Run() override;
Label label;
InputPort in_data;
InputPort in_filename;
InputPort prev;
InputPort opts;
InputPort filename;
};
struct StringConstantNode : Node {
@ -63,7 +70,105 @@ struct StreamSpecConstantNode : Node {
};
struct SplitterNode : Node {
SplitterNode();
Result<> Run() override;
void OnDisconnect() override;
void OnConnect() override;
Label label;
InputPort in;
OutputPort out1;
OutputPort out2;
};
template <static_string name, static_string ffmpegopt, PortTypeE arg_type, static_string arg_name = "Arg">
struct OptionNode : Node {
OptionNode()
: label(std::string(name.sv()), this)
, prev("Chain", this, PortTypeE::OPTIONS)
, arg(std::string(arg_name.sv()), this, arg_type)
, out("Out", this, PortTypeE::OPTIONS) {
ports.push_back(&label);
ports.push_back(&prev);
ports.push_back(&arg);
ports.push_back(&out);
}
Result<> Run() override {
out.SetValue(std::format("{} {} {}", prev.GetValue(), ffmpegopt.sv(), arg.GetValue()));
return {};
}
Label label;
InputPort prev;
InputPort arg;
OutputPort out;
static constexpr std::string_view label_view = name.sv();
};
template <static_string name, static_string ffmpegopt, PortTypeE arg_type, static_string arg_name = "Arg">
struct SpecOptionNode : Node {
SpecOptionNode()
: label(std::string(name.sv()), this)
, prev("Chain", this, PortTypeE::OPTIONS)
, spec("spec", this, PortTypeE::STREAM)
, arg(std::string(arg_name.sv()), this, arg_type)
, out("Out", this, PortTypeE::OPTIONS) {
ports.push_back(&label);
ports.push_back(&prev);
ports.push_back(&spec);
ports.push_back(&arg);
ports.push_back(&out);
}
Result<> Run() override {
out.SetValue(
std::format(
"{} {}{}{} {}", prev.GetValue(), ffmpegopt.sv(), std::get_if<Unit>(&spec.GetValue()) ? "" : ":",
spec.GetValue(), arg.GetValue()
)
);
return {};
}
Label label;
InputPort prev;
InputPort spec;
InputPort arg;
OutputPort out;
static constexpr std::string_view label_view = name.sv();
};
}
// General options
using ForceFormatOptionNode = OptionNode<"Force Format", "-f", PortTypeE::STRING>;
using StreamLoopOptionNode = OptionNode<"Loop Stream", "-stream_loop", PortTypeE::INT, "Count">;
using DurationOptionNode = OptionNode<"Duration", "-t", PortTypeE::DURATION>;
using PositionOptionNode = OptionNode<"Position", "-to", PortTypeE::DURATION>;
using SizeLimitOptionNode = OptionNode<"Size Limit", "-fs", PortTypeE::INT, "Bytes">;
using SeekStartOptionNode = OptionNode<"Seek from Start", "-ss", PortTypeE::DURATION>;
using SeekEndOptionNode = OptionNode<"Seek from End", "-sseof", PortTypeE::DURATION>;
using SyncToOptionNode = OptionNode<"Sync to Input", "-isync", PortTypeE::INT, "Input index">;
using InputTimeOffsetOptionNode = OptionNode<"Input Time Offset", "-itsoffset", PortTypeE::DURATION>;
using InputTimeScaleOptionNode = OptionNode<"Input Time Scale", "-itsscale", PortTypeE::DURATION>;
using TimestampOptionNode = OptionNode<"Output Timestamp", "-timestamp", PortTypeE::STRING>;
using TargetOptionNode = OptionNode<"Target", "-target", PortTypeE::STRING>;
using DiscardAllOptionNode = OptionNode<"Discard All", "-dn", PortTypeE::STRING, "IGNORED">;
using AttachOptionNode = OptionNode<"Attach", "-attach", PortTypeE::STRING, "Filename">;
using CodecOptionNode = SpecOptionNode<"Codec", "-c", PortTypeE::STRING>;
using DispositionOptionNode = SpecOptionNode<"Disposition", "-disposition", PortTypeE::STRING>;
using FrameLimitOptionNode = SpecOptionNode<"Frame Limit", "-frames", PortTypeE::INT, "Count">;
using QualityScaleOptionNode = SpecOptionNode<"Quality Scale", "-qscale", PortTypeE::STRING>;
using PresetOptionNode = SpecOptionNode<"Preset", "-pre", PortTypeE::STRING>;
using ExtractAttachment = SpecOptionNode<"Extract Attachment", "-dump_attachment", PortTypeE::STRING, "Filename">;
using AllOptions = list<
ForceFormatOptionNode, StreamLoopOptionNode, DurationOptionNode, PositionOptionNode, SizeLimitOptionNode,
SeekStartOptionNode, SeekEndOptionNode, SyncToOptionNode, InputTimeOffsetOptionNode, InputTimeScaleOptionNode,
TimestampOptionNode, TargetOptionNode, DiscardAllOptionNode, AttachOptionNode, CodecOptionNode,
DispositionOptionNode, FrameLimitOptionNode, QualityScaleOptionNode, PresetOptionNode, ExtractAttachment>;
// -program [title=title:][program_num=program_num:]st=stream[:st=stream...]
// -stream_group
// [map=input_file_id=stream_group][type=type:]st=stream[:st=stream][:stg=stream_group][:id=stream_group_id...]
// -filter[:stream_specifier] filtergraph
// -reinit_filter[:stream_specifier] integer
// -metadata[:metadata_specifier] key=value
} // namespace ffmpegraph

18
src/Nodes/InputNode.cpp

@ -5,17 +5,21 @@ module Node;
using namespace ffmpegraph;
InputNode::InputNode()
: label("Input File", this)
, filename_port("Filename", this, PortTypeE::STRING)
, output_port("Out", this, PortTypeE::STRING) {
: label("File Input", this)
, prev("Chain", this, PortTypeE::INPUTS)
, opts("Options", this, PortTypeE::OPTIONS)
, filename("Filename", this, PortTypeE::STRING)
, out("Out", this, PortTypeE::INPUTS) {
ports.push_back(&label);
ports.push_back(&filename_port);
ports.push_back(&output_port);
ports.push_back(&prev);
ports.push_back(&opts);
ports.push_back(&filename);
ports.push_back(&out);
}
Result<> InputNode::Run() {
auto data = std::get_if<std::string>(&filename_port.GetValue());
auto data = std::get_if<std::string>(&filename.GetValue());
if (not data or data->empty()) return Error("File Input needs a filename ");
output_port.SetValue(std::format("-i {}", *data));
out.SetValue(std::format("{} {} -i '{}'", prev.GetValue(), opts.GetValue(), *data));
return {};
}

20
src/Nodes/OutputNode.cpp

@ -1,20 +1,24 @@
module;
#include <string>
#include <variant>
module Node;
using namespace ffmpegraph;
OutputNode::OutputNode()
: label("File Output", this)
, in_data("Data", this, PortTypeE::STRING)
, in_filename("File", this, PortTypeE::STRING) {
, prev("Chain", this, PortTypeE::INPUTS)
, opts("Opts", this, PortTypeE::OPTIONS)
, filename("File", this, PortTypeE::STRING) {
ports.push_back(&label);
ports.push_back(&in_data);
ports.push_back(&in_filename);
ports.push_back(&prev);
ports.push_back(&opts);
ports.push_back(&filename);
}
Result<> OutputNode::Run() {
auto data = std::get_if<std::string>(&in_data.GetValue());
auto data = std::get_if<std::string>(&prev.GetValue());
if (not data) return {};
auto fname = std::get_if<std::string>(&in_filename.GetValue());
auto fname = std::get_if<std::string>(&filename.GetValue());
auto path = fname and not fname->empty() ? std::string_view{*fname} : "/tmp/ffmpegraph_out";
return Error("ffmpeg {} {}", *data, path);
}
return Error("ffmpeg -nostdin {} {} '{}'", *data, opts.GetValue(), path);
}

34
src/Nodes/SplitterNode.cpp

@ -0,0 +1,34 @@
module Node;
import Base;
using namespace ffmpegraph;
SplitterNode::SplitterNode()
: label("Splitter", this)
, in("Input", this, PortTypeE::GENERIC)
, out1("Output", this, PortTypeE::GENERIC)
, out2("Output", this, PortTypeE::GENERIC) {
ports.push_back(&label);
ports.push_back(&in);
ports.push_back(&out1);
ports.push_back(&out2);
}
Result<> SplitterNode::Run() {
out1.SetValue(in.GetValue());
out2.SetValue(in.GetValue());
return {};
}
void SplitterNode::OnConnect() {
out1.type = out2.type = in.type;
}
void SplitterNode::OnDisconnect() {
in.type = out1.type = out2.type = PortTypeE::GENERIC;
out1.Disconnect();
out2.Disconnect();
}

2
src/Nodes/StreamSpecConstantNode.cpp

@ -2,7 +2,7 @@ module Node;
using namespace ffmpegraph;
StreamSpecConstantNode::StreamSpecConstantNode()
: label("Stream Specifier Constant", this), in("Stream Specifier", this), out("Out", this, PortTypeE::STREAM_SPEC) {
: label("Stream Specifier Constant", this), in("Stream Specifier", this), out("Out", this, PortTypeE::STREAM) {
ports.push_back(&label);
ports.push_back(&in);
ports.push_back(&out);

18
src/Port.cppm

@ -12,7 +12,10 @@ enum struct PortTypeE {
GENERIC,
INT,
STRING,
STREAM_SPEC
STREAM,
OPTIONS,
INPUTS,
DURATION,
};
struct PortType {
@ -29,9 +32,12 @@ template <> struct std::formatter<ffmpegraph::PortType> : std::formatter<std::st
auto s = [data] -> string_view {
switch (data.t) {
case ffmpegraph::PortTypeE::INT: return "integer";
case ffmpegraph::PortTypeE::STREAM_SPEC: return "stream spec";
case ffmpegraph::PortTypeE::STREAM: return "stream";
case ffmpegraph::PortTypeE::STRING: return "string";
case ffmpegraph::PortTypeE::GENERIC: return "any";
case ffmpegraph::PortTypeE::OPTIONS: return "options";
case ffmpegraph::PortTypeE::INPUTS: return "inputs";
case ffmpegraph::PortTypeE::DURATION: return "duration";
default: return "unknown_type";
}
}();
@ -40,7 +46,7 @@ template <> struct std::formatter<ffmpegraph::PortType> : std::formatter<std::st
};
export namespace ffmpegraph {
constexpr i32 min_port_width = 100;
constexpr i32 min_port_width = 20;
using PortData = std::variant<i32, std::string, std::monostate>;
}
@ -48,7 +54,7 @@ template <> struct std::formatter<ffmpegraph::PortData> : std::formatter<std::st
template <class FormatContext> auto format(ffmpegraph::PortData const& data, FormatContext& ctx) const {
auto repr = std::visit(
utils::Overloaded{
[](std::monostate) { return "()"s; },
[](std::monostate) { return ""s; },
[](std::string const& x) { return x; },
[](i32 x) { return std::to_string(x); },
},
@ -75,18 +81,17 @@ struct OutputPort;
struct InputPort : Port {
protected:
PortType type;
PortData value = std::monostate{};
public:
InputPort(std::string name, Node* owner, PortType type) : Port(std::move(name), owner), type(type) {}
PortData const& GetValue() const;
PortType type;
i32 Render(i32 x, i32 y, i32 width) override;
friend OutputPort;
};
struct OutputPort : Port {
protected:
PortType type;
InputPort* connected = nullptr;
public:
OutputPort(std::string name, Node* owner, PortType type) : Port(std::move(name), owner), type(type) {}
@ -94,6 +99,7 @@ public:
bool TryConnect(InputPort& ip);
InputPort* GetConnected() const { return connected; }
void Disconnect();
PortType type;
i32 Render(i32 x, i32 y, i32 width) override;
};

5
src/Ports/InputPort.cpp

@ -14,8 +14,3 @@ i32 InputPort::Render(i32 x, i32 y, i32 width) {
DrawCircle(x, y + 10, 2.5f, BLACK);
return 10 + MeasureText(formatted.c_str(), 10);
}
i32 Label::Render(i32 x, i32 y, i32 width) {
DrawRectangleLines(x, y, width, 20, BLACK);
DrawText(name.c_str(), x + 5, y + 5, 10, BLACK);
return 10 + MeasureText(name.c_str(), 10);
}

10
src/Ports/Label.cpp

@ -0,0 +1,10 @@
module;
#include <raylib.h>
module Node;
using namespace ffmpegraph;
i32 Label::Render(i32 x, i32 y, i32 width) {
DrawRectangleLines(x, y, width, 20, BLACK);
DrawText(name.c_str(), x + 5, y + 5, 10, BLACK);
return 10 + MeasureText(name.c_str(), 10);
}

13
src/Ports/OutputPort.cpp

@ -1,6 +1,6 @@
module;
#include <raylib.h>
#include <format>
#include <raylib.h>
module Node;
using namespace ffmpegraph;
@ -8,16 +8,19 @@ void OutputPort::SetValue(PortData value) {
if (connected) { connected->value = std::move(value); }
}
bool OutputPort::TryConnect(InputPort& ip) {
if (ip.type == PortTypeE::GENERIC) {
ip.type = type;
ip.owner->OnConnect();
}
if (ip.type == type) {
connected = &ip;
return true;
}
return false;
}
void OutputPort::Disconnect() {
if (connected) {
connected->owner->OnDisconnect();
}
if (connected) { connected->owner->OnDisconnect(); }
connected = nullptr;
}
i32 OutputPort::Render(i32 x, i32 y, i32 width) {
@ -29,4 +32,4 @@ i32 OutputPort::Render(i32 x, i32 y, i32 width) {
if (type != PortTypeE::GENERIC) DrawCircle(x + width, y + 10, 2.5f, BLACK);
if (connected) { DrawLine(pos_x, pos_y, connected->pos_x, connected->pos_y, BLUE); }
return 10 + MeasureText(formatted.c_str(), 10);
}
}
Loading…
Cancel
Save