MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
argz.hpp
Go to the documentation of this file.
1
2/**
3 * @file argz.hpp
4 * @brief Lightweight, header-only, template command-line argument parser.
5 *
6 * Supports both short options (@c -x) and long options (@c --name), with or
7 * without values, for any string type that satisfies the StringType concept
8 * (typically @c std::string or @c std::wstring).
9 *
10 * Typical usage:
11 * @code
12 * Argz<std::string> parser(argc, argv);
13 * parser.addOptionSingle('h', "Show help")
14 * .addOptionSingleValue('o', "Output file");
15 * Argument<std::string> arg;
16 * int code;
17 * while ((code = parser.proc(arg)) != -1) { ... }
18 * @endcode
19 *
20 * A convenience wrapper proc_args() provides a pre-built parser that handles
21 * the options common to all libmx2 applications (-p path, -r resolution, -f fullscreen, …).
22 */
23
24#pragma once
25
27#include <algorithm>
28#include <cctype>
29#include <charconv>
30#include <cmath>
31#include <cstddef>
32#include <cstdio>
33#include <cstdlib>
34#include <filesystem>
35#include <iomanip>
36#include <iostream>
37#include <iterator>
38#include <ranges>
39#include <string>
40#include <string_view>
41#include <system_error>
42#include <type_traits>
43#include <unordered_map>
44#include <utility>
45#include <vector>
46
47#if defined(_WIN32)
48#include <io.h>
49#ifndef NOMINMAX
50#define NOMINMAX
51#endif
52#include <windows.h>
53#else
54#include <unistd.h>
55#endif
56
57/**
58 * @concept StringType
59 * @brief Models a string-like class with indexing, concatenation, length, and value_type.
60 *
61 * Both @c std::string and @c std::wstring satisfy this concept.
62 * @tparam T The type to constrain.
63 */
64template <typename T>
65concept StringType = std::is_class_v<T> && requires(T type) {
66 type.length();
67 type[0];
68 type += type;
69 type = type;
70 typename T::value_type;
71 typename T::size_type;
72 { type.length() } -> std::same_as<typename T::size_type>;
73 { type[0] } -> std::same_as<typename T::value_type &>;
74 { type += T{} } -> std::same_as<T &>;
75 { type = T{} } -> std::same_as<T &>;
76};
77
78[[nodiscard]] inline std::string executable_directory(const char *executable) {
79#if defined(_WIN32)
80 std::vector<char> buffer(32768);
81 const DWORD length = GetModuleFileNameA(nullptr, buffer.data(), static_cast<DWORD>(buffer.size()));
82 if (length > 0 && length < buffer.size()) {
83 return std::filesystem::path(std::string(buffer.data(), length)).parent_path().lexically_normal().string();
84 }
85#elif defined(__linux__)
86 std::vector<char> buffer(4096);
87 const ssize_t length = readlink("/proc/self/exe", buffer.data(), buffer.size());
88 if (length > 0 && static_cast<std::size_t>(length) < buffer.size()) {
89 return std::filesystem::path(std::string(buffer.data(), static_cast<std::size_t>(length))).parent_path().lexically_normal().string();
90 }
91#endif
92
93 std::error_code error;
94 const std::filesystem::path absolute_path = std::filesystem::absolute(executable == nullptr ? "." : executable, error);
95 if (!error && absolute_path.has_parent_path()) {
96 return absolute_path.parent_path().lexically_normal().string();
97 }
98 return ".";
99}
100
101/** @brief Discriminator for option kind used inside Argument. */
103
104/**
105 * @struct Argument
106 * @brief Describes a single parsed argument entry returned by Argz::proc().
107 * @tparam String String type satisfying StringType.
108 *
109 * After a successful call to Argz::proc() the member @c arg_letter holds the
110 * matched code (or @c '-' for bare positional arguments) and @c arg_value holds
111 * any associated value string.
112 */
113template <StringType String> struct Argument {
114 String arg_name; ///< Long option name (e.g. @c "output").
115 int arg_letter; ///< Short option code (e.g. @c 'o') or unique integer for long-only options.
116 String arg_value; ///< Value string supplied after the option, if any.
117 ArgType arg_type; ///< Which @c ArgType variant this argument represents.
118 String desc; ///< Human-readable description used in help output.
119 ~Argument() = default;
123 arg_name = a.arg_name;
126 arg_type = a.arg_type;
127 desc = a.desc;
128 return *this;
129 }
130 auto operator<=>(const Argument<String> &a) const { return (arg_letter <=> a.arg_letter); }
131 bool operator==(const Argument<String> &a) const { return arg_letter == a.arg_letter; }
132};
133
134/**
135 * @struct ArgumentData
136 * @brief Holds the raw @c argv strings converted to the target @c String type.
137 * @tparam String String type satisfying StringType.
138 */
139template <StringType String> struct ArgumentData {
140 std::vector<String> args; ///< Converted argv entries (argv[1] … argv[argc-1]).
141 int argc; ///< Original argc value.
142 ~ArgumentData() = default;
143 ArgumentData() = default;
146 if (this == &a) {
147 return *this;
148 }
149 args = a.args;
150 argc = a.argc;
151 return *this;
152 }
155 if (this == &a) {
156 return *this;
157 }
158 args = std::move(a.args);
159 argc = a.argc;
160 return *this;
161 }
162};
163
164/**
165 * @class ArgException
166 * @brief Exception thrown by Argz::proc() on unrecognised or malformed options.
167 * @tparam String String type satisfying StringType.
168 */
169template <StringType String> class ArgException {
170 public:
171 ArgException() = default;
172 ArgException(const String &s) : value{s} {}
173 String text() const { return value; }
174
175 private:
176 String value;
177};
178
179/**
180 * @class Argz
181 * @brief Template command-line argument parser.
182 * @tparam String String type satisfying StringType (usually @c std::string or @c std::wstring).
183 *
184 * Options are registered with addOption*() before parsing.
185 * Call proc() in a loop until it returns @c -1 to iterate over all arguments.
186 */
187template <StringType String> class Argz {
188 public:
189 ~Argz() = default;
190 Argz() = default;
191
192 /**
193 * @brief Construct and immediately ingest argv.
194 * @param argc Argument count from main().
195 * @param argv Argument vector from main().
196 */
197 Argz(int argc, char **argv) { initArgs(argc, argv); }
198 Argz(const Argz<String> &a) : arg_data{a.arg_data}, arg_info{a.arg_info}, index{a.index}, cindex{a.cindex} {}
199
201 if (this == &a) {
202 return *this;
203 }
204 arg_data = a.arg_data;
205 arg_info = a.arg_info;
206 index = a.index;
207 cindex = a.cindex;
208 return *this;
209 }
210
211 Argz(Argz<String> &&a) : arg_data{std::move(a.arg_data)}, arg_info{std::move(a.arg_info)}, index{a.index}, cindex{a.cindex} {}
212
214 if (this == &a) {
215 return *this;
216 }
217 arg_data = std::move(a.arg_data);
218 arg_info = std::move(a.arg_info);
219 index = a.index;
220 cindex = a.cindex;
221 return *this;
222 }
223
224 /**
225 * @brief Ingest argc/argv, converting to the target String type.
226 * @param argc Argument count.
227 * @param argv Argument vector.
228 * @return Reference to @c *this for method chaining.
229 */
230 Argz<String> &initArgs(int argc, char **argv) {
231 arg_data.argc = argc;
232 arg_data.args.clear();
233 if (argc > 1) {
234 arg_data.args.reserve(static_cast<size_t>(argc - 1));
235 }
236 if constexpr (std::is_same<typename String::value_type, char>::value) {
237 for (int i = 1; i < argc; ++i) {
238 const char *a = (argv != nullptr) ? argv[i] : nullptr;
239 arg_data.args.emplace_back(a != nullptr ? a : "");
240 }
241 reset();
242 return *this;
243 }
244 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
245 for (int i = 1; i < argc; ++i) {
246 const char *a = (argv != nullptr) ? argv[i] : nullptr;
247 String data;
248 if (a != nullptr) {
249 for (size_t z = 0; a[z] != 0; ++z) {
250 data += static_cast<typename String::value_type>(a[z]);
251 }
252 }
253 arg_data.args.push_back(data);
254 }
255 reset();
256 return *this;
257 }
258 reset();
259 return *this;
260 }
261
262 /** @brief Reset the internal parse cursor to the beginning of argv. */
263 void reset() {
264 index = 0;
265 cindex = 1;
266 }
267
268 /**
269 * @brief Register a flag-only short option (e.g. @c -v, @c -h).
270 * @param c Short option character code.
271 * @param description Help text.
272 * @return Reference to @c *this for chaining.
273 */
274 Argz<String> &addOptionSingle(const int &c, const String &description) {
276 a.arg_letter = c;
278 a.desc = description;
279 arg_info[c] = a;
280 return *this;
281 }
282
283 /**
284 * @brief Register a short option that requires a value argument (e.g. @c -o file).
285 * @param c Short option character code.
286 * @param description Help text.
287 * @return Reference to @c *this for chaining.
288 */
289 Argz<String> &addOptionSingleValue(const int &c, const String &description) {
291 a.arg_letter = c;
293 a.desc = description;
294 arg_info[c] = a;
295 return *this;
296 }
297
298 /**
299 * @brief Register a flag-only long option (e.g. @c --verbose).
300 * @param code Unique integer code associated with this option.
301 * @param value Long option name string (without @c --).
302 * @param description Help text.
303 * @return Reference to @c *this for chaining.
304 */
305 Argz<String> &addOptionDouble(const int &code, const String &value, const String &description) {
307 a.arg_letter = code;
309 a.desc = description;
310 a.arg_name = value;
311 arg_info[code] = a;
312 return *this;
313 }
314
315 /**
316 * @brief Register a long option that requires a value argument (e.g. @c --output file).
317 * @param code Unique integer code.
318 * @param value Long option name string.
319 * @param description Help text.
320 * @return Reference to @c *this for chaining.
321 */
322 Argz<String> &addOptionDoubleValue(const int &code, const String &value, const String &description) {
324 a.arg_letter = code;
326 a.desc = description;
327 a.arg_name = value;
328 arg_info[code] = a;
329 return *this;
330 }
331
332 /**
333 * @brief Look up the integer code registered for a long option name.
334 * @param value Long option name (without @c --).
335 * @return The registered code, or @c -1 if not found.
336 */
337 int lookUpCode(const String &value) const {
338 for (const auto &i : arg_info) {
339 if (i.second.arg_name == value) {
340 return i.second.arg_letter;
341 }
342 }
343 return -1;
344 }
345
346 /**
347 * @brief Advance the cursor and parse the next argument.
348 * @param a Output: filled with the matched option details.
349 * @return The option code on success; @c '-' for a positional argument; @c -1 when exhausted.
350 * @throws ArgException<String> On unrecognised options or missing values.
351 */
353 if (index < static_cast<int>(arg_data.args.size())) {
354 const String &type{arg_data.args[index]};
355 if (type.length() > 2 && type[0] == '-' && type[1] == '-') {
356 String name{};
357 String inline_value{};
358 const auto eq_pos = type.find(static_cast<typename String::value_type>('='));
359 const bool has_inline_value = (eq_pos != String::npos);
360 for (size_t z = 2; z < type.length(); ++z)
361 if (!has_inline_value || z < eq_pos) {
362 name += type[z];
363 } else if (z > eq_pos) {
364 inline_value += type[z];
365 }
366 int code = lookUpCode(name);
367 if (code != -1) {
368 auto pos = arg_info.find(code);
369 if (pos != arg_info.end()) {
370 if (pos->second.arg_type == ArgType::ARG_DOUBLE) {
371 if (has_inline_value) {
372 if constexpr (std::is_same<typename String::value_type, char>::value) {
373 throw ArgException<String>("Invalid switch not found!");
374 }
375 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
376 throw ArgException<String>(L"Invalid switch not found!");
377 }
378 }
379 a = pos->second;
380 a.arg_name = name;
381 index++;
382 return code;
383 } else {
384 a = pos->second;
385 a.arg_name = name;
386 if (has_inline_value) {
387 if (inline_value.empty()) {
388 if constexpr (std::is_same<typename String::value_type, char>::value) {
389 throw ArgException<String>("Expected Value");
390 }
391 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
392 throw ArgException<String>(L"Expected Value");
393 }
394 }
395 a.arg_value = inline_value;
396 index++;
397 return code;
398 }
399 if (++index < static_cast<int>(arg_data.args.size())) {
400 const String &s{arg_data.args[index]};
401 if (canUseAsOptionValue(s)) {
402 a.arg_name = name;
403 a.arg_value = s;
404 index++;
405 return code;
406 }
407 }
408 if constexpr (std::is_same<typename String::value_type, char>::value) {
409 throw ArgException<String>("Expected Value");
410 }
411 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
412 throw ArgException<String>(L"Expected Value");
413 }
414 }
415 }
416 } else {
417 throwUnknownOption(type);
418 }
419 } else if (type.length() == 1 && type[0] == '-') {
420 if constexpr (std::is_same<typename String::value_type, char>::value) {
421 throw ArgException<String>("Expected Value found -");
422 }
423 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
424 throw ArgException<String>(L"Expected Value found -");
425 }
426 } else if (type.length() > 1 && (type[0] == '-')) {
427 const int c{type[cindex]};
428 const auto pos{arg_info.find(c)};
429 cindex++;
430 if (cindex >= static_cast<int>(type.length())) {
431 cindex = 1;
432 index++;
433 }
434 String name_val{};
435 name_val += static_cast<typename String::value_type>(c);
436 if (pos != arg_info.end()) {
437 if (pos->second.arg_type == ArgType::ARG_SINGLE) {
438 a = pos->second;
439 a.arg_name = name_val;
440 return c;
441 } else if (pos->second.arg_type == ArgType::ARG_SINGLE_VALUE) {
442 if (index < static_cast<int>(arg_data.args.size())) {
443 const String &s{arg_data.args[index]};
444 if (!canUseAsOptionValue(s)) {
445 if constexpr (std::is_same<typename String::value_type, char>::value) {
446 throw ArgException<String>("Expected Value found -");
447 }
448 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
449 throw ArgException<String>(L"Expected Value found -");
450 }
451 }
452 if (s.length() > 0) {
453 a = pos->second;
454 a.arg_value = s;
455 a.arg_name = name_val;
456 index++;
457 return c;
458 }
459 } else {
460 if constexpr (std::is_same<typename String::value_type, char>::value) {
461 throw ArgException<String>("Expected Value");
462 }
463 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
464 throw ArgException<String>(L"Expected Value");
465 }
466 }
467 } else {
468 if constexpr (std::is_same<typename String::value_type, char>::value) {
469 throw ArgException<String>("Invalid switch not found!");
470 }
471 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
472 throw ArgException<String>(L"Invalid switch not found!");
473 }
474 }
475 } else {
476 throwUnknownOption(type);
477 }
478 } else {
479 a = Argument<String>();
480 a.arg_name = String{};
482 a.arg_name = a.arg_value = arg_data.args.at(index);
483 index++;
484 return '-';
485 }
486 }
487 return -1;
488 }
489
490 /**
491 * @brief Print all registered options to any ostream-like object.
492 * @tparam T Output stream type (e.g. @c std::ostream, @c std::wostream).
493 * @param cout Destination stream.
494 */
495 template <typename T> void help(T &cout) {
496 using char_type = typename std::decay<decltype(*std::declval<T>().rdbuf())>::type::char_type;
497 const bool use_color = supportsColor(cout);
498 auto write_ansi = [&](const char *seq) {
499 if (!use_color) {
500 return;
501 }
502 if constexpr (std::is_same_v<char_type, char>) {
503 cout << seq;
504 } else if constexpr (std::is_same_v<char_type, wchar_t>) {
505 for (const char *p = seq; *p != '\0'; ++p) {
506 cout << static_cast<char_type>(*p);
507 }
508 }
509 };
510 auto write_padding = [&](size_t count) {
511 for (size_t i = 0; i < count; ++i) {
512 cout << static_cast<char_type>(' ');
513 }
514 };
515 struct HelpRow {
516 String token;
517 String desc;
518 bool is_short;
519 };
520 std::vector<Argument<String>> v;
521 std::vector<Argument<String>> v2;
522 for (const auto &i : arg_info) {
523 if (i.second.arg_type == ArgType::ARG_SINGLE || i.second.arg_type == ArgType::ARG_SINGLE_VALUE)
524 v.push_back(i.second);
525 else if (i.second.arg_type == ArgType::ARG_DOUBLE || i.second.arg_type == ArgType::ARG_DOUBLE_VALUE)
526 v2.push_back(i.second);
527 }
528 std::ranges::sort(v);
529 std::ranges::sort(v2);
530 std::vector<HelpRow> rows;
531 rows.reserve(v.size() + v2.size());
532 for (const auto &a : v) {
533 String token;
534 token += static_cast<char_type>('-');
535 token += static_cast<char_type>(a.arg_letter);
536 rows.push_back(HelpRow{std::move(token), a.desc, true});
537 }
538 for (const auto &a : v2) {
539 String token;
540 token += static_cast<char_type>('-');
541 token += static_cast<char_type>('-');
542 token += a.arg_name;
543 rows.push_back(HelpRow{std::move(token), a.desc, false});
544 }
545 size_t token_width = 0;
546 for (const auto &row : rows) {
547 token_width = std::max(token_width, static_cast<size_t>(row.token.length()));
548 }
549 const size_t desc_column = token_width + 2;
550 for (const auto &row : rows) {
551 write_ansi(row.is_short ? "\x1b[1;36m" : "\x1b[1;35m");
552 cout << row.token;
553 write_ansi("\x1b[0m");
554 if (desc_column > row.token.length()) {
555 write_padding(desc_column - row.token.length());
556 } else {
557 write_padding(2);
558 }
559 write_ansi("\x1b[90m");
560 cout << row.desc;
561 write_ansi("\x1b[0m");
562 cout << '\n';
563 }
564 }
565 /** @return Number of argv entries consumed so far. */
566 const size_t count() const { return index; }
567
568 protected:
570 std::unordered_map<int, Argument<String>> arg_info;
571
572 private:
573 template <typename Stream> static bool supportsColor(const Stream &stream) {
574 if constexpr (std::is_same_v<Stream, std::ostream>) {
575 if (&stream != &std::cout) {
576 return false;
577 }
578#if defined(_WIN32)
579 return _isatty(_fileno(stdout));
580#else
581 return isatty(fileno(stdout));
582#endif
583 } else if constexpr (std::is_same_v<Stream, std::wostream>) {
584 if (&stream != &std::wcout) {
585 return false;
586 }
587#if defined(_WIN32)
588 return _isatty(_fileno(stdout));
589#else
590 return isatty(fileno(stdout));
591#endif
592 } else {
593 return false;
594 }
595 }
596
597 [[noreturn]] void throwUnknownOption(const String &token) const {
598 if constexpr (std::is_same<typename String::value_type, char>::value) {
599 String value = "Error argument: ";
600 value += token;
601 value += " switch not found";
602 throw ArgException<String>(value);
603 }
604 if constexpr (std::is_same<typename String::value_type, wchar_t>::value) {
605 String value = L"Error argument: ";
606 value += token;
607 value += L" switch not found";
608 throw ArgException<String>(value);
609 }
610 }
611
612 bool isSignedNumericToken(const String &s) const {
613 if (s.empty()) {
614 return false;
615 }
616
617 const auto ch_minus = static_cast<typename String::value_type>('-');
618 const auto ch_plus = static_cast<typename String::value_type>('+');
619 const auto ch_dot = static_cast<typename String::value_type>('.');
620 const auto ch_e = static_cast<typename String::value_type>('e');
621 const auto ch_E = static_cast<typename String::value_type>('E');
622 const auto ch_0 = static_cast<typename String::value_type>('0');
623 const auto ch_9 = static_cast<typename String::value_type>('9');
624
625 size_t i = 0;
626 if (s[i] == ch_minus || s[i] == ch_plus) {
627 ++i;
628 }
629 if (i >= s.length()) {
630 return false;
631 }
632
633 bool has_digit = false;
634 bool has_dot = false;
635 for (; i < s.length(); ++i) {
636 const auto ch = s[i];
637 if (ch >= ch_0 && ch <= ch_9) {
638 has_digit = true;
639 continue;
640 }
641 if (ch == ch_dot && !has_dot) {
642 has_dot = true;
643 continue;
644 }
645 if ((ch == ch_e || ch == ch_E) && has_digit) {
646 size_t j = i + 1;
647 if (j < s.length() && (s[j] == ch_minus || s[j] == ch_plus)) {
648 ++j;
649 }
650 if (j >= s.length()) {
651 return false;
652 }
653 bool exp_digit = false;
654 for (; j < s.length(); ++j) {
655 if (s[j] >= ch_0 && s[j] <= ch_9) {
656 exp_digit = true;
657 } else {
658 return false;
659 }
660 }
661 return exp_digit;
662 }
663 return false;
664 }
665 return has_digit;
666 }
667
668 bool isRecognizedOptionToken(const String &s) const {
669 if (s.length() <= 1 || s[0] != static_cast<typename String::value_type>('-')) {
670 return false;
671 }
672
673 if (s.length() > 2 && s[1] == static_cast<typename String::value_type>('-')) {
674 String name{};
675 for (size_t z = 2; z < s.length(); ++z) {
676 name += s[z];
677 }
678 return lookUpCode(name) != -1;
679 }
680
681 for (size_t z = 1; z < s.length(); ++z) {
682 if (arg_info.find(static_cast<int>(s[z])) == arg_info.end()) {
683 return false;
684 }
685 }
686 return true;
687 }
688
689 bool canUseAsOptionValue(const String &s) const {
690 if (s.empty()) {
691 return false;
692 }
693 if (s[0] != static_cast<typename String::value_type>('-')) {
694 return true;
695 }
696 if (isSignedNumericToken(s)) {
697 return true;
698 }
699 return !isRecognizedOptionToken(s);
700 }
701
702 int index = 0, cindex = 1;
703};
704
705/**
706 * @struct FramebufferDimensions
707 * @brief Parsed software framebuffer dimensions.
708 */
710 int width = 1280; ///< Software framebuffer width in pixels.
711 int height = 720; ///< Software framebuffer height in pixels.
712};
713
714/**
715 * @struct Arguments
716 * @brief Plain data structure returned by proc_args() with all common libmx2 CLI options.
717 */
718struct Arguments {
719 std::string executable_name = "mxvk"; ///< Executable basename derived from argv[0].
720 int width = 1280; ///< Viewport width in pixels (default: 1280).
721 int height = 720; ///< Viewport height in pixels (default: 720).
722 bool resolutionSpecified = false; ///< Whether -r/--resolution was provided.
723 std::string path = "."; ///< Asset root; proc_args() defaults it to the executable directory.
724 bool fullscreen = false; ///< Whether fullscreen mode was requested.
725 bool fast = false; ///< Whether fast mode was requested (@c --fast).
726 std::string filename; ///< Optional input filename (@c --filename).
727 std::string model; ///< Optional model filename (@c --model).
728 std::string output; ///< Optional output filename (@c --output).
729 std::string crf; ///< Optional CRF value (@c --crf).
730 std::string encodePreset; ///< Optional encoder preset (@c --encode-preset).
731 std::string encodeTune; ///< Optional encoder tune (@c --encode-tune).
732 std::string encodeCodec; ///< Optional encoder codec policy/name (@c --encode-codec).
733 bool encodeRealtime = false; ///< Enable low-latency encoder settings (@c --encode-realtime).
734 bool mxwriteBlockWhenFull = false; ///< Make MXWrite block instead of dropping frames (@c --mxwrite-block).
735 bool repeat = false; ///< Enable repeat behavior such as playback looping or wrapped textures.
736 bool binary = false; ///< Use binary glyphs only (@c --binary).
737 bool enable_crt = false; ///< Enable CRT post-processing at startup (@c --enable-crt).
738 bool enable_vsync = false; ///< Enable FIFO present mode / v-sync (@c --enable-vsync).
739 bool enable_screenshot = false; ///< Enable F10 screenshot capture (@c --enable-screenshot).
740 bool disable_sound = false; ///< Disable application background music (@c --disable-sound).
741 bool benchmark = false; ///< Enable application benchmark mode (@c --benchmark).
742 bool wireframe = false; ///< Render supported 3D models as wireframes (@c --wireframe).
743 bool nowarpfix = false; ///< Disable perspective-correct texture mapping (@c --nowarpfix).
744 bool disable_mipmap = false; ///< Disable mipmap generation and selection (@c --disable-mipmap).
745 float mip_bias = 0.0f; ///< Mipmap level-of-detail bias requested by @c --mip-bias.
746 FramebufferDimensions framebuffer; ///< Software framebuffer size requested by @c --framebuffer.
747 bool framebufferSpecified = false; ///< Whether @c --framebuffer was provided.
748 double fps = 0.0; ///< Optional FPS override (@c --fps); non-positive means unspecified.
749 int font_size = 22; ///< Matrix rain font size in pixels (@c --font-size).
750 std::string font_path; ///< Optional font file path (@c --font-path).
751 std::string color; ///< Optional rain RGB tint (@c --color).
752 std::string texture; ///< Optional texture file path (@c --texture).
753 std::string shaderPath; ///< Optional SPV shader folder path (@c -S / @c --shader-path).
754 std::string fragmentPath; ///< Optional fragment shader SPV path (@c --fragment).
755 int camera_index = 0; ///< Optional camera index
756 int index = 0; ///< Optional acidcam filter mode index.
757 int shader_index = 0; ///< Optional initial shader entry index.
758 std::string resource; ///< Resource file
759 std::string resource_path; ///< Resource path
760};
761
762[[nodiscard]] inline int parse_arg_int(const std::string &text, const std::string &option_name) {
763 int value = 0;
764 const char *begin = text.data();
765 const char *end = begin + text.size();
766 const std::from_chars_result result = std::from_chars(begin, end, value);
767 if (result.ec != std::errc{} || result.ptr != end) {
768 throw ArgException<std::string>("Invalid numeric value for " + option_name + ": " + text);
769 }
770 return value;
771}
772
773[[nodiscard]] inline double parse_arg_double(const std::string &text, const std::string &option_name) {
774 double value = 0.0;
775 const char *begin = text.data();
776 const char *end = begin + text.size();
777 const std::from_chars_result result = std::from_chars(begin, end, value);
778 if (result.ec != std::errc{} || result.ptr != end || !std::isfinite(value)) {
779 throw ArgException<std::string>("Invalid numeric value for " + option_name + ": " + text);
780 }
781 return value;
782}
783
784[[nodiscard]] inline std::string parse_executable_name(const char *argv0) {
785 if (argv0 == nullptr || argv0[0] == '\0') {
786 return "mxvk";
787 }
788
789 std::string name = argv0;
790 const std::string::size_type separator = name.find_last_of("/\\");
791 if (separator != std::string::npos) {
792 name.erase(0, separator + 1);
793 }
794
795 constexpr std::string_view exe_extension = ".exe";
796 if (name.size() >= exe_extension.size()) {
797 const std::string::size_type extension_pos = name.size() - exe_extension.size();
798 const bool has_exe_extension = std::ranges::equal(name.begin() + static_cast<std::ptrdiff_t>(extension_pos), name.end(), exe_extension.begin(), exe_extension.end(), [](char left, char right) { return std::tolower(static_cast<unsigned char>(left)) == std::tolower(static_cast<unsigned char>(right)); });
799 if (has_exe_extension) {
800 name.erase(extension_pos);
801 }
802 }
803
804 return name.empty() ? "mxvk" : name;
805}
806
807/**
808 * @brief Parse standard libmx2 command-line options from main()'s argv.
809 *
810 * Registers and processes the following options:
811 * | Flag | Long form | Description |
812 * |------|--------------------|----------------------------------------------|
813 * | -h | | Print help and exit |
814 * | -p | --path | Asset directory path |
815 * | -r | --resolution | Resolution as WxH (e.g. 1920x1080) |
816 * | -f | --fullscreen | Enable fullscreen |
817 * | | --fast | Enable fast mode |
818 * | | --filename | Input filename |
819 * | | --model | Model filename |
820 * | -o | --output | Output filename |
821 * | -c | --crf | Constant Rate Factor |
822 * | | --encode-preset | Encoder preset |
823 * | | --encode-tune | Encoder tune |
824 * | | --encode-codec | Encoder codec policy or name |
825 * | | --encode-realtime | Enable realtime/low-latency encoding |
826 * | | --mxwrite-block | Block MXWrite when its queue is full |
827 * | | --repeat | Enable playback or texture repetition |
828 * | | --binary | Use binary glyphs only |
829 * | | --enable-crt | Enable CRT post-processing at startup |
830 * | | --enable-vsync | Enable FIFO present mode / v-sync |
831 * | | --enable-screenshot| Enable F10 screenshot capture |
832 * | | --disable-sound | Disable application background music |
833 * | | --benchmark | Enable application benchmark mode |
834 * | | --wireframe | Render supported 3D models as wireframes |
835 * | | --nowarpfix | Disable perspective-correct texture mapping |
836 * | | --disable-mipmap | Disable mipmap generation and selection |
837 * | | --mip-bias | Mipmap level-of-detail bias |
838 * | | --framebuffer | Software framebuffer size as WxH |
839 * | | --fps | Override capture FPS |
840 * | -z | --font-size | Matrix rain font size |
841 * | -j | --font-path | Matrix rain font file path |
842 * | -C | --color | Matrix rain RGB tint (\#RRGGBB or R,G,B) |
843 * | | --texture | Texture file |
844 * | | --textures | Texture file alias |
845 * | -S | --shader-path | SPV shader folder (must contain index.txt) |
846 * | | --fragment | Fragment shader SPV path |
847 * | -i | --index | Acidcam filter mode index |
848 * | | --shader-index | Initial shader entry index |
849 *
850 * @param argc Reference to argc from main().
851 * @param argv argv from main().
852 * @return Populated Arguments struct; on parse error, returns a default-valued struct.
853 */
854inline Arguments proc_args(int &argc, char **argv) {
855 Arguments args;
856 const std::string executable_name = parse_executable_name(argc > 0 ? argv[0] : nullptr);
857 Argz<std::string> parser(argc, argv);
858 parser.addOptionSingle('h', "Display help message")
859 .addOptionSingle('v', "Print version")
860 .addOptionSingleValue('p', "assets path")
861 .addOptionDoubleValue('P', "path", "assets path")
862 .addOptionSingleValue('r', "Resolution WidthxHeight")
863 .addOptionDoubleValue('R', "resolution", "Resolution WidthxHeight")
864 .addOptionSingle('f', "fullscreen")
865 .addOptionDouble('F', "fullscreen", "fullscreen")
866 .addOptionDouble(301, "fast", "fast")
867 .addOptionDoubleValue(256, "filename", "input filename")
868 .addOptionDoubleValue(324, "model", "model filename (.obj, .mxmod, or .mxmod.z)")
869 .addOptionSingleValue('o', "output filename")
870 .addOptionDoubleValue(304, "output", "output filename")
871 .addOptionSingleValue('c', "crf value")
872 .addOptionDoubleValue(305, "crf", "crf value")
873 .addOptionDoubleValue(306, "encode-preset", "encoder preset")
874 .addOptionDoubleValue(307, "encode-tune", "encoder tune")
875 .addOptionDoubleValue(308, "encode-codec", "encoder codec policy or name")
876 .addOptionDouble(309, "encode-realtime", "encoder realtime mode")
877 .addOptionDouble(314, "mxwrite-block", "block MXWrite when its queue is full")
878 .addOptionDouble(310, "repeat", "repeat playback or wrapped textures")
879 .addOptionDouble(315, "binary", "use binary glyphs only")
880 .addOptionDouble(319, "enable-crt", "enable CRT post-processing at startup")
881 .addOptionDouble(320, "enable-vsync", "enable FIFO present mode / v-sync")
882 .addOptionDouble(322, "enable-screenshot", "enable F10 screenshot capture")
883 .addOptionDouble(325, "disable-sound", "disable background music")
884 .addOptionDouble(330, "benchmark", "enable application benchmark mode")
885 .addOptionDouble(331, "wireframe", "render supported 3D models as wireframes")
886 .addOptionDouble(326, "nowarpfix", "3dmath - disable perspective-correct texture mapping")
887 .addOptionDoubleValue(327, "framebuffer", "3dmath - software framebuffer size WidthxHeight")
888 .addOptionDouble(328, "disable-mipmap", "3dmath - disable mipmap generation and selection")
889 .addOptionDoubleValue(329, "mip-bias", "3dmath - mipmap level-of-detail bias (-16 to 16)")
890 .addOptionDoubleValue(321, "fps", "capture FPS override")
891 .addOptionSingleValue('z', "matrix rain font size")
892 .addOptionDoubleValue(316, "font-size", "matrix rain font size")
893 .addOptionSingleValue('j', "matrix rain font file path")
894 .addOptionDoubleValue(317, "font-path", "matrix rain font file path")
895 .addOptionSingleValue('C', "matrix rain RGB tint (#RRGGBB or R,G,B)")
896 .addOptionDoubleValue(318, "color", "matrix rain RGB tint (#RRGGBB or R,G,B)")
897 .addOptionDoubleValue(302, "resource", "resource file")
898 .addOptionDoubleValue(303, "resource_path", "resource data path")
899 .addOptionDoubleValue(257, "texture", "texture file (.png or .tex)")
900 .addOptionDoubleValue(323, "textures", "texture file (.png or .tex)")
901 .addOptionSingleValue('S', "shader SPV folder path (contains index.txt)")
902 .addOptionDoubleValue(258, "shader-path", "shader SPV folder path (contains index.txt)")
903 .addOptionDoubleValue(313, "fragment", "fragment shader SPV path")
904 .addOptionSingleValue('i', "acidcam filter mode index")
905 .addOptionDoubleValue(311, "index", "acidcam filter mode index")
906 .addOptionDoubleValue(312, "shader-index", "initial shader entry index")
907 .addOptionDoubleValue(300, "camera", "camera index");
908
910 std::string path;
911 int value = 0;
912 int tw = 1280, th = 720;
913 bool fullscreen = false;
914 bool fast = false;
915 bool resolutionSpecified = false;
916 std::string filename;
917 std::string model;
918 std::string output;
919 std::string crf;
920 std::string encodePreset;
921 std::string encodeTune;
922 std::string encodeCodec;
923 bool encodeRealtime = false;
924 bool mxwriteBlockWhenFull = false;
925 bool repeat = false;
926 bool binary = false;
927 bool enable_crt = false;
928 bool enable_vsync = false;
929 bool enable_screenshot = false;
930 bool disable_sound = false;
931 bool benchmark = false;
932 bool wireframe = false;
933 bool nowarpfix = false;
934 bool disable_mipmap = false;
935 float mip_bias = 0.0f;
936 FramebufferDimensions framebuffer;
937 bool framebufferSpecified = false;
938 double fps = 0.0;
939 int font_size = 22;
940 std::string font_path;
941 std::string color;
942 std::string texture;
943 std::string shaderPath;
944 std::string fragmentPath;
945 int camera_index = 0;
946 int index = 0;
947 int shader_index = 0;
948 std::string resource;
949 std::string resource_path;
950 while ((value = parser.proc(arg)) != -1) {
951 switch (value) {
952 case 303:
953 resource_path = arg.arg_value;
954 break;
955 case 302:
956 resource = arg.arg_value;
957 break;
958 case 256:
959 filename = arg.arg_value;
960 break;
961 case 324:
962 model = arg.arg_value;
963 break;
964 case 'o':
965 case 304:
966 output = arg.arg_value;
967 break;
968 case 'c':
969 case 305:
970 crf = arg.arg_value;
971 break;
972 case 306:
973 encodePreset = arg.arg_value;
974 break;
975 case 307:
976 encodeTune = arg.arg_value;
977 break;
978 case 308:
979 encodeCodec = arg.arg_value;
980 break;
981 case 309:
982 encodeRealtime = true;
983 break;
984 case 314:
985 mxwriteBlockWhenFull = true;
986 break;
987 case 310:
988 repeat = true;
989 break;
990 case 315:
991 binary = true;
992 break;
993 case 319:
994 enable_crt = true;
995 break;
996 case 320:
997 enable_vsync = true;
998 break;
999 case 322:
1000 enable_screenshot = true;
1001 break;
1002 case 325:
1003 disable_sound = true;
1004 break;
1005 case 330:
1006 benchmark = true;
1007 break;
1008 case 331:
1009 wireframe = true;
1010 break;
1011 case 326:
1012 nowarpfix = true;
1013 break;
1014 case 327: {
1015 const std::string::size_type separator = arg.arg_value.find('x');
1016 if (separator == std::string::npos) {
1017 throw ArgException<std::string>("Invalid framebuffer size, expected WidthxHeight: " + arg.arg_value);
1018 }
1019 framebuffer.width = parse_arg_int(arg.arg_value.substr(0, separator), "--framebuffer width");
1020 framebuffer.height = parse_arg_int(arg.arg_value.substr(separator + 1), "--framebuffer height");
1021 if (framebuffer.width <= 0 || framebuffer.height <= 0) {
1022 throw ArgException<std::string>("Invalid framebuffer size: " + arg.arg_value);
1023 }
1024 framebufferSpecified = true;
1025 } break;
1026 case 328:
1027 disable_mipmap = true;
1028 break;
1029 case 329: {
1030 const double parsed_mip_bias = parse_arg_double(arg.arg_value, "--mip-bias");
1031 if (parsed_mip_bias < -16.0 || parsed_mip_bias > 16.0) {
1032 throw ArgException<std::string>("Mip bias must be between -16 and 16: " + arg.arg_value);
1033 }
1034 mip_bias = static_cast<float>(parsed_mip_bias);
1035 } break;
1036 case 321:
1037 fps = parse_arg_double(arg.arg_value, "--fps");
1038 if (fps <= 0.0) {
1039 throw ArgException<std::string>("Invalid numeric value for --fps: " + arg.arg_value);
1040 }
1041 break;
1042 case 'z':
1043 case 316:
1044 font_size = parse_arg_int(arg.arg_value, "--font-size");
1045 if (font_size <= 0) {
1046 throw ArgException<std::string>("Invalid numeric value for --font-size: " + arg.arg_value);
1047 }
1048 break;
1049 case 'j':
1050 case 317:
1051 font_path = arg.arg_value;
1052 break;
1053 case 'C':
1054 case 318:
1055 color = arg.arg_value;
1056 break;
1057 case 257:
1058 case 323:
1059 texture = arg.arg_value;
1060 break;
1061 case 'S':
1062 case 258:
1063 shaderPath = arg.arg_value;
1064 break;
1065 case 313:
1066 fragmentPath = arg.arg_value;
1067 break;
1068 case 'h':
1069 case 'v':
1070 parser.help(std::cout);
1071 exit(EXIT_SUCCESS);
1072 break;
1073 case 'p':
1074 case 'P':
1075 path = arg.arg_value;
1076 break;
1077 case 'r':
1078 case 'R': {
1079 auto pos = arg.arg_value.find("x");
1080 if (pos == std::string::npos) {
1081 throw ArgException<std::string>("Invalid resolution for --resolution, expected WidthxHeight: " + arg.arg_value);
1082 }
1083 std::string left, right;
1084 left = arg.arg_value.substr(0, pos);
1085 right = arg.arg_value.substr(pos + 1);
1086 tw = parse_arg_int(left, "--resolution width");
1087 th = parse_arg_int(right, "--resolution height");
1088 if (tw <= 0 || th <= 0) {
1089 throw ArgException<std::string>("Invalid numeric value for --resolution: " + arg.arg_value);
1090 }
1091 resolutionSpecified = true;
1092 } break;
1093 case 'f':
1094 case 'F':
1095 fullscreen = true;
1096 break;
1097 case 301:
1098 fast = true;
1099 break;
1100 case 300:
1101 camera_index = parse_arg_int(arg.arg_value, "--camera");
1102 break;
1103 case 'i':
1104 case 311:
1105 index = parse_arg_int(arg.arg_value, "--index");
1106 break;
1107 case 312:
1108 shader_index = parse_arg_int(arg.arg_value, "--shader-index");
1109 break;
1110 }
1111 }
1112 if (path.empty()) {
1113 path = executable_directory(argc > 0 ? argv[0] : nullptr);
1114 std::cerr << "mx: No path provided; using executable directory: " << path << '\n';
1115 } else {
1116 std::error_code error;
1117 const std::filesystem::path absolute_path = std::filesystem::absolute(path, error);
1118 if (!error) {
1119 path = absolute_path.lexically_normal().string();
1120 }
1121 }
1122 args.executable_name = executable_name;
1123 mxvk::setDefaultExecutableName(executable_name);
1124 args.width = tw;
1125 args.height = th;
1126 args.resolutionSpecified = resolutionSpecified;
1127 args.path = path;
1128 args.fullscreen = fullscreen;
1129 args.fast = fast;
1130 args.filename = filename;
1131 args.model = model;
1132 args.output = output;
1133 args.crf = crf;
1134 args.encodePreset = encodePreset;
1135 args.encodeTune = encodeTune;
1136 args.encodeCodec = encodeCodec;
1137 args.encodeRealtime = encodeRealtime;
1138 args.mxwriteBlockWhenFull = mxwriteBlockWhenFull;
1139 args.repeat = repeat;
1140 args.binary = binary;
1141 args.enable_crt = enable_crt;
1142 args.enable_vsync = enable_vsync;
1143 args.enable_screenshot = enable_screenshot;
1144 args.disable_sound = disable_sound;
1145 args.benchmark = benchmark;
1146 args.wireframe = wireframe;
1147 args.nowarpfix = nowarpfix;
1148 args.disable_mipmap = disable_mipmap;
1149 args.mip_bias = mip_bias;
1150 args.framebuffer = framebuffer;
1151 args.framebufferSpecified = framebufferSpecified;
1152 mxvk::setDefaultEnableScreenshot(enable_screenshot);
1153 args.fps = fps;
1154 args.font_size = font_size;
1155 args.font_path = font_path;
1156 args.color = color;
1157 args.texture = texture;
1158 args.shaderPath = shaderPath;
1159 args.fragmentPath = fragmentPath;
1160 args.camera_index = camera_index;
1161 args.index = index;
1162 args.shader_index = shader_index;
1163 args.resource = resource;
1164 args.resource_path = resource_path;
1165 return args;
1166}
std::string executable_directory(const char *executable)
Definition argz.hpp:78
Arguments proc_args(int &argc, char **argv)
Parse standard libmx2 command-line options from main()'s argv.
Definition argz.hpp:854
double parse_arg_double(const std::string &text, const std::string &option_name)
Definition argz.hpp:773
ArgType
Discriminator for option kind used inside Argument.
Definition argz.hpp:102
@ ARG_DOUBLE_VALUE
Definition argz.hpp:102
@ ARG_SINGLE
Definition argz.hpp:102
@ ARG_SINGLE_VALUE
Definition argz.hpp:102
@ ARG_DOUBLE
Definition argz.hpp:102
@ ARG_NONE
Definition argz.hpp:102
int parse_arg_int(const std::string &text, const std::string &option_name)
Definition argz.hpp:762
std::string parse_executable_name(const char *argv0)
Definition argz.hpp:784
Exception thrown by Argz::proc() on unrecognised or malformed options.
Definition argz.hpp:169
ArgException(const String &s)
Definition argz.hpp:172
String text() const
Definition argz.hpp:173
ArgException()=default
Template command-line argument parser.
Definition argz.hpp:187
Argz()=default
void help(T &cout)
Print all registered options to any ostream-like object.
Definition argz.hpp:495
std::unordered_map< int, Argument< String > > arg_info
Definition argz.hpp:570
Argz< String > & addOptionSingleValue(const int &c, const String &description)
Register a short option that requires a value argument (e.g.
Definition argz.hpp:289
Argz(Argz< String > &&a)
Definition argz.hpp:211
ArgumentData< String > arg_data
Definition argz.hpp:569
int lookUpCode(const String &value) const
Look up the integer code registered for a long option name.
Definition argz.hpp:337
Argz< String > & addOptionDouble(const int &code, const String &value, const String &description)
Register a flag-only long option (e.g.
Definition argz.hpp:305
const size_t count() const
Definition argz.hpp:566
Argz< String > & initArgs(int argc, char **argv)
Ingest argc/argv, converting to the target String type.
Definition argz.hpp:230
~Argz()=default
Argz< String > & addOptionDoubleValue(const int &code, const String &value, const String &description)
Register a long option that requires a value argument (e.g.
Definition argz.hpp:322
int proc(Argument< String > &a)
Advance the cursor and parse the next argument.
Definition argz.hpp:352
Argz< String > & operator=(Argz< String > &&a)
Definition argz.hpp:213
Argz< String > & addOptionSingle(const int &c, const String &description)
Register a flag-only short option (e.g.
Definition argz.hpp:274
Argz< String > & operator=(const Argz< String > &a)
Definition argz.hpp:200
Argz(const Argz< String > &a)
Definition argz.hpp:198
void reset()
Reset the internal parse cursor to the beginning of argv.
Definition argz.hpp:263
Argz(int argc, char **argv)
Construct and immediately ingest argv.
Definition argz.hpp:197
Models a string-like class with indexing, concatenation, length, and value_type.
Definition argz.hpp:65
Definition model.py:1
void setDefaultEnableScreenshot(bool enabled)
void setDefaultExecutableName(const std::string &name)
Holds the raw argv strings converted to the target String type.
Definition argz.hpp:139
ArgumentData(ArgumentData< String > &&a)
Definition argz.hpp:153
ArgumentData< String > & operator=(ArgumentData< String > &&a)
Definition argz.hpp:154
ArgumentData(const ArgumentData< String > &a)
Definition argz.hpp:144
~ArgumentData()=default
ArgumentData()=default
ArgumentData & operator=(const ArgumentData< String > &a)
Definition argz.hpp:145
std::vector< String > args
Converted argv entries (argv[1] … argv[argc-1]).
Definition argz.hpp:140
int argc
Original argc value.
Definition argz.hpp:141
Describes a single parsed argument entry returned by Argz::proc().
Definition argz.hpp:113
int arg_letter
Short option code (e.g. 'o') or unique integer for long-only options.
Definition argz.hpp:115
~Argument()=default
Argument & operator=(const Argument< String > &a)
Definition argz.hpp:122
Argument(const Argument &a)
Definition argz.hpp:121
ArgType arg_type
Which ArgType variant this argument represents.
Definition argz.hpp:117
String arg_name
Long option name (e.g. "output").
Definition argz.hpp:114
auto operator<=>(const Argument< String > &a) const
Definition argz.hpp:130
Argument()
Definition argz.hpp:120
String arg_value
Value string supplied after the option, if any.
Definition argz.hpp:116
bool operator==(const Argument< String > &a) const
Definition argz.hpp:131
String desc
Human-readable description used in help output.
Definition argz.hpp:118
Plain data structure returned by proc_args() with all common libmx2 CLI options.
Definition argz.hpp:718
FramebufferDimensions framebuffer
Software framebuffer size requested by --framebuffer.
Definition argz.hpp:746
std::string shaderPath
Optional SPV shader folder path (-S / --shader-path).
Definition argz.hpp:753
bool framebufferSpecified
Whether --framebuffer was provided.
Definition argz.hpp:747
std::string output
Optional output filename (--output).
Definition argz.hpp:728
std::string font_path
Optional font file path (--font-path).
Definition argz.hpp:750
bool mxwriteBlockWhenFull
Make MXWrite block instead of dropping frames (--mxwrite-block).
Definition argz.hpp:734
bool fast
Whether fast mode was requested (--fast).
Definition argz.hpp:725
int camera_index
Optional camera index.
Definition argz.hpp:755
bool enable_screenshot
Enable F10 screenshot capture (--enable-screenshot).
Definition argz.hpp:739
std::string encodeTune
Optional encoder tune (--encode-tune).
Definition argz.hpp:731
bool fullscreen
Whether fullscreen mode was requested.
Definition argz.hpp:724
int index
Optional acidcam filter mode index.
Definition argz.hpp:756
bool encodeRealtime
Enable low-latency encoder settings (--encode-realtime).
Definition argz.hpp:733
bool resolutionSpecified
Whether -r/–resolution was provided.
Definition argz.hpp:722
float mip_bias
Mipmap level-of-detail bias requested by --mip-bias.
Definition argz.hpp:745
std::string model
Optional model filename (--model).
Definition argz.hpp:727
bool enable_vsync
Enable FIFO present mode / v-sync (--enable-vsync).
Definition argz.hpp:738
std::string crf
Optional CRF value (--crf).
Definition argz.hpp:729
bool nowarpfix
Disable perspective-correct texture mapping (--nowarpfix).
Definition argz.hpp:743
std::string texture
Optional texture file path (--texture).
Definition argz.hpp:752
int height
Viewport height in pixels (default: 720).
Definition argz.hpp:721
double fps
Optional FPS override (--fps); non-positive means unspecified.
Definition argz.hpp:748
std::string encodeCodec
Optional encoder codec policy/name (--encode-codec).
Definition argz.hpp:732
std::string color
Optional rain RGB tint (--color).
Definition argz.hpp:751
std::string resource_path
Resource path.
Definition argz.hpp:759
bool repeat
Enable repeat behavior such as playback looping or wrapped textures.
Definition argz.hpp:735
std::string filename
Optional input filename (--filename).
Definition argz.hpp:726
std::string encodePreset
Optional encoder preset (--encode-preset).
Definition argz.hpp:730
std::string path
Asset root; proc_args() defaults it to the executable directory.
Definition argz.hpp:723
std::string fragmentPath
Optional fragment shader SPV path (--fragment).
Definition argz.hpp:754
std::string executable_name
Executable basename derived from argv[0].
Definition argz.hpp:719
bool benchmark
Enable application benchmark mode (--benchmark).
Definition argz.hpp:741
bool wireframe
Render supported 3D models as wireframes (--wireframe).
Definition argz.hpp:742
int width
Viewport width in pixels (default: 1280).
Definition argz.hpp:720
std::string resource
Resource file.
Definition argz.hpp:758
bool enable_crt
Enable CRT post-processing at startup (--enable-crt).
Definition argz.hpp:737
int shader_index
Optional initial shader entry index.
Definition argz.hpp:757
bool disable_mipmap
Disable mipmap generation and selection (--disable-mipmap).
Definition argz.hpp:744
int font_size
Matrix rain font size in pixels (--font-size).
Definition argz.hpp:749
bool binary
Use binary glyphs only (--binary).
Definition argz.hpp:736
bool disable_sound
Disable application background music (--disable-sound).
Definition argz.hpp:740
Parsed software framebuffer dimensions.
Definition argz.hpp:709
int width
Software framebuffer width in pixels.
Definition argz.hpp:710
int height
Software framebuffer height in pixels.
Definition argz.hpp:711