1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
// 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";
std::cerr << "Example: " << argv[0]
<< " assets/demo.seq src/generated/timeline.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;
}
|