summaryrefslogtreecommitdiff
path: root/tools/seq_compiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/seq_compiler.cc')
-rw-r--r--tools/seq_compiler.cc130
1 files changed, 130 insertions, 0 deletions
diff --git a/tools/seq_compiler.cc b/tools/seq_compiler.cc
new file mode 100644
index 0000000..8da4e4e
--- /dev/null
+++ b/tools/seq_compiler.cc
@@ -0,0 +1,130 @@
+// This file is part of the 64k demo project.
+// It implements the sequence compiler tool.
+// Converts a text-based timeline description into C++ code.
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+struct EffectEntry {
+ std::string class_name;
+ std::string start;
+ std::string end;
+ std::string priority;
+ std::string extra_args;
+};
+
+struct SequenceEntry {
+ std::string start_time;
+ std::string priority;
+ std::vector<EffectEntry> effects;
+};
+
+std::string trim(const std::string &str) {
+ size_t first = str.find_first_not_of(" ");
+ if (std::string::npos == first)
+ return str;
+ size_t last = str.find_last_not_of(" ");
+ return str.substr(first, (last - first + 1));
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " <input.seq> <output.cc>\n";
+ return 1;
+ }
+
+ std::ifstream in_file(argv[1]);
+ if (!in_file.is_open()) {
+ std::cerr << "Error: Could not open input file " << argv[1] << "\n";
+ return 1;
+ }
+
+ std::vector<SequenceEntry> sequences;
+ SequenceEntry *current_seq = nullptr;
+
+ std::string line;
+ int line_num = 0;
+ while (std::getline(in_file, line)) {
+ line_num++;
+ std::string trimmed = trim(line);
+ if (trimmed.empty() || trimmed[0] == '#')
+ continue;
+
+ std::stringstream ss(trimmed);
+ std::string command;
+ ss >> command;
+
+ if (command == "SEQUENCE") {
+ std::string start, priority;
+ if (!(ss >> start >> priority)) {
+ std::cerr << "Error line " << line_num
+ << ": SEQUENCE requires <start> <priority>\n";
+ return 1;
+ }
+ sequences.push_back({start, priority, {}});
+ current_seq = &sequences.back();
+ } else if (command == "EFFECT") {
+ if (!current_seq) {
+ std::cerr << "Error line " << line_num
+ << ": EFFECT found outside of SEQUENCE\n";
+ return 1;
+ }
+ std::string class_name, start, end, priority;
+ if (!(ss >> class_name >> start >> end >> priority)) {
+ std::cerr << "Error line " << line_num
+ << ": EFFECT requires <Class> <start> <end> <priority>\n";
+ return 1;
+ }
+
+ // Capture remaining args
+ std::string extra_args;
+ std::getline(ss, extra_args); // Read rest of line
+ // Remove leading whitespace from getline if any (getline reads the space after priority)
+ extra_args = trim(extra_args);
+ if (!extra_args.empty()) {
+ extra_args = ", " + extra_args;
+ }
+
+ current_seq->effects.push_back(
+ {class_name, start, end, priority, extra_args});
+ } else {
+ std::cerr << "Error line " << line_num << ": Unknown command '" << command
+ << "'\n";
+ return 1;
+ }
+ }
+
+ std::ofstream out_file(argv[2]);
+ if (!out_file.is_open()) {
+ std::cerr << "Error: Could not open output file " << argv[2] << "\n";
+ return 1;
+ }
+
+ out_file << "// Auto-generated by seq_compiler. Do not edit.\n";
+ out_file << "#include \"gpu/demo_effects.h\"\n";
+ out_file << "#include \"gpu/effect.h\"\n\n";
+ out_file << "void LoadTimeline(MainSequence& main_seq, WGPUDevice device, "
+ "WGPUQueue queue, WGPUTextureFormat format) {\n";
+
+ for (const auto &seq : sequences) {
+ out_file << " {\n";
+ out_file << " auto seq = std::make_shared<Sequence>();\n";
+ for (const auto &eff : seq.effects) {
+ out_file << " seq->add_effect(std::make_shared<" << eff.class_name
+ << ">(device, queue, format" << eff.extra_args << "), "
+ << eff.start << "f, " << eff.end << "f, " << eff.priority << ");\n";
+ }
+ out_file << " main_seq.add_sequence(seq, " << seq.start_time << "f, "
+ << seq.priority << ");\n";
+ out_file << " }\n";
+ }
+
+ out_file << "}\n";
+
+ std::cout << "Successfully generated timeline with " << sequences.size() << " sequences.\n";
+
+ return 0;
+}