1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
//! Unsafe functions related to the libretro environment callback
//! For safe versions have a look at the [`contexts`] module and
//! the context types you get in your core callbacks.
use super::{types::*, *};
/// Gets a value from an environment callback.
///
/// The first value of the return type is the queried data,
/// the second value is the return value of the callback itself.
pub unsafe fn get<T: Default>(callback: retro_environment_t, id: u32) -> Option<(T, bool)> {
get_mut(callback, id, Default::default())
}
/// Similar to [`get`] but uses uninitialized memory instead of the [`Default`] trait.
pub unsafe fn get_unchecked<T>(callback: retro_environment_t, id: u32) -> Option<(T, bool)> {
get_mut(callback, id, std::mem::MaybeUninit::zeroed().assume_init())
}
/// Passes a value to the environment callback and returns the modified value.
///
/// The second value is the return value of the callback itself.
pub unsafe fn get_mut<T>(callback: retro_environment_t, id: u32, mut data: T) -> Option<(T, bool)> {
if let Some(callback) = callback {
if (callback as *const c_void).is_null() {
panic!("Expected environment callback, got NULL pointer instead!");
}
let status = (callback)(id, (&mut data as *mut _) as *mut c_void);
Some((data, status))
} else {
None
}
}
/// Helper function to query a string pointer and convert it into a [`Path`].
pub unsafe fn get_path<'a>(callback: retro_environment_t, id: u32) -> Option<&'a Path> {
let ptr: *mut c_void = std::ptr::null_mut();
if let Some((ptr, _)) = get_mut(callback, id, ptr) {
return get_path_from_pointer(ptr as *const c_char);
}
None
}
/// Passes a value to the environment callback.
///
/// Returns [`None`] if the environment callback hasn’t been set
/// and the return status of the callback otherwise.
pub unsafe fn set<T: std::fmt::Debug>(
callback: retro_environment_t,
id: u32,
value: T,
) -> Option<bool> {
set_ptr(callback, id, &value as *const _)
}
/// Passes a value (by a raw const pointer) to the environment callback.
///
/// Returns [`None`] if the environment callback hasn’t been set
/// and the return status of the callback otherwise.
pub unsafe fn set_ptr<T>(callback: retro_environment_t, id: u32, ptr: *const T) -> Option<bool> {
if let Some(callback) = callback {
if (callback as *const c_void).is_null() {
panic!("Expected environment callback, got NULL pointer instead!");
}
let status = (callback)(id, ptr as *mut c_void);
return Some(status);
}
None
}
/* ========================================================================== *\
* Environment callback implementations *
\* ========================================================================== */
/// Sets screen rotation of graphics.
#[proc::context(GenericContext)]
pub unsafe fn set_rotation(callback: retro_environment_t, rotation: Rotation) -> bool {
// const unsigned *
set(
callback,
RETRO_ENVIRONMENT_SET_ROTATION,
rotation.get_env_value(),
)
.unwrap_or(false)
}
/// Boolean value whether or not the implementation should use overscan,
/// or crop away overscan.
#[deprecated(
note = "This function is considered deprecated in favor of using core options to manage overscan in a more nuanced, core-specific way"
)]
#[proc::context(GenericContext)]
pub unsafe fn get_overscan(callback: retro_environment_t) -> bool {
// bool *
get(callback, RETRO_ENVIRONMENT_GET_OVERSCAN)
.map(|(v, _)| v)
.unwrap_or(false)
}
/// Boolean value whether or not frontend supports frame duping,
/// passing NULL to video frame callback.
#[proc::context(GenericContext)]
pub unsafe fn can_dupe(callback: retro_environment_t) -> bool {
// bool *
get(callback, RETRO_ENVIRONMENT_GET_CAN_DUPE)
.map(|(v, _)| v)
.unwrap_or(false)
}
/// Sets a message to be displayed in implementation-specific manner
/// for a certain amount of 'frames'.
/// Should not be used for trivial messages, which should simply be
/// logged via [`RETRO_ENVIRONMENT_GET_LOG_INTERFACE`] (or as a
/// fallback, stderr).
#[proc::context(GenericContext)]
pub unsafe fn set_message(callback: retro_environment_t, message: &str, frames: u32) -> bool {
let msg = CString::new(message).unwrap();
// const struct retro_message *
set(
callback,
RETRO_ENVIRONMENT_SET_MESSAGE,
retro_message {
msg: msg.as_ptr(),
frames,
},
)
.unwrap_or(false)
}
/// Requests the frontend to shutdown.
/// Should only be used if game has a specific
/// way to shutdown the game from a menu item or similar.
#[proc::context(GenericContext)]
pub unsafe fn shutdown(callback: retro_environment_t) {
// N/A (NULL)
set_ptr(
callback,
RETRO_ENVIRONMENT_SHUTDOWN,
std::ptr::null() as *const c_void,
);
}
/// Gives a hint to the frontend how demanding this implementation
/// is on a system. E.g. reporting a level of 2 means
/// this implementation should run decently on all frontends
/// of level 2 and up.
///
/// It can be used by the frontend to potentially warn
/// about too demanding implementations.
///
/// The levels are "floating".
///
/// This function can be called on a per-game basis,
/// as certain games an implementation can play might be
/// particularly demanding.
#[proc::context(LoadGameContext)]
pub unsafe fn set_performance_level(callback: retro_environment_t, level: u8) -> bool {
// const unsigned *
set(
callback,
RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL,
level as u32,
)
.unwrap_or(false)
}
/// Returns the "system" directory of the frontend.
/// This directory can be used to store system specific
/// content such as BIOSes, configuration data, etc.
/// The returned value can be `NULL`.
/// If so, no such directory is defined,
/// and it's up to the implementation to find a suitable directory.
///
/// **NOTE**: Some cores used this folder also for "save" data such as
/// memory cards, etc, for lack of a better place to put it.
/// This is now discouraged, and if possible, cores should try to
/// use the new [`get_save_directory()`].
#[proc::context(GenericContext)]
pub unsafe fn get_system_directory<'a>(callback: retro_environment_t) -> Option<&'a Path> {
// const char **
get_path(callback, RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY)
}
/// Sets the internal pixel format used by the implementation.
/// The default pixel format is [`retro_pixel_format::RETRO_PIXEL_FORMAT_0RGB1555`].
/// This pixel format however, is deprecated (see enum [`retro_pixel_format`]).
/// If the call returns `false`, the frontend does not support this pixel
/// format.
#[proc::context(LoadGameContext)]
#[proc::context(GetAvInfoContext)]
pub unsafe fn set_pixel_format(callback: retro_environment_t, format: retro_pixel_format) -> bool {
// const enum retro_pixel_format *
set(callback, RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, format).unwrap_or(false)
}
/// Sets an array of retro_input_descriptors.
/// It is up to the frontend to present this in a usable way.
/// The array is terminated by retro_input_descriptor::description
/// being set to `NULL`.
/// This function can be called at any time, but it is recommended
/// to call it as early as possible.
#[proc::context(GenericContext)]
pub unsafe fn set_input_descriptors(
callback: retro_environment_t,
descriptors: &[retro_input_descriptor],
) -> bool {
// const struct retro_input_descriptor *
set_ptr(
callback,
RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS,
descriptors.as_ptr(),
)
.unwrap_or(false)
}
/// Sets a callback function used to notify core about keyboard events.
#[proc::context(GenericContext)]
pub unsafe fn set_keyboard_callback(
callback: retro_environment_t,
data: retro_keyboard_callback,
) -> bool {
// const struct retro_keyboard_callback *
set(callback, RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK, data).unwrap_or(false)
}
/// Sets an interface which frontend can use to eject and insert
/// disk images.
/// This is used for games which consist of multiple images and
/// must be manually swapped out by the user (e.g. PSX).
#[proc::context(GenericContext)]
pub unsafe fn set_disk_control_interface(
callback: retro_environment_t,
data: retro_disk_control_callback,
) -> bool {
// const struct retro_disk_control_callback *
set(callback, RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, data).unwrap_or(false)
}
/// Sets an interface to let a libretro core render with
/// hardware acceleration.
///
/// If successful, libretro cores will be able to render to a
/// frontend-provided framebuffer.
/// The size of this framebuffer will be at least as large as
/// max_width/max_height provided in [`Core::on_get_av_info`].
/// If HW rendering is used, call either
/// [`RunContext::draw_hardware_frame`] or [`RunContext::dupe_frame`].
#[proc::context(LoadGameContext)]
pub unsafe fn set_hw_render(callback: retro_environment_t, data: retro_hw_render_callback) -> bool {
// struct retro_hw_render_callback *
set(callback, RETRO_ENVIRONMENT_SET_HW_RENDER, data).unwrap_or(false)
}
/// Interface to acquire user-defined information from environment
/// that cannot feasibly be supported in a multi-system way.
///
/// The `key` should be set to a key which has already been set by
/// [`set_variables`] or [`set_core_options`].
///
/// Returns [`None`] if the variable could not be found.
#[proc::context(GenericContext)]
#[proc::context(OptionsChangedContext)]
#[allow(clippy::needless_lifetimes)]
pub unsafe fn get_variable<'a>(callback: retro_environment_t, key: &'a str) -> Option<&'a str> {
let key = CString::new(key).unwrap();
let var = retro_variable {
key: key.as_ptr(),
value: std::ptr::null(),
};
// struct retro_variable *
if let Some((var, _)) = get_mut(callback, RETRO_ENVIRONMENT_GET_VARIABLE, var) {
if !var.value.is_null() {
return get_str_from_pointer(var.value as *const c_char);
}
}
None
}
/// Allows an implementation to signal the environment
/// which variables it might want to check for later using
/// [`get_variable`].
/// This allows the frontend to present these variables to
/// a user dynamically.
/// This should be called the first time as early as
/// possible (ideally in [`Core::on_set_environment`]).
/// Afterward it may be called again for the core to communicate
/// updated options to the frontend, but the number of core
/// options must not change from the number in the initial call.
///
/// The passed array of [`retro_variable`] structs must be
/// terminated by a
/// ```
/// # use rust_libretro_sys::retro_variable;
/// retro_variable {
/// key: 0 as *const libc::c_char,
/// value: 0 as *const libc::c_char,
/// }
/// # ;
/// ```
/// element.
/// [`retro_variable::key`] should be namespaced to not collide
/// with other implementations' keys. E.g. A core called
/// 'foo' should use keys named as `foo_option`.
/// [`retro_variable::value`] should contain a human readable
/// description of the key as well as a `|` delimited list
/// of expected values.
///
/// The number of possible options should be very limited,
/// i.e. it should be feasible to cycle through options
/// without a keyboard.
///
/// First entry should be treated as a default.
///
/// Example entry:
/// ```
/// # use rust_libretro_sys::retro_variable;
/// retro_variable {
/// key: b"foo_option" as *const u8 as *const libc::c_char,
/// value: b"Speed hack coprocessor X; false|true" as *const u8 as *const libc::c_char,
/// }
/// # ;
/// ```
///
/// Text before first `;` is description. This `;` must be
/// followed by a space, and followed by a list of possible
/// values split up with `|`.
///
/// Only strings are operated on. The possible values will
/// generally be displayed and stored as-is by the frontend.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_variables(callback: retro_environment_t, variables: &[retro_variable]) -> bool {
// const struct retro_variable *
set_ptr(
callback,
RETRO_ENVIRONMENT_SET_VARIABLES,
variables.as_ptr(),
)
.unwrap_or(false)
}
/// Result is set to [`true`] if some variables are updated by
/// frontend since last call to [`get_variable`].
#[proc::context(GenericContext)]
pub unsafe fn get_variable_update(callback: retro_environment_t) -> bool {
// bool *
get(callback, RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE)
.map(|(v, _)| v)
.unwrap_or(false)
}
/// Tell the frontend whether this Core can run without particular game data.
///
/// If true, the [`Core`] implementation supports calls to
/// [`Core::on_load_game`] with [`None`] as argument.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_support_no_game(callback: retro_environment_t, value: bool) -> bool {
// const bool *
set(callback, RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, value).unwrap_or(false)
}
/// Retrieves the absolute path from where this libretro
/// implementation was loaded.
/// [`None`] is returned if the libretro was loaded statically
/// (i.e. linked statically to frontend), or if the path cannot be
/// determined.
/// Mostly useful in cooperation with [`set_support_no_game`] as assets can
/// be loaded without ugly hacks.
#[proc::context(GenericContext)]
pub unsafe fn get_libretro_path<'a>(callback: retro_environment_t) -> Option<&'a Path> {
// const char **
get_path(callback, RETRO_ENVIRONMENT_GET_LIBRETRO_PATH)
}
/// Lets the core know how much time has passed since last
/// invocation of [`Core::on_run`].
/// The frontend can tamper with the timing to fake fast-forward,
/// slow-motion, frame stepping, etc.
/// In this case the delta time will use the reference value
/// in [`retro_frame_time_callback`].
#[proc::context(LoadGameContext)]
#[proc::context(LoadGameSpecialContext)]
pub unsafe fn set_frame_time_callback(
callback: retro_environment_t,
data: retro_frame_time_callback,
) -> bool {
// const struct retro_frame_time_callback *
set(callback, RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK, data).unwrap_or(false)
}
/// Sets an interface which is used to notify a libretro core about audio
/// being available for writing.
/// The callback can be called from any thread, so a core using this must
/// have a thread safe audio implementation.
///
/// It is intended for games where audio and video are completely
/// asynchronous and audio can be generated on the fly.
/// This interface is not recommended for use with emulators which have
/// highly synchronous audio.
///
/// The callback only notifies about writability; the libretro core still
/// has to call the normal audio callbacks
/// to write audio. The audio callbacks must be called from within the
/// notification callback.
/// The amount of audio data to write is up to the implementation.
/// Generally, the audio callback will be called continously in a loop.
///
/// Due to thread safety guarantees and lack of sync between audio and
/// video, a frontend can selectively disallow this interface based on
/// internal configuration. A core using this interface must also
/// implement the "normal" audio interface.
///
/// A libretro core using [`set_audio_callback`] should also make use of
/// [`set_frame_time_callback`].
#[proc::context(GenericContext)]
pub unsafe fn set_audio_callback(
callback: retro_environment_t,
data: retro_audio_callback,
) -> bool {
// const struct retro_audio_callback *
set(callback, RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, data).unwrap_or(false)
}
/// Gets an interface which is used by a libretro core to set
/// state of rumble motors in controllers.
/// A strong and weak motor is supported, and they can be
/// controlled indepedently.
/// Should be called from either [`Core::on_init`] or [`Core::on_load_game`].
/// Should not be called from [`Core::on_set_environment`].
/// Returns false if rumble functionality is unavailable.
#[proc::context(InitContext)]
#[proc::context(LoadGameContext)]
pub unsafe fn get_rumble_interface(
callback: retro_environment_t,
) -> Option<retro_rumble_interface> {
// struct retro_rumble_interface *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE).map(|(v, _)| v)
}
/// Gets a bitmask telling which device type are expected to be
/// handled properly in a call to [`retro_input_state_t`].
/// Devices which are not handled or recognized always return
/// 0 in [`retro_input_state_t`].
/// Example bitmask: `RetroDevice::JOYPAD | RetroDevice::ANALOG`.
#[proc::context(RunContext)]
pub unsafe fn get_input_device_capabilities(callback: retro_environment_t) -> RetroDevice {
// I’m not entirely sure why this call returns a 64 bit value when the `RETRO_DEVICE_MASK` allows only eight distinct types.
// uint64_t *
if let Some((caps, _)) = get::<u64>(callback, RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES) {
return RetroDevice::from_bits_truncate(caps as u8);
}
RetroDevice::NONE
}
/// Gets access to the sensor interface.
/// The purpose of this interface is to allow
/// setting state related to sensors such as polling rate,
/// enabling/disable it entirely, etc.
/// Reading sensor state is done via the normal
/// input_state_callback API.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_sensor_interface(
callback: retro_environment_t,
) -> Option<retro_sensor_interface> {
// const struct retro_sensor_interface *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE).map(|(v, _)| v)
}
/// Gets an interface to a video camera driver.
/// A libretro core can use this interface to get access to a
/// video camera.
/// New video frames are delivered in a callback in same
/// thread as [`Core::on_run`].
///
/// [`get_camera_interface`] should be called in [`Core::on_load_game`].
///
/// Depending on the camera implementation used, camera frames
/// will be delivered as a raw framebuffer,
/// or as an OpenGL texture directly.
///
/// The core has to tell the frontend here which types of
/// buffers can be handled properly.
/// An OpenGL texture can only be handled when using a
/// libretro GL core ([`set_hw_render`]).
/// It is recommended to use a libretro GL core when
/// using camera interface.
///
/// The camera is not started automatically. The retrieved start/stop
/// functions must be used to explicitly
#[proc::context(LoadGameContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_camera_interface(
callback: retro_environment_t,
data: retro_camera_callback,
) -> Option<retro_camera_callback> {
// struct retro_camera_callback *
get_mut(callback, RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE, data).map(|(v, _)| v)
}
/// Gets an interface for logging. This is useful for
/// logging in a cross-platform way
/// as certain platforms cannot use `stderr` for logging.
/// It also allows the frontend to
/// show logging information in a more suitable way.
/// If this interface is not used, libretro cores should
/// log to `stderr` as desired.
#[proc::context(GenericContext)]
pub unsafe fn get_log_callback(
callback: retro_environment_t,
) -> Result<Option<retro_log_callback>, Box<dyn std::error::Error>> {
// struct retro_log_callback *
match get_unchecked(callback, RETRO_ENVIRONMENT_GET_LOG_INTERFACE) {
Some((callback, true)) => Ok(Some(callback)),
_ => Err("Failed to query log callback".into()),
}
}
/// Gets an interface for performance counters. This is useful
/// for performance logging in a cross-platform way and for detecting
/// architecture-specific features, such as SIMD support.
#[proc::context(GenericContext)]
pub unsafe fn get_perf_interface(callback: retro_environment_t) -> Option<retro_perf_callback> {
// struct retro_perf_callback *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_PERF_INTERFACE).map(|(v, _)| v)
}
/// Gets access to the location interface.
/// The purpose of this interface is to be able to retrieve
/// location-based information from the host device,
/// such as current latitude / longitude.
#[proc::context(GenericContext)]
pub unsafe fn get_location_callback(
callback: retro_environment_t,
) -> Option<retro_location_callback> {
// struct retro_location_callback *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE).map(|(v, _)| v)
}
/// Returns the "core assets" directory of the frontend.
/// This directory can be used to store specific assets that the
/// core relies upon, such as art assets,
/// input data, etc etc.
/// The returned value can be [`None`].
/// If so, no such directory is defined,
/// and it's up to the implementation to find a suitable directory.
#[proc::context(GenericContext)]
pub unsafe fn get_core_assets_directory<'a>(callback: retro_environment_t) -> Option<&'a Path> {
// const char **
get_path(callback, RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY)
}
/// Returns the "save" directory of the frontend, unless there is no
/// save directory available. The save directory should be used to
/// store SRAM, memory cards, high scores, etc, if the libretro core
/// cannot use the regular memory interface ([`Core::get_memory_data`]).
///
/// If the frontend cannot designate a save directory, it will return
/// [`None`] to indicate that the core should attempt to operate without a
/// save directory set.
///
/// NOTE: early libretro cores used the system directory for save
/// files. Cores that need to be backwards-compatible can still check
/// [`get_system_directory`].
#[proc::context(GenericContext)]
pub unsafe fn get_save_directory<'a>(callback: retro_environment_t) -> Option<&'a Path> {
// const char **
get_path(callback, RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY)
}
/// Sets a new av_info structure.
///
/// This should **only** be used if the core is completely altering the
/// internal resolutions, aspect ratios, timings, sampling rate, etc.
/// Calling this can require a full reinitialization of video/audio
/// drivers in the frontend,
///
/// so it is important to call it very sparingly, and usually only with
/// the users explicit consent.
/// An eventual driver reinitialize will happen so that video and
/// audio callbacks
/// happening after this call within the same [`Core::on_run`] call will
/// target the newly initialized driver.
///
/// This callback makes it possible to support configurable resolutions
/// in games, which can be useful to
/// avoid setting the "worst case" in max_width/max_height.
///
/// **HIGHLY RECOMMENDED**
/// Do not call this callback every time
/// resolution changes in an emulator core if it's
/// expected to be a temporary change, for the reasons of possible
/// driver reinitialization.
/// This call is not a free pass for not trying to provide
/// correct values in [`Core::on_get_av_info`]. If you need to change
/// things like aspect ratio or nominal width/height,
/// use [`set_game_geometry`], which is a softer variant
/// of [`set_system_av_info`].
///
/// If this returns [`false`], the frontend does not acknowledge a
/// changed [`retro_system_av_info`] struct.
#[proc::context(RunContext)]
pub unsafe fn set_system_av_info(
callback: retro_environment_t,
av_info: retro_system_av_info,
) -> bool {
// const struct retro_system_av_info *
set(callback, RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, av_info).unwrap_or(false)
}
/// Allows a libretro core to announce support for the
/// [`retro_get_proc_address_interface`] interface.
/// This interface allows for a standard way to extend libretro where
/// use of environment calls are too indirect,
/// e.g. for cases where the frontend wants to call directly into the core.
///
/// If a core wants to expose this interface, [`set_proc_address_callback`]
/// **MUST** be called from within [`Core::on_set_environment`].
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_proc_address_callback(
callback: retro_environment_t,
data: retro_get_proc_address_interface,
) -> bool {
// const struct retro_get_proc_address_interface *
set(callback, RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK, data).unwrap_or(false)
}
/// This environment call introduces the concept of libretro "subsystems".
/// A subsystem is a variant of a libretro core which supports
/// different kinds of games.
/// The purpose of this is to support e.g. emulators which might
/// have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo.
/// It can also be used to pick among subsystems in an explicit way
/// if the libretro implementation is a multi-system emulator itself.
///
/// Loading a game via a subsystem is done with [`Core::on_load_game_special`],
/// and this environment call allows a libretro core to expose which
/// subsystems are supported for use with [`Core::on_load_game_special`].
/// A core passes an array of [`retro_game_info`] which is terminated
/// with a zeroed out [`retro_game_info`] struct.
///
/// If a core wants to use this functionality, [`set_subsystem_info`]
/// **MUST** be called from within [`Core::on_set_environment`].
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_subsystem_info(
callback: retro_environment_t,
data: retro_subsystem_info,
) -> bool {
// const struct retro_subsystem_info *
set(callback, RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO, data).unwrap_or(false)
}
/// This environment call lets a libretro core tell the frontend
/// which controller subclasses are recognized in calls to
/// [`Core::on_set_controller_port_device`].
///
/// Some emulators such as Super Nintendo support multiple lightgun
/// types which must be specifically selected from. It is therefore
/// sometimes necessary for a frontend to be able to tell the core
/// about a special kind of input device which is not specifcally
/// provided by the Libretro API.
///
/// In order for a frontend to understand the workings of those devices,
/// they must be defined as a specialized subclass of the generic device
/// types already defined in the libretro API.
///
/// The core must pass an **array** of `const struct` [`retro_controller_info`] which
/// is **terminated with a blanked out struct**.
/// Each element of the [`retro_controller_info`] struct corresponds to the
/// ascending port index that is passed to [`Core::on_set_controller_port_device`]
/// when that function is called to indicate to the core that the frontend has
/// changed the active device subclass.
/// **SEE ALSO**: [`Core::on_set_controller_port_device`]
///
/// The ascending input port indexes provided by the core in the struct
/// are generally presented by frontends as ascending User # or Player #,
/// such as Player 1, Player 2, Player 3, etc. Which device subclasses are
/// supported can vary per input port.
///
/// The first inner element of each entry in the [`retro_controller_info`] array
/// is a [`retro_controller_description`] struct that specifies the names and
/// codes of all device subclasses that are available for the corresponding
/// User or Player, beginning with the generic Libretro device that the
/// subclasses are derived from. The second inner element of each entry is the
/// total number of subclasses that are listed in the [`retro_controller_description`].
///
/// NOTE: Even if special device types are set in the libretro core,
/// libretro should only poll input based on the base input device types.
#[proc::context(GenericContext)]
pub unsafe fn set_controller_info(
callback: retro_environment_t,
data: retro_controller_info,
) -> bool {
// const struct retro_controller_info *
set(callback, RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, data).unwrap_or(false)
}
/// This environment call lets a libretro core tell the frontend
/// about the memory maps this core emulates.
/// This can be used to implement, for example, cheats in a core-agnostic way.
///
/// Should only be used by emulators; it doesn't make much sense for
/// anything else.
/// It is recommended to expose all relevant pointers through
/// retro_get_memory_* as well.
///
/// Can be called from [`Core::on_init`] and [`Core::on_load_game`].
#[proc::context(InitContext)]
#[proc::context(LoadGameContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn set_memory_maps(callback: retro_environment_t, data: retro_memory_map) -> bool {
// const struct retro_memory_map *
set(callback, RETRO_ENVIRONMENT_SET_MEMORY_MAPS, data).unwrap_or(false)
}
/// Sets a new game_geometry structure.
///
/// This environment call is similar to [`set_system_av_info`] for changing
/// video parameters, but provides a guarantee that drivers will not be
/// reinitialized.
///
/// The purpose of this call is to allow a core to alter nominal
/// width/heights as well as aspect ratios on-the-fly, which can be
/// useful for some emulators to change in run-time.
///
/// max_width/max_height arguments are ignored and cannot be changed
/// with this call as this could potentially require a reinitialization or a
/// non-constant time operation.
/// If max_width/max_height are to be changed, [`set_system_av_info`] is required.
///
/// A frontend must guarantee that this environment call completes in
/// constant time.
#[proc::context(RunContext)]
pub unsafe fn set_game_geometry(
callback: retro_environment_t,
geometry: retro_game_geometry,
) -> bool {
// const struct retro_game_geometry *
set(callback, RETRO_ENVIRONMENT_SET_GEOMETRY, geometry).unwrap_or(false)
}
/// Returns the specified username of the frontend, if specified by the user.
/// This username can be used as a nickname for a core that has online facilities
/// or any other mode where personalization of the user is desirable.
/// The returned value can be [`None`].
/// If this environment callback is used by a core that requires a valid username,
/// a default username should be specified by the core.
#[proc::context(GenericContext)]
pub unsafe fn get_username<'a>(callback: retro_environment_t) -> Option<&'a str> {
let ptr: *mut c_void = std::ptr::null_mut();
// const char **
if let Some((ptr, _)) = get_mut(callback, RETRO_ENVIRONMENT_GET_USERNAME, ptr) {
if ptr.is_null() {
return None;
}
return get_str_from_pointer(ptr as *const c_char);
}
None
}
/// Returns the language of the frontend, if specified by the user.
/// It can be used by the core for localization purposes.
#[proc::context(GenericContext)]
pub unsafe fn get_language(callback: retro_environment_t) -> Option<retro_language> {
// unsigned *
if let Some((id, _)) = get::<u32>(callback, RETRO_ENVIRONMENT_GET_LANGUAGE) {
if id < retro_language::RETRO_LANGUAGE_LAST as u32 {
// This is safe because all values from 0 to RETRO_LANGUAGE_LAST have defined values
return Some(std::mem::transmute(id));
}
}
None
}
/// Returns a preallocated framebuffer which the core can use for rendering
/// the frame into when not using [`set_hw_render`].
/// The framebuffer returned from this call must not be used
/// after the current call to [`Core::on_run`] returns.
///
/// The goal of this call is to allow zero-copy behavior where a core
/// can render directly into video memory, avoiding extra bandwidth cost by copying
/// memory from core to video memory.
///
/// If this call succeeds and the core renders into it,
/// the framebuffer pointer and pitch can be passed to [`RunContext::draw_framebuffer`].
/// If the buffer from [`get_current_software_framebuffer`] is to be used,
/// the core must pass the exact
/// same pointer as returned by [`get_current_software_framebuffer`];
/// i.e. passing a pointer which is offset from the
/// buffer is undefined. The width, height and pitch parameters
/// must also match exactly to the values obtained from [`get_current_software_framebuffer`].
///
/// It is possible for a frontend to return a different pixel format
/// than the one used in [`set_pixel_format`]. This can happen if the frontend
/// needs to perform conversion.
///
/// It is still valid for a core to render to a different buffer
/// even if [`get_current_software_framebuffer`] succeeds.
///
/// A frontend must make sure that the pointer obtained from this function is
/// writeable (and readable).
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_current_software_framebuffer(
callback: retro_environment_t,
) -> Option<retro_framebuffer> {
// struct retro_framebuffer *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER).map(|(v, _)| v)
}
/// TODO: GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
/// Similarly, after context_destroyed callback returns,
/// the contents of the HW_RENDER_INTERFACE are invalidated.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_hw_render_interface(
callback: retro_environment_t,
) -> Option<retro_hw_render_interface> {
// const struct retro_hw_render_interface **
get_unchecked(callback, RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE).map(|(v, _)| v)
}
/// If true, the Core implementation supports achievements.
///
/// Either via memory descriptors set with [`RETRO_ENVIRONMENT_SET_MEMORY_MAPS`]
/// or via [`Core::get_memory_data`] / [`Core::get_memory_size`].
#[proc::context(InitContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn set_support_achievements(callback: retro_environment_t, value: bool) -> bool {
// const bool *
set(callback, RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, value).unwrap_or(false)
}
/// Sets an interface which lets the libretro core negotiate with frontend how a context is created.
/// The semantics of this interface depends on which API is used in [`set_hw_render`] earlier.
/// This interface will be used when the frontend is trying to create a HW rendering context,
/// so it will be used after [`set_hw_render`], but before the context_reset callback.
#[proc::context(LoadGameContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn set_hw_render_context_negotiation_interface(
callback: retro_environment_t,
interface_type: retro_hw_render_context_negotiation_interface_type,
interface_version: ::std::os::raw::c_uint,
) -> bool {
let data = retro_hw_render_context_negotiation_interface {
interface_type,
interface_version,
};
// const struct retro_hw_render_context_negotiation_interface *
set(
callback,
RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE,
data,
)
.unwrap_or(false)
}
/// Sets quirk flags associated with serialization.
/// The frontend will zero any flags it doesn't recognize or support.
///
/// **Should be set in either [`Core::on_init`] or [`Core::on_load_game`], but not both.**
#[proc::context(InitContext)]
#[proc::context(LoadGameContext)]
pub unsafe fn set_serialization_quirks(
callback: retro_environment_t,
quirks: SerializationQuirks,
) -> bool {
// uint64_t *
set(
callback,
RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS,
quirks.bits() as u64,
)
.unwrap_or(false)
}
/// The frontend will try to use a 'shared' hardware context (mostly applicable
/// to OpenGL) when a hardware context is being set up.
///
/// Returns [`true`] if the frontend supports shared hardware contexts and [`false`]
/// if the frontend does not support shared hardware contexts.
///
/// This will do nothing on its own until `SET_HW_RENDER` environment callbacks are
/// being used.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn set_hw_shared_context(callback: retro_environment_t) -> bool {
// N/A (null) *
set_ptr(
callback,
RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT,
std::ptr::null() as *const c_void,
)
.unwrap_or(false)
}
/// Gets access to the VFS interface.
/// VFS presence needs to be queried prior to load_game or any
/// get_system/save/other_directory being called to let front end know
/// core supports VFS before it starts handing out paths.
/// It is recomended to do so in [`Core::on_set_environment`].
#[proc::context(SetEnvironmentContext)]
#[proc::unstable(feature = "env-commands")]
pub fn get_vfs_interface(callback: retro_environment_t) -> Option<retro_vfs_interface_info> {
// struct retro_vfs_interface_info *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_VFS_INTERFACE).map(|(v, _)| v)
}
/// Gets an interface which is used by a libretro core to set state of LEDs.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub fn get_led_interface(callback: retro_environment_t) -> Option<retro_led_interface> {
// struct retro_led_interface *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_LED_INTERFACE).map(|(v, _)| v)
}
/// Tells the core if the frontend wants audio or video.
/// If disabled, the frontend will discard the audio or video,
/// so the core may decide to skip generating a frame or generating audio.
/// This is mainly used for increasing performance.
///
/// See [`AudioVideoEnable`] for descriptions of the flags.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_audio_video_enable(callback: retro_environment_t) -> AudioVideoEnable {
// int *
if let Some((info, _)) = get(callback, RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE) {
return AudioVideoEnable::from_bits_truncate(info);
}
AudioVideoEnable::empty()
}
/// Returns a MIDI interface that can be used for raw data I/O.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub fn get_midi_interface(callback: retro_environment_t) -> Option<retro_midi_interface> {
// struct retro_midi_interface **
get_unchecked(callback, RETRO_ENVIRONMENT_GET_MIDI_INTERFACE).map(|(v, _)| v)
}
/// Boolean value that indicates whether or not the frontend is in fastforwarding mode.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_fastforwarding(callback: retro_environment_t) -> bool {
// bool *
get(callback, RETRO_ENVIRONMENT_GET_FASTFORWARDING)
.map(|(v, _)| v)
.unwrap_or(false)
}
/// Float value that lets us know what target refresh rate
/// is curently in use by the frontend.
///
/// The core can use the returned value to set an ideal
/// refresh rate/framerate.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_target_refresh_rate(callback: retro_environment_t) -> Option<f32> {
// float *
get(callback, RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE).map(|(v, _)| v)
}
/// Boolean value that indicates whether or not the frontend supports
/// input bitmasks being returned by [`retro_input_state_t`]. The advantage
/// of this is that [`retro_input_state_t`] has to be only called once to
/// grab all button states instead of multiple times.
///
/// If it returns true, you can pass [`RETRO_DEVICE_ID_JOYPAD_MASK`] as `id`
/// to [`retro_input_state_t`] (make sure `device` is set to [`RETRO_DEVICE_JOYPAD`]).
/// It will return a bitmask of all the digital buttons.
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_input_bitmasks(callback: retro_environment_t) -> bool {
// bool *
// get(callback, RETRO_ENVIRONMENT_GET_INPUT_BITMASKS).map(|(v, _)| v).unwrap_or(false)
// RetroArch uses the callback’s return value instead
set_ptr(
callback,
RETRO_ENVIRONMENT_GET_INPUT_BITMASKS,
std::ptr::null() as *const c_void,
)
.unwrap_or(false)
}
/// The returned value is the API version number of the core options
/// interface supported by the frontend.
/// If the underlying callback failed, API version is assumed to be 0.
///
/// In legacy code, core options are set by passing an array of
/// retro_variable structs to [`set_variables`].
/// This may be still be done regardless of the core options
/// interface version.
///
/// If version is `>= 1` however, core options may instead be set by
/// passing an array of [`retro_core_option_definition`] structs to
/// [`set_core_options`], or a 2D array of
/// [`retro_core_option_definition`] structs to [`RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL`].
/// This allows the core to additionally set option sublabel information
/// and/or provide localisation support.
///
/// If version is `>= 2,` core options may instead be set by passing
/// a `retro_core_options_v2` struct to [`set_core_options_v2`],
/// or an array of [`retro_core_options_v2`] structs to
/// [`set_core_options_v2_intl`]. This allows the core
/// to additionally set optional core option category information
/// for frontends with core option category support.
#[proc::context(GenericContext)]
pub unsafe fn get_core_options_version(callback: retro_environment_t) -> u32 {
// unsigned *
get(callback, RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION)
.map(|(v, _)| v)
.unwrap_or(0)
}
/// Checks whether the frontend supports the [`set_core_options`] interface.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn supports_set_core_options(callback: retro_environment_t) -> bool {
get_core_options_version(callback) >= 1
}
/// Checks whether the frontend supports the [`set_core_options_v2`] interface.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn supports_set_core_options_v2(callback: retro_environment_t) -> bool {
get_core_options_version(callback) >= 2
}
/// Allows an implementation to signal the environment
/// which variables it might want to check for later using
/// [`get_variable`].
/// This allows the frontend to present these variables to
/// a user dynamically.
/// This should only be called if [`get_core_options_version`]
/// returns an API version of >= 1.
/// This should be called instead of [`set_variables`].
/// This should be called the first time as early as
/// possible (ideally in [`Core::on_set_environment`]).
/// Afterwards it may be called again for the core to communicate
/// updated options to the frontend, but the number of core
/// options must not change from the number in the initial call.
///
/// 'data' points to an array of [`retro_core_option_definition`] structs
/// terminated by a `{ NULL, NULL, NULL, {{0}}, NULL }` element.
/// [`retro_core_option_definition::key`] should be namespaced to not collide
/// with other implementations' keys. e.g. A core called
/// `foo` should use keys named as `foo_option`.
/// [`retro_core_option_definition::desc`] should contain a human readable
/// description of the key.
/// [`retro_core_option_definition::info`] should contain any additional human
/// readable information text that a typical user may need to
/// understand the functionality of the option.
/// [`retro_core_option_definition::values`] is an array of [`retro_core_option_value`]
/// structs terminated by a `{ NULL, NULL }` element.
/// > `retro_core_option_definition::values[index].value` is an expected option
/// value.
/// > `retro_core_option_definition::values[index].label` is a human readable
/// label used when displaying the value on screen. If `NULL`,
/// the value itself is used.
/// [`retro_core_option_definition::default_value`] is the default core option
/// setting. It must match one of the expected option values in the
/// [`retro_core_option_definition::values`] array. If it does not, or the
/// default value is `NULL`, the first entry in the
/// [`retro_core_option_definition::values`] array is treated as the default.
///
/// The number of possible option values should be very limited,
/// and must be less than [`RETRO_NUM_CORE_OPTION_VALUES_MAX`].
/// i.e. it should be feasible to cycle through options
/// without a keyboard.
///
/// Example entry:
/// ```c
/// {
/// "foo_option",
/// "Speed hack coprocessor X",
/// "Provides increased performance at the expense of reduced accuracy",
/// {
/// { "false", NULL },
/// { "true", NULL },
/// { "unstable", "Turbo (Unstable)" },
/// { NULL, NULL },
/// },
/// "false"
/// }
/// ```
///
/// Only strings are operated on. The possible values will
/// generally be displayed and stored as-is by the frontend.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_core_options(
callback: retro_environment_t,
options: &[retro_core_option_definition],
) -> bool {
// const struct retro_core_option_definition **
set_ptr(
callback,
RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
options.as_ptr(),
)
.unwrap_or(false)
}
/// Allows an implementation to signal the environment
/// which variables it might want to check for later using
/// [`get_variable`].
/// This allows the frontend to present these variables to
/// a user dynamically.
///
/// This should only be called if [`get_core_options_version`]
/// returns an API version of `>= 2`.
///
/// This should be called instead of [`set_variables`].
///
/// This should be called instead of [`set_core_options`].
///
/// This should be called the first time as early as
/// possible (ideally in [`Core::on_set_environment`]).
///
/// Afterwards it may be called again for the core to communicate
/// updated options to the frontend, but the number of core
/// options must not change from the number in the initial call.
///
/// If [`get_core_options_version`] returns an API
/// version of `>= 2`, this callback is guaranteed to succeed
/// (i.e. callback return value does not indicate success)
///
/// If callback returns [`true`], frontend has core option category
/// support.
///
/// If callback returns [`false`], frontend does not have core option
/// category support.
///
/// 'data' points to a [`retro_core_options_v2`] struct, containing
/// of two pointers:
/// - [`retro_core_options_v2::categories`] is an array of
/// [`retro_core_option_v2_category`] structs terminated by a
/// `{ NULL, NULL, NULL }` element. If [`retro_core_options_v2::categories`]
/// is `NULL , all core options will have no category and will be shown
/// at the top level of the frontend core option interface. If frontend
/// does not have core option category support, categories array will
/// be ignored.
/// - [`retro_core_options_v2::definitions`] is an array of
/// [`retro_core_option_v2_definition`] structs terminated by a
/// `{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }`
/// element.
///
/// ## [`retro_core_option_v2_category`] notes:
///
/// - [`retro_core_option_v2_category::key`] should contain string
/// that uniquely identifies the core option category. Valid
/// key characters are `[a-z, A-Z, 0-9, _, -]`.
///
/// Namespace collisions with other implementations' category
/// keys are permitted.
/// - [`retro_core_option_v2_category::desc`] should contain a human
/// readable description of the category key.
/// - [`retro_core_option_v2_category::info`] should contain any
/// additional human readable information text that a typical
/// user may need to understand the nature of the core option
/// category.
///
/// ### Example entry:
/// ```c
/// {
/// "advanced_settings",
/// "Advanced",
/// "Options affecting low-level emulation performance and accuracy."
/// }
/// ```
///
/// ## [`retro_core_option_v2_definition`] notes:
///
/// - [`retro_core_option_v2_definition::key`] should be namespaced to not
/// collide with other implementations' keys. e.g. A core called
/// `foo` should use keys named as `foo_option`. Valid key characters
/// are `[a-z, A-Z, 0-9, _, -]`.
/// - [`retro_core_option_v2_definition::desc`] should contain a human readable
/// description of the key. Will be used when the frontend does not
/// have core option category support. Examples: `Aspect Ratio` or
/// `Video > Aspect Ratio`.
/// - [`retro_core_option_v2_definition::desc_categorized`] should contain a
/// human readable description of the key, which will be used when
/// frontend has core option category support. Example: `Aspect Ratio`,
/// where associated [`retro_core_option_v2_category::desc`] is `Video`.
///
/// If empty or `NULL`, the string specified by
/// [`retro_core_option_v2_definition::desc`] will be used instead.
///
/// [`retro_core_option_v2_definition::desc_categorized`] will be ignored
/// if [`retro_core_option_v2_definition::category_key`] is empty or `NULL`.
/// - [`retro_core_option_v2_definition::info`] should contain any additional
/// human readable information text that a typical user may need to
/// understand the functionality of the option.
/// - [`retro_core_option_v2_definition::info_categorized`] should contain
/// any additional human readable information text that a typical user
/// may need to understand the functionality of the option, and will be
/// used when frontend has core option category support. This is provided
/// to accommodate the case where info text references an option by
/// name/desc, and the desc/desc_categorized text for that option differ.
///
/// If empty or `NULL`, the string specified by
/// [`retro_core_option_v2_definition::info`] will be used instead.
///
/// [`retro_core_option_v2_definition::info_categorized`] will be ignored
/// if [`retro_core_option_v2_definition::category_key`] is empty or `NULL`.
/// - [`retro_core_option_v2_definition::category_key`] should contain a
/// category identifier (e.g. `video` or `audio`) that will be
/// assigned to the core option if frontend has core option category
/// support. A categorized option will be shown in a subsection/
/// submenu of the frontend core option interface.
///
/// If key is empty or `NULL`, or if key does not match one of the
/// [`retro_core_option_v2_category::key`] values in the associated
/// [`retro_core_option_v2_category`] array, option will have no category
/// and will be shown at the top level of the frontend core option
/// interface.
/// - [`retro_core_option_v2_definition::values`] is an array of
/// retro_core_option_value structs terminated by a `{ NULL, NULL }`
/// element.
///
/// - [`retro_core_option_v2_definition::values[index].value`](retro_core_option_value::value) is an
/// expected option value.
///
/// - [`retro_core_option_v2_definition::values[index].label`](retro_core_option_value::label) is a
/// human readable label used when displaying the value on screen.
/// If `NULL`, the value itself is used.
/// - [`retro_core_option_v2_definition::default_value`] is the default
/// core option setting.
///
/// It must match one of the expected option
/// values in the [`retro_core_option_v2_definition::values`] array.
///
/// If it does not, or the default value is `NULL`, the first entry in the
/// [`retro_core_option_v2_definition::values`] array is treated as the
/// default.
///
/// The number of possible option values should be very limited,
/// and must be less than [`RETRO_NUM_CORE_OPTION_VALUES_MAX`].
/// i.e. it should be feasible to cycle through options
/// without a keyboard.
///
/// ### Example entries:
///
/// - Uncategorized:
///
///```c
/// {
/// "foo_option",
/// "Speed hack coprocessor X",
/// NULL,
/// "Provides increased performance at the expense of reduced accuracy.",
/// NULL,
/// NULL,
/// {
/// { "false", NULL },
/// { "true", NULL },
/// { "unstable", "Turbo (Unstable)" },
/// { NULL, NULL },
/// },
/// "false"
/// }
///```
///
/// - Categorized:
///
///```c
/// {
/// "foo_option",
/// "Advanced > Speed hack coprocessor X",
/// "Speed hack coprocessor X",
/// "Setting 'Advanced > Speed hack coprocessor X' to 'true' or 'Turbo' provides increased performance at the expense of reduced accuracy",
/// "Setting 'Speed hack coprocessor X' to 'true' or 'Turbo' provides increased performance at the expense of reduced accuracy",
/// "advanced_settings",
/// {
/// { "false", NULL },
/// { "true", NULL },
/// { "unstable", "Turbo (Unstable)" },
/// { NULL, NULL },
/// },
/// "false"
/// }
///```
///
/// Only strings are operated on. The possible values will
/// generally be displayed and stored as-is by the frontend.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_core_options_v2(
callback: retro_environment_t,
options: &retro_core_options_v2,
) -> bool {
// const struct retro_core_options_v2 *
set_ptr(
callback,
RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
options as *const _,
)
.unwrap_or(false)
}
/// Allows an implementation to signal the environment
/// which variables it might want to check for later using
/// [`get_variable`].
///
/// This allows the frontend to present these variables to
/// a user dynamically.
///
/// This should only be called if [`get_core_options_version`]
/// returns an API version of `>= 1`.
///
/// This should be called instead of [`set_variables`].
///
/// This should be called instead of [`set_core_options`].
///
/// This should be called the first time as early as
/// possible (ideally in [`Core::on_set_environment`]).
///
/// Afterwards it may be called again for the core to communicate
/// updated options to the frontend, but the number of core
/// options must not change from the number in the initial call.
///
/// This is fundamentally the same as [`set_core_options`],
/// with the addition of localisation support. The description of
/// [`set_core_options`] callback should be consulted for further details.
///
/// 'data' points to a [`retro_core_options_intl`] struct.
///
/// [`retro_core_options_intl::us`] is a pointer to an array of
/// [`retro_core_option_definition`] structs defining the US English
/// core options implementation. It must point to a valid array.
///
/// [`retro_core_options_intl::local`] is a pointer to an array of
/// [`retro_core_option_definition`] structs defining core options for
/// the current frontend language. It may be `NULL` (in which case
/// [`retro_core_options_intl::us`] is used by the frontend). Any items
/// missing from this array will be read from [`retro_core_options_intl::us`]
/// instead.
///
/// NOTE: Default core option values are always taken from the
/// [`retro_core_options_intl::us`] array. Any default values in
/// [`retro_core_options_intl::local`] array will be ignored.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_core_options_intl(
callback: retro_environment_t,
options: retro_core_options_intl,
) -> bool {
// const struct retro_core_options_intl *
set(callback, RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, options).unwrap_or(false)
}
/// Allows an implementation to signal the environment
/// which variables it might want to check for later using
/// [`get_variable`].
///
/// This allows the frontend to present these variables to
/// a user dynamically.
///
/// This should only be called if [`get_core_options_version`]
/// returns an API version of >= 2.
///
/// This should be called instead of [`set_variables`].
///
/// This should be called instead of [`set_core_options`].
///
/// This should be called instead of [`set_core_options_intl`].
///
/// This should be called instead of [`set_core_options_v2`].
///
/// This should be called the first time as early as
/// possible (ideally in [`Core::on_set_environment`]).
///
/// Afterwards it may be called again for the core to communicate
/// updated options to the frontend, but the number of core
/// options must not change from the number in the initial call.
///
/// If [`get_core_options_version`] returns an API
/// version of `>= 2`, this callback is guaranteed to succeed
/// (i.e. callback return value does not indicate success)
///
/// If callback returns [`true`], frontend has core option category
/// support.
///
/// If callback returns [`false`], frontend does not have core option
/// category support.
///
/// This is fundamentally the same as [`set_core_options_v2`],
/// with the addition of localisation support. The description of the
/// [`set_core_options_v2`] callback should be consulted
/// for further details.
///
/// 'data' points to a [`retro_core_options_v2_intl`] struct.
///
/// - [`retro_core_options_v2_intl::us`] is a pointer to a
/// [`retro_core_options_v2`] struct defining the US English
/// core options implementation. It must point to a valid struct.
///
/// - [`retro_core_options_v2_intl::local`] is a pointer to a
/// [`retro_core_options_v2`] struct defining core options for
/// the current frontend language.
///
/// It may be `NULL` (in which case [`retro_core_options_v2_intl::us`] is used by the frontend).
/// Any items missing from this struct will be read from
/// [`retro_core_options_v2_intl::us`] instead.
///
/// NOTE: Default core option values are always taken from the
/// [`retro_core_options_v2_intl::us`] struct. Any default values in
/// the [`retro_core_options_v2_intl::local`] struct will be ignored.
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_core_options_v2_intl(
callback: retro_environment_t,
options: retro_core_options_v2_intl,
) -> bool {
// const struct retro_core_options_v2_intl *
set(
callback,
RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
options,
)
.unwrap_or(false)
}
/// Allows an implementation to signal the environment to show
/// or hide a variable when displaying core options. This is
/// considered a **suggestion**. The frontend is free to ignore
/// this callback, and its implementation not considered mandatory.
///
/// 'data' points to a [`retro_core_option_display`] struct
///
/// [`retro_core_option_display::key`] is a variable identifier
/// which has already been set by [`set_variables`] / [`set_core_options`].
///
/// [`retro_core_option_display::visible`] is a boolean, specifying
/// whether variable should be displayed
///
/// Note that all core option variables will be set visible by
/// default when calling [`set_variables`] / [`set_core_options`].
#[proc::context(GenericContext)]
pub unsafe fn set_core_options_display(
callback: retro_environment_t,
options: retro_core_option_display,
) -> bool {
// struct retro_core_option_display *
set(
callback,
RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY,
options,
)
.unwrap_or(false)
}
/// Allows an implementation to ask frontend preferred hardware
/// context to use. Core should use this information to deal
/// with what specific context to request with SET_HW_RENDER.
///
/// 'data' points to an unsigned variable
#[proc::context(GenericContext)]
pub unsafe fn get_preferred_hw_render(callback: retro_environment_t) -> u32 {
// unsigned *
get(callback, RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER)
.map(|(v, _)| v)
.unwrap_or(0)
}
/// Unsigned value is the API version number of the disk control
/// interface supported by the frontend. If callback return false,
/// API version is assumed to be 0.
///
/// In legacy code, the disk control interface is defined by passing
/// a struct of type [`retro_disk_control_callback] to
/// [`set_disk_control_interface`].
/// This may be still be done regardless of the disk control
/// interface version.
///
/// If version is >= 1 however, the disk control interface may
/// instead be defined by passing a struct of type
/// [`retro_disk_control_ext_callback`] to
/// [`set_disk_control_ext_interface`].
/// This allows the core to provide additional information about
/// disk images to the frontend and/or enables extra
/// disk control functionality by the frontend.
#[proc::context(GenericContext)]
pub unsafe fn get_disk_control_interface_version(callback: retro_environment_t) -> u32 {
// unsigned *
get(
callback,
RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION,
)
.map(|(v, _)| v)
.unwrap_or(0)
}
/// Sets an interface which frontend can use to eject and insert
/// disk images, and also obtain information about individual
/// disk image files registered by the core.
/// This is used for games which consist of multiple images and
/// must be manually swapped out by the user (e.g. PSX, floppy disk
/// based systems).
#[proc::context(GenericContext)]
pub unsafe fn set_disk_control_ext_interface(
callback: retro_environment_t,
data: retro_disk_control_ext_callback,
) -> bool {
// const struct retro_disk_control_ext_callback *
set(
callback,
RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE,
data,
)
.unwrap_or(false)
}
/// The returned value is the API version number of the message
/// interface supported by the frontend.
/// If the underlying callback failed, API version is assumed to be 0.
///
/// In legacy code, messages may be displayed in an
/// implementation-specific manner by passing a struct
/// of type retro_message to [`set_message`].
/// This may be still be done regardless of the message
/// interface version.
///
/// If version is >= 1 however, messages may instead be
/// displayed by calling [`set_message_ext`].
/// This allows the core to specify message logging level, priority and
/// destination (OSD, logging interface or both).
#[proc::context(GenericContext)]
pub unsafe fn get_message_interface_version(callback: retro_environment_t) -> u32 {
// unsigned *
get(callback, RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION)
.map(|(v, _)| v)
.unwrap_or(0)
}
/// Sets a message to be displayed in an implementation-specific
/// manner for a certain duration of milliseconds.
/// Additionally allows the core to specify message logging level, priority and
/// destination (OSD, logging interface or both).
/// Should not be used for trivial messages, which should simply be
/// logged via [`RETRO_ENVIRONMENT_GET_LOG_INTERFACE`] (or as a fallback, stderr).
#[allow(clippy::too_many_arguments)]
#[proc::context(GenericContext)]
pub unsafe fn set_message_ext(
callback: retro_environment_t,
message: &str,
duration: u32,
priority: u32,
level: retro_log_level,
target: retro_message_target,
type_: retro_message_type,
progress: MessageProgress,
) -> bool {
let msg = CString::new(message).unwrap();
// const struct retro_message_ext *
set(
callback,
RETRO_ENVIRONMENT_SET_MESSAGE_EXT,
retro_message_ext {
msg: msg.as_ptr(),
duration,
priority,
level,
target,
type_,
progress: progress.as_i8(),
},
)
.unwrap_or(false)
}
/// The first returned value is the number of active input devices
/// provided by the frontend. This may change between
/// frames, but will remain constant for the duration
/// of each frame.
///
/// If the second return value is [`true`], a core does not need to
/// poll any input device with an index greater than or equal to
/// the number of active devices.
///
/// If the second return value is [`false`], the number of active input
/// devices is unknown. In this case, all input devices
/// should be considered active.
#[proc::context(GenericContext)]
pub unsafe fn get_input_max_users(callback: retro_environment_t) -> (u32, bool) {
// unsigned *
get(callback, RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS).unwrap_or((0, false))
}
/// Lets the core know the occupancy level of the frontend
/// audio buffer. Can be used by a core to attempt frame
/// skipping in order to avoid buffer under-runs.
/// A core may pass `NULL` to disable buffer status reporting
/// in the frontend.
#[proc::context(GenericContext)]
pub unsafe fn set_audio_buffer_status_callback(
callback: retro_environment_t,
data: retro_audio_buffer_status_callback,
) -> bool {
// const struct retro_audio_buffer_status_callback *
set(
callback,
RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK,
data,
)
.unwrap_or(false)
}
/// Sets minimum frontend audio latency in milliseconds.
/// Resultant audio latency may be larger than set value,
/// or smaller if a hardware limit is encountered. A frontend
/// is expected to honour requests up to 512 ms.
///
/// * If value is less than current frontend
/// audio latency, callback has no effect
/// * If value is zero, default frontend audio
/// latency is set
///
/// May be used by a core to increase audio latency and
/// therefore decrease the probability of buffer under-runs
/// (crackling) when performing 'intensive' operations.
/// A core utilising [`RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK`]
/// to implement audio-buffer-based frame skipping may achieve
/// optimal results by setting the audio latency to a 'high'
/// (typically 6x or 8x) integer multiple of the expected
/// frame time.
///
/// Calling this can require a full reinitialization of audio
/// drivers in the frontend, so it is important to call it very
/// sparingly, and usually only with the users explicit consent.
/// An eventual driver reinitialize will happen so that audio
/// callbacks happening after this call within the same [`Core::on_run`]
/// call will target the newly initialized driver.
#[proc::context(RunContext)]
pub unsafe fn set_minimum_audio_latency(callback: retro_environment_t, latency: u32) -> bool {
// const unsigned *
set(
callback,
RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY,
latency,
)
.unwrap_or(false)
}
/// Checks whether the frontend supports the [`set_fastforwarding_override`] interface.
#[proc::context(GenericContext)]
pub unsafe fn supports_fastforwarding_override(callback: retro_environment_t) -> bool {
// const struct retro_fastforwarding_override *
set_ptr(
callback,
RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE,
std::ptr::null() as *const c_void,
)
.unwrap_or(false)
}
/// Used by a libretro core to override the current
/// fastforwarding mode of the frontend.
#[proc::context(GenericContext)]
pub unsafe fn set_fastforwarding_override(
callback: retro_environment_t,
value: retro_fastforwarding_override,
) -> bool {
// const struct retro_fastforwarding_override *
set(
callback,
RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE,
value,
)
.unwrap_or(false)
}
/// Allows an implementation to override 'global' content
/// info parameters reported by [`Core::get_info`].
/// Overrides also affect subsystem content info parameters
/// set via [`set_subsystem_info`].
/// This function must be called inside [`Core::on_set_environment`].
/// If callback returns [`false`], content info overrides
/// are unsupported by the frontend, and will be ignored.
/// If callback returns [`true`], extended game info may be
/// retrieved by calling [`get_game_info_ext`]
/// in [`Core::on_load_game`] or [`Core::on_load_game_special`].
///
/// 'data' points to an array of [`retro_system_content_info_override`]
/// structs terminated by a `{ NULL, false, false }` element.
/// If 'data' is `NULL`, no changes will be made to the frontend;
/// a core may therefore pass `NULL` in order to test whether
/// the [`set_content_info_override`] and
/// [`get_game_info_ext`] callbacks are supported
/// by the frontend.
///
/// For struct member descriptions, see the definition of
/// struct [`retro_system_content_info_override`].
///
/// Example:
///
/// - struct retro_system_info:
/// ```c
/// {
/// "My Core", // library_name
/// "v1.0", // library_version
/// "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
/// true, // need_fullpath
/// false // block_extract
/// }
/// ```
///
/// - Array of struct retro_system_content_info_override:
/// ```c
/// {
/// {
/// "md|sms|gg", // extensions
/// false, // need_fullpath
/// true // persistent_data
/// },
/// {
/// "sg", // extensions
/// false, // need_fullpath
/// false // persistent_data
/// },
/// { NULL, false, false }
/// }
/// ```
///
/// Result:
/// - Files of type `m3u`, `cue`, `iso`, `chd` will not be
/// loaded by the frontend. Frontend will pass a
/// valid path to the core, and core will handle
/// loading internally
/// - Files of type `md`, `sms`, `gg` will be loaded by
/// the frontend. A valid memory buffer will be
/// passed to the core. This memory buffer will
/// remain valid until [`Core::on_deinit`] returns
/// - Files of type `sg` will be loaded by the frontend.
/// A valid memory buffer will be passed to the core.
/// This memory buffer will remain valid until
/// [`Core::on_load_game`] (or [`Core::on_load_game_special`])
/// returns
///
/// NOTE: If an extension is listed multiple times in
/// an array of [`retro_system_content_info_override`]
/// structs, only the **first** instance will be registered
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_content_info_override(
callback: retro_environment_t,
value: retro_system_content_info_override,
) -> bool {
// const struct retro_system_content_info_override *
set(callback, RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE, value).unwrap_or(false)
}
/// Allows an implementation to fetch extended game
/// information, providing additional content path
/// and memory buffer status details.
/// This function may only be called inside
/// [`Core::on_load_game`] or [`Core::on_load_game_special`].
///
/// If callback returns `false`, extended game information
/// is unsupported by the frontend. In this case, only
/// regular [`retro_game_info`] will be available.
/// [`get_game_info_ext`] is guaranteed
/// to return true if [`set_content_info_override`]
/// returns [`true`].
///
/// 'data' points to an array of [`retro_game_info_ext structs`].
///
/// For struct member descriptions, see the definition of
/// struct [`retro_game_info_ext`].
///
/// - If function is called inside [`Core::on_load_game`],
/// the [`retro_game_info_ext`] array is guaranteed to
/// have a size of 1 - i.e. the returned pointer may
/// be used to access directly the members of the
/// first [`retro_game_info_ext`] struct, for example:
///
/// ```c
/// struct retro_game_info_ext *game_info_ext;
/// if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext))
/// printf("Content Directory: %s\n", game_info_ext->dir);
///```
///
/// - If the function is called inside [`Core::on_load_game_special`],
/// the [`retro_game_info_ext`] array is guaranteed to have a
/// size equal to the `num_info` argument passed to
/// [`Core::on_load_game_special`]
#[proc::context(LoadGameContext)]
#[proc::context(LoadGameSpecialContext)]
pub unsafe fn get_game_info_ext(callback: retro_environment_t) -> Option<retro_game_info_ext> {
// const struct retro_game_info_ext **
if let Some((v, true)) = get_unchecked(callback, RETRO_ENVIRONMENT_GET_GAME_INFO_EXT) {
Some(v)
} else {
None
}
}
/// Allows a frontend to signal that a core must update
/// the visibility of any dynamically hidden core options,
/// and enables the frontend to detect visibility changes.
///
/// Used by the frontend to update the menu display status
/// of core options without requiring a call of [`Core::on_run`].
/// Must be called in [`Core::on_set_environment`].
#[proc::context(SetEnvironmentContext)]
pub unsafe fn set_core_options_update_display_callback(
callback: retro_environment_t,
data: retro_core_options_update_display_callback,
) -> bool {
// const struct retro_core_options_update_display_callback *
set(
callback,
RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK,
data,
)
.unwrap_or(false)
}
/// Allows an implementation to notify the frontend
/// that a core option value has changed.
///
/// [`retro_variable::key`] and [`retro_variable::value`]
/// must match strings that have been set previously
/// via one of the following:
///
/// - [`set_variables`]
/// - [`set_core_options`]
/// - [`set_core_options_intl`]
/// - [`set_core_options_v2`]
/// - [`set_core_options_v2_intl`]
///
/// After changing a core option value via this
/// callback, [`get_variable_update`]
/// will return [`true`].
///
/// If data is `NULL`, no changes will be registered
/// and the callback will return [`true`]; an
/// implementation may therefore pass `NULL` in order
/// to test whether the callback is supported.
#[proc::context(GenericContext)]
pub unsafe fn set_variable(callback: retro_environment_t, value: retro_variable) -> bool {
// const struct retro_variable *
set(callback, RETRO_ENVIRONMENT_SET_VARIABLE, value).unwrap_or(false)
}
/// Allows an implementation to get details on the actual rate
/// the frontend is attempting to call [`Core::on_run`].
#[proc::context(GenericContext)]
#[proc::unstable(feature = "env-commands")]
pub unsafe fn get_throttle_state(callback: retro_environment_t) -> Option<retro_throttle_state> {
// struct retro_throttle_state *
get_unchecked(callback, RETRO_ENVIRONMENT_GET_THROTTLE_STATE).map(|(v, _)| v)
}
