Compare commits
763 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
7b5c19ff5e | |
![]() |
709237c79c | |
![]() |
b753f6eefa | |
![]() |
aaa6c15475 | |
![]() |
dccefede9b | |
![]() |
17652d9348 | |
![]() |
d9d4ea0ad4 | |
![]() |
d67ac42bbc | |
![]() |
60e07663d1 | |
![]() |
4c8740f309 | |
![]() |
acaeed8322 | |
![]() |
37e02b5a69 | |
![]() |
d4f3187ee0 | |
![]() |
122409e6f8 | |
![]() |
34e4439729 | |
![]() |
9b0c8c18de | |
![]() |
108478aaab | |
![]() |
175d578c07 | |
![]() |
0852d72dc9 | |
![]() |
e4b4b08c46 | |
![]() |
0197b406b8 | |
![]() |
727917773e | |
![]() |
d4b5cf6659 | |
![]() |
56a82682d5 | |
![]() |
0933f1ae66 | |
![]() |
6dfef64461 | |
![]() |
27b109b483 | |
![]() |
abb92327c0 | |
![]() |
682cdb0e28 | |
![]() |
146bec13ee | |
![]() |
13cf6aaacd | |
![]() |
f744e34687 | |
![]() |
ac64828880 | |
![]() |
f6b1d674db | |
![]() |
6fe0e61332 | |
![]() |
991a6b2447 | |
![]() |
ce37689720 | |
![]() |
18c1b44419 | |
![]() |
09679fb228 | |
![]() |
41fa2922f9 | |
![]() |
e787941351 | |
![]() |
f2164a9637 | |
![]() |
173a87f41b | |
![]() |
5e6ef2eaf7 | |
![]() |
51b8b06e91 | |
![]() |
f77ddc6fee | |
![]() |
6b982c8325 | |
![]() |
c9311529cb | |
![]() |
594380b2f9 | |
![]() |
c003a21362 | |
![]() |
ec8a8df269 | |
![]() |
3faee00fa7 | |
![]() |
02e0ff625b | |
![]() |
dded9debdb | |
![]() |
5d034cec3c | |
![]() |
d55b1aec0d | |
![]() |
01f8382c81 | |
![]() |
d7e9b98951 | |
![]() |
5ef3ebc287 | |
![]() |
14eb4226a5 | |
![]() |
56c18f57f9 | |
![]() |
d91cdcb1ec | |
![]() |
29a3f90648 | |
![]() |
323b6c9721 | |
![]() |
d577e0feeb | |
![]() |
3f70246896 | |
![]() |
0cb4de07f3 | |
![]() |
1c604d6dc2 | |
![]() |
357527370e | |
![]() |
7f3a4d34bb | |
![]() |
d4fd9292e1 | |
![]() |
bdaf399df1 | |
![]() |
78c77d0a9a | |
![]() |
18eeef3be6 | |
![]() |
03a9e858cd | |
![]() |
63bcb3e22f | |
![]() |
bca3892757 | |
![]() |
e0dc373741 | |
![]() |
005fa382cb | |
![]() |
0bc0843adc | |
![]() |
5bd4121064 | |
![]() |
ff4d7f2e9c | |
![]() |
b7ffc112de | |
![]() |
50ea6fd00f | |
![]() |
2dab3fab17 | |
![]() |
414b7947a6 | |
![]() |
df3ebd6fa9 | |
![]() |
1d43d19e36 | |
![]() |
9b631344bc | |
![]() |
50199cac48 | |
![]() |
98be025035 | |
![]() |
b5009a353a | |
![]() |
99fe920390 | |
![]() |
40a6427d25 | |
![]() |
5d27786116 | |
![]() |
5756641f2c | |
![]() |
a5c76df1b2 | |
![]() |
8e3cb19950 | |
![]() |
be04d30134 | |
![]() |
14b93e7b55 | |
![]() |
106413cd87 | |
![]() |
b9ffb761b0 | |
![]() |
8d5cd5d7b1 | |
![]() |
65b56d691a | |
![]() |
1b83ef98f3 | |
![]() |
6b944f258d | |
![]() |
e6aebaa736 | |
![]() |
2f4ce7668b | |
![]() |
17272af6a9 | |
![]() |
ce659c3cd7 | |
![]() |
ab36b0e725 | |
![]() |
20dd7ebeae | |
![]() |
4eb9319150 | |
![]() |
a3bd550cb3 | |
![]() |
9fa896354f | |
![]() |
0e3fc4f3a6 | |
![]() |
c01703ce1f | |
![]() |
e61efe6765 | |
![]() |
9bf342c998 | |
![]() |
cf8d751105 | |
![]() |
563c28dd66 | |
![]() |
417e37c51f | |
![]() |
412225bc04 | |
![]() |
14eac4bc62 | |
![]() |
507702ef25 | |
![]() |
f16c9b4c02 | |
![]() |
b4cb3c54a5 | |
![]() |
76dfe8563d | |
![]() |
74e25cb8e0 | |
![]() |
dd046c4f7c | |
![]() |
434ff28458 | |
![]() |
d8bad1efc7 | |
![]() |
c8ac92ee9f | |
![]() |
e48c8fbedb | |
![]() |
3be7e6e4a7 | |
![]() |
e4a665e7d2 | |
![]() |
7e8c868df7 | |
![]() |
5d68a1fd1c | |
![]() |
4b86397f9c | |
![]() |
24309542e4 | |
![]() |
e574566116 | |
![]() |
190c9c01b0 | |
![]() |
ba1b163f92 | |
![]() |
934fa282ba | |
![]() |
5ce96542cb | |
![]() |
2d83fc0a26 | |
![]() |
bf9515f34d | |
![]() |
4e546f1891 | |
![]() |
752219d4e2 | |
![]() |
428ef20a06 | |
![]() |
34a6b6979b | |
![]() |
54538fa46c | |
![]() |
d4423d40f8 | |
![]() |
a6d47814fd | |
![]() |
4773c53f8f | |
![]() |
151becc4fb | |
![]() |
86bb28d042 | |
![]() |
406f1e6956 | |
![]() |
c3b500ae61 | |
![]() |
7c97728895 | |
![]() |
b367744e0e | |
![]() |
986d631b7c | |
![]() |
75e54fd3ee | |
![]() |
52c51b525f | |
![]() |
9c54139460 | |
![]() |
f0e7b122e8 | |
![]() |
e47b2bb373 | |
![]() |
cfcec77e0b | |
![]() |
3e1bd09b0b | |
![]() |
7d5d19948e | |
![]() |
306ec76786 | |
![]() |
443a14a604 | |
![]() |
341f745684 | |
![]() |
e4e6878fdb | |
![]() |
d7a9ab4110 | |
![]() |
d2f5b74cdd | |
![]() |
32b8bbd32e | |
![]() |
39eb36083b | |
![]() |
b1e31ed032 | |
![]() |
8462cdf6cd | |
![]() |
b537b6d8a9 | |
![]() |
fde5414b24 | |
![]() |
cfaae11366 | |
![]() |
e529fb6690 | |
![]() |
ca3dea0155 | |
![]() |
2f239d90f9 | |
![]() |
0dc1431397 | |
![]() |
17c5d8a9a9 | |
![]() |
1a4d8c442f | |
![]() |
e34ea5c03e | |
![]() |
7a20a87715 | |
![]() |
01bdba70b0 | |
![]() |
1080723095 | |
![]() |
00337b1a3b | |
![]() |
6e24e500db | |
![]() |
86315bb0e4 | |
![]() |
f85d45e8bc | |
![]() |
f0b372ec3a | |
![]() |
68ad6eed1f | |
![]() |
0edc24856e | |
![]() |
3486e3087e | |
![]() |
bca8a9ff07 | |
![]() |
a39ca385ad | |
![]() |
523a812d84 | |
![]() |
9f80be42f2 | |
![]() |
f6e8ccc220 | |
![]() |
a1b7745904 | |
![]() |
a5f9f1d351 | |
![]() |
b29826ee93 | |
![]() |
732d4ea4e1 | |
![]() |
7d2b40672a | |
![]() |
3ad74cdeb9 | |
![]() |
fa4558526d | |
![]() |
0590819119 | |
![]() |
bd44bd2f8f | |
![]() |
dc6a88e61f | |
![]() |
7c4022c30c | |
![]() |
0f9be132e0 | |
![]() |
01f53cec6d | |
![]() |
436f9888a5 | |
![]() |
b38d9ad537 | |
![]() |
204ff51409 | |
![]() |
9be997a0f4 | |
![]() |
25d06c2770 | |
![]() |
923d32268a | |
![]() |
962bddae9b | |
![]() |
80c686fc62 | |
![]() |
15cb626994 | |
![]() |
ae9b558bc5 | |
![]() |
1fb7053411 | |
![]() |
4b80a12661 | |
![]() |
f4837ec174 | |
![]() |
64126610be | |
![]() |
3b018602e2 | |
![]() |
ccfe94d616 | |
![]() |
c8b38099e8 | |
![]() |
28caaa6cc0 | |
![]() |
f6beb2c39a | |
![]() |
6298093c3f | |
![]() |
45fe09d037 | |
![]() |
9d10519857 | |
![]() |
73de4a6258 | |
![]() |
bfe59b00b5 | |
![]() |
37a9c6587d | |
![]() |
0d99e2874b | |
![]() |
2755caaf0f | |
![]() |
d9ab573603 | |
![]() |
2b603a3776 | |
![]() |
78b671e20d | |
![]() |
69feb2fb08 | |
![]() |
0efa910af4 | |
![]() |
d19f9d88aa | |
![]() |
08098d89d4 | |
![]() |
75735c9d0b | |
![]() |
2d1cb7d24c | |
![]() |
13bb5d61bb | |
![]() |
dcaa48565d | |
![]() |
cfb9ebd91a | |
![]() |
cdb923628a | |
![]() |
9a0437aa2f | |
![]() |
fe8c0a0b66 | |
![]() |
3f72999e44 | |
![]() |
f891b9dd0a | |
![]() |
6008bdd48a | |
![]() |
a28c57f93d | |
![]() |
275e4a4f51 | |
![]() |
2beb93b28e | |
![]() |
156626fc1c | |
![]() |
82c975fbae | |
![]() |
f9cd1f0dc5 | |
![]() |
085e1737b3 | |
![]() |
8217b08128 | |
![]() |
5fd6e2328b | |
![]() |
cb80c00629 | |
![]() |
fdc1f106f8 | |
![]() |
7ea1cc650f | |
![]() |
4d67dcbaf7 | |
![]() |
5ec4915301 | |
![]() |
36f3f26ffa | |
![]() |
78ff25f0f9 | |
![]() |
43debd45d5 | |
![]() |
017a4d1444 | |
![]() |
45acce752d | |
![]() |
20f714c5d5 | |
![]() |
a0a0232f4d | |
![]() |
b57549e029 | |
![]() |
305ad0551a | |
![]() |
6920160d81 | |
![]() |
6e260274d9 | |
![]() |
5bf3dba8c9 | |
![]() |
4446232c6a | |
![]() |
55251c6507 | |
![]() |
18ff42d25f | |
![]() |
6d5235c1b8 | |
![]() |
01c5ac3a33 | |
![]() |
268f357b13 | |
![]() |
3db62a8f3b | |
![]() |
359f40028e | |
![]() |
1c3fcebc4b | |
![]() |
74855eee78 | |
![]() |
52fd4b8393 | |
![]() |
212b023ac8 | |
![]() |
1aee7b9246 | |
![]() |
d89b74b36c | |
![]() |
264dcf884b | |
![]() |
86f847115f | |
![]() |
08abd79850 | |
![]() |
5fc82a66b2 | |
![]() |
95d3be60f0 | |
![]() |
41abca8a29 | |
![]() |
822837aefd | |
![]() |
15cb66df0e | |
![]() |
580b86904b | |
![]() |
01a0941ffb | |
![]() |
c902f94e99 | |
![]() |
7f8a1f9e8a | |
![]() |
d87b7b793f | |
![]() |
a4e8a5e4b5 | |
![]() |
780edfe9bd | |
![]() |
8b79368b2e | |
![]() |
2365f65b2e | |
![]() |
02b204d1b9 | |
![]() |
e9dff90979 | |
![]() |
ba4184fc61 | |
![]() |
942e0659cf | |
![]() |
c44a7abe0a | |
![]() |
bca1f9e2a9 | |
![]() |
bb419a7c69 | |
![]() |
2252be4a86 | |
![]() |
2e2c870e38 | |
![]() |
157ce930ae | |
![]() |
87324ed3fa | |
![]() |
a729d207eb | |
![]() |
175756dd1f | |
![]() |
4e4bf34e62 | |
![]() |
08fa71141f | |
![]() |
eb8985762f | |
![]() |
5a48ed79c5 | |
![]() |
f2350d5d18 | |
![]() |
d7ab11d7d5 | |
![]() |
c315bd6655 | |
![]() |
0d0a5a1ddf | |
![]() |
81d6628bd8 | |
![]() |
c3d4c2c36d | |
![]() |
208aca7e9a | |
![]() |
d36a33098d | |
![]() |
43ff2cd1e2 | |
![]() |
6a4c4668e3 | |
![]() |
687d4ace0e | |
![]() |
201d7da936 | |
![]() |
dcde9bd35b | |
![]() |
85b9738b2a | |
![]() |
aaae28287f | |
![]() |
8aca3ce406 | |
![]() |
06581eb845 | |
![]() |
83c5920810 | |
![]() |
9e5da28a65 | |
![]() |
af7f02f0e9 | |
![]() |
3004121685 | |
![]() |
cd1dc3aea2 | |
![]() |
0a89640b44 | |
![]() |
e11f04fe51 | |
![]() |
972d3e2f0c | |
![]() |
7bd3bf6e39 | |
![]() |
066d948983 | |
![]() |
63543e825a | |
![]() |
2754edd176 | |
![]() |
140657c453 | |
![]() |
4c74e61039 | |
![]() |
ccecfe8717 | |
![]() |
5724632520 | |
![]() |
3d6cb7148f | |
![]() |
5bfa377b00 | |
![]() |
403d6859ea | |
![]() |
d8db5e869e | |
![]() |
7631123e1f | |
![]() |
f1688288d6 | |
![]() |
69969ab866 | |
![]() |
babef459b0 | |
![]() |
37bad6befc | |
![]() |
a8c75b5c5a | |
![]() |
236322c2cb | |
![]() |
6d8101454b | |
![]() |
5d72ba12f7 | |
![]() |
c1ca4db5da | |
![]() |
3ddcc22d10 | |
![]() |
4c19253805 | |
![]() |
b821415cc0 | |
![]() |
11607b69b4 | |
![]() |
3ad95c9ba2 | |
![]() |
e0523ddeeb | |
![]() |
ebb2467f38 | |
![]() |
ee1f0e2999 | |
![]() |
2b025249f5 | |
![]() |
27bf99717d | |
![]() |
5262d66216 | |
![]() |
c6e798b5a0 | |
![]() |
97587960fc | |
![]() |
044bffc806 | |
![]() |
f9d9a3aa68 | |
![]() |
c51d7be893 | |
![]() |
776acc4533 | |
![]() |
44056ef7b3 | |
![]() |
3f1d80deef | |
![]() |
839724cbae | |
![]() |
c0bc013505 | |
![]() |
90d667de43 | |
![]() |
8988df04c9 | |
![]() |
ae8d587f3b | |
![]() |
5c5a1e37bf | |
![]() |
fc34df3516 | |
![]() |
e7f15ba665 | |
![]() |
cc818ed9c5 | |
![]() |
32cbd2c38f | |
![]() |
991de73177 | |
![]() |
229c5ab1f7 | |
![]() |
ac1bbf7183 | |
![]() |
6acb7a6412 | |
![]() |
3782a4fe7e | |
![]() |
2202f58901 | |
![]() |
6b38bc3f5a | |
![]() |
56d6cb8926 | |
![]() |
8d8bea8525 | |
![]() |
5fb2cc8d8c | |
![]() |
868a3eeef3 | |
![]() |
aaa10ea414 | |
![]() |
7f9a595c22 | |
![]() |
beef0bd457 | |
![]() |
4e60a6b0db | |
![]() |
d8636f764b | |
![]() |
3714f634da | |
![]() |
4a74ea10fc | |
![]() |
08c4c68b74 | |
![]() |
e25c427557 | |
![]() |
0d8f62c996 | |
![]() |
6cff524e32 | |
![]() |
0fe232ffd3 | |
![]() |
26d0eb5c01 | |
![]() |
ded5074d11 | |
![]() |
db7fd59423 | |
![]() |
608ed4f748 | |
![]() |
95c49d764b | |
![]() |
abd4e5c8d9 | |
![]() |
868b2fd7cb | |
![]() |
9659a0a9af | |
![]() |
07cf16aa27 | |
![]() |
ef55d93525 | |
![]() |
f572ab0946 | |
![]() |
33cd6bf4f2 | |
![]() |
f0bd196372 | |
![]() |
479a077e0e | |
![]() |
9b65e6a2e4 | |
![]() |
d8ee31ec1f | |
![]() |
307b36b8c4 | |
![]() |
6c6eaed995 | |
![]() |
c10bc4d83e | |
![]() |
76eec054a6 | |
![]() |
3bcce2c481 | |
![]() |
7e20db0210 | |
![]() |
d0e066eb22 | |
![]() |
a3fa688819 | |
![]() |
aa38cb79b6 | |
![]() |
99cb62f6d3 | |
![]() |
197203e8f6 | |
![]() |
989fecc351 | |
![]() |
6726089791 | |
![]() |
7e41759b04 | |
![]() |
10b133c50f | |
![]() |
fe99919dd0 | |
![]() |
920d9ce91f | |
![]() |
55099ecbdd | |
![]() |
fc3b983080 | |
![]() |
3faefe7c46 | |
![]() |
492fce7645 | |
![]() |
22fd81aa7d | |
![]() |
3a389752bd | |
![]() |
bda42c3236 | |
![]() |
dd3d18ce8a | |
![]() |
f6087efe92 | |
![]() |
38d790b552 | |
![]() |
24942e2c20 | |
![]() |
38c45e0fee | |
![]() |
a3c862900d | |
![]() |
e7b0fcc45c | |
![]() |
4d8d30bd96 | |
![]() |
336a0bf22a | |
![]() |
e21a0400f4 | |
![]() |
1f2e9bbb28 | |
![]() |
74a3b42903 | |
![]() |
9c16cccdef | |
![]() |
8a4d629061 | |
![]() |
27f1968ef6 | |
![]() |
af526c0288 | |
![]() |
ada36cd3d7 | |
![]() |
db75df51b4 | |
![]() |
ec982482aa | |
![]() |
7779dea09b | |
![]() |
18afccf2b8 | |
![]() |
6e1bc4c77c | |
![]() |
c51b372a53 | |
![]() |
a0ee07fdc3 | |
![]() |
bdffdd7b9d | |
![]() |
ca59a8f3c8 | |
![]() |
e2fc5010bf | |
![]() |
61f8e202e7 | |
![]() |
1252d1da94 | |
![]() |
c81bdf642b | |
![]() |
d5f77514ab | |
![]() |
5efaebca76 | |
![]() |
200caa8423 | |
![]() |
3a5ec79227 | |
![]() |
c2a80ada0e | |
![]() |
ba5630e50b | |
![]() |
204a865da4 | |
![]() |
301f20889e | |
![]() |
217f52822d | |
![]() |
d428c6ac9a | |
![]() |
2dba71290d | |
![]() |
64ed418bb5 | |
![]() |
02d7b85fd9 | |
![]() |
eaca65d452 | |
![]() |
8637c11338 | |
![]() |
e407fd9d17 | |
![]() |
7c3200500e | |
![]() |
b382878d0e | |
![]() |
06699aafa0 | |
![]() |
e2534af4e8 | |
![]() |
50a2823da6 | |
![]() |
1966a9b805 | |
![]() |
8c7d8931f2 | |
![]() |
80d0db751f | |
![]() |
859dacdf63 | |
![]() |
bc12f241e5 | |
![]() |
262c2c18f7 | |
![]() |
fef3437579 | |
![]() |
8ca1fc5ad5 | |
![]() |
3e23e2f8bf | |
![]() |
2cdb52d1fa | |
![]() |
3370ca4afc | |
![]() |
e9efdbc3a1 | |
![]() |
f677acf273 | |
![]() |
e5bb3c9ff8 | |
![]() |
2efbca4ef8 | |
![]() |
6e86a2472f | |
![]() |
d02f06e6a3 | |
![]() |
746619a177 | |
![]() |
62ad70bed5 | |
![]() |
2761ffa793 | |
![]() |
36c0457cb3 | |
![]() |
380169f23c | |
![]() |
a0787d92da | |
![]() |
6293372122 | |
![]() |
05679d604e | |
![]() |
51f8d904d2 | |
![]() |
46f2b6aac0 | |
![]() |
1bbcd07da0 | |
![]() |
752b779699 | |
![]() |
ceb3ba9fd3 | |
![]() |
7febd63f99 | |
![]() |
06934fa8d0 | |
![]() |
4c09d07e07 | |
![]() |
2bfb885e87 | |
![]() |
75c6efbe9c | |
![]() |
9bf2373e71 | |
![]() |
4a62657cd3 | |
![]() |
62f48dc662 | |
![]() |
c48d878a20 | |
![]() |
78a6b00dde | |
![]() |
074c169c8c | |
![]() |
26610f44d9 | |
![]() |
5748de3833 | |
![]() |
4f39859c49 | |
![]() |
885b5e971a | |
![]() |
d8b2877649 | |
![]() |
3337086601 | |
![]() |
4302488754 | |
![]() |
f05aeb3e46 | |
![]() |
db185d326c | |
![]() |
65e4959a75 | |
![]() |
7914f4a1b3 | |
![]() |
ecfc678a18 | |
![]() |
38dc5173ec | |
![]() |
93df53e751 | |
![]() |
4ef65aa88b | |
![]() |
d6f1973688 | |
![]() |
963c7866dc | |
![]() |
f6762cb96d | |
![]() |
ae5b448478 | |
![]() |
75f93c566b | |
![]() |
2d7aa7cbb8 | |
![]() |
8ff021d1f8 | |
![]() |
dc888cf888 | |
![]() |
031eb78fd8 | |
![]() |
44161326ad | |
![]() |
7736d65c84 | |
![]() |
bd51fbdac5 | |
![]() |
7fd7f4df10 | |
![]() |
ae75b94f23 | |
![]() |
3ed08681ef | |
![]() |
c8192955b3 | |
![]() |
edc82b3888 | |
![]() |
27f84976da | |
![]() |
5f1d6ee028 | |
![]() |
13e74507cb | |
![]() |
9b62b15637 | |
![]() |
ce533245cf | |
![]() |
64bcd660b2 | |
![]() |
9406bc7c6b | |
![]() |
8682b5bda0 | |
![]() |
ad8e5eb3f7 | |
![]() |
2a6fdcdb3d | |
![]() |
7a39ca8b6e | |
![]() |
7655f7cd8a | |
![]() |
79efea994a | |
![]() |
d6acadc329 | |
![]() |
aebc097e95 | |
![]() |
72c6e69bf0 | |
![]() |
f98fef11db | |
![]() |
b927f214f3 | |
![]() |
d0c94e5e14 | |
![]() |
ce684daacc | |
![]() |
26d6f0db69 | |
![]() |
37f8a5595f | |
![]() |
af5272cff4 | |
![]() |
077366f34b | |
![]() |
2208460aee | |
![]() |
0330545769 | |
![]() |
67a55e5769 | |
![]() |
ca2542d3a1 | |
![]() |
8978295e84 | |
![]() |
397d7a003e | |
![]() |
a77569d1e5 | |
![]() |
35bebad0f8 | |
![]() |
40c77bba71 | |
![]() |
0d5bc7e7ac | |
![]() |
fb0736b2e0 | |
![]() |
4f1b1ab97e | |
![]() |
87eee88752 | |
![]() |
497cf09a98 | |
![]() |
cd147492be | |
![]() |
f753d47c71 | |
![]() |
6924a3d159 | |
![]() |
c7cac63a38 | |
![]() |
d54e7f34fe | |
![]() |
574b60588b | |
![]() |
287a035440 | |
![]() |
9b1238464e | |
![]() |
8e246e200c | |
![]() |
d0fad1091a | |
![]() |
74c0613147 | |
![]() |
02a8970bb6 | |
![]() |
5f0ded46ce | |
![]() |
371c369ae4 | |
![]() |
59c1b21b01 | |
![]() |
b8812d7b6b | |
![]() |
c8b3bd8ba0 | |
![]() |
99d81cc58c | |
![]() |
98b06cffc0 | |
![]() |
d6c1481d17 | |
![]() |
4b79864ccc | |
![]() |
21f1154c07 | |
![]() |
9179a5b1f0 | |
![]() |
2048c8f2a6 | |
![]() |
af50ea273c | |
![]() |
109d36a1c2 | |
![]() |
3e59afb4cf | |
![]() |
7f86868cbe | |
![]() |
84a63da5da | |
![]() |
85c6172224 | |
![]() |
72a4254272 | |
![]() |
4dfdc1b0f8 | |
![]() |
8063a3dacd | |
![]() |
17a29dec98 | |
![]() |
2a6adb536e | |
![]() |
a117ebd31e | |
![]() |
ec7d93b065 | |
![]() |
df59607b4d | |
![]() |
66dbd35807 | |
![]() |
4fdf485020 | |
![]() |
ded7982835 | |
![]() |
c3586060df | |
![]() |
53fd31408f | |
![]() |
2ae4cc49e4 | |
![]() |
2b37ae9ca6 | |
![]() |
0184fc34d2 | |
![]() |
1c42ef7ebb | |
![]() |
633735e085 | |
![]() |
b7722796a5 | |
![]() |
9a04d5275f | |
![]() |
83a7337bc5 | |
![]() |
cfaf737e92 | |
![]() |
7c5ab476da | |
![]() |
af728db149 | |
![]() |
241ee4803e | |
![]() |
7b7cf84594 | |
![]() |
93beb78754 | |
![]() |
a57ca5edc1 | |
![]() |
be5ea25619 | |
![]() |
bba721375d | |
![]() |
5598490601 | |
![]() |
81bc5188f5 | |
![]() |
a54163dbf7 | |
![]() |
576f1cb6fe | |
![]() |
c9ea1aa791 | |
![]() |
a9e63c1349 | |
![]() |
2998131b74 | |
![]() |
6d0cb6d458 | |
![]() |
ea84f0a194 | |
![]() |
1a309235b8 | |
![]() |
df2330989d | |
![]() |
82a5106b85 | |
![]() |
65c5498cda | |
![]() |
f2e465c969 | |
![]() |
7810b9f575 | |
![]() |
76659c10de | |
![]() |
4b73c9486c | |
![]() |
9355ac7fc9 | |
![]() |
eb1fe32c0a | |
![]() |
c648706e82 | |
![]() |
c43c6ad5be | |
![]() |
7590b9bad2 | |
![]() |
1883c5ab58 | |
![]() |
59fe1888c4 | |
![]() |
c9181e5add | |
![]() |
731432d676 | |
![]() |
70daa0868a | |
![]() |
999f9bfd5b | |
![]() |
25dd887283 | |
![]() |
6f5d4e3fff | |
![]() |
809119ff46 | |
![]() |
2697c7bd47 | |
![]() |
e88797253e | |
![]() |
0ef63d4b79 | |
![]() |
78e859725e | |
![]() |
5e4a8b66d3 | |
![]() |
a6746103ec | |
![]() |
87da2de653 | |
![]() |
bc5aaac936 | |
![]() |
ffec4ea576 | |
![]() |
2ca38d65bb | |
![]() |
a1f6194c53 | |
![]() |
b8527cd5ef | |
![]() |
5b736d13d9 | |
![]() |
84c391e17d | |
![]() |
526544e355 | |
![]() |
cd129decfc | |
![]() |
5b3c4eb2d1 | |
![]() |
a5d79817ef | |
![]() |
fd3915af18 | |
![]() |
4c243b6738 | |
![]() |
0a81ecc574 | |
![]() |
c7f4dacc69 | |
![]() |
e0c1aecfc3 | |
![]() |
358140dbf4 | |
![]() |
37c090d649 | |
![]() |
ec2b531f45 | |
![]() |
192897354d | |
![]() |
40206d8af8 | |
![]() |
70d15a5629 | |
![]() |
6a38fcef05 | |
![]() |
3521f60225 | |
![]() |
93f6635ea8 | |
![]() |
32e726b5f4 |
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
name: Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
|
||||
- name: Install SDL2
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libsdl2-dev
|
||||
- name: Build Stella
|
||||
run: |
|
||||
./configure && make -j2 all
|
||||
|
||||
macos:
|
||||
name: macOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: '16.2'
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
|
||||
- name: Install SDL2
|
||||
run: |
|
||||
curl https://www.libsdl.org/release/SDL2-2.26.0.tar.gz | tar xzf -
|
||||
mkdir SDL2-2.26.0/build
|
||||
cd SDL2-2.26.0/build
|
||||
../configure && make -j3 && sudo make install
|
||||
- name: Build Stella
|
||||
run: |
|
||||
./configure && make -j3 all
|
||||
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [x64]
|
||||
env:
|
||||
Platform: ${{ matrix.platform }}
|
||||
SDL2_version: 2.26.0
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
|
||||
- name: Set up MSBUILD
|
||||
uses: microsoft/setup-msbuild@34cfbaee7f672c76950673338facd8a73f637506
|
||||
- name: Install SDL2
|
||||
shell: cmd
|
||||
run: |
|
||||
curl -o "C:\SDL2-devel.zip" "https://www.libsdl.org/release/SDL2-devel-%SDL2_version%-VC.zip"
|
||||
7z x "C:\SDL2-devel.zip" -o"C:\"
|
||||
xcopy /S "C:\SDL2-%SDL2_version%\include" src\common
|
||||
if %Platform%==x64 xcopy /S "C:\SDL2-%SDL2_version%\lib\x64" src\os\windows
|
||||
|
||||
- name: Build Stella
|
||||
run: |
|
||||
msbuild src\os\windows\Stella.sln
|
|
@ -10,7 +10,9 @@ src/**/*.tlog
|
|||
out
|
||||
out.pgo
|
||||
out.pgen
|
||||
out.test
|
||||
stella
|
||||
stella-test
|
||||
stella-pgo
|
||||
stella-pgo-generate
|
||||
*.diff
|
||||
|
@ -18,17 +20,17 @@ project.xcworkspace/
|
|||
xcuserdata/
|
||||
.DS_Store
|
||||
build/
|
||||
src/macosx/M6502.ins
|
||||
src/os/macos/M6502.ins
|
||||
*.dSYM
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/settings.json
|
||||
src/windows/sdl/*
|
||||
src/windows/x64/*
|
||||
src/windows/Win32/*
|
||||
src/windows/Stella.vcxproj.user
|
||||
src/windows/*.bak
|
||||
src/libretro/x64/*
|
||||
src/libretro/Stella.vcxproj.user
|
||||
src/os/windows/sdl/*
|
||||
src/os/windows/x64/*
|
||||
src/os/windows/Win32/*
|
||||
src/os/windows/Stella.vcxproj.user
|
||||
src/os/windows/*.bak
|
||||
src/os/libretro/x64/*
|
||||
src/os/libretro/Stella.vcxproj.user
|
||||
.vs/*
|
||||
.tgitconfig
|
||||
src/**/*.psess
|
||||
|
@ -40,4 +42,5 @@ src/tools/fonts/*
|
|||
a.out
|
||||
*.json
|
||||
*.sqlite3
|
||||
*.bak
|
||||
*.bak
|
||||
debian/files
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
# Core definitions
|
||||
.core-defs:
|
||||
variables:
|
||||
JNI_PATH: src/libretro
|
||||
MAKEFILE_PATH: src/libretro
|
||||
JNI_PATH: src/os/libretro
|
||||
MAKEFILE_PATH: src/os/libretro
|
||||
CORENAME: stella
|
||||
|
||||
# Inclusion templates, required for the build to work
|
||||
|
@ -18,18 +18,10 @@ include:
|
|||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-x64-mingw.yml'
|
||||
|
||||
# Windows 32-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-i686-mingw.yml'
|
||||
|
||||
# Linux 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-x64.yml'
|
||||
|
||||
# Linux 32-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-i686.yml'
|
||||
|
||||
# MacOS 64-bit
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/osx-x64.yml'
|
||||
|
@ -59,7 +51,7 @@ include:
|
|||
# tvOS (AppleTV)
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/tvos-arm64.yml'
|
||||
|
||||
|
||||
#################################### MISC ##################################
|
||||
|
||||
# Stages for building
|
||||
|
@ -79,73 +71,69 @@ libretro-build-windows-x64:
|
|||
- .libretro-windows-x64-mingw-make-default
|
||||
- .core-defs
|
||||
|
||||
# Windows 32-bit
|
||||
libretro-build-windows-i686:
|
||||
extends:
|
||||
- .libretro-windows-i686-mingw-make-default
|
||||
- .core-defs
|
||||
|
||||
# Linux 64-bit
|
||||
libretro-build-linux-x64:
|
||||
extends:
|
||||
- .libretro-linux-x64-make-default
|
||||
- .core-defs
|
||||
|
||||
# Linux 32-bit
|
||||
libretro-build-linux-i686:
|
||||
extends:
|
||||
- .libretro-linux-i686-make-default
|
||||
- .core-defs
|
||||
image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-amd64-ubuntu:latest
|
||||
before_script:
|
||||
- export NUMPROC=$(($(nproc)/5))
|
||||
- sudo apt-get update -qy
|
||||
- sudo apt-get install -qy software-properties-common
|
||||
- sudo add-apt-repository -y ppa:savoury1/build-tools
|
||||
- sudo add-apt-repository -y ppa:savoury1/gcc-defaults-12
|
||||
- sudo apt-get update -qy
|
||||
- sudo apt-get install -qy gcc-12 g++-12
|
||||
# This container's existing installations of gcc and CMake are way too old
|
||||
variables:
|
||||
CC: /usr/bin/gcc-12
|
||||
CXX: /usr/bin/g++-12
|
||||
CXXFLAGS: -Wno-deprecated-declarations # Deprecation warnings aren't helpful on the libretro Gitlab
|
||||
|
||||
# MacOS 64-bit
|
||||
libretro-build-osx-x64:
|
||||
tags:
|
||||
- mac-apple-silicon
|
||||
extends:
|
||||
- .libretro-osx-x64-make-default
|
||||
- .core-defs
|
||||
|
||||
# MacOS ARM 64-bit
|
||||
libretro-build-osx-arm64:
|
||||
tags:
|
||||
- mac-apple-silicon
|
||||
extends:
|
||||
- .libretro-osx-arm64-make-default
|
||||
- .core-defs
|
||||
|
||||
|
||||
################################### CELLULAR #################################
|
||||
# Android ARMv7a
|
||||
android-armeabi-v7a:
|
||||
extends:
|
||||
- .libretro-android-jni-armeabi-v7a
|
||||
- .core-defs
|
||||
# android-armeabi-v7a:
|
||||
# extends:
|
||||
# - .libretro-android-jni-armeabi-v7a
|
||||
# - .core-defs
|
||||
|
||||
# Android ARMv8a
|
||||
android-arm64-v8a:
|
||||
extends:
|
||||
- .libretro-android-jni-arm64-v8a
|
||||
- .core-defs
|
||||
# android-arm64-v8a:
|
||||
# extends:
|
||||
# - .libretro-android-jni-arm64-v8a
|
||||
# - .core-defs
|
||||
|
||||
# Android 64-bit x86
|
||||
android-x86_64:
|
||||
extends:
|
||||
- .libretro-android-jni-x86_64
|
||||
- .core-defs
|
||||
|
||||
# Android 32-bit x86
|
||||
android-x86:
|
||||
extends:
|
||||
- .libretro-android-jni-x86
|
||||
- .core-defs
|
||||
# android-x86_64:
|
||||
# extends:
|
||||
# - .libretro-android-jni-x86_64
|
||||
# - .core-defs
|
||||
|
||||
# iOS
|
||||
libretro-build-ios-arm64:
|
||||
tags:
|
||||
- mac-apple-silicon
|
||||
extends:
|
||||
- .libretro-ios-arm64-make-default
|
||||
- .core-defs
|
||||
|
||||
# iOS (armv7) [iOS 9 and up]
|
||||
libretro-build-ios9:
|
||||
extends:
|
||||
- .libretro-ios9-make-default
|
||||
- .core-defs
|
||||
|
||||
# tvOS
|
||||
libretro-build-tvos-arm64:
|
||||
extends:
|
||||
|
@ -154,7 +142,7 @@ libretro-build-tvos-arm64:
|
|||
|
||||
################################### CONSOLES #################################
|
||||
# Nintendo Switch
|
||||
libretro-build-libnx-aarch64:
|
||||
extends:
|
||||
- .libretro-libnx-static-retroarch-master
|
||||
- .core-defs
|
||||
# libretro-build-libnx-aarch64:
|
||||
# extends:
|
||||
# - .libretro-libnx-static-retroarch-master
|
||||
# - .core-defs
|
||||
|
|
63
.travis.yml
|
@ -1,63 +0,0 @@
|
|||
# Build matrix / environment variables are explained on:
|
||||
# http://about.travis-ci.org/docs/user/build-configuration/
|
||||
# This file can be validated on: http://lint.travis-ci.org/
|
||||
|
||||
|
||||
language: cpp
|
||||
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
env: GCC=9 CC=gcc-9 CXX=g++-9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-9
|
||||
- g++-9
|
||||
update: true
|
||||
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode11.3
|
||||
compiler: clang
|
||||
addons:
|
||||
homebrew:
|
||||
update: true
|
||||
|
||||
|
||||
install:
|
||||
- |
|
||||
old_cwd=$(pwd)
|
||||
cd ~
|
||||
|
||||
if [[ "$HOST" == macosx-* ]]; then
|
||||
curl -O https://www.libsdl.org/release/SDL2-2.0.10.tar.gz
|
||||
tar xzf SDL2-2.0.10.tar.gz
|
||||
cd SDL2-2.0.10/Xcode/SDL
|
||||
sed -i -e 's/@rpath//g' SDL.xcodeproj/project.pbxproj
|
||||
xcodebuild -configuration Release
|
||||
mkdir -p ~/Library/Frameworks/
|
||||
ln -s `pwd`/build/Release/SDL2.framework ~/Library/Frameworks/
|
||||
else
|
||||
curl -O https://www.libsdl.org/release/SDL2-2.0.10.tar.gz
|
||||
tar xzf SDL2-2.0.10.tar.gz
|
||||
cd SDL2-2.0.10
|
||||
mkdir build
|
||||
cd build
|
||||
../configure
|
||||
make
|
||||
sudo make install
|
||||
fi
|
||||
|
||||
cd $old_cwd
|
||||
|
||||
|
||||
script:
|
||||
- |
|
||||
./configure
|
||||
make all
|
|
@ -14,6 +14,7 @@
|
|||
"C_Cpp.intelliSenseEngine": "Default",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.associations": {
|
||||
"*.h": "cpp",
|
||||
"__functional_base": "cpp",
|
||||
"array": "cpp",
|
||||
"istream": "cpp",
|
||||
|
@ -103,6 +104,18 @@
|
|||
"version": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp"
|
||||
"concepts": "cpp",
|
||||
"__verbose_abort": "cpp",
|
||||
"any": "cpp",
|
||||
"charconv": "cpp",
|
||||
"csignal": "cpp",
|
||||
"execution": "cpp",
|
||||
"numbers": "cpp",
|
||||
"span": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"variant": "cpp",
|
||||
"hash_map": "cpp",
|
||||
"format": "cpp",
|
||||
"*.inc": "cpp"
|
||||
}
|
||||
}
|
||||
|
|
19
Announce.txt
|
@ -9,7 +9,7 @@
|
|||
SSSS ttt eeeee llll llll aaaaa
|
||||
|
||||
===========================================================================
|
||||
Release 6.7.1 for Linux, macOS and Windows
|
||||
Release 7.0 for Linux, macOS and Windows
|
||||
===========================================================================
|
||||
|
||||
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
|
||||
|
@ -21,22 +21,21 @@ all of your favourite Atari 2600 games again! Stella was originally
|
|||
developed for Linux by Bradford W. Mott, however, it has been ported to a
|
||||
number of other platforms and is currently maintained by Stephen Anthony.
|
||||
|
||||
This is the 6.7.1 release of Stella for Linux, macOS and Windows. The
|
||||
This is the 7.0 release of Stella for Linux, macOS and Windows. The
|
||||
distributions currently available are:
|
||||
|
||||
* Binaries for Windows 7/8/10/11 :
|
||||
Stella-6.7.1-win32.exe (32-bit EXE installer)
|
||||
Stella-6.7.1-x64.exe (64-bit EXE installer)
|
||||
Stella-6.7.1-windows.zip (32/64 bit versions)
|
||||
* Binary for Windows 7/8/10/11 :
|
||||
Stella-7.0-x64.exe (64-bit EXE installer)
|
||||
Stella-7.0-windows.zip (64 bit ZIP version)
|
||||
|
||||
* Binary distribution for macOS 10.7 and above :
|
||||
Stella-6.7.1-macos.dmg (ARM M1 and 64-bit Intel)
|
||||
* Binary distribution for macOS 10.13 and above :
|
||||
Stella-7.0-macos.dmg (ARM M1 and 64-bit Intel)
|
||||
|
||||
* Binary distribution for 64-bit Ubuntu :
|
||||
stella_6.7.1-1_amd64.deb
|
||||
stella_7.0-1_amd64.deb
|
||||
|
||||
* Source code distribution for all platforms :
|
||||
stella-6.7.1-src.tar.xz
|
||||
stella-7.0-src.tar.xz
|
||||
|
||||
|
||||
Distribution Site
|
||||
|
|
70
Changes.txt
|
@ -12,6 +12,74 @@
|
|||
Release History
|
||||
===========================================================================
|
||||
|
||||
7.0 to 7.1 (xxx x, 202x)
|
||||
|
||||
* Added developer option for disabling PlusROM support (TODO: Doc)
|
||||
|
||||
* Enhanced PAL-60 detection, searches for signature (e.g. PAL60) in ROM
|
||||
|
||||
* Enhanced VSYNC emulation, considers VBLANK now too
|
||||
|
||||
6.7.1 to 7.0 (October 5, 2024)
|
||||
|
||||
* Enhanced ROM launcher to allow multiple images per ROM.
|
||||
|
||||
* Made heaps of additional images available for the ROM launcher.
|
||||
|
||||
* Added searching by filename for ROM launcher images.
|
||||
|
||||
* Added option to start random ROM.
|
||||
|
||||
* Added automatically enabled phosphor modes.
|
||||
|
||||
* Enhanced Game Properties dialog for multigame ROMs.
|
||||
|
||||
* Added 2nd UI theme and hotkey for toggling UI theme.
|
||||
|
||||
* Added bezel support (incl. Sinden Lightgun).
|
||||
|
||||
* Added optional type format detection based on colors used.
|
||||
|
||||
* Added Joy2B+ controller support.
|
||||
|
||||
* Added auto detection for QuadTari attached controllers.
|
||||
|
||||
* Enhanced Kid Vid support to play tape audio.
|
||||
|
||||
* Added port selection, used for controller default mapping.
|
||||
|
||||
* Added missing PlusROM support for E7 bankswitching.
|
||||
|
||||
* Enhanced movie cart (MVC) support.
|
||||
|
||||
* Accelerated emulation up to ~15% (ARM).
|
||||
|
||||
* Added limited GameLine Master Module bankswitching support.
|
||||
|
||||
* Added 03E0 bankswitching for Brazilian Parker Bros ROMs.
|
||||
|
||||
* Added WF8 bankswitching used by some certain Coleco white carts.
|
||||
|
||||
* Added JANE bankswitching used by Coleco's Tarzan prototype.
|
||||
|
||||
* Added ELF mapper for Mattress Monkeys.
|
||||
|
||||
* Added BUS bankswitching support for some older demos.
|
||||
|
||||
* Fixed broken 7800 pause key support.
|
||||
|
||||
* Added developer option for random hotspot peek values.
|
||||
|
||||
* Added user defined CPU cycle timers to debugger.
|
||||
|
||||
* Removed 'launcherroms' option, since it was causing some issues.
|
||||
|
||||
* Codebase now uses C++20 features, which means a minimum of gcc-11
|
||||
or clang-10 for Linux/Mac, and Visual Studio 2022 for Windows.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
6.7 to 6.7.1 (January 15, 2024)
|
||||
|
||||
* Fixed broken mouse and Stelladaptor input for Driving Controller.
|
||||
|
@ -20,8 +88,6 @@
|
|||
when available, and fixes delay on exiting app experienced on some
|
||||
systems.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
6.6 to 6.7 (June 13, 2022)
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
License Information and Copyright Notice
|
||||
===========================================================================
|
||||
|
||||
Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony and the
|
||||
Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony and the
|
||||
Stella Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
|
|
79
Makefile
|
@ -8,7 +8,7 @@
|
|||
## SS SS tt ee ll ll aa aa
|
||||
## SSSS ttt eeeee llll llll aaaaa
|
||||
##
|
||||
## Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
## Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
## and the Stella Team
|
||||
##
|
||||
## See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -26,6 +26,7 @@ LDFLAGS := -pthread
|
|||
INCLUDES :=
|
||||
LIBS :=
|
||||
OBJS :=
|
||||
OBJS_TEST :=
|
||||
PROF :=
|
||||
|
||||
MODULES :=
|
||||
|
@ -47,29 +48,53 @@ else
|
|||
CFLAGS:= -O2
|
||||
endif
|
||||
|
||||
ifndef CXXFLAGS_TEST
|
||||
CXXFLAGS_TEST := $(CXXFLAGS)
|
||||
endif
|
||||
|
||||
ifndef CFLAGS_TEST
|
||||
CFLAGS_TEST := $(CFLAGS)
|
||||
endif
|
||||
|
||||
ifndef LDFLAGS_TEST
|
||||
LDFLAGS_TEST := $(LDFLAGS)
|
||||
endif
|
||||
|
||||
CXXFLAGS+= -Wall -Wextra -Wno-unused-parameter
|
||||
CFLAGS+= -Wall -Wextra -Wno-unused-parameter
|
||||
|
||||
CXXFLAGS_TEST+= -Wall -Wextra -Wno-unused-parameter
|
||||
CFLAGS_TEST+= -Wall -Wextra -Wno-unused-parameter
|
||||
|
||||
ifdef HAVE_GCC
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17
|
||||
CFLAGS+= -Wno-multichar -Wunused
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -std=c++20
|
||||
CFLAGS+= -Wunused
|
||||
|
||||
CXXFLAGS_TEST+= -Wno-multichar -Wunused -Woverloaded-virtual -std=c++20
|
||||
CFLAGS_TEST+= -Wno-multichar -Wunused
|
||||
endif
|
||||
|
||||
ifdef HAVE_CLANG
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -Woverloaded-virtual -Wnon-virtual-dtor -std=c++17
|
||||
CFLAGS+= -Wno-multichar -Wunused
|
||||
CXXFLAGS+= -Wunused -Woverloaded-virtual -std=c++20
|
||||
CFLAGS+= -Wunused
|
||||
|
||||
CXXFLAGS_TEST+= -Wno-multichar -Wunused -Woverloaded-virtual -std=c++20
|
||||
CFLAGS_TEST+= -Wno-multichar -Wunused
|
||||
endif
|
||||
|
||||
ifdef CLANG_WARNINGS
|
||||
EXTRA_WARN=-Weverything -Wno-c++98-compat-pedantic -Wno-unknown-warning-option \
|
||||
EXTRA_WARN=-Wno-c++98-compat-pedantic -Wno-undefined-func-template \
|
||||
-Wno-switch-enum -Wno-conversion -Wno-covered-switch-default \
|
||||
-Wno-inconsistent-missing-destructor-override -Wno-float-equal \
|
||||
-Wno-documentation -Wno-float-equal \
|
||||
-Wno-exit-time-destructors -Wno-global-constructors -Wno-weak-vtables \
|
||||
-Wno-four-char-constants -Wno-padded -Wno-reserved-identifier \
|
||||
-Wno-duplicate-enum
|
||||
-Wno-duplicate-enum -Wno-unsafe-buffer-usage
|
||||
|
||||
CXXFLAGS+= $(EXTRA_WARN)
|
||||
CFLAGS+= $(EXTRA_WARN)
|
||||
|
||||
CXXFLAGS_TEST+= $(EXTRA_WARN)
|
||||
CFLAGS_TEST+= $(EXTRA_WARN)
|
||||
endif
|
||||
|
||||
ifdef PROFILE
|
||||
|
@ -108,12 +133,14 @@ ifdef STELLA_BUILD_ROOT
|
|||
else
|
||||
OBJECT_ROOT := out
|
||||
endif
|
||||
OBJECT_ROOT_TEST := out.test
|
||||
OBJECT_ROOT_PROFILE_GENERERATE := out.pgen
|
||||
OBJECT_ROOT_PROFILE_USE := out.pgo
|
||||
|
||||
EXECUTABLE := stella$(EXEEXT)
|
||||
EXECUTABLE_PROFILE_GENERATE := stella-pgo-generate$(EXEEXT)
|
||||
EXECUTABLE_PROFILE_USE := stella-pgo$(EXEEXT)
|
||||
EXECUTABLE_TEST := stella-test$(EXEEXT)
|
||||
|
||||
PROFILE_DIR = $(CURDIR)/test/roms/profile
|
||||
PROFILE_OUT = $(PROFILE_DIR)/out
|
||||
|
@ -154,6 +181,9 @@ all: $(EXECUTABLE)
|
|||
|
||||
pgo: $(EXECUTABLE_PROFILE_USE)
|
||||
|
||||
test: $(EXECUTABLE_TEST)
|
||||
./$(EXECUTABLE_TEST)
|
||||
|
||||
######################################################################
|
||||
# Various minor settings
|
||||
######################################################################
|
||||
|
@ -176,6 +206,7 @@ MODULES += \
|
|||
src/emucore \
|
||||
src/emucore/tia \
|
||||
src/emucore/tia/frame-manager \
|
||||
src/emucore/elf \
|
||||
src/common/repository/sqlite
|
||||
|
||||
######################################################################
|
||||
|
@ -194,6 +225,7 @@ DEPDIRS = $(addsuffix /$(DEPDIR),$(MODULE_DIRS))
|
|||
DEPFILES =
|
||||
|
||||
OBJ=$(addprefix $(OBJECT_ROOT)/,$(OBJS))
|
||||
OBJ_TEST=$(addprefix $(OBJECT_ROOT_TEST)/,$(OBJS_TEST))
|
||||
OBJ_PROFILE_GENERATE=$(addprefix $(OBJECT_ROOT_PROFILE_GENERERATE)/,$(OBJS))
|
||||
OBJ_PROFILE_USE=$(addprefix $(OBJECT_ROOT_PROFILE_USE)/,$(OBJS))
|
||||
|
||||
|
@ -201,6 +233,9 @@ OBJ_PROFILE_USE=$(addprefix $(OBJECT_ROOT_PROFILE_USE)/,$(OBJS))
|
|||
$(EXECUTABLE): $(OBJ)
|
||||
$(LD) $(LDFLAGS) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) $(PROF) -o $@
|
||||
|
||||
$(EXECUTABLE_TEST): $(OBJ_TEST)
|
||||
$(LD) $(LDFLAGS_TEST) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) -lgtest -lgtest_main -o $@
|
||||
|
||||
$(EXECUTABLE_PROFILE_GENERATE): $(OBJ_PROFILE_GENERATE)
|
||||
$(LD) $(LDFLAGS_PROFILE_GENERATE) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) $(PROF) -o $@
|
||||
|
||||
|
@ -215,7 +250,7 @@ clean:
|
|||
-$(RM) -fr \
|
||||
$(OBJECT_ROOT) $(OBJECT_ROOT_PROFILE_GENERERATE) $(OBJECT_ROOT_PROFILE_USE) \
|
||||
$(EXECUTABLE) $(EXECUTABLE_PROFILE_GENERATE) $(EXECUTABLE_PROFILE_USE) \
|
||||
$(PROFILE_OUT) $(PROFILE_STAMP)
|
||||
$(OBJECT_ROOT_TEST) $(PROFILE_OUT) $(PROFILE_STAMP)
|
||||
|
||||
.PHONY: all clean dist distclean
|
||||
|
||||
|
@ -243,6 +278,16 @@ $(OBJECT_ROOT)/%.o: %.cxx
|
|||
$(merge_dep)
|
||||
|
||||
$(OBJECT_ROOT)/%.o: %.c
|
||||
$(create_dir)
|
||||
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
|
||||
$(merge_dep)
|
||||
|
||||
$(OBJECT_ROOT_TEST)/%.o: %.cxx
|
||||
$(create_dir)
|
||||
$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
|
||||
$(merge_dep)
|
||||
|
||||
$(OBJECT_ROOT_TEST)/%.o: %.c
|
||||
$(create_dir)
|
||||
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS) $(CPPFLAGS) -c $(<) -o $@
|
||||
$(merge_dep)
|
||||
|
@ -280,6 +325,14 @@ $(OBJECT_ROOT)/%.o: %.c
|
|||
$(create_dir)
|
||||
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS) $(CPPFLAGS) -c $(<) -o $@
|
||||
|
||||
$(OBJECT_ROOT_TEST)/%.o: %.cxx
|
||||
$(create_dir)
|
||||
$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
|
||||
|
||||
$(OBJECT_ROOT_TEST)/%.o: %.c
|
||||
$(create_dir)
|
||||
$(CC) $(CXX_UPDATE_DEP_FLAG) $(CFLAGS_TEST) $(CPPFLAGS) -c $(<) -o $@
|
||||
|
||||
$(OBJECT_ROOT_PROFILE_GENERERATE)/%.o: %.cxx
|
||||
$(create_dir)
|
||||
$(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS_PROFILE_GENERATE) $(CPPFLAGS) -c $(<) -o $@
|
||||
|
@ -317,11 +370,11 @@ install: all
|
|||
$(INSTALL) -d "$(DESTDIR)$(BINDIR)"
|
||||
$(INSTALL) -c -m 755 "$(srcdir)/stella$(EXEEXT)" "$(DESTDIR)$(BINDIR)/stella$(EXEEXT)"
|
||||
$(INSTALL) -d "$(DESTDIR)$(DOCDIR)"
|
||||
$(INSTALL) -c -m 644 "$(srcdir)/Announce.txt" "$(srcdir)/Changes.txt" "$(srcdir)/Copyright.txt" "$(srcdir)/License.txt" "$(srcdir)/README-SDL.txt" "$(srcdir)/Readme.txt" "$(srcdir)/Todo.txt" "$(srcdir)/docs/index.html" "$(srcdir)/docs/debugger.html" "$(DESTDIR)$(DOCDIR)/"
|
||||
$(INSTALL) -c -m 644 "$(srcdir)/Announce.txt" "$(srcdir)/Changes.txt" "$(srcdir)/Copyright.txt" "$(srcdir)/License.txt" "$(srcdir)/README-SDL.txt" "$(srcdir)/README.md" "$(srcdir)/Todo.txt" "$(srcdir)/docs/index.html" "$(srcdir)/docs/debugger.html" "$(DESTDIR)$(DOCDIR)/"
|
||||
$(INSTALL) -d "$(DESTDIR)$(DOCDIR)/graphics"
|
||||
$(INSTALL) -c -m 644 $(wildcard $(srcdir)/docs/graphics/*.png) "$(DESTDIR)$(DOCDIR)/graphics"
|
||||
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/applications"
|
||||
$(INSTALL) -c -m 644 "$(srcdir)/src/unix/stella.desktop" "$(DESTDIR)$(DATADIR)/applications"
|
||||
$(INSTALL) -c -m 644 "$(srcdir)/src/os/unix/stella.desktop" "$(DESTDIR)$(DATADIR)/applications"
|
||||
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/16x16/apps"
|
||||
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/22x22/apps"
|
||||
$(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/24x24/apps"
|
||||
|
@ -357,7 +410,7 @@ src/emucore/M6502.ins: src/emucore/M6502.m4
|
|||
m4 src/emucore/M6502.m4 > src/emucore/M6502.ins
|
||||
|
||||
# Special rule for windows icon stuff (there's probably a better way to do this ...)
|
||||
src/windows/stella_icon.o: src/windows/stella.ico src/windows/stella.rc
|
||||
windres --include-dir src/windows src/windows/stella.rc src/windows/stella_icon.o
|
||||
src/os/windows/stella_icon.o: src/os/windows/stella.ico src/os/windows/stella.rc
|
||||
windres --include-dir src/os/windows src/os/windows/stella.rc src/os/windows/stella_icon.o
|
||||
|
||||
.PHONY: deb bundle test install uninstall
|
||||
|
|
|
@ -15,6 +15,10 @@ Please check the list of known issues first (see below) before reporting new one
|
|||
If you encounter any issues, please open a new issue on the project
|
||||
[issue tracker](https://github.com/stella-emu/stella/issues).
|
||||
|
||||
Note: Please do **not** report issues regarding platforms other than PC and RetroN 77
|
||||
(e.g. Libretro) here. The Stella Team is not responsible for these forks and cannot
|
||||
help with them.
|
||||
|
||||
# Known issues
|
||||
|
||||
Please check out the [issue tracker](https://github.com/stella-emu/stella/issues) for
|
||||
|
|
10
Readme.txt
|
@ -1,10 +0,0 @@
|
|||
Stella is a multi-platform Atari 2600 VCS emulator which allows you to
|
||||
play all of your favourite Atari 2600 games on your PC. You'll find the
|
||||
Stella Users Manual in the docs subdirectory. If you'd like to verify
|
||||
that you have the latest release of Stella, visit the Stella Website at:
|
||||
|
||||
https://stella-emu.github.io
|
||||
|
||||
Enjoy,
|
||||
|
||||
The Stella Team
|
32
appveyor.yml
|
@ -1,32 +0,0 @@
|
|||
image: Visual Studio 2019
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- Platform: x64
|
||||
- Platform: Win32
|
||||
|
||||
Configuration: Release
|
||||
|
||||
SDL2_version: 2.0.12
|
||||
|
||||
|
||||
install:
|
||||
- cmd: |
|
||||
curl -o "C:\SDL2-devel.zip" "https://www.libsdl.org/release/SDL2-devel-%SDL2_version%-VC.zip"
|
||||
7z x "C:\SDL2-devel.zip" -o"C:\"
|
||||
xcopy /S "C:\SDL2-%SDL2_version%\include" src\common
|
||||
|
||||
if %Platform%==x64 xcopy /S "C:\SDL2-%SDL2_version%\lib\x64" src\windows
|
||||
if %Platform%==Win32 xcopy /S "C:\SDL2-%SDL2_version%\lib\x86" src\windows
|
||||
|
||||
|
||||
build_script:
|
||||
- cmd: |
|
||||
msbuild src\windows\Stella.sln
|
||||
|
||||
|
||||
artifacts:
|
||||
- path: '**\stella.exe'
|
|
@ -4,7 +4,9 @@
|
|||
# contains the module name, a trick we use so we can keep multiple different
|
||||
# module object lists, one for each module.
|
||||
MODULE_OBJS-$(MODULE) := $(MODULE_OBJS)
|
||||
MODULE_TEST_OBJS-$(MODULE) := $(MODULE_TEST_OBJS)
|
||||
|
||||
# If not building as a plugin, add the object files to the main OBJS list
|
||||
#OBJS += $(MODULE_LIB-$(MODULE))
|
||||
OBJS += $(MODULE_OBJS)
|
||||
OBJS_TEST += $(MODULE_TEST_OBJS)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright 1992-2021 Free Software Foundation, Inc.
|
||||
# Copyright 1992-2024 Free Software Foundation, Inc.
|
||||
|
||||
# shellcheck disable=SC2006,SC2268 # see below for rationale
|
||||
|
||||
timestamp='2021-06-03'
|
||||
timestamp='2024-07-27'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
|
@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
|
|||
usage="\
|
||||
Usage: $0 [OPTION]
|
||||
|
||||
Output the configuration name of the system \`$me' is run on.
|
||||
Output the configuration name of the system '$me' is run on.
|
||||
|
||||
Options:
|
||||
-h, --help print this help, then exit
|
||||
|
@ -60,13 +60,13 @@ version="\
|
|||
GNU config.guess ($timestamp)
|
||||
|
||||
Originally written by Per Bothner.
|
||||
Copyright 1992-2021 Free Software Foundation, Inc.
|
||||
Copyright 1992-2024 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
|
||||
help="
|
||||
Try \`$me --help' for more information."
|
||||
Try '$me --help' for more information."
|
||||
|
||||
# Parse command line
|
||||
while test $# -gt 0 ; do
|
||||
|
@ -102,8 +102,8 @@ GUESS=
|
|||
# temporary files to be created and, as you can see below, it is a
|
||||
# headache to deal with in a portable fashion.
|
||||
|
||||
# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
|
||||
# use `HOST_CC' if defined, but it is deprecated.
|
||||
# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
|
||||
# use 'HOST_CC' if defined, but it is deprecated.
|
||||
|
||||
# Portable tmp directory creation inspired by the Autoconf team.
|
||||
|
||||
|
@ -123,7 +123,7 @@ set_cc_for_build() {
|
|||
dummy=$tmp/dummy
|
||||
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
|
||||
,,) echo "int x;" > "$dummy.c"
|
||||
for driver in cc gcc c89 c99 ; do
|
||||
for driver in cc gcc c17 c99 c89 ; do
|
||||
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
|
||||
CC_FOR_BUILD=$driver
|
||||
break
|
||||
|
@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
|
|||
|
||||
set_cc_for_build
|
||||
cat <<-EOF > "$dummy.c"
|
||||
#if defined(__ANDROID__)
|
||||
LIBC=android
|
||||
#else
|
||||
#include <features.h>
|
||||
#if defined(__UCLIBC__)
|
||||
LIBC=uclibc
|
||||
|
@ -162,6 +165,8 @@ Linux|GNU|GNU/*)
|
|||
LIBC=dietlibc
|
||||
#elif defined(__GLIBC__)
|
||||
LIBC=gnu
|
||||
#elif defined(__LLVM_LIBC__)
|
||||
LIBC=llvm
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
/* First heuristic to detect musl libc. */
|
||||
|
@ -169,6 +174,7 @@ Linux|GNU|GNU/*)
|
|||
LIBC=musl
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
|
||||
eval "$cc_set_libc"
|
||||
|
@ -437,7 +443,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
|
|||
# This test works for both compilers.
|
||||
if test "$CC_FOR_BUILD" != no_compiler_found; then
|
||||
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
(CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
SUN_ARCH=x86_64
|
||||
|
@ -459,7 +465,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
|
|||
UNAME_RELEASE=`uname -v`
|
||||
;;
|
||||
esac
|
||||
# Japanese Language versions have a version number like `4.1.3-JL'.
|
||||
# Japanese Language versions have a version number like '4.1.3-JL'.
|
||||
SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
|
||||
GUESS=sparc-sun-sunos$SUN_REL
|
||||
;;
|
||||
|
@ -628,7 +634,8 @@ EOF
|
|||
sed 's/^ //' << EOF > "$dummy.c"
|
||||
#include <sys/systemcfg.h>
|
||||
|
||||
main()
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (!__power_pc())
|
||||
exit(1);
|
||||
|
@ -712,7 +719,8 @@ EOF
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main ()
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#if defined(_SC_KERNEL_BITS)
|
||||
long bits = sysconf(_SC_KERNEL_BITS);
|
||||
|
@ -904,7 +912,7 @@ EOF
|
|||
fi
|
||||
;;
|
||||
*:FreeBSD:*:*)
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
UNAME_PROCESSOR=`uname -p`
|
||||
case $UNAME_PROCESSOR in
|
||||
amd64)
|
||||
UNAME_PROCESSOR=x86_64 ;;
|
||||
|
@ -929,6 +937,9 @@ EOF
|
|||
i*:PW*:*)
|
||||
GUESS=$UNAME_MACHINE-pc-pw32
|
||||
;;
|
||||
*:SerenityOS:*:*)
|
||||
GUESS=$UNAME_MACHINE-pc-serenity
|
||||
;;
|
||||
*:Interix*:*)
|
||||
case $UNAME_MACHINE in
|
||||
x86)
|
||||
|
@ -963,11 +974,37 @@ EOF
|
|||
GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
|
||||
GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
|
||||
;;
|
||||
x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
|
||||
GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
|
||||
;;
|
||||
*:[Mm]anagarm:*:*)
|
||||
GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
|
||||
;;
|
||||
*:Minix:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-minix
|
||||
;;
|
||||
aarch64:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
set_cc_for_build
|
||||
CPU=$UNAME_MACHINE
|
||||
LIBCABI=$LIBC
|
||||
if test "$CC_FOR_BUILD" != no_compiler_found; then
|
||||
ABI=64
|
||||
sed 's/^ //' << EOF > "$dummy.c"
|
||||
#ifdef __ARM_EABI__
|
||||
#ifdef __ARM_PCS_VFP
|
||||
ABI=eabihf
|
||||
#else
|
||||
ABI=eabi
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
|
||||
eval "$cc_set_abi"
|
||||
case $ABI in
|
||||
eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
|
||||
esac
|
||||
fi
|
||||
GUESS=$CPU-unknown-linux-$LIBCABI
|
||||
;;
|
||||
aarch64_be:Linux:*:*)
|
||||
UNAME_MACHINE=aarch64_be
|
||||
|
@ -1033,7 +1070,16 @@ EOF
|
|||
k1om:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
;;
|
||||
loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
|
||||
kvx:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
;;
|
||||
kvx:cos:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-cos
|
||||
;;
|
||||
kvx:mbr:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-mbr
|
||||
;;
|
||||
loongarch32:Linux:*:* | loongarch64:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
;;
|
||||
m32r*:Linux:*:*)
|
||||
|
@ -1148,16 +1194,27 @@ EOF
|
|||
;;
|
||||
x86_64:Linux:*:*)
|
||||
set_cc_for_build
|
||||
CPU=$UNAME_MACHINE
|
||||
LIBCABI=$LIBC
|
||||
if test "$CC_FOR_BUILD" != no_compiler_found; then
|
||||
if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
|
||||
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_X32 >/dev/null
|
||||
then
|
||||
LIBCABI=${LIBC}x32
|
||||
fi
|
||||
ABI=64
|
||||
sed 's/^ //' << EOF > "$dummy.c"
|
||||
#ifdef __i386__
|
||||
ABI=x86
|
||||
#else
|
||||
#ifdef __ILP32__
|
||||
ABI=x32
|
||||
#endif
|
||||
#endif
|
||||
EOF
|
||||
cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
|
||||
eval "$cc_set_abi"
|
||||
case $ABI in
|
||||
x86) CPU=i686 ;;
|
||||
x32) LIBCABI=${LIBC}x32 ;;
|
||||
esac
|
||||
fi
|
||||
GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
|
||||
GUESS=$CPU-pc-linux-$LIBCABI
|
||||
;;
|
||||
xtensa*:Linux:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
|
||||
|
@ -1177,7 +1234,7 @@ EOF
|
|||
GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
|
||||
;;
|
||||
i*86:OS/2:*:*)
|
||||
# If we were able to find `uname', then EMX Unix compatibility
|
||||
# If we were able to find 'uname', then EMX Unix compatibility
|
||||
# is probably installed.
|
||||
GUESS=$UNAME_MACHINE-pc-os2-emx
|
||||
;;
|
||||
|
@ -1318,7 +1375,7 @@ EOF
|
|||
GUESS=ns32k-sni-sysv
|
||||
fi
|
||||
;;
|
||||
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
|
||||
PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
|
||||
# says <Richard.M.Bartel@ccMail.Census.GOV>
|
||||
GUESS=i586-unisys-sysv4
|
||||
;;
|
||||
|
@ -1364,8 +1421,11 @@ EOF
|
|||
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
|
||||
GUESS=i586-pc-haiku
|
||||
;;
|
||||
x86_64:Haiku:*:*)
|
||||
GUESS=x86_64-unknown-haiku
|
||||
ppc:Haiku:*:*) # Haiku running on Apple PowerPC
|
||||
GUESS=powerpc-apple-haiku
|
||||
;;
|
||||
*:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
|
||||
GUESS=$UNAME_MACHINE-unknown-haiku
|
||||
;;
|
||||
SX-4:SUPER-UX:*:*)
|
||||
GUESS=sx4-nec-superux$UNAME_RELEASE
|
||||
|
@ -1522,6 +1582,9 @@ EOF
|
|||
i*86:rdos:*:*)
|
||||
GUESS=$UNAME_MACHINE-pc-rdos
|
||||
;;
|
||||
i*86:Fiwix:*:*)
|
||||
GUESS=$UNAME_MACHINE-pc-fiwix
|
||||
;;
|
||||
*:AROS:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-aros
|
||||
;;
|
||||
|
@ -1534,6 +1597,9 @@ EOF
|
|||
*:Unleashed:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
|
||||
;;
|
||||
*:Ironclad:*:*)
|
||||
GUESS=$UNAME_MACHINE-unknown-ironclad
|
||||
;;
|
||||
esac
|
||||
|
||||
# Do we have a guess based on uname results?
|
||||
|
@ -1557,6 +1623,7 @@ cat > "$dummy.c" <<EOF
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#if defined (sony)
|
||||
|
|
|
@ -13,6 +13,16 @@
|
|||
# use environment vars if set
|
||||
CXXFLAGS="$CXXFLAGS $CPPFLAGS"
|
||||
|
||||
if test -n "$CXXFLAGS_TEST"; then
|
||||
CXXFLAGS_TEST="$CXXFLAGS_TEST $CPPFLAGS"
|
||||
else
|
||||
CXXFLAGS_TEST="$CXXFLAGS"
|
||||
fi
|
||||
|
||||
if test -z "$LDFLAGS_TEST"; then
|
||||
LDFLAGS_TEST="$LDFLAGS"
|
||||
fi
|
||||
|
||||
# default option behaviour yes/no
|
||||
_build_gui=yes
|
||||
_build_windowed=yes
|
||||
|
@ -28,12 +38,14 @@ _build_static=no
|
|||
_build_profile=no
|
||||
_build_debug=no
|
||||
_build_release=no
|
||||
_build_mold=no
|
||||
|
||||
# more defaults
|
||||
_ranlib=ranlib
|
||||
_install=install
|
||||
_ar="ar cru"
|
||||
_strip=strip
|
||||
_pkg_config=pkg-config
|
||||
_mkdir="mkdir -p"
|
||||
_echo=printf
|
||||
_cat=cat
|
||||
|
@ -218,11 +230,13 @@ Optional Features:
|
|||
--disable-debug
|
||||
--enable-release build with all optimizations, for final release [disabled]
|
||||
--disable-release
|
||||
--use-mold-linker use mold linker (experimental) [disabled]
|
||||
|
||||
Optional Libraries:
|
||||
--with-sdl-prefix=DIR Prefix where the sdl2-config script is installed (optional)
|
||||
--with-libpng-prefix=DIR Prefix where libpng is installed (optional)
|
||||
--with-zlib-prefix=DIR Prefix where zlib is installed (optional)
|
||||
--with-gtest-prefix=DIR Prefix where googletest is installed (optional)
|
||||
|
||||
Some influential environment variables:
|
||||
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
|
||||
|
@ -231,6 +245,8 @@ Some influential environment variables:
|
|||
CXXFLAGS C++ compiler flags
|
||||
CPPFLAGS C++ preprocessor flags, e.g. -I<include dir> if you have
|
||||
headers in a nonstandard directory <include dir>
|
||||
LDFLAGS_TEST linker flags for unit tests
|
||||
CXXFLAGS_TEST C++ compiler flags for unit tests
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
|
@ -264,6 +280,7 @@ for ac_option in $@; do
|
|||
--disable-debug) _build_debug=no ;;
|
||||
--enable-release) _build_release=yes ;;
|
||||
--disable-release) _build_release=no ;;
|
||||
--use-mold-linker) _build_mold=yes ;;
|
||||
--with-sdl-prefix=*)
|
||||
arg=`echo $ac_option | cut -d '=' -f 2`
|
||||
_sdlpath="$arg:$arg/bin"
|
||||
|
@ -277,6 +294,11 @@ for ac_option in $@; do
|
|||
_prefix=`echo $ac_option | cut -d '=' -f 2`
|
||||
ZLIB_CFLAGS="-I$_prefix/include"
|
||||
ZLIB_LIBS="-L$_prefix/lib"
|
||||
;;
|
||||
--with-gtest-prefix=*)
|
||||
_prefix=`echo $ac_option | cut -d '=' -f 2`
|
||||
CXXFLAGS_TEST="$CXXFLAGS_TEST -I$_prefix/include"
|
||||
LDFLAGS_TEST="$LDFLAGS_TEST -L$_prefix/lib"
|
||||
;;
|
||||
--host=*)
|
||||
_host=`echo $ac_option | cut -d '=' -f 2`
|
||||
|
@ -322,12 +344,17 @@ mingw32-cross)
|
|||
_host_cpu=i386
|
||||
_host_prefix=i386-mingw32msvc
|
||||
;;
|
||||
*)
|
||||
"")
|
||||
guessed_host=`$_srcdir/config.guess`
|
||||
_host_cpu=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
|
||||
_host_os=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
|
||||
_host_vendor=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
|
||||
;;
|
||||
*)
|
||||
_host_cpu=`echo "$_host" | sed 's/^\([^-]*\)-.*/\1/'`
|
||||
_host_os=`echo "$_host" | sed 's/-\([^-]*\)-[^-]*$/\1/'`
|
||||
_host_prefix="$_host"
|
||||
;;
|
||||
esac
|
||||
|
||||
#
|
||||
|
@ -343,9 +370,6 @@ arm-riscos-aof)
|
|||
psp)
|
||||
EXEEXT=".elf"
|
||||
;;
|
||||
gp2x)
|
||||
EXEEXT=""
|
||||
;;
|
||||
*)
|
||||
EXEEXT=""
|
||||
;;
|
||||
|
@ -378,7 +402,7 @@ else
|
|||
fi
|
||||
|
||||
for compiler in $compilers; do
|
||||
if test_compiler "$compiler -std=c++17"; then
|
||||
if test_compiler "$compiler -std=c++20"; then
|
||||
CXX=$compiler
|
||||
echo $CXX
|
||||
break
|
||||
|
@ -608,6 +632,9 @@ fi
|
|||
# Cross-compilers use their own commands for the following functions
|
||||
if test -n "$_host_prefix"; then
|
||||
_strip="$_host_prefix-$_strip"
|
||||
if command -v "$_host_prefix-$_pkg_config" >/dev/null 2>&1; then
|
||||
_pkg_config="$_host_prefix-$_pkg_config"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
|
@ -621,7 +648,7 @@ if test "$_build_zip" = yes ; then
|
|||
#include <zlib.h>
|
||||
int main(void) { return strcmp(ZLIB_VERSION, zlibVersion()); }
|
||||
EOF
|
||||
cc_check $LDFLAGS $CXXFLAGS $ZLIB_CFLAGS $ZLIB_LIBS `pkg-config --libs zlib` && _zlib=yes
|
||||
cc_check $LDFLAGS $CXXFLAGS $ZLIB_CFLAGS $ZLIB_LIBS `$_pkg_config --libs zlib` && _zlib=yes
|
||||
|
||||
if test "$_zlib" = yes ; then
|
||||
echo "$_zlib"
|
||||
|
@ -647,7 +674,7 @@ if test "$_build_png" = yes ; then
|
|||
#include <png.h>
|
||||
int main(void) { return printf("%s\n", PNG_HEADER_VERSION_STRING); }
|
||||
EOF
|
||||
cc_check $LDFLAGS $CXXFLAGS $LIBPNG_CFLAGS $LIBPNG_LIBS `pkg-config --libs libpng` && _libpng=yes
|
||||
cc_check $LDFLAGS $CXXFLAGS $LIBPNG_CFLAGS $LIBPNG_LIBS `$_pkg_config --libs libpng` && _libpng=yes
|
||||
|
||||
if test "$_libpng" = yes ; then
|
||||
echo "$_libpng"
|
||||
|
@ -671,7 +698,7 @@ if test "$_build_sqlite3" = yes ; then
|
|||
#include <sqlite3.h>
|
||||
int main(void) { return printf("%s\n", SQLITE_VERSION); }
|
||||
EOF
|
||||
cc_check $LDFLAGS $CXXFLAGS `pkg-config --libs sqlite3` && _libsqlite3=yes
|
||||
cc_check $LDFLAGS $CXXFLAGS `$_pkg_config --libs sqlite3` && _libsqlite3=yes
|
||||
|
||||
if test "$_libsqlite3" = yes ; then
|
||||
echo "$_libsqlite3"
|
||||
|
@ -794,24 +821,29 @@ echo
|
|||
find_sdlconfig
|
||||
|
||||
SRC="src"
|
||||
SRC_OS="$SRC/os"
|
||||
SRC_LIB="$SRC/lib"
|
||||
CORE="$SRC/emucore"
|
||||
COMMON="$SRC/common"
|
||||
TIA="$SRC/emucore/tia"
|
||||
ELF="$SRC/emucore/elf"
|
||||
TIA_FRAME_MANAGER="$SRC/emucore/tia/frame-manager"
|
||||
TV="$SRC/common/tv_filters"
|
||||
GUI="$SRC/gui"
|
||||
DBG="$SRC/debugger"
|
||||
DBGGUI="$SRC/debugger/gui"
|
||||
YACC="$SRC/yacc"
|
||||
YACC="$SRC/debugger/yacc"
|
||||
CHEAT="$SRC/cheat"
|
||||
LIBPNG="$SRC/libpng"
|
||||
ZLIB="$SRC/zlib"
|
||||
LIBPNG="$SRC_LIB/libpng"
|
||||
LIBJPG="$SRC_LIB/nanojpeg"
|
||||
LIBJPGEXIF="$SRC_LIB/tinyexif"
|
||||
ZLIB="$SRC_LIB/zlib"
|
||||
SQLITE_REPO="$SRC/common/repository/sqlite"
|
||||
SQLITE_LIB="$SRC/sqlite"
|
||||
JSON="$SRC/json"
|
||||
HTTP_LIB="$SRC/httplib"
|
||||
SQLITE_LIB="$SRC_LIB/sqlite"
|
||||
JSON="$SRC_LIB/json"
|
||||
HTTP_LIB="$SRC_LIB/httplib"
|
||||
|
||||
INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$JSON -I$SQLITE_REPO"
|
||||
INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$ELF -I$JSON -I$SQLITE_REPO"
|
||||
|
||||
INCLUDES="$INCLUDES `$_sdlconfig --cflags`"
|
||||
if test "$_build_static" = yes ; then
|
||||
|
@ -827,26 +859,30 @@ LD=$CXX
|
|||
case $_host_os in
|
||||
unix)
|
||||
DEFINES="$DEFINES -DBSPF_UNIX"
|
||||
MODULES="$MODULES $SRC/unix"
|
||||
INCLUDES="$INCLUDES -I$SRC/unix"
|
||||
MODULES="$MODULES $SRC_OS/unix"
|
||||
INCLUDES="$INCLUDES -I$SRC_OS/unix"
|
||||
;;
|
||||
darwin)
|
||||
DEFINES="$DEFINES -DBSPF_UNIX -DMACOS_KEYS"
|
||||
MODULES="$MODULES $SRC/unix"
|
||||
INCLUDES="$INCLUDES -I$SRC/unix"
|
||||
MODULES="$MODULES $SRC_OS/unix"
|
||||
INCLUDES="$INCLUDES -I$SRC_OS/unix"
|
||||
if test "$have_clang" == yes; then
|
||||
CXXFLAGS="$CXXFLAGS -Wno-poison-system-directories"
|
||||
if test -n "$CXXFLAGS_TEST"; then
|
||||
CXXFLAGS_TEST="$CXXFLAGS_TEST -Wno-poison-system-directories"
|
||||
fi
|
||||
fi
|
||||
_libsqlite3=no
|
||||
;;
|
||||
retron77)
|
||||
DEFINES="$DEFINES -DBSPF_UNIX -DRETRON77"
|
||||
MODULES="$MODULES $SRC/unix $SRC/unix/r77"
|
||||
INCLUDES="$INCLUDES -I$SRC/unix -I$SRC/unix/r77"
|
||||
MODULES="$MODULES $SRC_OS/unix $SRC_OS/unix/r77"
|
||||
INCLUDES="$INCLUDES -I$SRC_OS/unix -I$SRC_OS/unix/r77"
|
||||
;;
|
||||
win32)
|
||||
DEFINES="$DEFINES -DBSPF_WINDOWS"
|
||||
MODULES="$MODULES $SRC/windows"
|
||||
INCLUDES="$INCLUDES -I$SRC/windows"
|
||||
MODULES="$MODULES $SRC_OS/windows"
|
||||
INCLUDES="$INCLUDES -I$SRC_OS/windows"
|
||||
LIBS="$LIBS -lmingw32 -lwinmm"
|
||||
;;
|
||||
*)
|
||||
|
@ -891,9 +927,11 @@ if test "$_build_httplib" = yes ; then
|
|||
fi
|
||||
|
||||
if test "$_build_png" = yes ; then
|
||||
DEFINES="$DEFINES -DPNG_SUPPORT"
|
||||
DEFINES="$DEFINES -DIMAGE_SUPPORT"
|
||||
INCLUDES="$INCLUDES -I$LIBJPG -I$LIBJPGEXIF"
|
||||
MODULES="$MODULES $LIBJPGEXIF"
|
||||
if test "$_libpng" = yes ; then
|
||||
LIBS="$LIBS `pkg-config --libs libpng`"
|
||||
LIBS="$LIBS `$_pkg_config --libs libpng`"
|
||||
else
|
||||
MODULES="$MODULES $LIBPNG"
|
||||
INCLUDES="$INCLUDES -I$LIBPNG"
|
||||
|
@ -901,7 +939,7 @@ if test "$_build_png" = yes ; then
|
|||
fi
|
||||
|
||||
if test "$_libsqlite3" = yes ; then
|
||||
LIBS="$LIBS `pkg-config --libs sqlite3`"
|
||||
LIBS="$LIBS `$_pkg_config --libs sqlite3`"
|
||||
else
|
||||
MODULES="$MODULES $SQLITE_LIB"
|
||||
INCLUDES="$INCLUDES -I$SQLITE_LIB"
|
||||
|
@ -910,7 +948,7 @@ fi
|
|||
if test "$_build_zip" = yes ; then
|
||||
DEFINES="$DEFINES -DZIP_SUPPORT"
|
||||
if test "$_zlib" = yes ; then
|
||||
LIBS="$LIBS `pkg-config --libs zlib`"
|
||||
LIBS="$LIBS `$_pkg_config --libs zlib`"
|
||||
else
|
||||
MODULES="$MODULES $ZLIB"
|
||||
INCLUDES="$INCLUDES -I$ZLIB"
|
||||
|
@ -929,6 +967,10 @@ if test "$_build_release" = no ; then
|
|||
_build_release=
|
||||
fi
|
||||
|
||||
if test "$_build_mold" = yes ; then
|
||||
LDFLAGS="-fuse-ld=mold"
|
||||
fi
|
||||
|
||||
# Workaround until we deal with autodetection of C compiler properly
|
||||
# Or we remove C files from Stella entirely, by making them C++
|
||||
if test -z "$CC"; then
|
||||
|
@ -942,6 +984,7 @@ cat > config.mak << EOF
|
|||
CC := $CC
|
||||
CXX := $CXX
|
||||
CXXFLAGS := $CXXFLAGS
|
||||
CXXFLAGS_TEST := $CXXFLAGS_TEST
|
||||
LD := $LD
|
||||
LIBS += $LIBS
|
||||
RANLIB := $_ranlib
|
||||
|
@ -979,6 +1022,7 @@ INCLUDES += $INCLUDES
|
|||
OBJS += $OBJS
|
||||
DEFINES += $DEFINES
|
||||
LDFLAGS += $LDFLAGS
|
||||
LDFLAGS_TEST += $LDFLAGS_TEST
|
||||
$_config_mk_data
|
||||
EOF
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
stella (6.7.1) stable; urgency=high
|
||||
stella (7.0) stable; urgency=high
|
||||
|
||||
* Version 6.7.1 release
|
||||
* Version 7.0 release
|
||||
|
||||
-- Stephen Anthony <sa666666@gmail.com> Mon, 15 Jan 2024 17:09:59 -0230
|
||||
-- Stephen Anthony <sa666666@gmail.com> Sat, 5 Oct 2024 17:09:59 -0230
|
||||
|
||||
|
||||
stella (6.7) stable; urgency=high
|
||||
|
|
|
@ -3,6 +3,7 @@ Maintainer: Stephen Anthony <sa666666@gmail.com>
|
|||
Section: otherosfs
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>= 10~),
|
||||
libgtest-dev,
|
||||
libpng-dev,
|
||||
libsdl2-dev,
|
||||
zlib1g-dev
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0
|
||||
Upstream-Name: stella
|
||||
Source: https://stella-emu.github.io
|
||||
Copyright: 1995-2022 Bradford W. Mott, Stephen Anthony and the Stella Team
|
||||
Copyright: 1995-2025 Bradford W. Mott, Stephen Anthony and the Stella Team
|
||||
License: GPL-2+
|
||||
|
||||
Files: *
|
||||
Copyright: 1995-2022 Bradford W. Mott, Stephen Anthony and the Stella
|
||||
Copyright: 1995-2025 Bradford W. Mott, Stephen Anthony and the Stella
|
||||
Team
|
||||
License: GPL-2+
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 1998-2004 Tom Lear <tom@trap.mtview.ca.us>
|
||||
2006 Mario Iseli <admin@marioiseli.com>
|
||||
2010-2022 Stephen Kitt <skitt@debian.org>
|
||||
2010-2025 Stephen Kitt <skitt@debian.org>
|
||||
License: GPL-2+
|
||||
|
||||
Files:
|
||||
|
@ -73,7 +73,7 @@ License: RSA
|
|||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
|
||||
Files: src/libpng/*
|
||||
Files: src/lib/libpng/*
|
||||
Copyright: 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
1996-1997 Andreas Dilger
|
||||
1998-2013 Glenn Randers-Pehrson
|
||||
|
@ -112,7 +112,7 @@ License: libpng
|
|||
risk of satisfactory quality, performance, accuracy, and effort is
|
||||
with the user.
|
||||
|
||||
Files: src/libretro/libretro.h
|
||||
Files: src/os/libretro/libretro.h
|
||||
Copyright: 2010-2017 The RetroArch team
|
||||
License: MIT
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -135,7 +135,7 @@ License: MIT
|
|||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Files: src/macos/*
|
||||
Files: src/os/macos/*
|
||||
Copyright: 2005-2006 Mark Grebe
|
||||
License: GPL-2+
|
||||
|
||||
|
@ -164,7 +164,7 @@ License: GPL-2
|
|||
License version 2 can be found in
|
||||
`/usr/share/common-licenses/GPL-2'.
|
||||
|
||||
Files: src/zlib/*
|
||||
Files: src/lib/zlib/*
|
||||
Copyright: 1995-2012, 2016 Jean-loup Gailly and Mark Adler
|
||||
License: zlib
|
||||
This software is provided 'as-is', without any express or implied
|
||||
|
|
|
@ -2,7 +2,7 @@ Announce.txt
|
|||
Changes.txt
|
||||
Copyright.txt
|
||||
README-SDL.txt
|
||||
Readme.txt
|
||||
README.md
|
||||
docs/*.html
|
||||
docs/graphics/*.png
|
||||
Todo.txt
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<body>
|
||||
|
||||
<center><b><font size="7">Stella</font></b></center>
|
||||
<center><h4><b>Release 6.7.1</b></h4></center>
|
||||
<center><h4><b>Release 7.0</b></h4></center>
|
||||
<center><h1><b>Integrated Debugger</b></h1></center>
|
||||
<center><h4><b>(a work in progress)</b></h4></center>
|
||||
<br>
|
||||
|
@ -45,6 +45,7 @@
|
|||
<li><a href="#PseudoRegisters">Pseudo-Registers</a></li>
|
||||
<li><a href="#Watches">Watches</a></li>
|
||||
<li><a href="#Traps">Traps</a></li>
|
||||
<li><a href="#Timers">Timers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#SaveWork">Save your work!</a></li>
|
||||
|
@ -310,7 +311,7 @@ more convenient.
|
|||
</li>
|
||||
<li>
|
||||
"<rom_filename>.sym" (located in the same directory as the ROM)</br>
|
||||
If you provied the -l and -s parameters DASM will create these two files during
|
||||
If you provide the -l and -s parameters DASM will create these two files during
|
||||
assembly. Stella uses the file content to display the correct labels.
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -858,6 +859,22 @@ can remove a trap with "delTrap number", where the number comes from
|
|||
"listTraps" or by entering the identical trap again. You can get rid of
|
||||
all traps at once with the "clearTraps" command.</p></p>
|
||||
|
||||
<h4><a name="Timers">Timers</a></h4>
|
||||
|
||||
<p>Timers are used to measure cycles used between two timer points. They
|
||||
measure the minimum, maximum and average cycles executed between their two
|
||||
timer points. Start and end points can be set via prompt command or ROM
|
||||
Disassembly settings dialog.</p>
|
||||
|
||||
<p>If the timer point is defined without an address or bank, the current PC
|
||||
address or bank are used. If a '+' is added, both timer points use address
|
||||
mirrors too, a '*' triggers both timer points in any bank.</p>
|
||||
|
||||
<p>All timers can be shown in detail with "listTimers", a single timer
|
||||
with "printTimer number". "resetTimers" allows resetting all timer statistics,
|
||||
"delTimer number" removes a single timer. All timers can be deleted with the
|
||||
"clearTimers" command.</p>
|
||||
|
||||
</br>
|
||||
<h3><a name="SaveWork">Save your work!</a></h3>
|
||||
<p>Stella offers several commands to save your work inside the debugger for
|
||||
|
@ -945,6 +962,7 @@ Type "help 'cmd'" to see extended information about the given command.</p>
|
|||
clearConfig - Clear DiStella config directives [bank xx]
|
||||
clearHistory - Clear the prompt history
|
||||
clearSaveStateIfs - Clear all saveState points
|
||||
clearTimers - Clear all timers
|
||||
clearTraps - Clear all traps
|
||||
clearWatches - Clear all watches
|
||||
cls - Clear prompt area of text
|
||||
|
@ -959,6 +977,7 @@ clearSaveStateIfs - Clear all saveState points
|
|||
delFunction - Delete function with label xx
|
||||
delSaveStateIf - Delete conditional saveState point <xx>
|
||||
delTrap - Delete trap <xx>
|
||||
delTimer - Delete timer <xx>
|
||||
delWatch - Delete watch <xx>
|
||||
disAsm - Disassemble address xx [yy lines] (default=PC)
|
||||
dump - Dump data at address <xx> [to yy] [1: memory; 2: CPU state; 4: input regs] [?]
|
||||
|
@ -988,14 +1007,17 @@ clearSaveStateIfs - Clear all saveState points
|
|||
loadAllStates - Load all emulator states
|
||||
loadState - Load emulator state xx (0-9)
|
||||
logBreaks - Logs breaks and traps and continues emulation
|
||||
logTrace - Logs emulation (note: emulation may slow down and the log becomes huge soon)
|
||||
n - Negative Flag: set (0 or 1), or toggle (no arg)
|
||||
palette - Show current TIA palette
|
||||
pc - Set Program Counter to address xx
|
||||
pCol - Mark 'PCOL' range in disassembly
|
||||
pGfx - Mark 'PGFX' range in disassembly
|
||||
print - Evaluate/print expression xx in hex/dec/binary
|
||||
printTimer - Print details of timer xx
|
||||
ram - Show ZP RAM, or set address xx to yy1 [yy2 ...]
|
||||
reset - Reset system to power-on state
|
||||
resetTimers - Reset all timers' statistics
|
||||
rewind - Rewind state by one or [xx] steps/traces/scanlines/frames...
|
||||
riot - Show RIOT timer/input status
|
||||
rom - Set ROM address xx to yy1 [yy2 ...]
|
||||
|
@ -1017,7 +1039,9 @@ clearSaveStateIfs - Clear all saveState points
|
|||
scanLine - Advance emulation by <xx> scanlines (default=1)
|
||||
step - Single step CPU [with count xx]
|
||||
stepWhile - Single step CPU while <condition> is true
|
||||
swchb - Set SWCHB to value xx
|
||||
tia - Show TIA state
|
||||
timer - Set a timer point
|
||||
trace - Single step CPU over subroutines [with count xx]
|
||||
trap - Trap read/write access to address(es) xx [yy]
|
||||
trapIf - On <condition> trap R/W access to address(es) xx [yy]
|
||||
|
@ -1084,7 +1108,7 @@ VDELBL selects the register that is used to control the ball. This is
|
|||
visualized in the debugger in the same way as the two copies of GRP0 and
|
||||
GRP1</p>
|
||||
|
||||
<p>For many registers, writes don't take effect immediatelly as the
|
||||
<p>For many registers, writes don't take effect immediately as the
|
||||
TIA takes some color clocks to change state. In Stella's TIA core, this
|
||||
is implemented by queueing the writes, and the contents of this queue
|
||||
are visualized in the debugger in the "Queued Writes" area of the TIA tab.</p>
|
||||
|
@ -1562,13 +1586,16 @@ matches the address of the disassembly line where the mouse was clicked.</li>
|
|||
<li><b>Disassemble @ current line</b>: Disassemble from the disassembly line where the mouse was clicked.
|
||||
This allows to fill gaps in the disassembly and is most useful for bankswitched ROMs.</li>
|
||||
|
||||
<li><b>Set timer @ current line</b>: Set a timer point using the current
|
||||
disassembly line's address and bank</li>
|
||||
|
||||
<li><b>Show tentative code</b>: Allow DiStella to do a static analysis/disassembly.</li>
|
||||
|
||||
<li><b>Show PC addresses</b>: Show Program Counter addresses as labels (where there
|
||||
isn't already a defined label).</li>
|
||||
|
||||
<li><b>Show GFX as binary</b>: Switch between displaying/editing GFX and PGFX sections
|
||||
in either binary or hexidecimal.</li>
|
||||
in either binary or hexadecimal.</li>
|
||||
|
||||
<li><b>Use address relocation</b>: Corresponds to the DiStella '-r' option
|
||||
(Relocate calls out of address range).</br>
|
||||
|
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 197 B |
Before Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
915
docs/index.html
|
@ -58,7 +58,7 @@
|
|||
|
||||
<center><h1>Stella for RetroN 77</h1></center>
|
||||
<center><h2>Atari 2600 VCS emulator</h2></center>
|
||||
<center>Release 6.7.1</center>
|
||||
<center>Release 7.0</center>
|
||||
<center><h2>Quick Navigation Guide</h2></center>
|
||||
<br/>
|
||||
|
||||
|
@ -95,17 +95,17 @@
|
|||
<td>Open settings</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 7</td>
|
||||
<td>Button 8</td>
|
||||
<td>-</td>
|
||||
<td>Rewind game</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 8</td>
|
||||
<td>Button 9</td>
|
||||
<td>MODE</td>
|
||||
<td>Select</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 9</td>
|
||||
<td>Button 10</td>
|
||||
<td>RESET</td>
|
||||
<td>Reset</td>
|
||||
</tr>
|
||||
|
@ -160,6 +160,21 @@
|
|||
Button 2 or 6 close the menu without any action.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 1 + Left</td>
|
||||
<td>-</td>
|
||||
<td>Display previous image</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 1 + Right</td>
|
||||
<td>-</td>
|
||||
<td>Display next image</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 1 + Up</td>
|
||||
<td>-</td>
|
||||
<td>Toggle image zoom</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button 2</td>
|
||||
<td>SKILL P2</td>
|
||||
|
@ -249,7 +264,7 @@
|
|||
<td width="41%">This dialog is similar to the PC version's
|
||||
<a href="index.html#CommandMenu"><b>Command Menu</b></a>, but with some
|
||||
commands especially selected for the RetroN 77.</td>
|
||||
<td><p><img src="commandsmenu_r77.png"></p></td>
|
||||
<td><p><img src="graphics/commandsmenu_r77.png"></p></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
@ -294,7 +309,7 @@
|
|||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td><p><img src="basic_settings.png"></p></td>
|
||||
<td><p><img src="graphics/basic_settings.png"></p></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -21,19 +21,19 @@
|
|||
#include "BankRomCheat.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
BankRomCheat::BankRomCheat(OSystem& os, const string& name, const string& code)
|
||||
BankRomCheat::BankRomCheat(OSystem& os, string_view name, string_view code)
|
||||
: Cheat(os, name, code)
|
||||
{
|
||||
if(myCode.length() == 7)
|
||||
myCode = "0" + code;
|
||||
myCode = "0" + string{code};
|
||||
|
||||
bank = unhex(myCode.substr(0, 2));
|
||||
address = 0xf000 + unhex(myCode.substr(2, 3));
|
||||
value = static_cast<uInt8>(unhex(myCode.substr(5, 2)));
|
||||
count = static_cast<uInt8>(unhex(myCode.substr(7, 1)) + 1);
|
||||
bank = BSPF::stoi<16>(myCode.substr(0, 2));
|
||||
address = 0xf000 + BSPF::stoi<16>(myCode.substr(2, 3));
|
||||
value = static_cast<uInt8>(BSPF::stoi<16>(myCode.substr(5, 2)));
|
||||
count = static_cast<uInt8>(BSPF::stoi<16>(myCode.substr(7, 1)) + 1);
|
||||
|
||||
// Back up original data; we need this if the cheat is ever disabled
|
||||
for(int i = 0; i < count; ++i)
|
||||
for(int i = 0; std::cmp_less(i, count); ++i)
|
||||
savedRom[i] = myOSystem.console().cartridge().peek(address + i);
|
||||
}
|
||||
|
||||
|
@ -50,8 +50,8 @@ bool BankRomCheat::disable()
|
|||
const int oldBank = myOSystem.console().cartridge().getBank(address);
|
||||
myOSystem.console().cartridge().bank(bank);
|
||||
|
||||
for(int i = 0; i < count; ++i)
|
||||
myOSystem.console().cartridge().patch(address + i, savedRom[i]);
|
||||
for(int i = 0; std::cmp_less(i, count); ++i)
|
||||
myOSystem.console().cartridge().patch(address + i, savedRom[i]);
|
||||
|
||||
myOSystem.console().cartridge().bank(oldBank);
|
||||
|
||||
|
@ -66,7 +66,7 @@ void BankRomCheat::evaluate()
|
|||
const int oldBank = myOSystem.console().cartridge().getBank(address);
|
||||
myOSystem.console().cartridge().bank(bank);
|
||||
|
||||
for(int i = 0; i < count; ++i)
|
||||
for(int i = 0; std::cmp_less(i, count); ++i)
|
||||
myOSystem.console().cartridge().patch(address + i, value);
|
||||
|
||||
myOSystem.console().cartridge().bank(oldBank);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -23,7 +23,7 @@
|
|||
class BankRomCheat : public Cheat
|
||||
{
|
||||
public:
|
||||
BankRomCheat(OSystem& os, const string& name, const string& code);
|
||||
BankRomCheat(OSystem& os, string_view name, string_view code);
|
||||
~BankRomCheat() override = default;
|
||||
|
||||
bool enable() override;
|
||||
|
@ -31,7 +31,7 @@ class BankRomCheat : public Cheat
|
|||
void evaluate() override;
|
||||
|
||||
private:
|
||||
std::array<uInt8, 16> savedRom;
|
||||
std::array<uInt8, 16> savedRom{};
|
||||
uInt16 address{0};
|
||||
uInt8 value{0};
|
||||
uInt8 count{0};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -25,9 +25,9 @@ class OSystem;
|
|||
class Cheat
|
||||
{
|
||||
public:
|
||||
Cheat(OSystem& osystem, const string& name, const string& code)
|
||||
Cheat(OSystem& osystem, string_view name, string_view code)
|
||||
: myOSystem{osystem},
|
||||
myName{name == "" ? code : name},
|
||||
myName{name.empty() ? code : name},
|
||||
myCode{code} { }
|
||||
virtual ~Cheat() = default;
|
||||
|
||||
|
@ -40,23 +40,6 @@ class Cheat
|
|||
|
||||
virtual void evaluate() = 0;
|
||||
|
||||
protected:
|
||||
static uInt16 unhex(const string& hex)
|
||||
{
|
||||
int ret = 0;
|
||||
for(const auto c: hex)
|
||||
{
|
||||
ret *= 16;
|
||||
if(c >= '0' && c <= '9')
|
||||
ret += c - '0';
|
||||
else if(c >= 'A' && c <= 'F')
|
||||
ret += c - 'A' + 10;
|
||||
else
|
||||
ret += c - 'a' + 10;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
OSystem& myOSystem;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -25,7 +25,6 @@
|
|||
#include "Font.hxx"
|
||||
#include "InputTextDialog.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "Props.hxx"
|
||||
#include "Widget.hxx"
|
||||
|
||||
#include "CheatCodeDialog.hxx"
|
||||
|
@ -83,18 +82,18 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
|
|||
|
||||
// Inputbox which will pop up when adding/editing a cheat
|
||||
StringList labels;
|
||||
labels.push_back("Name ");
|
||||
labels.push_back("Code (hex) ");
|
||||
labels.emplace_back("Name ");
|
||||
labels.emplace_back("Code (hex) ");
|
||||
myCheatInput = make_unique<InputTextDialog>(this, font, labels, "Cheat code");
|
||||
myCheatInput->setTarget(this);
|
||||
|
||||
// Add filtering for each textfield
|
||||
EditableWidget::TextFilter f0 = [](char c) {
|
||||
const EditableWidget::TextFilter f0 = [](char c) {
|
||||
return isprint(c) && c != '\"' && c != ':';
|
||||
};
|
||||
myCheatInput->setTextFilter(f0, 0);
|
||||
|
||||
EditableWidget::TextFilter f1 = [](char c) {
|
||||
const EditableWidget::TextFilter f1 = [](char c) {
|
||||
return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9');
|
||||
};
|
||||
myCheatInput->setTextFilter(f1, 1);
|
||||
|
@ -111,7 +110,7 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CheatCodeDialog::~CheatCodeDialog()
|
||||
CheatCodeDialog::~CheatCodeDialog() // NOLINT (we need an empty d'tor)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -128,14 +127,14 @@ void CheatCodeDialog::loadConfig()
|
|||
for(const auto& c: list)
|
||||
{
|
||||
l.push_back(c->name());
|
||||
b.push_back(bool(c->enabled()));
|
||||
b.push_back(c->enabled());
|
||||
}
|
||||
myCheatList->setList(l, b);
|
||||
|
||||
// Redraw the list, auto-selecting the first item if possible
|
||||
myCheatList->setSelected(l.size() > 0 ? 0 : -1);
|
||||
myCheatList->setSelected(!l.empty() ? 0 : -1);
|
||||
|
||||
const bool enabled = (list.size() > 0);
|
||||
const bool enabled = !list.empty();
|
||||
myEditButton->setEnabled(enabled);
|
||||
myRemoveButton->setEnabled(enabled);
|
||||
}
|
||||
|
@ -233,7 +232,7 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
{
|
||||
const string& name = myCheatInput->getResult(0);
|
||||
const string& code = myCheatInput->getResult(1);
|
||||
if(instance().cheat().isValidCode(code))
|
||||
if(CheatManager::isValidCode(code))
|
||||
{
|
||||
myCheatInput->close();
|
||||
instance().cheat().add(name, code);
|
||||
|
@ -250,7 +249,7 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
const string& code = myCheatInput->getResult(1);
|
||||
const bool enable = myCheatList->getSelectedState();
|
||||
const int idx = myCheatList->getSelected();
|
||||
if(instance().cheat().isValidCode(code))
|
||||
if(CheatManager::isValidCode(code))
|
||||
{
|
||||
myCheatInput->close();
|
||||
instance().cheat().add(name, code, enable, idx);
|
||||
|
@ -273,7 +272,7 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
{
|
||||
const string& name = myCheatInput->getResult(0);
|
||||
const string& code = myCheatInput->getResult(1);
|
||||
if(instance().cheat().isValidCode(code))
|
||||
if(CheatManager::isValidCode(code))
|
||||
{
|
||||
myCheatInput->close();
|
||||
instance().cheat().addOneShot(name, code);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -16,7 +16,6 @@
|
|||
//============================================================================
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "Cheat.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "CheetahCheat.hxx"
|
||||
|
@ -33,10 +32,10 @@ CheatManager::CheatManager(OSystem& osystem)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CheatManager::add(const string& name, const string& code,
|
||||
bool CheatManager::add(string_view name, string_view code,
|
||||
bool enable, int idx)
|
||||
{
|
||||
shared_ptr<Cheat> cheat = createCheat(name, code);
|
||||
const shared_ptr<Cheat> cheat = createCheat(name, code);
|
||||
if(!cheat)
|
||||
return false;
|
||||
|
||||
|
@ -79,7 +78,7 @@ void CheatManager::remove(int idx)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheatManager::addPerFrame(const string& name, const string& code, bool enable)
|
||||
void CheatManager::addPerFrame(string_view name, string_view code, bool enable)
|
||||
{
|
||||
// The actual cheat will always be in the main list; we look there first
|
||||
shared_ptr<Cheat> cheat;
|
||||
|
@ -93,8 +92,8 @@ void CheatManager::addPerFrame(const string& name, const string& code, bool enab
|
|||
}
|
||||
|
||||
// Make sure there are no duplicates
|
||||
bool found = false;
|
||||
uInt32 i;
|
||||
bool found{false};
|
||||
uInt32 i{0};
|
||||
for(i = 0; i < myPerFrameList.size(); ++i)
|
||||
{
|
||||
if(myPerFrameList[i]->code() == cheat->code())
|
||||
|
@ -117,16 +116,16 @@ void CheatManager::addPerFrame(const string& name, const string& code, bool enab
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheatManager::addOneShot(const string& name, const string& code)
|
||||
void CheatManager::addOneShot(string_view name, string_view code)
|
||||
{
|
||||
// Evaluate this cheat once, and then immediately discard it
|
||||
shared_ptr<Cheat> cheat = createCheat(name, code);
|
||||
const shared_ptr<Cheat> cheat = createCheat(name, code);
|
||||
if(cheat)
|
||||
cheat->evaluate();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
shared_ptr<Cheat> CheatManager::createCheat(const string& name, const string& code) const
|
||||
shared_ptr<Cheat> CheatManager::createCheat(string_view name, string_view code) const
|
||||
{
|
||||
if(!isValidCode(code))
|
||||
return nullptr;
|
||||
|
@ -136,14 +135,14 @@ shared_ptr<Cheat> CheatManager::createCheat(const string& name, const string& co
|
|||
{
|
||||
case 4: return make_shared<RamCheat>(myOSystem, name, code);
|
||||
case 6: return make_shared<CheetahCheat>(myOSystem, name, code);
|
||||
case 7: return make_shared<BankRomCheat>(myOSystem, name, code);
|
||||
case 7: [[fallthrough]];
|
||||
case 8: return make_shared<BankRomCheat>(myOSystem, name, code);
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheatManager::parse(const string& cheats)
|
||||
void CheatManager::parse(string_view cheats)
|
||||
{
|
||||
StringList s;
|
||||
string::size_type lastPos = cheats.find_first_not_of(',', 0);
|
||||
|
@ -198,7 +197,7 @@ void CheatManager::parse(const string& cheats)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheatManager::enable(const string& code, bool enable)
|
||||
void CheatManager::enable(string_view code, bool enable)
|
||||
{
|
||||
for(const auto& cheat: myCheatList)
|
||||
{
|
||||
|
@ -225,7 +224,7 @@ void CheatManager::loadCheatDatabase()
|
|||
// Loop reading cheats
|
||||
while(getline(in, line))
|
||||
{
|
||||
if(line.length() == 0)
|
||||
if(line.empty())
|
||||
continue;
|
||||
|
||||
const string::size_type one = line.find('\"', 0);
|
||||
|
@ -256,14 +255,14 @@ void CheatManager::saveCheatDatabase()
|
|||
|
||||
stringstream out;
|
||||
for(const auto& [md5, cheat]: myCheatMap)
|
||||
out << "\"" << md5 << "\" " << "\"" << cheat << "\"" << endl;
|
||||
out << "\"" << md5 << "\" " << "\"" << cheat << "\"\n";
|
||||
|
||||
try { myOSystem.cheatFile().write(out); }
|
||||
catch(...) { return; }
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheatManager::loadCheats(const string& md5sum)
|
||||
void CheatManager::loadCheats(string_view md5sum)
|
||||
{
|
||||
myPerFrameList.clear();
|
||||
myCheatList.clear();
|
||||
|
@ -272,11 +271,11 @@ void CheatManager::loadCheats(const string& md5sum)
|
|||
// Set up any cheatcodes that was on the command line
|
||||
// (and remove the key from the settings, so they won't get set again)
|
||||
const string& cheats = myOSystem.settings().getString("cheat");
|
||||
if(cheats != "")
|
||||
if(!cheats.empty())
|
||||
myOSystem.settings().setValue("cheat", "");
|
||||
|
||||
const auto& iter = myCheatMap.find(md5sum);
|
||||
if(iter == myCheatMap.end() && cheats == "")
|
||||
if(iter == myCheatMap.end() && cheats.empty())
|
||||
return;
|
||||
|
||||
// Remember the cheats for this ROM
|
||||
|
@ -287,7 +286,7 @@ void CheatManager::loadCheats(const string& md5sum)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CheatManager::saveCheats(const string& md5sum)
|
||||
void CheatManager::saveCheats(string_view md5sum)
|
||||
{
|
||||
ostringstream cheats;
|
||||
for(uInt32 i = 0; i < myCheatList.size(); ++i)
|
||||
|
@ -299,7 +298,7 @@ void CheatManager::saveCheats(const string& md5sum)
|
|||
cheats << ",";
|
||||
}
|
||||
|
||||
bool changed = cheats.str() != myCurrentCheat;
|
||||
const bool changed = cheats.view() != myCurrentCheat;
|
||||
|
||||
// Only update the list if absolutely necessary
|
||||
if(changed)
|
||||
|
@ -311,8 +310,8 @@ void CheatManager::saveCheats(const string& md5sum)
|
|||
myCheatMap.erase(iter);
|
||||
|
||||
// Add new entry only if there are any cheats defined
|
||||
if(cheats.str() != "")
|
||||
myCheatMap.emplace(md5sum, cheats.str());
|
||||
if(!cheats.view().empty())
|
||||
myCheatMap.emplace(md5sum, cheats.view());
|
||||
}
|
||||
|
||||
// Update the dirty flag
|
||||
|
@ -322,7 +321,7 @@ void CheatManager::saveCheats(const string& md5sum)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CheatManager::isValidCode(const string& code) const
|
||||
bool CheatManager::isValidCode(string_view code)
|
||||
{
|
||||
for(const auto c: code)
|
||||
if(!isxdigit(c))
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -38,6 +38,7 @@ class CheatManager
|
|||
{
|
||||
public:
|
||||
explicit CheatManager(OSystem& osystem);
|
||||
~CheatManager() = default;
|
||||
|
||||
/**
|
||||
Adds the specified cheat to an internal list.
|
||||
|
@ -49,7 +50,7 @@ class CheatManager
|
|||
|
||||
@return Whether the cheat was created and enabled.
|
||||
*/
|
||||
bool add(const string& name, const string& code,
|
||||
bool add(string_view name, string_view code,
|
||||
bool enable = true, int idx = -1);
|
||||
|
||||
/**
|
||||
|
@ -68,7 +69,7 @@ class CheatManager
|
|||
@param code The actual cheatcode
|
||||
@param enable Add or remove the cheat to the per-frame list
|
||||
*/
|
||||
void addPerFrame(const string& name, const string& code, bool enable);
|
||||
void addPerFrame(string_view name, string_view code, bool enable);
|
||||
|
||||
/**
|
||||
Creates and enables a one-shot cheat. One-shot cheats are the
|
||||
|
@ -78,7 +79,7 @@ class CheatManager
|
|||
@param name Name of the cheat (not absolutely required)
|
||||
@param code The actual cheatcode (in hex)
|
||||
*/
|
||||
void addOneShot(const string& name, const string& code);
|
||||
void addOneShot(string_view name, string_view code);
|
||||
|
||||
/**
|
||||
Enable/disabled the cheat specified by the given code.
|
||||
|
@ -86,7 +87,7 @@ class CheatManager
|
|||
@param code The actual cheatcode to search for
|
||||
@param enable Enable/disable the cheat
|
||||
*/
|
||||
void enable(const string& code, bool enable);
|
||||
void enable(string_view code, bool enable);
|
||||
|
||||
/**
|
||||
Returns the game cheatlist.
|
||||
|
@ -111,17 +112,17 @@ class CheatManager
|
|||
/**
|
||||
Load cheats for ROM with given MD5sum to cheatlist(s).
|
||||
*/
|
||||
void loadCheats(const string& md5sum);
|
||||
void loadCheats(string_view md5sum);
|
||||
|
||||
/**
|
||||
Saves cheats for ROM with given MD5sum to cheat map.
|
||||
*/
|
||||
void saveCheats(const string& md5sum);
|
||||
void saveCheats(string_view md5sum);
|
||||
|
||||
/**
|
||||
Checks if a code is valid.
|
||||
*/
|
||||
bool isValidCode(const string& code) const;
|
||||
static bool isValidCode(string_view code);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -132,14 +133,14 @@ class CheatManager
|
|||
|
||||
@return The cheat (if was created), else nullptr.
|
||||
*/
|
||||
shared_ptr<Cheat> createCheat(const string& name, const string& code) const;
|
||||
shared_ptr<Cheat> createCheat(string_view name, string_view code) const;
|
||||
|
||||
/**
|
||||
Parses a list of cheats and adds/enables each one.
|
||||
|
||||
@param cheats Comma-separated list of cheats (without any names)
|
||||
*/
|
||||
void parse(const string& cheats);
|
||||
void parse(string_view cheats);
|
||||
|
||||
private:
|
||||
OSystem& myOSystem;
|
||||
|
@ -147,7 +148,7 @@ class CheatManager
|
|||
CheatList myCheatList;
|
||||
CheatList myPerFrameList;
|
||||
|
||||
std::map<string,string> myCheatMap;
|
||||
std::map<string,string, std::less<>> myCheatMap;
|
||||
string myCheatFile;
|
||||
|
||||
// This is set each time a new cheat/ROM is loaded, for later
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -21,14 +21,14 @@
|
|||
#include "CheetahCheat.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CheetahCheat::CheetahCheat(OSystem& os, const string& name, const string& code)
|
||||
CheetahCheat::CheetahCheat(OSystem& os, string_view name, string_view code)
|
||||
: Cheat(os, name, code),
|
||||
address{static_cast<uInt16>(0xf000 + unhex(code.substr(0, 3)))},
|
||||
value{static_cast<uInt8>(unhex(code.substr(3, 2)))},
|
||||
count{static_cast<uInt8>(unhex(code.substr(5, 1)) + 1)}
|
||||
address{static_cast<uInt16>(0xf000 + BSPF::stoi<16>(code.substr(0, 3)))},
|
||||
value{static_cast<uInt8>(BSPF::stoi<16>(code.substr(3, 2)))},
|
||||
count{static_cast<uInt8>(BSPF::stoi<16>(code.substr(5, 1)) + 1)}
|
||||
{
|
||||
// Back up original data; we need this if the cheat is ever disabled
|
||||
for(int i = 0; i < count; ++i)
|
||||
for(uInt8 i = 0; i < count; ++i)
|
||||
savedRom[i] = myOSystem.console().cartridge().peek(address + i);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ bool CheetahCheat::enable()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CheetahCheat::disable()
|
||||
{
|
||||
for(int i = 0; i < count; ++i)
|
||||
for(uInt8 i = 0; i < count; ++i)
|
||||
myOSystem.console().cartridge().patch(address + i, savedRom[i]);
|
||||
|
||||
return myEnabled = false;
|
||||
|
@ -53,7 +53,7 @@ void CheetahCheat::evaluate()
|
|||
{
|
||||
if(!myEnabled)
|
||||
{
|
||||
for(int i = 0; i < count; ++i)
|
||||
for(uInt8 i = 0; i < count; ++i)
|
||||
myOSystem.console().cartridge().patch(address + i, value);
|
||||
|
||||
myEnabled = true;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -23,7 +23,7 @@
|
|||
class CheetahCheat : public Cheat
|
||||
{
|
||||
public:
|
||||
CheetahCheat(OSystem& os, const string& name, const string& code);
|
||||
CheetahCheat(OSystem& os, string_view name, string_view code);
|
||||
~CheetahCheat() override = default;
|
||||
|
||||
bool enable() override;
|
||||
|
@ -31,7 +31,7 @@ class CheetahCheat : public Cheat
|
|||
void evaluate() override;
|
||||
|
||||
private:
|
||||
std::array<uInt8, 16> savedRom;
|
||||
std::array<uInt8, 16> savedRom{};
|
||||
uInt16 address{0};
|
||||
uInt8 value{0};
|
||||
uInt8 count{0};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -23,10 +23,10 @@
|
|||
#include "RamCheat.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RamCheat::RamCheat(OSystem& os, const string& name, const string& code)
|
||||
RamCheat::RamCheat(OSystem& os, string_view name, string_view code)
|
||||
: Cheat(os, name, code),
|
||||
address{static_cast<uInt16>(unhex(myCode.substr(0, 2)))},
|
||||
value{static_cast<uInt8>(unhex(myCode.substr(2, 2)))}
|
||||
address{static_cast<uInt16>(BSPF::stoi<16>(myCode.substr(0, 2)))},
|
||||
value{static_cast<uInt8>(BSPF::stoi<16>(myCode.substr(2, 2)))}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,5 +55,5 @@ bool RamCheat::disable()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RamCheat::evaluate()
|
||||
{
|
||||
myOSystem.console().system().poke(address, value);
|
||||
myOSystem.console().system().pokeOob(address, value);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -23,7 +23,7 @@
|
|||
class RamCheat : public Cheat
|
||||
{
|
||||
public:
|
||||
RamCheat(OSystem& os, const string& name, const string& code);
|
||||
RamCheat(OSystem& os, string_view name, string_view code);
|
||||
~RamCheat() override = default;
|
||||
|
||||
bool enable() override;
|
||||
|
|
|
@ -7,8 +7,10 @@ MODULE_OBJS := \
|
|||
src/cheat/BankRomCheat.o \
|
||||
src/cheat/RamCheat.o
|
||||
|
||||
MODULE_TEST_OBJS =
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/cheat
|
||||
|
||||
# Include common rules
|
||||
# Include common rules
|
||||
include $(srcdir)/common.rules
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -29,16 +29,20 @@ AudioQueue::AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo)
|
|||
{
|
||||
const uInt8 sampleSize = myIsStereo ? 2 : 1;
|
||||
|
||||
myFragmentBuffer = make_unique<Int16[]>(myFragmentSize * sampleSize * (capacity + 2));
|
||||
myFragmentBuffer = make_unique<Int16[]>(
|
||||
static_cast<size_t>(myFragmentSize) * sampleSize * (capacity + 2));
|
||||
|
||||
for (uInt32 i = 0; i < capacity; ++i)
|
||||
myFragmentQueue[i] = myAllFragments[i] = myFragmentBuffer.get() + i * sampleSize * myFragmentSize;
|
||||
myFragmentQueue[i] = myAllFragments[i] = myFragmentBuffer.get() +
|
||||
static_cast<size_t>(myFragmentSize) * sampleSize * i;
|
||||
|
||||
myAllFragments[capacity] = myFirstFragmentForEnqueue =
|
||||
myFragmentBuffer.get() + capacity * sampleSize * myFragmentSize;
|
||||
myFragmentBuffer.get() + static_cast<size_t>(myFragmentSize) * sampleSize *
|
||||
capacity;
|
||||
|
||||
myAllFragments[capacity + 1] = myFirstFragmentForDequeue =
|
||||
myFragmentBuffer.get() + (capacity + 1) * sampleSize * myFragmentSize;
|
||||
myFragmentBuffer.get() + static_cast<size_t>(myFragmentSize) * sampleSize *
|
||||
(capacity + 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -50,7 +54,7 @@ uInt32 AudioQueue::capacity() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioQueue::size() const
|
||||
{
|
||||
lock_guard<mutex> guard(myMutex);
|
||||
const lock_guard<mutex> guard(myMutex);
|
||||
|
||||
return mySize;
|
||||
}
|
||||
|
@ -70,7 +74,7 @@ uInt32 AudioQueue::fragmentSize() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int16* AudioQueue::enqueue(Int16* fragment)
|
||||
{
|
||||
lock_guard<mutex> guard(myMutex);
|
||||
const lock_guard<mutex> guard(myMutex);
|
||||
|
||||
Int16* newFragment = nullptr;
|
||||
|
||||
|
@ -83,7 +87,7 @@ Int16* AudioQueue::enqueue(Int16* fragment)
|
|||
return newFragment;
|
||||
}
|
||||
|
||||
const uInt8 capacity = static_cast<uInt8>(myFragmentQueue.size());
|
||||
const auto capacity = static_cast<uInt8>(myFragmentQueue.size());
|
||||
const uInt8 fragmentIndex = (myNextFragment + mySize) % capacity;
|
||||
|
||||
newFragment = myFragmentQueue.at(fragmentIndex);
|
||||
|
@ -101,7 +105,7 @@ Int16* AudioQueue::enqueue(Int16* fragment)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int16* AudioQueue::dequeue(Int16* fragment)
|
||||
{
|
||||
lock_guard<mutex> guard(myMutex);
|
||||
const lock_guard<mutex> guard(myMutex);
|
||||
|
||||
if (mySize == 0) return nullptr;
|
||||
|
||||
|
@ -124,7 +128,7 @@ Int16* AudioQueue::dequeue(Int16* fragment)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioQueue::closeSink(Int16* fragment)
|
||||
{
|
||||
lock_guard<mutex> guard(myMutex);
|
||||
const lock_guard<mutex> guard(myMutex);
|
||||
|
||||
if (myFirstFragmentForDequeue && fragment)
|
||||
throw runtime_error("attempt to return unknown buffer on closeSink");
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -24,7 +24,7 @@
|
|||
#include "StaggeredLogger.hxx"
|
||||
|
||||
/**
|
||||
This class implements a an audio queue that acts both like a ring buffer
|
||||
This class implements an audio queue that acts both like a ring buffer
|
||||
and a pool of audio fragments. The TIA emulation core fills a fragment
|
||||
with samples and then returns it to the queue, receiving a new fragment
|
||||
in return. The sound driver removes fragments for playback from the
|
||||
|
@ -46,6 +46,7 @@ class AudioQueue
|
|||
@param isStereo Whether samples are stereo or mono.
|
||||
*/
|
||||
AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo);
|
||||
~AudioQueue() = default;
|
||||
|
||||
/**
|
||||
Capacity getter.
|
||||
|
@ -133,7 +134,6 @@ class AudioQueue
|
|||
StaggeredLogger myOverflowLogger{"audio buffer overflow", Logger::Level::INFO};
|
||||
|
||||
private:
|
||||
|
||||
AudioQueue() = delete;
|
||||
AudioQueue(const AudioQueue&) = delete;
|
||||
AudioQueue(AudioQueue&&) = delete;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -35,11 +35,11 @@ namespace {
|
|||
constexpr AudioSettings::ResamplingQuality normalizeResamplingQuality(int numericResamplingQuality)
|
||||
{
|
||||
return (
|
||||
numericResamplingQuality >= static_cast<int>(AudioSettings::ResamplingQuality::nearestNeightbour) &&
|
||||
numericResamplingQuality >= static_cast<int>(AudioSettings::ResamplingQuality::nearestNeighbour) &&
|
||||
numericResamplingQuality <= static_cast<int>(AudioSettings::ResamplingQuality::lanczos_3)
|
||||
) ? static_cast<AudioSettings::ResamplingQuality>(numericResamplingQuality) : AudioSettings::DEFAULT_RESAMPLING_QUALITY;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::AudioSettings(Settings& settings)
|
||||
|
@ -51,9 +51,10 @@ AudioSettings::AudioSettings(Settings& settings)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::normalize(Settings& settings)
|
||||
{
|
||||
int settingPreset = settings.getInt(SETTING_PRESET);
|
||||
const int settingPreset = settings.getInt(SETTING_PRESET);
|
||||
const Preset preset = normalizedPreset(settingPreset);
|
||||
if (static_cast<int>(preset) != settingPreset) settings.setValue(SETTING_PRESET, static_cast<int>(DEFAULT_PRESET));
|
||||
if (static_cast<int>(preset) != settingPreset)
|
||||
settings.setValue(SETTING_PRESET, static_cast<int>(DEFAULT_PRESET));
|
||||
|
||||
switch (settings.getInt(SETTING_SAMPLE_RATE)) {
|
||||
case 44100:
|
||||
|
@ -80,18 +81,19 @@ void AudioSettings::normalize(Settings& settings)
|
|||
break;
|
||||
}
|
||||
|
||||
int settingBufferSize = settings.getInt(SETTING_BUFFER_SIZE);
|
||||
const int settingBufferSize = settings.getInt(SETTING_BUFFER_SIZE);
|
||||
if (settingBufferSize < 0 || settingBufferSize > MAX_BUFFER_SIZE) settings.setValue(SETTING_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
|
||||
|
||||
int settingHeadroom = settings.getInt(SETTING_HEADROOM);
|
||||
const int settingHeadroom = settings.getInt(SETTING_HEADROOM);
|
||||
if (settingHeadroom < 0 || settingHeadroom > MAX_HEADROOM) settings.setValue(SETTING_HEADROOM, DEFAULT_HEADROOM);
|
||||
|
||||
int settingResamplingQuality = settings.getInt(SETTING_RESAMPLING_QUALITY);
|
||||
const ResamplingQuality resamplingQuality = normalizeResamplingQuality(settingResamplingQuality);
|
||||
const int settingResamplingQuality = settings.getInt(SETTING_RESAMPLING_QUALITY);
|
||||
const ResamplingQuality resamplingQuality =
|
||||
normalizeResamplingQuality(settingResamplingQuality);
|
||||
if (static_cast<int>(resamplingQuality) != settingResamplingQuality)
|
||||
settings.setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(DEFAULT_RESAMPLING_QUALITY));
|
||||
|
||||
int settingVolume = settings.getInt(SETTING_VOLUME);
|
||||
const int settingVolume = settings.getInt(SETTING_VOLUME);
|
||||
if (settingVolume < 0 || settingVolume > 100) settings.setValue(SETTING_VOLUME, DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
|
@ -186,7 +188,7 @@ void AudioSettings::setPreset(AudioSettings::Preset preset)
|
|||
myPresetFragmentSize = 1024;
|
||||
myPresetBufferSize = 6;
|
||||
myPresetHeadroom = 5;
|
||||
myPresetResamplingQuality = ResamplingQuality::nearestNeightbour;
|
||||
myPresetResamplingQuality = ResamplingQuality::nearestNeighbour;
|
||||
break;
|
||||
|
||||
case Preset::highQualityMediumLag:
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -26,7 +26,7 @@ class AudioSettings
|
|||
{
|
||||
public:
|
||||
|
||||
enum class Preset {
|
||||
enum class Preset: uInt8 {
|
||||
custom = 1,
|
||||
lowQualityMediumLag = 2,
|
||||
highQualityMediumLag = 3,
|
||||
|
@ -34,23 +34,23 @@ class AudioSettings
|
|||
ultraQualityMinimalLag = 5
|
||||
};
|
||||
|
||||
enum class ResamplingQuality {
|
||||
nearestNeightbour = 1,
|
||||
lanczos_2 = 2,
|
||||
lanczos_3 = 3
|
||||
enum class ResamplingQuality: uInt8 {
|
||||
nearestNeighbour = 1,
|
||||
lanczos_2 = 2,
|
||||
lanczos_3 = 3
|
||||
};
|
||||
|
||||
static constexpr const char* SETTING_PRESET = "audio.preset";
|
||||
static constexpr const char* SETTING_SAMPLE_RATE = "audio.sample_rate";
|
||||
static constexpr const char* SETTING_FRAGMENT_SIZE = "audio.fragment_size";
|
||||
static constexpr const char* SETTING_BUFFER_SIZE = "audio.buffer_size";
|
||||
static constexpr const char* SETTING_HEADROOM = "audio.headroom";
|
||||
static constexpr const char* SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
|
||||
static constexpr const char* SETTING_STEREO = "audio.stereo";
|
||||
static constexpr const char* SETTING_VOLUME = "audio.volume";
|
||||
static constexpr const char* SETTING_DEVICE = "audio.device";
|
||||
static constexpr const char* SETTING_ENABLED = "audio.enabled";
|
||||
static constexpr const char* SETTING_DPC_PITCH = "audio.dpc_pitch";
|
||||
static constexpr string_view SETTING_PRESET = "audio.preset";
|
||||
static constexpr string_view SETTING_SAMPLE_RATE = "audio.sample_rate";
|
||||
static constexpr string_view SETTING_FRAGMENT_SIZE = "audio.fragment_size";
|
||||
static constexpr string_view SETTING_BUFFER_SIZE = "audio.buffer_size";
|
||||
static constexpr string_view SETTING_HEADROOM = "audio.headroom";
|
||||
static constexpr string_view SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
|
||||
static constexpr string_view SETTING_STEREO = "audio.stereo";
|
||||
static constexpr string_view SETTING_VOLUME = "audio.volume";
|
||||
static constexpr string_view SETTING_DEVICE = "audio.device";
|
||||
static constexpr string_view SETTING_ENABLED = "audio.enabled";
|
||||
static constexpr string_view SETTING_DPC_PITCH = "audio.dpc_pitch";
|
||||
|
||||
static constexpr Preset DEFAULT_PRESET = Preset::highQualityMediumLag;
|
||||
static constexpr uInt32 DEFAULT_SAMPLE_RATE = 44100;
|
||||
|
@ -127,7 +127,7 @@ class AudioSettings
|
|||
|
||||
private:
|
||||
|
||||
Settings& mySettings;
|
||||
Settings& mySettings; // NOLINT: we want a reference here
|
||||
|
||||
Preset myPreset{Preset::custom};
|
||||
|
||||
|
@ -135,7 +135,7 @@ class AudioSettings
|
|||
uInt32 myPresetFragmentSize{0};
|
||||
uInt32 myPresetBufferSize{0};
|
||||
uInt32 myPresetHeadroom{0};
|
||||
ResamplingQuality myPresetResamplingQuality{ResamplingQuality::nearestNeightbour};
|
||||
ResamplingQuality myPresetResamplingQuality{ResamplingQuality::nearestNeighbour};
|
||||
|
||||
bool myIsPersistent{true};
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -24,7 +24,7 @@ string Base::toString(int value, Common::Base::Fmt outputBase)
|
|||
{
|
||||
static char vToS_buf[32]; // NOLINT : One place where C-style is acceptable
|
||||
|
||||
if(outputBase == Base::Fmt::_DEFAULT)
|
||||
if(outputBase == Base::Fmt::DEFAULT)
|
||||
outputBase = myDefaultBase;
|
||||
|
||||
switch(outputBase)
|
||||
|
@ -47,74 +47,83 @@ string Base::toString(int value, Common::Base::Fmt outputBase)
|
|||
|
||||
case Base::Fmt::_10: // base 10: 3 or 5 bytes (depending on value)
|
||||
if(value > -0x100 && value < 0x100)
|
||||
std::snprintf(vToS_buf, 5, "%3d", static_cast<Int16>(value));
|
||||
std::ignore = std::snprintf(vToS_buf, 5, "%3d", static_cast<Int16>(value));
|
||||
else
|
||||
std::snprintf(vToS_buf, 6, "%5d", value);
|
||||
std::ignore = std::snprintf(vToS_buf, 6, "%5d", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_10_02: // base 10: 2 digits (with leading zero)
|
||||
std::snprintf(vToS_buf, 3, "%02d", value);
|
||||
std::ignore = std::snprintf(vToS_buf, 3, "%02d", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_10_3: // base 10: 3 digits
|
||||
std::snprintf(vToS_buf, 4, "%3d", value);
|
||||
std::ignore = std::snprintf(vToS_buf, 4, "%3d", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_10_4: // base 10: 4 digits
|
||||
std::snprintf(vToS_buf, 5, "%4d", value);
|
||||
std::ignore = std::snprintf(vToS_buf, 5, "%4d", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_10_5: // base 10: 5 digits
|
||||
std::snprintf(vToS_buf, 6, "%5d", value);
|
||||
std::ignore = std::snprintf(vToS_buf, 6, "%5d", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_10_6: // base 10: 6 digits
|
||||
std::snprintf(vToS_buf, 7, "%6d", value);
|
||||
std::ignore = std::snprintf(vToS_buf, 7, "%6d", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_10_8: // base 10: 8 digits
|
||||
std::snprintf(vToS_buf, 9, "%8d", value);
|
||||
std::ignore = std::snprintf(vToS_buf, 9, "%8d", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_16_1: // base 16: 1 byte wide
|
||||
std::snprintf(vToS_buf, 2, hexUppercase() ? "%1X" : "%1x", value);
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 2, hexUppercase() ? "%1X" : "%1x", value);
|
||||
break;
|
||||
case Base::Fmt::_16_2: // base 16: 2 bytes wide
|
||||
std::snprintf(vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
|
||||
break;
|
||||
case Base::Fmt::_16_2_2:
|
||||
std::snprintf(vToS_buf, 6, hexUppercase() ? "%02X.%02X" : "%02x.%02x",
|
||||
value >> 8, value & 0xff );
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 6, hexUppercase() ? "%02X.%02X" : "%02x.%02x",
|
||||
value >> 8, value & 0xff );
|
||||
break;
|
||||
case Base::Fmt::_16_3_2:
|
||||
std::snprintf(vToS_buf, 7, hexUppercase() ? "%03X.%02X" : "%03x.%02x",
|
||||
value >> 8, value & 0xff );
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 7, hexUppercase() ? "%03X.%02X" : "%03x.%02x",
|
||||
value >> 8, value & 0xff );
|
||||
break;
|
||||
case Base::Fmt::_16_4: // base 16: 4 bytes wide
|
||||
std::snprintf(vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
|
||||
break;
|
||||
case Base::Fmt::_16_8: // base 16: 8 bytes wide
|
||||
std::snprintf(vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
|
||||
break;
|
||||
|
||||
case Base::Fmt::_16: // base 16: 2, 4, 8 bytes (depending on value)
|
||||
default:
|
||||
if(value < 0x100)
|
||||
std::snprintf(vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 3, hexUppercase() ? "%02X" : "%02x", value);
|
||||
else if(value < 0x10000)
|
||||
std::snprintf(vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 5, hexUppercase() ? "%04X" : "%04x", value);
|
||||
else
|
||||
std::snprintf(vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
|
||||
std::ignore = std::snprintf(
|
||||
vToS_buf, 9, hexUppercase() ? "%08X" : "%08x", value);
|
||||
break;
|
||||
}
|
||||
|
||||
return string(vToS_buf);
|
||||
return {vToS_buf};
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Base::Fmt Base::myDefaultBase = Base::Fmt::_16;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
std::ios_base::fmtflags Base::myHexflags = std::ios_base::hex;
|
||||
std::ios_base::fmtflags Base::myHexflags = std::ios_base::hex; // NOLINT
|
||||
|
||||
} // Namespace Common
|
||||
} // namespace Common
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -38,7 +38,7 @@ class Base
|
|||
// The base to use for conversion from integers to strings
|
||||
// Note that the actual number of places will be determined by
|
||||
// the magnitude of the value itself in the general case
|
||||
enum class Fmt {
|
||||
enum class Fmt: uInt8 {
|
||||
_16, // base 16: 2, 4, 8 bytes (depending on value)
|
||||
_16_1, // base 16: 1 byte wide
|
||||
_16_2, // base 16: 2 bytes wide
|
||||
|
@ -56,7 +56,7 @@ class Base
|
|||
_2, // base 2: 8 or 16 bits (depending on value)
|
||||
_2_8, // base 2: 1 byte (8 bits) wide
|
||||
_2_16, // base 2: 2 bytes (16 bits) wide
|
||||
_DEFAULT
|
||||
DEFAULT
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -72,31 +72,31 @@ class Base
|
|||
static bool hexUppercase() { return myHexflags & std::ios_base::uppercase; }
|
||||
|
||||
/** Output HEX digits in 0.5/1/2/4 byte format */
|
||||
static inline std::ostream& HEX1(std::ostream& os) {
|
||||
static std::ostream& HEX1(std::ostream& os) {
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(1);
|
||||
}
|
||||
static inline std::ostream& HEX2(std::ostream& os) {
|
||||
static std::ostream& HEX2(std::ostream& os) {
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(2) << std::setfill('0');
|
||||
}
|
||||
static inline std::ostream& HEX3(std::ostream& os)
|
||||
static std::ostream& HEX3(std::ostream& os)
|
||||
{
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(3) << std::setfill('0');
|
||||
}
|
||||
static inline std::ostream& HEX4(std::ostream& os) {
|
||||
static std::ostream& HEX4(std::ostream& os) {
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(4) << std::setfill('0');
|
||||
}
|
||||
static inline std::ostream& HEX8(std::ostream& os) {
|
||||
static std::ostream& HEX8(std::ostream& os) {
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(8) << std::setfill('0');
|
||||
}
|
||||
|
||||
/** Convert integer to a string in the given base format */
|
||||
static string toString(int value,
|
||||
Common::Base::Fmt outputBase = Common::Base::Fmt::_DEFAULT);
|
||||
Common::Base::Fmt outputBase = Common::Base::Fmt::DEFAULT);
|
||||
|
||||
private:
|
||||
// Default format to use when none is specified
|
||||
|
@ -108,6 +108,7 @@ class Base
|
|||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Base() = delete;
|
||||
~Base() = delete;
|
||||
Base(const Base&) = delete;
|
||||
Base(Base&&) = delete;
|
||||
Base& operator=(const Base&) = delete;
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "PNGLibrary.hxx"
|
||||
#include "PropsSet.hxx"
|
||||
|
||||
#include "Bezel.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Bezel::Bezel(OSystem& osystem)
|
||||
: myOSystem{osystem},
|
||||
myFB{osystem.frameBuffer()}
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string Bezel::getName(const string& path, const Properties& props)
|
||||
{
|
||||
string imageName;
|
||||
int index = 1; // skip property name
|
||||
|
||||
do
|
||||
{
|
||||
imageName = getName(props, index);
|
||||
if(imageName != EmptyString)
|
||||
{
|
||||
// Note: JPG does not support transparency
|
||||
const string imagePath = path + imageName + ".png";
|
||||
const FSNode node(imagePath);
|
||||
if(node.exists())
|
||||
break;
|
||||
}
|
||||
} while(index != -1);
|
||||
|
||||
return imageName;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string Bezel::getName(const Properties& props, int& index)
|
||||
{
|
||||
if(++index == 1)
|
||||
return props.get(PropType::Bezel_Name);
|
||||
|
||||
// Try to generate bezel name from cart name
|
||||
const string& cartName = props.get(PropType::Cart_Name);
|
||||
size_t pos = cartName.find_first_of('(');
|
||||
if(pos == std::string::npos)
|
||||
pos = cartName.length() + 1;
|
||||
if(index < 10 && pos != std::string::npos && pos > 0)
|
||||
{
|
||||
// The following suffixes are from "The Official No-Intro Convention",
|
||||
// covering all used combinations by "The Bezel Project" (except single ones)
|
||||
// (Unl) = unlicensed (Homebrews)
|
||||
const std::array<string, 8> suffixes = {
|
||||
" (USA)", " (USA) (Proto)", " (USA) (Unl)", " (USA) (Hack)",
|
||||
" (Europe)", " (Germany)", " (France) (Unl)", " (Australia)"
|
||||
};
|
||||
return cartName.substr(0, pos - 1) + suffixes[index - 2];
|
||||
}
|
||||
|
||||
if(index == 10)
|
||||
{
|
||||
return "Atari-2600";
|
||||
}
|
||||
|
||||
if(index == 11)
|
||||
{
|
||||
index = -1;
|
||||
return "default";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string Bezel::getName(int& index) const
|
||||
{
|
||||
return getName(myOSystem.console().properties(), index);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Bezel::borderSize(uInt32 x, uInt32 y, uInt32 size, Int32 step) const
|
||||
{
|
||||
uInt32 *pixels{nullptr}, pitch{0};
|
||||
|
||||
mySurface->basePtr(pixels, pitch);
|
||||
pixels += x + y * pitch;
|
||||
|
||||
for(uInt32 i = 0; i < size; ++i, pixels += step)
|
||||
{
|
||||
uInt8 r{0}, g{0}, b{0}, a{0};
|
||||
|
||||
myFB.getRGBA(*pixels, &r, &g, &b, &a);
|
||||
if(a < 255) // transparent pixel?
|
||||
return i;
|
||||
}
|
||||
return size - 1;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Bezel::load()
|
||||
{
|
||||
const Settings& settings = myOSystem.settings();
|
||||
bool isValid = false;
|
||||
string imageName;
|
||||
|
||||
#ifdef IMAGE_SUPPORT
|
||||
const bool show = myOSystem.eventHandler().inTIAMode() &&
|
||||
settings.getBool("bezel.show") &&
|
||||
(settings.getBool("fullscreen") ||
|
||||
settings.getBool("bezel.windowed"));
|
||||
|
||||
if(show)
|
||||
{
|
||||
if(!mySurface)
|
||||
mySurface = myFB.allocateSurface(1, 1); // dummy size
|
||||
try
|
||||
{
|
||||
const string& path = myOSystem.bezelDir().getPath();
|
||||
VariantList metaData;
|
||||
int index = 0;
|
||||
|
||||
do
|
||||
{
|
||||
imageName = getName(index);
|
||||
if(imageName != EmptyString)
|
||||
{
|
||||
// Note: JPG does not support transparency
|
||||
const string imagePath = path + imageName + ".png";
|
||||
const FSNode node(imagePath);
|
||||
if(node.exists())
|
||||
{
|
||||
isValid = true;
|
||||
myOSystem.png().loadImage(imagePath, *mySurface, metaData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(index != -1);
|
||||
}
|
||||
catch(const runtime_error&) { cerr << "ERROR: Bezel load\n"; }
|
||||
}
|
||||
#else
|
||||
const bool show = false;
|
||||
#endif
|
||||
if(isValid)
|
||||
{
|
||||
const Int32 w = mySurface->width();
|
||||
const Int32 h = mySurface->height();
|
||||
uInt32 top{0}, bottom{0}, left{0}, right{0};
|
||||
|
||||
if(settings.getBool("bezel.win.auto"))
|
||||
{
|
||||
// Determine transparent window inside bezel image
|
||||
const uInt32 xCenter = w >> 1;
|
||||
top = borderSize(xCenter, 0, h, w);
|
||||
bottom = h - 1 - borderSize(xCenter, h - 1, h, -w);
|
||||
const uInt32 yCenter = (bottom + top) >> 1;
|
||||
left = borderSize(0, yCenter, w, 1);
|
||||
right = w - 1 - borderSize(w - 1, yCenter, w, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// BP: 13, 13, 0, 0%
|
||||
// HY: 12, 12, 0, 0%
|
||||
// P1: 25, 25, 11, 22%
|
||||
// P2: 23, 23, 7, 20%
|
||||
left = std::min(w - 1, static_cast<Int32>(w * settings.getInt("bezel.win.left") / 100. + .5)); // NOLINT
|
||||
right = w - 1 - std::min(w - 1, static_cast<Int32>(w * settings.getInt("bezel.win.right") / 100. + .5)); // NOLINT
|
||||
top = std::min(h - 1, static_cast<Int32>(h * settings.getInt("bezel.win.top") / 100. + .5)); // NOLINT
|
||||
bottom = h - 1 - std::min(h - 1, static_cast<Int32>(h * settings.getInt("bezel.win.bottom") / 100. + .5)); // NOLINT
|
||||
}
|
||||
|
||||
//cerr << (int)(right - left + 1) << " x " << (int)(bottom - top + 1) << " = "
|
||||
// << double((int)(right - left + 1)) / double((int)(bottom - top + 1));
|
||||
|
||||
// Disable bezel is no transparent window was found
|
||||
if(left < right && top < bottom)
|
||||
myInfo = Info(Common::Size(w, h), Common::Rect(left, top, right, bottom));
|
||||
else
|
||||
{
|
||||
if(mySurface)
|
||||
myFB.deallocateSurface(mySurface);
|
||||
mySurface = nullptr;
|
||||
myInfo = Info();
|
||||
myFB.showTextMessage("Invalid bezel image ('" + imageName + "')!");
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myInfo = Info();
|
||||
if(show)
|
||||
myFB.showTextMessage("No bezel image found");
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Bezel::apply()
|
||||
{
|
||||
if(isShown())
|
||||
{
|
||||
const uInt32 bezelW =
|
||||
std::min(myFB.screenSize().w,
|
||||
static_cast<uInt32>(std::round(myFB.imageRect().w() * myInfo.ratioW())));
|
||||
const uInt32 bezelH =
|
||||
std::min(myFB.screenSize().h,
|
||||
static_cast<uInt32>(std::round(myFB.imageRect().h() * myInfo.ratioH())));
|
||||
|
||||
// Position and scale bezel
|
||||
mySurface->setDstSize(bezelW, bezelH);
|
||||
mySurface->setDstPos((myFB.screenSize().w - bezelW) / 2, // center
|
||||
(myFB.screenSize().h - bezelH) / 2);
|
||||
mySurface->setScalingInterpolation(ScalingInterpolation::sharp);
|
||||
// Note: Variable bezel window positions are handled in VideoModeHandler::Mode
|
||||
|
||||
// Enable blending to allow overlaying the bezel over the TIA output
|
||||
mySurface->attributes().blending = true;
|
||||
mySurface->attributes().blendalpha = 100;
|
||||
mySurface->applyAttributes();
|
||||
mySurface->setVisible(true);
|
||||
}
|
||||
else
|
||||
if(mySurface)
|
||||
mySurface->setVisible(false);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Bezel::render()
|
||||
{
|
||||
if(mySurface)
|
||||
mySurface->render();
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef BEZEL_HXX
|
||||
#define BEZEL_HXX
|
||||
|
||||
class OSystem;
|
||||
class FBSurface;
|
||||
class FrameBuffer;
|
||||
class Properties;
|
||||
|
||||
#include "Rect.hxx"
|
||||
|
||||
/**
|
||||
This class handles the bezels.
|
||||
|
||||
Bezels are loaded using a file name which is either a bezel name property or
|
||||
is autogenerated from the cart name property. The bezels can be any size and
|
||||
their transparent emulation window can be at any position. The position of
|
||||
the window can be determined automatically.
|
||||
|
||||
+--------------------------------------+
|
||||
| | display.h
|
||||
+--------------------------------------+
|
||||
| |
|
||||
| +---------------+ |
|
||||
| | window | |
|
||||
| | | |
|
||||
| | tia.h * zoom | |
|
||||
| | | | bezel.h * zoom
|
||||
| | | |
|
||||
| +---------------+ |
|
||||
| |
|
||||
+--------------------------------------+ size
|
||||
| |
|
||||
+--------------------------------------+
|
||||
|
||||
The bezel and window sizes and their ratios are used for correct scaling.
|
||||
|
||||
@author Thomas Jentzsch
|
||||
*/
|
||||
|
||||
class Bezel
|
||||
{
|
||||
public:
|
||||
explicit Bezel(OSystem& osystem);
|
||||
~Bezel() = default;
|
||||
|
||||
struct Info
|
||||
{
|
||||
private:
|
||||
bool _isShown{false}; // Is bezel shown?
|
||||
Common::Size _size{1, 1}; // Bezel size
|
||||
Common::Rect _window{1, 1}; // Area of transparent TIA window inside bezel
|
||||
|
||||
public:
|
||||
explicit Info() = default;
|
||||
explicit Info(Common::Size size, Common::Rect window)
|
||||
: _isShown{true}, _size{size}, _window{window} { }
|
||||
|
||||
bool isShown() const { return _isShown; }
|
||||
Common::Size size() const { return _size; }
|
||||
Common::Rect window() const { return _window; }
|
||||
|
||||
// Ratios between bezel sizes and TIA window sizes
|
||||
double ratioW() const { return static_cast<double>(size().w) / window().w(); }
|
||||
double ratioH() const { return static_cast<double>(size().h) / window().h(); }
|
||||
};
|
||||
|
||||
// Structure access methods
|
||||
const Info& info() const { return myInfo; }
|
||||
bool isShown() const { return myInfo.isShown(); }
|
||||
Common::Size size() const { return myInfo.size(); }
|
||||
Common::Rect window() const { return myInfo.window(); }
|
||||
// Ratio between bezel size and TIA window size
|
||||
double ratioW() const { return myInfo.ratioW(); }
|
||||
double ratioH() const { return myInfo.ratioH(); }
|
||||
|
||||
/*
|
||||
Calculate size of a bezel border.
|
||||
*/
|
||||
uInt32 borderSize(uInt32 x, uInt32 y, uInt32 size, Int32 step) const;
|
||||
|
||||
/*
|
||||
Load the bezel.
|
||||
*/
|
||||
bool load();
|
||||
|
||||
/*
|
||||
Display scaled bezel.
|
||||
*/
|
||||
void apply();
|
||||
|
||||
/*
|
||||
Render bezel surface
|
||||
*/
|
||||
void render();
|
||||
|
||||
/*
|
||||
Generate bezel file name.
|
||||
*/
|
||||
static string getName(const string& path, const Properties& props);
|
||||
|
||||
private:
|
||||
/*
|
||||
Generate bezel file name.
|
||||
*/
|
||||
static string getName(const Properties& props, int& index);
|
||||
|
||||
/*
|
||||
Generate bezel file name.
|
||||
*/
|
||||
string getName(int& index) const;
|
||||
|
||||
private:
|
||||
// The parent system for the bezel
|
||||
OSystem& myOSystem;
|
||||
|
||||
// Pointer to the FrameBuffer object
|
||||
FrameBuffer& myFB;
|
||||
|
||||
// The bezel surface which blends over the TIA surface
|
||||
shared_ptr<FBSurface> mySurface;
|
||||
|
||||
// Bezel info structure
|
||||
Info myInfo;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Bezel() = delete;
|
||||
Bezel(const Bezel&) = delete;
|
||||
Bezel(Bezel&&) = delete;
|
||||
Bezel& operator=(const Bezel&) = delete;
|
||||
Bezel& operator=(Bezel&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -23,6 +23,8 @@
|
|||
#include "Settings.hxx"
|
||||
#include "StateManager.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "Cart.hxx"
|
||||
#include "CartELF.hxx"
|
||||
|
||||
#include "DevSettingsHandler.hxx"
|
||||
|
||||
|
@ -41,12 +43,17 @@ void DevSettingsHandler::loadSettings(SettingsSet set)
|
|||
|
||||
myFrameStats[set] = settings.getBool(prefix + "stats");
|
||||
myDetectedInfo[set] = settings.getBool(prefix + "detectedinfo");
|
||||
// AtariVox/SaveKey/PlusROM access
|
||||
myExternAccess[set] = settings.getBool(prefix + "extaccess");
|
||||
myConsole[set] = settings.getString(prefix + "console") == "7800" ? 1 : 0;
|
||||
myPlusROM[set] = devSettings ? settings.getBool("dev.plusroms.on") : true;
|
||||
// Randomization
|
||||
myRandomBank[set] = settings.getBool(prefix + "bankrandom");
|
||||
myRandomizeTIA[set] = settings.getBool(prefix + "tiarandom");
|
||||
myRandomizeRAM[set] = settings.getBool(prefix + "ramrandom");
|
||||
myRandomizeCPU[set] = settings.getString(prefix + "cpurandom");
|
||||
// Random hotspot peeks
|
||||
myRandomHotspots[set] = devSettings ? settings.getBool("dev.hsrandom") : false;
|
||||
// Undriven TIA pins
|
||||
myUndrivenPins[set] = devSettings ? settings.getBool("dev.tiadriven") : false;
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
|
@ -57,14 +64,16 @@ void DevSettingsHandler::loadSettings(SettingsSet set)
|
|||
#endif
|
||||
// Thumb ARM emulation exception
|
||||
myThumbException[set] = devSettings ? settings.getBool("dev.thumb.trapfatal") : false;
|
||||
// AtariVox/SaveKey/PlusROM access
|
||||
myExternAccess[set] = settings.getBool(prefix + "extaccess");
|
||||
myArmSpeed[set] = devSettings ? settings.getInt("dev.arm.mips") : CartridgeELF::MIPS_MAX;
|
||||
|
||||
// TIA tab
|
||||
myTIAType[set] = devSettings ? settings.getString("dev.tia.type") : "standard";
|
||||
myPlInvPhase[set] = devSettings ? settings.getBool("dev.tia.plinvphase") : false;
|
||||
myMsInvPhase[set] = devSettings ? settings.getBool("dev.tia.msinvphase") : false;
|
||||
myBlInvPhase[set] = devSettings ? settings.getBool("dev.tia.blinvphase") : false;
|
||||
myPlLateHMove[set] = devSettings ? settings.getBool("dev.tia.pllatehmove") : false;
|
||||
myMsLateHMove[set] = devSettings ? settings.getBool("dev.tia.mslatehmove") : false;
|
||||
myBlLateHMove[set] = devSettings ? settings.getBool("dev.tia.bllatehmove") : false;
|
||||
myPFBits[set] = devSettings ? settings.getBool("dev.tia.delaypfbits") : false;
|
||||
myPFColor[set] = devSettings ? settings.getBool("dev.tia.delaypfcolor") : false;
|
||||
myPFScore[set] = devSettings ? settings.getBool("dev.tia.pfscoreglitch") : false;
|
||||
|
@ -110,6 +119,8 @@ void DevSettingsHandler::saveSettings(SettingsSet set)
|
|||
|
||||
if(devSettings)
|
||||
{
|
||||
settings.setValue("dev.plusroms.on", myPlusROM[set]);
|
||||
settings.setValue("dev.hsrandom", myRandomHotspots[set]);
|
||||
// Undriven TIA pins
|
||||
settings.setValue("dev.tiadriven", myUndrivenPins[set]);
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
|
@ -120,6 +131,7 @@ void DevSettingsHandler::saveSettings(SettingsSet set)
|
|||
#endif
|
||||
// Thumb ARM emulation exception
|
||||
settings.setValue("dev.thumb.trapfatal", myThumbException[set]);
|
||||
settings.setValue("dev.arm.mips", myArmSpeed[set]);
|
||||
}
|
||||
|
||||
// AtariVox/SaveKey/PlusROM access
|
||||
|
@ -134,6 +146,9 @@ void DevSettingsHandler::saveSettings(SettingsSet set)
|
|||
settings.setValue("dev.tia.plinvphase", myPlInvPhase[set]);
|
||||
settings.setValue("dev.tia.msinvphase", myMsInvPhase[set]);
|
||||
settings.setValue("dev.tia.blinvphase", myBlInvPhase[set]);
|
||||
settings.setValue("dev.tia.pllatehmove", myPlLateHMove[set]);
|
||||
settings.setValue("dev.tia.mslatehmove", myMsLateHMove[set]);
|
||||
settings.setValue("dev.tia.bllatehmove", myBlLateHMove[set]);
|
||||
settings.setValue("dev.tia.delaypfbits", myPFBits[set]);
|
||||
settings.setValue("dev.tia.delaypfcolor", myPFColor[set]);
|
||||
settings.setValue("dev.tia.pfscoreglitch", myPFScore[set]);
|
||||
|
@ -168,7 +183,9 @@ void DevSettingsHandler::applySettings(SettingsSet set)
|
|||
|
||||
if(myOSystem.hasConsole())
|
||||
{
|
||||
myOSystem.console().cartridge().enableRandomHotspots(myRandomHotspots[set]);
|
||||
myOSystem.console().tia().driveUnusedPinsRandom(myUndrivenPins[set]);
|
||||
myOSystem.console().cartridge().enablePlusROM(myPlusROM[set]);
|
||||
// Notes:
|
||||
// - thumb exceptions not updated, because set in cart constructor
|
||||
// - other missing settings are used on-the-fly
|
||||
|
@ -189,6 +206,9 @@ void DevSettingsHandler::applySettings(SettingsSet set)
|
|||
myOSystem.console().tia().setPlInvertedPhaseClock(myPlInvPhase[set]);
|
||||
myOSystem.console().tia().setMsInvertedPhaseClock(myMsInvPhase[set]);
|
||||
myOSystem.console().tia().setBlInvertedPhaseClock(myBlInvPhase[set]);
|
||||
myOSystem.console().tia().setPlShortLateHMove(myPlLateHMove[set]);
|
||||
myOSystem.console().tia().setMsShortLateHMove(myMsLateHMove[set]);
|
||||
myOSystem.console().tia().setBlShortLateHMove(myBlLateHMove[set]);
|
||||
myOSystem.console().tia().setPFBitsDelay(myPFBits[set]);
|
||||
myOSystem.console().tia().setPFColorDelay(myPFColor[set]);
|
||||
myOSystem.console().tia().setPFScoreGlitch(myPFScore[set]);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -21,6 +21,7 @@
|
|||
class OSystem;
|
||||
|
||||
#include <array>
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class takes care of developer settings sets.
|
||||
|
@ -30,13 +31,14 @@ class OSystem;
|
|||
class DevSettingsHandler
|
||||
{
|
||||
public:
|
||||
enum SettingsSet {
|
||||
enum SettingsSet: uInt8 {
|
||||
player,
|
||||
developer,
|
||||
numSets
|
||||
};
|
||||
|
||||
explicit DevSettingsHandler(OSystem& osystem);
|
||||
~DevSettingsHandler() = default;
|
||||
|
||||
void loadSettings(SettingsSet set);
|
||||
void saveSettings(SettingsSet set);
|
||||
|
@ -45,42 +47,48 @@ class DevSettingsHandler
|
|||
protected:
|
||||
OSystem& myOSystem;
|
||||
// Emulator sets
|
||||
std::array<bool, numSets> myFrameStats;
|
||||
std::array<bool, numSets> myDetectedInfo;
|
||||
std::array<bool, numSets> myExternAccess;
|
||||
std::array<int, numSets> myConsole;
|
||||
std::array<bool, numSets> myRandomBank;
|
||||
std::array<bool, numSets> myRandomizeTIA;
|
||||
std::array<bool, numSets> myRandomizeRAM;
|
||||
std::array<string, numSets> myRandomizeCPU;
|
||||
std::array<bool, numSets> myColorLoss;
|
||||
std::array<bool, numSets> myTVJitter;
|
||||
std::array<int, numSets> myTVJitterSense;
|
||||
std::array<int, numSets> myTVJitterRec;
|
||||
std::array<bool, numSets> myDebugColors;
|
||||
std::array<bool, numSets> myUndrivenPins;
|
||||
std::array<bool, numSets> myFrameStats{};
|
||||
std::array<bool, numSets> myDetectedInfo{};
|
||||
std::array<bool, numSets> myExternAccess{};
|
||||
std::array<int, numSets> myConsole{};
|
||||
std::array<int, numSets> myPlusROM{};
|
||||
std::array<bool, numSets> myRandomBank{};
|
||||
std::array<bool, numSets> myRandomizeTIA{};
|
||||
std::array<bool, numSets> myRandomizeRAM{};
|
||||
std::array<string, numSets> myRandomizeCPU{};
|
||||
std::array<bool, numSets> myColorLoss{};
|
||||
std::array<bool, numSets> myTVJitter{};
|
||||
std::array<int, numSets> myTVJitterSense{};
|
||||
std::array<int, numSets> myTVJitterRec{};
|
||||
std::array<bool, numSets> myDebugColors{};
|
||||
std::array<bool, numSets> myRandomHotspots{};
|
||||
std::array<bool, numSets> myUndrivenPins{};
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
std::array<bool, numSets> myRWPortBreak;
|
||||
std::array<bool, numSets> myWRPortBreak;
|
||||
std::array<bool, numSets> myRWPortBreak{};
|
||||
std::array<bool, numSets> myWRPortBreak{};
|
||||
#endif
|
||||
std::array<bool, numSets> myThumbException;
|
||||
std::array<bool, numSets> myThumbException{};
|
||||
std::array<int, numSets> myArmSpeed{};
|
||||
// TIA sets
|
||||
std::array<string, numSets> myTIAType;
|
||||
std::array<bool, numSets> myPlInvPhase;
|
||||
std::array<bool, numSets> myMsInvPhase;
|
||||
std::array<bool, numSets> myBlInvPhase;
|
||||
std::array<bool, numSets> myPFBits;
|
||||
std::array<bool, numSets> myPFColor;
|
||||
std::array<bool, numSets> myPFScore;
|
||||
std::array<bool, numSets> myBKColor;
|
||||
std::array<bool, numSets> myPlSwap;
|
||||
std::array<bool, numSets> myBlSwap;
|
||||
std::array<string, numSets> myTIAType{};
|
||||
std::array<bool, numSets> myPlInvPhase{};
|
||||
std::array<bool, numSets> myMsInvPhase{};
|
||||
std::array<bool, numSets> myBlInvPhase{};
|
||||
std::array<bool, numSets> myPlLateHMove{};
|
||||
std::array<bool, numSets> myMsLateHMove{};
|
||||
std::array<bool, numSets> myBlLateHMove{};
|
||||
std::array<bool, numSets> myPFBits{};
|
||||
std::array<bool, numSets> myPFColor{};
|
||||
std::array<bool, numSets> myPFScore{};
|
||||
std::array<bool, numSets> myBKColor{};
|
||||
std::array<bool, numSets> myPlSwap{};
|
||||
std::array<bool, numSets> myBlSwap{};
|
||||
// States sets
|
||||
std::array<bool, numSets> myTimeMachine;
|
||||
std::array<int, numSets> myStateSize;
|
||||
std::array<int, numSets> myUncompressed;
|
||||
std::array<string, numSets> myStateInterval;
|
||||
std::array<string, numSets> myStateHorizon;
|
||||
std::array<bool, numSets> myTimeMachine{};
|
||||
std::array<int, numSets> myStateSize{};
|
||||
std::array<int, numSets> myUncompressed{};
|
||||
std::array<string, numSets> myStateInterval{};
|
||||
std::array<string, numSets> myStateHorizon{};
|
||||
|
||||
private:
|
||||
void handleEnableDebugColors(bool enable);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -30,9 +30,10 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
|
|||
#ifdef GUI_SUPPORT
|
||||
{
|
||||
ostringstream buf;
|
||||
myQwertz = int{'y'} == static_cast<int>(SDL_GetKeyFromScancode(SDL_Scancode(KBDK_Z)));
|
||||
myQwertz = int{'y'} == static_cast<int>
|
||||
(SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(KBDK_Z)));
|
||||
buf << "Keyboard: " << (myQwertz ? "QWERTZ" : "QWERTY");
|
||||
Logger::debug(buf.str());
|
||||
Logger::debug(buf.view());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -40,8 +41,9 @@ EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
|
|||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << "ERROR: Couldn't initialize SDL joystick support: " << SDL_GetError() << endl;
|
||||
Logger::error(buf.str());
|
||||
buf << "ERROR: Couldn't initialize SDL joystick support: "
|
||||
<< SDL_GetError() << '\n';
|
||||
Logger::error(buf.view());
|
||||
}
|
||||
Logger::debug("EventHandlerSDL2::EventHandlerSDL2 SDL_INIT_JOYSTICK");
|
||||
#endif
|
||||
|
@ -123,25 +125,29 @@ void EventHandlerSDL2::pollEvent()
|
|||
case SDL_MOUSEBUTTONUP:
|
||||
{
|
||||
// ToDo: check support of more buttons and double-click
|
||||
MouseButton b{MouseButton::NONE};
|
||||
switch(myEvent.button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
handleMouseButtonEvent(MouseButton::LEFT, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
|
||||
myEvent.button.x, myEvent.button.y);
|
||||
b = MouseButton::LEFT;
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
handleMouseButtonEvent(MouseButton::RIGHT, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
|
||||
myEvent.button.x, myEvent.button.y);
|
||||
b = MouseButton::RIGHT;
|
||||
break;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
b = MouseButton::MIDDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
handleMouseButtonEvent(b, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
|
||||
myEvent.button.x, myEvent.button.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
int x, y;
|
||||
int x{0}, y{0};
|
||||
SDL_GetMouseState(&x, &y); // we need mouse position too
|
||||
if(myEvent.wheel.y < 0)
|
||||
handleMouseButtonEvent(MouseButton::WHEELDOWN, true, x, y);
|
||||
|
@ -259,6 +265,7 @@ EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
|
|||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
// NOLINTNEXTLINE: we want to initialize here, not in the member list
|
||||
myStick = SDL_JoystickOpen(idx);
|
||||
if(myStick)
|
||||
{
|
||||
|
@ -267,7 +274,7 @@ EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
|
|||
// it also appends " #x", where x seems to vary. Obviously this wreaks
|
||||
// havoc with the idea that a joystick will always have the same name.
|
||||
// So we truncate the number.
|
||||
const char* sdlname = SDL_JoystickName(myStick);
|
||||
const char* const sdlname = SDL_JoystickName(myStick);
|
||||
const string& desc = BSPF::startsWithIgnoreCase(sdlname, "XInput Controller")
|
||||
? "XInput Controller" : sdlname;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include <cmath>
|
||||
|
||||
#include "SDL_lib.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "Logger.hxx"
|
||||
|
||||
|
@ -84,7 +83,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
myNumDisplays = SDL_GetNumVideoDisplays();
|
||||
|
||||
// First get the maximum fullscreen desktop resolution
|
||||
SDL_DisplayMode display;
|
||||
SDL_DisplayMode display{};
|
||||
for(int i = 0; i < myNumDisplays; ++i)
|
||||
{
|
||||
SDL_GetDesktopDisplayMode(i, &display);
|
||||
|
@ -97,8 +96,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
s << "Supported video modes (" << numModes << ") for display " << i
|
||||
<< " (" << SDL_GetDisplayName(i) << "):";
|
||||
|
||||
string lastRes = "";
|
||||
|
||||
string lastRes;
|
||||
for(int m = 0; m < numModes; ++m)
|
||||
{
|
||||
SDL_DisplayMode mode;
|
||||
|
@ -107,11 +105,11 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
SDL_GetDisplayMode(i, m, &mode);
|
||||
res << std::setw(4) << mode.w << "x" << std::setw(4) << mode.h;
|
||||
|
||||
if(lastRes != res.str())
|
||||
if(lastRes != res.view())
|
||||
{
|
||||
Logger::debug(s.str());
|
||||
Logger::debug(s.view());
|
||||
s.str("");
|
||||
lastRes = res.str();
|
||||
lastRes = res.view();
|
||||
s << " " << lastRes << ": ";
|
||||
}
|
||||
s << mode.refresh_rate << "Hz";
|
||||
|
@ -120,7 +118,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
else
|
||||
s << " ";
|
||||
}
|
||||
Logger::debug(s.str());
|
||||
Logger::debug(s.view());
|
||||
}
|
||||
|
||||
// Now get the maximum windowed desktop resolution
|
||||
|
@ -135,7 +133,7 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
SDL_DestroyWindow(tmpWindow);
|
||||
}
|
||||
|
||||
SDL_Rect r;
|
||||
SDL_Rect r{};
|
||||
for(int i = 0; i < myNumDisplays; ++i)
|
||||
{
|
||||
// Display bounds minus dock
|
||||
|
@ -157,13 +155,15 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
string stellaName;
|
||||
};
|
||||
// Create name map for all currently known SDL renderers
|
||||
static const std::array<RenderName, 6> RENDERER_NAMES = {{
|
||||
{ "direct3d", "Direct3D" },
|
||||
{ "metal", "Metal" },
|
||||
{ "opengl", "OpenGL" },
|
||||
{ "opengles", "OpenGLES" },
|
||||
{ "opengles2", "OpenGLES2" },
|
||||
{ "software", "Software" }
|
||||
static const std::array<RenderName, 8> RENDERER_NAMES = {{
|
||||
{ "direct3d", "Direct3D" },
|
||||
{ "direct3d11", "Direct3D 11" },
|
||||
{ "direct3d12", "Direct3D 12" },
|
||||
{ "metal", "Metal" },
|
||||
{ "opengl", "OpenGL" },
|
||||
{ "opengles", "OpenGL ES" },
|
||||
{ "opengles2", "OpenGL ES 2" },
|
||||
{ "software", "Software" }
|
||||
}};
|
||||
|
||||
const int numDrivers = SDL_GetNumRenderDrivers();
|
||||
|
@ -174,11 +174,11 @@ void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
{
|
||||
// Map SDL names into nicer Stella names (if available)
|
||||
bool found = false;
|
||||
for(size_t j = 0; j < RENDERER_NAMES.size(); ++j)
|
||||
for(const auto& render: RENDERER_NAMES)
|
||||
{
|
||||
if(RENDERER_NAMES[j].sdlName == info.name)
|
||||
if(render.sdlName == info.name)
|
||||
{
|
||||
VarList::push_back(renderers, RENDERER_NAMES[j].stellaName, info.name);
|
||||
VarList::push_back(renderers, render.stellaName, info.name);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
|
|||
}
|
||||
|
||||
#ifdef ADAPTABLE_REFRESH_SUPPORT
|
||||
SDL_DisplayMode adaptedSdlMode;
|
||||
SDL_DisplayMode adaptedSdlMode{};
|
||||
const int gameRefreshRate =
|
||||
myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
|
||||
const bool shouldAdapt = fullScreen
|
||||
|
@ -284,11 +284,12 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
|
|||
if(myWindow)
|
||||
{
|
||||
const int d = SDL_GetWindowDisplayIndex(myWindow);
|
||||
int w, h;
|
||||
int w{0}, h{0};
|
||||
|
||||
SDL_GetWindowSize(myWindow, &w, &h);
|
||||
if(d != displayIndex || static_cast<uInt32>(w) != mode.screenS.w ||
|
||||
static_cast<uInt32>(h) != mode.screenS.h || adaptRefresh)
|
||||
if(d != displayIndex ||
|
||||
std::cmp_not_equal(w, mode.screenS.w) ||
|
||||
std::cmp_not_equal(h, mode.screenS.h) || adaptRefresh)
|
||||
{
|
||||
// Renderer has to be destroyed *before* the window gets destroyed to avoid memory leaks
|
||||
SDL_DestroyRenderer(myRenderer);
|
||||
|
@ -310,7 +311,7 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
|
|||
mode.screenS.w, mode.screenS.h, flags);
|
||||
if(myWindow == nullptr)
|
||||
{
|
||||
string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError());
|
||||
const string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError());
|
||||
Logger::error(msg);
|
||||
return false;
|
||||
}
|
||||
|
@ -331,8 +332,12 @@ bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
|
|||
ostringstream msg;
|
||||
|
||||
msg << "Display refresh rate changed to "
|
||||
<< adaptedSdlMode.refresh_rate << " Hz";
|
||||
Logger::info(msg.str());
|
||||
<< adaptedSdlMode.refresh_rate << " Hz " << "(" << adaptedSdlMode.w << "x" << adaptedSdlMode.h << ")";
|
||||
Logger::info(msg.view());
|
||||
|
||||
SDL_DisplayMode setSdlMode;
|
||||
SDL_GetWindowDisplayMode(myWindow, &setSdlMode);
|
||||
cerr << setSdlMode.refresh_rate << "Hz\n";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -358,8 +363,8 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
|
|||
const int wantedRefreshRate =
|
||||
myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
|
||||
// Take care of rounded refresh rates (e.g. 59.94 Hz)
|
||||
float factor = std::min(float(currentRefreshRate) / wantedRefreshRate,
|
||||
float(currentRefreshRate) / (wantedRefreshRate - 1));
|
||||
float factor = std::min(
|
||||
static_cast<float>(currentRefreshRate) / wantedRefreshRate, static_cast<float>(currentRefreshRate) / (wantedRefreshRate - 1));
|
||||
// Calculate difference taking care of integer factors (e.g. 100/120)
|
||||
float bestDiff = std::abs(factor - std::round(factor)) / factor;
|
||||
bool adapt = false;
|
||||
|
@ -370,7 +375,7 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
|
|||
// Check for integer factors 1 (60/50 Hz) and 2 (120/100 Hz)
|
||||
for(int m = 1; m <= 2; ++m)
|
||||
{
|
||||
SDL_DisplayMode closestSdlMode;
|
||||
SDL_DisplayMode closestSdlMode{};
|
||||
|
||||
sdlMode.refresh_rate = wantedRefreshRate * m;
|
||||
if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == nullptr)
|
||||
|
@ -378,8 +383,9 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
|
|||
Logger::error("ERROR: Closest display mode could not be retrieved");
|
||||
return adapt;
|
||||
}
|
||||
factor = std::min(float(sdlMode.refresh_rate) / sdlMode.refresh_rate,
|
||||
float(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
|
||||
factor = std::min(
|
||||
static_cast<float>(sdlMode.refresh_rate) / sdlMode.refresh_rate,
|
||||
static_cast<float>(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
|
||||
const float diff = std::abs(factor - std::round(factor)) / factor;
|
||||
if(diff < bestDiff)
|
||||
{
|
||||
|
@ -393,7 +399,7 @@ bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
|
|||
// cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)";
|
||||
//else
|
||||
// cerr << "not required/possible";
|
||||
//cerr << endl;
|
||||
//cerr << '\n';
|
||||
|
||||
// Only change if the display supports a better refresh rate
|
||||
return adapt;
|
||||
|
@ -411,7 +417,7 @@ bool FBBackendSDL2::createRenderer()
|
|||
bool recreate = myRenderer == nullptr;
|
||||
uInt32 renderFlags = SDL_RENDERER_ACCELERATED;
|
||||
const string& video = myOSystem.settings().getString("video"); // Render hint
|
||||
SDL_RendererInfo renderInfo;
|
||||
SDL_RendererInfo renderInfo{};
|
||||
|
||||
if(myOSystem.settings().getBool("vsync")
|
||||
&& !myOSystem.settings().getBool("turbo")) // V'synced blits option
|
||||
|
@ -424,11 +430,11 @@ bool FBBackendSDL2::createRenderer()
|
|||
|
||||
if(recreate)
|
||||
{
|
||||
//cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl;
|
||||
//cerr << "Create new renderer for buffer type #" << int(myBufferType) << '\n';
|
||||
if(myRenderer)
|
||||
SDL_DestroyRenderer(myRenderer);
|
||||
|
||||
if(video != "")
|
||||
if(!video.empty())
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str());
|
||||
|
||||
myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags);
|
||||
|
@ -438,8 +444,8 @@ bool FBBackendSDL2::createRenderer()
|
|||
|
||||
if(myRenderer == nullptr)
|
||||
{
|
||||
string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError());
|
||||
Logger::error(msg);
|
||||
Logger::error("ERROR: Unable to create SDL renderer: " +
|
||||
string{SDL_GetError()});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -454,14 +460,14 @@ bool FBBackendSDL2::createRenderer()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBBackendSDL2::setTitle(const string& title)
|
||||
void FBBackendSDL2::setTitle(string_view title)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
myScreenTitle = title;
|
||||
|
||||
if(myWindow)
|
||||
SDL_SetWindowTitle(myWindow, title.c_str());
|
||||
SDL_SetWindowTitle(myWindow, string{title}.c_str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -470,18 +476,18 @@ string FBBackendSDL2::about() const
|
|||
ASSERT_MAIN_THREAD;
|
||||
|
||||
ostringstream out;
|
||||
out << "Video system: " << SDL_GetCurrentVideoDriver() << endl;
|
||||
out << "Video system: " << SDL_GetCurrentVideoDriver() << '\n';
|
||||
SDL_RendererInfo info;
|
||||
if(SDL_GetRendererInfo(myRenderer, &info) >= 0)
|
||||
{
|
||||
out << " Renderer: " << info.name << endl;
|
||||
out << " Renderer: " << info.name << '\n';
|
||||
if(info.max_texture_width > 0 && info.max_texture_height > 0)
|
||||
out << " Max texture: " << info.max_texture_width << "x"
|
||||
<< info.max_texture_height << endl;
|
||||
<< info.max_texture_height << '\n';
|
||||
out << " Flags: "
|
||||
<< ((info.flags & SDL_RENDERER_PRESENTVSYNC) ? "+" : "-") << "vsync, "
|
||||
<< ((info.flags & SDL_RENDERER_ACCELERATED) ? "+" : "-") << "accel"
|
||||
<< endl;
|
||||
<< '\n';
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
@ -567,7 +573,7 @@ unique_ptr<FBSurface> FBBackendSDL2::createSurface(
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBBackendSDL2::readPixels(uInt8* pixels, uInt32 pitch,
|
||||
void FBBackendSDL2::readPixels(uInt8* buffer, size_t pitch,
|
||||
const Common::Rect& rect) const
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
@ -576,7 +582,7 @@ void FBBackendSDL2::readPixels(uInt8* pixels, uInt32 pitch,
|
|||
r.x = rect.x(); r.y = rect.y();
|
||||
r.w = rect.w(); r.h = rect.h();
|
||||
|
||||
SDL_RenderReadPixels(myRenderer, &r, 0, pixels, pitch);
|
||||
SDL_RenderReadPixels(myRenderer, &r, 0, buffer, static_cast<int>(pitch));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -78,7 +78,7 @@ class FBBackendSDL2 : public FBBackend
|
|||
|
||||
@param title The title of the application / window
|
||||
*/
|
||||
void setTitle(const string& title) override;
|
||||
void setTitle(string_view title) override;
|
||||
|
||||
/**
|
||||
Shows or hides the cursor based on the given boolean value.
|
||||
|
@ -98,9 +98,21 @@ class FBBackendSDL2 : public FBBackend
|
|||
@param g The green component of the color
|
||||
@param b The blue component of the color
|
||||
*/
|
||||
inline void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
|
||||
FORCE_INLINE void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
|
||||
{ SDL_GetRGB(pixel, myPixelFormat, r, g, b); }
|
||||
|
||||
/**
|
||||
This method is called to retrieve the R/G/B/A data from the given pixel.
|
||||
|
||||
@param pixel The pixel containing R/G/B data
|
||||
@param r The red component of the color
|
||||
@param g The green component of the color
|
||||
@param b The blue component of the color
|
||||
@param a The alpha component of the color.
|
||||
*/
|
||||
FORCE_INLINE void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const override
|
||||
{ SDL_GetRGBA(pixel, myPixelFormat, r, g, b, a); }
|
||||
|
||||
/**
|
||||
This method is called to map a given R/G/B triple to the screen palette.
|
||||
|
||||
|
@ -108,9 +120,20 @@ class FBBackendSDL2 : public FBBackend
|
|||
@param g The green component of the color.
|
||||
@param b The blue component of the color.
|
||||
*/
|
||||
inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
|
||||
uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
|
||||
{ return SDL_MapRGB(myPixelFormat, r, g, b); }
|
||||
|
||||
/**
|
||||
This method is called to map a given R/G/B/A triple to the screen palette.
|
||||
|
||||
@param r The red component of the color.
|
||||
@param g The green component of the color.
|
||||
@param b The blue component of the color.
|
||||
@param a The alpha component of the color.
|
||||
*/
|
||||
uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const override
|
||||
{ return SDL_MapRGBA(myPixelFormat, r, g, b, a); }
|
||||
|
||||
/**
|
||||
This method is called to get a copy of the specified ARGB data from the
|
||||
viewable FrameBuffer area. Note that this isn't the same as any
|
||||
|
@ -121,7 +144,7 @@ class FBBackendSDL2 : public FBBackend
|
|||
@param pitch The pitch (in bytes) for the pixel data
|
||||
@param rect The bounding rectangle for the buffer
|
||||
*/
|
||||
void readPixels(uInt8* buffer, uInt32 pitch,
|
||||
void readPixels(uInt8* buffer, size_t pitch,
|
||||
const Common::Rect& rect) const override;
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -38,7 +38,7 @@ namespace {
|
|||
throw runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
|
||||
|
@ -48,6 +48,7 @@ FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
|
|||
: myBackend{backend},
|
||||
myInterpolationMode{inter}
|
||||
{
|
||||
//cerr << width << " x " << height << '\n';
|
||||
createSurface(width, height, staticData);
|
||||
}
|
||||
|
||||
|
@ -233,6 +234,7 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
|
|||
|
||||
mySurface = SDL_CreateRGBSurface(0, width, height,
|
||||
pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask);
|
||||
//SDL_SetSurfaceBlendMode(mySurface, SDL_BLENDMODE_ADD); // default: SDL_BLENDMODE_BLEND
|
||||
|
||||
// We start out with the src and dst rectangles containing the same
|
||||
// dimensions, indicating no scaling or re-positioning
|
||||
|
@ -249,9 +251,10 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
|
|||
|
||||
myIsStatic = data != nullptr;
|
||||
if(myIsStatic)
|
||||
SDL_memcpy(mySurface->pixels, data, mySurface->w * mySurface->h * 4);
|
||||
SDL_memcpy(mySurface->pixels, data,
|
||||
static_cast<size_t>(mySurface->w) * mySurface->h * 4);
|
||||
|
||||
reload();
|
||||
reload(); // NOLINT
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -278,8 +281,12 @@ void FBSurfaceSDL2::applyAttributes()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurfaceSDL2::setScalingInterpolation(ScalingInterpolation interpolation)
|
||||
{
|
||||
if (interpolation == ScalingInterpolation::sharp
|
||||
&& mySrcGUIR.h() >= myDstGUIR.h())
|
||||
if (interpolation == ScalingInterpolation::sharp &&
|
||||
(
|
||||
static_cast<int>(mySrcGUIR.h()) >= myBackend.scaleY(myDstGUIR.h()) ||
|
||||
static_cast<int>(mySrcGUIR.w()) >= myBackend.scaleX(myDstGUIR.w())
|
||||
)
|
||||
)
|
||||
interpolation = ScalingInterpolation::blur;
|
||||
|
||||
if (interpolation == myInterpolationMode) return;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -69,8 +69,8 @@ class FBSurfaceSDL2 : public FBSurface
|
|||
void applyAttributes() override;
|
||||
|
||||
private:
|
||||
inline bool setSrcPosInternal(uInt32 x, uInt32 y) {
|
||||
if(x != static_cast<uInt32>(mySrcR.x) || y != static_cast<uInt32>(mySrcR.y))
|
||||
bool setSrcPosInternal(uInt32 x, uInt32 y) {
|
||||
if(std::cmp_not_equal(x, mySrcR.x) || std::cmp_not_equal(y, mySrcR.y))
|
||||
{
|
||||
mySrcR.x = x; mySrcR.y = y;
|
||||
mySrcGUIR.moveTo(x, y);
|
||||
|
@ -78,8 +78,8 @@ class FBSurfaceSDL2 : public FBSurface
|
|||
}
|
||||
return false;
|
||||
}
|
||||
inline bool setSrcSizeInternal(uInt32 w, uInt32 h) {
|
||||
if(w != static_cast<uInt32>(mySrcR.w) || h != static_cast<uInt32>(mySrcR.h))
|
||||
bool setSrcSizeInternal(uInt32 w, uInt32 h) {
|
||||
if(std::cmp_not_equal(w, mySrcR.w) || std::cmp_not_equal(h, mySrcR.h))
|
||||
{
|
||||
mySrcR.w = w; mySrcR.h = h;
|
||||
mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h);
|
||||
|
@ -87,8 +87,8 @@ class FBSurfaceSDL2 : public FBSurface
|
|||
}
|
||||
return false;
|
||||
}
|
||||
inline bool setDstPosInternal(uInt32 x, uInt32 y) {
|
||||
if(x != static_cast<uInt32>(myDstR.x) || y != static_cast<uInt32>(myDstR.y))
|
||||
bool setDstPosInternal(uInt32 x, uInt32 y) {
|
||||
if(std::cmp_not_equal(x, myDstR.x) || std::cmp_not_equal(y, myDstR.y))
|
||||
{
|
||||
myDstR.x = x; myDstR.y = y;
|
||||
myDstGUIR.moveTo(x, y);
|
||||
|
@ -96,8 +96,8 @@ class FBSurfaceSDL2 : public FBSurface
|
|||
}
|
||||
return false;
|
||||
}
|
||||
inline bool setDstSizeInternal(uInt32 w, uInt32 h) {
|
||||
if(w != static_cast<uInt32>(myDstR.w) || h != static_cast<uInt32>(myDstR.h))
|
||||
bool setDstSizeInternal(uInt32 w, uInt32 h) {
|
||||
if(std::cmp_not_equal(w, myDstR.w) || std::cmp_not_equal(h, myDstR.h))
|
||||
{
|
||||
myDstR.w = w; myDstR.h = h;
|
||||
myDstGUIR.setWidth(w); myDstGUIR.setHeight(h);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -38,41 +38,44 @@ class AbstractFSNode;
|
|||
|
||||
@author Stephen Anthony
|
||||
*/
|
||||
class FilesystemNodeFactory
|
||||
class FSNodeFactory
|
||||
{
|
||||
public:
|
||||
enum class Type { SYSTEM, ZIP };
|
||||
enum class Type: uInt8 { SYSTEM, ZIP };
|
||||
|
||||
public:
|
||||
static unique_ptr<AbstractFSNode> create(const string& path, Type type)
|
||||
static unique_ptr<AbstractFSNode> create(string_view path, Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Type::SYSTEM:
|
||||
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
|
||||
return make_unique<FilesystemNodePOSIX>(path);
|
||||
return make_unique<FSNodePOSIX>(path);
|
||||
#elif defined(BSPF_WINDOWS)
|
||||
return make_unique<FilesystemNodeWINDOWS>(path);
|
||||
return make_unique<FSNodeWINDOWS>(path);
|
||||
#elif defined(__LIB_RETRO__)
|
||||
return make_unique<FilesystemNodeLIBRETRO>(path);
|
||||
return make_unique<FSNodeLIBRETRO>(path);
|
||||
#endif
|
||||
break;
|
||||
case Type::ZIP:
|
||||
#if defined(ZIP_SUPPORT)
|
||||
return make_unique<FilesystemNodeZIP>(path);
|
||||
return make_unique<FSNodeZIP>(path);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
return nullptr; // satisfy compiler
|
||||
}
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
FilesystemNodeFactory() = delete;
|
||||
FilesystemNodeFactory(const FilesystemNodeFactory&) = delete;
|
||||
FilesystemNodeFactory(FilesystemNodeFactory&&) = delete;
|
||||
FilesystemNodeFactory& operator=(const FilesystemNodeFactory&) = delete;
|
||||
FilesystemNodeFactory& operator=(FilesystemNodeFactory&&) = delete;
|
||||
FSNodeFactory() = delete;
|
||||
~FSNodeFactory() = delete;
|
||||
FSNodeFactory(const FSNodeFactory&) = delete;
|
||||
FSNodeFactory(FSNodeFactory&&) = delete;
|
||||
FSNodeFactory& operator=(const FSNodeFactory&) = delete;
|
||||
FSNodeFactory& operator=(FSNodeFactory&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -21,12 +21,11 @@
|
|||
|
||||
#include "bspf.hxx"
|
||||
#include "Bankswitch.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "FSNodeFactory.hxx"
|
||||
#include "FSNodeZIP.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
||||
FSNodeZIP::FSNodeZIP(string_view p)
|
||||
{
|
||||
// Extract ZIP file and virtual file (if specified)
|
||||
const size_t pos = BSPF::findIgnoreCase(p, ".zip");
|
||||
|
@ -36,18 +35,18 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
_zipFile = p.substr(0, pos+4);
|
||||
|
||||
// Expand '~' to the users 'home' directory
|
||||
if (_zipFile[0] == '~')
|
||||
if(_zipFile[0] == '~')
|
||||
{
|
||||
#if defined(BSPF_UNIX) || defined(BSPF_MACOS)
|
||||
const char* home = std::getenv("HOME");
|
||||
if (home != nullptr)
|
||||
const char* const home = std::getenv("HOME"); // NOLINT (not thread safe)
|
||||
if(home != nullptr)
|
||||
_zipFile.replace(0, 1, home);
|
||||
#elif defined(BSPF_WINDOWS)
|
||||
_zipFile.replace(0, 1, myHomeFinder.getHomePath());
|
||||
_zipFile.replace(0, 1, HomeFinder::getHomePath());
|
||||
#endif
|
||||
}
|
||||
|
||||
// cerr << " => p: " << p << endl;
|
||||
// cerr << " => p: " << p << '\n';
|
||||
|
||||
// Open file at least once to initialize the virtual file count
|
||||
try
|
||||
|
@ -100,30 +99,28 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
// has direct access to the actual filesystem (aka, a 'System' node)
|
||||
// Behind the scenes, this node is actually a platform-specific object
|
||||
// for whatever system we are running on
|
||||
_realNode = FilesystemNodeFactory::create(_zipFile,
|
||||
FilesystemNodeFactory::Type::SYSTEM);
|
||||
_realNode = FSNodeFactory::create(_zipFile,
|
||||
FSNodeFactory::Type::SYSTEM);
|
||||
|
||||
setFlags(_zipFile, _virtualPath, _realNode);
|
||||
// cerr << "==============================================================\n";
|
||||
// cerr << _name << ", file: " << _isFile << ", dir: " << _isDirectory << endl << endl;
|
||||
// cerr << _name << ", file: " << _isFile << ", dir: " << _isDirectory << "\n\n";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodeZIP::FilesystemNodeZIP(
|
||||
const string& zipfile, const string& virtualpath,
|
||||
const AbstractFSNodePtr& realnode, size_t size, bool isdir)
|
||||
FSNodeZIP::FSNodeZIP(const string& zipfile, const string& virtualpath,
|
||||
const AbstractFSNodePtr& realnode, size_t size, bool isdir)
|
||||
: _size{size},
|
||||
_isDirectory{isdir},
|
||||
_isFile{!isdir}
|
||||
{
|
||||
// cerr << "=> c'tor 2: " << zipfile << ", " << virtualpath << ", " << isdir << endl;
|
||||
// cerr << "=> c'tor 2: " << zipfile << ", " << virtualpath << ", " << isdir << '\n';
|
||||
setFlags(zipfile, virtualpath, realnode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FilesystemNodeZIP::setFlags(const string& zipfile,
|
||||
const string& virtualpath,
|
||||
const AbstractFSNodePtr& realnode)
|
||||
void FSNodeZIP::setFlags(const string& zipfile, const string& virtualpath,
|
||||
const AbstractFSNodePtr& realnode)
|
||||
{
|
||||
_zipFile = zipfile;
|
||||
_virtualPath = virtualpath;
|
||||
|
@ -133,7 +130,7 @@ void FilesystemNodeZIP::setFlags(const string& zipfile,
|
|||
_shortPath = _realNode->getShortPath();
|
||||
|
||||
// Is a file component present?
|
||||
if(_virtualPath.size() != 0)
|
||||
if(!_virtualPath.empty())
|
||||
{
|
||||
_path += ("/" + _virtualPath);
|
||||
_shortPath += ("/" + _virtualPath);
|
||||
|
@ -147,7 +144,7 @@ void FilesystemNodeZIP::setFlags(const string& zipfile,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNodeZIP::exists() const
|
||||
bool FSNodeZIP::exists() const
|
||||
{
|
||||
if(_realNode && _realNode->exists())
|
||||
{
|
||||
|
@ -165,6 +162,7 @@ bool FilesystemNodeZIP::exists() const
|
|||
catch(const runtime_error&)
|
||||
{
|
||||
// TODO: Actually present the error passed in back to the user
|
||||
cerr << "ERROR: FSNodeZIP::exists()\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +170,7 @@ bool FilesystemNodeZIP::exists() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
|
||||
bool FSNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
|
||||
{
|
||||
// Files within ZIP archives don't contain children
|
||||
if(!isDirectory() || _error != zip_error::NONE)
|
||||
|
@ -180,7 +178,6 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
|
|||
|
||||
std::set<string> dirs;
|
||||
myZipHandler->open(_zipFile);
|
||||
// cerr << "CHILDREN: --------------------------------\n";
|
||||
while(myZipHandler->hasNext())
|
||||
{
|
||||
// Only consider entries that start with '_virtualPath'
|
||||
|
@ -192,39 +189,37 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const
|
|||
{
|
||||
// First strip off the leading directory
|
||||
const string& curr = name.substr(
|
||||
_virtualPath == "" ? 0 : _virtualPath.size()+1);
|
||||
// cerr << " curr: " << curr << endl;
|
||||
_virtualPath.empty() ? 0 : _virtualPath.size()+1);
|
||||
|
||||
// Only add sub-directory entries once
|
||||
const auto pos = curr.find_first_of("/\\");
|
||||
if(pos != string::npos)
|
||||
dirs.emplace(curr.substr(0, pos));
|
||||
else
|
||||
myList.emplace_back(new FilesystemNodeZIP(_zipFile, name, _realNode, size, false));
|
||||
myList.emplace_back(new FSNodeZIP(_zipFile, name, _realNode, size, false));
|
||||
}
|
||||
}
|
||||
for(const auto& dir: dirs)
|
||||
{
|
||||
// Prepend previous path
|
||||
const string& vpath = _virtualPath != "" ? _virtualPath + "/" + dir : dir;
|
||||
myList.emplace_back(new FilesystemNodeZIP(_zipFile, vpath, _realNode, 0, true));
|
||||
const string& vpath = !_virtualPath.empty() ? _virtualPath + "/" + dir : dir;
|
||||
myList.emplace_back(new FSNodeZIP(_zipFile, vpath, _realNode, 0, true));
|
||||
}
|
||||
|
||||
// cerr << "list: \n";
|
||||
// for(auto& s: myList)
|
||||
// cerr << s->getPath() << " : isdir: " << s->isDirectory() << endl;
|
||||
// cerr << "------------------------------------------\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
size_t FilesystemNodeZIP::read(ByteBuffer& image, size_t) const
|
||||
size_t FSNodeZIP::read(ByteBuffer& buffer, size_t) const
|
||||
{
|
||||
switch(_error)
|
||||
{
|
||||
case zip_error::NONE: break;
|
||||
case zip_error::NOT_A_FILE: throw runtime_error("ZIP file contains errors/not found");
|
||||
case zip_error::NOT_READABLE: throw runtime_error("ZIP file not readable");
|
||||
case zip_error::NO_ROMS: throw runtime_error("ZIP file doesn't contain any ROMs");
|
||||
using enum zip_error;
|
||||
case NONE: break;
|
||||
case NOT_A_FILE: throw runtime_error("ZIP file contains errors/not found");
|
||||
case NOT_READABLE: throw runtime_error("ZIP file not readable");
|
||||
case NO_ROMS: throw runtime_error("ZIP file doesn't contain any ROMs");
|
||||
default: throw runtime_error("FSNodeZIP::read default case hit");
|
||||
}
|
||||
|
||||
myZipHandler->open(_zipFile);
|
||||
|
@ -236,49 +231,58 @@ size_t FilesystemNodeZIP::read(ByteBuffer& image, size_t) const
|
|||
found = name == _virtualPath;
|
||||
}
|
||||
|
||||
return found ? myZipHandler->decompress(image) : 0;
|
||||
return found ? myZipHandler->decompress(buffer) : 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
size_t FilesystemNodeZIP::read(stringstream& image) const
|
||||
size_t FSNodeZIP::read(stringstream& buffer) const
|
||||
{
|
||||
// For now, we just read into a buffer and store in the stream
|
||||
// TODO: maybe there's a more efficient way to do this?
|
||||
ByteBuffer buffer;
|
||||
const size_t size = read(buffer, 0);
|
||||
ByteBuffer read_buf;
|
||||
const size_t size = read(read_buf, 0);
|
||||
if(size > 0)
|
||||
image.write(reinterpret_cast<char*>(buffer.get()), size);
|
||||
buffer.write(reinterpret_cast<char*>(read_buf.get()), size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
size_t FilesystemNodeZIP::write(const ByteBuffer& buffer, size_t size) const
|
||||
size_t FSNodeZIP::write(const ByteBuffer& buffer, size_t) const
|
||||
{
|
||||
// TODO: Not yet implemented
|
||||
throw runtime_error("ZIP file not writable");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
size_t FilesystemNodeZIP::write(const stringstream& buffer) const
|
||||
size_t FSNodeZIP::write(const stringstream& buffer) const
|
||||
{
|
||||
// TODO: Not yet implemented
|
||||
throw runtime_error("ZIP file not writable");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AbstractFSNodePtr FilesystemNodeZIP::getParent() const
|
||||
AbstractFSNodePtr FSNodeZIP::getParent() const
|
||||
{
|
||||
if(_virtualPath == "")
|
||||
if(_virtualPath.empty())
|
||||
return _realNode ? _realNode->getParent() : nullptr;
|
||||
|
||||
const char* start = _path.c_str();
|
||||
const char* end = lastPathComponent(_path);
|
||||
// TODO: For some reason, getting the stem for normal paths and zip paths
|
||||
// behaves differently. For now, we'll use the old method here.
|
||||
auto STEM_FOR_ZIP = [](string_view s) {
|
||||
const char* const start = s.data();
|
||||
const char* cur = start + s.size() - 2;
|
||||
|
||||
return make_unique<FilesystemNodeZIP>(string(start, end - start - 1));
|
||||
while (cur >= start && !(*cur == '/' || *cur == '\\'))
|
||||
--cur;
|
||||
|
||||
return s.substr(0, (cur + 1) - start - 1);
|
||||
};
|
||||
|
||||
return make_unique<FSNodeZIP>(STEM_FOR_ZIP(_path));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
unique_ptr<ZipHandler> FilesystemNodeZIP::myZipHandler = make_unique<ZipHandler>();
|
||||
unique_ptr<ZipHandler> FSNodeZIP::myZipHandler = make_unique<ZipHandler>();
|
||||
|
||||
#endif // ZIP_SUPPORT
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -32,19 +32,19 @@
|
|||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class FilesystemNodeZIP : public AbstractFSNode
|
||||
class FSNodeZIP : public AbstractFSNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a FilesystemNodeZIP for a given path.
|
||||
* Creates a FSNodeZIP for a given path.
|
||||
*
|
||||
* @param path String with the path the new node should point to.
|
||||
*/
|
||||
explicit FilesystemNodeZIP(const string& path);
|
||||
explicit FSNodeZIP(string_view path);
|
||||
|
||||
bool exists() const override;
|
||||
const string& getName() const override { return _name; }
|
||||
void setName(const string& name) override { _name = name; }
|
||||
const string& getName() const override { return _name; }
|
||||
void setName(string_view name) override { _name = name; }
|
||||
const string& getPath() const override { return _path; }
|
||||
string getShortPath() const override { return _shortPath; }
|
||||
bool hasParent() const override { return true; }
|
||||
|
@ -56,39 +56,39 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
//////////////////////////////////////////////////////////
|
||||
// For now, ZIP files cannot be modified in any way
|
||||
bool makeDir() override { return false; }
|
||||
bool rename(const string& newfile) override { return false; }
|
||||
bool rename(string_view) override { return false; }
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
size_t getSize() const override { return _size; }
|
||||
bool getChildren(AbstractFSList& list, ListMode mode) const override;
|
||||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
size_t read(ByteBuffer& buffer, size_t size) const override;
|
||||
size_t read(ByteBuffer& buffer, size_t) const override;
|
||||
size_t read(stringstream& buffer) const override;
|
||||
size_t write(const ByteBuffer& buffer, size_t size) const override;
|
||||
size_t write(const ByteBuffer& buffer, size_t) const override;
|
||||
size_t write(const stringstream& buffer) const override;
|
||||
|
||||
private:
|
||||
FilesystemNodeZIP(const string& zipfile, const string& virtualpath,
|
||||
FSNodeZIP(const string& zipfile, const string& virtualpath,
|
||||
const AbstractFSNodePtr& realnode, size_t size, bool isdir);
|
||||
|
||||
void setFlags(const string& zipfile, const string& virtualpath,
|
||||
const AbstractFSNodePtr& realnode);
|
||||
|
||||
friend ostream& operator<<(ostream& os, const FilesystemNodeZIP& node)
|
||||
friend ostream& operator<<(ostream& os, const FSNodeZIP& node)
|
||||
{
|
||||
os << "_zipFile: " << node._zipFile << endl
|
||||
<< "_virtualPath: " << node._virtualPath << endl
|
||||
<< "_name: " << node._name << endl
|
||||
<< "_path: " << node._path << endl
|
||||
<< "_size: " << node._size << endl
|
||||
<< "_shortPath: " << node._shortPath << endl;
|
||||
os << "_zipFile: " << node._zipFile << '\n'
|
||||
<< "_virtualPath: " << node._virtualPath << '\n'
|
||||
<< "_name: " << node._name << '\n'
|
||||
<< "_path: " << node._path << '\n'
|
||||
<< "_size: " << node._size << '\n'
|
||||
<< "_shortPath: " << node._shortPath << '\n';
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
/* Error types */
|
||||
enum class zip_error
|
||||
enum class zip_error: uInt8
|
||||
{
|
||||
NONE,
|
||||
NOT_A_FILE,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -46,32 +46,27 @@ void FpsMeter::render(uInt32 frameCount)
|
|||
}
|
||||
|
||||
const size_t queueSize = myQueue.capacity();
|
||||
entry first, last;
|
||||
entry e_first, e_last;
|
||||
|
||||
last.frames = frameCount;
|
||||
last.timestamp = high_resolution_clock::now();
|
||||
e_last.frames = frameCount;
|
||||
e_last.timestamp = high_resolution_clock::now();
|
||||
|
||||
if (myQueue.size() < queueSize) {
|
||||
myQueue.push_back(last);
|
||||
myQueue.push_back(e_last);
|
||||
myFrameCount += frameCount;
|
||||
|
||||
first = myQueue.at(myQueueOffset);
|
||||
e_first = myQueue.at(myQueueOffset);
|
||||
} else {
|
||||
myFrameCount = myFrameCount - myQueue.at(myQueueOffset).frames + frameCount;
|
||||
myQueue.at(myQueueOffset) = last;
|
||||
myQueue.at(myQueueOffset) = e_last;
|
||||
|
||||
myQueueOffset = (myQueueOffset + 1) % queueSize;
|
||||
first = myQueue.at(myQueueOffset);
|
||||
e_first = myQueue.at(myQueueOffset);
|
||||
}
|
||||
|
||||
const float myTimeInterval =
|
||||
duration_cast<duration<float>>(last.timestamp - first.timestamp).count();
|
||||
duration_cast<duration<float>>(e_last.timestamp - e_first.timestamp).count();
|
||||
|
||||
if (myTimeInterval > 0) myFps = (myFrameCount - first.frames) / myTimeInterval;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
float FpsMeter::fps() const
|
||||
{
|
||||
return myFps;
|
||||
if (myTimeInterval > 0)
|
||||
myFps = (myFrameCount - e_first.frames) / myTimeInterval;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -27,12 +27,13 @@ class FpsMeter
|
|||
public:
|
||||
|
||||
explicit FpsMeter(uInt32 queueSize);
|
||||
~FpsMeter() = default;
|
||||
|
||||
void reset(uInt32 garbageFrameLimit = 0);
|
||||
|
||||
void render(uInt32 frameCount);
|
||||
|
||||
float fps() const;
|
||||
float fps() const { return myFps; }
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -65,9 +65,10 @@ HighScoresManager::HighScoresManager(OSystem& osystem)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void HighScoresManager::setRepository(shared_ptr<CompositeKeyValueRepositoryAtomic> repo)
|
||||
void HighScoresManager::setRepository(
|
||||
shared_ptr<CompositeKeyValueRepositoryAtomic> repo)
|
||||
{
|
||||
myHighscoreRepository = repo;
|
||||
myHighscoreRepository = std::move(repo);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -76,7 +77,7 @@ Int16 HighScoresManager::peek(uInt16 addr) const
|
|||
if (myOSystem.hasConsole())
|
||||
{
|
||||
if(addr < 0x100U || myOSystem.console().cartridge().internalRamSize() == 0)
|
||||
return myOSystem.console().system().peek(addr);
|
||||
return myOSystem.console().system().peekOob(addr);
|
||||
else
|
||||
return myOSystem.console().cartridge().internalRamGetValue(addr);
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ Int16 HighScoresManager::peek(uInt16 addr) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const json HighScoresManager::properties(const Properties& props) const
|
||||
json HighScoresManager::properties(const Properties& props)
|
||||
{
|
||||
const string& property = props.get(PropType::Cart_Highscore);
|
||||
|
||||
|
@ -94,7 +95,6 @@ const json HighScoresManager::properties(const Properties& props) const
|
|||
return json::parse(property);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json HighScoresManager::properties(json& jprops) const
|
||||
{
|
||||
|
@ -113,7 +113,6 @@ json HighScoresManager::properties(json& jprops) const
|
|||
return jprops = properties(props);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::enabled() const
|
||||
{
|
||||
|
@ -123,17 +122,16 @@ bool HighScoresManager::enabled() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numVariations(const json& jprops) const
|
||||
uInt32 HighScoresManager::numVariations(const json& jprops)
|
||||
{
|
||||
return min(getPropInt(jprops, VARIATIONS_COUNT, DEFAULT_VARIATION), MAX_VARIATIONS);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::get(const Properties& props, uInt32& numVariationsR,
|
||||
ScoresProps& info) const
|
||||
{
|
||||
json jprops = properties(props);
|
||||
const json jprops = properties(props);
|
||||
|
||||
numVariationsR = numVariations(jprops);
|
||||
|
||||
|
@ -158,7 +156,7 @@ bool HighScoresManager::get(const Properties& props, uInt32& numVariationsR,
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void HighScoresManager::set(Properties& props, uInt32 numVariations,
|
||||
const ScoresProps& info) const
|
||||
const ScoresProps& info)
|
||||
{
|
||||
json jprops = json::object();
|
||||
|
||||
|
@ -206,85 +204,79 @@ void HighScoresManager::set(Properties& props, uInt32 numVariations,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numDigits(const json& jprops) const
|
||||
uInt32 HighScoresManager::numDigits(const json& jprops)
|
||||
{
|
||||
return min(getPropInt(jprops, SCORE_DIGITS, DEFAULT_DIGITS), MAX_SCORE_DIGITS);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::trailingZeroes(const json& jprops) const
|
||||
uInt32 HighScoresManager::trailingZeroes(const json& jprops)
|
||||
{
|
||||
return min(getPropInt(jprops, SCORE_TRAILING_ZEROES, DEFAULT_TRAILING), MAX_TRAILING);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::scoreBCD(const json& jprops) const
|
||||
bool HighScoresManager::scoreBCD(const json& jprops)
|
||||
{
|
||||
return getPropBool(jprops, SCORE_BCD, DEFAULT_SCORE_BCD);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::scoreInvert(const json& jprops) const
|
||||
bool HighScoresManager::scoreInvert(const json& jprops)
|
||||
{
|
||||
return getPropBool(jprops, SCORE_INVERTED, DEFAULT_SCORE_REVERSED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::varBCD(const json& jprops) const
|
||||
bool HighScoresManager::varBCD(const json& jprops)
|
||||
{
|
||||
return getPropBool(jprops, VARIATIONS_BCD, DEFAULT_VARS_BCD);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::varZeroBased(const json& jprops) const
|
||||
bool HighScoresManager::varZeroBased(const json& jprops)
|
||||
{
|
||||
return getPropBool(jprops, VARIATIONS_ZERO_BASED, DEFAULT_VARS_ZERO_BASED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::specialLabel(const json& jprops) const
|
||||
string HighScoresManager::specialLabel(const json& jprops)
|
||||
{
|
||||
return getPropStr(jprops, SPECIAL_LABEL);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::specialBCD(const json& jprops) const
|
||||
bool HighScoresManager::specialBCD(const json& jprops)
|
||||
{
|
||||
return getPropBool(jprops, SPECIAL_BCD, DEFAULT_SPECIAL_BCD);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::specialZeroBased(const json& jprops) const
|
||||
bool HighScoresManager::specialZeroBased(const json& jprops)
|
||||
{
|
||||
return getPropBool(jprops, SPECIAL_ZERO_BASED, DEFAULT_SPECIAL_ZERO_BASED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::notes(const json& jprops) const
|
||||
string HighScoresManager::notes(const json& jprops)
|
||||
{
|
||||
return getPropStr(jprops, NOTES);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::varAddress(const json& jprops) const
|
||||
uInt16 HighScoresManager::varAddress(const json& jprops)
|
||||
{
|
||||
return getPropAddr(jprops, VARIATIONS_ADDRESS, DEFAULT_ADDRESS);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::specialAddress(const json& jprops) const
|
||||
uInt16 HighScoresManager::specialAddress(const json& jprops)
|
||||
{
|
||||
return getPropAddr(jprops, SPECIAL_ADDRESS, DEFAULT_ADDRESS);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numAddrBytes(Int32 digits, Int32 trailing) const
|
||||
{
|
||||
return (digits - trailing + 1) / 2;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numAddrBytes(const json& jprops) const
|
||||
uInt32 HighScoresManager::numAddrBytes(const json& jprops)
|
||||
{
|
||||
return numAddrBytes(numDigits(jprops), trailingZeroes(jprops));
|
||||
}
|
||||
|
@ -298,7 +290,7 @@ Int32 HighScoresManager::numVariations() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::specialLabel() const
|
||||
string HighScoresManager::specialLabel() const
|
||||
{
|
||||
json jprops;
|
||||
|
||||
|
@ -321,7 +313,7 @@ Int32 HighScoresManager::variation(uInt16 addr, bool varBCD, bool zeroBased,
|
|||
Int32 HighScoresManager::variation() const
|
||||
{
|
||||
json jprops;
|
||||
uInt16 addr = varAddress(properties(jprops));
|
||||
const uInt16 addr = varAddress(properties(jprops));
|
||||
|
||||
if(addr == DEFAULT_ADDRESS) {
|
||||
if(numVariations() == 1)
|
||||
|
@ -369,7 +361,7 @@ Int32 HighScoresManager::score(uInt32 numAddrBytes, uInt32 trailingZeroes,
|
|||
Int32 HighScoresManager::score() const
|
||||
{
|
||||
json jprops;
|
||||
uInt32 numBytes = numAddrBytes(properties(jprops));
|
||||
const uInt32 numBytes = numAddrBytes(properties(jprops));
|
||||
const ScoreAddresses scoreAddr = getPropScoreAddr(jprops);
|
||||
|
||||
if(static_cast<uInt32>(scoreAddr.size()) < numBytes)
|
||||
|
@ -378,7 +370,7 @@ Int32 HighScoresManager::score() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
|
||||
string HighScoresManager::formattedScore(Int32 score, Int32 width) const
|
||||
{
|
||||
if(score <= 0)
|
||||
return "";
|
||||
|
@ -389,8 +381,7 @@ const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
|
|||
|
||||
if(scoreBCD(jprops))
|
||||
{
|
||||
if(width > digits)
|
||||
digits = width;
|
||||
digits = std::max(width, digits);
|
||||
buf << std::setw(digits) << std::setfill(' ') << score;
|
||||
}
|
||||
else {
|
||||
|
@ -402,6 +393,7 @@ const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
|
|||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string HighScoresManager::md5Props() const
|
||||
{
|
||||
json jprops;
|
||||
|
@ -421,9 +413,10 @@ string HighScoresManager::md5Props() const
|
|||
|
||||
buf << specialAddress(jprops) << specialBCD(jprops) << specialZeroBased(jprops);
|
||||
|
||||
return MD5::hash(buf.str());
|
||||
return MD5::hash(buf.view());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::scoreInvert() const
|
||||
{
|
||||
json jprops;
|
||||
|
@ -438,7 +431,7 @@ Int32 HighScoresManager::special() const
|
|||
return NO_VALUE;
|
||||
|
||||
json jprops;
|
||||
uInt16 addr = specialAddress(properties(jprops));
|
||||
const uInt16 addr = specialAddress(properties(jprops));
|
||||
|
||||
if (addr == DEFAULT_ADDRESS)
|
||||
return NO_VALUE;
|
||||
|
@ -454,7 +447,7 @@ Int32 HighScoresManager::special() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::notes() const
|
||||
string HighScoresManager::notes() const
|
||||
{
|
||||
json jprops;
|
||||
|
||||
|
@ -462,13 +455,14 @@ const string HighScoresManager::notes() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const
|
||||
Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD,
|
||||
bool zeroBased)
|
||||
{
|
||||
//maxVal += zeroBased ? 0 : 1;
|
||||
maxVal -= zeroBased ? 1 : 0;
|
||||
const Int32 bits = isBCD
|
||||
? ceil(log(maxVal) / log(10) * 4)
|
||||
: ceil(log(maxVal) / log(2));
|
||||
? ceil(log(maxVal) / BSPF::ln10 * 4)
|
||||
: ceil(log(maxVal) / BSPF::ln2);
|
||||
|
||||
// limit to maxVal's bits
|
||||
val %= 1 << bits;
|
||||
|
@ -485,30 +479,29 @@ Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD, bool zero
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::getPropBool(const json& jprops, const string& key,
|
||||
bool defVal) const
|
||||
bool HighScoresManager::getPropBool(const json& jprops, string_view key,
|
||||
bool defVal)
|
||||
{
|
||||
return jprops.contains(key) ? jprops.at(key).get<bool>() : defVal;
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::getPropInt(const json& jprops, const string& key,
|
||||
uInt32 defVal) const
|
||||
uInt32 HighScoresManager::getPropInt(const json& jprops, string_view key,
|
||||
uInt32 defVal)
|
||||
{
|
||||
return jprops.contains(key) ? jprops.at(key).get<uInt32>() : defVal;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::getPropStr(const json& jprops, const string& key,
|
||||
const string& defVal) const
|
||||
string HighScoresManager::getPropStr(const json& jprops, string_view key,
|
||||
string_view defVal)
|
||||
{
|
||||
return jprops.contains(key) ? jprops.at(key).get<string>() : defVal;
|
||||
return jprops.contains(key) ? jprops.at(key).get<string>() : string{defVal};
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::getPropAddr(const json& jprops, const string& key,
|
||||
uInt16 defVal) const
|
||||
uInt16 HighScoresManager::getPropAddr(const json& jprops, string_view key,
|
||||
uInt16 defVal)
|
||||
{
|
||||
const string str = getPropStr(jprops, key);
|
||||
|
||||
|
@ -516,7 +509,7 @@ uInt16 HighScoresManager::getPropAddr(const json& jprops, const string& key,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops) const
|
||||
HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops)
|
||||
{
|
||||
ScoreAddresses scoreAddr{};
|
||||
|
||||
|
@ -543,18 +536,16 @@ const HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::fromHexStr(const string& addr) const
|
||||
uInt16 HighScoresManager::fromHexStr(string_view addr)
|
||||
{
|
||||
string naked = addr;
|
||||
if(const auto pos = addr.find("0x") != std::string::npos)
|
||||
addr = addr.substr(pos + 1);
|
||||
|
||||
if(const int pos = naked.find("0x") != std::string::npos)
|
||||
naked = naked.substr(pos + 1);
|
||||
|
||||
return stringToIntBase16(naked);
|
||||
return static_cast<uInt16>(BSPF::stoi<16>(addr));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::fromBCD(uInt8 bcd) const
|
||||
Int32 HighScoresManager::fromBCD(uInt8 bcd)
|
||||
{
|
||||
// verify if score is legit
|
||||
if ((bcd & 0xF0) >= 0xA0 || (bcd & 0xF) >= 0xA)
|
||||
|
@ -578,7 +569,7 @@ string HighScoresManager::hash(const ScoresData& data) const
|
|||
<< data.scores[r].date;
|
||||
}
|
||||
|
||||
return MD5::hash(buf.str());
|
||||
return MD5::hash(buf.view());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -665,7 +656,7 @@ void HighScoresManager::loadHighScores(ScoresData& data)
|
|||
clearHighScores(data);
|
||||
buf << "Error: Invalid high scores data for variation " << data.variation << ".";
|
||||
}
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.view());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -701,12 +692,12 @@ bool HighScoresManager::load(const json& hsData, ScoresData& data)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void HighScoresManager::clearHighScores(ScoresData& data)
|
||||
{
|
||||
for(uInt32 r = 0; r < NUM_RANKS; ++r)
|
||||
for(auto& s: data.scores)
|
||||
{
|
||||
data.scores[r].score = 0;
|
||||
data.scores[r].special = 0;
|
||||
data.scores[r].name = "";
|
||||
data.scores[r].date = "";
|
||||
s.score = 0;
|
||||
s.special = 0;
|
||||
s.name = "";
|
||||
s.date = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -65,7 +65,7 @@ namespace HSM {
|
|||
bool specialZeroBased{false};
|
||||
string notes;
|
||||
// Addresses
|
||||
ScoreAddresses scoreAddr;
|
||||
ScoreAddresses scoreAddr{};
|
||||
uInt16 varsAddr{0};
|
||||
uInt16 specialAddr{0};
|
||||
};
|
||||
|
@ -112,8 +112,8 @@ class HighScoresManager
|
|||
/**
|
||||
Set the highscore data of game's properties
|
||||
*/
|
||||
void set(Properties& props, uInt32 numVariations,
|
||||
const HSM::ScoresProps& info) const;
|
||||
static void set(Properties& props, uInt32 numVariations,
|
||||
const HSM::ScoresProps& info);
|
||||
|
||||
/**
|
||||
Calculate the score from given parameters
|
||||
|
@ -125,24 +125,26 @@ class HighScoresManager
|
|||
|
||||
// Convert the given value, using only the maximum bits required by maxVal
|
||||
// and adjusted for BCD and zero based data
|
||||
Int32 convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const;
|
||||
static Int32 convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased);
|
||||
|
||||
/**
|
||||
Calculate the number of bytes for one player's score from given parameters
|
||||
|
||||
@return The number of score address bytes
|
||||
*/
|
||||
uInt32 numAddrBytes(Int32 digits, Int32 trailing) const;
|
||||
static constexpr uInt32 numAddrBytes(Int32 digits, Int32 trailing) {
|
||||
return (digits - trailing + 1) / 2;
|
||||
}
|
||||
|
||||
// Retrieve current values (using game's properties)
|
||||
Int32 numVariations() const;
|
||||
const string specialLabel() const;
|
||||
string specialLabel() const;
|
||||
Int32 variation() const;
|
||||
Int32 score() const;
|
||||
const string formattedScore(Int32 score, Int32 width = -1) const;
|
||||
string formattedScore(Int32 score, Int32 width = -1) const;
|
||||
bool scoreInvert() const;
|
||||
Int32 special() const;
|
||||
const string notes() const;
|
||||
string notes() const;
|
||||
|
||||
// Get md5 property definition checksum
|
||||
string md5Props() const;
|
||||
|
@ -150,8 +152,8 @@ class HighScoresManager
|
|||
// Peek into memory
|
||||
Int16 peek(uInt16 addr) const;
|
||||
|
||||
void loadHighScores(HSM::ScoresData& scores);
|
||||
void saveHighScores(HSM::ScoresData& scores) const;
|
||||
void loadHighScores(HSM::ScoresData& data);
|
||||
void saveHighScores(HSM::ScoresData& data) const;
|
||||
|
||||
private:
|
||||
static const string VARIATIONS_COUNT;
|
||||
|
@ -198,53 +200,53 @@ class HighScoresManager
|
|||
Int32 variation(uInt16 addr, bool varBCD, bool zeroBased, uInt32 numVariations) const;
|
||||
|
||||
// Get individual highscore info from properties
|
||||
uInt32 numVariations(const json& jprops) const;
|
||||
uInt16 varAddress(const json& jprops) const;
|
||||
uInt16 specialAddress(const json& jprops) const;
|
||||
uInt32 numDigits(const json& jprops) const;
|
||||
uInt32 trailingZeroes(const json& jprops) const;
|
||||
bool scoreBCD(const json& jprops) const;
|
||||
bool scoreInvert(const json& jprops) const;
|
||||
bool varBCD(const json& jprops) const;
|
||||
bool varZeroBased(const json& jprops) const;
|
||||
const string specialLabel(const json& jprops) const;
|
||||
bool specialBCD(const json& jprops) const;
|
||||
bool specialZeroBased(const json& jprops) const;
|
||||
const string notes(const json& jprops) const;
|
||||
static uInt32 numVariations(const json& jprops);
|
||||
static uInt16 varAddress(const json& jprops);
|
||||
static uInt16 specialAddress(const json& jprops);
|
||||
static uInt32 numDigits(const json& jprops);
|
||||
static uInt32 trailingZeroes(const json& jprops);
|
||||
static bool scoreBCD(const json& jprops);
|
||||
static bool scoreInvert(const json& jprops);
|
||||
static bool varBCD(const json& jprops);
|
||||
static bool varZeroBased(const json& jprops);
|
||||
static string specialLabel(const json& jprops);
|
||||
static bool specialBCD(const json& jprops);
|
||||
static bool specialZeroBased(const json& jprops);
|
||||
static string notes(const json& jprops);
|
||||
|
||||
// Calculate the number of bytes for one player's score from property parameters
|
||||
uInt32 numAddrBytes(const json& jprops) const;
|
||||
static uInt32 numAddrBytes(const json& jprops);
|
||||
|
||||
// Get properties
|
||||
const json properties(const Properties& props) const;
|
||||
static json properties(const Properties& props);
|
||||
json properties(json& jprops) const;
|
||||
|
||||
// Get value from highscore properties for given key
|
||||
bool getPropBool(const json& jprops, const string& key,
|
||||
bool defVal = false) const;
|
||||
uInt32 getPropInt(const json& jprops, const string& key,
|
||||
uInt32 defVal = 0) const;
|
||||
const string getPropStr(const json& jprops, const string& key,
|
||||
const string& defVal = "") const;
|
||||
uInt16 getPropAddr(const json& jprops, const string& key,
|
||||
uInt16 defVal = 0) const;
|
||||
const HSM::ScoreAddresses getPropScoreAddr(const json& jprops) const;
|
||||
static bool getPropBool(const json& jprops, string_view key,
|
||||
bool defVal = false);
|
||||
static uInt32 getPropInt(const json& jprops, string_view key,
|
||||
uInt32 defVal = 0);
|
||||
static string getPropStr(const json& jprops, string_view key,
|
||||
string_view defVal = "");
|
||||
static uInt16 getPropAddr(const json& jprops, string_view key,
|
||||
uInt16 defVal = 0);
|
||||
static HSM::ScoreAddresses getPropScoreAddr(const json& jprops);
|
||||
|
||||
uInt16 fromHexStr(const string& addr) const;
|
||||
Int32 fromBCD(uInt8 bcd) const;
|
||||
static uInt16 fromHexStr(string_view addr);
|
||||
static Int32 fromBCD(uInt8 bcd);
|
||||
string hash(const HSM::ScoresData& data) const;
|
||||
|
||||
/**
|
||||
Loads the current high scores for this game and variation from the given JSON object.
|
||||
|
||||
@param hsData The JSON to parse
|
||||
@param scores The loaded high score data
|
||||
@param data The loaded high score data
|
||||
|
||||
@return The result of the load. True on success, false on failure.
|
||||
*/
|
||||
bool load(const json& hsData, HSM::ScoresData& scores);
|
||||
static bool load(const json& hsData, HSM::ScoresData& data);
|
||||
|
||||
void clearHighScores(HSM::ScoresData& data);
|
||||
static void clearHighScores(HSM::ScoresData& data);
|
||||
|
||||
private:
|
||||
// Reference to the osystem object
|
||||
|
@ -261,4 +263,5 @@ class HighScoresManager
|
|||
HighScoresManager& operator=(const HighScoresManager&) = delete;
|
||||
HighScoresManager& operator=(HighScoresManager&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifdef IMAGE_SUPPORT
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "nanojpeg_lib.hxx"
|
||||
#include "tinyexif_lib.hxx"
|
||||
|
||||
#include "JPGLibrary.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
JPGLibrary::JPGLibrary(OSystem& osystem)
|
||||
: myOSystem{osystem}
|
||||
{
|
||||
njInit();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JPGLibrary::loadImage(const string& filename, FBSurface& surface,
|
||||
VariantList& metaData)
|
||||
{
|
||||
std::ifstream in(filename, std::ios_base::binary | std::ios::ate);
|
||||
if(!in.is_open())
|
||||
throw runtime_error("No image found");
|
||||
const size_t size = in.tellg();
|
||||
in.clear();
|
||||
in.seekg(0);
|
||||
|
||||
// Create space for the entire file
|
||||
if(size > myFileBuffer.capacity())
|
||||
myFileBuffer.reserve(size * 1.5);
|
||||
if(!in.read(myFileBuffer.data(), size))
|
||||
throw runtime_error("JPG image data reading failed");
|
||||
|
||||
if(njDecode(myFileBuffer.data(), static_cast<int>(size)))
|
||||
throw runtime_error("Error decoding the JPG image");
|
||||
|
||||
// Read the entire image in one go
|
||||
myReadInfo.buffer = njGetImage();
|
||||
myReadInfo.width = njGetWidth();
|
||||
myReadInfo.height = njGetHeight();
|
||||
myReadInfo.pitch = myReadInfo.width * 3;
|
||||
|
||||
// Read the meta data we got
|
||||
readMetaData(filename, metaData);
|
||||
|
||||
// Load image into the surface, setting the correct dimensions
|
||||
loadImagetoSurface(surface);
|
||||
|
||||
// Cleanup
|
||||
njDone();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JPGLibrary::loadImagetoSurface(FBSurface& surface)
|
||||
{
|
||||
// First determine if we need to resize the surface
|
||||
const uInt32 iw = myReadInfo.width, ih = myReadInfo.height;
|
||||
if(iw > surface.width() || ih > surface.height())
|
||||
surface.resize(iw, ih);
|
||||
|
||||
// The source dimensions are set here; the destination dimensions are
|
||||
// set by whoever owns the surface
|
||||
surface.setSrcPos(0, 0);
|
||||
surface.setSrcSize(iw, ih);
|
||||
|
||||
// Convert RGB triples into pixels and store in the surface
|
||||
uInt32 *s_buf{nullptr}, s_pitch{0};
|
||||
surface.basePtr(s_buf, s_pitch);
|
||||
const uInt8* i_buf = myReadInfo.buffer;
|
||||
const uInt32 i_pitch = myReadInfo.pitch;
|
||||
|
||||
const FrameBuffer& fb = myOSystem.frameBuffer();
|
||||
for(uInt32 irow = 0; irow < ih; ++irow, i_buf += i_pitch, s_buf += s_pitch)
|
||||
{
|
||||
const uInt8* i_ptr = i_buf;
|
||||
uInt32* s_ptr = s_buf;
|
||||
for(uInt32 icol = 0; icol < myReadInfo.width; ++icol, i_ptr += 3)
|
||||
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr + 1), *(i_ptr + 2));
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JPGLibrary::readMetaData(const string& filename, VariantList& metaData)
|
||||
{
|
||||
metaData.clear();
|
||||
|
||||
// open a stream to read just the necessary parts of the image file
|
||||
std::ifstream in(filename, std::ifstream::binary);
|
||||
|
||||
// parse image EXIF metadata
|
||||
const TinyEXIF::EXIFInfo imageEXIF(in);
|
||||
if(imageEXIF.Fields)
|
||||
{
|
||||
// For now we only read the image description
|
||||
if(!imageEXIF.ImageDescription.empty())
|
||||
VarList::push_back(metaData, "ImageDescription", imageEXIF.ImageDescription);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
std::vector<char> JPGLibrary::myFileBuffer;
|
||||
|
||||
#endif // IMAGE_SUPPORT
|
|
@ -0,0 +1,96 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifdef IMAGE_SUPPORT
|
||||
|
||||
#ifndef JPG_LIBRARY_HXX
|
||||
#define JPG_LIBRARY_HXX
|
||||
|
||||
class OSystem;
|
||||
class FBSurface;
|
||||
|
||||
#include "Variant.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class implements a thin wrapper around the nanojpeg library, and
|
||||
abstracts all the irrelevant details other loading an actual image.
|
||||
|
||||
@author Thomas Jentzsch
|
||||
*/
|
||||
class JPGLibrary
|
||||
{
|
||||
public:
|
||||
explicit JPGLibrary(OSystem& osystem);
|
||||
~JPGLibrary() = default;
|
||||
|
||||
/**
|
||||
Read a JPG image from the specified file into a FBSurface structure,
|
||||
scaling the image to the surface bounds.
|
||||
|
||||
@param filename The filename to load the JPG image
|
||||
@param surface The FBSurface into which to place the JPG data
|
||||
@param metaData The meta data of the JPG image
|
||||
|
||||
@post On success, the FBSurface containing image data, otherwise a
|
||||
runtime_error is thrown containing a more detailed
|
||||
error message.
|
||||
*/
|
||||
void loadImage(const string& filename, FBSurface& surface,
|
||||
VariantList& metaData);
|
||||
|
||||
private:
|
||||
// Global OSystem object
|
||||
OSystem& myOSystem;
|
||||
|
||||
// The following data remains between invocations of allocateStorage,
|
||||
// and is only changed when absolutely necessary.
|
||||
struct ReadInfoType {
|
||||
unsigned char* buffer{nullptr};
|
||||
uInt32 width{0}, height{0}, pitch{0};
|
||||
};
|
||||
ReadInfoType myReadInfo;
|
||||
static std::vector<char> myFileBuffer;
|
||||
|
||||
/**
|
||||
Load the JPG data from 'ReadInfo' into the FBSurface. The surface
|
||||
is resized as necessary to accommodate the data.
|
||||
|
||||
@param surface The FBSurface into which to place the JPG data
|
||||
*/
|
||||
void loadImagetoSurface(FBSurface& surface);
|
||||
|
||||
/**
|
||||
Read EXIF meta data chunks from the image.
|
||||
|
||||
@param filename The filename to load the JPG image
|
||||
@param metaData The meta data of the JPG image
|
||||
*/
|
||||
static void readMetaData(const string& filename, VariantList& metaData);
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
JPGLibrary() = delete;
|
||||
JPGLibrary(const JPGLibrary&) = delete;
|
||||
JPGLibrary(JPGLibrary&&) = delete;
|
||||
JPGLibrary& operator=(const JPGLibrary&) = delete;
|
||||
JPGLibrary& operator=(JPGLibrary&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // IMAGE_SUPPORT
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -16,28 +16,27 @@
|
|||
//============================================================================
|
||||
|
||||
#include "JoyMap.hxx"
|
||||
#include "jsonDefinitions.hxx"
|
||||
#include "Logger.hxx"
|
||||
#include "jsonDefinitions.hxx"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::add(const Event::Type event, const JoyMapping& mapping)
|
||||
void JoyMap::add(Event::Type event, const JoyMapping& mapping)
|
||||
{
|
||||
myMap[mapping] = event;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::add(const Event::Type event, const EventMode mode, const int button,
|
||||
const JoyAxis axis, const JoyDir adir,
|
||||
const int hat, const JoyHatDir hdir)
|
||||
void JoyMap::add(Event::Type event, EventMode mode, int button,
|
||||
JoyAxis axis, JoyDir adir, int hat, JoyHatDir hdir)
|
||||
{
|
||||
add(event, JoyMapping(mode, button, axis, adir, hat, hdir));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::add(const Event::Type event, const EventMode mode, const int button,
|
||||
const int hat, const JoyHatDir hdir)
|
||||
void JoyMap::add(Event::Type event, EventMode mode, int button,
|
||||
int hat, JoyHatDir hdir)
|
||||
{
|
||||
add(event, JoyMapping(mode, button, hat, hdir));
|
||||
}
|
||||
|
@ -49,15 +48,13 @@ void JoyMap::erase(const JoyMapping& mapping)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::erase(const EventMode mode, const int button,
|
||||
const JoyAxis axis, const JoyDir adir)
|
||||
void JoyMap::erase(EventMode mode, int button, JoyAxis axis, JoyDir adir)
|
||||
{
|
||||
erase(JoyMapping(mode, button, axis, adir));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::erase(const EventMode mode, const int button,
|
||||
const int hat, const JoyHatDir hdir)
|
||||
void JoyMap::erase(EventMode mode, int button, int hat, JoyHatDir hdir)
|
||||
{
|
||||
erase(JoyMapping(mode, button, hat, hdir));
|
||||
}
|
||||
|
@ -82,15 +79,15 @@ Event::Type JoyMap::get(const JoyMapping& mapping) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Event::Type JoyMap::get(const EventMode mode, const int button,
|
||||
const JoyAxis axis, const JoyDir adir) const
|
||||
Event::Type JoyMap::get(EventMode mode, int button,
|
||||
JoyAxis axis, JoyDir adir) const
|
||||
{
|
||||
return get(JoyMapping(mode, button, axis, adir));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Event::Type JoyMap::get(const EventMode mode, const int button,
|
||||
const int hat, const JoyHatDir hdir) const
|
||||
Event::Type JoyMap::get(EventMode mode, int button,
|
||||
int hat, JoyHatDir hdir) const
|
||||
{
|
||||
return get(JoyMapping(mode, button, hat, hdir));
|
||||
}
|
||||
|
@ -98,21 +95,18 @@ Event::Type JoyMap::get(const EventMode mode, const int button,
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool JoyMap::check(const JoyMapping& mapping) const
|
||||
{
|
||||
const auto find = myMap.find(mapping);
|
||||
|
||||
return (find != myMap.end());
|
||||
return myMap.contains(mapping);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool JoyMap::check(const EventMode mode, const int button,
|
||||
const JoyAxis axis, const JoyDir adir,
|
||||
const int hat, const JoyHatDir hdir) const
|
||||
bool JoyMap::check(EventMode mode, int button, JoyAxis axis, JoyDir adir,
|
||||
int hat, JoyHatDir hdir) const
|
||||
{
|
||||
return check(JoyMapping(mode, button, axis, adir, hat, hdir));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
|
||||
string JoyMap::getDesc(Event::Type event, const JoyMapping& mapping)
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
|
@ -158,7 +152,8 @@ string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const EventMode mode) const
|
||||
string JoyMap::getEventMappingDesc(int stick, Event::Type event,
|
||||
EventMode mode) const
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
|
@ -166,7 +161,7 @@ string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const Eve
|
|||
{
|
||||
if (_event == event && _mapping.mode == mode)
|
||||
{
|
||||
if(buf.str() != "")
|
||||
if(!buf.view().empty())
|
||||
buf << ", ";
|
||||
buf << "C" << stick << getDesc(event, _mapping);
|
||||
}
|
||||
|
@ -175,7 +170,8 @@ string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const Eve
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const EventMode mode) const
|
||||
JoyMap::JoyMappingArray JoyMap::getEventMapping(Event::Type event,
|
||||
EventMode mode) const
|
||||
{
|
||||
JoyMappingArray map;
|
||||
|
||||
|
@ -187,32 +183,31 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json JoyMap::saveMapping(const EventMode mode) const
|
||||
json JoyMap::saveMapping(EventMode mode) const
|
||||
{
|
||||
using MapType = std::pair<JoyMapping, Event::Type>;
|
||||
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
|
||||
|
||||
std::sort(sortedMap.begin(), sortedMap.end(),
|
||||
[](const MapType& a, const MapType& b)
|
||||
{
|
||||
// Event::Type first
|
||||
if(a.first.button != b.first.button)
|
||||
return a.first.button < b.first.button;
|
||||
std::ranges::sort(sortedMap, [](const MapType& a, const MapType& b)
|
||||
{
|
||||
// Event::Type first
|
||||
if(a.first.button != b.first.button)
|
||||
return a.first.button < b.first.button;
|
||||
|
||||
if(a.first.axis != b.first.axis)
|
||||
return a.first.axis < b.first.axis;
|
||||
if(a.first.axis != b.first.axis)
|
||||
return a.first.axis < b.first.axis;
|
||||
|
||||
if(a.first.adir != b.first.adir)
|
||||
return a.first.adir < b.first.adir;
|
||||
if(a.first.adir != b.first.adir)
|
||||
return a.first.adir < b.first.adir;
|
||||
|
||||
if(a.first.hat != b.first.hat)
|
||||
return a.first.hat < b.first.hat;
|
||||
if(a.first.hat != b.first.hat)
|
||||
return a.first.hat < b.first.hat;
|
||||
|
||||
if(a.first.hdir != b.first.hdir)
|
||||
return a.first.hdir < b.first.hdir;
|
||||
if(a.first.hdir != b.first.hdir)
|
||||
return a.first.hdir < b.first.hdir;
|
||||
|
||||
return a.second < b.second;
|
||||
}
|
||||
return a.second < b.second;
|
||||
}
|
||||
);
|
||||
|
||||
json eventMappings = json::array();
|
||||
|
@ -243,16 +238,26 @@ json JoyMap::saveMapping(const EventMode mode) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
|
||||
int JoyMap::loadMapping(const json& eventMappings, EventMode mode)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for(const json& eventMapping : eventMappings) {
|
||||
int button = eventMapping.contains("button") ? eventMapping.at("button").get<int>() : JOY_CTRL_NONE;
|
||||
JoyAxis axis = eventMapping.contains("axis") ? eventMapping.at("axis").get<JoyAxis>() : JoyAxis::NONE;
|
||||
JoyDir axisDirection = eventMapping.contains("axis") ? eventMapping.at("axisDirection").get<JoyDir>() : JoyDir::NONE;
|
||||
int hat = eventMapping.contains("hat") ? eventMapping.at("hat").get<int>() : -1;
|
||||
JoyHatDir hatDirection = eventMapping.contains("hat") ? eventMapping.at("hatDirection").get<JoyHatDir>() : JoyHatDir::CENTER;
|
||||
const int button = eventMapping.contains("button")
|
||||
? eventMapping.at("button").get<int>()
|
||||
: JOY_CTRL_NONE;
|
||||
const JoyAxis axis = eventMapping.contains("axis")
|
||||
? eventMapping.at("axis").get<JoyAxis>()
|
||||
: JoyAxis::NONE;
|
||||
const JoyDir axisDirection = eventMapping.contains("axis")
|
||||
? eventMapping.at("axisDirection").get<JoyDir>()
|
||||
: JoyDir::NONE;
|
||||
const int hat = eventMapping.contains("hat")
|
||||
? eventMapping.at("hat").get<int>()
|
||||
: -1;
|
||||
const JoyHatDir hatDirection = eventMapping.contains("hat")
|
||||
? eventMapping.at("hatDirection").get<JoyHatDir>()
|
||||
: JoyHatDir::CENTER;
|
||||
|
||||
try {
|
||||
// avoid blocking mappings for NoType events
|
||||
|
@ -279,17 +284,17 @@ int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json JoyMap::convertLegacyMapping(string list)
|
||||
json JoyMap::convertLegacyMapping(string lst)
|
||||
{
|
||||
json eventMappings = json::array();
|
||||
|
||||
// Since istringstream swallows whitespace, we have to make the
|
||||
// delimiters be spaces
|
||||
std::replace(list.begin(), list.end(), '|', ' ');
|
||||
std::replace(list.begin(), list.end(), ':', ' ');
|
||||
std::replace(list.begin(), list.end(), ',', ' ');
|
||||
std::ranges::replace(lst, '|', ' ');
|
||||
std::ranges::replace(lst, ':', ' ');
|
||||
std::ranges::replace(lst, ',', ' ');
|
||||
|
||||
istringstream buf(list);
|
||||
istringstream buf(lst);
|
||||
int event = 0, button = 0, axis = 0, adir = 0, hat = 0, hdir = 0;
|
||||
|
||||
while(buf >> event && buf >> button
|
||||
|
@ -298,18 +303,18 @@ json JoyMap::convertLegacyMapping(string list)
|
|||
{
|
||||
json eventMapping = json::object();
|
||||
|
||||
eventMapping["event"] = Event::Type(event);
|
||||
eventMapping["event"] = static_cast<Event::Type>(event);
|
||||
|
||||
if(button != JOY_CTRL_NONE) eventMapping["button"] = button;
|
||||
|
||||
if(static_cast<JoyAxis>(axis) != JoyAxis::NONE) {
|
||||
eventMapping["axis"] = JoyAxis(axis);
|
||||
eventMapping["axisDirection"] = JoyDir(adir);
|
||||
eventMapping["axis"] = static_cast<JoyAxis>(axis);
|
||||
eventMapping["axisDirection"] = static_cast<JoyDir>(adir);
|
||||
}
|
||||
|
||||
if(hat != -1) {
|
||||
eventMapping["hat"] = hat;
|
||||
eventMapping["hatDirection"] = JoyHatDir(hdir);
|
||||
eventMapping["hatDirection"] = static_cast<JoyHatDir>(hdir);
|
||||
}
|
||||
|
||||
eventMappings.push_back(eventMapping);
|
||||
|
@ -319,7 +324,7 @@ json JoyMap::convertLegacyMapping(string list)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::eraseMode(const EventMode mode)
|
||||
void JoyMap::eraseMode(EventMode mode)
|
||||
{
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->first.mode == mode) {
|
||||
|
@ -330,7 +335,7 @@ void JoyMap::eraseMode(const EventMode mode)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::eraseEvent(const Event::Type event, const EventMode mode)
|
||||
void JoyMap::eraseEvent(Event::Type event, EventMode mode)
|
||||
{
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->second == event && item->first.mode == mode) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -58,6 +58,7 @@ class JoyMap
|
|||
axis{JoyAxis::NONE}, adir{JoyDir::NONE},
|
||||
hat{c_hat}, hdir{c_hdir} { }
|
||||
|
||||
~JoyMapping() = default;
|
||||
JoyMapping(const JoyMapping&) = default;
|
||||
JoyMapping& operator=(const JoyMapping&) = default;
|
||||
JoyMapping(JoyMapping&&) = default;
|
||||
|
@ -77,64 +78,61 @@ class JoyMap
|
|||
using JoyMappingArray = std::vector<JoyMapping>;
|
||||
|
||||
JoyMap() = default;
|
||||
~JoyMap() = default;
|
||||
|
||||
/** Add new mapping for given event */
|
||||
void add(const Event::Type event, const JoyMapping& mapping);
|
||||
void add(const Event::Type event, const EventMode mode, const int button,
|
||||
const JoyAxis axis, const JoyDir adir,
|
||||
const int hat = JOY_CTRL_NONE, const JoyHatDir hdir = JoyHatDir::CENTER);
|
||||
void add(const Event::Type event, const EventMode mode, const int button,
|
||||
const int hat, const JoyHatDir hdir);
|
||||
void add(Event::Type event, const JoyMapping& mapping);
|
||||
void add(Event::Type event, EventMode mode, int button,
|
||||
JoyAxis axis, JoyDir adir,
|
||||
int hat = JOY_CTRL_NONE, JoyHatDir hdir = JoyHatDir::CENTER);
|
||||
void add(Event::Type event, EventMode mode, int button,
|
||||
int hat, JoyHatDir hdir);
|
||||
|
||||
/** Erase mapping */
|
||||
void erase(const JoyMapping& mapping);
|
||||
void erase(const EventMode mode, const int button,
|
||||
const JoyAxis axis, const JoyDir adir);
|
||||
void erase(const EventMode mode, const int button,
|
||||
const int hat, const JoyHatDir hdir);
|
||||
void erase(EventMode mode, int button, JoyAxis axis, JoyDir adir);
|
||||
void erase(EventMode mode, int button, int hat, JoyHatDir hdir);
|
||||
|
||||
/** Get event for mapping */
|
||||
Event::Type get(const JoyMapping& mapping) const;
|
||||
Event::Type get(const EventMode mode, const int button,
|
||||
const JoyAxis axis = JoyAxis::NONE, const JoyDir adir = JoyDir::NONE) const;
|
||||
Event::Type get(const EventMode mode, const int button,
|
||||
const int hat, const JoyHatDir hdir) const;
|
||||
Event::Type get(EventMode mode, int button, JoyAxis axis = JoyAxis::NONE,
|
||||
JoyDir adir = JoyDir::NONE) const;
|
||||
Event::Type get(EventMode mode, int button, int hat, JoyHatDir hdir) const;
|
||||
|
||||
/** Check if a mapping exists */
|
||||
bool check(const JoyMapping& mapping) const;
|
||||
bool check(const EventMode mode, const int button,
|
||||
const JoyAxis axis, const JoyDir adir,
|
||||
const int hat = JOY_CTRL_NONE, const JoyHatDir hdir = JoyHatDir::CENTER) const;
|
||||
bool check(EventMode mode, int button, JoyAxis axis, JoyDir adir,
|
||||
int hat = JOY_CTRL_NONE, JoyHatDir hdir = JoyHatDir::CENTER) const;
|
||||
|
||||
/** Get mapping description */
|
||||
string getEventMappingDesc(int stick, const Event::Type event, const EventMode mode) const;
|
||||
string getEventMappingDesc(int stick, Event::Type event, EventMode mode) const;
|
||||
|
||||
JoyMappingArray getEventMapping(const Event::Type event, const EventMode mode) const;
|
||||
JoyMappingArray getEventMapping(Event::Type event, EventMode mode) const;
|
||||
|
||||
nlohmann::json saveMapping(const EventMode mode) const;
|
||||
int loadMapping(const nlohmann::json& eventMappings, const EventMode mode);
|
||||
nlohmann::json saveMapping(EventMode mode) const;
|
||||
int loadMapping(const nlohmann::json& eventMappings, EventMode mode);
|
||||
|
||||
static nlohmann::json convertLegacyMapping(string list);
|
||||
static nlohmann::json convertLegacyMapping(string lst);
|
||||
|
||||
/** Erase all mappings for given mode */
|
||||
void eraseMode(const EventMode mode);
|
||||
void eraseMode(EventMode mode);
|
||||
/** Erase given event's mapping for given mode */
|
||||
void eraseEvent(const Event::Type event, const EventMode mode);
|
||||
void eraseEvent(Event::Type event, EventMode mode);
|
||||
/** clear all mappings for a modes */
|
||||
// void clear() { myMap.clear(); }
|
||||
size_t size() { return myMap.size(); }
|
||||
size_t size() const { return myMap.size(); }
|
||||
|
||||
private:
|
||||
string getDesc(const Event::Type event, const JoyMapping& mapping) const;
|
||||
static string getDesc(Event::Type event, const JoyMapping& mapping);
|
||||
|
||||
struct JoyHash {
|
||||
size_t operator()(const JoyMapping& m)const {
|
||||
return std::hash<uInt64>()((uInt64(m.mode)) // 3 bits
|
||||
+ ((uInt64(m.button)) * 7) // 3 bits
|
||||
+ (((uInt64(m.axis)) << 0) // 2 bits
|
||||
| ((uInt64(m.adir)) << 2) // 2 bits
|
||||
| ((uInt64(m.hat )) << 4) // 1 bit
|
||||
| ((uInt64(m.hdir)) << 5) // 2 bits
|
||||
return std::hash<uInt64>()((static_cast<uInt64>(m.mode)) // 3 bits
|
||||
+ ((static_cast<uInt64>(m.button)) * 7) // 3 bits
|
||||
+ (((static_cast<uInt64>(m.axis)) << 0) // 3 bits
|
||||
| ((static_cast<uInt64>(m.adir)) << 3) // 2 bits
|
||||
| ((static_cast<uInt64>(m.hat )) << 5) // 1 bit
|
||||
| ((static_cast<uInt64>(m.hdir)) << 6) // 2 bits
|
||||
) * 61
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -18,18 +18,17 @@
|
|||
#include "KeyMap.hxx"
|
||||
#include "Logger.hxx"
|
||||
#include "jsonDefinitions.hxx"
|
||||
#include <map>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace {
|
||||
json serializeModkeyMask(int mask)
|
||||
{
|
||||
if(mask == StellaMod::KBDM_NONE) return json(nullptr);
|
||||
if(mask == StellaMod::KBDM_NONE) return {};
|
||||
|
||||
json serializedMask = json::array();
|
||||
|
||||
for(StellaMod mod: {
|
||||
for(const StellaMod mod: {
|
||||
StellaMod::KBDM_CTRL,
|
||||
StellaMod::KBDM_SHIFT,
|
||||
StellaMod::KBDM_ALT,
|
||||
|
@ -66,16 +65,16 @@ namespace {
|
|||
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::add(const Event::Type event, const Mapping& mapping)
|
||||
void KeyMap::add(Event::Type event, const Mapping& mapping)
|
||||
{
|
||||
myMap[convertMod(mapping)] = event;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::add(const Event::Type event, const EventMode mode, const int key, const int mod)
|
||||
void KeyMap::add(Event::Type event, EventMode mode, int key, int mod)
|
||||
{
|
||||
add(event, Mapping(mode, key, mod));
|
||||
}
|
||||
|
@ -87,7 +86,7 @@ void KeyMap::erase(const Mapping& mapping)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::erase(const EventMode mode, const int key, const int mod)
|
||||
void KeyMap::erase(EventMode mode, int key, int mod)
|
||||
{
|
||||
erase(Mapping(mode, key, mod));
|
||||
}
|
||||
|
@ -115,7 +114,7 @@ Event::Type KeyMap::get(const Mapping& mapping) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Event::Type KeyMap::get(const EventMode mode, const int key, const int mod) const
|
||||
Event::Type KeyMap::get(EventMode mode, int key, int mod) const
|
||||
{
|
||||
return get(Mapping(mode, key, mod));
|
||||
}
|
||||
|
@ -123,19 +122,17 @@ Event::Type KeyMap::get(const EventMode mode, const int key, const int mod) cons
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool KeyMap::check(const Mapping& mapping) const
|
||||
{
|
||||
const auto find = myMap.find(convertMod(mapping));
|
||||
|
||||
return (find != myMap.end());
|
||||
return myMap.contains(convertMod(mapping));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool KeyMap::check(const EventMode mode, const int key, const int mod) const
|
||||
bool KeyMap::check(EventMode mode, int key, int mod) const
|
||||
{
|
||||
return check(Mapping(mode, key, mod));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string KeyMap::getDesc(const Mapping& mapping) const
|
||||
string KeyMap::getDesc(const Mapping& mapping)
|
||||
{
|
||||
ostringstream buf;
|
||||
#if defined(BSPF_MACOS) || defined(MACOS_KEYS)
|
||||
|
@ -184,13 +181,13 @@ string KeyMap::getDesc(const Mapping& mapping) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string KeyMap::getDesc(const EventMode mode, const int key, const int mod) const
|
||||
string KeyMap::getDesc(EventMode mode, int key, int mod)
|
||||
{
|
||||
return getDesc(Mapping(mode, key, mod));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode) const
|
||||
string KeyMap::getEventMappingDesc(Event::Type event, EventMode mode) const
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
|
@ -198,7 +195,7 @@ string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode
|
|||
{
|
||||
if (_event == event && _mapping.mode == mode)
|
||||
{
|
||||
if(buf.str() != "")
|
||||
if(!buf.view().empty())
|
||||
buf << ", ";
|
||||
buf << getDesc(_mapping);
|
||||
}
|
||||
|
@ -207,25 +204,25 @@ string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const EventMode mode) const
|
||||
KeyMap::MappingArray KeyMap::getEventMapping(Event::Type event,
|
||||
EventMode mode) const
|
||||
{
|
||||
MappingArray map;
|
||||
MappingArray ma;
|
||||
|
||||
for (const auto& [_mapping, _event]: myMap)
|
||||
if (_event == event && _mapping.mode == mode)
|
||||
map.push_back(_mapping);
|
||||
ma.push_back(_mapping);
|
||||
|
||||
return map;
|
||||
return ma;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json KeyMap::saveMapping(const EventMode mode) const
|
||||
json KeyMap::saveMapping(EventMode mode) const
|
||||
{
|
||||
using MapType = std::pair<Mapping, Event::Type>;
|
||||
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
|
||||
|
||||
std::sort(sortedMap.begin(), sortedMap.end(),
|
||||
[](const MapType& a, const MapType& b)
|
||||
std::ranges::sort(sortedMap, [](const MapType& a, const MapType& b)
|
||||
{
|
||||
// Event::Type first
|
||||
if(a.first.key != b.first.key)
|
||||
|
@ -258,7 +255,8 @@ json KeyMap::saveMapping(const EventMode mode) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int KeyMap::loadMapping(const json& mappings, const EventMode mode) {
|
||||
int KeyMap::loadMapping(const json& mappings, EventMode mode)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for(const json& mapping : mappings)
|
||||
|
@ -285,27 +283,28 @@ int KeyMap::loadMapping(const json& mappings, const EventMode mode) {
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json KeyMap::convertLegacyMapping(string list)
|
||||
json KeyMap::convertLegacyMapping(string_view lm)
|
||||
{
|
||||
json convertedMapping = json::array();
|
||||
|
||||
// Since istringstream swallows whitespace, we have to make the
|
||||
// delimiters be spaces
|
||||
std::replace(list.begin(), list.end(), '|', ' ');
|
||||
std::replace(list.begin(), list.end(), ':', ' ');
|
||||
std::replace(list.begin(), list.end(), ',', ' ');
|
||||
istringstream buf(list);
|
||||
string lst{lm};
|
||||
std::ranges::replace(lst, '|', ' ');
|
||||
std::ranges::replace(lst, ':', ' ');
|
||||
std::ranges::replace(lst, ',', ' ');
|
||||
istringstream buf(lst);
|
||||
int event = 0, key = 0, mod = 0;
|
||||
|
||||
while(buf >> event && buf >> key && buf >> mod)
|
||||
{
|
||||
json mapping = json::object();
|
||||
|
||||
mapping["event"] = Event::Type(event);
|
||||
mapping["key"] = StellaKey(key);
|
||||
mapping["event"] = static_cast<Event::Type>(event);
|
||||
mapping["key"] = static_cast<StellaKey>(key);
|
||||
|
||||
if(StellaMod(mod) != StellaMod::KBDM_NONE)
|
||||
mapping["mod"] = serializeModkeyMask(StellaMod(mod));
|
||||
if(static_cast<StellaMod>(mod) != StellaMod::KBDM_NONE)
|
||||
mapping["mod"] = serializeModkeyMask(static_cast<StellaMod>(mod));
|
||||
|
||||
convertedMapping.push_back(mapping);
|
||||
}
|
||||
|
@ -314,7 +313,7 @@ json KeyMap::convertLegacyMapping(string list)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::eraseMode(const EventMode mode)
|
||||
void KeyMap::eraseMode(EventMode mode)
|
||||
{
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->first.mode == mode) {
|
||||
|
@ -325,7 +324,7 @@ void KeyMap::eraseMode(const EventMode mode)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::eraseEvent(const Event::Type event, const EventMode mode)
|
||||
void KeyMap::eraseEvent(Event::Type event, EventMode mode)
|
||||
{
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->second == event && item->first.mode == mode) {
|
||||
|
@ -336,7 +335,7 @@ void KeyMap::eraseEvent(const Event::Type event, const EventMode mode)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
KeyMap::Mapping KeyMap::convertMod(const Mapping& mapping) const
|
||||
KeyMap::Mapping KeyMap::convertMod(const Mapping& mapping)
|
||||
{
|
||||
Mapping m = mapping;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -42,6 +42,7 @@ class KeyMap
|
|||
: mode{c_mode}, key{c_key}, mod{c_mod} { }
|
||||
explicit Mapping(EventMode c_mode, int c_key, int c_mod)
|
||||
: mode{c_mode}, key{static_cast<StellaKey>(c_key)}, mod{static_cast<StellaMod>(c_mod)} { }
|
||||
~Mapping() = default;
|
||||
Mapping(const Mapping&) = default;
|
||||
Mapping& operator=(const Mapping&) = default;
|
||||
Mapping(Mapping&&) = default;
|
||||
|
@ -61,41 +62,42 @@ class KeyMap
|
|||
using MappingArray = std::vector<Mapping>;
|
||||
|
||||
KeyMap() = default;
|
||||
~KeyMap() = default;
|
||||
|
||||
/** Add new mapping for given event */
|
||||
void add(const Event::Type event, const Mapping& mapping);
|
||||
void add(const Event::Type event, const EventMode mode, const int key, const int mod);
|
||||
void add(Event::Type event, const Mapping& mapping);
|
||||
void add(Event::Type event, EventMode mode, int key, int mod);
|
||||
|
||||
/** Erase mapping */
|
||||
void erase(const Mapping& mapping);
|
||||
void erase(const EventMode mode, const int key, const int mod);
|
||||
void erase(EventMode mode, int key, int mod);
|
||||
|
||||
/** Get event for mapping */
|
||||
Event::Type get(const Mapping& mapping) const;
|
||||
Event::Type get(const EventMode mode, const int key, const int mod) const;
|
||||
Event::Type get(EventMode mode, int key, int mod) const;
|
||||
|
||||
/** Check if a mapping exists */
|
||||
bool check(const Mapping& mapping) const;
|
||||
bool check(const EventMode mode, const int key, const int mod) const;
|
||||
bool check(EventMode mode, int key, int mod) const;
|
||||
|
||||
/** Get mapping description */
|
||||
string getDesc(const Mapping& mapping) const;
|
||||
string getDesc(const EventMode mode, const int key, const int mod) const;
|
||||
static string getDesc(const Mapping& mapping);
|
||||
static string getDesc(EventMode mode, int key, int mod);
|
||||
|
||||
/** Get the mapping description(s) for given event and mode */
|
||||
string getEventMappingDesc(const Event::Type event, const EventMode mode) const;
|
||||
string getEventMappingDesc(Event::Type event, EventMode mode) const;
|
||||
|
||||
MappingArray getEventMapping(const Event::Type event, const EventMode mode) const;
|
||||
MappingArray getEventMapping(Event::Type event, EventMode mode) const;
|
||||
|
||||
nlohmann::json saveMapping(const EventMode mode) const;
|
||||
int loadMapping(const nlohmann::json& mapping, const EventMode mode);
|
||||
nlohmann::json saveMapping(EventMode mode) const;
|
||||
int loadMapping(const nlohmann::json& mapping, EventMode mode);
|
||||
|
||||
static nlohmann::json convertLegacyMapping(string list);
|
||||
static nlohmann::json convertLegacyMapping(string_view lm);
|
||||
|
||||
/** Erase all mappings for given mode */
|
||||
void eraseMode(const EventMode mode);
|
||||
void eraseMode(EventMode mode);
|
||||
/** Erase given event's mapping for given mode */
|
||||
void eraseEvent(const Event::Type event, const EventMode mode);
|
||||
void eraseEvent(Event::Type event, EventMode mode);
|
||||
/** clear all mappings for a modes */
|
||||
// void clear() { myMap.clear(); }
|
||||
size_t size() { return myMap.size(); }
|
||||
|
@ -104,16 +106,16 @@ class KeyMap
|
|||
|
||||
private:
|
||||
//** Convert modifiers */
|
||||
Mapping convertMod(const Mapping& mapping) const;
|
||||
static Mapping convertMod(const Mapping& mapping);
|
||||
|
||||
struct KeyHash {
|
||||
size_t operator()(const Mapping& m) const {
|
||||
return std::hash<uInt64>()((uInt64(m.mode)) // 3 bits
|
||||
+ ((uInt64(m.key)) * 7) // 8 bits
|
||||
+ (((uInt64((m.mod & KBDM_SHIFT) != 0) << 0)) // 1 bit
|
||||
| ((uInt64((m.mod & KBDM_ALT ) != 0) << 1)) // 1 bit
|
||||
| ((uInt64((m.mod & KBDM_GUI ) != 0) << 2)) // 1 bit
|
||||
| ((uInt64((m.mod & KBDM_CTRL ) != 0) << 3)) // 1 bit
|
||||
return std::hash<uInt64>()((static_cast<uInt64>(m.mode)) // 3 bits
|
||||
+ ((static_cast<uInt64>(m.key)) * 7) // 8 bits
|
||||
+ (((static_cast<uInt64>((m.mod & KBDM_SHIFT) != 0) << 0)) // 1 bit
|
||||
| ((static_cast<uInt64>((m.mod & KBDM_ALT ) != 0) << 1)) // 1 bit
|
||||
| ((static_cast<uInt64>((m.mod & KBDM_GUI ) != 0) << 2)) // 1 bit
|
||||
| ((static_cast<uInt64>((m.mod & KBDM_CTRL ) != 0) << 3)) // 1 bit
|
||||
) * 2047
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -59,7 +59,8 @@ class LinkedObjectPool
|
|||
/*
|
||||
Create a pool of size CAPACITY; the active list starts out empty.
|
||||
*/
|
||||
LinkedObjectPool<T, CAPACITY>() { resize(CAPACITY); }
|
||||
LinkedObjectPool() { resize(CAPACITY); }
|
||||
~LinkedObjectPool() = default;
|
||||
|
||||
/**
|
||||
Return node data that the 'current' iterator points to.
|
||||
|
@ -287,6 +288,6 @@ class LinkedObjectPool
|
|||
LinkedObjectPool& operator=(LinkedObjectPool&&) = delete;
|
||||
};
|
||||
|
||||
} // Namespace Common
|
||||
} // namespace Common
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -26,44 +26,46 @@ Logger& Logger::instance()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Logger::log(const string& message, Level level)
|
||||
void Logger::log(string_view message, Level level)
|
||||
{
|
||||
instance().logMessage(message, level);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Logger::error(const string& message)
|
||||
void Logger::error(string_view message)
|
||||
{
|
||||
instance().logMessage(message, Level::ERR);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Logger::info(const string& message)
|
||||
void Logger::info(string_view message)
|
||||
{
|
||||
instance().logMessage(message, Level::INFO);
|
||||
}
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Logger::debug(const string& message)
|
||||
void Logger::debug(string_view message)
|
||||
{
|
||||
instance().logMessage(message, Level::DEBUG);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Logger::logMessage(const string& message, Level level)
|
||||
void Logger::logMessage(string_view message, Level level)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
if(level == Logger::Level::ERR)
|
||||
{
|
||||
cout << message << endl << std::flush;
|
||||
myLogMessages += message + "\n";
|
||||
cout << message << '\n' << std::flush;
|
||||
myLogMessages += message;
|
||||
myLogMessages += "\n";
|
||||
}
|
||||
else if(static_cast<int>(level) <= myLogLevel ||
|
||||
level == Logger::Level::ALWAYS)
|
||||
{
|
||||
if(myLogToConsole)
|
||||
cout << message << endl << std::flush;
|
||||
myLogMessages += message + "\n";
|
||||
cout << message << '\n' << std::flush;
|
||||
myLogMessages += message;
|
||||
myLogMessages += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -27,7 +27,7 @@ class Logger {
|
|||
|
||||
public:
|
||||
|
||||
enum class Level {
|
||||
enum class Level: uInt8 {
|
||||
ERR = 0, // cannot use ERROR???
|
||||
INFO = 1,
|
||||
DEBUG = 2,
|
||||
|
@ -40,13 +40,13 @@ class Logger {
|
|||
|
||||
static Logger& instance();
|
||||
|
||||
static void log(const string& message, Level level = Level::ALWAYS);
|
||||
static void log(string_view message, Level level = Level::ALWAYS);
|
||||
|
||||
static void error(const string& message);
|
||||
static void error(string_view message);
|
||||
|
||||
static void info(const string& message);
|
||||
static void info(string_view message);
|
||||
|
||||
static void debug(const string& message);
|
||||
static void debug(string_view message);
|
||||
|
||||
void setLogParameters(int logLevel, bool logToConsole);
|
||||
void setLogParameters(Level logLevel, bool logToConsole);
|
||||
|
@ -55,6 +55,7 @@ class Logger {
|
|||
|
||||
protected:
|
||||
Logger() = default;
|
||||
~Logger() = default;
|
||||
|
||||
private:
|
||||
int myLogLevel{static_cast<int>(Level::MAX)};
|
||||
|
@ -66,7 +67,7 @@ class Logger {
|
|||
std::mutex mutex;
|
||||
|
||||
private:
|
||||
void logMessage(const string& message, Level level);
|
||||
void logMessage(string_view message, Level level);
|
||||
|
||||
Logger(const Logger&) = delete;
|
||||
Logger(Logger&&) = delete;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -181,6 +181,15 @@ class MediaFactory
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool supportsURL()
|
||||
{
|
||||
#if defined(SDL_SUPPORT)
|
||||
return SDLSupportsURL();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool openURL(const string& url)
|
||||
{
|
||||
#if defined(SDL_SUPPORT)
|
||||
|
@ -193,6 +202,7 @@ class MediaFactory
|
|||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
MediaFactory() = delete;
|
||||
~MediaFactory() = delete;
|
||||
MediaFactory(const MediaFactory&) = delete;
|
||||
MediaFactory(MediaFactory&&) = delete;
|
||||
MediaFactory& operator=(const MediaFactory&) = delete;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -23,12 +23,12 @@
|
|||
#include "MouseControl.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
MouseControl::MouseControl(Console& console, const string& mode)
|
||||
MouseControl::MouseControl(Console& console, string_view mode)
|
||||
: myProps{console.properties()},
|
||||
myLeftController{console.leftController()},
|
||||
myRightController{console.rightController()}
|
||||
{
|
||||
istringstream m_axis(mode);
|
||||
istringstream m_axis(string{mode}); // TODO: fixed in C++20
|
||||
string m_mode;
|
||||
m_axis >> m_mode;
|
||||
|
||||
|
@ -41,8 +41,10 @@ MouseControl::MouseControl(Console& console, const string& mode)
|
|||
m_mode[0] >= '0' && m_mode[0] <= '8' &&
|
||||
m_mode[1] >= '0' && m_mode[1] <= '8')
|
||||
{
|
||||
const MouseControl::Type xaxis = static_cast<MouseControl::Type>(static_cast<int>(m_mode[0]) - '0');
|
||||
const MouseControl::Type yaxis = static_cast<MouseControl::Type>(static_cast<int>(m_mode[1]) - '0');
|
||||
const auto xaxis = static_cast<MouseControl::Type>
|
||||
(static_cast<int>(m_mode[0]) - '0');
|
||||
const auto yaxis = static_cast<MouseControl::Type>
|
||||
(static_cast<int>(m_mode[1]) - '0');
|
||||
ostringstream msg;
|
||||
Controller::Type xtype = Controller::Type::Joystick, ytype = Controller::Type::Joystick;
|
||||
int xid = -1, yid = -1;
|
||||
|
@ -51,49 +53,52 @@ MouseControl::MouseControl(Console& console, const string& mode)
|
|||
Controller::Type& type, int& id) {
|
||||
switch(axis)
|
||||
{
|
||||
case MouseControl::Type::NoControl:
|
||||
using enum MouseControl::Type;
|
||||
case NoControl:
|
||||
msg << "not used";
|
||||
break;
|
||||
case MouseControl::Type::LeftPaddleA:
|
||||
case LeftPaddleA:
|
||||
type = Controller::Type::Paddles;
|
||||
id = 0;
|
||||
msg << "Left Paddle A";
|
||||
break;
|
||||
case MouseControl::Type::LeftPaddleB:
|
||||
case LeftPaddleB:
|
||||
type = Controller::Type::Paddles;
|
||||
id = 1;
|
||||
msg << "Left Paddle B";
|
||||
break;
|
||||
case MouseControl::Type::RightPaddleA:
|
||||
case RightPaddleA:
|
||||
type = Controller::Type::Paddles;
|
||||
id = 2;
|
||||
msg << "Right Paddle A";
|
||||
break;
|
||||
case MouseControl::Type::RightPaddleB:
|
||||
case RightPaddleB:
|
||||
type = Controller::Type::Paddles;
|
||||
id = 3;
|
||||
msg << "Right Paddle B";
|
||||
break;
|
||||
case MouseControl::Type::LeftDriving:
|
||||
case LeftDriving:
|
||||
type = Controller::Type::Driving;
|
||||
id = 0;
|
||||
msg << "Left Driving";
|
||||
break;
|
||||
case MouseControl::Type::RightDriving:
|
||||
case RightDriving:
|
||||
type = Controller::Type::Driving;
|
||||
id = 1;
|
||||
msg << "Right Driving";
|
||||
break;
|
||||
case MouseControl::Type::LeftMindLink:
|
||||
case LeftMindLink:
|
||||
type = Controller::Type::MindLink;
|
||||
id = 0;
|
||||
msg << "Left MindLink";
|
||||
break;
|
||||
case MouseControl::Type::RightMindLink:
|
||||
case RightMindLink:
|
||||
type = Controller::Type::MindLink;
|
||||
id = 1;
|
||||
msg << "Right MindLink";
|
||||
break;
|
||||
default:
|
||||
break; // Not supposed to get here
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -102,7 +107,7 @@ MouseControl::MouseControl(Console& console, const string& mode)
|
|||
msg << ", Y-axis is ";
|
||||
MControlToController(yaxis, ytype, yid);
|
||||
|
||||
myModeList.emplace_back(xtype, xid, ytype, yid, msg.str());
|
||||
myModeList.emplace_back(xtype, xid, ytype, yid, msg.view());
|
||||
}
|
||||
|
||||
// Now consider the possible modes for the mouse based on the left
|
||||
|
@ -127,12 +132,12 @@ MouseControl::MouseControl(Console& console, const string& mode)
|
|||
Paddles::setDigitalPaddleRange(m_range);
|
||||
|
||||
// If the mouse isn't used at all, we still need one item in the list
|
||||
if(myModeList.size() == 0)
|
||||
if(myModeList.empty())
|
||||
myModeList.emplace_back("Mouse not used for current controllers");
|
||||
|
||||
#if 0
|
||||
for(const auto& m: myModeList)
|
||||
cerr << m << endl;
|
||||
cerr << m << '\n';
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -167,9 +172,9 @@ void MouseControl::addLeftControllerModes(bool noswap)
|
|||
{
|
||||
ostringstream msg;
|
||||
msg << "Mouse is left " << myLeftController.name() << " controller";
|
||||
Controller::Type type = myLeftController.type();
|
||||
int id = noswap ? 0 : 1;
|
||||
myModeList.emplace_back(type, id, type, id, msg.str());
|
||||
const Controller::Type type = myLeftController.type();
|
||||
const int id = noswap ? 0 : 1;
|
||||
myModeList.emplace_back(type, id, type, id, msg.view());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,9 +193,9 @@ void MouseControl::addRightControllerModes(bool noswap)
|
|||
{
|
||||
ostringstream msg;
|
||||
msg << "Mouse is right " << myRightController.name() << " controller";
|
||||
Controller::Type type = myRightController.type();
|
||||
int id = noswap ? 1 : 0;
|
||||
myModeList.emplace_back(type, id, type, id, msg.str());
|
||||
const Controller::Type type = myRightController.type();
|
||||
const int id = noswap ? 1 : 0;
|
||||
myModeList.emplace_back(type, id, type, id, msg.view());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -201,11 +206,11 @@ void MouseControl::addPaddleModes(int lport, int rport, int lname, int rname)
|
|||
const Controller::Type type = Controller::Type::Paddles;
|
||||
ostringstream msg;
|
||||
msg << "Mouse is Paddle " << lname << " controller";
|
||||
const MouseMode mode0(type, lport, type, lport, msg.str());
|
||||
const MouseMode mode0(type, lport, type, lport, msg.view());
|
||||
|
||||
msg.str("");
|
||||
msg << "Mouse is Paddle " << rname << " controller";
|
||||
const MouseMode mode1(type, rport, type, rport, msg.str());
|
||||
const MouseMode mode1(type, rport, type, rport, msg.view());
|
||||
|
||||
if(BSPF::equalsIgnoreCase(myProps.get(PropType::Controller_SwapPaddles), "NO"))
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -19,9 +19,9 @@
|
|||
#define MOUSE_CONTROL_HXX
|
||||
|
||||
class Console;
|
||||
class Controller;
|
||||
class Properties;
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
|
@ -41,7 +41,7 @@ class MouseControl
|
|||
/**
|
||||
Enumeration of mouse axis control types
|
||||
*/
|
||||
enum class Type
|
||||
enum class Type: uInt8
|
||||
{
|
||||
LeftPaddleA = 0, LeftPaddleB, RightPaddleA, RightPaddleB,
|
||||
LeftDriving, RightDriving, LeftMindLink, RightMindLink,
|
||||
|
@ -55,7 +55,8 @@ class MouseControl
|
|||
@param console The console in use by the system
|
||||
@param mode Contains information about how to use the mouse axes/buttons
|
||||
*/
|
||||
MouseControl(Console& console, const string& mode);
|
||||
MouseControl(Console& console, string_view mode);
|
||||
~MouseControl() = default;
|
||||
|
||||
/**
|
||||
Cycle through each available mouse control mode
|
||||
|
@ -73,7 +74,7 @@ class MouseControl
|
|||
void addLeftControllerModes(bool noswap);
|
||||
void addRightControllerModes(bool noswap);
|
||||
void addPaddleModes(int lport, int rport, int lname, int rname);
|
||||
bool controllerSupportsMouse(Controller& controller);
|
||||
static bool controllerSupportsMouse(Controller& controller);
|
||||
|
||||
private:
|
||||
const Properties& myProps;
|
||||
|
@ -85,10 +86,10 @@ class MouseControl
|
|||
int xid{-1}, yid{-1};
|
||||
string message;
|
||||
|
||||
explicit MouseMode(const string& msg = "") : message{msg} { }
|
||||
explicit MouseMode(string_view msg = "") : message{msg} { }
|
||||
MouseMode(Controller::Type xt, int xi,
|
||||
Controller::Type yt, int yi,
|
||||
const string& msg)
|
||||
string_view msg)
|
||||
: xtype{xt}, ytype{yt}, xid{xi}, yid{yi}, message{msg} { }
|
||||
|
||||
friend ostream& operator<<(ostream& os, const MouseMode& mm)
|
||||
|
|
|
@ -8,19 +8,16 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "Logger.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "Joystick.hxx"
|
||||
#include "Paddles.hxx"
|
||||
#include "MindLink.hxx"
|
||||
#include "PointingDevice.hxx"
|
||||
#include "Driving.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
@ -48,7 +45,7 @@ PhysicalJoystickHandler::PhysicalJoystickHandler(
|
|||
}
|
||||
|
||||
json mappings;
|
||||
const string& serializedMapping = myOSystem.settings().getString("joymap");
|
||||
const string_view serializedMapping = myOSystem.settings().getString("joymap");
|
||||
|
||||
try {
|
||||
mappings = json::parse(serializedMapping);
|
||||
|
@ -69,11 +66,11 @@ PhysicalJoystickHandler::PhysicalJoystickHandler(
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json PhysicalJoystickHandler::convertLegacyMapping(const string& mapping)
|
||||
json PhysicalJoystickHandler::convertLegacyMapping(string_view mapping)
|
||||
{
|
||||
constexpr char CTRL_DELIM = '^';
|
||||
|
||||
istringstream buf(mapping);
|
||||
istringstream buf(string{mapping}); // TODO: fixed in C++20
|
||||
string joymap, joyname;
|
||||
|
||||
getline(buf, joymap, CTRL_DELIM); // event list size, ignore
|
||||
|
@ -120,7 +117,7 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
|
|||
{
|
||||
ostringstream name;
|
||||
name << stick->name << " #" << count+1;
|
||||
stick->name = name.str();
|
||||
stick->name = name.view();
|
||||
}
|
||||
stick->type = PhysicalJoystick::Type::REGULAR;
|
||||
}
|
||||
|
@ -149,11 +146,9 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
|
|||
// We're potentially swapping out an input device behind the back of
|
||||
// the Event system, so we make sure all Stelladaptor-generated events
|
||||
// are reset
|
||||
for(int port = 0; port < NUM_PORTS; ++port)
|
||||
{
|
||||
for(int axis = 0; axis < NUM_SA_AXIS; ++axis)
|
||||
for(int port = 0; port < NUM_PORTS; ++port) // NOLINT
|
||||
for(int axis = 0; axis < NUM_SA_AXIS; ++axis) // NOLINT
|
||||
myEvent.set(SA_Axis[port][axis], 0);
|
||||
}
|
||||
|
||||
return stick->ID;
|
||||
}
|
||||
|
@ -171,16 +166,16 @@ void PhysicalJoystickHandler::addToDatabase(const PhysicalJoystickPtr& stick)
|
|||
}
|
||||
else // adding for the first time
|
||||
{
|
||||
StickInfo info("", stick);
|
||||
const StickInfo info("", stick);
|
||||
myDatabase.emplace(stick->name, info);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kMenuMode);
|
||||
setStickDefaultMapping(stick->ID, Event::NoType, EventMode::kEmulationMode);
|
||||
}
|
||||
|
||||
ostringstream buf;
|
||||
buf << "Added joystick " << stick->ID << ":" << endl
|
||||
<< " " << stick->about() << endl;
|
||||
Logger::info(buf.str());
|
||||
buf << "Added joystick " << stick->ID << ":\n"
|
||||
<< " " << stick->about() << '\n';
|
||||
Logger::info(buf.view());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -193,15 +188,15 @@ bool PhysicalJoystickHandler::remove(int id)
|
|||
// So we use the 'active' joystick list to access them
|
||||
try
|
||||
{
|
||||
PhysicalJoystickPtr stick = mySticks.at(id);
|
||||
const PhysicalJoystickPtr stick = mySticks.at(id);
|
||||
|
||||
const auto it = myDatabase.find(stick->name);
|
||||
if(it != myDatabase.end() && it->second.joy == stick)
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << "Removed joystick " << mySticks[id]->ID << ":" << endl
|
||||
<< " " << mySticks[id]->about() << endl;
|
||||
Logger::info(buf.str());
|
||||
buf << "Removed joystick " << mySticks[id]->ID << ":\n"
|
||||
<< " " << mySticks[id]->about() << '\n';
|
||||
Logger::info(buf.view());
|
||||
|
||||
// Remove joystick, but remember mapping
|
||||
it->second.mapping = stick->getMap();
|
||||
|
@ -213,14 +208,13 @@ bool PhysicalJoystickHandler::remove(int id)
|
|||
}
|
||||
catch(const std::out_of_range&)
|
||||
{
|
||||
// fall through to indicate remove failed
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::remove(const string& name)
|
||||
bool PhysicalJoystickHandler::remove(string_view name)
|
||||
{
|
||||
const auto it = myDatabase.find(name);
|
||||
if(it != myDatabase.end() && it->second.joy == nullptr)
|
||||
|
@ -232,7 +226,18 @@ bool PhysicalJoystickHandler::remove(const string& name)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::mapStelladaptors(const string& saport, int ID)
|
||||
void PhysicalJoystickHandler::setPort(string_view name, PhysicalJoystick::Port port)
|
||||
{
|
||||
const auto it = myDatabase.find(name);
|
||||
if(it != myDatabase.end() && it->second.joy != nullptr)
|
||||
{
|
||||
it->second.joy->setPort(port);
|
||||
// TODO: update mappings
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::mapStelladaptors(string_view saport, int ID)
|
||||
{
|
||||
bool erased = false;
|
||||
// saport will have two values:
|
||||
|
@ -257,9 +262,9 @@ bool PhysicalJoystickHandler::mapStelladaptors(const string& saport, int ID)
|
|||
{
|
||||
// Erase a previously added Stelladapter with a higher ID
|
||||
ostringstream buf;
|
||||
buf << "Erased joystick " << _stick->ID << ":" << endl
|
||||
<< " " << _stick->about() << endl;
|
||||
Logger::info(buf.str());
|
||||
buf << "Erased joystick " << _stick->ID << ":\n"
|
||||
<< " " << _stick->about() << '\n';
|
||||
Logger::info(buf.view());
|
||||
|
||||
_stick->name.erase(pos);
|
||||
erased = true;
|
||||
|
@ -300,7 +305,7 @@ bool PhysicalJoystickHandler::mapStelladaptors(const string& saport, int ID)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::hasStelladaptors() const
|
||||
{
|
||||
for(auto& [_id, _joyptr] : mySticks)
|
||||
for(const auto& [_id, _joyptr] : mySticks)
|
||||
{
|
||||
// remove previously added emulated ports
|
||||
const size_t pos = _joyptr->name.find(" (emulates ");
|
||||
|
@ -321,8 +326,7 @@ bool PhysicalJoystickHandler::hasStelladaptors() const
|
|||
// 2. reset all events to default (event == Event::NoType, updateDefault == false)
|
||||
// 3. reset one event to default (event != Event::NoType)
|
||||
void PhysicalJoystickHandler::setDefaultAction(int stick,
|
||||
EventMapping map, Event::Type event,
|
||||
EventMode mode, bool updateDefaults)
|
||||
EventMapping map, Event::Type event, EventMode mode, bool updateDefaults)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
|
||||
|
@ -334,7 +338,7 @@ void PhysicalJoystickHandler::setDefaultAction(int stick,
|
|||
{
|
||||
// if there is no existing mapping for the event and
|
||||
// the default mapping for the event is unused, set default key for event
|
||||
if(j->joyMap.getEventMapping(map.event, mode).size() == 0 &&
|
||||
if(j->joyMap.getEventMapping(map.event, mode).empty() &&
|
||||
!j->joyMap.check(mode, map.button, map.axis, map.adir, map.hat, map.hdir))
|
||||
{
|
||||
if (map.hat == JOY_CTRL_NONE)
|
||||
|
@ -355,50 +359,57 @@ void PhysicalJoystickHandler::setDefaultAction(int stick,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type event,
|
||||
EventMode mode, bool updateDefaults)
|
||||
void PhysicalJoystickHandler::setStickDefaultMapping(
|
||||
int stick, Event::Type event, EventMode mode, bool updateDefaults)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
|
||||
if(j)
|
||||
{
|
||||
switch (mode)
|
||||
switch(mode)
|
||||
{
|
||||
case EventMode::kEmulationMode:
|
||||
{
|
||||
// A regular joystick defaults to left or right based on the
|
||||
// stick number being even or odd; 'daptor joysticks request a
|
||||
// specific port
|
||||
const bool useLeftMappings =
|
||||
j->type == PhysicalJoystick::Type::REGULAR ? ((stick % 2) == 0) :
|
||||
(j->type == PhysicalJoystick::Type::LEFT_STELLADAPTOR ||
|
||||
j->type == PhysicalJoystick::Type::LEFT_2600DAPTOR);
|
||||
// A regular joystick defaults to left or right based on
|
||||
// the defined port or stick number being even or odd;
|
||||
// 'daptor' joysticks request a specific port
|
||||
bool useLeftMappings = true;
|
||||
if(j->type == PhysicalJoystick::Type::REGULAR)
|
||||
{
|
||||
useLeftMappings = j->port == PhysicalJoystick::Port::LEFT
|
||||
|| (j->port == PhysicalJoystick::Port::AUTO && (stick % 2) == 0);
|
||||
}
|
||||
else
|
||||
useLeftMappings =
|
||||
j->type == PhysicalJoystick::Type::LEFT_STELLADAPTOR ||
|
||||
j->type == PhysicalJoystick::Type::LEFT_2600DAPTOR;
|
||||
|
||||
if(useLeftMappings)
|
||||
{
|
||||
// put all controller events into their own mode's mappings
|
||||
for (const auto& item : DefaultLeftJoystickMapping)
|
||||
for(const auto& item : DefaultLeftJoystickMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults);
|
||||
for (const auto& item : DefaultLeftKeyboardMapping)
|
||||
for(const auto& item : DefaultLeftKeyboardMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults);
|
||||
for (const auto& item : DefaultLeftDrivingMapping)
|
||||
for(const auto& item : DefaultLeftDrivingMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kDrivingMode, updateDefaults);
|
||||
}
|
||||
else
|
||||
{
|
||||
// put all controller events into their own mode's mappings
|
||||
for (const auto& item : DefaultRightJoystickMapping)
|
||||
for(const auto& item : DefaultRightJoystickMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults);
|
||||
for (const auto& item : DefaultRightKeyboardMapping)
|
||||
for(const auto& item : DefaultRightKeyboardMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults);
|
||||
for (const auto& item : DefaultRightDrivingMapping)
|
||||
for(const auto& item : DefaultRightDrivingMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kDrivingMode, updateDefaults);
|
||||
}
|
||||
|
||||
#if defined(RETRON77)
|
||||
#if defined(RETRON77)
|
||||
constexpr bool retron77 = true;
|
||||
#else
|
||||
#else
|
||||
constexpr bool retron77 = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Regular joysticks can only be used by one player at a time,
|
||||
// so we need to separate the paddles onto different
|
||||
|
@ -407,16 +418,16 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
|
|||
// and 2600-daptors support two players natively.
|
||||
const int paddlesPerJoystick = (j->type == PhysicalJoystick::Type::REGULAR && !retron77) ? 1 : 2;
|
||||
|
||||
if( paddlesPerJoystick == 2 )
|
||||
if(paddlesPerJoystick == 2)
|
||||
{
|
||||
if( useLeftMappings )
|
||||
if(useLeftMappings)
|
||||
{
|
||||
for (const auto& item : DefaultLeftPaddlesMapping)
|
||||
for(const auto& item : DefaultLeftPaddlesMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& item : DefaultRightPaddlesMapping)
|
||||
for(const auto& item : DefaultRightPaddlesMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
|
||||
}
|
||||
}
|
||||
|
@ -433,29 +444,29 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
|
|||
const bool useLeftPaddleMappings = (stick % 4) < 2;
|
||||
const bool useAPaddleMappings = (stick % 2) == 0;
|
||||
|
||||
if( useLeftPaddleMappings )
|
||||
if(useLeftPaddleMappings)
|
||||
{
|
||||
if( useAPaddleMappings )
|
||||
if(useAPaddleMappings)
|
||||
{
|
||||
for (const auto& item : DefaultLeftAPaddlesMapping)
|
||||
for(const auto& item : DefaultLeftAPaddlesMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& item : DefaultLeftBPaddlesMapping)
|
||||
for(const auto& item : DefaultLeftBPaddlesMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( useAPaddleMappings )
|
||||
if(useAPaddleMappings)
|
||||
{
|
||||
for (const auto& item : DefaultRightAPaddlesMapping)
|
||||
for(const auto& item : DefaultRightAPaddlesMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& item : DefaultRightBPaddlesMapping)
|
||||
for(const auto& item : DefaultRightBPaddlesMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults);
|
||||
}
|
||||
}
|
||||
|
@ -469,7 +480,7 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
|
|||
}
|
||||
|
||||
case EventMode::kMenuMode:
|
||||
for (const auto& item : DefaultMenuMapping)
|
||||
for(const auto& item : DefaultMenuMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kMenuMode, updateDefaults);
|
||||
break;
|
||||
|
||||
|
@ -488,45 +499,71 @@ void PhysicalJoystickHandler::setDefaultMapping(Event::Type event, EventMode mod
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::defineControllerMappings(const Controller::Type type, Controller::Jack port)
|
||||
void PhysicalJoystickHandler::defineControllerMappings(
|
||||
Controller::Type type, Controller::Jack port, const Properties& properties,
|
||||
Controller::Type qtType1, Controller::Type qtType2)
|
||||
{
|
||||
// Determine controller events to use
|
||||
if(type == Controller::Type::QuadTari)
|
||||
{
|
||||
if(port == Controller::Jack::Left)
|
||||
{
|
||||
myLeftMode = getMode(qtType1);
|
||||
myLeft2ndMode = getMode(qtType2);
|
||||
}
|
||||
else
|
||||
{
|
||||
myRightMode = getMode(qtType1);
|
||||
myRight2ndMode = getMode(qtType2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const EventMode mode = getMode(type);
|
||||
|
||||
if(port == Controller::Jack::Left)
|
||||
myLeftMode = mode;
|
||||
else
|
||||
myRightMode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventMode PhysicalJoystickHandler::getMode(const Properties& properties,
|
||||
PropType propType)
|
||||
{
|
||||
const string& propName = properties.get(propType);
|
||||
|
||||
if(!propName.empty())
|
||||
return getMode(Controller::getType(propName));
|
||||
|
||||
return EventMode::kJoystickMode;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventMode PhysicalJoystickHandler::getMode(Controller::Type type)
|
||||
{
|
||||
// determine controller events to use
|
||||
switch(type)
|
||||
{
|
||||
case Controller::Type::Keyboard:
|
||||
case Controller::Type::KidVid:
|
||||
if(port == Controller::Jack::Left)
|
||||
myLeftMode = EventMode::kKeyboardMode;
|
||||
else
|
||||
myRightMode = EventMode::kKeyboardMode;
|
||||
break;
|
||||
using enum Controller::Type;
|
||||
case Keyboard:
|
||||
case KidVid:
|
||||
return EventMode::kKeyboardMode;
|
||||
|
||||
case Controller::Type::Paddles:
|
||||
case Controller::Type::PaddlesIAxDr:
|
||||
case Controller::Type::PaddlesIAxis:
|
||||
if(port == Controller::Jack::Left)
|
||||
myLeftMode = EventMode::kPaddlesMode;
|
||||
else
|
||||
myRightMode = EventMode::kPaddlesMode;
|
||||
break;
|
||||
case Paddles:
|
||||
case PaddlesIAxDr:
|
||||
case PaddlesIAxis:
|
||||
return EventMode::kPaddlesMode;
|
||||
|
||||
case Controller::Type::CompuMate:
|
||||
myLeftMode = myRightMode = EventMode::kCompuMateMode;
|
||||
break;
|
||||
case CompuMate:
|
||||
return EventMode::kCompuMateMode;
|
||||
|
||||
case Controller::Type::Driving:
|
||||
if(port == Controller::Jack::Left)
|
||||
myLeftMode = EventMode::kDrivingMode;
|
||||
else
|
||||
myRightMode = EventMode::kDrivingMode;
|
||||
break;
|
||||
case Driving:
|
||||
return EventMode::kDrivingMode;
|
||||
|
||||
default:
|
||||
// let's use joystick then
|
||||
if(port == Controller::Jack::Left)
|
||||
myLeftMode = EventMode::kJoystickMode;
|
||||
else
|
||||
myRightMode = EventMode::kJoystickMode;
|
||||
return EventMode::kJoystickMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,8 +580,38 @@ void PhysicalJoystickHandler::enableEmulationMappings()
|
|||
|
||||
enableCommonMappings();
|
||||
|
||||
// Process in increasing priority order, so that in case of mapping clashes
|
||||
// the higher priority controller has preference
|
||||
switch(myRight2ndMode)
|
||||
{
|
||||
case EventMode::kPaddlesMode:
|
||||
enableMappings(QTPaddles4Events, EventMode::kPaddlesMode);
|
||||
break;
|
||||
|
||||
case EventMode::kEmulationMode: // no QuadTari
|
||||
break;
|
||||
|
||||
default:
|
||||
enableMappings(QTJoystick4Events, EventMode::kJoystickMode);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(myLeft2ndMode)
|
||||
{
|
||||
case EventMode::kPaddlesMode:
|
||||
enableMappings(QTPaddles3Events, EventMode::kPaddlesMode);
|
||||
break;
|
||||
|
||||
case EventMode::kEmulationMode: // no QuadTari
|
||||
break;
|
||||
|
||||
default:
|
||||
enableMappings(QTJoystick3Events, EventMode::kJoystickMode);
|
||||
break;
|
||||
}
|
||||
|
||||
// enable right mode first, so that in case of mapping clashes the left controller has preference
|
||||
switch (myRightMode)
|
||||
switch(myRightMode)
|
||||
{
|
||||
case EventMode::kPaddlesMode:
|
||||
enableMappings(RightPaddlesEvents, EventMode::kPaddlesMode);
|
||||
|
@ -563,7 +630,7 @@ void PhysicalJoystickHandler::enableEmulationMappings()
|
|||
break;
|
||||
}
|
||||
|
||||
switch (myLeftMode)
|
||||
switch(myLeftMode)
|
||||
{
|
||||
case EventMode::kPaddlesMode:
|
||||
enableMappings(LeftPaddlesEvents, EventMode::kPaddlesMode);
|
||||
|
@ -588,7 +655,7 @@ void PhysicalJoystickHandler::enableCommonMappings()
|
|||
{
|
||||
for (int i = Event::NoType + 1; i < Event::LastType; i++)
|
||||
{
|
||||
const Event::Type event = static_cast<Event::Type>(i);
|
||||
const auto event = static_cast<Event::Type>(i);
|
||||
|
||||
if(isCommonEvent(event))
|
||||
enableMapping(event, EventMode::kCommonMode);
|
||||
|
@ -603,14 +670,14 @@ void PhysicalJoystickHandler::enableMappings(const Event::EventSet& events, Even
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::enableMapping(const Event::Type event, EventMode mode)
|
||||
void PhysicalJoystickHandler::enableMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
// copy from controller mode into emulation mode
|
||||
for (auto& stick : mySticks)
|
||||
{
|
||||
const PhysicalJoystickPtr j = stick.second;
|
||||
|
||||
JoyMap::JoyMappingArray joyMappings = j->joyMap.getEventMapping(event, mode);
|
||||
const JoyMap::JoyMappingArray joyMappings = j->joyMap.getEventMapping(event, mode);
|
||||
|
||||
for (const auto& mapping : joyMappings)
|
||||
j->joyMap.add(event, EventMode::kEmulationMode, mapping.button,
|
||||
|
@ -619,7 +686,7 @@ void PhysicalJoystickHandler::enableMapping(const Event::Type event, EventMode m
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventMode PhysicalJoystickHandler::getEventMode(const Event::Type event, const EventMode mode) const
|
||||
EventMode PhysicalJoystickHandler::getEventMode(Event::Type event, EventMode mode)
|
||||
{
|
||||
if(mode == EventMode::kEmulationMode)
|
||||
{
|
||||
|
@ -643,37 +710,42 @@ EventMode PhysicalJoystickHandler::getEventMode(const Event::Type event, const E
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::isJoystickEvent(const Event::Type event) const
|
||||
bool PhysicalJoystickHandler::isJoystickEvent(Event::Type event)
|
||||
{
|
||||
return LeftJoystickEvents.find(event) != LeftJoystickEvents.end()
|
||||
|| RightJoystickEvents.find(event) != RightJoystickEvents.end();
|
||||
return LeftJoystickEvents.contains(event)
|
||||
|| QTJoystick3Events.contains(event)
|
||||
|| RightJoystickEvents.contains(event)
|
||||
|| QTJoystick4Events.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::isPaddleEvent(const Event::Type event) const
|
||||
bool PhysicalJoystickHandler::isPaddleEvent(Event::Type event)
|
||||
{
|
||||
return LeftPaddlesEvents.find(event) != LeftPaddlesEvents.end()
|
||||
|| RightPaddlesEvents.find(event) != RightPaddlesEvents.end();
|
||||
return LeftPaddlesEvents.contains(event)
|
||||
|| QTPaddles3Events.contains(event)
|
||||
|| RightPaddlesEvents.contains(event)
|
||||
|| QTPaddles4Events.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::isKeyboardEvent(const Event::Type event) const
|
||||
bool PhysicalJoystickHandler::isKeyboardEvent(Event::Type event)
|
||||
{
|
||||
return LeftKeyboardEvents.find(event) != LeftKeyboardEvents.end()
|
||||
|| RightKeyboardEvents.find(event) != RightKeyboardEvents.end();
|
||||
return LeftKeyboardEvents.contains(event)
|
||||
|| RightKeyboardEvents.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::isDrivingEvent(const Event::Type event) const
|
||||
bool PhysicalJoystickHandler::isDrivingEvent(Event::Type event)
|
||||
{
|
||||
return LeftDrivingEvents.find(event) != LeftDrivingEvents.end()
|
||||
|| RightDrivingEvents.find(event) != RightDrivingEvents.end();
|
||||
return LeftDrivingEvents.contains(event)
|
||||
|| RightDrivingEvents.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::isCommonEvent(const Event::Type event) const
|
||||
bool PhysicalJoystickHandler::isCommonEvent(Event::Type event)
|
||||
{
|
||||
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeyboardEvent(event) || isDrivingEvent(event));
|
||||
return !(isJoystickEvent(event) || isPaddleEvent(event)
|
||||
|| isKeyboardEvent(event) || isDrivingEvent(event));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -715,7 +787,7 @@ void PhysicalJoystickHandler::saveMapping()
|
|||
|
||||
for(const auto& [_name, _info]: myDatabase)
|
||||
{
|
||||
json map = _info.joy ? _info.joy->getMap() : _info.mapping;
|
||||
const json map = _info.joy ? _info.joy->getMap() : _info.mapping;
|
||||
|
||||
if (!map.is_null()) mapping.emplace_back(map);
|
||||
}
|
||||
|
@ -734,9 +806,9 @@ string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode
|
|||
if(_joyptr)
|
||||
{
|
||||
//Joystick mapping / labeling
|
||||
if(_joyptr->joyMap.getEventMapping(event, evMode).size())
|
||||
if(!_joyptr->joyMap.getEventMapping(event, evMode).empty())
|
||||
{
|
||||
if(buf.str() != "")
|
||||
if(!buf.view().empty())
|
||||
buf << ", ";
|
||||
buf << _joyptr->joyMap.getEventMappingDesc(_id, event, evMode);
|
||||
}
|
||||
|
@ -746,8 +818,8 @@ string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode, int stick,
|
||||
int button, JoyAxis axis, JoyDir adir)
|
||||
bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode,
|
||||
int stick, int button, JoyAxis axis, JoyDir adir)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
|
||||
|
@ -787,8 +859,8 @@ bool PhysicalJoystickHandler::addJoyMapping(Event::Type event, EventMode mode, i
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::addJoyHatMapping(Event::Type event, EventMode mode, int stick,
|
||||
int button, int hat, JoyHatDir hdir)
|
||||
bool PhysicalJoystickHandler::addJoyHatMapping(Event::Type event, EventMode mode,
|
||||
int stick, int button, int hat, JoyHatDir hdir)
|
||||
{
|
||||
const PhysicalJoystickPtr j = joy(stick);
|
||||
|
||||
|
@ -829,17 +901,18 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
|
|||
|
||||
if(j)
|
||||
{
|
||||
//int button = j->buttonLast[stick];
|
||||
//int button = j->buttonLast;
|
||||
|
||||
switch(j->type)
|
||||
{
|
||||
using enum PhysicalJoystick::Type;
|
||||
// Since the various controller classes deal with Stelladaptor
|
||||
// devices differently, we send the raw X and Y axis data directly,
|
||||
// and let the controller handle it
|
||||
// These events don't have to pass through handleEvent, since
|
||||
// they can never be remapped
|
||||
case PhysicalJoystick::Type::LEFT_STELLADAPTOR:
|
||||
case PhysicalJoystick::Type::LEFT_2600DAPTOR:
|
||||
case LEFT_STELLADAPTOR:
|
||||
case LEFT_2600DAPTOR:
|
||||
if(myOSystem.hasConsole()
|
||||
&& myOSystem.console().leftController().type() == Controller::Type::Driving)
|
||||
{
|
||||
|
@ -850,8 +923,8 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
|
|||
handleRegularAxisEvent(j, stick, axis, value);
|
||||
break; // axis on left controller (0)
|
||||
|
||||
case PhysicalJoystick::Type::RIGHT_STELLADAPTOR:
|
||||
case PhysicalJoystick::Type::RIGHT_2600DAPTOR:
|
||||
case RIGHT_STELLADAPTOR:
|
||||
case RIGHT_2600DAPTOR:
|
||||
if(myOSystem.hasConsole()
|
||||
&& myOSystem.console().rightController().type() == Controller::Type::Driving)
|
||||
{
|
||||
|
@ -872,7 +945,7 @@ void PhysicalJoystickHandler::handleAxisEvent(int stick, int axis, int value)
|
|||
void PhysicalJoystickHandler::handleRegularAxisEvent(const PhysicalJoystickPtr& j,
|
||||
int stick, int axis, int value)
|
||||
{
|
||||
const int button = j->buttonLast[stick];
|
||||
const int button = j->buttonLast;
|
||||
|
||||
if(myHandler.state() == EventHandlerState::EMULATION)
|
||||
{
|
||||
|
@ -952,7 +1025,7 @@ void PhysicalJoystickHandler::handleBtnEvent(int stick, int button, bool pressed
|
|||
|
||||
if(j)
|
||||
{
|
||||
j->buttonLast[stick] = pressed ? button : JOY_CTRL_NONE;
|
||||
j->buttonLast = pressed ? button : JOY_CTRL_NONE;
|
||||
|
||||
// Handle buttons which switch eventhandler state
|
||||
if(!pressed && myHandler.changeStateByEvent(j->joyMap.get(EventMode::kEmulationMode, button)))
|
||||
|
@ -979,7 +1052,7 @@ void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value)
|
|||
|
||||
if(j)
|
||||
{
|
||||
const int button = j->buttonLast[stick];
|
||||
const int button = j->buttonLast;
|
||||
|
||||
if(myHandler.state() == EventHandlerState::EMULATION)
|
||||
{
|
||||
|
@ -1014,29 +1087,35 @@ void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
VariantList PhysicalJoystickHandler::database() const
|
||||
PhysicalJoystickHandler::MinStrickInfoList PhysicalJoystickHandler::minStickList() const
|
||||
{
|
||||
VariantList db;
|
||||
for(const auto& [_name, _info]: myDatabase)
|
||||
VarList::push_back(db, _name, _info.joy ? _info.joy->ID : -1);
|
||||
MinStrickInfoList list;
|
||||
|
||||
return db;
|
||||
for(const auto& [_name, _info] : myDatabase)
|
||||
{
|
||||
const MinStrickInfo stick(_name,
|
||||
_info.joy ? _info.joy->ID : -1,
|
||||
_info.joy ? _info.joy->port : PhysicalJoystick::Port::AUTO);
|
||||
|
||||
list.push_back(stick);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh)
|
||||
{
|
||||
os << "---------------------------------------------------------" << endl
|
||||
<< "joy database:" << endl;
|
||||
os << "---------------------------------------------------------\n"
|
||||
<< "joy database:\n";
|
||||
for(const auto& [_name, _info]: jh.myDatabase)
|
||||
os << _name << endl << _info << endl << endl;
|
||||
os << _name << '\n' << _info << "\n\n";
|
||||
|
||||
os << "---------------------" << endl
|
||||
<< "joy active:" << endl;
|
||||
os << "---------------------\n"
|
||||
<< "joy active:\n";
|
||||
for(const auto& [_id, _joyptr]: jh.mySticks)
|
||||
os << _id << ": " << *_joyptr << endl;
|
||||
os << _id << ": " << *_joyptr << '\n';
|
||||
os << "---------------------------------------------------------"
|
||||
<< endl << endl << endl;
|
||||
<< "\n\n\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
@ -1044,8 +1123,9 @@ ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeDigitalDeadZone(int direction)
|
||||
{
|
||||
int deadZone = BSPF::clamp(myOSystem.settings().getInt("joydeadzone") + direction,
|
||||
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
|
||||
const int deadZone =
|
||||
BSPF::clamp(myOSystem.settings().getInt("joydeadzone") + direction,
|
||||
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
|
||||
myOSystem.settings().setValue("joydeadzone", deadZone);
|
||||
|
||||
Controller::setDigitalDeadZone(deadZone);
|
||||
|
@ -1053,15 +1133,17 @@ void PhysicalJoystickHandler::changeDigitalDeadZone(int direction)
|
|||
ostringstream ss;
|
||||
ss << std::round(Controller::digitalDeadZoneValue(deadZone) * 100.F / 32768) << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Digital controller dead zone", ss. str(), deadZone,
|
||||
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Digital controller dead zone", ss.view(), deadZone,
|
||||
Controller::MIN_DIGITAL_DEADZONE, Controller::MAX_DIGITAL_DEADZONE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeAnalogPaddleDeadZone(int direction)
|
||||
{
|
||||
int deadZone = BSPF::clamp(myOSystem.settings().getInt("adeadzone") + direction,
|
||||
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
|
||||
const int deadZone =
|
||||
BSPF::clamp(myOSystem.settings().getInt("adeadzone") + direction,
|
||||
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
|
||||
myOSystem.settings().setValue("adeadzone", deadZone);
|
||||
|
||||
Controller::setAnalogDeadZone(deadZone);
|
||||
|
@ -1069,15 +1151,17 @@ void PhysicalJoystickHandler::changeAnalogPaddleDeadZone(int direction)
|
|||
ostringstream ss;
|
||||
ss << std::round(Controller::analogDeadZoneValue(deadZone) * 100.F / 32768) << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog controller dead zone", ss.str(), deadZone,
|
||||
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Analog controller dead zone", ss.view(), deadZone,
|
||||
Controller::MIN_ANALOG_DEADZONE, Controller::MAX_ANALOG_DEADZONE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeAnalogPaddleSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("psense") + direction,
|
||||
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
|
||||
const int sense =
|
||||
BSPF::clamp(myOSystem.settings().getInt("psense") + direction,
|
||||
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
|
||||
myOSystem.settings().setValue("psense", sense);
|
||||
|
||||
Paddles::setAnalogSensitivity(sense);
|
||||
|
@ -1085,15 +1169,17 @@ void PhysicalJoystickHandler::changeAnalogPaddleSensitivity(int direction)
|
|||
ostringstream ss;
|
||||
ss << std::round(Paddles::analogSensitivityValue(sense) * 100.F) << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog paddle sensitivity", ss.str(), sense,
|
||||
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Analog paddle sensitivity", ss.view(), sense,
|
||||
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeAnalogPaddleLinearity(int direction)
|
||||
{
|
||||
int linear = BSPF::clamp(myOSystem.settings().getInt("plinear") + direction * 5,
|
||||
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
|
||||
const int linear =
|
||||
BSPF::clamp(myOSystem.settings().getInt("plinear") + direction * 5,
|
||||
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
|
||||
myOSystem.settings().setValue("plinear", linear);
|
||||
|
||||
Paddles::setAnalogLinearity(linear);
|
||||
|
@ -1104,15 +1190,17 @@ void PhysicalJoystickHandler::changeAnalogPaddleLinearity(int direction)
|
|||
else
|
||||
ss << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog paddle linearity", ss.str(), linear,
|
||||
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Analog paddle linearity", ss.view(), linear,
|
||||
Paddles::MIN_ANALOG_LINEARITY, Paddles::MAX_ANALOG_LINEARITY);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changePaddleDejitterAveraging(int direction)
|
||||
{
|
||||
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.base") + direction,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
const int dejitter =
|
||||
BSPF::clamp(myOSystem.settings().getInt("dejitter.base") + direction,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
myOSystem.settings().setValue("dejitter.base", dejitter);
|
||||
|
||||
Paddles::setDejitterBase(dejitter);
|
||||
|
@ -1123,16 +1211,17 @@ void PhysicalJoystickHandler::changePaddleDejitterAveraging(int direction)
|
|||
else
|
||||
ss << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter averaging",
|
||||
ss.str(), dejitter,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Analog paddle dejitter averaging", ss.view(), dejitter,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changePaddleDejitterReaction(int direction)
|
||||
{
|
||||
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.diff") + direction,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
const int dejitter =
|
||||
BSPF::clamp(myOSystem.settings().getInt("dejitter.diff") + direction,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
myOSystem.settings().setValue("dejitter.diff", dejitter);
|
||||
|
||||
Paddles::setDejitterDiff(dejitter);
|
||||
|
@ -1143,16 +1232,17 @@ void PhysicalJoystickHandler::changePaddleDejitterReaction(int direction)
|
|||
else
|
||||
ss << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter reaction",
|
||||
ss.str(), dejitter,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Analog paddle dejitter reaction", ss.view(), dejitter,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeDigitalPaddleSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("dsense") + direction,
|
||||
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
|
||||
const int sense =
|
||||
BSPF::clamp(myOSystem.settings().getInt("dsense") + direction,
|
||||
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
|
||||
myOSystem.settings().setValue("dsense", sense);
|
||||
|
||||
Paddles::setDigitalSensitivity(sense);
|
||||
|
@ -1163,16 +1253,17 @@ void PhysicalJoystickHandler::changeDigitalPaddleSensitivity(int direction)
|
|||
else
|
||||
ss << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Digital sensitivity",
|
||||
ss.str(), sense,
|
||||
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Digital sensitivity", ss.view(), sense,
|
||||
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeMousePaddleSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("msense") + direction,
|
||||
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
|
||||
const int sense =
|
||||
BSPF::clamp(myOSystem.settings().getInt("msense") + direction,
|
||||
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
|
||||
myOSystem.settings().setValue("msense", sense);
|
||||
|
||||
Controller::setMouseSensitivity(sense);
|
||||
|
@ -1180,16 +1271,17 @@ void PhysicalJoystickHandler::changeMousePaddleSensitivity(int direction)
|
|||
ostringstream ss;
|
||||
ss << sense * 10 << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Mouse paddle sensitivity",
|
||||
ss.str(), sense,
|
||||
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Mouse paddle sensitivity", ss.view(), sense,
|
||||
Controller::MIN_MOUSE_SENSE, Controller::MAX_MOUSE_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeMouseTrackballSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("tsense") + direction,
|
||||
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
|
||||
const int sense =
|
||||
BSPF::clamp(myOSystem.settings().getInt("tsense") + direction,
|
||||
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
|
||||
myOSystem.settings().setValue("tsense", sense);
|
||||
|
||||
PointingDevice::setSensitivity(sense);
|
||||
|
@ -1197,16 +1289,17 @@ void PhysicalJoystickHandler::changeMouseTrackballSensitivity(int direction)
|
|||
ostringstream ss;
|
||||
ss << sense * 10 << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Mouse trackball sensitivity",
|
||||
ss.str(), sense,
|
||||
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Mouse trackball sensitivity", ss.view(), sense,
|
||||
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeDrivingSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("dcsense") + direction,
|
||||
Driving::MIN_SENSE, Driving::MAX_SENSE);
|
||||
const int sense =
|
||||
BSPF::clamp(myOSystem.settings().getInt("dcsense") + direction,
|
||||
Driving::MIN_SENSE, Driving::MAX_SENSE);
|
||||
myOSystem.settings().setValue("dcsense", sense);
|
||||
|
||||
Driving::setSensitivity(sense);
|
||||
|
@ -1214,9 +1307,9 @@ void PhysicalJoystickHandler::changeDrivingSensitivity(int direction)
|
|||
ostringstream ss;
|
||||
ss << sense * 10 << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Driving controller sensitivity",
|
||||
ss.str(), sense,
|
||||
Driving::MIN_SENSE, Driving::MAX_SENSE);
|
||||
myOSystem.frameBuffer().showGaugeMessage(
|
||||
"Driving controller sensitivity", ss.view(), sense,
|
||||
Driving::MIN_SENSE, Driving::MAX_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1391,13 +1484,22 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRight
|
|||
PhysicalJoystickHandler::EventMappingArray
|
||||
PhysicalJoystickHandler::DefaultCommonMapping = {
|
||||
// valid for all joysticks
|
||||
// Note: buttons 0..2 are used by controllers!
|
||||
#if defined(RETRON77)
|
||||
{Event::CmdMenuMode, 3}, // Note: buttons 0..2 are used by controllers!
|
||||
{Event::ExitMode, 4},
|
||||
{Event::OptionsMenuMode, 5},
|
||||
{Event::RewindPause, 6},
|
||||
{Event::ConsoleSelect, 7},
|
||||
{Event::ConsoleReset, 8},
|
||||
{Event::CmdMenuMode, 3}, // Button "Y" / "4"
|
||||
{Event::ExitMode, 4}, // Left Shoulder Button
|
||||
{Event::OptionsMenuMode, 5}, // Right Shoulder Button
|
||||
{Event::RewindPause, 7}, // Right Trigger Button
|
||||
{Event::ConsoleSelect, 8}, // Button "Select"
|
||||
{Event::ConsoleReset, 9}, // Button "Start"
|
||||
#else
|
||||
{Event::ConsoleSelect, 8}, // Button "Select"
|
||||
{Event::ConsoleReset, 9}, // Button "Start"
|
||||
{Event::ConsoleColorToggle, 3}, // Button "Y" / "4"
|
||||
{Event::ConsoleLeftDiffToggle, 4}, // Left Shoulder Button
|
||||
{Event::ConsoleRightDiffToggle, 5}, // Right Shoulder Button
|
||||
{Event::CmdMenuMode, 6}, // Left Trigger Button
|
||||
{Event::OptionsMenuMode, 7}, // Right Trigger Button
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1416,7 +1518,9 @@ PhysicalJoystickHandler::DefaultMenuMapping = {
|
|||
{Event::UINavNext, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
|
||||
{Event::UITabNext, 0, JoyAxis::X, JoyDir::POS},
|
||||
{Event::UIUp, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
|
||||
{Event::UIOK, 0 , JoyAxis::Y, JoyDir::NEG},
|
||||
{Event::UIDown, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
|
||||
{Event::UICancel, 0 , JoyAxis::Y, JoyDir::POS},
|
||||
|
||||
{Event::UINavPrev, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::LEFT},
|
||||
{Event::UINavNext, JOY_CTRL_NONE, JoyAxis::NONE, JoyDir::NONE, 0, JoyHatDir::RIGHT},
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -46,6 +46,18 @@ using PhysicalJoystickPtr = shared_ptr<PhysicalJoystick>;
|
|||
*/
|
||||
class PhysicalJoystickHandler
|
||||
{
|
||||
public:
|
||||
struct MinStrickInfo
|
||||
{
|
||||
string name;
|
||||
int ID;
|
||||
PhysicalJoystick::Port port;
|
||||
|
||||
explicit MinStrickInfo(string_view _name, int _id, PhysicalJoystick::Port _port)
|
||||
: name{_name}, ID{_id}, port{_port} {}
|
||||
};
|
||||
using MinStrickInfoList = std::vector<MinStrickInfo>;
|
||||
|
||||
private:
|
||||
struct StickInfo
|
||||
{
|
||||
|
@ -54,13 +66,13 @@ class PhysicalJoystickHandler
|
|||
// on the 'mapping' instance variable; there lay dragons ...
|
||||
// https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays
|
||||
explicit StickInfo(nlohmann::json map, PhysicalJoystickPtr stick = nullptr)
|
||||
: mapping(map), joy{std::move(stick)} {}
|
||||
: mapping(map), joy{std::move(stick)} {} // NOLINT
|
||||
|
||||
nlohmann::json mapping;
|
||||
PhysicalJoystickPtr joy;
|
||||
|
||||
friend ostream& operator<<(ostream& os, const StickInfo& si) {
|
||||
os << " joy: " << si.joy << endl << " map: " << si.mapping;
|
||||
os << " joy: " << si.joy << "\n map: " << si.mapping;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
@ -68,18 +80,22 @@ class PhysicalJoystickHandler
|
|||
public:
|
||||
PhysicalJoystickHandler(OSystem& system, EventHandler& handler, Event& event);
|
||||
|
||||
static nlohmann::json convertLegacyMapping(const string& mapping);
|
||||
static nlohmann::json convertLegacyMapping(string_view mapping);
|
||||
|
||||
/** Return stick ID on success, -1 on failure. */
|
||||
int add(const PhysicalJoystickPtr& stick);
|
||||
bool remove(int id);
|
||||
bool remove(const string& name);
|
||||
bool mapStelladaptors(const string& saport, int ID = -1);
|
||||
bool remove(string_view name);
|
||||
void setPort(string_view name, PhysicalJoystick::Port port);
|
||||
bool mapStelladaptors(string_view saport, int ID = -1);
|
||||
bool hasStelladaptors() const;
|
||||
void setDefaultMapping(Event::Type type, EventMode mode);
|
||||
void setDefaultMapping(Event::Type event, EventMode mode);
|
||||
|
||||
/** define mappings for current controllers */
|
||||
void defineControllerMappings(const Controller::Type type, Controller::Jack port);
|
||||
void defineControllerMappings(Controller::Type type, Controller::Jack port,
|
||||
const Properties& properties,
|
||||
Controller::Type qtType1 = Controller::Type::Unknown,
|
||||
Controller::Type qtType2 = Controller::Type::Unknown);
|
||||
/** enable mappings for emulation mode */
|
||||
void enableEmulationMappings();
|
||||
|
||||
|
@ -111,8 +127,8 @@ class PhysicalJoystickHandler
|
|||
return j->joyMap.get(mode, button, hat, hatDir);
|
||||
}
|
||||
|
||||
/** Returns a list of pairs consisting of joystick name and associated ID. */
|
||||
VariantList database() const;
|
||||
/** Returns a list containing minimal controller info (name, ID, port). */
|
||||
MinStrickInfoList minStickList() const;
|
||||
|
||||
void changeDigitalDeadZone(int direction = +1);
|
||||
void changeAnalogPaddleDeadZone(int direction = +1);
|
||||
|
@ -126,12 +142,12 @@ class PhysicalJoystickHandler
|
|||
void changeDrivingSensitivity(int direction = +1);
|
||||
|
||||
private:
|
||||
using StickDatabase = std::map<string,StickInfo>;
|
||||
using StickDatabase = std::map<string, StickInfo, std::less<>>;
|
||||
using StickList = std::map<int, PhysicalJoystickPtr>;
|
||||
|
||||
OSystem& myOSystem;
|
||||
EventHandler& myHandler;
|
||||
Event& myEvent;
|
||||
OSystem& myOSystem; // NOLINT: we want a reference here
|
||||
EventHandler& myHandler; // NOLINT: we want a reference here
|
||||
Event& myEvent; // NOLINT: we want a reference here
|
||||
|
||||
// Contains all joysticks that Stella knows about, indexed by name
|
||||
StickDatabase myDatabase;
|
||||
|
@ -141,7 +157,7 @@ class PhysicalJoystickHandler
|
|||
|
||||
// Get joystick corresponding to given id (or nullptr if it doesn't exist)
|
||||
// Make this inline so it's as fast as possible
|
||||
const PhysicalJoystickPtr joy(int id) const {
|
||||
PhysicalJoystickPtr joy(int id) const {
|
||||
const auto& i = mySticks.find(id);
|
||||
return i != mySticks.cend() ? i->second : nullptr;
|
||||
}
|
||||
|
@ -150,13 +166,15 @@ class PhysicalJoystickHandler
|
|||
void addToDatabase(const PhysicalJoystickPtr& stick);
|
||||
|
||||
// Set default mapping for given joystick when no mappings already exist
|
||||
void setStickDefaultMapping(int stick, Event::Type type, EventMode mode,
|
||||
void setStickDefaultMapping(int stick, Event::Type event, EventMode mode,
|
||||
bool updateDefaults = false);
|
||||
|
||||
friend ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh);
|
||||
|
||||
JoyDir convertAxisValue(int value) const {
|
||||
return value == int(JoyDir::NONE) ? JoyDir::NONE : value > 0 ? JoyDir::POS : JoyDir::NEG;
|
||||
static constexpr JoyDir convertAxisValue(int value) {
|
||||
return value == static_cast<int>(JoyDir::NONE)
|
||||
? JoyDir::NONE
|
||||
: value > 0 ? JoyDir::POS : JoyDir::NEG;
|
||||
}
|
||||
|
||||
// Handle regular axis events (besides special Stelladaptor handling)
|
||||
|
@ -179,23 +197,31 @@ class PhysicalJoystickHandler
|
|||
EventMode mode = EventMode::kEmulationMode,
|
||||
bool updateDefaults = false);
|
||||
|
||||
/** return event mode for given property */
|
||||
static EventMode getMode(const Properties& properties, PropType propType);
|
||||
/** return event mode for given controller type */
|
||||
static EventMode getMode(Controller::Type type);
|
||||
|
||||
/** returns the event's controller mode */
|
||||
EventMode getEventMode(const Event::Type event, const EventMode mode) const;
|
||||
static EventMode getEventMode(Event::Type event, EventMode mode);
|
||||
/** Checks event type. */
|
||||
bool isJoystickEvent(const Event::Type event) const;
|
||||
bool isPaddleEvent(const Event::Type event) const;
|
||||
bool isKeyboardEvent(const Event::Type event) const;
|
||||
bool isDrivingEvent(const Event::Type event) const;
|
||||
bool isCommonEvent(const Event::Type event) const;
|
||||
static bool isJoystickEvent(Event::Type event);
|
||||
static bool isPaddleEvent(Event::Type event);
|
||||
static bool isKeyboardEvent(Event::Type event);
|
||||
static bool isDrivingEvent(Event::Type event);
|
||||
static bool isCommonEvent(Event::Type event);
|
||||
|
||||
void enableCommonMappings();
|
||||
|
||||
void enableMappings(const Event::EventSet& events, EventMode mode);
|
||||
void enableMapping(const Event::Type event, EventMode mode);
|
||||
void enableMapping(Event::Type event, EventMode mode);
|
||||
|
||||
private:
|
||||
EventMode myLeftMode{EventMode::kEmulationMode};
|
||||
EventMode myRightMode{EventMode::kEmulationMode};
|
||||
// Additional modes for QuadTari controller
|
||||
EventMode myLeft2ndMode{EventMode::kEmulationMode};
|
||||
EventMode myRight2ndMode{EventMode::kEmulationMode};
|
||||
|
||||
// Controller menu and common emulation mappings
|
||||
static EventMappingArray DefaultMenuMapping;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -44,7 +44,7 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
|
|||
: myOSystem{system},
|
||||
myHandler{handler}
|
||||
{
|
||||
Int32 version = myOSystem.settings().getInt("event_ver");
|
||||
const Int32 version = myOSystem.settings().getInt("event_ver");
|
||||
bool updateDefaults = false;
|
||||
|
||||
// Compare if event list version has changed so that key maps became invalid
|
||||
|
@ -70,10 +70,28 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
|
|||
#ifdef DEBUGGER_SUPPORT
|
||||
setDefaultMapping(Event::NoType, EventMode::kPromptMode, updateDefaults);
|
||||
#endif
|
||||
#ifdef DEBUG_BUILD
|
||||
verifyDefaultMapping(DefaultCommonMapping, EventMode::kEmulationMode, "EmulationMode");
|
||||
verifyDefaultMapping(DefaultMenuMapping, EventMode::kMenuMode, "MenuMode");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalKeyboardHandler::loadSerializedMappings(const string& serializedMapping, EventMode mode)
|
||||
void PhysicalKeyboardHandler::verifyDefaultMapping(
|
||||
PhysicalKeyboardHandler::EventMappingArray mapping, EventMode mode, string_view name)
|
||||
{
|
||||
for(const auto& item1 : mapping)
|
||||
for(const auto& item2 : mapping)
|
||||
if(item1.event != item2.event && item1.key == item2.key && item1.mod == item2.mod)
|
||||
cerr << "ERROR! Duplicate hotkey mapping found: " << name << ", "
|
||||
<< myKeyMap.getDesc(KeyMap::Mapping(mode, item1.key, item1.mod)) << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalKeyboardHandler::loadSerializedMappings(
|
||||
string_view serializedMapping, EventMode mode)
|
||||
{
|
||||
json mapping;
|
||||
|
||||
|
@ -145,7 +163,7 @@ void PhysicalKeyboardHandler::setDefaultKey(EventMapping map, Event::Type event,
|
|||
{
|
||||
// if there is no existing mapping for the event and
|
||||
// the default mapping for the event is unused, set default key for event
|
||||
if (myKeyMap.getEventMapping(map.event, mode).size() == 0 &&
|
||||
if (myKeyMap.getEventMapping(map.event, mode).empty() &&
|
||||
!isMappingUsed(mode, map))
|
||||
{
|
||||
addMapping(map.event, mode, map.key, static_cast<StellaMod>(map.mod));
|
||||
|
@ -217,68 +235,65 @@ void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mod
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalKeyboardHandler::defineControllerMappings(
|
||||
const Controller::Type type, Controller::Jack port, const Properties& properties)
|
||||
Controller::Type type, Controller::Jack port, const Properties& properties,
|
||||
Controller::Type qtType1, Controller::Type qtType2)
|
||||
{
|
||||
|
||||
//const string& test = myOSystem.settings().getString("aq");
|
||||
// determine controller events to use
|
||||
switch(type)
|
||||
// Determine controller events to use
|
||||
if(type == Controller::Type::QuadTari)
|
||||
{
|
||||
case Controller::Type::QuadTari:
|
||||
if(port == Controller::Jack::Left)
|
||||
{
|
||||
myLeftMode = getMode(properties, PropType::Controller_Left1);
|
||||
myLeft2ndMode = getMode(properties, PropType::Controller_Left2);
|
||||
}
|
||||
else
|
||||
{
|
||||
myRightMode = getMode(properties, PropType::Controller_Right1);
|
||||
myRight2ndMode = getMode(properties, PropType::Controller_Right2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if(port == Controller::Jack::Left)
|
||||
{
|
||||
const EventMode mode = getMode(type);
|
||||
|
||||
if(port == Controller::Jack::Left)
|
||||
myLeftMode = mode;
|
||||
else
|
||||
myRightMode = mode;
|
||||
break;
|
||||
myLeftMode = getMode(qtType1);
|
||||
myLeft2ndMode = getMode(qtType2);
|
||||
}
|
||||
else
|
||||
{
|
||||
myRightMode = getMode(qtType1);
|
||||
myRight2ndMode = getMode(qtType2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const EventMode mode = getMode(type);
|
||||
|
||||
if(port == Controller::Jack::Left)
|
||||
myLeftMode = mode;
|
||||
else
|
||||
myRightMode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventMode PhysicalKeyboardHandler::getMode(const Properties& properties, const PropType propType)
|
||||
EventMode PhysicalKeyboardHandler::getMode(const Properties& properties,
|
||||
PropType propType)
|
||||
{
|
||||
const string& propName = properties.get(propType);
|
||||
|
||||
if(!propName.empty())
|
||||
return getMode(Controller::getType(propName));
|
||||
|
||||
return getMode(Controller::Type::Joystick);
|
||||
return EventMode::kJoystickMode;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventMode PhysicalKeyboardHandler::getMode(const Controller::Type type)
|
||||
EventMode PhysicalKeyboardHandler::getMode(Controller::Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case Controller::Type::Keyboard:
|
||||
case Controller::Type::KidVid:
|
||||
using enum Controller::Type;
|
||||
case Keyboard:
|
||||
case KidVid:
|
||||
return EventMode::kKeyboardMode;
|
||||
|
||||
case Controller::Type::Paddles:
|
||||
case Controller::Type::PaddlesIAxDr:
|
||||
case Controller::Type::PaddlesIAxis:
|
||||
case Paddles:
|
||||
case PaddlesIAxDr:
|
||||
case PaddlesIAxis:
|
||||
return EventMode::kPaddlesMode;
|
||||
|
||||
case Controller::Type::CompuMate:
|
||||
case CompuMate:
|
||||
return EventMode::kCompuMateMode;
|
||||
|
||||
case Controller::Type::Driving:
|
||||
case Driving:
|
||||
return EventMode::kDrivingMode;
|
||||
|
||||
default:
|
||||
|
@ -377,7 +392,7 @@ void PhysicalKeyboardHandler::enableCommonMappings()
|
|||
{
|
||||
for (int i = Event::NoType + 1; i < Event::LastType; i++)
|
||||
{
|
||||
const Event::Type event = static_cast<Event::Type>(i);
|
||||
const auto event = static_cast<Event::Type>(i);
|
||||
|
||||
if (isCommonEvent(event))
|
||||
enableMapping(event, EventMode::kCommonMode);
|
||||
|
@ -393,19 +408,17 @@ void PhysicalKeyboardHandler::enableMappings(const Event::EventSet& events,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalKeyboardHandler::enableMapping(const Event::Type event,
|
||||
EventMode mode)
|
||||
void PhysicalKeyboardHandler::enableMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
// copy from controller mode into emulation mode
|
||||
KeyMap::MappingArray mappings = myKeyMap.getEventMapping(event, mode);
|
||||
const KeyMap::MappingArray mappings = myKeyMap.getEventMapping(event, mode);
|
||||
|
||||
for (const auto& mapping : mappings)
|
||||
myKeyMap.add(event, EventMode::kEmulationMode, mapping.key, mapping.mod);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event,
|
||||
const EventMode mode) const
|
||||
EventMode PhysicalKeyboardHandler::getEventMode(Event::Type event, EventMode mode)
|
||||
{
|
||||
if (mode == EventMode::kEmulationMode)
|
||||
{
|
||||
|
@ -429,41 +442,42 @@ EventMode PhysicalKeyboardHandler::getEventMode(const Event::Type event,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalKeyboardHandler::isJoystickEvent(const Event::Type event) const
|
||||
bool PhysicalKeyboardHandler::isJoystickEvent(Event::Type event)
|
||||
{
|
||||
return LeftJoystickEvents.find(event) != LeftJoystickEvents.end()
|
||||
|| QTJoystick3Events.find(event) != QTJoystick3Events.end()
|
||||
|| RightJoystickEvents.find(event) != RightJoystickEvents.end()
|
||||
|| QTJoystick4Events.find(event) != QTJoystick4Events.end();
|
||||
return LeftJoystickEvents.contains(event)
|
||||
|| QTJoystick3Events.contains(event)
|
||||
|| RightJoystickEvents.contains(event)
|
||||
|| QTJoystick4Events.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalKeyboardHandler::isPaddleEvent(const Event::Type event) const
|
||||
bool PhysicalKeyboardHandler::isPaddleEvent(Event::Type event)
|
||||
{
|
||||
return LeftPaddlesEvents.find(event) != LeftPaddlesEvents.end()
|
||||
|| QTPaddles3Events.find(event) != QTPaddles3Events.end()
|
||||
|| RightPaddlesEvents.find(event) != RightPaddlesEvents.end()
|
||||
|| QTPaddles4Events.find(event) != QTPaddles4Events.end();
|
||||
return LeftPaddlesEvents.contains(event)
|
||||
|| QTPaddles3Events.contains(event)
|
||||
|| RightPaddlesEvents.contains(event)
|
||||
|| QTPaddles4Events.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalKeyboardHandler::isDrivingEvent(const Event::Type event) const
|
||||
bool PhysicalKeyboardHandler::isKeyboardEvent(Event::Type event)
|
||||
{
|
||||
return LeftDrivingEvents.find(event) != LeftDrivingEvents.end()
|
||||
|| RightDrivingEvents.find(event) != RightDrivingEvents.end();
|
||||
return LeftKeyboardEvents.contains(event)
|
||||
|| RightKeyboardEvents.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalKeyboardHandler::isKeyboardEvent(const Event::Type event) const
|
||||
bool PhysicalKeyboardHandler::isDrivingEvent(Event::Type event)
|
||||
{
|
||||
return LeftKeyboardEvents.find(event) != LeftKeyboardEvents.end()
|
||||
|| RightKeyboardEvents.find(event) != RightKeyboardEvents.end();
|
||||
return LeftDrivingEvents.contains(event)
|
||||
|| RightDrivingEvents.contains(event);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalKeyboardHandler::isCommonEvent(const Event::Type event) const
|
||||
bool PhysicalKeyboardHandler::isCommonEvent(Event::Type event)
|
||||
{
|
||||
return !(isJoystickEvent(event) || isPaddleEvent(event) || isKeyboardEvent(event));
|
||||
return !(isJoystickEvent(event) || isPaddleEvent(event)
|
||||
|| isKeyboardEvent(event) || isDrivingEvent(event));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -599,7 +613,7 @@ void PhysicalKeyboardHandler::toggleModKeys(bool toggle)
|
|||
ostringstream ss;
|
||||
ss << "Modifier key combos ";
|
||||
ss << (modCombo ? "enabled" : "disabled");
|
||||
myOSystem.frameBuffer().showTextMessage(ss.str());
|
||||
myOSystem.frameBuffer().showTextMessage(ss.view());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -626,6 +640,7 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
|
|||
#endif
|
||||
{ Event::OptionsMenuMode, KBDK_TAB },
|
||||
{ Event::CmdMenuMode, KBDK_BACKSLASH },
|
||||
{ Event::ToggleBezel, KBDK_B, KBDM_CTRL },
|
||||
{ Event::TimeMachineMode, KBDK_T, KBDM_SHIFT },
|
||||
{ Event::DebuggerMode, KBDK_GRAVE },
|
||||
{ Event::PlusRomsSetupMode, KBDK_P, KBDM_SHIFT | KBDM_CTRL | MOD3 },
|
||||
|
@ -644,7 +659,7 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
|
|||
{ Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3 },
|
||||
{ Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3 },
|
||||
{ Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleCorrectAspectRatio, KBDK_C, KBDM_CTRL },
|
||||
{ Event::ToggleCorrectAspectRatio, KBDK_C, KBDM_SHIFT | KBDM_CTRL },
|
||||
{ Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3 },
|
||||
{ Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3 },
|
||||
{ Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL },
|
||||
|
@ -662,6 +677,8 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
|
|||
{ Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3 },
|
||||
{ Event::PhosphorIncrease, KBDK_4, MOD3 },
|
||||
{ Event::TogglePhosphor, KBDK_P, MOD3 },
|
||||
//{ Event::PhosphorModeDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL | MOD3 },
|
||||
{ Event::PhosphorModeIncrease, KBDK_P, KBDM_CTRL | MOD3 },
|
||||
{ Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ScanlinesIncrease, KBDK_5, MOD3 },
|
||||
{ Event::PreviousScanlineMask, KBDK_6, KBDM_SHIFT | MOD3 },
|
||||
|
@ -709,7 +726,7 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
|
|||
{ Event::ToggleFrameStats, KBDK_L, MOD3 },
|
||||
{ Event::ToggleTimeMachine, KBDK_T, MOD3 },
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
{ Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL },
|
||||
{ Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL },
|
||||
#endif
|
||||
|
@ -836,6 +853,7 @@ PhysicalKeyboardHandler::DefaultMenuMapping = {
|
|||
{Event::UITabPrev, KBDK_TAB, KBDM_SHIFT | KBDM_CTRL},
|
||||
{Event::UITabNext, KBDK_TAB, KBDM_CTRL},
|
||||
|
||||
{Event::ToggleUIPalette, KBDK_T, MOD3},
|
||||
{Event::ToggleFullScreen, KBDK_RETURN, MOD3},
|
||||
|
||||
#ifdef BSPF_MACOS
|
||||
|
@ -962,11 +980,9 @@ PhysicalKeyboardHandler::FixedPromptMapping = {
|
|||
{Event::UIDown, KBDK_DOWN, KBDM_SHIFT},
|
||||
{Event::UILeft, KBDK_DOWN},
|
||||
{Event::UIRight, KBDK_UP},
|
||||
|
||||
};
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoystickMapping = {
|
||||
{Event::LeftJoystickUp, KBDK_UP},
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
|
@ -24,6 +24,7 @@ class OSystem;
|
|||
class EventHandler;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Control.hxx"
|
||||
#include "Event.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "Props.hxx"
|
||||
|
@ -46,13 +47,17 @@ class PhysicalKeyboardHandler
|
|||
|
||||
PhysicalKeyboardHandler(OSystem& system, EventHandler& handler);
|
||||
|
||||
void loadSerializedMappings(const string& serializedMappings, EventMode mode);
|
||||
void loadSerializedMappings(string_view serializedMappings, EventMode mode);
|
||||
|
||||
void setDefaultMapping(Event::Type type, EventMode mode, bool updateDefaults = false);
|
||||
void setDefaultMapping(Event::Type event, EventMode mode,
|
||||
bool updateDefaults = false);
|
||||
|
||||
/** define mappings for current controllers */
|
||||
void defineControllerMappings(const Controller::Type type, Controller::Jack port,
|
||||
const Properties& properties);
|
||||
void defineControllerMappings(Controller::Type type,
|
||||
Controller::Jack port,
|
||||
const Properties& properties,
|
||||
Controller::Type qtType1 = Controller::Type::Unknown,
|
||||
Controller::Type qtType2 = Controller::Type::Unknown);
|
||||
/** enable mappings for emulation mode */
|
||||
void enableEmulationMappings();
|
||||
|
||||
|
@ -73,6 +78,10 @@ class PhysicalKeyboardHandler
|
|||
return myKeyMap.get(mode, key, mod);
|
||||
}
|
||||
|
||||
bool checkEventForKey(EventMode mode, StellaKey key, StellaMod mod) const {
|
||||
return myKeyMap.check(mode, key, mod);
|
||||
}
|
||||
|
||||
#ifdef BSPF_UNIX
|
||||
/** See comments on 'myAltKeyCounter' for more information. */
|
||||
uInt8& altKeyCount() { return myAltKeyCounter; }
|
||||
|
@ -100,23 +109,28 @@ class PhysicalKeyboardHandler
|
|||
EventMode mode = EventMode::kEmulationMode, bool updateDefaults = false);
|
||||
|
||||
/** returns the event's controller mode */
|
||||
EventMode getEventMode(const Event::Type event, const EventMode mode) const;
|
||||
static EventMode getEventMode(Event::Type event, EventMode mode);
|
||||
/** Checks event type. */
|
||||
bool isJoystickEvent(const Event::Type event) const;
|
||||
bool isPaddleEvent(const Event::Type event) const;
|
||||
bool isKeyboardEvent(const Event::Type event) const;
|
||||
bool isDrivingEvent(const Event::Type event) const;
|
||||
bool isCommonEvent(const Event::Type event) const;
|
||||
static bool isJoystickEvent(Event::Type event);
|
||||
static bool isPaddleEvent(Event::Type event);
|
||||
static bool isKeyboardEvent(Event::Type event);
|
||||
static bool isDrivingEvent(Event::Type event);
|
||||
static bool isCommonEvent(Event::Type event);
|
||||
|
||||
void enableCommonMappings();
|
||||
|
||||
void enableMappings(const Event::EventSet& events, EventMode mode);
|
||||
void enableMapping(const Event::Type event, EventMode mode);
|
||||
void enableMapping(Event::Type event, EventMode mode);
|
||||
|
||||
/** return event mode for given property */
|
||||
EventMode getMode(const Properties& properties, const PropType propType);
|
||||
static EventMode getMode(const Properties& properties, PropType propType);
|
||||
/** return event mode for given controller type */
|
||||
EventMode getMode(const Controller::Type type);
|
||||
static EventMode getMode(Controller::Type type);
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
void verifyDefaultMapping(PhysicalKeyboardHandler::EventMappingArray mapping,
|
||||
EventMode mode, string_view name);
|
||||
#endif
|
||||
|
||||
private:
|
||||
OSystem& myOSystem;
|
||||
|
|
|
@ -8,28 +8,23 @@
|
|||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#if defined(PNG_SUPPORT)
|
||||
#ifdef IMAGE_SUPPORT
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "Props.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "TIASurface.hxx"
|
||||
#include "Version.hxx"
|
||||
#include "PNGLibrary.hxx"
|
||||
#include "Rect.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PNGLibrary::PNGLibrary(OSystem& osystem)
|
||||
|
@ -38,34 +33,35 @@ PNGLibrary::PNGLibrary(OSystem& osystem)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
||||
void PNGLibrary::loadImage(const string& filename, FBSurface& surface,
|
||||
VariantList& metaData)
|
||||
{
|
||||
png_structp png_ptr{nullptr};
|
||||
png_infop info_ptr{nullptr};
|
||||
png_uint_32 iwidth{0}, iheight{0};
|
||||
int bit_depth{0}, color_type{0}, interlace_type{0};
|
||||
bool hasAlpha = false;
|
||||
|
||||
const auto loadImageERROR = [&](const char* s) {
|
||||
const auto loadImageERROR = [&](string_view s) {
|
||||
if(png_ptr)
|
||||
png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : nullptr, nullptr);
|
||||
if(s)
|
||||
throw runtime_error(s);
|
||||
throw runtime_error(string{s});
|
||||
};
|
||||
|
||||
std::ifstream in(filename, std::ios_base::binary);
|
||||
if(!in.is_open())
|
||||
loadImageERROR("No snapshot found");
|
||||
loadImageERROR("No image found");
|
||||
|
||||
// Create the PNG loading context structure
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
|
||||
png_user_error, png_user_warn);
|
||||
if(png_ptr == nullptr)
|
||||
loadImageERROR("Couldn't allocate memory for PNG file");
|
||||
loadImageERROR("Couldn't allocate memory for PNG image");
|
||||
|
||||
// Allocate/initialize the memory for image information. REQUIRED.
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if(info_ptr == nullptr)
|
||||
loadImageERROR("Couldn't create image information for PNG file");
|
||||
loadImageERROR("Couldn't create image information for PNG image");
|
||||
|
||||
// Set up the input control
|
||||
png_set_read_fn(png_ptr, &in, png_read_data);
|
||||
|
@ -82,18 +78,25 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
|||
// byte into separate bytes (useful for paletted and grayscale images).
|
||||
png_set_packing(png_ptr);
|
||||
|
||||
// Only normal RBG(A) images are supported (without the alpha channel)
|
||||
// Alpha channel is supported
|
||||
if(color_type == PNG_COLOR_TYPE_RGBA)
|
||||
{
|
||||
png_set_strip_alpha(png_ptr);
|
||||
hasAlpha = true;
|
||||
}
|
||||
else if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
{
|
||||
// TODO: preserve alpha
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
}
|
||||
else if(color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
|
||||
{
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
hasAlpha = true;
|
||||
}
|
||||
else
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
}
|
||||
else if(color_type != PNG_COLOR_TYPE_RGB)
|
||||
{
|
||||
|
@ -101,8 +104,8 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
|||
}
|
||||
|
||||
// Create/initialize storage area for the current image
|
||||
if(!allocateStorage(iwidth, iheight))
|
||||
loadImageERROR("Not enough memory to read PNG file");
|
||||
if(!allocateStorage(iwidth, iheight, hasAlpha))
|
||||
loadImageERROR("Not enough memory to read PNG image");
|
||||
|
||||
// The PNG read function expects an array of rows, not a single 1-D array
|
||||
for(uInt32 irow = 0, offset = 0; irow < ReadInfo.height; ++irow, offset += ReadInfo.pitch)
|
||||
|
@ -114,8 +117,11 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
|||
// We're finished reading
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
|
||||
// Read the meta data we got
|
||||
readMetaData(png_ptr, info_ptr, metaData);
|
||||
|
||||
// Load image into the surface, setting the correct dimensions
|
||||
loadImagetoSurface(surface);
|
||||
loadImagetoSurface(surface, hasAlpha);
|
||||
|
||||
// Cleanup
|
||||
if(png_ptr)
|
||||
|
@ -123,7 +129,7 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
|
||||
void PNGLibrary::saveImage(const string& filename, const VariantList& metaData)
|
||||
{
|
||||
std::ofstream out(filename, std::ios_base::binary);
|
||||
if(!out.is_open())
|
||||
|
@ -137,31 +143,31 @@ void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
|
|||
fb.scaleX(rectUnscaled.w()), fb.scaleY(rectUnscaled.h())
|
||||
);
|
||||
|
||||
const png_uint_32 width = rect.w(), height = rect.h();
|
||||
const size_t width = rect.w(), height = rect.h();
|
||||
|
||||
// Get framebuffer pixel data (we get ABGR format)
|
||||
vector<png_byte> buffer(width * height * 4);
|
||||
fb.readPixels(buffer.data(), width*4, rect);
|
||||
fb.readPixels(buffer.data(), width * 4, rect);
|
||||
|
||||
// Set up pointers into "buffer" byte array
|
||||
vector<png_bytep> rows(height);
|
||||
for(png_uint_32 k = 0; k < height; ++k)
|
||||
rows[k] = buffer.data() + k*width*4;
|
||||
for(size_t k = 0; k < height; ++k)
|
||||
rows[k] = buffer.data() + k * width * 4;
|
||||
|
||||
// And save the image
|
||||
saveImageToDisk(out, rows, width, height, comments);
|
||||
saveImageToDisk(out, rows, width, height, metaData);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::saveImage(const string& filename, const FBSurface& surface,
|
||||
const Common::Rect& rect, const VariantList& comments)
|
||||
const Common::Rect& rect, const VariantList& metaData)
|
||||
{
|
||||
std::ofstream out(filename, std::ios_base::binary);
|
||||
if(!out.is_open())
|
||||
throw runtime_error("ERROR: Couldn't create snapshot file");
|
||||
|
||||
// Do we want the entire surface or just a section?
|
||||
png_uint_32 width = rect.w(), height = rect.h();
|
||||
size_t width = rect.w(), height = rect.h();
|
||||
if(rect.empty())
|
||||
{
|
||||
width = surface.width();
|
||||
|
@ -170,29 +176,28 @@ void PNGLibrary::saveImage(const string& filename, const FBSurface& surface,
|
|||
|
||||
// Get the surface pixel data (we get ABGR format)
|
||||
vector<png_byte> buffer(width * height * 4);
|
||||
surface.readPixels(buffer.data(), width, rect);
|
||||
surface.readPixels(buffer.data(), static_cast<uInt32>(width), rect);
|
||||
|
||||
// Set up pointers into "buffer" byte array
|
||||
vector<png_bytep> rows(height);
|
||||
for(png_uint_32 k = 0; k < height; ++k)
|
||||
rows[k] = buffer.data() + k*width*4;
|
||||
for(size_t k = 0; k < height; ++k)
|
||||
rows[k] = buffer.data() + k * width * 4;
|
||||
|
||||
// And save the image
|
||||
saveImageToDisk(out, rows, width, height, comments);
|
||||
saveImageToDisk(out, rows, width, height, metaData);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::saveImageToDisk(std::ofstream& out, const vector<png_bytep>& rows,
|
||||
png_uint_32 width, png_uint_32 height, const VariantList& comments)
|
||||
size_t width, size_t height, const VariantList& metaData)
|
||||
{
|
||||
png_structp png_ptr = nullptr;
|
||||
png_infop info_ptr = nullptr;
|
||||
png_structp png_ptr{nullptr};
|
||||
png_infop info_ptr{nullptr};
|
||||
|
||||
const auto saveImageERROR = [&](const char* s) {
|
||||
const auto saveImageERROR = [&](string_view s) {
|
||||
if(png_ptr)
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
if(s)
|
||||
throw runtime_error(s);
|
||||
throw runtime_error(string{s});
|
||||
};
|
||||
|
||||
// Create the PNG saving context structure
|
||||
|
@ -210,12 +215,13 @@ void PNGLibrary::saveImageToDisk(std::ofstream& out, const vector<png_bytep>& ro
|
|||
png_set_write_fn(png_ptr, &out, png_write_data, png_io_flush);
|
||||
|
||||
// Write PNG header info
|
||||
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
|
||||
png_set_IHDR(png_ptr, info_ptr,
|
||||
static_cast<png_uint_32>(width), static_cast<png_uint_32>(height), 8,
|
||||
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
// Write comments
|
||||
writeComments(png_ptr, info_ptr, comments);
|
||||
// Write meta data
|
||||
writeMetaData(png_ptr, info_ptr, metaData);
|
||||
|
||||
// Write the file header information. REQUIRED
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
@ -267,7 +273,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame)
|
|||
buf << "Enabling snapshots in " << interval << " second intervals";
|
||||
interval *= static_cast<uInt32>(myOSystem.frameRate());
|
||||
}
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.view());
|
||||
setContinuousSnapInterval(interval);
|
||||
}
|
||||
else
|
||||
|
@ -276,7 +282,7 @@ void PNGLibrary::toggleContinuousSnapshots(bool perFrame)
|
|||
buf << "Disabling snapshots, generated "
|
||||
<< (mySnapCounter / mySnapInterval)
|
||||
<< " files";
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
myOSystem.frameBuffer().showTextMessage(buf.view());
|
||||
setContinuousSnapInterval(0);
|
||||
}
|
||||
}
|
||||
|
@ -296,9 +302,9 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
|
||||
// Figure out the correct snapshot name
|
||||
string filename;
|
||||
string sspath = myOSystem.snapshotSaveDir().getPath() +
|
||||
(myOSystem.settings().getString("snapname") != "int" ?
|
||||
myOSystem.romFile().getNameWithExt("")
|
||||
const string sspath = myOSystem.snapshotSaveDir().getPath() +
|
||||
(myOSystem.settings().getString("snapname") != "int"
|
||||
? myOSystem.romFile().getNameWithExt("")
|
||||
: myOSystem.console().properties().get(PropType::Cart_Name));
|
||||
|
||||
// Check whether we want multiple snapshots created
|
||||
|
@ -307,14 +313,14 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
ostringstream buf;
|
||||
buf << sspath << "_" << std::hex << std::setw(8) << std::setfill('0')
|
||||
<< number << ".png";
|
||||
filename = buf.str();
|
||||
filename = buf.view();
|
||||
}
|
||||
else if(!myOSystem.settings().getBool("sssingle"))
|
||||
{
|
||||
// Determine if the file already exists, checking each successive filename
|
||||
// until one doesn't exist
|
||||
filename = sspath + ".png";
|
||||
FilesystemNode node(filename);
|
||||
const FSNode node(filename);
|
||||
if(node.exists())
|
||||
{
|
||||
ostringstream buf;
|
||||
|
@ -322,28 +328,29 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
{
|
||||
buf.str("");
|
||||
buf << sspath << "_" << i << ".png";
|
||||
FilesystemNode next(buf.str());
|
||||
const FSNode next(buf.view());
|
||||
if(!next.exists())
|
||||
break;
|
||||
}
|
||||
filename = buf.str();
|
||||
filename = buf.view();
|
||||
}
|
||||
}
|
||||
else
|
||||
filename = sspath + ".png";
|
||||
|
||||
// Some text fields to add to the PNG snapshot
|
||||
VariantList comments;
|
||||
VariantList metaData;
|
||||
ostringstream version;
|
||||
VarList::push_back(metaData, "Title", "Snapshot");
|
||||
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
|
||||
<< BSPF::ARCH << "]";
|
||||
VarList::push_back(comments, "Software", version.str());
|
||||
VarList::push_back(metaData, "Software", version.view());
|
||||
const string& name = (myOSystem.settings().getString("snapname") == "int")
|
||||
? myOSystem.console().properties().get(PropType::Cart_Name)
|
||||
: myOSystem.romFile().getName();
|
||||
VarList::push_back(comments, "ROM Name", name);
|
||||
VarList::push_back(comments, "ROM MD5", myOSystem.console().properties().get(PropType::Cart_MD5));
|
||||
VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
|
||||
VarList::push_back(metaData, "ROM Name", name);
|
||||
VarList::push_back(metaData, "ROM MD5", myOSystem.console().properties().get(PropType::Cart_MD5));
|
||||
VarList::push_back(metaData, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
|
||||
|
||||
// Now create a PNG snapshot
|
||||
string message = "Snapshot saved";
|
||||
|
@ -352,8 +359,9 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
try
|
||||
{
|
||||
Common::Rect rect;
|
||||
const FBSurface& surface = myOSystem.frameBuffer().tiaSurface().baseSurface(rect);
|
||||
myOSystem.png().saveImage(filename, surface, rect, comments);
|
||||
const FBSurface& surface =
|
||||
myOSystem.frameBuffer().tiaSurface().baseSurface(rect);
|
||||
PNGLibrary::saveImage(filename, surface, rect, metaData);
|
||||
}
|
||||
catch(const runtime_error& e)
|
||||
{
|
||||
|
@ -368,7 +376,7 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
|
||||
try
|
||||
{
|
||||
myOSystem.png().saveImage(filename, comments);
|
||||
PNGLibrary::saveImage(filename, metaData);
|
||||
}
|
||||
catch(const runtime_error& e)
|
||||
{
|
||||
|
@ -382,26 +390,26 @@ void PNGLibrary::takeSnapshot(uInt32 number)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h)
|
||||
bool PNGLibrary::allocateStorage(size_t width, size_t height, bool hasAlpha)
|
||||
{
|
||||
// Create space for the entire image (3 bytes per pixel in RGB format)
|
||||
const size_t req_buffer_size = w * h * 3;
|
||||
if(req_buffer_size > ReadInfo.buffer.size())
|
||||
ReadInfo.buffer.resize(req_buffer_size);
|
||||
// Create space for the entire image (3(4) bytes per pixel in RGB(A) format)
|
||||
const size_t req_buffer_size = width * height * (hasAlpha ? 4 : 3);
|
||||
if(req_buffer_size > ReadInfo.buffer.capacity())
|
||||
ReadInfo.buffer.resize(req_buffer_size * 1.5);
|
||||
|
||||
const size_t req_row_size = h;
|
||||
if(req_row_size > ReadInfo.row_pointers.size())
|
||||
ReadInfo.row_pointers.resize(req_row_size);
|
||||
const size_t req_row_size = height;
|
||||
if(req_row_size > ReadInfo.row_pointers.capacity())
|
||||
ReadInfo.row_pointers.resize(req_row_size * 1.5);
|
||||
|
||||
ReadInfo.width = w;
|
||||
ReadInfo.height = h;
|
||||
ReadInfo.pitch = w * 3;
|
||||
ReadInfo.width = static_cast<png_uint_32>(width);
|
||||
ReadInfo.height = static_cast<png_uint_32>(height);
|
||||
ReadInfo.pitch = static_cast<png_uint_32>(width * (hasAlpha ? 4 : 3));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::loadImagetoSurface(FBSurface& surface)
|
||||
void PNGLibrary::loadImagetoSurface(FBSurface& surface, bool hasAlpha)
|
||||
{
|
||||
// First determine if we need to resize the surface
|
||||
const uInt32 iw = ReadInfo.width, ih = ReadInfo.height;
|
||||
|
@ -414,7 +422,7 @@ void PNGLibrary::loadImagetoSurface(FBSurface& surface)
|
|||
surface.setSrcSize(iw, ih);
|
||||
|
||||
// Convert RGB triples into pixels and store in the surface
|
||||
uInt32 *s_buf, s_pitch;
|
||||
uInt32 *s_buf{nullptr}, s_pitch{0};
|
||||
surface.basePtr(s_buf, s_pitch);
|
||||
const uInt8* i_buf = ReadInfo.buffer.data();
|
||||
const uInt32 i_pitch = ReadInfo.pitch;
|
||||
|
@ -424,58 +432,78 @@ void PNGLibrary::loadImagetoSurface(FBSurface& surface)
|
|||
{
|
||||
const uInt8* i_ptr = i_buf;
|
||||
uInt32* s_ptr = s_buf;
|
||||
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 3)
|
||||
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
|
||||
if(hasAlpha)
|
||||
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 4)
|
||||
*s_ptr++ = fb.mapRGBA(*i_ptr, *(i_ptr+1), *(i_ptr+2), *(i_ptr+3));
|
||||
else
|
||||
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 3)
|
||||
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::writeComments(const png_structp png_ptr, png_infop info_ptr,
|
||||
const VariantList& comments)
|
||||
void PNGLibrary::writeMetaData(png_structp png_ptr, png_infop info_ptr,
|
||||
const VariantList& metaData)
|
||||
{
|
||||
const uInt32 numComments = static_cast<uInt32>(comments.size());
|
||||
if(numComments == 0)
|
||||
const size_t numMetaData = metaData.size();
|
||||
if(numMetaData == 0)
|
||||
return;
|
||||
|
||||
vector<png_text> text_ptr(numComments);
|
||||
for(uInt32 i = 0; i < numComments; ++i)
|
||||
vector<png_text> text_ptr(numMetaData);
|
||||
for(size_t i = 0; i < numMetaData; ++i)
|
||||
{
|
||||
text_ptr[i].key = const_cast<char*>(comments[i].first.c_str());
|
||||
text_ptr[i].text = const_cast<char*>(comments[i].second.toCString());
|
||||
text_ptr[i].key = const_cast<char*>(metaData[i].first.c_str());
|
||||
text_ptr[i].text = const_cast<char*>(metaData[i].second.toCString());
|
||||
text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text_ptr[i].text_length = 0;
|
||||
}
|
||||
png_set_text(png_ptr, info_ptr, text_ptr.data(), numComments);
|
||||
png_set_text(png_ptr, info_ptr, text_ptr.data(), static_cast<int>(numMetaData));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::png_read_data(const png_structp ctx, png_bytep area, png_size_t size)
|
||||
void PNGLibrary::readMetaData(png_structp png_ptr, png_infop info_ptr,
|
||||
VariantList& metaData)
|
||||
{
|
||||
png_textp text_ptr{nullptr};
|
||||
int numMetaData{0};
|
||||
|
||||
png_get_text(png_ptr, info_ptr, &text_ptr, &numMetaData);
|
||||
|
||||
metaData.clear();
|
||||
for(int i = 0; i < numMetaData; ++i)
|
||||
{
|
||||
VarList::push_back(metaData, text_ptr[i].key, text_ptr[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::png_read_data(png_structp ctx, png_bytep area, png_size_t size)
|
||||
{
|
||||
(static_cast<std::ifstream*>(png_get_io_ptr(ctx)))->read(
|
||||
reinterpret_cast<char *>(area), size);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::png_write_data(const png_structp ctx, png_bytep area, png_size_t size)
|
||||
void PNGLibrary::png_write_data(png_structp ctx, png_bytep area, png_size_t size)
|
||||
{
|
||||
(static_cast<std::ofstream*>(png_get_io_ptr(ctx)))->write(
|
||||
reinterpret_cast<const char *>(area), size);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::png_io_flush(const png_structp ctx)
|
||||
void PNGLibrary::png_io_flush(png_structp ctx)
|
||||
{
|
||||
(static_cast<std::ofstream*>(png_get_io_ptr(ctx)))->flush();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::png_user_warn(const png_structp ctx, png_const_charp str)
|
||||
void PNGLibrary::png_user_warn(png_structp ctx, png_const_charp str)
|
||||
{
|
||||
throw runtime_error(string("PNGLibrary warning: ") + str);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::png_user_error(const png_structp ctx, png_const_charp str)
|
||||
void PNGLibrary::png_user_error(png_structp ctx, png_const_charp str)
|
||||
{
|
||||
throw runtime_error(string("PNGLibrary error: ") + str);
|
||||
}
|
||||
|
@ -483,4 +511,4 @@ void PNGLibrary::png_user_error(const png_structp ctx, png_const_charp str)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PNGLibrary::ReadInfoType PNGLibrary::ReadInfo;
|
||||
|
||||
#endif // PNG_SUPPORT
|
||||
#endif // IMAGE_SUPPORT
|
||||
|
|