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