Compare commits
2924 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
385b34933d | ||
|
22a2e0a165 | ||
|
9716212d70 | ||
|
27fdd39e5c | ||
|
b3ce74253e | ||
|
64a433a644 | ||
|
d3a3280f90 | ||
|
924fa315dc | ||
|
50ac621430 | ||
|
b424c4b2f7 | ||
|
ad259a55c0 | ||
|
f83bc75270 | ||
|
ec8aed3f3b | ||
|
b7678f5261 | ||
|
08e6de3186 | ||
|
aec384b4b0 | ||
|
253075bfd8 | ||
|
88de1f11f1 | ||
|
a4f0b478ea | ||
|
a6db3d6013 | ||
|
fb09f52093 | ||
|
58694a2935 | ||
|
f05dd784fd | ||
|
8011051eea | ||
|
2e2440fe74 | ||
|
85ca044ba5 | ||
|
052980f63f | ||
|
b8dcfcd59d | ||
|
5b88346537 | ||
|
20e5e18122 | ||
|
b948a1f3fd | ||
|
8215c03d62 | ||
|
8b2af8adf1 | ||
|
00f772b29d | ||
|
4107198548 | ||
|
e997ce0ce7 | ||
|
58c946f249 | ||
|
0b57886491 | ||
|
2db60c2b3f | ||
|
f54bfae01f | ||
|
c40221abb6 | ||
|
eb38034b76 | ||
|
c6a968ed74 | ||
|
e69f6b8579 | ||
|
cfbc7b481a | ||
|
1dfcdffa71 | ||
|
5b983bc7ad | ||
|
634b90e4fc | ||
|
b31cca77be | ||
|
ddc3dc2d47 | ||
|
5b17b41e07 | ||
|
239e0462c3 | ||
|
8505f00cdf | ||
|
08d58aa992 | ||
|
8cce6f7b13 | ||
|
ec8baa6329 | ||
|
9bd84978cf | ||
|
aa0fe30d5c | ||
|
6d6aafe887 | ||
|
003e8914b1 | ||
|
d7e1672ae7 | ||
|
1157ff0f36 | ||
|
bdd4522ca9 | ||
|
4abb5f3539 | ||
|
764b5e2d16 | ||
|
9b85864259 | ||
|
ed21294992 | ||
|
420146929c | ||
|
c84914ac83 | ||
|
b53bf3d178 | ||
|
aff7f1706c | ||
|
20ddad606f | ||
|
33d237706e | ||
|
a39efd31cf | ||
|
69bb4c3e95 | ||
|
ae2d68aaf3 | ||
|
e381ebd1ea | ||
|
34c29b052e | ||
|
4ebb108ae1 | ||
|
d1da91da7c | ||
|
490d63b26f | ||
|
be63d7eaa3 | ||
|
15588a065f | ||
|
d52a50353d | ||
|
5d70f93920 | ||
|
f3cbc1990e | ||
|
583c234953 | ||
|
3f744254fd | ||
|
7abedaed4c | ||
|
42ffbd18d0 | ||
|
8508eb7b7c | ||
|
00000971d7 | ||
|
58bd40b833 | ||
|
cbaf5c4c4a | ||
|
67d338164b | ||
|
7bf8145a91 | ||
|
e043279500 | ||
|
9d6f378d21 | ||
|
bfb1092cbb | ||
|
282140822e | ||
|
19a1e3ec1a | ||
|
1ad8bad18c | ||
|
9577cbce85 | ||
|
6dd2f609f2 | ||
|
976fe7a337 | ||
|
1400bd40e8 | ||
|
6a97192e8c | ||
|
42732b20eb | ||
|
f0a672c39e | ||
|
d211120312 | ||
|
6ab1be654b | ||
|
f706988171 | ||
|
bed9f8220c | ||
|
750112f6dd | ||
|
63a02d90bc | ||
|
795fba1320 | ||
|
1923c324d9 | ||
|
6a24b9206f | ||
|
30a8c4bf42 | ||
|
152e242485 | ||
|
c4e6161959 | ||
|
1951df3476 | ||
|
1cf84a5436 | ||
|
81c29fa371 | ||
|
8b27952680 | ||
|
3c58deb46f | ||
|
0fc08d93be | ||
|
cd82311c54 | ||
|
bf9212bcff | ||
|
dfd3b42929 | ||
|
18edb65680 | ||
|
3468d5de7e | ||
|
d146b3a309 | ||
|
71d4e60c57 | ||
|
8f21c8ed66 | ||
|
3ad28b7a8d | ||
|
edce971d8c | ||
|
6d9ab972d0 | ||
|
ed7d0546a3 | ||
|
474caaccd5 | ||
|
1d7ecb7f1b | ||
|
8c30a7c90c | ||
|
2b89923a6f | ||
|
8a0ff891bd | ||
|
9359f7a2d9 | ||
|
f1d52c53d3 | ||
|
9096f629c9 | ||
|
d50f9df974 | ||
|
15215000f9 | ||
|
4e35048f46 | ||
|
e2b22a0df6 | ||
|
9c958a1cb4 | ||
|
3cb04e88d1 | ||
|
917b62785c | ||
|
7b511dd76b | ||
|
04cd94de3f | ||
|
da0380c32d | ||
|
e76088cde2 | ||
|
abf108f6b8 | ||
|
fab91444dd | ||
|
9442a2a8e8 | ||
|
9793e15f4d | ||
|
670540116a | ||
|
1354b77373 | ||
|
63e081e9c2 | ||
|
4d28af4fcf | ||
|
a659de9960 | ||
|
d6b7157a0c | ||
|
48cc359f0c | ||
|
6549684e1f | ||
|
150855f2e9 | ||
|
215a690e92 | ||
|
1d5cb77464 | ||
|
b5761c29d5 | ||
|
7994869b1f | ||
|
ac54d5b7ec | ||
|
9df4f22873 | ||
|
d049dfe983 | ||
|
4c904d11ff | ||
|
aa5fc484d1 | ||
|
849ae42b99 | ||
|
fe72561a8f | ||
|
e5950aa4ef | ||
|
5180e8e03b | ||
|
67dee21804 | ||
|
007d3b2555 | ||
|
9ff3bffddd | ||
|
12859683b7 | ||
|
27a064caff | ||
|
b4fc2ff7ba | ||
|
fe2c868d6c | ||
|
150f0fcad4 | ||
|
a39b1913b8 | ||
|
1ab690ba18 | ||
|
c3d83eae22 | ||
|
117da602ca | ||
|
a0c5b6f97a | ||
|
7e071e463d | ||
|
ad2360b5c3 | ||
|
ee3f37b39c | ||
|
ebfc877c1c | ||
|
8f9e1e9ea5 | ||
|
1bf57ece70 | ||
|
29d8cca511 | ||
|
14cf76776a | ||
|
f1f97f0692 | ||
|
0b5be876b3 | ||
|
fdc39f9bd6 | ||
|
14e486017a | ||
|
3bee0deda5 | ||
|
101e894314 | ||
|
2e6ff5fd9f | ||
|
2b3ec9d991 | ||
|
375fb4388c | ||
|
fc76063ec0 | ||
|
6568cca6bb | ||
|
d386ca8726 | ||
|
f21761338c | ||
|
41af62d793 | ||
|
2dfde867a9 | ||
|
6efefab526 | ||
|
207dc993d4 | ||
|
b815744b4c | ||
|
52d5169cc8 | ||
|
73a6d35f73 | ||
|
2498456bcc | ||
|
ec65cfd942 | ||
|
122549d3cd | ||
|
e13048d07b | ||
|
6eeba2f6f6 | ||
|
cdef244f38 | ||
|
1fac8870d4 | ||
|
741637e625 | ||
|
73168aa7f2 | ||
|
7e5996df82 | ||
|
52de44049c | ||
|
f5c7c4443d | ||
|
db5fa8df4c | ||
|
177859bec6 | ||
|
bd3799d431 | ||
|
e533b59759 | ||
|
38e2760531 | ||
|
447cdf2672 | ||
|
062d44e065 | ||
|
f33f3f6951 | ||
|
291887cd10 | ||
|
8ded1ca3b3 | ||
|
710d92cbdd | ||
|
2aa4726e01 | ||
|
3a7e5ecac5 | ||
|
5d952565c9 | ||
|
42be4ef827 | ||
|
1931c2830f | ||
|
8cb94e7a8b | ||
|
8c8e59cd81 | ||
|
ece40bcf0e | ||
|
392bc8c0d9 | ||
|
8e3d8c4a18 | ||
|
92f425655d | ||
|
9fbbea23d3 | ||
|
df4981787c | ||
|
4adbcdc017 | ||
|
0fd8f56a6e | ||
|
50a56a4b68 | ||
|
11f70c09af | ||
|
a372b2ec0f | ||
|
7127e3e068 | ||
|
f1b187d512 | ||
|
11b9c4fab7 | ||
|
b88a3a02a9 | ||
|
619792db7f | ||
|
bd5d01c0a4 | ||
|
4647c55949 | ||
|
d97c2fb701 | ||
|
712ed9b6b0 | ||
|
d4c715b5f0 | ||
|
8dda5ee098 | ||
|
5b33cebca9 | ||
|
6178ff2a78 | ||
|
fc508427b8 | ||
|
430e42fa72 | ||
|
c7c54abb6b | ||
|
b6c6b9ed54 | ||
|
f0bab07f26 | ||
|
645ef429bc | ||
|
a7d977a5c5 | ||
|
795d772c83 | ||
|
2b2bb3569b | ||
|
fb8508ea20 | ||
|
461083523a | ||
|
b8e32e6d53 | ||
|
d5c6ed9510 | ||
|
47cdefd3d0 | ||
|
53fc5a74ed | ||
|
035291b955 | ||
|
5f71ec4974 | ||
|
5eb0e5d605 | ||
|
b1ea179513 | ||
|
d34579e3bb | ||
|
64cf389edf | ||
|
0c9cf8d594 | ||
|
44b70bf275 | ||
|
06c6ce7d65 | ||
|
9d4d535758 | ||
|
136e11cc13 | ||
|
18206718e3 | ||
|
c3e3fb91cc | ||
|
a4525c3336 | ||
|
5dbddb344d | ||
|
a66d4ea64c | ||
|
3dad68618e | ||
|
366c374461 | ||
|
6e1112157c | ||
|
488f17941f | ||
|
1dde5c1ce1 | ||
|
17f1b91b8c | ||
|
4f25521cba | ||
|
64ad67d5a5 | ||
|
a26c57d582 | ||
|
64d45dd23a | ||
|
8e2769b946 | ||
|
4cc34f97ec | ||
|
323f3e89b7 | ||
|
482b9a1562 | ||
|
c6103d23fa | ||
|
0b6a73f380 | ||
|
d873abfadf | ||
|
446fc15521 | ||
|
b3cecf2413 | ||
|
e4ceb3d93b | ||
|
cee486ab11 | ||
|
407e540638 | ||
|
8db2490077 | ||
|
d42aad2b84 | ||
|
3bf94d281a | ||
|
66da5fd530 | ||
|
5c21c5e985 | ||
|
25576899d8 | ||
|
d07b199668 | ||
|
ad5ca0dcf0 | ||
|
9991c3b0b4 | ||
|
c9dfc86291 | ||
|
2bf5819c36 | ||
|
08178c9f3a | ||
|
3581945d85 | ||
|
77b7f861f3 | ||
|
9588cf44aa | ||
|
3116f63e37 | ||
|
496baafbf9 | ||
|
7f110c4415 | ||
|
b5cd06a41e | ||
|
d55426afa0 | ||
|
d1b4af5e76 | ||
|
eebdbbfd5b | ||
|
60ff8577bb | ||
|
a3128d89c0 | ||
|
2018f0ee01 | ||
|
76c93254ed | ||
|
e578843745 | ||
|
8600f96fa2 | ||
|
cb7cc44b7b | ||
|
2c5455e35d | ||
|
0b77662504 | ||
|
b2d1086e2e | ||
|
93cc19b3b9 | ||
|
0bc0618a6a | ||
|
322f3c7013 | ||
|
5be5bc4709 | ||
|
ee3878e43a | ||
|
b1fec62564 | ||
|
2bf8feb299 | ||
|
e5e9cf145a | ||
|
5408fe8dd2 | ||
|
eba7e2dde9 | ||
|
1d613adac2 | ||
|
ebf4d1d0ee | ||
|
6c613d3b0c | ||
|
302eaf6eca | ||
|
7758713f86 | ||
|
19cf8d26b1 | ||
|
c9700dfb29 | ||
|
44a35e57f6 | ||
|
038a2c5892 | ||
|
2ea0932726 | ||
|
5d06f45c0f | ||
|
c5b3e47925 | ||
|
bd31258725 | ||
|
b40ba73533 | ||
|
fe917efad5 | ||
|
3fe9de88a2 | ||
|
86cf0c4d84 | ||
|
b63ddc6e3d | ||
|
4a42dc073b | ||
|
a791f7e621 | ||
|
3f799f21ff | ||
|
a80a19b418 | ||
|
2b37404447 | ||
|
514e27d975 | ||
|
a39445e63b | ||
|
3caf6183bc | ||
|
0f6299edfc | ||
|
0b0abce956 | ||
|
60d77a6931 | ||
|
7ed8fb1de9 | ||
|
66ec48e0eb | ||
|
00dce71eab | ||
|
d7523d27e8 | ||
|
e7792c16b2 | ||
|
5e2b6e7e9e | ||
|
a125da6a98 | ||
|
8739da61c0 | ||
|
efc93d0422 | ||
|
17c962e500 | ||
|
2d29ece3b8 | ||
|
6eedee78db | ||
|
8aa19fe092 | ||
|
17f0ff2cf7 | ||
c382f7ea5a | |||
|
df59294c38 | ||
|
6d6982abee | ||
|
cd2275c129 | ||
|
7113c5484b | ||
|
633ea9df90 | ||
|
ba45911734 | ||
|
de0046d7d6 | ||
|
b583f62e7b | ||
|
950c0d5524 | ||
|
06bc4cd0bf | ||
|
3ef8fab7c4 | ||
|
153cdb2e11 | ||
|
5e4a1f6db7 | ||
|
8c9c97b74f | ||
|
42474a0859 | ||
|
a3a751b1b6 | ||
|
6d7dad9ce5 | ||
|
e3b240147a | ||
|
79770f6207 | ||
|
ccbe394e7d | ||
|
6edc35804c | ||
|
8017a4a044 | ||
|
4faca659c1 | ||
|
e79f2c1764 | ||
|
9c13590f30 | ||
|
0c81f36269 | ||
|
27b5935b8d | ||
|
8d063391a4 | ||
|
9f53fcc30b | ||
|
4cf3b3c948 | ||
|
a9c01d35fc | ||
|
686a506e17 | ||
|
5fb6d55c67 | ||
|
226825bda4 | ||
|
927b7493e5 | ||
|
e9c2c866eb | ||
|
97e8df29c5 | ||
|
f725e70e84 | ||
|
4569114cab | ||
|
d51dcaca19 | ||
|
10eb15bb90 | ||
|
91f2a82f19 | ||
|
8cf319e941 | ||
|
e666ec09db | ||
|
c9fb3b3ec6 | ||
|
e89df2df43 | ||
|
b516f9a3ee | ||
|
2e38cec98b | ||
|
8ed46a6a58 | ||
|
27d42146ba | ||
|
00e1c925a4 | ||
|
9619500445 | ||
|
9cc70c085f | ||
|
746204e57c | ||
|
3fd09ffcde | ||
|
6e923645d3 | ||
|
c7c2d08dc5 | ||
|
fcf31be735 | ||
|
d8905f57bf | ||
|
8b2f683c20 | ||
|
404e153744 | ||
|
9f56f5fee0 | ||
|
977d941f48 | ||
|
34c9d4c791 | ||
|
40ded1114f | ||
|
fbd1d06f1c | ||
|
1c0f65177f | ||
|
b51aac4bf5 | ||
|
68ba89cf43 | ||
|
8642715a6d | ||
|
6d3a65759e | ||
|
eba273d89c | ||
|
bce413821d | ||
|
1c8a14ff1c | ||
|
5823bf9d70 | ||
|
ecbdb9e95e | ||
|
35a91768b4 | ||
|
a795514bc4 | ||
|
40486d61c2 | ||
|
9560959fef | ||
|
2b7bc3b08e | ||
|
3f93cd4393 | ||
|
dab534b658 | ||
|
8657d3e4b6 | ||
|
aff42affc0 | ||
|
0ece951173 | ||
|
d267d83cec | ||
|
e59bc436bd | ||
|
55925d9149 | ||
|
340d4e0630 | ||
|
3ab6150508 | ||
|
5192e3a07b | ||
|
d662407df0 | ||
|
4f69e4e86c | ||
|
816cdf2c62 | ||
|
7542de74e7 | ||
|
6b6800445f | ||
|
240d8d1ffa | ||
|
3bad68f2ab | ||
|
3168e0e1fa | ||
|
e3fcc35922 | ||
|
7e6f1f866e | ||
|
10955abe6c | ||
|
18afbc3770 | ||
|
3389f50884 | ||
|
c709ea0d98 | ||
|
12ad85355c | ||
|
a9ce9f538f | ||
|
0b54eea084 | ||
|
e40e254add | ||
|
fb3db82d42 | ||
|
ac45888a37 | ||
|
aedb3e2332 | ||
|
048da6e6d1 | ||
|
4ab256d896 | ||
|
10d996330c | ||
|
29becc2870 | ||
|
d209628369 | ||
|
323b6fafa8 | ||
|
f2466fd770 | ||
|
dd1330d707 | ||
|
61f3c8d7f3 | ||
|
54f45f2fd3 | ||
|
636349d5f2 | ||
|
a5903ca5bc | ||
|
df1b89bf61 | ||
|
d93c1e501c | ||
|
8cb4085218 | ||
|
803abd9925 | ||
|
49ec02b3b3 | ||
|
e9be438d91 | ||
|
ea05fa0c3e | ||
|
1b50856dcf | ||
|
207851bc56 | ||
|
57b50cab63 | ||
|
16294baa05 | ||
|
074d152a4e | ||
|
dad9e4b704 | ||
|
9148b26bd8 | ||
|
4213524286 | ||
|
ae855d470d | ||
|
ec9536eede | ||
|
7bdf8dbe47 | ||
|
5c7b1f01a3 | ||
|
951d0b07f0 | ||
|
7ec3077079 | ||
|
de9fc76a2c | ||
|
d61e5f248d | ||
|
daf713132b | ||
|
fef175dcc6 | ||
|
e658f50da2 | ||
|
bed26daf73 | ||
|
d62132be38 | ||
|
ee9b6c1444 | ||
|
406189b79e | ||
|
6eb42ab283 | ||
|
be171cfe66 | ||
|
3ca0504e67 | ||
|
4254dcdb2c | ||
|
b8d6bb7fd2 | ||
|
c234111024 | ||
|
996ebaafa3 | ||
|
96e337edac | ||
|
40b7e25126 | ||
|
06621d1dfe | ||
|
3e3ac23432 | ||
|
c6e187a80b | ||
|
32a419ad2e | ||
|
237e127b36 | ||
|
4421dedbb9 | ||
|
479c16e698 | ||
|
aaba172c02 | ||
|
5b37d3c402 | ||
|
9a5aa6b5c8 | ||
|
a6de76eb2b | ||
|
47ce95afb5 | ||
|
147341a1d4 | ||
|
5cefce5c08 | ||
|
a22c5c3eeb | ||
|
7ac920d2be | ||
|
502f64e6d7 | ||
|
e48eb3515d | ||
|
cc4baa1d28 | ||
|
1c8397e8f3 | ||
|
f145f05f15 | ||
|
29e920697a | ||
|
22afa576c2 | ||
|
42ce9c410b | ||
|
ef8f3aff66 | ||
|
8dd5e6d9b8 | ||
|
59ecd4b9bc | ||
|
947687ac0d | ||
|
3f033e1e53 | ||
|
175af178bd | ||
|
4f8b081f82 | ||
|
f79f18704d | ||
|
38a130714f | ||
|
801e61a4e7 | ||
|
91c75141a8 | ||
|
e1be593a65 | ||
|
c0d6c3d6bb | ||
|
ed01c569d4 | ||
|
30e2a7b7e4 | ||
|
a040b1b395 | ||
|
c8b3b080a8 | ||
|
830f2ddc38 | ||
|
2b6cf0c8f1 | ||
|
93aa93e42c | ||
|
65a646f050 | ||
|
4c8f364ad7 | ||
|
c36c7126f8 | ||
|
7f3b3879a0 | ||
|
1757e1b128 | ||
|
d5ff93af3b | ||
|
c06e320b95 | ||
|
b032b89457 | ||
|
9972ce999d | ||
|
8755e505d5 | ||
|
2e1f4445e9 | ||
|
8edbbbdf49 | ||
|
0cf095dd21 | ||
|
0cf3aec939 | ||
|
bbf6b66251 | ||
|
5ec10d3c9a | ||
|
ed39e6258d | ||
|
fabc3901b8 | ||
|
ff12bd2bec | ||
|
df248736c8 | ||
|
6829ebf44a | ||
|
e1075b1bdc | ||
|
b2bbd9cfdc | ||
|
8b1b5b9348 | ||
|
8557a2c1ec | ||
|
e7cce8fdde | ||
|
defd8d4f69 | ||
|
413212f993 | ||
|
f7ad805559 | ||
|
8ea5e8d74d | ||
|
6ddc3b0f0a | ||
|
e582e38abc | ||
|
1cc131227c | ||
|
31c53e8e05 | ||
|
e0b77d3821 | ||
|
2530370f90 | ||
|
1fde385cd7 | ||
|
d32bff58a4 | ||
|
21f21f6bc7 | ||
|
322ead9b93 | ||
|
3b1fc41064 | ||
|
00367a79b4 | ||
|
181a236fce | ||
|
6673427c54 | ||
|
0549dc702c | ||
|
a838c31d02 | ||
|
7f0ad795ec | ||
|
e04aeebc0a | ||
|
1c1d6bec78 | ||
|
d0f17cfaed | ||
|
76500ebf15 | ||
|
ffc80b2c0d | ||
|
e0af961ad3 | ||
|
3e75016fe0 | ||
|
7624688e3b | ||
|
be765a3e7e | ||
|
4c5d896630 | ||
|
093998389c | ||
|
0441967332 | ||
|
d9bf739f52 | ||
|
7ed8169d30 | ||
|
aa8b7b0c03 | ||
|
d90ecec085 | ||
|
f5092c00de | ||
|
88e64fadda | ||
|
c92a2c2131 | ||
|
7a390414ff | ||
|
0e6803aaa9 | ||
|
bd6843444f | ||
|
29d6960075 | ||
|
37785f779f | ||
|
0989ee2763 | ||
|
288bd84d19 | ||
|
1247d00cbb | ||
|
c0c60c83a8 | ||
|
43e42b2dca | ||
|
9e5d3e449b | ||
|
bbe425e695 | ||
|
f1e912b64f | ||
|
31340d2a90 | ||
|
717606dda9 | ||
|
1a85abfd2a | ||
|
b6e38bfa5f | ||
|
e1fa28bd54 | ||
|
052e2429e0 | ||
|
cfee59918e | ||
|
2776c8ad36 | ||
|
5ef668251c | ||
|
a43c293629 | ||
|
354f68a861 | ||
|
6547137389 | ||
|
36f084f474 | ||
|
a450ab2a8e | ||
|
eeb15c74f9 | ||
|
0d1f686d68 | ||
|
87a2b0c842 | ||
|
6536754944 | ||
|
36149dfa9f | ||
|
4649cdd290 | ||
|
5d5ff1702e | ||
|
9b202c670e | ||
|
4180348567 | ||
|
eef8b8448c | ||
|
ac9e36bc1a | ||
|
e49527eff8 | ||
|
1720638017 | ||
|
ec6612d445 | ||
|
90b3e1ff38 | ||
|
b3d9404055 | ||
|
cbb7e018b8 | ||
|
832c7463bc | ||
|
51510b53fd | ||
|
c0966ceeba | ||
|
55507274d6 | ||
|
36cf778232 | ||
|
ecaa92f853 | ||
|
cb33119114 | ||
|
98e986b48b | ||
|
e545413a42 | ||
|
51aa09517d | ||
|
93eb32c40f | ||
|
abaf471350 | ||
|
ea40a7be05 | ||
|
0ebfdb840a | ||
|
14c4548325 | ||
|
c9a22ddfd1 | ||
|
7917984376 | ||
|
c580c44ad3 | ||
|
4f78e4b109 | ||
|
8d2e01c4b6 | ||
|
9208f82d09 | ||
|
2f00211321 | ||
|
b380f71886 | ||
|
c368c77d28 | ||
|
5194a41d99 | ||
|
7efd26c548 | ||
|
70332621cb | ||
|
e7de1fccab | ||
|
9fcac76a03 | ||
|
58750424c7 | ||
|
2c7343a6ad | ||
|
6ecc2f15b5 | ||
|
9bf7e0b4df | ||
|
95773b9538 | ||
|
52ab200544 | ||
|
f0959d4e70 | ||
|
779ffe3e1b | ||
|
ab07f955e4 | ||
|
ae1d3ddf6c | ||
|
a005ebe417 | ||
|
1bdd58d051 | ||
|
7b5846fbaf | ||
|
d6adbe0c7f | ||
|
9383acda34 | ||
|
44618f75c4 | ||
|
352f8d54f8 | ||
|
3f7bcb9af2 | ||
|
0894c1dcda | ||
|
86a05e2591 | ||
|
84a193a918 | ||
|
f3915a6494 | ||
|
859ff79527 | ||
|
1414e68a76 | ||
|
99ac632d3a | ||
|
f6de7b3fbd | ||
|
12655cb50c | ||
|
f47e143e75 | ||
|
e0436e33d4 | ||
|
43e1e85179 | ||
|
ae14fcfbd7 | ||
|
c5362023c8 | ||
|
bcfe36897c | ||
|
dd435ae5f0 | ||
|
53dd19ec35 | ||
|
10df4d7a13 | ||
|
45bd5342e7 | ||
|
0c2772942e | ||
|
dbd33684e8 | ||
|
4db047c7d1 | ||
|
6f9da353bd | ||
|
03f4f03661 | ||
|
5cd65f845d | ||
|
4b03cc05c1 | ||
|
0f31c7a1ba | ||
|
a524cc3105 | ||
|
33ba353c3a | ||
|
0e1d6545e9 | ||
|
04afa64597 | ||
|
8e125b31f6 | ||
|
2a29570f17 | ||
|
dd24801507 | ||
|
6a8743e13a | ||
|
93c611e9bc | ||
|
bb8f973fb4 | ||
|
f5f79f88ab | ||
|
f75f170448 | ||
|
029b7492b6 | ||
|
537d0e1b25 | ||
|
ee407f07f3 | ||
|
1fedb81ab7 | ||
|
3a86b868fe | ||
|
349114097b | ||
|
08549c1395 | ||
|
541dbc5db3 | ||
|
de10338962 | ||
|
110deee6f8 | ||
|
43210876be | ||
|
8760cc5517 | ||
|
91a2b459f9 | ||
|
d48037beec | ||
|
8fa02e0ea2 | ||
|
7a24073f6d | ||
|
64db300f24 | ||
|
09cbf6a13f | ||
|
a856566b54 | ||
|
d31f34cab4 | ||
|
96b5306ff3 | ||
|
cbf1a5481f | ||
|
9a966a5581 | ||
|
500e767247 | ||
|
f9401300b5 | ||
|
56deb4b92e | ||
|
eceb2e4830 | ||
|
0dbfaef4cf | ||
|
88f5b22bf6 | ||
|
d9b8e829a5 | ||
|
856a2b0ebe | ||
|
004c20d8e2 | ||
|
3c4bfd2a1b | ||
|
faccdd3e9b | ||
|
e466c3c5b1 | ||
|
7071032288 | ||
|
887a8104f5 | ||
|
a773297b3a | ||
|
63a858d767 | ||
|
1065a40d8f | ||
|
f2429e1c25 | ||
|
96d127e160 | ||
|
1b38e8c932 | ||
|
52a4c09855 | ||
|
6a24598266 | ||
|
aaf9a76b67 | ||
|
58df8144ec | ||
|
16913f925b | ||
|
9a765820cc | ||
|
fd6b734fd0 | ||
|
9ae2c9fd54 | ||
|
8f8b7f6b33 | ||
|
ec4c1948f5 | ||
|
22f8ab6509 | ||
|
517f455486 | ||
|
9b5dc9eca7 | ||
|
b932f6699e | ||
|
20e9b1c655 | ||
|
3fbeb61c09 | ||
|
ab4fa3a478 | ||
|
4d90504688 | ||
|
d41c188cfd | ||
|
24796acccf | ||
|
979d32faed | ||
|
197a475fab | ||
|
426d3d3a37 | ||
|
4f91b19a94 | ||
|
abf6e5632c | ||
|
eb60dbce0d | ||
|
12891c641b | ||
|
6bd7b96ed5 | ||
|
95f5eeb40b | ||
|
c79e67b8cc | ||
|
cdfcc4ca2d | ||
|
6055092249 | ||
|
5cc845d715 | ||
|
706135113c | ||
|
8c86cff486 | ||
|
bb836662dd | ||
|
87fdf91e0c | ||
|
f866284b49 | ||
|
4521bb4767 | ||
|
a68f749c3a | ||
|
cb73e0b91a | ||
|
6337e3e43a | ||
|
ac29b4391e | ||
|
69a5ed3396 | ||
|
36e2896ec7 | ||
|
bef1529bb2 | ||
|
851d44869f | ||
|
18126994ff | ||
|
51cf4c638c | ||
|
de21e8d628 | ||
|
bfdab8f246 | ||
|
b2edcc9543 | ||
|
2a034d4ebe | ||
|
339de0db96 | ||
|
9c271a637d | ||
|
019f262531 | ||
|
9e8f918b27 | ||
|
b31bd58642 | ||
|
dc16104cfd | ||
|
79945c8c18 | ||
|
9c7bed97d5 | ||
|
86a1977034 | ||
|
9fe965bcc2 | ||
|
b5e271386a | ||
|
ef15c9b160 | ||
|
d713ba85c7 | ||
|
ab109da683 | ||
|
5e119548e9 | ||
|
0925b06555 | ||
|
965e623637 | ||
|
7350843cca | ||
|
c78a003712 | ||
|
a621803e82 | ||
|
777013e998 | ||
|
2c635c7a87 | ||
|
641f26e13e | ||
|
8073e3d39e | ||
|
4d74719d56 | ||
|
f52152b2c9 | ||
|
586459bb74 | ||
|
7c8b9cf05a | ||
|
a48f251039 | ||
|
9a2e8e1acf | ||
|
f02bb2f0e6 | ||
|
3c6a46830d | ||
|
4c6bc91ded | ||
|
a4209b47d0 | ||
|
efe31cefc9 | ||
|
c730ba767b | ||
|
f8a105e8d0 | ||
|
97c758ba75 | ||
|
4e27558ac2 | ||
|
850e7bb78c | ||
|
b5eea012cc | ||
|
6a8db89ae5 | ||
|
1c6ecc2e14 | ||
|
e7236deb11 | ||
|
ba5416ee5b | ||
|
320aff1d1e | ||
|
864f0927be | ||
|
7c5704621a | ||
|
37ca174f37 | ||
|
cead58471d | ||
|
76b881c2e1 | ||
|
967fdadd7c | ||
|
1a41957b3c | ||
|
ad1f019893 | ||
|
941afee3ba | ||
|
dbb14d7040 | ||
|
44ee6dc73f | ||
|
a7f7530eed | ||
|
4bebd2bc33 | ||
|
3a2d028efa | ||
|
9e3ad31df1 | ||
|
26656de44f | ||
|
81e2ec08e0 | ||
|
aa5a279116 | ||
|
0ab7bf7749 | ||
|
196aaaa7ed | ||
|
8676a7c7bc | ||
|
f810a2cd60 | ||
|
582a5588ba | ||
|
56b14c67aa | ||
|
95153af1d6 | ||
|
13e0b90b47 | ||
|
ee03b1e433 | ||
|
cce36f1754 | ||
|
e903333c7e | ||
|
ab75858c86 | ||
|
b45761146f | ||
|
3133687e68 | ||
|
dbe9035c55 | ||
|
5088bd0959 | ||
|
e922b3fc4a | ||
|
7c9ab0fd46 | ||
|
eaeeb49612 | ||
|
b92dd51101 | ||
|
adfc329cdf | ||
|
5cf71b406e | ||
|
d92148b461 | ||
|
ffa53eda20 | ||
|
4ce8e77796 | ||
|
20cbc896a1 | ||
|
fefb81ab65 | ||
|
ec012cf9f8 | ||
|
c4a14ac4db | ||
|
b1187919d3 | ||
|
2c71ca789f | ||
|
8df572f92e | ||
|
b7f03dea8d | ||
|
ab1d4cd26e | ||
|
5e7bb0f891 | ||
|
79ec22b28e | ||
|
5c17c0ec3b | ||
|
cd16431699 | ||
|
81e45b00b9 | ||
|
c7298ae5a6 | ||
|
8e675295a8 | ||
|
bc073e3d09 | ||
|
52c5610528 | ||
|
38eafeb0cf | ||
|
97652b7460 | ||
|
59c315a5dd | ||
|
b72c2ea225 | ||
|
769aac93c0 | ||
|
db50462710 | ||
|
59dfb1a85a | ||
|
6ffe924637 | ||
|
d178ece909 | ||
|
6e7ba7589c | ||
|
66f7babe86 | ||
|
c53d99dbc4 | ||
|
c5f6be1e64 | ||
|
69de3f0fae | ||
|
f3277ab8d3 | ||
|
e9906e44cd | ||
|
f866441481 | ||
|
e9629407a5 | ||
|
cdc3321c36 | ||
|
eaccd792ed | ||
|
5127cb0022 | ||
|
c63ddbe771 | ||
|
c3d9141b7c | ||
|
c1ae129ed4 | ||
|
f78fac12c2 | ||
|
7e5e672988 | ||
|
a30247cf16 | ||
|
7508ddb0cf | ||
|
e087bd5218 | ||
|
9e57201b08 | ||
|
25e3414974 | ||
|
4b3c77bfa5 | ||
|
8660e20eeb | ||
|
b770bbea2e | ||
|
486f8a2c10 | ||
|
06b744259b | ||
|
bdbe02b043 | ||
|
33090a5cc0 | ||
|
d0a9d2f72a | ||
|
f1e5e04198 | ||
|
d0d39015ee | ||
|
f08f16346e | ||
|
d94c8b9125 | ||
|
d15eaf4134 | ||
|
ae930472f0 | ||
|
7a78649e21 | ||
|
06ce30d3a8 | ||
|
c6f39bc60b | ||
|
02f55d12d3 | ||
|
1650820edb | ||
|
18e7a3f4fa | ||
|
fbf1bb7f98 | ||
|
5565c2540b | ||
|
4a7afb246d | ||
|
178860e715 | ||
|
f237b1e9b9 | ||
|
6fc6bf14a3 | ||
|
74f6ffe89b | ||
|
6df1807068 | ||
|
6cd13be624 | ||
|
b54365fc40 | ||
|
72b6d6c532 | ||
|
43831d0bc1 | ||
|
0f6a0186cd | ||
|
deb037d87d | ||
|
4498d16bed | ||
|
8d319c65c2 | ||
|
0d7cc66ffd | ||
|
0dcd233cbb | ||
|
fd8c9bba5d | ||
|
1f7b20251b | ||
|
93ef8d7db8 | ||
|
739a9eb2bf | ||
|
e6c4ceaf5a | ||
|
2ec573c84a | ||
|
5b9746084d | ||
|
18007f0e53 | ||
|
5808d4485f | ||
|
fc10a90dec | ||
|
3f954f1d0c | ||
|
0e6b9da42d | ||
|
1376c386a2 | ||
|
2f2e469790 | ||
|
e04dcd90d6 | ||
|
94776fcf8c | ||
|
de16ab5d08 | ||
|
886363b398 | ||
|
7ef198ec50 | ||
|
f1b8164613 | ||
|
40fc477b56 | ||
|
4ce643d5eb | ||
|
01f80a3f3e | ||
|
8f9365251d | ||
|
b580e63c37 | ||
|
d263a8f6f8 | ||
|
46e1b79b63 | ||
|
6b947c46bc | ||
|
893d7d162a | ||
|
85da5b64d3 | ||
|
a7c8b702da | ||
|
f1761340fc | ||
|
3b1094058b | ||
|
004b004f98 | ||
|
191f7cee02 | ||
|
164a870189 | ||
|
24af1c5a31 | ||
|
c05c3c2abd | ||
|
d4999fbbdb | ||
|
ef053ff113 | ||
|
d1caeafe5e | ||
|
9a957674d9 | ||
|
345e51647f | ||
|
8068ff41fb | ||
|
20d580881a | ||
|
1050a7a533 | ||
|
6e2abe23ef | ||
|
7aca04f4c4 | ||
|
24a7467735 | ||
|
84c5f8b92d | ||
|
51be70275d | ||
|
2dc0e14d0a | ||
|
c25c94d142 | ||
|
c5d91fc448 | ||
|
336bc65dbf | ||
|
d8a9f12a4f | ||
|
e5809740a5 | ||
|
b27bd4eed7 | ||
|
e5454a39b7 | ||
|
0ca1ee6a35 | ||
|
eefaac3d04 | ||
|
3c6d094763 | ||
|
50bf8c4919 | ||
|
063e645ff2 | ||
|
3ccb543622 | ||
|
8c1f41e65a | ||
|
56e359af28 | ||
|
139a44b142 | ||
|
fba00e5d34 | ||
|
d31ac2e10b | ||
|
de500cd397 | ||
|
c459058156 | ||
|
48397683b8 | ||
|
0b2411ecc6 | ||
|
c7e8d7fa13 | ||
|
6138833b28 | ||
|
690a263648 | ||
|
41f30f348a | ||
|
0ff882f3bc | ||
|
b454ee28db | ||
|
4d1a28f1d1 | ||
|
e8105c46a7 | ||
|
1d7692cff5 | ||
|
a5325d3374 | ||
|
6f6f72dcbd | ||
|
efb644bc72 | ||
|
52d9bfde94 | ||
|
75ec1c0334 | ||
|
e1453f1961 | ||
|
278224299f | ||
|
94add1d172 | ||
|
a2d34c9bd9 | ||
|
ceacc226bc | ||
|
23e8cc58c5 | ||
|
b4709fd66b | ||
|
339613263c | ||
|
a12ec3c8c8 | ||
|
7a6ae2d951 | ||
|
e71d3a7d3c | ||
|
b444ecd1ee | ||
|
1e5e236e84 | ||
|
ebb0cb5e81 | ||
|
3ed18a76da | ||
|
64d484476d | ||
|
033f025851 | ||
|
75d3470d55 | ||
|
fcbbecea17 | ||
|
2afeb7dee3 | ||
|
ea67a7e3f0 | ||
|
9b2dfe7ae2 | ||
|
e9ab7fa7df | ||
|
c944142b36 | ||
|
a4a8ad00d5 | ||
|
0dff3ef144 | ||
|
1d0366052d | ||
|
898ef2c981 | ||
|
ea05a0c765 | ||
|
ac5b0aca2c | ||
|
0e8d8effdf | ||
|
a2d3b8c174 | ||
|
c29edc1963 | ||
|
2971b17701 | ||
|
5f2e893828 | ||
|
d9b9385eb4 | ||
|
939817df73 | ||
|
e8158be454 | ||
|
9fcdc082d2 | ||
|
817c4a7752 | ||
|
87a2d48675 | ||
|
f0a6488546 | ||
|
2078c2a8fb | ||
|
98a39ae49a | ||
|
b325148544 | ||
|
ba6e22dfc0 | ||
|
55e05c89c2 | ||
|
dd86077410 | ||
|
8a84a5897e | ||
|
c1509b6339 | ||
|
6f0b640702 | ||
|
79f109b463 | ||
|
43fb86320e | ||
|
0af4f1fa4d | ||
|
24915e41eb | ||
|
976f5e4d02 | ||
|
fada772cb1 | ||
|
dfdbff7304 | ||
|
6ee488688b | ||
|
a3a73602fc | ||
|
5b993ed775 | ||
|
4346b063f5 | ||
|
9c1889f450 | ||
|
9a1f962281 | ||
|
251dd15ff9 | ||
|
80f422d0ca | ||
|
763de9d2e0 | ||
|
42471095e4 | ||
|
0c5e15b49d | ||
|
f24489b983 | ||
|
44c75ae7be | ||
|
ad05eb6d0a | ||
|
955ef59140 | ||
|
f89c80caa5 | ||
|
d0bbf383d6 | ||
|
6ddfcc9725 | ||
|
77384a5f6a | ||
|
20ffa27dd4 | ||
|
4ea984b688 | ||
|
34af95da9e | ||
|
1c31812ffd | ||
|
7a558492b6 | ||
|
e6fa2336da | ||
|
f67d3947d6 | ||
|
83e76c87eb | ||
|
bb3a73ff88 | ||
|
9996c7b4a2 | ||
|
39c71b40e7 | ||
|
328e2d9e40 | ||
|
6b8eb8063a | ||
|
b7348b5478 | ||
|
e460b0a7b4 | ||
|
9314bcf98d | ||
|
48ec3e6413 | ||
|
8adaba237e | ||
|
b9030bb2d0 | ||
|
aca2fd04b1 | ||
|
659f954028 | ||
|
a52302f2f6 | ||
|
75bc1e9a86 | ||
|
925bd863c0 | ||
|
da1003263f | ||
|
ad54dc57b0 | ||
|
f57657f27d | ||
|
73b275a7d0 | ||
|
5c1b89e82d | ||
|
5a966bba91 | ||
|
f50d9310a7 | ||
|
4d67fa8e80 | ||
|
ea97c1dc0b | ||
|
d2ed1343e5 | ||
|
c6ea57209f | ||
|
f21fd33cc3 | ||
|
975d379d76 | ||
|
2d593a95e3 | ||
|
57080c48bc | ||
|
6a995bfe10 | ||
|
ec7d756e3b | ||
|
0fbd714d4a | ||
|
81bfea9ba2 | ||
|
d2eb8e0996 | ||
|
5cc2dcc864 | ||
|
d50514ede9 | ||
|
5cd920d363 | ||
|
1fdb4f09b4 | ||
|
c9665d0449 | ||
|
ec2661ac03 | ||
|
e8bfc4050e | ||
|
0a4cb8148f | ||
|
54d733f356 | ||
|
1dae345b24 | ||
|
e57b5dd57e | ||
|
a59cd856c7 | ||
|
cd2e4b3cef | ||
|
3c0f4d458d | ||
|
aebc11744c | ||
|
2b263937da | ||
|
0a983b788e | ||
|
ce44773caa | ||
|
cb721dae5d | ||
|
34b0404ffa | ||
|
bae91cdb1d | ||
|
72cb391612 | ||
|
71c6fa45e0 | ||
|
a13469c4e2 | ||
|
e08df2a089 | ||
|
807712b9c2 | ||
|
9fa564f97c | ||
|
6ec4583aa0 | ||
|
fa5420136e | ||
|
4c05ebcea6 | ||
|
8809d8ac2f | ||
|
71c88323b7 | ||
|
9da0449797 | ||
|
393269ae1f | ||
|
c2481ac115 | ||
|
d50fdc52ea | ||
|
6d2d88648e | ||
|
2dc384adcb | ||
|
be0ee7652c | ||
|
759ff1927e | ||
|
1a87c452b7 | ||
|
e7a5be70c2 | ||
|
95051d1c1c | ||
|
d343f0c969 | ||
|
3316954d14 | ||
|
0ceddd3968 | ||
|
ee543e7ecd | ||
|
bfab1a3a9c | ||
|
8ad08c1b35 | ||
|
301c0f41c2 | ||
|
6798b1f11a | ||
|
2d76698279 | ||
|
d67580c964 | ||
|
fbfa20a2cd | ||
|
bbfd16f63d | ||
|
b1a4f2700e | ||
|
ef9671010b | ||
|
4649eb83ea | ||
|
e7accf7092 | ||
|
4f75515cd3 | ||
|
8e1e889ce0 | ||
|
aa421258b8 | ||
|
13a1e9d332 | ||
|
0056cc2d61 | ||
|
557f554270 | ||
|
8f91533a9a | ||
|
931045fd9b | ||
|
0b8ee0585a | ||
|
1707c8818a | ||
|
60f226321d | ||
|
6dca01ad27 | ||
|
a22bd9dba2 | ||
|
e384707615 | ||
|
07e76a4ecf | ||
|
1b3f52e8c0 | ||
|
2aa171e0ea | ||
|
96736fe7c5 | ||
|
c496797fce | ||
|
c0582fd994 | ||
|
0dcbe627c2 | ||
|
8420fb7364 | ||
|
e4c7333a1a | ||
|
29a3b18186 | ||
|
f9b13c66b1 | ||
|
ecace40fb0 | ||
|
a9c337264e | ||
|
b54a72d9b9 | ||
|
5c854dbdca | ||
|
8e858c1bf1 | ||
|
e535d97e84 | ||
|
9e808b255c | ||
|
1d34637bda | ||
|
47ebc31733 | ||
|
3dbd2eac91 | ||
|
7fc59b5cf4 | ||
|
e1f797c212 | ||
|
c471696fbb | ||
|
6d5ce6c54d | ||
|
544d39f19d | ||
|
4bbd27735f | ||
|
159d9d0348 | ||
|
b5a611c5db | ||
|
84b388692a | ||
|
66f62d696c | ||
|
aa2bdf2a1c | ||
|
8f64f49c3b | ||
|
b0eb87dfab | ||
|
8a13b7be24 | ||
|
7a3ebb708c | ||
|
db483ce95f | ||
|
555835549a | ||
|
770885440f | ||
|
4f408eae7c | ||
|
dffc12331b | ||
|
6b30de5fb1 | ||
|
7de6194e28 | ||
|
1baa0446a9 | ||
|
13bc8679f9 | ||
|
74cf452a48 | ||
|
0485124076 | ||
|
67c0e03f3b | ||
|
bbf609f46b | ||
|
027cecde24 | ||
|
bdd27ce50d | ||
|
1d9ac5ccc3 | ||
|
b7f3454763 | ||
|
cd2310f0a7 | ||
|
7fdc58a07e | ||
|
c36bdc22f6 | ||
|
60b8978762 | ||
|
88198e64f4 | ||
|
67d8586720 | ||
|
4f7a269ba5 | ||
|
c15877a7b7 | ||
|
083406f404 | ||
|
868fff9c06 | ||
|
7a1d16bb3b | ||
|
d29677b778 | ||
|
dba608a808 | ||
|
0a9d15a978 | ||
|
f78502e131 | ||
|
a2571fe106 | ||
|
33cb7eb106 | ||
|
09100f5d88 | ||
|
d4e1c34d0b | ||
|
216bcee66b | ||
|
6b38388a67 | ||
|
42f9e68fb2 | ||
|
39c37ec2d1 | ||
|
9d262ed113 | ||
|
ac37afd153 | ||
|
f09c45f3e4 | ||
|
090b79b3be | ||
|
968e6b5feb | ||
|
1f943663b8 | ||
|
03cbab2f85 | ||
|
1936dd7f67 | ||
|
6e0c09f78c | ||
|
e866a909dc | ||
|
ec18efcb04 | ||
|
844e23d0f4 | ||
|
919a88ec23 | ||
|
eb295de218 | ||
|
696bebc673 | ||
|
714227883f | ||
|
526c2e029a | ||
|
2bfca48e0f | ||
|
cd526d960e | ||
|
8dc60d0b87 | ||
|
efe8d6b643 | ||
|
faeb1d2e18 | ||
|
8b45c32d77 | ||
|
c35fe8b517 | ||
|
195329463b | ||
|
99ec5b32fc | ||
|
64963e1746 | ||
|
0ab0ab6957 | ||
|
5e109224fb | ||
|
38afb187cf | ||
|
0b5853070a | ||
|
28234da2d2 | ||
|
04e5f1b8cf | ||
|
d0efbfbcd9 | ||
|
d72874fa59 | ||
|
a2255f6052 | ||
|
fcc982dff0 | ||
|
2a5aed626d | ||
|
1e9e961e9c | ||
|
9517080349 | ||
|
7eee058864 | ||
|
366a20386c | ||
|
9ef085fb06 | ||
|
1c83a6fe44 | ||
|
a8c1f19f75 | ||
|
c2c479440e | ||
|
7c92845882 | ||
|
7ff3556bc3 | ||
|
b9ccb90324 | ||
|
24503fc922 | ||
|
d383f0e883 | ||
|
e35c22d405 | ||
|
faf91508e2 | ||
|
abea3888db | ||
|
e0d6aa59ad | ||
|
9c50a992af | ||
|
d31c6e75a5 | ||
|
2e4a638077 | ||
|
abce93640c | ||
|
ceec044a22 | ||
|
ebcc0d18ce | ||
|
e307de8064 | ||
|
dab1c1bcfa | ||
|
832dc127a4 | ||
|
c2410a4ffc | ||
|
5cffdbcd27 | ||
|
cc37632714 | ||
|
d9f80db036 | ||
|
096df4242a | ||
|
766529d7be | ||
|
bce4bfba61 | ||
|
012b9a2ba0 | ||
|
5b2eec214b | ||
|
3f97b8eaa8 | ||
|
d3664d5da0 | ||
|
289853445f | ||
|
b0d118f246 | ||
|
68b8d4bb1e | ||
|
445aa74b14 | ||
|
ac3b09966c | ||
|
fdacdf976d | ||
|
4248ba8512 | ||
|
44ff0563c0 | ||
|
a7942d6a1f | ||
|
5bb5e34aa1 | ||
|
1931c7d20d | ||
|
d4a67ab8d5 | ||
|
64f381fa23 | ||
|
a2e656a7c2 | ||
|
92c3eafc72 | ||
|
cfcdce81ba | ||
|
3808e8e25f | ||
|
5d1a33daf7 | ||
|
57cabdcf58 | ||
|
ac521641ec | ||
|
87d25c0896 | ||
|
e88a48e0a1 | ||
|
096eb78be7 | ||
|
4f42f4f718 | ||
|
7eb4a92d2a | ||
|
006ee4f6cb | ||
|
b6b56d0766 | ||
|
edf7762408 | ||
|
4a51f5c956 | ||
|
8dc73b6cec | ||
|
35598cf622 | ||
|
f6d2645fd4 | ||
|
92ebbae4ce | ||
|
bbcdddfcd1 | ||
|
20fa36a7d8 | ||
|
fb700978ac | ||
|
bd9d4c96be | ||
|
c07588e3bd | ||
|
f98cb01d0a | ||
|
7ff2a874b6 | ||
|
b94720ffa6 | ||
|
b98ce40021 | ||
|
ef203cf0e5 | ||
|
b7a9039e50 | ||
|
6a3cd371d0 | ||
|
9e8b4345c0 | ||
|
9521729e4e | ||
|
08efb46d41 | ||
|
0c0ca8e862 | ||
|
97e844a0b7 | ||
|
5f4aee8ca1 | ||
|
f1ea39f1c6 | ||
|
fd97e11919 | ||
|
6fcf77c7f6 | ||
|
abdece7737 | ||
|
f105f28017 | ||
|
83b959c126 | ||
|
c665fcb2ed | ||
|
c9b401135f | ||
|
af5cb72edc | ||
|
e678b50101 | ||
|
59b94b92ca | ||
|
4d91081046 | ||
|
fa7232944f | ||
|
ffa569deeb | ||
|
29b64d7545 | ||
|
17dfe0dd6a | ||
|
f1442b0ea6 | ||
|
7af66387de | ||
|
369410f370 | ||
|
08ca56eec7 | ||
|
ce9114ed55 | ||
|
933b622886 | ||
|
157123e118 | ||
|
a588993f28 | ||
|
a9023d08c6 | ||
|
2cc980755e | ||
|
060136306b | ||
|
1b7c3c4c7c | ||
|
0200596391 | ||
|
ca24f54bee | ||
|
3cba3e8e27 | ||
|
5f2c7b966f | ||
|
e4aa212f9a | ||
|
24220defd6 | ||
|
620ee3cf51 | ||
|
ccc7d2e887 | ||
|
e063671816 | ||
|
c4a8669501 | ||
|
8625b23c0d | ||
|
99ec31dfdc | ||
|
8f69703726 | ||
|
7cff35368d | ||
|
184743637e | ||
|
730567dc60 | ||
|
a3f261184d | ||
|
f46f138e9f | ||
|
260f61f33a | ||
|
72a90ba91c | ||
|
2225fd114c | ||
|
b057e0d10a | ||
|
cb738190be | ||
|
19126df7f4 | ||
|
6910c3d24b | ||
|
bb37f8d2f0 | ||
|
9413d68976 | ||
|
78e2b94cb5 | ||
|
e5302a9b1e | ||
|
c492022ae6 | ||
|
69fb2ad0a3 | ||
|
7e124e169e | ||
|
2854578527 | ||
|
021cdb402d | ||
|
4bf252800e | ||
|
5a56c3b882 | ||
|
ea18ba9335 | ||
|
5da80062d9 | ||
|
40562b1c54 | ||
|
160282c42a | ||
|
60ad3160cf | ||
|
6bcaffe27d | ||
|
4c1f073d20 | ||
|
0f73282e4e | ||
|
03ea6dc708 | ||
|
9f876e380c | ||
|
66112af37e | ||
|
5c9d50e25f | ||
|
05cf3656b8 | ||
|
0c91502859 | ||
|
4b24178553 | ||
|
4c443d51ce | ||
|
6448a692e2 | ||
|
151d58eb60 | ||
|
5a14eb93c6 | ||
|
8f6047fdca | ||
|
1e54c55c11 | ||
|
c64d5b58b6 | ||
|
8d016f19d2 | ||
|
110cedeaac | ||
|
d1e3ad7790 | ||
|
0534b091a5 | ||
|
9e99ce434e | ||
|
ca567bee79 | ||
|
152924e13f | ||
|
36aa3f31b9 | ||
|
f65dc73632 | ||
|
9fbafab67f | ||
|
65fb6afd60 | ||
|
09e7068658 | ||
|
aa9ccc724f | ||
|
7760e11544 | ||
|
a35164dc0a | ||
|
e819b91a97 | ||
|
bf67811392 | ||
|
8e702f1452 | ||
|
bb5c9f7fc6 | ||
|
66112f4930 | ||
|
c62704e26b | ||
|
1e7737a239 | ||
|
c2a395006e | ||
|
097705456c | ||
|
7e908fef0e | ||
|
17c97c3c2b | ||
|
385cd1b8c7 | ||
|
2df6d266bd | ||
|
94acbce822 | ||
|
ddad913e06 | ||
|
8ac029d3fe | ||
|
198942b273 | ||
|
634dcefd01 | ||
|
0cf168f32b | ||
|
d38fd41b0e | ||
|
30e274953a | ||
|
c5b39e2dfc | ||
|
7871e50f7d | ||
|
db9410caa5 | ||
|
32a0dc0e43 | ||
|
695c6ee943 | ||
|
0abd3b2c46 | ||
|
5df45417fa | ||
|
0c3db932b2 | ||
|
2bc75caf9e | ||
|
852a6997ed | ||
|
337e74352d | ||
|
1d80c185d8 | ||
|
4a21dd3232 | ||
|
a6567d9ee1 | ||
|
a9cd3f2c11 | ||
|
92d6cc6394 | ||
|
d8e89f5114 | ||
|
0ed5cf6b38 | ||
|
882e5d292f | ||
|
1ebed1701a | ||
|
97452b6ec3 | ||
|
d75b7c0023 | ||
|
9f3bffd4dd | ||
|
2f1b8e5b57 | ||
|
1a3572316f | ||
|
05403d3a56 | ||
|
876b36ac1c | ||
|
588c0734a9 | ||
|
4cb56dc76f | ||
|
fa1c84f18f | ||
|
7a807f5cae | ||
|
5ecb845662 | ||
|
e94e7cc501 | ||
|
1cde5dfad8 | ||
|
7d9ebc59a0 | ||
|
69d527f322 | ||
|
da335007e7 | ||
|
3df6623fbf | ||
|
84e8e45b7b | ||
|
e7f6ac8828 | ||
|
34cf0f558d | ||
|
fe7667a00c | ||
|
4963ec4cc4 | ||
|
ee939a3782 | ||
|
78b552fe82 | ||
|
c6f9d05124 | ||
|
4d2f56c42d | ||
|
1c7351fc85 | ||
|
8e80d2f8a4 | ||
|
409ab2a6d4 | ||
|
e846f4f3b0 | ||
|
2a8b26d5e6 | ||
|
b7194402eb | ||
|
5ca602fbd2 | ||
|
39b999a68b | ||
|
955860b463 | ||
|
e29246fd91 | ||
|
2a8f15c68b | ||
|
60f01fe947 | ||
|
40868df759 | ||
|
bd1759eb45 | ||
|
0c716bd970 | ||
|
52a3bf5f24 | ||
|
67d5a53503 | ||
|
89303ab046 | ||
|
9c7a8fdb1b | ||
|
5296176151 | ||
|
b37a0b285a | ||
|
7456beb7b9 | ||
|
248e7bc332 | ||
|
25b51362e9 | ||
|
3864ff37e1 | ||
|
c22611c701 | ||
|
c0ba898ef2 | ||
|
64d20a062a | ||
|
c22ef09f13 | ||
|
2223a843c9 | ||
|
d2211d8818 | ||
|
2be58439bf | ||
|
83ea4edce2 | ||
|
d8282fe3c9 | ||
|
39b88d546b | ||
|
ea2f32b255 | ||
|
f86e682d2c | ||
|
8409d3bcfb | ||
|
7d51ba3d97 | ||
|
91404edd13 | ||
|
56118d2a67 | ||
|
a8f63aea3c | ||
|
c13745d753 | ||
|
0290e70445 | ||
|
bf32ae66c6 | ||
|
bec09a012c | ||
|
08eb2f3d98 | ||
|
f550360f1a | ||
|
0677b1d099 | ||
|
8b7805b95d | ||
|
804b9bec63 | ||
|
dcb3f6db9e | ||
|
103caa56e1 | ||
|
370f02661d | ||
|
b806ae4e82 | ||
|
38ee020653 | ||
|
ce5153544c | ||
|
48d3504de7 | ||
|
99d2c0258c | ||
|
046b09052c | ||
|
163a5ea20c | ||
|
7053a0b605 | ||
|
58eb6838b7 | ||
|
1f4f1223a1 | ||
|
3cc8c589cc | ||
|
52d5b3e2a2 | ||
|
358a3ceed7 | ||
|
c6918fc170 | ||
|
1afd440c86 | ||
|
702977f0b9 | ||
|
fb463d34ef | ||
|
55e78b03de | ||
|
47dcdc1b4f | ||
|
e13ab011eb | ||
|
0737655753 | ||
|
95af00a752 | ||
|
89713521d4 | ||
|
5a1812f237 | ||
|
23c7fb2885 | ||
|
e9f6667cf5 | ||
|
892f202945 | ||
|
3882b1b4b9 | ||
|
7929573dc1 | ||
|
e575196abc | ||
|
404caeab50 | ||
|
dde9b4c2c7 | ||
|
e434b625ea | ||
|
793f2e5bf4 | ||
|
4c24323530 | ||
|
cc4ab9bc25 | ||
|
2551f20f3a | ||
|
5b29ddbcaa | ||
|
ac4d16c917 | ||
|
01c16dcf4d | ||
|
169c0871c7 | ||
|
8a99d41c31 | ||
|
ffee61a1b1 | ||
|
526df86ee6 | ||
|
748cf44f35 | ||
|
a4f96f0648 | ||
|
2ca1bab9ed | ||
|
1e6a745f19 | ||
|
7c9508ae96 | ||
|
1c7e6c58c3 | ||
|
0d6a02168b | ||
|
d094c21824 | ||
|
0ea361a82f | ||
|
436dc0b67a | ||
|
bd9ac204c2 | ||
|
31609319de | ||
|
c802361800 | ||
|
143e1f88a8 | ||
|
68187d7c5f | ||
|
0bfcdafe2d | ||
|
97a2cc2566 | ||
|
cfc0215089 | ||
|
2f4a10913b | ||
|
139ae8cc08 | ||
|
719a92d8a4 | ||
|
70542137f2 | ||
|
0ece21bca7 | ||
|
0d87e92a10 | ||
|
ef1d4b592a | ||
|
7d6cdf3819 | ||
|
3a1855a80f | ||
|
dee29c118c | ||
|
0a7a0ca5fe | ||
|
c50ea6a63f | ||
|
ca370eee7e | ||
|
ac418b9de1 | ||
|
0c48ecb3f8 | ||
|
652e52df3d | ||
|
851dbd3ccd | ||
|
4fcc921b46 | ||
|
eaa1c1cd4a | ||
|
07c1beadfb | ||
|
6d4cddb818 | ||
|
e3672e8293 | ||
|
17793ef361 | ||
|
d2e9025be6 | ||
|
1a263a3acc | ||
|
8c1f76a594 | ||
|
ffb9f1b134 | ||
|
e634019ac9 | ||
|
4f9c8e9374 | ||
|
ea7dec4e88 | ||
|
33198fc7b7 | ||
|
f0809a667f | ||
|
df7f7d8171 | ||
|
5ff2383af7 | ||
|
772289c545 | ||
|
9651f2bb6b | ||
|
597dc72e46 | ||
|
0d35f2277b | ||
|
ee4864449c | ||
|
23ca397206 | ||
|
0857abe6a4 | ||
|
26cf970713 | ||
|
4504de828a | ||
|
1bf5fb208f | ||
|
9efd20d7cd | ||
|
11a9f1df21 | ||
|
eb95f1de55 | ||
|
d6ffae9c1b | ||
|
9ba6915c85 | ||
|
2d7f54a775 | ||
|
ce9ce07817 | ||
|
346e499602 | ||
|
e1873ad2ec | ||
|
2bfe922650 | ||
|
9f7255cd23 | ||
|
8c8d5afe62 | ||
|
f55c254959 | ||
|
30a58ecd5c | ||
|
6b06d07bcc | ||
|
4dae9affda | ||
|
4541efe86a | ||
|
8a751a7946 | ||
|
72be66414d | ||
|
23229f1118 | ||
|
080fde08b6 | ||
|
970a5f562b | ||
|
f1b578fd2e | ||
|
b478b5b568 | ||
|
72d1d9b154 | ||
|
36a87f96bd | ||
|
24b58da8c6 | ||
|
7c61445fe3 | ||
|
72b1fe0500 | ||
|
50a6a3e35c | ||
|
91b0e491c5 | ||
|
280f609785 | ||
|
431f1f8199 | ||
|
e268efefef | ||
|
083b4a2970 | ||
|
8b7922b679 | ||
|
b2397a2e7a | ||
|
66b814a226 | ||
|
5a04054145 | ||
|
8389c6a450 | ||
|
a956d58ea1 | ||
|
c678407d1e | ||
|
e2ef8dbbe0 | ||
|
843683a492 | ||
|
8386aaf12f | ||
|
8b1c165253 | ||
|
a0c5baecd8 | ||
|
49d8a5cb44 | ||
|
0da2930109 | ||
|
bb7fa95426 | ||
|
5cda1f2f5f | ||
|
d0bd741049 | ||
|
274760746e | ||
|
7fc3de69da | ||
|
9d8adbb581 | ||
|
2f9de4942c | ||
|
64879f5b02 | ||
|
4c34e0a6e0 | ||
|
6888047102 | ||
|
9acb4636db | ||
|
cdc36f329e | ||
|
f9cc7a3b46 | ||
|
54c353830f | ||
|
1de34b12ac | ||
|
85c43fa81f | ||
|
c29b5b5800 | ||
|
e12e03d9c2 | ||
|
3e724afb0a | ||
|
ec5d1b7b88 | ||
|
3ee2c64899 | ||
|
6648a0a84d | ||
|
8d9149b020 | ||
|
280467ad38 | ||
|
0158803bde | ||
|
91eeb4d9d5 | ||
|
40f83c8f25 | ||
|
07bdc60a49 | ||
|
795823e372 | ||
|
4a54985441 | ||
|
ddc4e7484b | ||
|
32361589c9 | ||
|
06670fc970 | ||
|
1433c59778 | ||
|
aa0309e425 | ||
|
6ad8e30f88 | ||
|
2bded45397 | ||
|
5ce8cf5016 | ||
|
b6e92dc8a7 | ||
|
10be34b5b2 | ||
|
2a0e5f667b | ||
|
9e44306c04 | ||
|
f8244c8119 | ||
|
82ce597573 | ||
|
05cd81b77c | ||
|
19f42d5a3a | ||
|
b3939e8fdc | ||
|
a62541e577 | ||
|
d4e8a886c5 | ||
|
7242ddae64 | ||
|
936afedb4b | ||
|
c342663200 | ||
|
57b0fe7fed | ||
|
80cc16d62d | ||
|
0b03b61564 | ||
|
9d0aadb83f | ||
|
42ef41182d | ||
|
dde06e7cae | ||
|
5ead9d49f4 | ||
|
b996ed9220 | ||
|
73a54049d2 | ||
|
68a72037fa | ||
|
10547a6d74 | ||
|
4536581a6e | ||
|
e2d9a353a0 | ||
|
c266e4045b | ||
|
ca8426ea60 | ||
|
9fa6a2fe92 | ||
|
312478e509 | ||
|
879d3b607d | ||
|
ba5c07bed9 | ||
|
c74b39e712 | ||
|
21d2a59a5f | ||
|
4e2b5bb336 | ||
|
c756861822 | ||
|
9b22224bc4 | ||
|
653c7fc1e6 | ||
|
de3718c718 | ||
|
112a174f4a | ||
|
7b36ee10a4 | ||
|
ae959cd878 | ||
|
4051f190a5 | ||
|
9d947c7ce6 | ||
|
af0430dbc5 | ||
|
21eb96a2f5 | ||
|
7b02b3cb89 | ||
|
612cd07fb3 | ||
|
e8dfc18d11 | ||
|
ea09dfc888 | ||
|
241577a7f1 | ||
|
b852add773 | ||
|
a1c39173dd | ||
|
cbbe3fe207 | ||
|
51b7780d83 | ||
|
b1a2e45168 | ||
|
6d28e74667 | ||
|
4b93f89763 | ||
|
389d8ae045 | ||
|
2d6d1e6325 | ||
|
b3166135eb | ||
|
558f9b9bae | ||
|
3ba1364d60 | ||
|
aaafd482cc | ||
|
a7d4c091a0 | ||
|
6160f513aa | ||
|
67d52b78b6 | ||
|
af5ef50cf9 | ||
|
deb5e21842 | ||
|
b698ce5d95 | ||
|
e5e7ce8203 | ||
|
d42cbcdee2 | ||
|
91a3091b2e | ||
|
2710939e1e | ||
|
595907cae2 | ||
|
69ac36cca1 | ||
|
398148f7ea | ||
|
382d9f8898 | ||
|
2f2b792edf | ||
|
634a54c046 | ||
|
6ba5cfbeef | ||
|
7735d638c6 | ||
|
5c581651ce | ||
|
44891d5c4a | ||
|
a47e3cc62c | ||
|
7ffed9c43c | ||
|
94136f5741 | ||
|
453673a2a6 | ||
|
969fb5a9d8 | ||
|
bc48c9bc26 | ||
|
06ff367fdb | ||
|
81582574c1 | ||
|
91904df5e8 | ||
|
bbffb49b8f | ||
|
d05ee826d4 | ||
|
792b45d5dd | ||
|
a39b314378 | ||
|
96e9ea2d1e | ||
|
c9d6a1381f | ||
|
64922fff4b | ||
|
9ffeef88d5 | ||
|
3035f43428 | ||
|
4276549acd | ||
|
324201f336 | ||
|
839de39c1f | ||
|
0f19db5e8e | ||
|
7a6d6c3850 | ||
|
63fd5b4c10 | ||
|
86005bcfb8 | ||
|
e9b78b6370 | ||
|
2da7a3f7fb | ||
|
e834d32b8e | ||
|
f8609e0279 | ||
|
ec41e87cf1 | ||
|
b8825127fd | ||
|
f4ee044347 | ||
|
7854686903 | ||
|
9080a23913 | ||
|
1b049b8f75 | ||
|
11c148c851 | ||
|
dbc338a887 | ||
|
629550c30b | ||
|
ec0a879a93 | ||
|
3151821e6d | ||
|
57cc4809ba | ||
|
83ab8efbd7 | ||
|
737c1e2a4f | ||
|
a36dd791ec | ||
|
f7b882f0e8 | ||
|
b7426f93c0 | ||
|
538038e49c | ||
|
ce80acc818 | ||
|
b1cc55b786 | ||
|
c66b6fbafc | ||
|
2e9e3424ec | ||
|
0145b790a3 | ||
|
0783f131b8 | ||
|
e5f4495ca0 | ||
|
5f58323c01 | ||
|
dc4c23c0da | ||
|
afcb7b8579 | ||
|
dc5cb71c22 | ||
|
f3437d7cc0 | ||
|
b7b35c9b59 | ||
|
0a78f735d3 | ||
|
18ae18a95c | ||
|
a7aabca618 | ||
|
47a74cb6c3 | ||
|
d9dfbcd199 | ||
|
81662e954b | ||
|
045c863117 | ||
|
32443a9675 | ||
|
3a4ed6fd40 | ||
|
82436ad838 | ||
|
74abf61a08 | ||
|
1915365b1a | ||
|
2791775c5d | ||
|
6b2c25475f | ||
|
0ffb936885 | ||
|
30f13bd28c | ||
|
6a7c084177 | ||
|
70d68a500e | ||
|
a4bfb026a8 | ||
|
a37a0b1b00 | ||
|
d81c23cb16 | ||
|
59c1468e5a | ||
|
d6879c4f8a | ||
|
ca9249d4db | ||
|
bc876ec30c | ||
|
45c73e0175 | ||
|
c286203640 | ||
|
968ff4879a | ||
|
1c1cddb53e | ||
|
a068b7b09f | ||
|
cd045fde15 | ||
|
4466a55de6 | ||
|
da7c32cb10 | ||
|
c6dba26d02 | ||
|
c1fcd1a0c0 | ||
|
5b39cacc8a | ||
|
9a3d53ae51 | ||
|
d95ad1ca54 | ||
|
38c0cb3323 | ||
|
f64da1864f | ||
|
593cb7c107 | ||
|
ca01ff6f79 | ||
|
127324d2d6 | ||
|
f1dfa2a1bc | ||
|
8f892ab798 | ||
|
0481ff9af5 | ||
|
66ab22a5e9 | ||
|
6f1070cccd | ||
|
8721a48206 | ||
|
7003e31b7e | ||
|
80c92daacd | ||
|
6532aef089 | ||
|
9693b2de6a | ||
|
855ffb490a | ||
|
249acb04cc | ||
|
562b43a7c5 | ||
|
7df571d42f | ||
|
1fcde88d8a | ||
|
4527d9ee39 | ||
|
9a29beb189 | ||
|
6b6c25635a | ||
|
bfc96abf8f | ||
|
feaa0d0654 | ||
|
f4eddf316b | ||
|
713dc02e46 | ||
|
af3554c1d1 | ||
|
0f8385a798 | ||
|
8f3fc1c2ad | ||
|
ca571c6fa5 | ||
|
2407304177 | ||
|
7fe86cec59 | ||
|
9343d8162d | ||
|
be9df4d658 | ||
|
2c6f7906c5 | ||
|
84aa06aba5 | ||
|
d667d87bbe | ||
|
f1ec42d4ba | ||
|
51e3cb7b9f | ||
|
10dc12c502 | ||
|
417ae21dfa | ||
|
ebe0aa0c76 | ||
|
89094950f8 | ||
|
5be2b3db29 | ||
|
0725b008be | ||
|
097b768127 | ||
|
9ce028056a | ||
|
fed2556fc3 | ||
|
0751eae90b | ||
|
0461fb5b2a | ||
|
cb01259073 | ||
|
0c86ff1ee4 | ||
|
a6ed2029b7 | ||
|
cc95c89d3c | ||
|
9aadc80f75 | ||
|
d785e45308 | ||
|
d8e0683c35 | ||
|
b1d65fd84f | ||
|
5d63892949 | ||
|
ba07e7ba85 | ||
|
e163026ca9 | ||
|
9339a6027f | ||
|
ec64c041ab | ||
|
69a625af97 | ||
|
0d0d9ccdae | ||
|
73dc3560a5 | ||
|
0a2d6e6dcb | ||
|
7706b8727a | ||
|
9811dceca1 | ||
|
2c44ffbe39 | ||
|
311a470806 | ||
|
3a52d2da97 | ||
|
5a81d83d30 | ||
|
b757b4c590 | ||
|
c7ca786e77 | ||
|
a9fbbd3894 | ||
|
e380a00b67 | ||
|
b89c93a624 | ||
|
7ffe132e79 | ||
|
7bfe5de9c7 | ||
|
96063fb0da | ||
|
4cf78139a8 | ||
|
fd2e169dc9 | ||
|
0e3d2770d9 | ||
|
0912a30bb9 | ||
|
f5493e023d | ||
|
7671648fca | ||
|
7543461c24 | ||
|
4cbade9a88 | ||
|
4986930511 | ||
|
9093f22293 | ||
|
5cb74fb684 | ||
|
d343152fca | ||
|
f8c6b9e7a0 | ||
|
4e3928df81 | ||
|
48a8db233d | ||
|
e9eeace995 | ||
|
04bfc89816 | ||
|
c11af7ea26 | ||
|
3e5e17d1a3 | ||
|
18e32d1755 | ||
|
2a5407cf70 | ||
|
577e23925b | ||
|
6176befecb | ||
|
f050457976 | ||
|
337617afbb | ||
|
e9f243a913 | ||
|
cb33a5b25a | ||
|
007765daa6 | ||
|
b1ea7c5f06 | ||
|
3b5b400909 | ||
|
3883b7d86a | ||
|
b50c97f4a7 | ||
|
202eb2b5cc | ||
|
80b1275e07 | ||
|
0dc30f081a | ||
|
12ae5745db | ||
|
269bac4626 | ||
|
2f1e21dc2d | ||
|
8b4714d8e2 | ||
|
c365c450a7 | ||
|
0c80ac3296 | ||
|
029c685268 | ||
|
05ba352f2f | ||
|
21b75494a2 | ||
|
15b6c48d7c | ||
|
c267ad00b5 | ||
|
e8b107efdb | ||
|
cb6bb0590e | ||
|
9083e883fe | ||
|
a32f232bb1 | ||
|
1149c266cf | ||
|
544ca2be4c | ||
|
88a11b891f | ||
|
3d1c8b50c4 | ||
|
476133abd0 | ||
|
518746f664 | ||
|
496c5589e6 | ||
|
5ea33cc931 | ||
|
b08f02c4f3 | ||
|
487c063d48 | ||
|
6e8567eadc | ||
|
3c8f3ad3fc | ||
|
a67db0595b | ||
|
b702d56547 | ||
|
94c6dbd281 | ||
|
7248403be7 | ||
|
fb03479a1f | ||
|
58d287da7a | ||
|
980acc3fb8 | ||
|
b02e40d5a2 | ||
|
90a943d05a | ||
|
ef670986c6 | ||
|
42ab746a66 | ||
|
c48097a484 | ||
|
5974092c94 | ||
|
56eac9f875 | ||
|
9802ca41dd | ||
|
058913f8a2 | ||
|
d0202a3f9a | ||
|
f79af39ea2 | ||
|
fc35111ae7 | ||
|
0c231db9e7 | ||
|
bfb37884e1 | ||
|
afcc66fb3c | ||
|
0cbbaac490 | ||
|
220ba9ff38 | ||
|
81f808e184 | ||
|
00c67f8842 | ||
|
369a915d66 | ||
|
1c61b006ba | ||
|
217e9787bd | ||
|
26d51a831c | ||
|
cc296a3114 | ||
|
8dd94505a8 | ||
|
792087276e | ||
|
ff8a20ef04 | ||
|
d3a67f9e19 | ||
|
567936a21d | ||
|
0b96df1428 | ||
|
f98b71a257 | ||
|
a5b182f0fa | ||
|
b74095a2cd | ||
|
b169d86bf8 | ||
|
7459b9610c | ||
|
a8741674ce | ||
|
50fd7f1140 | ||
|
120edb6f8c | ||
|
ef143261e5 | ||
|
5e04600ab1 | ||
|
408bf5baab | ||
|
945ee0bdb3 | ||
|
88dfb9a159 | ||
|
457b3b3f06 | ||
|
8b506e84fd | ||
|
7ee063da28 | ||
|
f7d129bd24 | ||
|
52634b8023 | ||
|
b573fbcdc4 | ||
|
49a8cd0bb5 | ||
|
91816c30b5 | ||
|
45e0a75491 | ||
|
3b858fb6af | ||
|
ff4168b8f6 | ||
|
db0269cd3f | ||
|
dd7704e572 | ||
|
a939fed872 | ||
|
9a09f92032 | ||
|
a04646ab5b | ||
|
e1bd85caa6 | ||
|
3bd1c122c3 | ||
|
ede16f1d3b | ||
|
9c23fe2563 | ||
|
39c352c89b | ||
|
5660b762c0 | ||
|
e97624ba7d | ||
|
d047897462 | ||
|
96f6839434 | ||
|
8f56da465a | ||
|
51eacd3174 | ||
|
aeb9f0eda4 | ||
|
f3c07f1f99 | ||
|
95234036bb | ||
|
bc55531204 | ||
|
2bda598ac6 | ||
|
ab49034205 | ||
|
b047c7a9e1 | ||
|
6d868c8f7c | ||
|
cc73796897 | ||
|
ce31de47cb | ||
|
935b2f6114 | ||
|
59fe551f26 | ||
|
af143b0420 | ||
|
09dd47c6de | ||
|
37906bcd1f | ||
|
130c7c28c2 | ||
|
5c16d0e656 | ||
|
69a712b07f | ||
|
2cd5c49935 | ||
|
59d4cb4bc2 | ||
|
82e2df7a2a | ||
|
bebb94738c | ||
|
a2a1148354 | ||
|
0a76881eb6 | ||
|
a20e8a8220 | ||
|
a1af4c59ca | ||
|
afbd62c665 | ||
|
968399a409 | ||
|
8bbfab3183 | ||
|
acac96310b | ||
|
c578b36dfb | ||
|
c0cf5646da | ||
|
60862a35c8 | ||
|
e4fbece88f | ||
|
d62ff4eb75 | ||
|
f905c4d0f6 | ||
|
1272405f16 | ||
|
42bf575a0e | ||
|
2205493862 | ||
|
a4465b72e7 | ||
|
8eeda02d50 | ||
|
d6236b87dd | ||
|
595bb563f9 | ||
|
e8f0615635 | ||
|
fc15b5c9f9 | ||
|
0891de668b | ||
|
d3a2e49d38 | ||
|
600f0eadd9 | ||
|
3d8e22ed50 | ||
|
b1edf540d8 | ||
|
ca92c51f51 | ||
|
effc02ce8e | ||
|
61f9dbd95d | ||
|
c559a308ad | ||
|
dc59fdf40e | ||
|
3c1a805770 | ||
|
d262dde71a | ||
|
c03ccba8db | ||
|
3f9d62ceee | ||
|
f48194f480 | ||
|
f0e772ca97 | ||
|
1d96a10acb | ||
|
2a69081e53 | ||
|
536e47c567 | ||
|
2184fd0902 | ||
|
be3385a8c1 | ||
|
19c382c9e0 | ||
|
40524fef8a | ||
|
57826a7ef1 | ||
|
8c9ff67b21 | ||
|
212947d83c | ||
|
f1bcddf421 | ||
|
32e4d705c6 | ||
|
a8dbae00c2 | ||
|
85971e9158 | ||
|
4b69331321 | ||
|
e71154b7e0 | ||
|
55412d7093 | ||
|
f724cbbacd | ||
|
9f8d871c9c | ||
|
d57d4dbe24 | ||
|
d8e460ca47 | ||
|
7313473fd2 | ||
|
a42fed5d53 | ||
|
930ee8145c | ||
|
42712a0280 | ||
|
8e61098fec | ||
|
47d5b485d4 | ||
|
2dfe22e834 | ||
|
c66e9a06cf | ||
|
7a024d2a69 | ||
|
c7e82b4a47 | ||
|
6c97bb9052 | ||
|
57f50edaa2 | ||
|
bbd3b7e550 | ||
|
27b5718b07 | ||
|
a753e00b59 | ||
|
a5f66c8b8b | ||
|
a498b19bfd | ||
|
49095ebc5e | ||
|
40e4f93637 | ||
|
6b71d1d477 | ||
|
441781cbe9 | ||
|
7c0ad24175 | ||
|
a50aa2486b | ||
|
dcadfc37f4 | ||
|
9615ca6fa6 | ||
|
65dd02cc52 | ||
|
6f40885f73 | ||
|
8d691563c7 | ||
|
18b376ac5f | ||
|
dd30b63426 | ||
|
1eb1113a24 | ||
|
a009616726 | ||
|
a7db98c22e | ||
|
b02aeab022 | ||
|
5e3a24573e | ||
|
091df682cd | ||
|
09f4edda57 | ||
|
aeea20ae9d | ||
|
9f5b746e0b | ||
|
63b17e14af | ||
|
fedea2cad7 | ||
|
7d2dbe2988 | ||
|
765a072c73 | ||
|
3dffa3a0ca | ||
|
65e6e5f30b | ||
|
33a9c54842 | ||
|
d433cdf260 | ||
|
3f86d898a3 | ||
|
009a66d723 | ||
|
947c62bea9 | ||
|
d171a0ccee | ||
|
9cc8b3320a | ||
|
c1f27d7b27 | ||
|
d9b0576351 | ||
|
78446f0ed4 | ||
|
7a41a9b417 | ||
|
1804a5c8e6 | ||
|
67f1566b5e | ||
|
e0a6edac35 | ||
|
2ffce49e16 | ||
|
75db33559a | ||
|
8f4cd5c412 | ||
|
882b141478 | ||
|
2ca550273a | ||
|
d3c15ef6ca | ||
|
02ac609f3c | ||
|
be038dc8e7 | ||
|
57e7782ac4 | ||
|
09b7e2fff4 | ||
|
b9bdd6c49c | ||
|
14f267b4fa | ||
|
02841ddde6 | ||
|
026baddbab | ||
|
1e90400916 | ||
|
742c9e95d3 | ||
|
e5d354e896 | ||
|
0f1fa3176f | ||
|
0f643e01b7 | ||
|
ba0e66a5b7 | ||
|
72d26c7046 | ||
|
9bde98dede | ||
|
a1a13c61bf | ||
|
0532d2a159 | ||
|
9b490396bb | ||
|
54eb51d8db | ||
|
e7d5cdbb42 | ||
|
cbbaf2ee84 | ||
|
62878fdc7a | ||
|
8d011ca4b9 | ||
|
5d84ee250e | ||
|
d04aaddcbd | ||
|
ca59aca4a6 | ||
|
36943866e2 | ||
|
d43daed6a6 | ||
|
7df4e56454 | ||
|
dba7370d6d | ||
|
688991f57f | ||
|
4b8be255ce | ||
|
066efab985 | ||
|
0e22ad8eb1 | ||
|
1a8bcd314d | ||
|
ab5611119a | ||
|
d65c2247e5 | ||
|
0382100a97 | ||
|
9a271f5452 | ||
|
91104e6ab6 | ||
|
2936f7fa57 | ||
|
a19ee1e5e0 | ||
|
baccf336d7 | ||
|
c0a8a570e8 | ||
|
eb7492c6c6 | ||
|
efc11783c7 | ||
|
c4ccbd5cce | ||
|
623f92378d | ||
|
c59272d46d | ||
|
efbc385417 | ||
|
aefca34b39 | ||
|
abf7efcc5a | ||
|
86c9f9d89d | ||
|
bbd2ca8ddf | ||
|
babcc0a7dc | ||
|
204e22657b | ||
|
144d0348dd | ||
|
c650337928 | ||
|
a9475fbdf4 | ||
|
65b0dcb2c5 | ||
|
d72807dd67 | ||
|
48acc09e91 | ||
|
22ee6f6ca2 | ||
|
81de2c3d9b | ||
|
1e228e1d9b | ||
|
9b89d76b3b | ||
|
f34103473e | ||
|
a69f0a64b1 | ||
|
6b2a302393 | ||
|
44b414d45f | ||
|
da852119de | ||
|
096bd8ba94 | ||
|
6e7ab3558a | ||
|
a01ea29cf1 | ||
|
7d88ee00cc | ||
|
ece1a11a23 | ||
|
4d5dc6a30e | ||
|
52e99adc32 | ||
|
00439f4d49 | ||
|
bef89c6604 | ||
|
50a21da4d5 | ||
|
6dd24e0733 | ||
|
86332d0311 | ||
|
00623d4eea | ||
|
b858f17425 | ||
|
22d3510dde | ||
|
c766704267 | ||
|
fb55c35f87 | ||
|
3feaeb153e | ||
|
a925ef130d | ||
|
0b1e2784cd | ||
|
4bf391b1c8 | ||
|
55e54d9499 | ||
|
2c1d2571d3 | ||
|
dbd04f09e8 | ||
|
9fbcce689c | ||
|
ce05b5f7f0 | ||
|
371b575d2e | ||
|
c116c70bfa | ||
|
724153e5ef | ||
|
3d99773ddb | ||
|
39253bec80 | ||
|
319857db89 | ||
|
a420cfd798 | ||
|
c5ce14dad1 | ||
|
f4a364c3db | ||
|
fed3b4f9cd | ||
|
aca7687edd | ||
|
b0dfb8c5ac | ||
|
91513ced22 | ||
|
399e88d5fe | ||
|
74d00b84b7 | ||
|
6b1363e96e | ||
|
421d3b27f5 | ||
|
10ab2b4fe0 | ||
|
86837761fa | ||
|
3fbc2c5716 | ||
|
4b6fda0cb6 | ||
|
d5c9a52337 | ||
|
7ee96766b6 | ||
|
cfe0e55df8 | ||
|
a17213d89c | ||
|
eed8a06fc0 | ||
|
57c73c8a51 | ||
|
6f94664428 | ||
|
a5f72627fe | ||
|
dd76846cf2 | ||
|
9779635c34 | ||
|
7a9377de34 | ||
|
430b733da6 | ||
|
0d8244748c | ||
|
a012d721a3 | ||
|
517e72f92b | ||
|
8cd82ebb68 | ||
|
8d5bacf6ae | ||
|
5dcc8e744e | ||
|
613d3b2e82 | ||
|
527ae01e0e | ||
|
cd382ef236 | ||
|
8c14ec3268 | ||
|
22c34e1095 | ||
|
15f6412581 | ||
|
388fb600de | ||
|
47aaf44017 | ||
|
2d51d13479 | ||
|
1b8832a7ff | ||
|
ee51dec20e | ||
|
18ec502cfe | ||
|
edf93abff1 | ||
|
11f8c41305 | ||
|
3fc4fcc538 | ||
|
9ca7540c69 | ||
|
5cca2a4168 | ||
|
fa35869bc4 | ||
|
11cbe58eb1 | ||
|
76c795a966 | ||
|
90b7383df7 | ||
|
2d06599a85 | ||
|
8941504863 | ||
|
dd23fffcc0 | ||
|
2a84d62187 | ||
|
b50b38c78a | ||
|
479a64dca6 | ||
|
de7c15fc68 | ||
|
9c68ac1419 | ||
|
ab5f66795a | ||
|
b3b041a151 | ||
|
9b71454f07 | ||
|
58a4081b48 | ||
|
21b91adf6a | ||
|
4904277f0d | ||
|
80a1b12ae7 | ||
|
3dd1580256 | ||
|
4a2bec239a | ||
|
17748b980a | ||
|
5c5b1cd3ae | ||
|
4f9b86c900 | ||
|
7bf9cc8f1a | ||
|
5565c096c7 | ||
|
3ac3eccebb | ||
|
258500bda3 | ||
|
52ed2ca55e | ||
|
42c01a21b2 | ||
|
0991705379 | ||
|
bc3cab7dfa | ||
|
252439c1af | ||
|
c40b86d4a4 | ||
|
6f2b36cacb | ||
|
97eb3fe209 | ||
|
f88c9d299b | ||
|
f46414b7b1 | ||
|
37e895352f | ||
|
a026f8b26d | ||
|
f049284324 | ||
|
1a3a96762b | ||
|
ed31358934 | ||
|
fe51805ed7 | ||
|
f4c5cf20bc | ||
|
71d4ba21f2 | ||
|
4beb946468 | ||
|
45a725e4b7 | ||
|
f274cbc2ec | ||
|
594aea2d5a | ||
|
eefc998e43 | ||
|
ff7b8a6854 | ||
|
b95860c034 | ||
|
43be91f032 | ||
|
71a9b7eb77 | ||
|
6e86dbcebb | ||
|
95cfb114a2 | ||
|
6d836b9f48 | ||
|
ad604036a5 | ||
|
7bafb6a843 | ||
|
62ecadeb57 | ||
|
01fc137256 | ||
|
ae003ee020 | ||
|
603b8969ab | ||
|
ab2e532cc3 | ||
|
84a4701733 | ||
|
a6c5a8fdaa | ||
|
a2d77b1754 | ||
|
a746c726ee | ||
|
833cd88aea | ||
|
ee4907949b | ||
|
92c2b22735 | ||
|
33da8734fe | ||
|
9479fce7d0 | ||
|
0420538034 | ||
|
276fe53385 | ||
|
44dfb60c9c | ||
|
e7626535a8 | ||
|
0734e990b3 | ||
|
f9236d12bf | ||
|
e79ddee705 | ||
|
806d0775a4 | ||
|
a5670b6643 | ||
|
109af49933 | ||
|
bebb5c7a41 | ||
|
cc8664b0a8 | ||
|
af10e07ed7 | ||
|
5816b6a688 | ||
|
e95d2c4abe | ||
|
68740c70e4 | ||
|
722550c5bc | ||
|
553f700b79 | ||
|
d03a1fbd16 | ||
|
85a33ed8ef | ||
|
4a50000e83 | ||
|
8dd5462525 | ||
|
0f98ac5ff9 | ||
|
55cbe5d4d0 | ||
|
d098458ee4 | ||
|
47e3300b66 | ||
|
fad1007427 | ||
|
e6d4cac00e | ||
|
185e71fe12 | ||
|
b740b7f3ba | ||
|
1d35c04ab1 | ||
|
0fbc72f197 | ||
|
da0911d69b | ||
|
b30822fd0b | ||
|
aa6438fa06 | ||
|
67f3a3a9d8 | ||
|
9d53760016 | ||
|
a68b06226a | ||
|
eaca0634aa | ||
|
e20e81befd | ||
|
c3a831db7d | ||
|
909f3ba75e | ||
|
ce837b3727 | ||
|
65f37bccbd | ||
|
ea082b777d | ||
|
f6b10ed439 | ||
|
46714108ac | ||
|
c3f1eb26b1 | ||
|
d49404d248 | ||
|
e9b3a38171 | ||
|
bd7f8f2555 | ||
|
c6bafe3fc3 | ||
|
78a809795e | ||
|
b4208be4f4 | ||
|
de4983099a | ||
|
dce0e5fdeb | ||
|
1268bf3a35 | ||
|
c9d4a4ebb5 | ||
|
39f91f0dd6 | ||
|
9321df9630 | ||
|
cc9af4a5c5 | ||
|
19aea4096b | ||
|
8eee70aed9 | ||
|
79fd9ed6ad | ||
|
70bd90740a | ||
|
32a1ad87b7 | ||
|
180f0e16b0 | ||
|
b99ed2676a | ||
|
64832e0e9e | ||
|
d58ddef07b | ||
|
07c5e8fcb1 | ||
|
7e8d5fe57c | ||
|
846a9318ba | ||
|
5723b82293 | ||
|
6f73ee053d | ||
|
e6c4b4d1b2 | ||
|
52afba21d1 | ||
|
8153b765a2 | ||
|
d7d8da3fa9 | ||
|
b7e999b242 | ||
|
36d46567ba | ||
|
6c7dd761e2 | ||
|
ee7e58e44b | ||
|
759b497c07 | ||
|
aca5873de2 | ||
|
3e1863ec51 | ||
|
6bc64a9902 | ||
|
4d8f2cfac8 | ||
|
c27ee9d879 | ||
|
94ea44da0c | ||
|
8a3e0c3f24 | ||
|
da65b4e90d | ||
|
8d59bfcbdd | ||
|
dde983db8f | ||
|
79e4c22c6b | ||
|
0fa2d6ea2f | ||
|
7dc575d01e | ||
|
ddc9605271 | ||
|
d63a801821 | ||
|
b8bc84db4e | ||
|
4a05c4243d | ||
|
2a5375a0c8 | ||
|
8dd1b3c854 | ||
|
71ef40f4b6 | ||
|
bf6dff30cb | ||
|
0a09fba091 | ||
|
de95e6f6fc | ||
|
80d03f3c91 | ||
|
a3b44d20cb | ||
|
6fd2daae06 | ||
|
c97033b81c | ||
|
d580a33a7f | ||
|
d5a13900dd | ||
|
448e46ddce | ||
|
f448865b8a | ||
|
1069637e45 | ||
|
eb3e0eaa1e | ||
|
1c2af7fa5b | ||
|
eb0b642247 | ||
|
3e135a7c00 | ||
|
cda6621dc2 | ||
|
af7309b98d | ||
|
0787e5b271 | ||
|
b7555e9976 | ||
|
da00e240e5 | ||
|
8ff433bb97 | ||
|
cc8a09763f | ||
|
1538ad451c | ||
|
abfebf0eb2 | ||
|
1a66f26a5e | ||
|
e11faaf3fb | ||
|
a3dd58c92c | ||
|
3344480de7 | ||
|
e822f17bb7 | ||
|
ec8823e620 | ||
|
f1e9623371 | ||
|
750af6ebc3 | ||
|
f0d1b7fa8c | ||
|
6b44980c6c | ||
|
ddffcd7600 | ||
|
81a87a1e01 | ||
|
5a09a0476d | ||
|
d9d3ac685a | ||
|
772fb31ee5 | ||
|
648061bb95 | ||
|
7dcdaef9bd | ||
|
cc2950139d | ||
|
e6e19a7c89 | ||
|
b45ff0433e | ||
|
dc692754c3 | ||
|
b934ce41d9 |
BIN
.assets/bahamut-lagoon.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
.assets/tengai-makyou-zero.png
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
.assets/user-interface.png
Normal file
After Width: | Height: | Size: 46 KiB |
84
.cirrus.yml
@@ -1,84 +0,0 @@
|
||||
linux-x86_64-binaries_task:
|
||||
container:
|
||||
image: ubuntu:latest
|
||||
|
||||
setup_script:
|
||||
- apt-get update && apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libgtksourceview2.0-dev libcairo2-dev libsdl2-dev libxv-dev libao-dev libopenal-dev libudev-dev zip
|
||||
|
||||
compile_script:
|
||||
- make -C bsnes local=false
|
||||
|
||||
package_script:
|
||||
- mkdir bsnes-nightly
|
||||
- mkdir bsnes-nightly/Database
|
||||
- mkdir bsnes-nightly/Firmware
|
||||
- cp -a bsnes/out/bsnes bsnes-nightly/bsnes
|
||||
- cp -a bsnes/Database/* bsnes-nightly/Database
|
||||
- cp -a shaders bsnes-nightly/Shaders
|
||||
- cp -a GPLv3.txt bsnes-nightly
|
||||
- zip -r bsnes-nightly.zip bsnes-nightly
|
||||
|
||||
bsnes-nightly_artifacts:
|
||||
path: "bsnes-nightly.zip"
|
||||
|
||||
freebsd-x86_64-binaries_task:
|
||||
freebsd_instance:
|
||||
image: freebsd-12-0-release-amd64
|
||||
|
||||
setup_script:
|
||||
- pkg install --yes gmake gdb gcc8 pkgconf sdl2 openal-soft gtksourceview2 libXv zip
|
||||
|
||||
compile_script:
|
||||
- gmake -C bsnes local=false
|
||||
|
||||
package_script:
|
||||
- mkdir bsnes-nightly
|
||||
- mkdir bsnes-nightly/Database
|
||||
- mkdir bsnes-nightly/Firmware
|
||||
- cp -a bsnes/out/bsnes bsnes-nightly/bsnes
|
||||
- cp -a bsnes/Database/* bsnes-nightly/Database
|
||||
- cp -a shaders bsnes-nightly/Shaders
|
||||
- cp -a GPLv3.txt bsnes-nightly
|
||||
- zip -r bsnes-nightly.zip bsnes-nightly
|
||||
|
||||
bsnes-nightly_artifacts:
|
||||
path: "bsnes-nightly.zip"
|
||||
|
||||
windows-x86_64-binaries_task:
|
||||
container:
|
||||
image: ubuntu:latest
|
||||
|
||||
setup_script:
|
||||
- apt-get update && apt-get -y install build-essential mingw-w64 zip
|
||||
|
||||
compile_script:
|
||||
- make -C bsnes local=false platform=windows compiler="x86_64-w64-mingw32-g++" windres="x86_64-w64-mingw32-windres"
|
||||
|
||||
package_script:
|
||||
- mkdir bsnes-nightly
|
||||
- mkdir bsnes-nightly/Database
|
||||
- mkdir bsnes-nightly/Firmware
|
||||
- cp -a bsnes/out/bsnes bsnes-nightly/bsnes.exe
|
||||
- cp -a bsnes/Database/* bsnes-nightly/Database
|
||||
- cp -a shaders bsnes-nightly/Shaders
|
||||
- cp -a GPLv3.txt bsnes-nightly
|
||||
- zip -r bsnes-nightly.zip bsnes-nightly
|
||||
|
||||
bsnes-nightly_artifacts:
|
||||
path: "bsnes-nightly.zip"
|
||||
|
||||
macOS-x86_64-binaries_task:
|
||||
osx_instance:
|
||||
image: mojave-base
|
||||
|
||||
compile_script:
|
||||
- make -C bsnes local=false
|
||||
|
||||
package_script:
|
||||
- mkdir bsnes-nightly
|
||||
- cp -a bsnes/out/bsnes.app bsnes-nightly
|
||||
- cp -a GPLv3.txt bsnes-nightly
|
||||
- zip -r bsnes-nightly.zip bsnes-nightly
|
||||
|
||||
bsnes-nightly_artifacts:
|
||||
path: "bsnes-nightly.zip"
|
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
||||
patreon: byuu
|
158
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags: [ 'v*' ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- name: ubuntu
|
||||
version: latest
|
||||
- name: windows
|
||||
version: latest
|
||||
- name: macos
|
||||
version: latest
|
||||
runs-on: ${{ matrix.os.name }}-${{ matrix.os.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Dependencies
|
||||
if: matrix.os.name == 'ubuntu'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install libsdl2-dev libgtk-3-dev gtksourceview-3.0 libao-dev libopenal-dev
|
||||
- name: Make
|
||||
run: make -j4 -C bsnes local=false
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bsnes-${{ matrix.os.name }}
|
||||
path: bsnes/out/bsnes*
|
||||
|
||||
build-freebsd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
release: "14.3"
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg install --yes gmake gdb gcc14 pkgconf sdl2 openal-soft gtk3 gtksourceview3 libXv zip
|
||||
run: |
|
||||
gmake -j4 -C bsnes local=false
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bsnes-freebsd
|
||||
path: bsnes/out/bsnes*
|
||||
|
||||
release:
|
||||
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
|
||||
# Prevent multiple conflicting release jobs from running at once.
|
||||
concurrency: release-${{ github.ref == 'refs/heads/master' && 'nightly' || github.ref }}
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
- build-freebsd
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: 'src'
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
path: 'bin'
|
||||
- name: Package Artifacts
|
||||
run: |
|
||||
set -eu
|
||||
case ${GITHUB_REF} in
|
||||
refs/tags/*) suffix="-${GITHUB_REF#refs/tags/}" ;;
|
||||
refs/heads/master) suffix="-nightly" ;;
|
||||
*) suffix="" ;;
|
||||
esac
|
||||
|
||||
srcdir="${GITHUB_WORKSPACE}/src"
|
||||
bindir="${GITHUB_WORKSPACE}/bin"
|
||||
|
||||
# Hack: Workaround for GitHub artifacts losing attributes.
|
||||
for program in bsnes
|
||||
do
|
||||
chmod +x ${bindir}/${program}-ubuntu/${program}
|
||||
chmod +x ${bindir}/${program}-macos/${program}.app/Contents/MacOS/${program}
|
||||
done
|
||||
|
||||
for os in ubuntu windows macos freebsd
|
||||
do
|
||||
mkdir "${os}"
|
||||
cd "${os}"
|
||||
|
||||
# Package bsnes.
|
||||
outdir=bsnes${suffix}
|
||||
mkdir ${outdir}
|
||||
mkdir ${outdir}/Database
|
||||
mkdir ${outdir}/Firmware
|
||||
cp -ar ${bindir}/bsnes-${os}/* ${outdir}
|
||||
cp -a ${srcdir}/bsnes/Database/* ${outdir}/Database
|
||||
cp -a ${srcdir}/shaders ${outdir}/Shaders
|
||||
cp -a ${srcdir}/GPLv3.txt ${outdir}
|
||||
cp -a ${srcdir}/extras/* ${outdir}
|
||||
zip -r ../bsnes-${os}.zip ${outdir}
|
||||
|
||||
cd -
|
||||
done
|
||||
- name: Calculate release info
|
||||
id: relinfo
|
||||
run: |
|
||||
echo "datetime=$(date -u +"%Y-%m-%d %T %Z")" >> $GITHUB_OUTPUT
|
||||
echo "date=$(date +"%Y-%m-%d")" >> $GITHUB_OUTPUT
|
||||
- name: Delete old nightly release
|
||||
uses: actions/github-script@v7
|
||||
id: release
|
||||
if: ${{!startsWith(github.ref, 'refs/tags/')}}
|
||||
with:
|
||||
retries: 3
|
||||
script: |
|
||||
const {owner, repo} = context.repo;
|
||||
try {
|
||||
const release = await github.rest.repos.getReleaseByTag({owner, repo, tag: "nightly"});
|
||||
if (release && release.status === 200) {
|
||||
await github.rest.repos.deleteRelease({owner, repo, release_id: release.data.id});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`error deleting old release: ${e}`);
|
||||
}
|
||||
try {
|
||||
await github.rest.git.deleteRef({owner, repo, ref: "tags/nightly"});
|
||||
} catch (e) {
|
||||
console.log(`error trying to delete ref: ${e}`);
|
||||
}
|
||||
await github.rest.git.createTag({
|
||||
owner,
|
||||
repo,
|
||||
tag: "nightly",
|
||||
message: "nightly release",
|
||||
object: context.sha,
|
||||
type: "commit",
|
||||
})
|
||||
- name: Create nightly release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: ${{!startsWith(github.ref, 'refs/tags/')}}
|
||||
with:
|
||||
tag_name: nightly
|
||||
name: bsnes nightly ${{steps.relinfo.outputs.date}}
|
||||
body: Auto-generated nightly release on ${{steps.relinfo.outputs.datetime}}
|
||||
files: bsnes*.zip
|
||||
prerelease: true
|
||||
- name: Create version release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: ${{startsWith(github.ref, 'refs/tags/')}}
|
||||
with:
|
||||
name: bsnes ${{github.ref_name}}
|
||||
body: This is bsnes ${{github.ref_name}}, released on ${{steps.relinfo.outputs.date}}.
|
||||
files: bsnes*.zip
|
1
.gitignore
vendored
@@ -0,0 +1 @@
|
||||
hiro/qt/qt.moc
|
||||
|
@@ -1,89 +0,0 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
Code contributions are most welcome and highly appreciated!
|
||||
|
||||
But first, please note that although bsnes is licensed under the GPLv3 license,
|
||||
in order to be merged upstream, any code contributions must be provided under
|
||||
the ISC source code license.
|
||||
|
||||
This is *not* a CLA (community license agreement), no legal contract needs to be
|
||||
signed, and you will maintain full and exclusive copyright ownership over any
|
||||
contributed source code.
|
||||
|
||||
There are two reasons for this requirement:
|
||||
|
||||
GPLv4+
|
||||
------
|
||||
|
||||
bsnes is currently licensed under the GPLv3 license only. I do not license bsnes
|
||||
under the GPLv3 or later license, because there is no way of knowing what the
|
||||
GPLv4 and later licenses will change, and if they will be in the best interests
|
||||
of emulator development and video game preservation.
|
||||
|
||||
Although I put a good deal of trust into the FSF, no one is an oracle that can
|
||||
predict the future. Would *you* agree to a license before being able to read it?
|
||||
|
||||
However, the GPLv4 may prove beneficial, and close important holes in the GPLv3
|
||||
license, just as the GPLv3 license closed the GPLv2's TiVoization loophole. And
|
||||
so it is important that bsnes retains the option of relicensing to the GPLv4+ in
|
||||
the future.
|
||||
|
||||
As a point of interest, there have been projects with similar concerns about
|
||||
using a GPLv2 or later clause, that are now permanently stuck on the GPLv2
|
||||
license. There have also been projects that did use a GPLv2 or later clause,
|
||||
only to disagree with the changes introduced in the GPLv3.
|
||||
|
||||
ISC
|
||||
---
|
||||
|
||||
The more important reason for this requirement is that it is my intention to
|
||||
release the entirety of bsnes under the ISC license once official upstream
|
||||
development has ceased.
|
||||
|
||||
The reason I would want to relicense bsnes to the ISC license upon its official
|
||||
discontinuation is because once again, no one is an oracle, and I cannot predict
|
||||
what future issues bsnes permanently remaining under the GPLv3 license may
|
||||
cause.
|
||||
|
||||
For instance, imagine a world where a certain vendor took over the world, and
|
||||
the only way to distribute applications was with their approval, and their store
|
||||
rules forbade GPLv3 software. Or perhaps a world where the GPL was abandoned in
|
||||
favor of the new OSSv1 license. But GPLv3 software was incompatible with the
|
||||
OSSv1 license. Other open source developers would not be able to use bsnes in
|
||||
that scenario.
|
||||
|
||||
It would be very disappointing if all of our work ended up unusable 50+ years
|
||||
into the future because it was permanently bound to the GPLv3 license.
|
||||
|
||||
GPLv3
|
||||
-----
|
||||
|
||||
The reason I use the GPLv3 license currently is because it is a balance between
|
||||
altruism and self-interest. The GPLv3 allows other vendors to sell my own code
|
||||
without sharing revenue with me, and indeed this has already happened. But the
|
||||
GPLv3 also prevents other vendors from improving upon bsnes without sharing
|
||||
their work with everyone else as I have.
|
||||
|
||||
While I am actively developing bsnes, I do not wish to compete against myself.
|
||||
|
||||
As such, I believe the GPLv3 is the best license during active development, and
|
||||
the ISC is the best license once bsnes is officially discontinued.
|
||||
|
||||
Considerations
|
||||
--------------
|
||||
|
||||
This is the part that should concern you as a contributor: I am not requesting
|
||||
contributed source code to be released under the ISC so that I personally may
|
||||
sell GPLv3 commercial license exemptions to your work, but in the future when
|
||||
bsnes is released under the ISC license, that will open the door for anyone to
|
||||
sell the work commercially in a closed source form.
|
||||
|
||||
If this is not acceptable to you, I wholly understand and I welcome you to
|
||||
release your work under the GPLv3 in the form of a bsnes fork. And if your work
|
||||
is not an essential part of the core emulation -- that is to say, it may be
|
||||
optionally disabled -- then I am still willing to work with you in merging such
|
||||
work upstream anyway under the full GPLv3 license, but please reach out to me
|
||||
first before developing under the assumption your work will be merged upstream.
|
||||
|
||||
Thank you very much for reading and hopefully for your understanding.
|
59
CREDITS.md
Normal file
@@ -0,0 +1,59 @@
|
||||
bsnes was originally developed by byuu, and is now a group project.
|
||||
|
||||
This software would not be where it is today without the help and support of the following individuals:
|
||||
|
||||
- Andreas Naive
|
||||
- Ange Albertini
|
||||
- anomie
|
||||
- AWJ
|
||||
- BearOso
|
||||
- Bisqwit
|
||||
- blargg
|
||||
- byuu
|
||||
- Łukasz Krawczyk
|
||||
- Danish
|
||||
- DerKoun
|
||||
- DMV27
|
||||
- Dr. Decapitator
|
||||
- endrift
|
||||
- Fatbag
|
||||
- FitzRoy
|
||||
- gekkio
|
||||
- GIGO
|
||||
- Hendricks266
|
||||
- hex_usr
|
||||
- ikari_01
|
||||
- jchadwick
|
||||
- Jonas Quinn
|
||||
- kode54
|
||||
- krom
|
||||
- Lioncash
|
||||
- Lord Nightmare
|
||||
- lowkey
|
||||
- Matthew Callis
|
||||
- Max833
|
||||
- MerryMage
|
||||
- mightymo
|
||||
- Nach
|
||||
- ncbncb
|
||||
- neviksti
|
||||
- OV2
|
||||
- Overload
|
||||
- p4plus2
|
||||
- quequotion
|
||||
- qwertymodo
|
||||
- RedDwarf
|
||||
- Richard Bannister
|
||||
- Ryphecha
|
||||
- segher
|
||||
- Sintendo
|
||||
- SuperMikeMan
|
||||
- Talarubi
|
||||
- tetsuo55
|
||||
- TmEE
|
||||
- TRAC
|
||||
- wareya
|
||||
- zones
|
||||
|
||||
If you feel you are missing from this list, please submit a pull request and we will be happy to add your name here!
|
||||
|
10
LICENSE.txt
@@ -1,14 +1,14 @@
|
||||
----------------------------------------------------------------------
|
||||
bsnes - Super Nintendo emulator
|
||||
|
||||
Copyright © 2004-2019 byuu
|
||||
Copyright © 2004-2020 byuu et al
|
||||
|
||||
https://byuu.org
|
||||
https://byuu.org/bsnes/
|
||||
|
||||
This program 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, specifically version 3 of the License
|
||||
and no other version.
|
||||
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 WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -25,7 +25,7 @@ nall - C++ template library
|
||||
ruby - Hardware abstraction library
|
||||
hiro - User interface library
|
||||
|
||||
Copyright © 2006-2019 byuu
|
||||
Copyright © 2006-2020 byuu et al
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted, provided that the
|
||||
|
43
README.md
@@ -1,31 +1,15 @@
|
||||
bsnes
|
||||
=====
|
||||
|
||||

|
||||

|
||||
|
||||
bsnes is a multi-platform Super Nintendo (Super Famicom) emulator that focuses
|
||||
on performance, features, and ease of use.
|
||||
|
||||
bsnes currently enjoys 100% known, bug-free compatibility with the entire SNES
|
||||
library when configured to its most accurate settings, giving it the same
|
||||
accuracy level as higan. Accuracy can also optionally be traded for performance,
|
||||
allowing bsnes to operate more than 300% faster than higan while still remaining
|
||||
almost as accurate.
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
Git is used for the development of new releases, and represents a staging
|
||||
environment. As bsnes is rather mature, things should generally be quite stable.
|
||||
However, bugs will exist, regressions will occur, so proceed at your own risk.
|
||||
|
||||
If stability is required, please download the latest stable release from the
|
||||
[official website.](https://bsnes.byuu.org)
|
||||
bsnes is a multi-platform Super Nintendo (Super Famicom) emulator, originally
|
||||
developed by Near, which focuses on performance,
|
||||
features, and ease of use.
|
||||
|
||||
Unique Features
|
||||
---------------
|
||||
|
||||
- 100% (known) bug-free compatibility with the entire officially licensed SNES games library
|
||||
- True Super Game Boy emulation (using the SameBoy core by Lior Halphon)
|
||||
- HD mode 7 graphics with optional supersampling (by DerKoun)
|
||||
- Low-level emulation of all SNES coprocessors (DSP-n, ST-01n, Cx4)
|
||||
@@ -72,21 +56,20 @@ Standard Features
|
||||
Links
|
||||
-----
|
||||
|
||||
- [Official website](https://bsnes.byuu.org)
|
||||
- [Official git repository](https://github.com/byuu/bsnes)
|
||||
- [Developer resources](https://byuu.net)
|
||||
- [Donations](https://patreon.com/byuu)
|
||||
- [Official git repository](https://github.com/bsnes-emu/bsnes)
|
||||
- [Official Discord](https://discord.gg/B27hf27ZVf)
|
||||
|
||||
Nightly Builds
|
||||
--------------
|
||||
|
||||
- [Download](https://cirrus-ci.com/github/byuu/bsnes/master)
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- [Windows](https://github.com/bsnes-emu/bsnes/releases/download/nightly/bsnes-windows.zip)
|
||||
- [macOS](https://github.com/bsnes-emu/bsnes/releases/download/nightly/bsnes-macos.zip)
|
||||
- [Linux](https://github.com/bsnes-emu/bsnes/releases/download/nightly/bsnes-ubuntu.zip)
|
||||
- [FreeBSD](https://api.cirrus-ci.com/v1/artifact/github/bsnes-emu/bsnes/freebsd-x86_64-binaries/bsnes-nightly/bsnes-nightly.zip)
|
||||
|
||||
Preview
|
||||
-------
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
@@ -1,5 +1,5 @@
|
||||
database
|
||||
revision: 2018-09-20
|
||||
revision: 2020-01-01
|
||||
|
||||
//BS Memory (JPN)
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
database
|
||||
revision: 2018-09-20
|
||||
revision: 2020-01-01
|
||||
|
||||
//Sufami Turbo (JPN)
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
database
|
||||
revision: 2018-09-20
|
||||
revision: 2020-01-21
|
||||
|
||||
//Prototypes (JPN)
|
||||
|
||||
@@ -125,7 +125,7 @@ game
|
||||
//Super Famicom (JPN)
|
||||
|
||||
database
|
||||
revision: 2018-09-20
|
||||
revision: 2020-01-21
|
||||
|
||||
game
|
||||
sha256: 5c4e283efc338958b8dd45ebd6daf133a9eb280420a98e2e1df358ae0242c366
|
||||
@@ -171,6 +171,22 @@ game
|
||||
size: 0x8000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: a98eb5f0521746e6ce6d208591e86d366b6e0479d96474bfff43856fe8cfec12
|
||||
label: バハムートラグーン
|
||||
name: Bahamut Lagoon
|
||||
region: SHVC-AXBJ-JPN
|
||||
revision: SHVC-AXBJ-0
|
||||
board: SHVC-1J3M-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x300000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 47779500c43a0c2e75d7684078489a17baea31170a123063b8ece6ce77359413
|
||||
label: ボール・ブレット・ガン
|
||||
@@ -1277,7 +1293,7 @@ game
|
||||
size: 0x100
|
||||
content: Boot
|
||||
manufacturer: Nintendo
|
||||
architecture: LR35902
|
||||
architecture: SM83
|
||||
identifier: SGB1
|
||||
|
||||
game
|
||||
@@ -1296,7 +1312,7 @@ game
|
||||
size: 0x100
|
||||
content: Boot
|
||||
manufacturer: Nintendo
|
||||
architecture: LR35902
|
||||
architecture: SM83
|
||||
identifier: SGB2
|
||||
oscillator
|
||||
frequency: 20971520
|
||||
@@ -1465,6 +1481,22 @@ game
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 77b2d5450ce3c87185f913c2584673530c13dfbe8cc433b1e9fe5e9a653bf7d5
|
||||
label: テイルズオブファンタジア
|
||||
name: Tales of Phantasia
|
||||
region: SHVC-ATVJ-JPN
|
||||
revision: SHVC-ATVJ-0
|
||||
board: SHVC-LJ3M-01
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x600000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: c9002e77bcc656e033c35e2574ee6067c4c0d070943359a850806c123a558949
|
||||
label: 戦え原始人3 主役はやっぱりジョーアンドマック
|
||||
@@ -1705,7 +1737,7 @@ game
|
||||
//Super Nintendo (ESP)
|
||||
|
||||
database
|
||||
revision: 2018-04-14
|
||||
revision: 2018-09-21
|
||||
|
||||
game
|
||||
sha256: bd5e7a6bc08f64d39c54204b82c6c156f144c03e13c890128588c5faa560659c
|
||||
@@ -1767,6 +1799,50 @@ game
|
||||
size: 0x200000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: bd7e98db82d6b52307be1f3e1fd171e1e7204dc1f8810a95ee2cc64757087e4a
|
||||
label: The Lost Vikings
|
||||
name: Lost Vikings, The
|
||||
region: SNSP-LV-ESP
|
||||
revision: SESP-LV-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 6eecabd46305ac95d9cf3a17e1392c24a1b68a7a313173ef0c5b5a3a24cf3353
|
||||
label: Lufia
|
||||
name: Lufia
|
||||
region: SNSP-ANIS-ESP
|
||||
revision: SPAL-ANIS-0
|
||||
board: SHVC-1A3M-30
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x300000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: d70bc7916ed5132c3b0053f2adbb5004d78ccb986210c9440fedf642cac68554
|
||||
label: MechWarrior
|
||||
name: MechWarrior
|
||||
region: SNSP-WM-ESP
|
||||
revision: SESP-WM-0
|
||||
board: SHVC-1A1M-10
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x800
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: d2233d6310522bbf183b6ca9bbe3e2afaf24de0cc4304bff6d0d547d678aed6f
|
||||
label: Sonic Blast Man
|
||||
@@ -1779,6 +1855,18 @@ game
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: a20d346da18ddabf70dc43f5095c4189c4a646ca8e6d4ed6c68c20e380f50332
|
||||
label: Super Battletank 2
|
||||
name: Super Battletank 2
|
||||
region: SNSP-2X-ESP
|
||||
revision: SESP-2X-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x200000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 9eaf1c46d8a068c910d66f582e23b1155882ddfa4b9fd0813819fc5c008167e2
|
||||
label: Super James Pond
|
||||
@@ -1803,6 +1891,46 @@ game
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 7f731f4bb620e682132660da39641dda5762211dca4732f8192dd2411211b822
|
||||
label: Terranigma
|
||||
name: Terranigma
|
||||
region: SNSP-AQTS-ESP
|
||||
revision: SPAL-AQTS-0
|
||||
board: SHVC-1J3M-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x400000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 981128c93f0753dec7af29ec084f13e704cc5d02414be55bb477fc4b2fef5e58
|
||||
label: Tiny Toon Adventures: Buster Busts Loose!
|
||||
name: Tiny Toon Adventures - Buster Busts Loose!
|
||||
region: SNSP-TA-ESP
|
||||
revision: SESP-TA-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: ce2445ecd0a43f6025dc80857d91dae7c46d33f7821bf98232c2894ca1959da2
|
||||
label: Turn and Burn: No-Fly Zone
|
||||
name: Turn and Burn - No-Fly Zone
|
||||
region: SNSP-ZN-ESP
|
||||
revision: SESP-ZN-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x200000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 9ed876a632aa699047e9efba8a64ab57abc55086a0aab6b5fa67d87ea4647f3f
|
||||
label: Whirlo
|
||||
@@ -1846,7 +1974,7 @@ game
|
||||
//Super Nintendo (EUR)
|
||||
|
||||
database
|
||||
revision: 2018-05-06
|
||||
revision: 2018-09-21
|
||||
|
||||
game
|
||||
sha256: ec3e81d628a293514e303b44e3b1ac03461ddd1da32764b10b7fab1e507602df
|
||||
@@ -2904,6 +3032,18 @@ game
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 4ad736a9e1c7f34740afaa7777b8f1a31da4bb4a021e7ae341d1dafd74fa0acc
|
||||
label: True Lies
|
||||
name: True Lies
|
||||
region: SNSP-ATLP-EUR
|
||||
revision: SPAL-ATLP-0
|
||||
board: SHVC-1A0N-30
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x200000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: dbf11d4c77b9aa3416f687201d57d71a23bb8fb0b8fe5e9e8212db3fac036631
|
||||
label: Turbo Toons
|
||||
@@ -2942,7 +3082,7 @@ game
|
||||
|
||||
game
|
||||
sha256: 1217ddf2fe475661a54f50e111864102faf854397ce5aceea4297204ebd6cbb6
|
||||
label: Val d'isére Championship
|
||||
label: Val d'isère Championship
|
||||
name: Val d'isere Championship
|
||||
region: SNSP-8Z-EUR
|
||||
revision: SPAL-8Z-0
|
||||
@@ -3016,7 +3156,7 @@ game
|
||||
//Super Nintendo (FAH)
|
||||
|
||||
database
|
||||
revision: 2018-04-14
|
||||
revision: 2018-09-21
|
||||
|
||||
game
|
||||
sha256: 0aafd04a43ae29266e43920a7f9954d4a49f6fe43a5abffecc9c2fd5ad7d6cea
|
||||
@@ -3110,6 +3250,18 @@ game
|
||||
size: 0x800
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 826a328f401cdf5a9ee87aaa7a2784cbb21813b165a6c7ca3f702fe6ba8c0804
|
||||
label: Eric Cantona: Football Challenge
|
||||
name: Eric Cantona - Football Challenge
|
||||
region: SNSP-EC-FAH
|
||||
revision: SPAL-EC-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x80000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: ce09743d44a54f64862d8c53c11c2c84f2f861ec74c778bd8b05b0a3b07708d6
|
||||
label: FIFA International Soccer
|
||||
@@ -3423,10 +3575,22 @@ game
|
||||
size: 0x180000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 5a9103b04b9246f63af9018cbbd7934c6b79076dd9b0062887bd16077cd37c81
|
||||
label: Val d'Isère Championship
|
||||
name: Val d'Isere Championship
|
||||
region: SNSP-8V-FAH
|
||||
revision: SPAL-8V-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
//Super Nintendo (FRA)
|
||||
|
||||
database
|
||||
revision: 2018-04-14
|
||||
revision: 2018-09-21
|
||||
|
||||
game
|
||||
sha256: 65df600780021f13ced52e7fbc507b7b2e6491b2c5c25fe78d0515dcbe669403
|
||||
@@ -3660,6 +3824,22 @@ game
|
||||
size: 0x180000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: b730adcbb34a19f8fd1c2abe27455cc3256329a9b8a021291e3009ea33004127
|
||||
label: Secret of Mana
|
||||
name: Secret of Mana
|
||||
region: SNSP-K2-FRA
|
||||
revision: SFRA-K2-1
|
||||
board: SHVC-1J3M-11
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x200000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: f73e6da9e979c839c7c22ec487bea6667d3e65e7d8f9fcc97a2bcdeb4487cddf
|
||||
label: SimCity
|
||||
@@ -3676,6 +3856,38 @@ game
|
||||
size: 0x8000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 1f226553ba05fe738d085a88154469bbc9f9058f7dfc320a327259d84ae5f393
|
||||
label: Soul Blazer
|
||||
name: Soul Blazer
|
||||
region: SNSP-SO-FRA
|
||||
revision: SFRA-SO-0
|
||||
board: SHVC-1J3M-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 5d0a234a2fcb343d169206d9d7d578507c44f800ead9cc9ccfa0b1d4cb1cc9e5
|
||||
label: Terranigma
|
||||
name: Terranigma
|
||||
region: SNSP-AQTF-FRA
|
||||
revision: SPAL-AQTF-0
|
||||
board: SHVC-1J3M-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x400000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
//Super Nintendo (FRG)
|
||||
|
||||
database
|
||||
@@ -3762,7 +3974,23 @@ game
|
||||
//Super Nintendo (ITA)
|
||||
|
||||
database
|
||||
revision: 2018-04-14
|
||||
revision: 2018-09-21
|
||||
|
||||
game
|
||||
sha256: deab7aad7c168423e43eae14e9e31efa29c7341ab84f936be508911ce508b372
|
||||
label: MechWarrior
|
||||
name: MechWarrior
|
||||
region: SNSP-WM-ITA
|
||||
revision: SITA-WM-0
|
||||
board: SHVC-1A1M-01
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x800
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: aafbae4c2a7a5a35c81a183df0470027b4b5690f836592af21c15af6b259328d
|
||||
@@ -3796,7 +4024,7 @@ game
|
||||
//Super Nintendo (NOE)
|
||||
|
||||
database
|
||||
revision: 2018-04-14
|
||||
revision: 2020-01-01
|
||||
|
||||
game
|
||||
sha256: b342d12d71729edebc1911725ea23d58c1a397b27253a5c8cd96cfb58af242a9
|
||||
@@ -4394,6 +4622,18 @@ game
|
||||
size: 0x80000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 09299d142e485ba2fcdbd9b3a6d1a5acfbc7fc70b06cf22be28479686419a7a9
|
||||
label: Jimmy Connors Pro Tennis Tour
|
||||
name: Jimmy Connors Pro Tennis Tour
|
||||
region: SNSP-JC-NOE
|
||||
revision: SFRG-JC-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x80000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 74c55ea3c9733bf263628a260df7492fc840d7de1c3fceebb7bcf6d99a8c81d6
|
||||
label: Joe & Mac: Caveman Ninja
|
||||
@@ -4470,6 +4710,18 @@ game
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 4a7444780a750f97943d974589586d4cf89d8957e396cc5a7ad565cd4c1b70a7
|
||||
label: The Legend of the Mystical Ninja
|
||||
name: Legend of the Mystical Ninja, The
|
||||
region: SNSP-GG-NOE
|
||||
revision: SFRG-GG-0
|
||||
board: SHVC-1A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 5ec66298ddb579b35cc5d3df5bfeeee05bdf71347565c7c5f5f3869bf4f1e469
|
||||
label: Looney Tunes Basketball
|
||||
@@ -4820,7 +5072,7 @@ game
|
||||
size: 0x100
|
||||
content: Boot
|
||||
manufacturer: Nintendo
|
||||
architecture: LR35902
|
||||
architecture: SM83
|
||||
identifier: SGB1
|
||||
|
||||
game
|
||||
@@ -4975,6 +5227,18 @@ game
|
||||
size: 0x100000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 94e6fe78bb1a1d89ccfd74ad92e2a489f8e2e257d6dfe62404155741763f962f
|
||||
label: True Lies
|
||||
name: True Lies
|
||||
region: SNSP-ATLD-NOE
|
||||
revision: SPAL-ATLD-0
|
||||
board: SHVC-1A0N-30
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x200000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: a1105819d48c04d680c8292bbfa9abbce05224f1bc231afd66af43b7e0a1fd4e
|
||||
label: Unirally
|
||||
@@ -5054,7 +5318,7 @@ game
|
||||
//Super Nintendo (SCN)
|
||||
|
||||
database
|
||||
revision: 2018-04-14
|
||||
revision: 2018-09-21
|
||||
|
||||
game
|
||||
sha256: beb379ba48f63561c0f939ecd8f623ec06c1b5e06976eef9887e5c62f3df2766
|
||||
@@ -5080,6 +5344,22 @@ game
|
||||
size: 0x300000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: 4fb9eb8fa4d9c3a0b6c24bac5b0a0b0f079f083f5e6dfa937a161c8f4bcde853
|
||||
label: Shadowrun
|
||||
name: Shadowrun
|
||||
region: SNSP-WR-SCN
|
||||
revision: SSWE-WR-0
|
||||
board: SHVC-1A3M-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x100000
|
||||
content: Program
|
||||
memory
|
||||
type: RAM
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: e15247495311e91db9431d61777a264d4b42def011291d512b273fc8acd1cbfa
|
||||
label: Soul Blazer
|
||||
@@ -5096,6 +5376,18 @@ game
|
||||
size: 0x2000
|
||||
content: Save
|
||||
|
||||
game
|
||||
sha256: 687c4f9a14cc16605f5e92aa0fe33bf083fe8e39ba781676259fadf932480890
|
||||
label: Tintin i Tibet
|
||||
name: Tintin i Tibet
|
||||
region: SNSP-AT6X-SCN
|
||||
revision: SPAL-AT6X-0
|
||||
board: SHVC-2A0N-20
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x180000
|
||||
content: Program
|
||||
|
||||
game
|
||||
sha256: a6297356fb06f1575b432fae463171f53e3b786fd77b841557547a9117fb52fe
|
||||
label: X-Zone
|
||||
@@ -5761,7 +6053,7 @@ game
|
||||
//Super Nintendo (USA)
|
||||
|
||||
database
|
||||
revision: 2018-09-20
|
||||
revision: 2020-01-01
|
||||
|
||||
game
|
||||
sha256: 2ffe8828480f943056fb1ab5c3c84d48a0bf8cbe3ed7c9960b349b59adb07f3b
|
||||
@@ -6555,8 +6847,8 @@ game
|
||||
sha256: 6fa6b8a8804ff6544bdedf94339a86ba64ce0b6dbf059605abb1cd6f102d3483
|
||||
label: Bill Laimbeer's Combat Basketball
|
||||
name: Bill Laimbeer's Combat Basketball
|
||||
region: SNS-C8-USA
|
||||
revision: SNS-C8-0
|
||||
region: SNS-CB-USA
|
||||
revision: SNS-CB-0
|
||||
board: SHVC-1A3B-12
|
||||
memory
|
||||
type: ROM
|
||||
@@ -13628,7 +13920,7 @@ game
|
||||
size: 0x100
|
||||
content: Boot
|
||||
manufacturer: Nintendo
|
||||
architecture: LR35902
|
||||
architecture: SM83
|
||||
identifier: SGB1
|
||||
|
||||
game
|
||||
@@ -14516,8 +14808,8 @@ game
|
||||
sha256: 3cdebbd8adc4bb6773a7995f542fdac49adefca71cba583255a1c1bf37ac3946
|
||||
label: Tetris & Dr. Mario
|
||||
name: Tetris & Dr. Mario
|
||||
region: SNS-AFTE-USA
|
||||
revision: SNS-AFTE-0
|
||||
region: SNS-ATFE-USA
|
||||
revision: SNS-ATFE-0
|
||||
board: SHVC-1A0N-30
|
||||
memory
|
||||
type: ROM
|
||||
|
53
bsnes/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
bsnes source code
|
||||
=================
|
||||
|
||||
A guide to what all these directories are for:
|
||||
|
||||
- [Database](./Database/)
|
||||
contains the databases bsnes uses
|
||||
to figure out what circuit board a game expects,
|
||||
and also the database of pre-made game cheats
|
||||
- [emulator](./emulator/)
|
||||
contains the interface
|
||||
that the emulation core in [sfc](./sfc/) implements
|
||||
- It comes from higan v106,
|
||||
which has many emulation cores
|
||||
that all implement the same interface —
|
||||
bsnes only has one,
|
||||
but the interface is still a good abstraction,
|
||||
so it's still here.
|
||||
- [filter](./filter/)
|
||||
contains classic CPU-based image upscaling filters,
|
||||
like HQ2x and Super Eagle
|
||||
- [gb](./gb/)
|
||||
contains the SameBoy emulator code
|
||||
used for Super Game Boy emulation
|
||||
- [heuristics](./heuristics/)
|
||||
contains the logic that guesses
|
||||
which memory map a particular game expects
|
||||
and what extra hardware it assumes is present,
|
||||
when a game cannot be found in the database
|
||||
- [Locale](./Locale/)
|
||||
contains translation databases
|
||||
that bsnes can use to display its user interface
|
||||
in a different language
|
||||
- [lzma](./lzma/)
|
||||
contains the 7-Zip SDK
|
||||
allowing bsnes to understad `.7z` archives
|
||||
- [processor](./processor/)
|
||||
contains all the CPU emulation cores
|
||||
used by the hardware bsnes emulates
|
||||
- Another holdover from higan v106,
|
||||
where different supported systems
|
||||
happen to use the same model CPU,
|
||||
so the CPU emulation cores
|
||||
are not specific to a system
|
||||
- [sfc](./sfc/)
|
||||
contains Super Famicom (SNES) emulation code
|
||||
- [target-bsnes](./target-bsnes/)
|
||||
contains the normal bsnes user interface
|
||||
- [target-libretro](./target-libretro/)
|
||||
implements the "libretro" API
|
||||
on top of bsnes' native
|
||||
[emulator](./emulator/) API,
|
||||
so bsnes can be used with libretro-based frontends
|
@@ -1,5 +1,3 @@
|
||||
#define double float
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
#include "stream.cpp"
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#define double float
|
||||
|
||||
#include <nall/dsp/iir/dc-removal.hpp>
|
||||
#include <nall/dsp/iir/one-pole.hpp>
|
||||
|
@@ -28,14 +28,14 @@ using namespace nall;
|
||||
#include <emulator/audio/audio.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "bsnes";
|
||||
static const string Version = "113";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org";
|
||||
static const string Name = "bsnes";
|
||||
static const string Version = "115";
|
||||
static const string Copyright = "bsnes team";
|
||||
static const string License = "GPLv3 or later";
|
||||
static const string Website = "https://github.com/bsnes-emu/bsnes/";
|
||||
|
||||
//incremented only when serialization format changes
|
||||
static const string SerializerVersion = "112";
|
||||
static const string SerializerVersion = "115.1";
|
||||
|
||||
namespace Constants {
|
||||
namespace Colorburst {
|
||||
|
@@ -101,7 +101,6 @@ Game::Memory::Memory(Markup::Node node) {
|
||||
}
|
||||
|
||||
auto Game::Memory::name() const -> string {
|
||||
if(identifier) return string{identifier, ".", content, ".", type}.downcase();
|
||||
if(architecture) return string{architecture, ".", content, ".", type}.downcase();
|
||||
return string{content, ".", type}.downcase();
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ struct Platform {
|
||||
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> shared_pointer<vfs::file> { return {}; }
|
||||
virtual auto load(uint id, string name, string type, vector<string> options = {}) -> Load { return {}; }
|
||||
virtual auto videoFrame(const uint16* data, uint pitch, uint width, uint height, uint scale) -> void {}
|
||||
virtual auto audioFrame(const float* samples, uint channels) -> void {}
|
||||
virtual auto audioFrame(const double* samples, uint channels) -> void {}
|
||||
virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; }
|
||||
virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {}
|
||||
virtual auto dipSettings(Markup::Node node) -> uint { return 0; }
|
||||
|
11
bsnes/gb/.gitattributes
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# Always use LF line endings for shaders
|
||||
*.fsh text eol=lf
|
||||
*.metal text eol=lf
|
||||
|
||||
HexFiend/* linguist-vendored
|
||||
*.inc linguist-language=C
|
||||
Core/*.h linguist-language=C
|
||||
SDL/*.h linguist-language=C
|
||||
Windows/*.h linguist-language=C
|
||||
XdgThumbnailer/*.h linguist-language=C
|
||||
Cocoa/*.h linguist-language=Objective-C
|
3
bsnes/gb/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: LIJI32
|
25
bsnes/gb/.github/actions/LICENSE
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Blargg's Test ROMs by Shay Green <gblargg@gmail.com>
|
||||
|
||||
Acid2 tests by Matt Currie under MIT:
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Matt Currie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
BIN
bsnes/gb/.github/actions/cgb-acid2.gbc
vendored
Normal file
BIN
bsnes/gb/.github/actions/cgb_sound.gb
vendored
Normal file
BIN
bsnes/gb/.github/actions/dmg-acid2.gb
vendored
Normal file
BIN
bsnes/gb/.github/actions/dmg_sound-2.gb
vendored
Executable file
36
bsnes/gb/.github/actions/install_deps.sh
vendored
Executable file
@@ -0,0 +1,36 @@
|
||||
case `echo $1 | cut -d '-' -f 1` in
|
||||
ubuntu)
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get install -yq bison libpng-dev pkg-config libsdl2-dev libgdk-pixbuf2.0-dev
|
||||
(
|
||||
cd `mktemp -d`
|
||||
curl -L https://github.com/rednex/rgbds/archive/v0.6.0.zip > rgbds.zip
|
||||
unzip rgbds.zip
|
||||
cd rgbds-*
|
||||
make -sj
|
||||
sudo make install
|
||||
cd ..
|
||||
rm -rf *
|
||||
)
|
||||
|
||||
(
|
||||
cd `mktemp -d`
|
||||
curl -L https://github.com/BR903/cppp/archive/refs/heads/master.zip > cppp.zip
|
||||
unzip cppp.zip
|
||||
cd cppp-*
|
||||
make -sj
|
||||
sudo make install
|
||||
cd ..
|
||||
rm -rf *
|
||||
)
|
||||
|
||||
|
||||
;;
|
||||
macos)
|
||||
brew install rgbds sdl2 cppp
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported OS"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
BIN
bsnes/gb/.github/actions/oam_bug-2.gb
vendored
Executable file
35
bsnes/gb/.github/actions/sanity_tests.sh
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
./build/bin/tester/sameboy_tester --jobs 5 \
|
||||
--length 45 .github/actions/cgb_sound.gb \
|
||||
--length 10 .github/actions/cgb-acid2.gbc \
|
||||
--length 10 .github/actions/dmg-acid2.gb \
|
||||
--dmg --length 45 .github/actions/dmg_sound-2.gb \
|
||||
--dmg --length 20 .github/actions/oam_bug-2.gb
|
||||
|
||||
mv .github/actions/dmg-acid2.bmp .github/actions/dmg-mode-acid2.bmp
|
||||
|
||||
./build/bin/tester/sameboy_tester \
|
||||
--dmg --length 10 .github/actions/dmg-acid2.gb
|
||||
|
||||
set +e
|
||||
|
||||
FAILED_TESTS=`
|
||||
shasum .github/actions/*.bmp | grep -E -v \(\
|
||||
64c3fd9a5fe9aee40fe15f3371029c0d2f20f5bc\ \ .github/actions/cgb-acid2.bmp\|\
|
||||
dbcc438dcea13b5d1b80c5cd06bda2592cc5d9e0\ \ .github/actions/cgb_sound.bmp\|\
|
||||
0caadf9634e40247ae9c15ff71992e8f77bbf89e\ \ .github/actions/dmg-acid2.bmp\|\
|
||||
fbdb5e342bfdd2edda3ea5601d35d0ca60d18034\ \ .github/actions/dmg-mode-acid2.bmp\|\
|
||||
c9e944b7e01078bdeba1819bc2fa9372b111f52d\ \ .github/actions/dmg_sound-2.bmp\|\
|
||||
f0172cc91867d3343fbd113a2bb98100074be0de\ \ .github/actions/oam_bug-2.bmp\
|
||||
\)`
|
||||
|
||||
if [ -n "$FAILED_TESTS" ] ; then
|
||||
echo "Failed the following tests:"
|
||||
echo $FAILED_TESTS | tr " " "\n" | grep -o -E "[^/]+\.bmp" | sed s/.bmp// | sort
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Passed all tests
|
30
bsnes/gb/.github/actions/update_libretro.sh
vendored
Executable file
@@ -0,0 +1,30 @@
|
||||
set -ex
|
||||
|
||||
git fetch --tags
|
||||
LATEST=$(git tag --sort=-creatordate | grep "^v" | grep -v libretro | head -n 1)
|
||||
|
||||
if [ $(git tag -l "$LATEST"-libretro) ]; then
|
||||
echo "The libretro branch is already up-to-date"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config --global --add --bool push.autoSetupRemote true
|
||||
git config --global user.name 'Libretro Updater'
|
||||
git config --global user.email '<>'
|
||||
|
||||
cp libretro/gitlab-ci.yml .gitlab-ci.yml
|
||||
|
||||
echo "Switching to tag $LATEST"
|
||||
git branch --delete libretro || true
|
||||
git checkout tags/$LATEST -b libretro
|
||||
|
||||
echo "Building boot ROMs..."
|
||||
make -j bootroms
|
||||
|
||||
echo "Updating branch"
|
||||
mv build/bin/BootROMs BootROMs/prebuilt
|
||||
git add BootROMs/prebuilt/* .gitlab-ci.yml
|
||||
git commit -m "Update libretro branch to $LATEST"
|
||||
git tag "$LATEST"-libretro
|
||||
git push --force
|
||||
git push --tags
|
28
bsnes/gb/.github/workflows/libretro.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: "libretro branch update"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
libretro-prebuilt-update:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
with:
|
||||
repository: LIJI32/SameBoy
|
||||
token: ${{ secrets.WEBSITETOKEN }}
|
||||
submodules: false
|
||||
- name: Install Deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/actions/install_deps.sh ${{ matrix.os }}
|
||||
- name: Build Boot ROMs and Push
|
||||
run: |
|
||||
./.github/actions/update_libretro.sh
|
44
bsnes/gb/.github/workflows/sanity.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: "Bulidability and Sanity"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '*'
|
||||
- '!libretro'
|
||||
|
||||
jobs:
|
||||
sanity:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, ubuntu-22.04]
|
||||
cc: [gcc, clang]
|
||||
include:
|
||||
- os: macos-latest
|
||||
cc: clang
|
||||
extra_targets: cocoa ios-ipa ios-deb
|
||||
exclude:
|
||||
- os: macos-latest
|
||||
cc: gcc
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/actions/install_deps.sh ${{ matrix.os }}
|
||||
- name: Build
|
||||
run: |
|
||||
${{ matrix.cc }} -v; (make -j all CONF=release CC=${{ matrix.cc }} || (echo "==== Build Failed ==="; make all CONF=release CC=${{ matrix.cc }}))
|
||||
- name: Sanity tests
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/actions/sanity_tests.sh
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sameboy-canary-${{ matrix.os }}-${{ matrix.cc }}
|
||||
path: |
|
||||
build/bin
|
||||
build/lib
|
||||
build/include
|
1
bsnes/gb/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
build
|
12
bsnes/gb/AppleCommon/GBAudioClient.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Core/gb.h>
|
||||
|
||||
@interface GBAudioClient : NSObject
|
||||
@property (nonatomic, strong) void (^renderBlock)(UInt32 sampleRate, UInt32 nFrames, GB_sample_t *buffer);
|
||||
@property (nonatomic, readonly) UInt32 rate;
|
||||
@property (nonatomic, readonly, getter=isPlaying) bool playing;
|
||||
- (void)start;
|
||||
- (void)stop;
|
||||
- (id)initWithRendererBlock:(void (^)(UInt32 sampleRate, UInt32 nFrames, GB_sample_t *buffer)) block
|
||||
andSampleRate:(UInt32) rate;
|
||||
@end
|
134
bsnes/gb/AppleCommon/GBAudioClient.m
Normal file
@@ -0,0 +1,134 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import "GBAudioClient.h"
|
||||
|
||||
static OSStatus render(
|
||||
GBAudioClient *self,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList *ioData)
|
||||
|
||||
{
|
||||
GB_sample_t *buffer = (GB_sample_t *)ioData->mBuffers[0].mData;
|
||||
|
||||
self.renderBlock(self.rate, inNumberFrames, buffer);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
@implementation GBAudioClient
|
||||
{
|
||||
AudioComponentInstance audioUnit;
|
||||
}
|
||||
|
||||
- (id)initWithRendererBlock:(void (^)(UInt32 sampleRate, UInt32 nFrames, GB_sample_t *buffer)) block
|
||||
andSampleRate:(UInt32) rate
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Configure the search parameters to find the default playback output unit
|
||||
// (called the kAudioUnitSubType_RemoteIO on iOS but
|
||||
// kAudioUnitSubType_DefaultOutput on Mac OS X)
|
||||
AudioComponentDescription defaultOutputDescription;
|
||||
defaultOutputDescription.componentType = kAudioUnitType_Output;
|
||||
#if TARGET_OS_IPHONE
|
||||
defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
#else
|
||||
defaultOutputDescription.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
#endif
|
||||
defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
defaultOutputDescription.componentFlags = 0;
|
||||
defaultOutputDescription.componentFlagsMask = 0;
|
||||
|
||||
// Get the default playback output unit
|
||||
AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription);
|
||||
if (!defaultOutput) {
|
||||
NSLog(@"Can't find default output");
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Create a new unit based on this that we'll use for output
|
||||
OSErr err = AudioComponentInstanceNew(defaultOutput, &audioUnit);
|
||||
if (!audioUnit) {
|
||||
NSLog(@"Error creating unit: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Set our tone rendering function on the unit
|
||||
AURenderCallbackStruct input;
|
||||
input.inputProc = (void*)render;
|
||||
input.inputProcRefCon = (__bridge void *)(self);
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&input,
|
||||
sizeof(input));
|
||||
if (err) {
|
||||
NSLog(@"Error setting callback: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
AudioStreamBasicDescription streamFormat;
|
||||
streamFormat.mSampleRate = rate;
|
||||
streamFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
streamFormat.mFormatFlags =
|
||||
kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian;
|
||||
streamFormat.mBytesPerPacket = 4;
|
||||
streamFormat.mFramesPerPacket = 1;
|
||||
streamFormat.mBytesPerFrame = 4;
|
||||
streamFormat.mChannelsPerFrame = 2;
|
||||
streamFormat.mBitsPerChannel = 2 * 8;
|
||||
err = AudioUnitSetProperty (audioUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&streamFormat,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
|
||||
if (err) {
|
||||
NSLog(@"Error setting stream format: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
err = AudioUnitInitialize(audioUnit);
|
||||
if (err) {
|
||||
NSLog(@"Error initializing unit: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.renderBlock = block;
|
||||
_rate = rate;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) start
|
||||
{
|
||||
OSErr err = AudioOutputUnitStart(audioUnit);
|
||||
if (err) {
|
||||
NSLog(@"Error starting unit: %hd", err);
|
||||
return;
|
||||
}
|
||||
_playing = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void) stop
|
||||
{
|
||||
AudioOutputUnitStop(audioUnit);
|
||||
_playing = false;
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
[self stop];
|
||||
AudioUnitUninitialize(audioUnit);
|
||||
AudioComponentInstanceDispose(audioUnit);
|
||||
}
|
||||
|
||||
@end
|
36
bsnes/gb/AppleCommon/GBViewBase.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define NSView UIView
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
#import <Core/gb.h>
|
||||
|
||||
typedef enum {
|
||||
GB_FRAME_BLENDING_MODE_DISABLED,
|
||||
GB_FRAME_BLENDING_MODE_SIMPLE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE_EVEN = GB_FRAME_BLENDING_MODE_ACCURATE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE_ODD,
|
||||
} GB_frame_blending_mode_t;
|
||||
|
||||
@interface GBViewBase : NSView
|
||||
{
|
||||
@public
|
||||
GB_gameboy_t *_gb;
|
||||
}
|
||||
|
||||
@property (nonatomic) GB_gameboy_t *gb;
|
||||
@property (nonatomic) GB_frame_blending_mode_t frameBlendingMode;
|
||||
@property (nonatomic, strong) NSView *internalView;
|
||||
- (void) flip;
|
||||
- (uint32_t *) pixels;
|
||||
- (void)screenSizeChanged;
|
||||
- (void) createInternalView;
|
||||
- (uint32_t *)currentBuffer;
|
||||
- (uint32_t *)previousBuffer;
|
||||
- (instancetype)mirroredView;
|
||||
@end
|
121
bsnes/gb/AppleCommon/GBViewBase.m
Normal file
@@ -0,0 +1,121 @@
|
||||
#import "GBViewBase.h"
|
||||
|
||||
@implementation GBViewBase
|
||||
{
|
||||
uint32_t *_imageBuffers[3];
|
||||
unsigned _currentBuffer;
|
||||
GB_frame_blending_mode_t _frameBlendingMode;
|
||||
bool _oddFrame;
|
||||
GBViewBase *_parent;
|
||||
__weak GBViewBase *_child;
|
||||
}
|
||||
|
||||
- (void)screenSizeChanged
|
||||
{
|
||||
if (_parent) return;
|
||||
if (_imageBuffers[0]) free(_imageBuffers[0]);
|
||||
if (_imageBuffers[1]) free(_imageBuffers[1]);
|
||||
if (_imageBuffers[2]) free(_imageBuffers[2]);
|
||||
|
||||
size_t buffer_size = sizeof(_imageBuffers[0][0]) * GB_get_screen_width(_gb) * GB_get_screen_height(_gb);
|
||||
|
||||
_imageBuffers[0] = calloc(1, buffer_size);
|
||||
_imageBuffers[1] = calloc(1, buffer_size);
|
||||
_imageBuffers[2] = calloc(1, buffer_size);
|
||||
}
|
||||
|
||||
- (void)flip
|
||||
{
|
||||
if (_parent) return;
|
||||
_currentBuffer = (_currentBuffer + 1) % self.numberOfBuffers;
|
||||
_oddFrame = GB_is_odd_frame(_gb);
|
||||
[_child flip];
|
||||
}
|
||||
|
||||
- (unsigned) numberOfBuffers
|
||||
{
|
||||
assert(!_parent);
|
||||
return _frameBlendingMode? 3 : 2;
|
||||
}
|
||||
|
||||
- (void) createInternalView
|
||||
{
|
||||
assert(false && "createInternalView must not be inherited");
|
||||
}
|
||||
|
||||
- (uint32_t *)currentBuffer
|
||||
{
|
||||
if (GB_unlikely(_parent)) {
|
||||
return [_parent currentBuffer];
|
||||
}
|
||||
return _imageBuffers[_currentBuffer];
|
||||
}
|
||||
|
||||
- (uint32_t *)previousBuffer
|
||||
{
|
||||
if (GB_unlikely(_parent)) {
|
||||
return [_parent previousBuffer];
|
||||
}
|
||||
return _imageBuffers[(_currentBuffer + 2) % self.numberOfBuffers];
|
||||
}
|
||||
|
||||
- (uint32_t *) pixels
|
||||
{
|
||||
assert(!_parent);
|
||||
return _imageBuffers[(_currentBuffer + 1) % self.numberOfBuffers];
|
||||
}
|
||||
|
||||
- (void) setFrameBlendingMode:(GB_frame_blending_mode_t)frameBlendingMode
|
||||
{
|
||||
_frameBlendingMode = frameBlendingMode;
|
||||
[self setNeedsDisplay];
|
||||
[_child setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (GB_frame_blending_mode_t)frameBlendingMode
|
||||
{
|
||||
if (GB_unlikely(_parent)) {
|
||||
return [_parent frameBlendingMode];
|
||||
}
|
||||
if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) {
|
||||
if (!_gb || GB_is_sgb(_gb)) {
|
||||
return GB_FRAME_BLENDING_MODE_SIMPLE;
|
||||
}
|
||||
return _oddFrame ? GB_FRAME_BLENDING_MODE_ACCURATE_ODD : GB_FRAME_BLENDING_MODE_ACCURATE_EVEN;
|
||||
}
|
||||
return _frameBlendingMode;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_parent) return;
|
||||
free(_imageBuffers[0]);
|
||||
free(_imageBuffers[1]);
|
||||
free(_imageBuffers[2]);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
- (void)setNeedsDisplay
|
||||
{
|
||||
[self setNeedsDisplay:true];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)setGb:(GB_gameboy_t *)gb
|
||||
{
|
||||
assert(!_parent);
|
||||
_gb = gb;
|
||||
if (_child) {
|
||||
_child->_gb = gb;
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)mirroredView
|
||||
{
|
||||
if (_child) return _child;
|
||||
GBViewBase *ret = [[self.class alloc] initWithFrame:self.bounds];
|
||||
ret->_parent = self;
|
||||
ret->_gb = _gb;
|
||||
return _child = ret;
|
||||
}
|
||||
@end
|
11
bsnes/gb/AppleCommon/GBViewMetal.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#import <TargetConditionals.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "../iOS/GBView.h"
|
||||
#else
|
||||
#import "../Cocoa/GBView.h"
|
||||
#endif
|
||||
|
||||
@interface GBViewMetal : GBView<MTKViewDelegate>
|
||||
+ (bool) isSupported;
|
||||
@end
|
266
bsnes/gb/AppleCommon/GBViewMetal.m
Normal file
@@ -0,0 +1,266 @@
|
||||
#import <CoreImage/CoreImage.h>
|
||||
#import "GBViewMetal.h"
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
#if !TARGET_OS_IPHONE
|
||||
#import "../Cocoa/NSObject+DefaultsObserver.h"
|
||||
#endif
|
||||
|
||||
static const vector_float2 rect[] =
|
||||
{
|
||||
{-1, -1},
|
||||
{ 1, -1},
|
||||
{-1, 1},
|
||||
{ 1, 1},
|
||||
};
|
||||
|
||||
@implementation GBViewMetal
|
||||
{
|
||||
id<MTLDevice> _device;
|
||||
id<MTLTexture> _texture, _previousTexture;
|
||||
id<MTLBuffer> _vertices;
|
||||
id<MTLRenderPipelineState> _pipelineState;
|
||||
id<MTLCommandQueue> _commandQueue;
|
||||
id<MTLBuffer> _frameBlendingModeBuffer;
|
||||
id<MTLBuffer> _outputResolutionBuffer;
|
||||
vector_float2 _outputResolution;
|
||||
id<MTLCommandBuffer> _commandBuffer;
|
||||
bool _waitedForFrame;
|
||||
_Atomic unsigned _pendingFrames;
|
||||
}
|
||||
|
||||
+ (bool)isSupported
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
return true;
|
||||
#else
|
||||
if (MTLCopyAllDevices) {
|
||||
return [MTLCopyAllDevices() count];
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
- (void) allocateTextures
|
||||
{
|
||||
if (!_device) return;
|
||||
|
||||
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
|
||||
|
||||
texture_descriptor.pixelFormat = MTLPixelFormatRGBA8Unorm;
|
||||
|
||||
texture_descriptor.width = GB_get_screen_width(self.gb);
|
||||
texture_descriptor.height = GB_get_screen_height(self.gb);
|
||||
|
||||
_texture = [_device newTextureWithDescriptor:texture_descriptor];
|
||||
_previousTexture = [_device newTextureWithDescriptor:texture_descriptor];
|
||||
|
||||
}
|
||||
|
||||
- (void)createInternalView
|
||||
{
|
||||
MTKView *view = [[MTKView alloc] initWithFrame:self.frame device:(_device = MTLCreateSystemDefaultDevice())];
|
||||
view.delegate = self;
|
||||
self.internalView = view;
|
||||
view.paused = true;
|
||||
view.enableSetNeedsDisplay = true;
|
||||
view.framebufferOnly = false;
|
||||
|
||||
_vertices = [_device newBufferWithBytes:rect
|
||||
length:sizeof(rect)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
static const GB_frame_blending_mode_t default_blending_mode = GB_FRAME_BLENDING_MODE_DISABLED;
|
||||
_frameBlendingModeBuffer = [_device newBufferWithBytes:&default_blending_mode
|
||||
length:sizeof(default_blending_mode)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
_outputResolutionBuffer = [_device newBufferWithBytes:&_outputResolution
|
||||
length:sizeof(_outputResolution)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
_outputResolution = (simd_float2){view.drawableSize.width, view.drawableSize.height};
|
||||
/* TODO: NSObject+DefaultsObserver can replace the less flexible `addDefaultObserver` in iOS */
|
||||
#if TARGET_OS_IPHONE
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadShader) name:@"GBFilterChanged" object:nil];
|
||||
[self loadShader];
|
||||
#else
|
||||
[self observeStandardDefaultsKey:@"GBFilter" selector:@selector(loadShader)];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)loadShader
|
||||
{
|
||||
NSError *error = nil;
|
||||
NSString *shader_source = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"MasterShader"
|
||||
ofType:@"metal"
|
||||
inDirectory:@"Shaders"]
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
|
||||
NSString *shader_name = [[NSUserDefaults standardUserDefaults] objectForKey:@"GBFilter"];
|
||||
NSString *scaler_source = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:shader_name
|
||||
ofType:@"fsh"
|
||||
inDirectory:@"Shaders"]
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
|
||||
shader_source = [shader_source stringByReplacingOccurrencesOfString:@"{filter}"
|
||||
withString:scaler_source];
|
||||
|
||||
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
|
||||
options.fastMathEnabled = true;
|
||||
id<MTLLibrary> library = [_device newLibraryWithSource:shader_source
|
||||
options:options
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Error: %@", error);
|
||||
if (!library) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
id<MTLFunction> vertex_function = [library newFunctionWithName:@"vertex_shader"];
|
||||
id<MTLFunction> fragment_function = [library newFunctionWithName:@"fragment_shader"];
|
||||
|
||||
// Set up a descriptor for creating a pipeline state object
|
||||
MTLRenderPipelineDescriptor *pipeline_state_descriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
pipeline_state_descriptor.vertexFunction = vertex_function;
|
||||
pipeline_state_descriptor.fragmentFunction = fragment_function;
|
||||
pipeline_state_descriptor.colorAttachments[0].pixelFormat = ((MTKView *)self.internalView).colorPixelFormat;
|
||||
|
||||
error = nil;
|
||||
_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
||||
return;
|
||||
}
|
||||
|
||||
_commandQueue = [_device newCommandQueue];
|
||||
}
|
||||
|
||||
- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size
|
||||
{
|
||||
_outputResolution = (vector_float2){size.width, size.height};
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[(MTKView *)self.internalView draw];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)drawInMTKView:(MTKView *)view
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (!(view.window.occlusionState & NSWindowOcclusionStateVisible)) return;
|
||||
#endif
|
||||
if (!self.gb) return;
|
||||
if (_texture.width != GB_get_screen_width(self.gb) ||
|
||||
_texture.height != GB_get_screen_height(self.gb)) {
|
||||
[self allocateTextures];
|
||||
}
|
||||
|
||||
MTLRegion region = {
|
||||
{0, 0, 0}, // MTLOrigin
|
||||
{_texture.width, _texture.height, 1} // MTLSize
|
||||
};
|
||||
|
||||
/* Don't start rendering if the previous frame hasn't finished yet. Either wait, or skip the frame */
|
||||
if (_commandBuffer && _commandBuffer.status != MTLCommandBufferStatusCompleted) {
|
||||
if (_waitedForFrame) return;
|
||||
[_commandBuffer waitUntilCompleted];
|
||||
_waitedForFrame = true;
|
||||
}
|
||||
else {
|
||||
_waitedForFrame = false;
|
||||
}
|
||||
|
||||
GB_frame_blending_mode_t mode = [self frameBlendingMode];
|
||||
|
||||
[_texture replaceRegion:region
|
||||
mipmapLevel:0
|
||||
withBytes:[self currentBuffer]
|
||||
bytesPerRow:_texture.width * 4];
|
||||
|
||||
if (mode) {
|
||||
[_previousTexture replaceRegion:region
|
||||
mipmapLevel:0
|
||||
withBytes:[self previousBuffer]
|
||||
bytesPerRow:_texture.width * 4];
|
||||
}
|
||||
|
||||
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
|
||||
_commandBuffer = [_commandQueue commandBuffer];
|
||||
|
||||
if (renderPassDescriptor) {
|
||||
*(GB_frame_blending_mode_t *)[_frameBlendingModeBuffer contents] = mode;
|
||||
*(vector_float2 *)[_outputResolutionBuffer contents] = _outputResolution;
|
||||
|
||||
id<MTLRenderCommandEncoder> renderEncoder =
|
||||
[_commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||
|
||||
[renderEncoder setViewport:(MTLViewport){0.0, 0.0,
|
||||
_outputResolution.x,
|
||||
_outputResolution.y,
|
||||
-1.0, 1.0}];
|
||||
|
||||
[renderEncoder setRenderPipelineState:_pipelineState];
|
||||
|
||||
[renderEncoder setVertexBuffer:_vertices
|
||||
offset:0
|
||||
atIndex:0];
|
||||
|
||||
[renderEncoder setFragmentBuffer:_frameBlendingModeBuffer
|
||||
offset:0
|
||||
atIndex:0];
|
||||
|
||||
[renderEncoder setFragmentBuffer:_outputResolutionBuffer
|
||||
offset:0
|
||||
atIndex:1];
|
||||
|
||||
[renderEncoder setFragmentTexture:_texture
|
||||
atIndex:0];
|
||||
|
||||
[renderEncoder setFragmentTexture:_previousTexture
|
||||
atIndex:1];
|
||||
|
||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
|
||||
vertexStart:0
|
||||
vertexCount:4];
|
||||
|
||||
[renderEncoder endEncoding];
|
||||
|
||||
[_commandBuffer presentDrawable:view.currentDrawable];
|
||||
}
|
||||
|
||||
|
||||
[_commandBuffer commit];
|
||||
}
|
||||
|
||||
- (void)flip
|
||||
{
|
||||
[super flip];
|
||||
if (_pendingFrames == 2) return;
|
||||
_pendingFrames++;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[(MTKView *)self.internalView draw];
|
||||
_pendingFrames--;
|
||||
});
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
- (NSImage *)renderToImage
|
||||
{
|
||||
CIImage *ciImage = [CIImage imageWithMTLTexture:[[(MTKView *)self.internalView currentDrawable] texture]
|
||||
options:@{
|
||||
kCIImageColorSpace: (__bridge_transfer id)CGColorSpaceCreateDeviceRGB(),
|
||||
kCIImageProperties: [NSNull null]
|
||||
}];
|
||||
ciImage = [ciImage imageByApplyingTransform:CGAffineTransformTranslate(CGAffineTransformMakeScale(1, -1),
|
||||
0, ciImage.extent.size.height)];
|
||||
CIContext *context = [CIContext context];
|
||||
CGImageRef cgImage = [context createCGImage:ciImage fromRect:ciImage.extent];
|
||||
NSImage *ret = [[NSImage alloc] initWithCGImage:cgImage size:self.internalView.bounds.size];
|
||||
CGImageRelease(cgImage);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
259
bsnes/gb/BESS.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# BESS – Best Effort Save State 1.0
|
||||
|
||||
## Motivation
|
||||
|
||||
BESS is a save state format specification designed to allow different emulators, as well as majorly different versions of the same emulator, to import save states from other BESS-compliant save states. BESS works by appending additional, implementation-agnostic information about the emulation state. This allows a single save state file to be read as both a fully-featured, implementation specific save state which includes detailed timing information; and as a portable "best effort" save state that represents a state accurately enough to be restored in casual use-cases.
|
||||
|
||||
## Specification
|
||||
|
||||
Every integer used in the BESS specification is stored in Little Endian encoding.
|
||||
|
||||
### BESS footer
|
||||
|
||||
BESS works by appending a detectable footer at the end of an existing save state format. The footer uses the following format:
|
||||
|
||||
| Offset from end of file | Content |
|
||||
|-------------------------|-------------------------------------------------------|
|
||||
| -8 | Offset to the first BESS Block, from the file's start |
|
||||
| -4 | The ASCII string 'BESS' |
|
||||
|
||||
### BESS blocks
|
||||
|
||||
BESS uses a block format where each block contains the following header:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|-----------------------------------------------------------|
|
||||
| 0 | A four-letter ASCII identifier |
|
||||
| 4 | Length of the block as a 32-bit integer, excluding header |
|
||||
|
||||
Every block is followed by another block, until the END block is reached. If an implementation encounters an unsupported block, it should be completely ignored (Should not have any effect and should not trigger a failure).
|
||||
|
||||
#### NAME block
|
||||
|
||||
The NAME block uses the `'NAME'` identifier, and is an optional block that contains the name of the emulator that created this save state. While optional, it is highly recommended to be included in every implementation – it allows the user to know which emulator and version is compatible with the native save state format contained in this file. When used, this block should come first.
|
||||
|
||||
The length of the NAME block is variable, and it only contains the name and version of the originating emulator in ASCII.
|
||||
|
||||
|
||||
#### INFO block
|
||||
|
||||
The INFO block uses the `'INFO'` identifier, and is an optional block that contains information about the ROM this save state originates from. When used, this block should come before `CORE` but after `NAME`. This block is 0x12 bytes long, and it follows this structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|--------------------------------------------------|
|
||||
| 0x00 | Bytes 0x134-0x143 from the ROM (Title) |
|
||||
| 0x10 | Bytes 0x14E-0x14F from the ROM (Global checksum) |
|
||||
|
||||
#### CORE block
|
||||
|
||||
The CORE block uses the `'CORE'` identifier, and is a required block that contains both core state information, as well as basic information about the BESS version used. This block must be the first block, unless the `NAME` or `INFO` blocks exist then it must come directly after them. An implementation should not enforce block order on blocks unknown to it for future compatibility.
|
||||
|
||||
The length of the CORE block is 0xD0 bytes, but implementations are expected to ignore any excess bytes. Following the BESS block header, the structure is as follows:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|----------------------------------------|
|
||||
| 0x00 | Major BESS version as a 16-bit integer |
|
||||
| 0x02 | Minor BESS version as a 16-bit integer |
|
||||
|
||||
Both major and minor versions should be 1. Implementations are expected to reject incompatible majors, but still attempt to read newer minor versions.
|
||||
|
||||
| Offset | Content |
|
||||
|--------|----------------------------------------|
|
||||
| 0x04 | A four-character ASCII model identifier |
|
||||
|
||||
BESS uses a four-character string to identify Game Boy models:
|
||||
|
||||
* The first letter represents mutually-incompatible families of models and is required. The allowed values are `'G'` for the original Game Boy family, `'S'` for the Super Game Boy family, and `'C'` for the Game Boy Color and Advance family.
|
||||
* The second letter represents a specific model within the family, and is optional (If an implementation does not distinguish between specific models in a family, a space character may be used). The allowed values for family G are `'D'` for DMG and `'M'` for MGB; the allowed values for family S are `'N'` for NTSC, `'P'` for PAL, and `'2'` for SGB2; and the allowed values for family C are `'C'` for CGB, and `'A'` for the various GBA line models.
|
||||
* The third letter represents a specific CPU revision within a model, and is optional (If an implementation does not distinguish between revisions, a space character may be used). The allowed values for model GD (DMG) are `'0'` and `'A'`, through `'C'`; the allowed values for model CC (CGB) are `'0'` and `'A'`, through `'E'`; the allowed values for model CA (AGB, AGS, GBP) are `'0'`, `'A'` and `'B'`; and for every other model this value must be a space character.
|
||||
* The last character is used for padding and must be a space character.
|
||||
|
||||
For example; `'GD '` represents a DMG of an unspecified revision, `'S '` represents some model of the SGB family, and `'CCE '` represent a CGB using CPU revision E.
|
||||
|
||||
| Offset | Content |
|
||||
|--------|--------------------------------------------------------|
|
||||
| 0x08 | The value of the PC register |
|
||||
| 0x0A | The value of the AF register |
|
||||
| 0x0C | The value of the BC register |
|
||||
| 0x0E | The value of the DE register |
|
||||
| 0x10 | The value of the HL register |
|
||||
| 0x12 | The value of the SP register |
|
||||
| 0x14 | The value of IME (0 or 1) |
|
||||
| 0x15 | The value of the IE register |
|
||||
| 0x16 | Execution state (0 = running; 1 = halted; 2 = stopped) |
|
||||
| 0x17 | Reserved, must be 0 |
|
||||
| 0x18 | The values of every memory-mapped register (128 bytes) |
|
||||
|
||||
The values of memory-mapped registers should be written 'as-is' to memory as if the actual ROM wrote them, with the following exceptions and note:
|
||||
* Unused registers have Don't-Care values which should be ignored
|
||||
* Unused register bits have Don't-Care values which should be ignored
|
||||
* If the model is CGB or newer, the value of KEY0 (FF4C) must be valid as it determines DMG mode
|
||||
* Bit 2 determines DMG mode. A value of 0x04 usually denotes DMG mode, while a value of `0x80` usually denotes CGB mode.
|
||||
* Object priority is derived from KEY0 (FF4C) instead of OPRI (FF6C) because OPRI can be modified after booting, but only the value of OPRI during boot ROM execution takes effect
|
||||
* If a register doesn't exist on the emulated model (For example, KEY0 (FF4C) on a DMG), its value should be ignored.
|
||||
* BANK (FF50) should be 0 if the boot ROM is still mapped, and 1 otherwise, and must be valid.
|
||||
* Implementations should not start a serial transfer when writing the value of SB
|
||||
* Similarly, no value of NRx4 should trigger a sound pulse on save state load
|
||||
* And similarly again, implementations should not trigger DMA transfers when writing the values of DMA or HDMA5
|
||||
* The value store for DIV will be used to set the internal divisor to `DIV << 8`
|
||||
* Implementation should apply care when ordering the write operations (For example, writes to NR52 must come before writes to the other APU registers)
|
||||
|
||||
| Offset | Content |
|
||||
|--------|--------------------------------------------------------------------|
|
||||
| 0x98 | The size of RAM (32-bit integer) |
|
||||
| 0x9C | The offset of RAM from file start (32-bit integer) |
|
||||
| 0xA0 | The size of VRAM (32-bit integer) |
|
||||
| 0xA4 | The offset of VRAM from file start (32-bit integer) |
|
||||
| 0xA8 | The size of MBC RAM (32-bit integer) |
|
||||
| 0xAC | The offset of MBC RAM from file start (32-bit integer) |
|
||||
| 0xB0 | The size of OAM (=0xA0, 32-bit integer) |
|
||||
| 0xB4 | The offset of OAM from file start (32-bit integer) |
|
||||
| 0xB8 | The size of HRAM (=0x7F, 32-bit integer) |
|
||||
| 0xBC | The offset of HRAM from file start (32-bit integer) |
|
||||
| 0xC0 | The size of background palettes (=0x40 or 0, 32-bit integer) |
|
||||
| 0xC4 | The offset of background palettes from file start (32-bit integer) |
|
||||
| 0xC8 | The size of object palettes (=0x40 or 0, 32-bit integer) |
|
||||
| 0xCC | The offset of object palettes from file start (32-bit integer) |
|
||||
|
||||
The contents of large buffers are stored outside of BESS structure so data from an implementation's native save state format can be reused. The offsets are absolute offsets from the save state file's start. Background and object palette sizes must be 0 for models prior to Game Boy Color.
|
||||
|
||||
An implementation needs handle size mismatches gracefully. For example, if too large MBC RAM size is specified, the superfluous data should be ignored. On the other hand, if a too small VRAM size is specified (For example, if it's a save state from an emulator emulating a CGB in DMG mode, and it didn't save the second CGB VRAM bank), the implementation is expected to set that extra bank to all zeros.
|
||||
|
||||
#### XOAM block
|
||||
|
||||
The XOAM block uses the `'XOAM'` identifier, and is an optional block that contains the data of extra OAM (addresses `0xFEA0-0xFEFF`). This block length must be `0x60`. Implementations that do not emulate this extra range are free to ignore the excess bytes, and to not create this block.
|
||||
|
||||
|
||||
#### MBC block
|
||||
|
||||
The MBC block uses the `'MBC '` identifier, and is an optional block that is only used when saving states of ROMs that use an MBC. The length of this block is variable and must be divisible by 3.
|
||||
|
||||
This block contains an MBC-specific number of 3-byte-long pairs that represent the values of each MBC register. For example, for MBC5 the contents would look like:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|---------------------------------------|
|
||||
| 0x0 | The value 0x0000 as a 16-bit integer |
|
||||
| 0x2 | 0x0A if RAM is enabled, 0 otherwise |
|
||||
| 0x3 | The value 0x2000 as a 16-bit integer |
|
||||
| 0x5 | The lower 8 bits of the ROM bank |
|
||||
| 0x6 | The value 0x3000 as a 16-bit integer |
|
||||
| 0x8 | The bit 9 of the ROM bank |
|
||||
| 0x9 | The value 0x4000 as a 16-bit integer |
|
||||
| 0xB | The current RAM bank |
|
||||
|
||||
An implementation should parse this block as a series of writes to be made. Values outside the `0x0000-0x7FFF` and `0xA000-0xBFFF` ranges are not allowed. Implementations must perform the writes in order (i.e. not reverse, sorted, or any other transformation on their order)
|
||||
|
||||
#### RTC block
|
||||
The RTC block uses the `'RTC '` identifier, and is an optional block that is used while emulating an MBC3 with an RTC. The contents of this block are identical to 64-bit RTC saves from VBA, which are also used by SameBoy and different emulators such as BGB.
|
||||
|
||||
The length of this block is 0x30 bytes long and it follows the following structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|------------------------------------------------------------------------|
|
||||
| 0x00 | Current seconds (1 byte), followed by 3 bytes of padding |
|
||||
| 0x04 | Current minutes (1 byte), followed by 3 bytes of padding |
|
||||
| 0x08 | Current hours (1 byte), followed by 3 bytes of padding |
|
||||
| 0x0C | Current days (1 byte), followed by 3 bytes of padding |
|
||||
| 0x10 | Current high/overflow/running (1 byte), followed by 3 bytes of padding |
|
||||
| 0x14 | Latched seconds (1 byte), followed by 3 bytes of padding |
|
||||
| 0x18 | Latched minutes (1 byte), followed by 3 bytes of padding |
|
||||
| 0x1C | Latched hours (1 byte), followed by 3 bytes of padding |
|
||||
| 0x20 | Latched days (1 byte), followed by 3 bytes of padding |
|
||||
| 0x24 | Latched high/overflow/running (1 byte), followed by 3 bytes of padding |
|
||||
| 0x28 | UNIX timestamp at the time of the save state (64-bit) |
|
||||
|
||||
#### HUC3 block
|
||||
The HUC3 block uses the `'HUC3'` identifier, and is an optional block that is used while emulating an HuC3 cartridge to store RTC and alarm information. The contents of this block are identical to HuC3 RTC saves from SameBoy.
|
||||
|
||||
The length of this block is 0x11 bytes long and it follows the following structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|-------------------------------------------------------|
|
||||
| 0x00 | UNIX timestamp at the time of the save state (64-bit) |
|
||||
| 0x08 | RTC minutes (16-bit) |
|
||||
| 0x0A | RTC days (16-bit) |
|
||||
| 0x0C | Scheduled alarm time minutes (16-bit) |
|
||||
| 0x0E | Scheduled alarm time days (16-bit) |
|
||||
| 0x10 | Alarm enabled flag (8-bits, either 0 or 1) |
|
||||
|
||||
#### TPP1 block
|
||||
The TPP1 block uses the `'TPP1'` identifier, and is an optional block that is used while emulating a TPP1 cartridge to store RTC information. This block can be omitted if the ROM header does not specify the inclusion of a RTC.
|
||||
|
||||
The length of this block is 0x11 bytes long and it follows the following structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|-------------------------------------------------------|
|
||||
| 0x00 | UNIX timestamp at the time of the save state (64-bit) |
|
||||
| 0x08 | The current RTC data (4 bytes) |
|
||||
| 0x0C | The latched RTC data (4 bytes) |
|
||||
| 0x10 | The value of the MR4 register (8-bits) |
|
||||
|
||||
|
||||
#### MBC7 block
|
||||
The MBC7 block uses the `'MBC7'` identifier, and is an optional block that is used while emulating an MBC7 cartridge to store the EEPROM communication state and motion control state.
|
||||
|
||||
The length of this block is 0xA bytes long and it follows the following structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|-------------------------------------------------------|
|
||||
| 0x00 | Flags (8-bits) |
|
||||
| 0x01 | Argument bits left (8-bits) |
|
||||
| 0x02 | Current EEPROM command (16-bits) |
|
||||
| 0x04 | Pending bits to read (16-bits) |
|
||||
| 0x06 | Latched gyro X value (16-bits) |
|
||||
| 0x08 | Latched gyro Y value (16-bits) |
|
||||
|
||||
The meaning of the individual bits in flags are:
|
||||
* Bit 0: Latch ready; set after writing `0x55` to `0xAX0X` and reset after writing `0xAA` to `0xAX1X`
|
||||
* Bit 1: EEPROM DO line
|
||||
* Bit 2: EEPROM DI line
|
||||
* Bit 3: EEPROM CLK line
|
||||
* Bit 4: EEPROM CS line
|
||||
* Bit 5: EEPROM write enable; set after an `EWEN` command, reset after an `EWDS` command
|
||||
* Bits 6-7: Unused.
|
||||
|
||||
The current EEPROM command field has bits pushed to its LSB first, padded with zeros. For example, if the ROM clocked a single `1` bit, this field should contain `0b1`; if the ROM later clocks a `0` bit, this field should contain `0b10`.
|
||||
|
||||
If the currently transmitted command has an argument, the "Argument bits left" field should contain the number argument bits remaining. Otherwise, it should contain 0.
|
||||
|
||||
The "Pending bits to read" field contains the pending bits waiting to be shifted into the DO signal, MSB first, padded with ones.
|
||||
|
||||
#### SGB block
|
||||
|
||||
The SGB block uses the `'SGB '` identifier, and is an optional block that is only used while emulating an SGB or SGB2 *and* SGB commands enabled. Implementations must not save this block on other models or when SGB commands are disabled, and should assume SGB commands are disabled if this block is missing.
|
||||
|
||||
The length of this block is 0x39 bytes, but implementations should allow and ignore excess data in this block for extensions. The block follows the following structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|--------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0x00 | The size of the border tile data (=0x2000, 32-bit integer) |
|
||||
| 0x04 | The offset of the border tile data (SNES tile format, 32-bit integer) |
|
||||
| 0x08 | The size of the border tilemap (=0x800, 32-bit integer) |
|
||||
| 0x0C | The offset of the border tilemap (LE 16-bit sequences, 32-bit integer) |
|
||||
| 0x10 | The size of the border palettes (=0x80, 32-bit integer) |
|
||||
| 0x14 | The offset of the border palettes (LE 16-bit sequences, 32-bit integer) |
|
||||
| 0x18 | The size of active colorization palettes (=0x20, 32-bit integer) |
|
||||
| 0x1C | The offset of the active colorization palettes (LE 16-bit sequences, 32-bit integer) |
|
||||
| 0x20 | The size of RAM colorization palettes (=0x1000, 32-bit integer) |
|
||||
| 0x24 | The offset of the RAM colorization palettes (LE 16-bit sequences, 32-bit integer) |
|
||||
| 0x28 | The size of the attribute map (=0x168, 32-bit integer) |
|
||||
| 0x2C | The offset of the attribute map (32-bit integer) |
|
||||
| 0x30 | The size of the attribute files (=0xfd2, 32-bit integer) |
|
||||
| 0x34 | The offset of the attribute files (32-bit integer) |
|
||||
| 0x38 | Multiplayer status (1 byte); high nibble is player count (1, 2 or 4), low nibble is current player (Where Player 1 is 0) |
|
||||
|
||||
If only some of the size-offset pairs are available (for example, partial HLE SGB implementation), missing fields are allowed to have 0 as their size, and implementations are expected to fall back to a sane default.
|
||||
|
||||
#### END block
|
||||
The END block uses the `'END '` identifier, and is a required block that marks the end of BESS data. Naturally, it must be the last block. The length of the END block must be 0.
|
||||
|
||||
## Validation and Failures
|
||||
|
||||
Other than previously specified required fail conditions, an implementation is free to decide what format errors should abort the loading of a save file. Structural errors (e.g. a block with an invalid length, a file offset that is outside the file's range, or a missing END block) should be considered as irrecoverable errors. Other errors that are considered fatal by SameBoy's implementation:
|
||||
* Duplicate CORE block
|
||||
* A known block, other than NAME, appearing before CORE
|
||||
* An invalid length for the XOAM, RTC, SGB or HUC3 blocks
|
||||
* An invalid length of MBC (not a multiple of 3)
|
||||
* A write outside the $0000-$7FFF and $A000-$BFFF ranges in the MBC block
|
||||
* An SGB block on a save state targeting another model
|
||||
* An END block with non-zero length
|
BIN
bsnes/gb/BootROMs/SameBoyLogo.png
Normal file
After Width: | Height: | Size: 477 B |
2
bsnes/gb/BootROMs/agb_boot.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
DEF AGB = 1
|
||||
include "cgb_boot.asm"
|
2
bsnes/gb/BootROMs/cgb0_boot.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
DEF CGB0 = 1
|
||||
include "cgb_boot.asm"
|
1270
bsnes/gb/BootROMs/cgb_boot.asm
Normal file
2
bsnes/gb/BootROMs/cgb_boot_fast.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
DEF FAST = 1
|
||||
include "cgb_boot.asm"
|
196
bsnes/gb/BootROMs/dmg_boot.asm
Normal file
@@ -0,0 +1,196 @@
|
||||
; SameBoy DMG bootstrap ROM
|
||||
|
||||
include "sameboot.inc"
|
||||
|
||||
SECTION "BootCode", ROM0[$0000]
|
||||
Start:
|
||||
; Init stack pointer
|
||||
ld sp, $FFFE
|
||||
|
||||
; Clear memory VRAM
|
||||
ld hl, _VRAM
|
||||
xor a
|
||||
|
||||
.clearVRAMLoop
|
||||
ldi [hl], a
|
||||
bit 5, h
|
||||
jr z, .clearVRAMLoop
|
||||
|
||||
; Init Audio
|
||||
ld a, AUDENA_ON
|
||||
ldh [rNR52], a
|
||||
assert AUDENA_ON == AUDLEN_DUTY_50
|
||||
ldh [rNR11], a
|
||||
ld a, $F3
|
||||
ldh [rNR12], a ; Envelope $F, decreasing, sweep $3
|
||||
ldh [rNR51], a ; Channels 1+2+3+4 left, channels 1+2 right
|
||||
ld a, $77
|
||||
ldh [rNR50], a ; Volume $7, left and right
|
||||
|
||||
; Init BG palette
|
||||
ld a, %01_01_01_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Load logo from ROM.
|
||||
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
||||
; Tiles are ordered left to right, top to bottom.
|
||||
ld de, NintendoLogo
|
||||
ld hl, _VRAM + $10 ; This is where we load the tiles in VRAM
|
||||
|
||||
.loadLogoLoop
|
||||
ld a, [de] ; Read 2 rows
|
||||
ld b, a
|
||||
call DoubleBitsAndWriteRow
|
||||
call DoubleBitsAndWriteRow
|
||||
inc de
|
||||
ld a, e
|
||||
xor LOW(NintendoLogoEnd)
|
||||
jr nz, .loadLogoLoop
|
||||
|
||||
; Load trademark symbol
|
||||
ld de, TrademarkSymbol
|
||||
ld c, TrademarkSymbolEnd - TrademarkSymbol
|
||||
.loadTrademarkSymbolLoop:
|
||||
ld a, [de]
|
||||
inc de
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
dec c
|
||||
jr nz, .loadTrademarkSymbolLoop
|
||||
|
||||
; Set up tilemap
|
||||
ld a, $19 ; Trademark symbol tile ID
|
||||
ld [_SCRN0 + 8 * SCRN_VX_B + 16], a ; ... put in the superscript position
|
||||
ld hl, _SCRN0 + 9 * SCRN_VX_B + 15 ; Bottom right corner of the logo
|
||||
ld c, 12 ; Tiles in a logo row
|
||||
.tilemapLoop
|
||||
dec a
|
||||
jr z, .tilemapDone
|
||||
ldd [hl], a
|
||||
dec c
|
||||
jr nz, .tilemapLoop
|
||||
ld l, $0F ; Jump to top row
|
||||
jr .tilemapLoop
|
||||
.tilemapDone
|
||||
|
||||
ld a, 30
|
||||
ldh [rSCY], a
|
||||
|
||||
; Turn on LCD
|
||||
ld a, LCDCF_ON | LCDCF_BLK01 | LCDCF_BGON
|
||||
ldh [rLCDC], a
|
||||
|
||||
ld d, LOW(-119)
|
||||
ld c, 15
|
||||
|
||||
.animate
|
||||
call WaitFrame
|
||||
ld a, d
|
||||
sra a
|
||||
sra a
|
||||
ldh [rSCY], a
|
||||
ld a, d
|
||||
add c
|
||||
ld d, a
|
||||
ld a, c
|
||||
cp 8
|
||||
jr nz, .noPaletteChange
|
||||
ld a, %10_10_10_00
|
||||
ldh [rBGP], a
|
||||
.noPaletteChange
|
||||
dec c
|
||||
jr nz, .animate
|
||||
ld a, %11_11_11_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Play first sound
|
||||
ld a, $83
|
||||
call PlaySound
|
||||
ld b, 5
|
||||
call WaitBFrames
|
||||
; Play second sound
|
||||
ld a, $C1
|
||||
call PlaySound
|
||||
|
||||
|
||||
|
||||
; Wait ~1 second
|
||||
ld b, 60
|
||||
call WaitBFrames
|
||||
|
||||
; Set registers to match the original DMG boot
|
||||
IF DEF(MGB)
|
||||
lb hl, BOOTUP_A_MGB, %10110000
|
||||
ELSE
|
||||
lb hl, BOOTUP_A_DMG, %10110000
|
||||
ENDC
|
||||
push hl
|
||||
pop af
|
||||
ld hl, HeaderChecksum
|
||||
lb bc, 0, LOW(rNR13) ; $0013
|
||||
lb de, 0, $D8 ; $00D8
|
||||
|
||||
; Boot the game
|
||||
jp BootGame
|
||||
|
||||
|
||||
DoubleBitsAndWriteRow:
|
||||
; Double the most significant 4 bits, b is shifted by 4
|
||||
ld a, 4
|
||||
ld c, 0
|
||||
.doubleCurrentBit
|
||||
sla b
|
||||
push af
|
||||
rl c
|
||||
pop af
|
||||
rl c
|
||||
dec a
|
||||
jr nz, .doubleCurrentBit
|
||||
ld a, c
|
||||
; Write as two rows
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ret
|
||||
|
||||
WaitFrame:
|
||||
push hl
|
||||
ld hl, rIF
|
||||
res 0, [hl]
|
||||
.wait
|
||||
bit 0, [hl]
|
||||
jr z, .wait
|
||||
pop hl
|
||||
ret
|
||||
|
||||
WaitBFrames:
|
||||
call WaitFrame
|
||||
dec b
|
||||
jr nz, WaitBFrames
|
||||
ret
|
||||
|
||||
PlaySound:
|
||||
ldh [rNR13], a
|
||||
ld a, AUDHIGH_RESTART | $7
|
||||
ldh [rNR14], a
|
||||
ret
|
||||
|
||||
|
||||
TrademarkSymbol:
|
||||
pusho
|
||||
opt b.X
|
||||
db %..XXXX..
|
||||
db %.X....X.
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %.X....X.
|
||||
db %..XXXX..
|
||||
popo
|
||||
TrademarkSymbolEnd:
|
||||
|
||||
SECTION "BootGame", ROM0[$00FE]
|
||||
BootGame:
|
||||
ldh [rBANK], a ; unmap boot ROM
|
1113
bsnes/gb/BootROMs/hardware.inc
Executable file
2
bsnes/gb/BootROMs/mgb_boot.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
DEF MGB = 1
|
||||
include "dmg_boot.asm"
|
102
bsnes/gb/BootROMs/pb12.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
static void opts(uint8_t byte, uint8_t *options)
|
||||
{
|
||||
*(options++) = byte | ((byte << 1) & 0xff);
|
||||
*(options++) = byte & (byte << 1);
|
||||
*(options++) = byte | ((byte >> 1) & 0xff);
|
||||
*(options++) = byte & (byte >> 1);
|
||||
}
|
||||
|
||||
static void write_all(int fd, const void *buf, size_t count) {
|
||||
while (count) {
|
||||
ssize_t written = write(fd, buf, count);
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "write");
|
||||
exit(1);
|
||||
}
|
||||
count -= written;
|
||||
buf += written;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static uint8_t source[0x4000];
|
||||
size_t size = read(STDIN_FILENO, &source, sizeof(source));
|
||||
unsigned pos = 0;
|
||||
assert(size <= 0x4000);
|
||||
while (size && source[size - 1] == 0) {
|
||||
size--;
|
||||
}
|
||||
|
||||
uint8_t literals[8];
|
||||
size_t literals_size = 0;
|
||||
unsigned bits = 0;
|
||||
unsigned control = 0;
|
||||
unsigned prev[2] = {-1, -1}; // Unsigned to allow "not set" values
|
||||
|
||||
while (true) {
|
||||
|
||||
uint8_t byte = 0;
|
||||
if (pos == size){
|
||||
if (bits == 0) break;
|
||||
}
|
||||
else {
|
||||
byte = source[pos++];
|
||||
}
|
||||
|
||||
if (byte == prev[0] || byte == prev[1]) {
|
||||
bits += 2;
|
||||
control <<= 1;
|
||||
control |= 1;
|
||||
control <<= 1;
|
||||
if (byte == prev[1]) {
|
||||
control |= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bits += 2;
|
||||
control <<= 2;
|
||||
uint8_t options[4];
|
||||
opts(prev[1], options);
|
||||
bool found = false;
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
if (options[i] == byte) {
|
||||
// 01 = modify
|
||||
control |= 1;
|
||||
|
||||
bits += 2;
|
||||
control <<= 2;
|
||||
control |= i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
literals[literals_size++] = byte;
|
||||
}
|
||||
}
|
||||
|
||||
prev[0] = prev[1];
|
||||
prev[1] = byte;
|
||||
if (bits >= 8) {
|
||||
uint8_t outctl = control >> (bits - 8);
|
||||
assert(outctl != 1); // 1 is reserved as the end byte
|
||||
write_all(STDOUT_FILENO, &outctl, 1);
|
||||
write_all(STDOUT_FILENO, literals, literals_size);
|
||||
bits -= 8;
|
||||
control &= (1 << bits) - 1;
|
||||
literals_size = 0;
|
||||
}
|
||||
}
|
||||
uint8_t end_byte = 1;
|
||||
write_all(STDOUT_FILENO, &end_byte, 1);
|
||||
|
||||
return 0;
|
||||
}
|
40
bsnes/gb/BootROMs/sameboot.inc
Normal file
@@ -0,0 +1,40 @@
|
||||
IF !DEF(SAMEBOY_INC)
|
||||
DEF SAMEBOY_INC EQU 1
|
||||
|
||||
include "hardware.inc"
|
||||
|
||||
DEF rKEY0 EQU $FF4C
|
||||
DEF rBANK EQU $FF50
|
||||
|
||||
DEF rJOYP EQU rP1
|
||||
|
||||
|
||||
MACRO lb ; r16, high, low
|
||||
ld \1, LOW(\2) << 8 | LOW(\3)
|
||||
ENDM
|
||||
|
||||
|
||||
MACRO header_section ; name, address
|
||||
PUSHS
|
||||
SECTION "\1", ROM0[\2]
|
||||
\1:
|
||||
POPS
|
||||
ENDM
|
||||
header_section EntryPoint, $0100
|
||||
header_section NintendoLogo, $0104
|
||||
header_section NintendoLogoEnd, $0134
|
||||
header_section Title, $0134
|
||||
header_section ManufacturerCode, $013F
|
||||
header_section CGBFlag, $0143
|
||||
header_section NewLicenseeCode, $0144
|
||||
header_section SGBFlag, $0146
|
||||
header_section CartridgeType, $0147
|
||||
header_section ROMSize, $0148
|
||||
header_section RAMSize, $0149
|
||||
header_section DestinationCode, $014A
|
||||
header_section OldLicenseeCode, $014B
|
||||
header_section MaskRomVersion, $014C
|
||||
header_section HeaderChecksum, $014D
|
||||
header_section GlobalChecksum, $014E
|
||||
|
||||
ENDC
|
2
bsnes/gb/BootROMs/sgb2_boot.asm
Normal file
@@ -0,0 +1,2 @@
|
||||
DEF SGB2 = 1
|
||||
include "sgb_boot.asm"
|
235
bsnes/gb/BootROMs/sgb_boot.asm
Normal file
@@ -0,0 +1,235 @@
|
||||
; SameBoy SGB bootstrap ROM
|
||||
|
||||
include "sameboot.inc"
|
||||
|
||||
SECTION "BootCode", ROM0[$0000]
|
||||
Start:
|
||||
; Init stack pointer
|
||||
ld sp, $FFFE
|
||||
|
||||
; Clear memory VRAM
|
||||
ld hl, _VRAM
|
||||
xor a
|
||||
|
||||
.clearVRAMLoop
|
||||
ldi [hl], a
|
||||
bit 5, h
|
||||
jr z, .clearVRAMLoop
|
||||
|
||||
; Init Audio
|
||||
ld a, AUDENA_ON
|
||||
ldh [rNR52], a
|
||||
assert AUDENA_ON == AUDLEN_DUTY_50
|
||||
ldh [rNR11], a
|
||||
ld a, $F3
|
||||
ldh [rNR12], a ; Envelope $F, decreasing, sweep $3
|
||||
ldh [rNR51], a ; Channels 1+2+3+4 left, channels 1+2 right
|
||||
ld a, $77
|
||||
ldh [rNR50], a ; Volume $7, left and right
|
||||
|
||||
; Init BG palette to white
|
||||
ld a, %00_00_00_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Load logo from ROM.
|
||||
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
||||
; Tiles are ordered left to right, top to bottom.
|
||||
ld de, NintendoLogo
|
||||
ld hl, _VRAM + $10 ; This is where we load the tiles in VRAM
|
||||
|
||||
.loadLogoLoop
|
||||
ld a, [de] ; Read 2 rows
|
||||
ld b, a
|
||||
call DoubleBitsAndWriteRow
|
||||
call DoubleBitsAndWriteRow
|
||||
inc de
|
||||
ld a, e
|
||||
xor LOW(NintendoLogoEnd)
|
||||
jr nz, .loadLogoLoop
|
||||
|
||||
; Load trademark symbol
|
||||
ld de, TrademarkSymbol
|
||||
ld c, TrademarkSymbolEnd - TrademarkSymbol
|
||||
.loadTrademarkSymbolLoop:
|
||||
ld a, [de]
|
||||
inc de
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
dec c
|
||||
jr nz, .loadTrademarkSymbolLoop
|
||||
|
||||
; Set up tilemap
|
||||
ld a, $19 ; Trademark symbol tile ID
|
||||
ld [_SCRN0 + 8 * SCRN_VX_B + 16], a ; ... put in the superscript position
|
||||
ld hl, _SCRN0 + 9 * SCRN_VX_B + 15 ; Bottom right corner of the logo
|
||||
ld c, 12 ; Tiles in a logo row
|
||||
.tilemapLoop
|
||||
dec a
|
||||
jr z, .tilemapDone
|
||||
ldd [hl], a
|
||||
dec c
|
||||
jr nz, .tilemapLoop
|
||||
ld l, $0F ; Jump to top row
|
||||
jr .tilemapLoop
|
||||
.tilemapDone
|
||||
|
||||
; Turn on LCD
|
||||
ld a, LCDCF_ON | LCDCF_BLK01 | LCDCF_BGON
|
||||
ldh [rLCDC], a
|
||||
|
||||
ld a, $F1 ; Packet magic, increases by 2 for every packet
|
||||
ldh [hCommand], a
|
||||
ld hl, NintendoLogo ; Header start
|
||||
|
||||
xor a
|
||||
ld c, a ; JOYP
|
||||
|
||||
.sendCommand
|
||||
xor a
|
||||
ldh [c], a
|
||||
ld a, $30
|
||||
ldh [c], a
|
||||
|
||||
ldh a, [hCommand]
|
||||
call SendByte
|
||||
push hl
|
||||
|
||||
ld b, 14
|
||||
ld d, 0
|
||||
.checksumLoop
|
||||
call ReadHeaderByte
|
||||
add d
|
||||
ld d, a
|
||||
dec b
|
||||
jr nz, .checksumLoop
|
||||
|
||||
; Send checksum
|
||||
call SendByte
|
||||
pop hl
|
||||
|
||||
ld b, 14
|
||||
.sendLoop
|
||||
call ReadHeaderByte
|
||||
call SendByte
|
||||
dec b
|
||||
jr nz, .sendLoop
|
||||
|
||||
; Done bit
|
||||
ld a, $20
|
||||
ldh [c], a
|
||||
ld a, $30
|
||||
ldh [c], a
|
||||
|
||||
; Wait 4 frames
|
||||
ld e, 4
|
||||
ld a, 1
|
||||
ldh [rIE], a
|
||||
xor a
|
||||
.waitLoop
|
||||
ldh [rIF], a
|
||||
halt
|
||||
nop
|
||||
dec e
|
||||
jr nz, .waitLoop
|
||||
ldh [rIE], a
|
||||
|
||||
; Update command
|
||||
ldh a, [hCommand]
|
||||
add 2
|
||||
ldh [hCommand], a
|
||||
|
||||
ld a, $58
|
||||
cp l
|
||||
jr nz, .sendCommand
|
||||
|
||||
; Write to sound registers for DMG compatibility
|
||||
ld c, LOW(rNR13)
|
||||
ld a, $C1
|
||||
ldh [c], a
|
||||
inc c
|
||||
ld a, $7
|
||||
ldh [c], a
|
||||
|
||||
; Init BG palette
|
||||
ld a, %11_11_11_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Set registers to match the original SGB boot
|
||||
IF DEF(SGB2)
|
||||
ld a, BOOTUP_A_MGB
|
||||
ELSE
|
||||
ld a, BOOTUP_A_DMG
|
||||
ENDC
|
||||
ld hl, $C060
|
||||
|
||||
; Boot the game
|
||||
jp BootGame
|
||||
|
||||
ReadHeaderByte:
|
||||
ld a, $4F
|
||||
cp l
|
||||
jr c, .zero
|
||||
ld a, [hli]
|
||||
ret
|
||||
.zero:
|
||||
inc hl
|
||||
xor a
|
||||
ret
|
||||
|
||||
SendByte:
|
||||
ld e, a
|
||||
ld d, 8
|
||||
.loop
|
||||
ld a, $10
|
||||
rr e
|
||||
jr c, .zeroBit
|
||||
add a ; 10 -> 20
|
||||
.zeroBit
|
||||
ldh [c], a
|
||||
ld a, $30
|
||||
ldh [c], a
|
||||
dec d
|
||||
ret z
|
||||
jr .loop
|
||||
|
||||
DoubleBitsAndWriteRow:
|
||||
; Double the most significant 4 bits, b is shifted by 4
|
||||
ld a, 4
|
||||
ld c, 0
|
||||
.doubleCurrentBit
|
||||
sla b
|
||||
push af
|
||||
rl c
|
||||
pop af
|
||||
rl c
|
||||
dec a
|
||||
jr nz, .doubleCurrentBit
|
||||
ld a, c
|
||||
; Write as two rows
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
ret
|
||||
|
||||
TrademarkSymbol:
|
||||
pusho
|
||||
opt b.X
|
||||
db %..XXXX..
|
||||
db %.X....X.
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %.X....X.
|
||||
db %..XXXX..
|
||||
popo
|
||||
TrademarkSymbolEnd:
|
||||
|
||||
SECTION "BootGame", ROM0[$00FE]
|
||||
BootGame:
|
||||
ldh [rBANK], a
|
||||
|
||||
SECTION "HRAM", HRAM[_HRAM]
|
||||
hCommand:
|
||||
ds 1
|
1
bsnes/gb/CHANGES.md
Normal file
@@ -0,0 +1 @@
|
||||
See https://sameboy.github.io/changelog/
|
79
bsnes/gb/CONTRIBUTING.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# SameBoy Coding and Contribution Guidelines
|
||||
|
||||
## Issues
|
||||
|
||||
GitHub Issues are the most effective way to report a bug or request a feature in SameBoy. When reporting a bug, make sure you use the latest stable release, and make sure you mention the SameBoy frontend (Cocoa, SDL, Libretro) and operating system you're using. If you're using Linux/BSD/etc, or you build your own copy of SameBoy for another reason, give as much details as possible on your environment.
|
||||
|
||||
If your bug involves a crash, please attach a crash log or a core dump. If you're using Linux/BSD/etc, or if you're using the Libretro core, please attach the `sameboy` binary (or `libretro_sameboy` library) in that case.
|
||||
|
||||
If your bug is a regression, it'd be extremely helpful if you can report the the first affected version. You get extra credits if you use `git bisect` to point the exact breaking commit.
|
||||
|
||||
If your bug is an emulation bug (Such as a failing test ROM), and you have access to a Game Boy you can test on, please confirm SameBoy is indeed behaving differently from hardware, and report both the emulated model and revision in SameBoy, and the hardware revision you're testing on.
|
||||
|
||||
If your issue is a feature request, demonstrating use cases can help me better prioritize it.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
To allow quicker integration into SameBoy's master branch, contributors are asked to follow SameBoy's style and coding guidelines. Keep in mind that despite the seemingly strict guidelines, all pull requests are welcome – not following the guidelines does not mean your pull request will not be accepted, but it will require manual tweaks from my side for integrating.
|
||||
|
||||
### Languages and Compilers
|
||||
|
||||
SameBoy's core, SDL frontend, Libretro frontend, and automatic tester (Folders `Core`, `SDL` & `OpenDialog`, `libretro`, and `Tester`; respectively) are all written in C11. The Cocoa frontend, SameBoy's fork of Hex Fiend, JoyKit and the Quick Look previewer (Folders `Cocoa`, `HexFiend`, `JoyKit` and `QuickLook`; respectively) are all written in ARC-enabled Objective-C. The SameBoot ROMs (Under `BootROMs`) are written in rgbds-flavor SM83 assembly, with build tools in C11. The shaders (inside `Shaders`) are written in a polyglot GLSL and Metal style, with a few GLSL- and Metal-specific sources. The build system uses standalone Make, in the GNU flavor. Avoid adding new languages (C++, Swift, Python, CMake...) to any of the existing sub-projects.
|
||||
|
||||
SameBoy's main target compiler is Clang, but GCC is also supported when targeting Linux and Libretro. Other compilers (e.g. MSVC) are not supported, and unless there's a good reason, there's no need to go out of your way to add specific support for them. Extensions that are supported by both compilers (Such as `typeof`) may be used if it makes sense. It's OK if you can't test one of these compilers yourself; once you push a commit, the CI bot will let you know if you broke something.
|
||||
|
||||
### Third Party Libraries and Tools
|
||||
|
||||
Avoid adding new required dependencies; run-time and compile-time dependencies alike. Most importantly, avoid linking against GPL licensed libraries (LGPL libraries are fine), so SameBoy can retain its Expat license.
|
||||
|
||||
### Spacing, Indentation and Formatting
|
||||
|
||||
In all files and languages (Other than Makefiles when required), 4 spaces are used for indentation. Unix line endings (`\n`) are used exclusively, even in Windows-specific source files. (`\r` and `\t` shouldn't appear in any source file). Opening braces belong on the same line as their control flow directive, and on their own line when following a function prototype. The `else` keyword always starts on its own line. The `case` keyword is indented relative to its `switch` block, and the code inside a `case` is indented relative to its label. A control flow keyword should have a space between it and the following `(`, commas should follow a space, and operator (except `.` and `->`) should be surrounded by spaces.
|
||||
|
||||
Control flow statements must use `{}`, with the exception of `if` statements that only contain a single `break`, `continue`, or trivial `return` statements. If `{}`s are omitted, the statement must be on the same line as the `if` condition. Functions that do not have any argument must be specified as `(void)`, as mandated by the C standard. The `sizeof` and `typeof` operators should be used as if they're functions (With `()`). `*`, when used to declare pointer types (including functions that return pointers), and when used to dereference a pointer, is attached to the right side (The variable name) – not to the left, and not with spaces on both sides.
|
||||
|
||||
No strict limitations on a line's maximum width, but use your best judgement if you think a statement would benefit from an additional line break.
|
||||
|
||||
Well formatted code example:
|
||||
|
||||
```
|
||||
static void my_function(void)
|
||||
{
|
||||
GB_something_t *thing = GB_function(&gb, GB_FLAG_ONE | GB_FLAG_TWO, sizeof(thing));
|
||||
if (GB_is_thing(thing)) return;
|
||||
|
||||
switch (*thing) {
|
||||
case GB_QUACK:
|
||||
// Something
|
||||
case GB_DUCK:
|
||||
// Something else
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Badly formatted code example:
|
||||
```
|
||||
static void my_function(){
|
||||
GB_something_t* thing=GB_function(&gb , GB_FLAG_ONE|GB_FLAG_TWO , sizeof thing);
|
||||
if( GB_is_thing ( thing ) )
|
||||
return;
|
||||
|
||||
switch(* thing)
|
||||
{
|
||||
case GB_QUACK:
|
||||
// Something
|
||||
case GB_DUCK:
|
||||
// Something else
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Other Coding Conventions
|
||||
|
||||
The primitive types to be used in SameBoy are `unsigned` and `signed` (Without the `int` keyword), the `(u)int*_t` types, `char *` for UTF-8 strings, `double` for non-integer numbers, and `bool` for booleans (Including in Objective-C code, avoid `BOOL`). As long as it's not mandated by a 3rd-party API (e.g. `int` when using file descriptors), avoid using other primitive types. Use `const` whenever possible.
|
||||
|
||||
Most C names should be `lower_case_snake_case`. Constants and macros use `UPPER_CASE_SNAKE_CASE`. Type definitions use a `_t` suffix. Type definitions, as well as non-static (exported) core symbols, should be prefixed with `GB_` (SameBoy's core is intended to be used as a library, so it shouldn't contaminate the global namespace without prefixes). Exported symbols that are only meant to be used by other parts of the core should still get the `GB_` prefix, but their header definition should be inside `#ifdef GB_INTERNAL`.
|
||||
|
||||
For Objective-C naming conventions, use Apple's conventions (Some old Objective-C code mixes these with the C naming convention; new code should use Apple's convention exclusively). The name prefix for SameBoy classes and constants is `GB`. JoyKit's prefix is `JOY`, and Hex Fiend's prefix is `HF`.
|
||||
|
||||
In all languages, prefer long, unambiguous names over short ambiguous ones.
|
BIN
bsnes/gb/Cocoa/AppIcon.icns
Normal file
BIN
bsnes/gb/Cocoa/Assets.car
Normal file
51
bsnes/gb/Cocoa/AudioRecordingAccessoryView.xib
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="Document">
|
||||
<connections>
|
||||
<outlet property="audioFormatButton" destination="knX-AW-zt5" id="fKt-eI-H0y"/>
|
||||
<outlet property="audioRecordingAccessoryView" destination="c22-O7-iKe" id="XD8-Gi-qOC"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="354" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Atq-RE-328">
|
||||
<rect key="frame" x="18" y="10" width="56" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Format:" id="dso-NS-JlD">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="knX-AW-zt5">
|
||||
<rect key="frame" x="81" y="4" width="256" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Apple AIFF" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="M3Z-UN-VKZ" id="tLM-Di-Dy3">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<menu key="menu" id="gqn-SL-AA5">
|
||||
<items>
|
||||
<menuItem title="Apple AIFF" state="on" tag="1" id="M3Z-UN-VKZ"/>
|
||||
<menuItem title="RIFF WAVE" tag="2" id="zA0-Np-4XD"/>
|
||||
<menuItem title="Raw PCM (Stereo 96KHz, 16-bit LE)" id="r9J-4k-XH5"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="audioFormatChanged:" target="-2" id="I1k-d9-afp"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="75" y="19"/>
|
||||
</customView>
|
||||
</objects>
|
||||
</document>
|
BIN
bsnes/gb/Cocoa/BackstepTemplate.png
Normal file
After Width: | Height: | Size: 201 B |
BIN
bsnes/gb/Cocoa/BackstepTemplate@2x.png
Normal file
After Width: | Height: | Size: 336 B |
26
bsnes/gb/Cocoa/BigSurToolbar.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/* Backport the toolbarStyle property to allow compilation with older SDKs*/
|
||||
#ifndef __MAC_10_16
|
||||
typedef NS_ENUM(NSInteger, NSWindowToolbarStyle) {
|
||||
// The default value. The style will be determined by the window's given configuration
|
||||
NSWindowToolbarStyleAutomatic,
|
||||
// The toolbar will appear below the window title
|
||||
NSWindowToolbarStyleExpanded,
|
||||
// The toolbar will appear below the window title and the items in the toolbar will attempt to have equal widths when possible
|
||||
NSWindowToolbarStylePreference,
|
||||
// The window title will appear inline with the toolbar when visible
|
||||
NSWindowToolbarStyleUnified,
|
||||
// Same as NSWindowToolbarStyleUnified, but with reduced margins in the toolbar allowing more focus to be on the contents of the window
|
||||
NSWindowToolbarStyleUnifiedCompact
|
||||
} API_AVAILABLE(macos(11.0));
|
||||
|
||||
@interface NSWindow (toolbarStyle)
|
||||
@property (nonatomic) NSWindowToolbarStyle toolbarStyle API_AVAILABLE(macos(11.0));
|
||||
@end
|
||||
|
||||
@interface NSImage (SFSymbols)
|
||||
+ (instancetype)imageWithSystemSymbolName:(NSString *)symbolName accessibilityDescription:(NSString *)description API_AVAILABLE(macos(11.0));
|
||||
@end
|
||||
|
||||
#endif
|
BIN
bsnes/gb/Cocoa/CPU.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
bsnes/gb/Cocoa/CPU@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
bsnes/gb/Cocoa/CPU~solid.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
bsnes/gb/Cocoa/CPU~solid@2x.png
Normal file
After Width: | Height: | Size: 431 B |
BIN
bsnes/gb/Cocoa/CPU~solid~dark.png
Normal file
After Width: | Height: | Size: 202 B |
BIN
bsnes/gb/Cocoa/CPU~solid~dark@2x.png
Normal file
After Width: | Height: | Size: 420 B |
BIN
bsnes/gb/Cocoa/Cartridge.icns
Normal file
253
bsnes/gb/Cocoa/CheatSearch.xib
Normal file
@@ -0,0 +1,253 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24093.7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24093.7"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="GBCheatSearchController">
|
||||
<connections>
|
||||
<outlet property="addCheatButton" destination="o1I-5D-V4k" id="lRE-uQ-vul"/>
|
||||
<outlet property="conditionField" destination="XN7-BO-THS" id="vzh-y2-CcN"/>
|
||||
<outlet property="conditionTypeButton" destination="6RO-h8-lZ8" id="5wx-NY-lbK"/>
|
||||
<outlet property="dataTypeButton" destination="5Db-vP-S60" id="wdR-m7-fEI"/>
|
||||
<outlet property="operandField" destination="Q42-Vu-TJW" id="hRn-67-UmU"/>
|
||||
<outlet property="resultsLabel" destination="wbN-MX-lEy" id="gJB-fD-eKK"/>
|
||||
<outlet property="tableView" destination="fSU-85-fVM" id="1kO-kP-yBb"/>
|
||||
<outlet property="window" destination="QvC-M9-y7g" id="g09-DO-GsE"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="Cheat Search" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="GBPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="372"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
|
||||
<value key="minSize" type="size" width="480" height="372"/>
|
||||
<value key="maxSize" type="size" width="480" height="99999"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="372"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fvf-Co-5Ga">
|
||||
<rect key="frame" x="-1" y="155" width="482" height="218"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" drawsBackground="NO" id="1kJ-HR-keu">
|
||||
<rect key="frame" x="1" y="1" width="480" height="216"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" tableStyle="plain" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" headerView="oyv-sh-ulk" id="fSU-85-fVM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="188"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="17" height="0.0"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn identifier="AutomaticTableColumnIdentifier.0" editable="NO" width="143" minWidth="40" maxWidth="1000" id="8z0-o5-dNI">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Address">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" controlSize="large" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" title="Text Cell" id="bmG-fw-HDR" customClass="GBCenteredTextCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn identifier="AutomaticTableColumnIdentifier.1" editable="NO" width="143" minWidth="40" maxWidth="1000" id="mBc-yv-f00">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Previous Value">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" controlSize="large" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" title="Text Cell" id="BSe-S3-KNH" customClass="GBCenteredTextCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="143" minWidth="10" maxWidth="3.4028234663852886e+38" id="F7j-ck-3H0">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Current Value">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" controlSize="large" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="wjH-Ei-6hv" customClass="GBCenteredTextCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-2" id="Yqt-V5-OkG"/>
|
||||
<outlet property="delegate" destination="-2" id="TRM-gh-TG4"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<nil key="backgroundColor"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="ZbQ-IG-kyP">
|
||||
<rect key="frame" x="1" y="201" width="480" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="wK3-8v-kAQ">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<tableHeaderView key="headerView" wantsLayer="YES" id="oyv-sh-ulk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableHeaderView>
|
||||
</scrollView>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KdM-lW-WbP">
|
||||
<rect key="frame" x="371" y="24" width="96" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Search" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="t4Y-Ud-mJm">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="search:" target="-2" id="7pG-JY-vEF"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fTv-nr-5FT">
|
||||
<rect key="frame" x="6" y="95" width="124" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" alignment="right" title="Search Condition:" id="9C2-Xp-JIA">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vMd-zb-8jT">
|
||||
<rect key="frame" x="6" y="64" width="124" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" alignment="right" title="Expression:" id="Jgg-sA-jjs">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5Db-vP-S60">
|
||||
<rect key="frame" x="133" y="120" width="197" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="8-Bit" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="al4-Jb-OJB" id="dkg-V5-wsX">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="message"/>
|
||||
<menu key="menu" id="e5r-qR-pg7">
|
||||
<items>
|
||||
<menuItem title="8-Bit" state="on" id="al4-Jb-OJB"/>
|
||||
<menuItem title="16-Bit" tag="1" id="G2m-fU-8Lt"/>
|
||||
<menuItem title="16-Bit (Big Endian)" tag="3" id="JRa-DB-dyG"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
</popUpButton>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6RO-h8-lZ8">
|
||||
<rect key="frame" x="133" y="89" width="197" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Is Equal To…" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Vfb-Dg-Jkb" id="DPm-QO-c64">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="message"/>
|
||||
<menu key="menu" id="Kg9-Rd-1GQ">
|
||||
<items>
|
||||
<menuItem title="Any" id="cEg-eI-4hb"/>
|
||||
<menuItem title="Is Equal To…" state="on" id="Vfb-Dg-Jkb"/>
|
||||
<menuItem title="Is Different From…" id="JDg-d9-5Ux"/>
|
||||
<menuItem title="Is Greater Than…" id="Rir-w0-737"/>
|
||||
<menuItem title="Is Equal or Greater Than…" id="Lvo-pV-Syt"/>
|
||||
<menuItem title="Is Less Than…" id="VUW-DY-2cI"/>
|
||||
<menuItem title="Is Equal or Less Than…" id="rDN-UF-tIo"/>
|
||||
<menuItem title="Did Change" id="JdI-CW-E8H"/>
|
||||
<menuItem title="Did Not Change" id="sWc-Yz-Cve"/>
|
||||
<menuItem title="Did Increase" id="LHF-Lf-7tK"/>
|
||||
<menuItem title="Did Decrease" id="8s2-8n-aQO"/>
|
||||
<menuItem title="Custom…" id="8xc-2v-YQj"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="conditionChanged:" target="-2" id="KF9-vz-yNC"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q42-Vu-TJW">
|
||||
<rect key="frame" x="334" y="93" width="126" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" continuous="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="$0" drawsBackground="YES" usesSingleLineMode="YES" id="WDs-GG-7Lc">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="search:" target="-2" id="BDa-5j-qEz"/>
|
||||
<outlet property="delegate" destination="-2" id="1bO-hp-igc"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XN7-BO-THS">
|
||||
<rect key="frame" x="136" y="62" width="324" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" borderStyle="bezel" title="new == ($0)" drawsBackground="YES" usesSingleLineMode="YES" id="Krh-8w-4ug">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="search:" target="-2" id="sv5-eX-Kb9"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tBa-6c-9AY">
|
||||
<rect key="frame" x="13" y="24" width="96" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Pge-SU-Y1n">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="reset:" target="-2" id="KCy-Ob-tlg"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wbN-MX-lEy">
|
||||
<rect key="frame" x="-3" y="4" width="486" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Status" id="CM3-4U-qao">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="o1I-5D-V4k">
|
||||
<rect key="frame" x="264" y="24" width="110" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Add Cheat" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="GGV-nm-ASn">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="addCheat:" target="-2" id="7ax-kM-TeV"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="veO-Qn-0Sz">
|
||||
<rect key="frame" x="6" y="126" width="124" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Data Type:" id="KuT-rz-eHm">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<contentBorderThickness minY="22"/>
|
||||
<point key="canvasLocation" x="161" y="182"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
BIN
bsnes/gb/Cocoa/ColorCartridge.icns
Normal file
BIN
bsnes/gb/Cocoa/ContinueTemplate.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
bsnes/gb/Cocoa/ContinueTemplate@2x.png
Normal file
After Width: | Height: | Size: 314 B |
BIN
bsnes/gb/Cocoa/Display.png
Normal file
After Width: | Height: | Size: 462 B |
BIN
bsnes/gb/Cocoa/Display@2x.png
Normal file
After Width: | Height: | Size: 849 B |
BIN
bsnes/gb/Cocoa/Display~solid.png
Normal file
After Width: | Height: | Size: 132 B |
BIN
bsnes/gb/Cocoa/Display~solid@2x.png
Normal file
After Width: | Height: | Size: 461 B |
BIN
bsnes/gb/Cocoa/Display~solid~dark.png
Normal file
After Width: | Height: | Size: 120 B |
BIN
bsnes/gb/Cocoa/Display~solid~dark@2x.png
Normal file
After Width: | Height: | Size: 448 B |
98
bsnes/gb/Cocoa/Document.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "GBView.h"
|
||||
#import "GBImageView.h"
|
||||
#import "GBSplitView.h"
|
||||
#import "GBVisualizerView.h"
|
||||
#import "GBCPUView.h"
|
||||
#import "GBOSDView.h"
|
||||
#import "GBDebuggerButton.h"
|
||||
|
||||
enum model {
|
||||
MODEL_NONE,
|
||||
MODEL_DMG,
|
||||
MODEL_CGB,
|
||||
MODEL_AGB,
|
||||
MODEL_SGB,
|
||||
MODEL_MGB,
|
||||
MODEL_AUTO,
|
||||
|
||||
MODEL_QUICK_RESET = -1,
|
||||
};
|
||||
|
||||
@class GBCheatWindowController;
|
||||
@class GBPaletteView;
|
||||
@class GBObjectView;
|
||||
|
||||
@interface Document : NSDocument <NSWindowDelegate, GBImageViewDelegate, NSSplitViewDelegate>
|
||||
@property (readonly) GB_gameboy_t *gb;
|
||||
@property IBOutlet GBView *view;
|
||||
@property IBOutlet NSTextView *consoleOutput;
|
||||
@property IBOutlet NSPanel *consoleWindow;
|
||||
@property IBOutlet NSTextField *consoleInput;
|
||||
@property IBOutlet NSWindow *mainWindow;
|
||||
@property IBOutlet NSView *memoryView;
|
||||
@property IBOutlet NSPanel *memoryWindow;
|
||||
@property (readonly) GB_gameboy_t *gameboy;
|
||||
@property IBOutlet NSTextField *memoryBankInput;
|
||||
@property IBOutlet NSToolbarItem *memoryBankItem;
|
||||
@property IBOutlet NSPopUpButton *memorySpaceButton;
|
||||
@property IBOutlet GBImageView *tilesetImageView;
|
||||
@property IBOutlet NSPopUpButton *tilesetPaletteButton;
|
||||
@property IBOutlet GBImageView *tilemapImageView;
|
||||
@property IBOutlet NSPopUpButton *tilemapPaletteButton;
|
||||
@property IBOutlet NSPopUpButton *tilemapMapButton;
|
||||
@property IBOutlet NSPopUpButton *TilemapSetButton;
|
||||
@property IBOutlet NSButton *gridButton;
|
||||
@property IBOutlet NSTabView *vramTabView;
|
||||
@property IBOutlet NSPanel *vramWindow;
|
||||
@property IBOutlet NSTextField *vramStatusLabel;
|
||||
@property IBOutlet GBPaletteView *paletteView;
|
||||
@property IBOutlet GBObjectView *objectView;
|
||||
@property IBOutlet NSPanel *printerFeedWindow;
|
||||
@property IBOutlet NSProgressIndicator *printerSpinner;
|
||||
@property IBOutlet NSImageView *feedImageView;
|
||||
@property IBOutlet NSTextView *debuggerSideViewInput;
|
||||
@property IBOutlet NSTextView *debuggerSideView;
|
||||
@property IBOutlet GBSplitView *debuggerSplitView;
|
||||
@property IBOutlet NSBox *debuggerVerticalLine;
|
||||
@property IBOutlet NSPanel *cheatsWindow;
|
||||
@property IBOutlet GBCheatWindowController *cheatWindowController;
|
||||
@property (readonly) Document *partner;
|
||||
@property (readonly) bool isSlave;
|
||||
@property IBOutlet NSView *gbsPlayerView;
|
||||
@property IBOutlet NSTextField *gbsTitle;
|
||||
@property IBOutlet NSTextField *gbsAuthor;
|
||||
@property IBOutlet NSTextField *gbsCopyright;
|
||||
@property IBOutlet NSPopUpButton *gbsTracks;
|
||||
@property IBOutlet NSButton *gbsPlayPauseButton;
|
||||
@property IBOutlet NSButton *gbsRewindButton;
|
||||
@property IBOutlet NSSegmentedControl *gbsNextPrevButton;
|
||||
@property IBOutlet GBVisualizerView *gbsVisualizer;
|
||||
@property IBOutlet GBOSDView *osdView;
|
||||
@property (readonly) GB_oam_info_t *oamInfo;
|
||||
@property uint8_t oamCount;
|
||||
@property uint8_t oamHeight;
|
||||
@property IBOutlet NSView *audioRecordingAccessoryView;
|
||||
@property IBOutlet NSPopUpButton *audioFormatButton;
|
||||
@property IBOutlet NSVisualEffectView *debuggerSidebarEffectView API_AVAILABLE(macos(10.10));
|
||||
|
||||
@property IBOutlet GBDebuggerButton *debuggerContinueButton;
|
||||
@property IBOutlet GBDebuggerButton *debuggerNextButton;
|
||||
@property IBOutlet GBDebuggerButton *debuggerStepButton;
|
||||
@property IBOutlet GBDebuggerButton *debuggerFinishButton;
|
||||
@property IBOutlet GBDebuggerButton *debuggerBackstepButton;
|
||||
|
||||
@property IBOutlet NSScrollView *debuggerScrollView;
|
||||
@property IBOutlet NSView *debugBar;
|
||||
|
||||
@property IBOutlet GBCPUView *cpuView;
|
||||
@property IBOutlet NSTextField *cpuCounter;
|
||||
|
||||
+ (NSImage *) imageFromData:(NSData *)data width:(NSUInteger) width height:(NSUInteger) height scale:(double) scale;
|
||||
- (void) performAtomicBlock: (void (^)())block;
|
||||
- (void) connectLinkCable:(NSMenuItem *)sender;
|
||||
- (int)loadStateFile:(const char *)path noErrorOnNotFound:(bool)noErrorOnFileNotFound;
|
||||
- (NSString *)captureOutputForBlock: (void (^)())block;
|
||||
- (NSFont *)debuggerFontOfSize:(unsigned)size;
|
||||
@end
|
||||
|
2972
bsnes/gb/Cocoa/Document.m
Normal file
1034
bsnes/gb/Cocoa/Document.xib
Normal file
BIN
bsnes/gb/Cocoa/FinishTemplate.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
bsnes/gb/Cocoa/FinishTemplate@2x.png
Normal file
After Width: | Height: | Size: 298 B |
27
bsnes/gb/Cocoa/GBApp.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <JoyKit/JoyKit.h>
|
||||
|
||||
@interface GBApp : NSApplication <NSApplicationDelegate, NSUserNotificationCenterDelegate, NSMenuDelegate, WebUIDelegate, WebPolicyDelegate, WebFrameLoadDelegate, JOYListener>
|
||||
|
||||
@property (nonatomic, strong) IBOutlet NSWindow *preferencesWindow;
|
||||
@property (nonatomic, strong) IBOutlet NSView *graphicsTab;
|
||||
@property (nonatomic, strong) IBOutlet NSView *emulationTab;
|
||||
@property (nonatomic, strong) IBOutlet NSView *audioTab;
|
||||
@property (nonatomic, strong) IBOutlet NSView *controlsTab;
|
||||
@property (nonatomic, strong) IBOutlet NSView *updatesTab;
|
||||
- (IBAction)showPreferences: (id) sender;
|
||||
- (IBAction)toggleDeveloperMode:(id)sender;
|
||||
- (IBAction)switchPreferencesTab:(id)sender;
|
||||
@property (nonatomic, weak) IBOutlet NSMenuItem *linkCableMenuItem;
|
||||
@property (nonatomic, strong) IBOutlet NSWindow *updateWindow;
|
||||
@property (nonatomic, strong) IBOutlet WebView *updateChanges;
|
||||
@property (nonatomic, strong) IBOutlet NSProgressIndicator *updatesSpinner;
|
||||
@property (strong) IBOutlet NSButton *updatesButton;
|
||||
@property (strong) IBOutlet NSTextField *updateProgressLabel;
|
||||
@property (strong) IBOutlet NSButton *updateProgressButton;
|
||||
@property (strong) IBOutlet NSWindow *updateProgressWindow;
|
||||
@property (strong) IBOutlet NSProgressIndicator *updateProgressSpinner;
|
||||
- (void)updateThemesDefault:(bool)overwrite;
|
||||
@end
|
||||
|
817
bsnes/gb/Cocoa/GBApp.m
Normal file
@@ -0,0 +1,817 @@
|
||||
#import "GBApp.h"
|
||||
#import "GBButtons.h"
|
||||
#import "GBView.h"
|
||||
#import "Document.h"
|
||||
#import "GBJoyConManager.h"
|
||||
#import <Core/gb.h>
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <JoyKit/JoyKit.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <mach-o/dyld.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/xattr.h>
|
||||
|
||||
#define UPDATE_SERVER "https://sameboy.github.io"
|
||||
|
||||
@interface NSToolbarItem(private)
|
||||
- (NSButton *)_view;
|
||||
@end
|
||||
|
||||
static uint32_t color_to_int(NSColor *color)
|
||||
{
|
||||
color = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
|
||||
return (((unsigned)(color.redComponent * 0xFF)) << 16) |
|
||||
(((unsigned)(color.greenComponent * 0xFF)) << 8) |
|
||||
((unsigned)(color.blueComponent * 0xFF));
|
||||
}
|
||||
|
||||
@implementation GBApp
|
||||
{
|
||||
NSArray<NSView *> *_preferencesTabs;
|
||||
NSString *_lastVersion;
|
||||
NSString *_updateURL;
|
||||
NSURLSessionDownloadTask *_updateTask;
|
||||
enum {
|
||||
UPDATE_DOWNLOADING,
|
||||
UPDATE_EXTRACTING,
|
||||
UPDATE_WAIT_INSTALL,
|
||||
UPDATE_INSTALLING,
|
||||
UPDATE_FAILED,
|
||||
} _updateState;
|
||||
NSString *_downloadDirectory;
|
||||
AuthorizationRef _auth;
|
||||
bool _simulatingMenuEvent;
|
||||
}
|
||||
|
||||
- (void) applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
// Refresh icon if launched via a software update
|
||||
if (@available(macOS 26.0, *)) {
|
||||
// Severely broken on macOS 26
|
||||
}
|
||||
else {
|
||||
NSImage *icon = [[NSWorkspace sharedWorkspace] iconForFile:[[NSBundle mainBundle] bundlePath]];
|
||||
icon.size = [NSApplication sharedApplication].applicationIconImage.size;
|
||||
[NSApplication sharedApplication].applicationIconImage = icon;
|
||||
}
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
for (unsigned i = 0; i < GBKeyboardButtonCount; i++) {
|
||||
if ([[defaults objectForKey:button_to_preference_name(i, 0)] isKindOfClass:[NSString class]]) {
|
||||
[defaults removeObjectForKey:button_to_preference_name(i, 0)];
|
||||
}
|
||||
}
|
||||
|
||||
bool hasSFMono = false;
|
||||
if (@available(macOS 10.15, *)) {
|
||||
hasSFMono = [[NSFont monospacedSystemFontOfSize:12 weight:NSFontWeightRegular].displayName containsString:@"SF"];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
|
||||
@"GBRight": @(kVK_RightArrow),
|
||||
@"GBLeft": @(kVK_LeftArrow),
|
||||
@"GBUp": @(kVK_UpArrow),
|
||||
@"GBDown": @(kVK_DownArrow),
|
||||
|
||||
@"GBA": @(kVK_ANSI_X),
|
||||
@"GBB": @(kVK_ANSI_Z),
|
||||
@"GBSelect": @(kVK_Delete),
|
||||
@"GBStart": @(kVK_Return),
|
||||
|
||||
@"GBTurbo": @(kVK_Space),
|
||||
@"GBRewind": @(kVK_Tab),
|
||||
@"GBSlow-Motion": @(kVK_Shift),
|
||||
|
||||
@"GBFilter": @"NearestNeighbor",
|
||||
@"GBColorCorrection": @(GB_COLOR_CORRECTION_MODERN_BALANCED),
|
||||
@"GBHighpassFilter": @(GB_HIGHPASS_ACCURATE),
|
||||
@"GBRewindLength": @(120),
|
||||
@"GBFrameBlendingMode": @([defaults boolForKey:@"DisableFrameBlending"]? GB_FRAME_BLENDING_MODE_DISABLED : GB_FRAME_BLENDING_MODE_ACCURATE),
|
||||
|
||||
@"GBDMGModel": @(GB_MODEL_DMG_B),
|
||||
@"GBCGBModel": @(GB_MODEL_CGB_E),
|
||||
@"GBAGBModel": @(GB_MODEL_AGB_A),
|
||||
@"GBSGBModel": @(GB_MODEL_SGB2),
|
||||
@"GBRumbleMode": @(GB_RUMBLE_CARTRIDGE_ONLY),
|
||||
|
||||
@"GBVolume": @(1.0),
|
||||
|
||||
@"GBMBC7JoystickOverride": @NO,
|
||||
@"GBMBC7AllowMouse": @YES,
|
||||
|
||||
@"GBJoyConAutoPair": @YES,
|
||||
@"GBJoyConsDefaultsToHorizontal": @YES,
|
||||
|
||||
@"GBEmulatedModel": @(MODEL_AUTO),
|
||||
|
||||
@"GBDebuggerFont": hasSFMono? @"SF Mono" : @"Menlo",
|
||||
@"GBDebuggerFontSize": @12,
|
||||
|
||||
@"GBColorPalette": @1,
|
||||
@"GBTurboCap": @0,
|
||||
|
||||
// Default themes
|
||||
@"GBThemes": @{
|
||||
@"Canyon": @{
|
||||
@"BrightnessBias": @0.1227009965823247,
|
||||
@"Colors": @[@0xff0c1e20, @0xff122b91, @0xff466aa2, @0xfff1efae, @0xfff1efae],
|
||||
@"DisabledLCDColor": @NO,
|
||||
@"HueBias": @0.01782661816105247,
|
||||
@"HueBiasStrength": @1,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Desert": @{
|
||||
@"BrightnessBias": @0.0,
|
||||
@"Colors": @[@0xff302f3e, @0xff576674, @0xff839ba4, @0xffb1d0d2, @0xffb7d7d8],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.10087773904382469,
|
||||
@"HueBiasStrength": @0.062142056772908363,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Evening": @{
|
||||
@"BrightnessBias": @-0.10168700106441975,
|
||||
@"Colors": @[@0xff362601, @0xff695518, @0xff899853, @0xffa6e4ae, @0xffa9eebb],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.60027079191058874,
|
||||
@"HueBiasStrength": @0.33816297305747867,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Fog": @{
|
||||
@"BrightnessBias": @0.0,
|
||||
@"Colors": @[@0xff373c34, @0xff737256, @0xff9da386, @0xffc3d2bf, @0xffc7d8c6],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.55750435756972117,
|
||||
@"HueBiasStrength": @0.18424738545816732,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Green Slate": @{
|
||||
@"BrightnessBias": @0.2210012227296829,
|
||||
@"Colors": @[@0xff343117, @0xff6a876f, @0xff98b4a1, @0xffc3daca, @0xffc8decf],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.1887667975388467,
|
||||
@"HueBiasStrength": @0.1272283345460892,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Green Tea": @{
|
||||
@"BrightnessBias": @-0.4946326622596153,
|
||||
@"Colors": @[@0xff1a1d08, @0xff1d5231, @0xff3b9774, @0xff97e4c6, @0xffa9eed1],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.1912955007245464,
|
||||
@"HueBiasStrength": @0.3621708039314516,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Lavender": @{
|
||||
@"BrightnessBias": @0.10072476038566,
|
||||
@"Colors": @[@0xff2b2a3a, @0xff8c507c, @0xffbf82a8, @0xffe9bcce, @0xffeec3d3],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.7914529587142169,
|
||||
@"HueBiasStrength": @0.2498168498277664,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Magic Eggplant": @{
|
||||
@"BrightnessBias": @0.0,
|
||||
@"Colors": @[@0xff3c2136, @0xff942e84, @0xffc7699d, @0xfff1e4b0, @0xfff6f9b2],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.87717878486055778,
|
||||
@"HueBiasStrength": @0.65018052788844627,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Mystic Blue": @{
|
||||
@"BrightnessBias": @-0.3291049897670746,
|
||||
@"Colors": @[@0xff3b2306, @0xffa27807, @0xffd1b523, @0xfff6ebbe, @0xfffaf1e4],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.5282051088288426,
|
||||
@"HueBiasStrength": @0.7699633836746216,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Pink Pop": @{
|
||||
@"BrightnessBias": @0.624908447265625,
|
||||
@"Colors": @[@0xff28140a, @0xff7c42cb, @0xffaa83de, @0xffd1ceeb, @0xffd5d8ec],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.9477411056868732,
|
||||
@"HueBiasStrength": @0.80024421215057373,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Radioactive Pea": @{
|
||||
@"BrightnessBias": @-0.48079556772908372,
|
||||
@"Colors": @[@0xff215200, @0xff1f7306, @0xff169e34, @0xff03ceb8, @0xff00d4d1],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.3795131972111554,
|
||||
@"HueBiasStrength": @0.34337649402390436,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Rose": @{
|
||||
@"BrightnessBias": @0.2727272808551788,
|
||||
@"Colors": @[@0xff001500, @0xff4e1fae, @0xff865ac4, @0xffb7e6d3, @0xffbdffd4],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.9238900924101472,
|
||||
@"HueBiasStrength": @0.9957716464996338,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Seaweed": @{
|
||||
@"BrightnessBias": @-0.28532744023904377,
|
||||
@"Colors": @[@0xff3f0015, @0xff426532, @0xff58a778, @0xff95e0df, @0xffa0e7ee],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.2694067480079681,
|
||||
@"HueBiasStrength": @0.51565612549800799,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Twilight": @{
|
||||
@"BrightnessBias": @-0.091789093625498031,
|
||||
@"Colors": @[@0xff3f0015, @0xff461286, @0xff6254bd, @0xff97d3e9, @0xffa0e7ee],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.0,
|
||||
@"HueBiasStrength": @0.49710532868525897,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
},
|
||||
|
||||
@"NSToolbarItemForcesStandardSize": @YES, // Forces Monterey to resepect toolbar item sizes
|
||||
@"NSToolbarItemWarnOnMinMaxSize": @NO, // Not going to use Constraints, Apple
|
||||
}];
|
||||
|
||||
[JOYController startOnRunLoop:[NSRunLoop currentRunLoop] withOptions:@{
|
||||
JOYAxes2DEmulateButtonsKey: @YES,
|
||||
JOYHatsEmulateButtonsKey: @YES,
|
||||
}];
|
||||
|
||||
[GBJoyConManager sharedInstance]; // Starts handling Joy-Cons
|
||||
|
||||
[JOYController registerListener:self];
|
||||
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBNotificationsUsed"]) {
|
||||
[NSUserNotificationCenter defaultUserNotificationCenter].delegate = self;
|
||||
}
|
||||
|
||||
[self askAutoUpdates];
|
||||
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBAutoUpdatesEnabled"]) {
|
||||
[self checkForUpdates];
|
||||
}
|
||||
|
||||
if ([[NSProcessInfo processInfo].arguments containsObject:@"--update-launch"]) {
|
||||
[NSApp activateIgnoringOtherApps:true];
|
||||
}
|
||||
|
||||
if (![[[NSUserDefaults standardUserDefaults] stringForKey:@"GBThemesVersion"] isEqualToString:@(GB_VERSION)]) {
|
||||
[self updateThemesDefault:false];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@(GB_VERSION) forKey:@"GBThemesVersion"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateThemesDefault:(bool)overwrite
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableDictionary *currentThemes = [defaults dictionaryForKey:@"GBThemes"].mutableCopy;
|
||||
[defaults removeObjectForKey:@"GBThemes"];
|
||||
NSMutableDictionary *defaultThemes = [defaults dictionaryForKey:@"GBThemes"].mutableCopy;
|
||||
if (![[NSUserDefaults standardUserDefaults] stringForKey:@"GBThemesVersion"]) {
|
||||
// Force update the Pink Pop theme, it was glitchy in 1.0
|
||||
[currentThemes removeObjectForKey:@"Pink Pop"];
|
||||
}
|
||||
if (overwrite) {
|
||||
[currentThemes addEntriesFromDictionary:defaultThemes];
|
||||
[defaults setObject:currentThemes forKey:@"GBThemes"];
|
||||
}
|
||||
else {
|
||||
[defaultThemes addEntriesFromDictionary:currentThemes];
|
||||
[defaults setObject:defaultThemes forKey:@"GBThemes"];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleDeveloperMode:(id)sender
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setBool:![defaults boolForKey:@"DeveloperMode"] forKey:@"DeveloperMode"];
|
||||
}
|
||||
|
||||
- (IBAction)switchPreferencesTab:(id)sender
|
||||
{
|
||||
for (NSView *view in _preferencesTabs) {
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
NSView *tab = _preferencesTabs[[sender tag]];
|
||||
NSRect old = [_preferencesWindow frame];
|
||||
NSRect new = [_preferencesWindow frameRectForContentRect:tab.frame];
|
||||
new.origin.x = old.origin.x;
|
||||
new.origin.y = old.origin.y + (old.size.height - new.size.height);
|
||||
[_preferencesWindow setFrame:new display:true animate:_preferencesWindow.visible];
|
||||
[_preferencesWindow.contentView addSubview:tab];
|
||||
}
|
||||
|
||||
- (BOOL)validateMenuItem:(NSMenuItem *)anItem
|
||||
{
|
||||
if ([anItem action] == @selector(toggleDeveloperMode:)) {
|
||||
[(NSMenuItem *)anItem setState:[[NSUserDefaults standardUserDefaults] boolForKey:@"DeveloperMode"]];
|
||||
}
|
||||
|
||||
if (anItem == self.linkCableMenuItem) {
|
||||
return [[NSDocumentController sharedDocumentController] documents].count > 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)menuNeedsUpdate:(NSMenu *)menu
|
||||
{
|
||||
NSMutableArray *items = [NSMutableArray array];
|
||||
NSDocument *currentDocument = [[NSDocumentController sharedDocumentController] currentDocument];
|
||||
|
||||
for (NSDocument *document in [[NSDocumentController sharedDocumentController] documents]) {
|
||||
if (document == currentDocument) continue;
|
||||
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:document.displayName action:@selector(connectLinkCable:) keyEquivalent:@""];
|
||||
item.representedObject = document;
|
||||
item.image = [[NSWorkspace sharedWorkspace] iconForFile:document.fileURL.path];
|
||||
[item.image setSize:NSMakeSize(16, 16)];
|
||||
[items addObject:item];
|
||||
}
|
||||
[menu removeAllItems];
|
||||
for (NSMenuItem *item in items) {
|
||||
[menu addItem:item];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction) showPreferences: (id) sender
|
||||
{
|
||||
NSArray *objects;
|
||||
if (!_preferencesWindow) {
|
||||
[[NSBundle mainBundle] loadNibNamed:@"Preferences" owner:self topLevelObjects:&objects];
|
||||
NSToolbarItem *first_toolbar_item = [_preferencesWindow.toolbar.items firstObject];
|
||||
_preferencesWindow.toolbar.selectedItemIdentifier = [first_toolbar_item itemIdentifier];
|
||||
_preferencesTabs = @[self.emulationTab, self.graphicsTab, self.audioTab, self.controlsTab, self.updatesTab];
|
||||
[self switchPreferencesTab:first_toolbar_item];
|
||||
[_preferencesWindow center];
|
||||
#ifndef UPDATE_SUPPORT
|
||||
[_preferencesWindow.toolbar removeItemAtIndex:4];
|
||||
#endif
|
||||
for (unsigned i = _preferencesWindow.toolbar.items.count; i--;) {
|
||||
[_preferencesWindow.toolbar.items[i] _view].imageScaling = NSImageScaleNone;
|
||||
}
|
||||
}
|
||||
[_preferencesWindow makeKeyAndOrderFront:self];
|
||||
}
|
||||
|
||||
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender
|
||||
{
|
||||
[self askAutoUpdates];
|
||||
/* Bring an existing panel to the foreground */
|
||||
for (NSWindow *window in [[NSApplication sharedApplication] windows]) {
|
||||
if ([window isKindOfClass:[NSOpenPanel class]]) {
|
||||
[(NSOpenPanel *)window makeKeyAndOrderFront:nil];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
[[NSDocumentController sharedDocumentController] openDocument:self];
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
|
||||
{
|
||||
[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfFile:notification.identifier display:true];
|
||||
}
|
||||
|
||||
- (void)updateFound
|
||||
{
|
||||
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@UPDATE_SERVER "/raw_changes"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
|
||||
NSColor *linkColor = [NSColor colorWithRed:0.125 green:0.325 blue:1.0 alpha:1.0];
|
||||
if (@available(macOS 10.10, *)) {
|
||||
linkColor = [NSColor linkColor];
|
||||
}
|
||||
|
||||
NSString *changes = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSRange cutoffRange = [changes rangeOfString:@"<!--(" GB_VERSION ")-->"];
|
||||
if (cutoffRange.location != NSNotFound) {
|
||||
changes = [changes substringToIndex:cutoffRange.location];
|
||||
}
|
||||
|
||||
NSString *html = [NSString stringWithFormat:@"<!DOCTYPE html><html><head><title></title>"
|
||||
"<style>html {background-color:transparent; color: #%06x; line-height:1.5} a:link, a:visited{color:#%06x; text-decoration:none}</style>"
|
||||
"</head><body>%@</body></html>",
|
||||
color_to_int([NSColor textColor]),
|
||||
color_to_int(linkColor),
|
||||
changes];
|
||||
|
||||
if ([(NSHTTPURLResponse *)response statusCode] == 200) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSArray *objects;
|
||||
[[NSBundle mainBundle] loadNibNamed:@"UpdateWindow" owner:self topLevelObjects:&objects];
|
||||
if (@available(macOS 10.11, *)) {
|
||||
self.updateChanges.preferences.standardFontFamily = @"-apple-system";
|
||||
}
|
||||
else if (@available(macOS 10.10, *)) {
|
||||
self.updateChanges.preferences.standardFontFamily = @"Helvetica Neue";
|
||||
}
|
||||
else {
|
||||
self.updateChanges.preferences.standardFontFamily = @"Lucida Grande";
|
||||
}
|
||||
if (@available(macOS 10.15, *)) {
|
||||
self.updateChanges.preferences.fixedFontFamily = [NSFont monospacedSystemFontOfSize:12 weight:NSFontWeightRegular].displayName;
|
||||
}
|
||||
else {
|
||||
self.updateChanges.preferences.fixedFontFamily = @"Menlo";
|
||||
}
|
||||
self.updateChanges.drawsBackground = false;
|
||||
[self.updateChanges.mainFrame loadHTMLString:html baseURL:nil];
|
||||
});
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
|
||||
- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
|
||||
{
|
||||
// Disable reload context menu
|
||||
if ([defaultMenuItems count] <= 2) {
|
||||
return nil;
|
||||
}
|
||||
return defaultMenuItems;
|
||||
}
|
||||
|
||||
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sender.mainFrame.frameView.documentView.enclosingScrollView.drawsBackground = true;
|
||||
sender.mainFrame.frameView.documentView.enclosingScrollView.backgroundColor = [NSColor textBackgroundColor];
|
||||
sender.policyDelegate = self;
|
||||
[self.updateWindow center];
|
||||
[self.updateWindow makeKeyAndOrderFront:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
|
||||
{
|
||||
[listener ignore];
|
||||
[[NSWorkspace sharedWorkspace] openURL:[request URL]];
|
||||
}
|
||||
|
||||
- (void)checkForUpdates
|
||||
{
|
||||
#ifdef UPDATE_SUPPORT
|
||||
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@UPDATE_SERVER "/latest_version"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.updatesSpinner stopAnimation:nil];
|
||||
[self.updatesButton setEnabled:true];
|
||||
});
|
||||
if ([(NSHTTPURLResponse *)response statusCode] == 200) {
|
||||
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSArray <NSString *> *components = [string componentsSeparatedByString:@"|"];
|
||||
if (components.count != 2) return;
|
||||
_lastVersion = components[0];
|
||||
_updateURL = components[1];
|
||||
if (![@GB_VERSION isEqualToString:_lastVersion] &&
|
||||
![[[NSUserDefaults standardUserDefaults] stringForKey:@"GBSkippedVersion"] isEqualToString:_lastVersion]) {
|
||||
[self updateFound];
|
||||
}
|
||||
}
|
||||
}] resume];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (IBAction)userCheckForUpdates:(id)sender
|
||||
{
|
||||
if (self.updateWindow) {
|
||||
[self.updateWindow makeKeyAndOrderFront:sender];
|
||||
}
|
||||
else {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:@"GBSkippedVersion"];
|
||||
[self checkForUpdates];
|
||||
[sender setEnabled:false];
|
||||
[self.updatesSpinner startAnimation:sender];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)askAutoUpdates
|
||||
{
|
||||
#ifdef UPDATE_SUPPORT
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"GBAskedAutoUpdates"]) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
alert.messageText = @"Should SameBoy check for updates when launched?";
|
||||
alert.informativeText = @"SameBoy is frequently updated with new features, accuracy improvements, and bug fixes. This setting can always be changed in the preferences window.";
|
||||
[alert addButtonWithTitle:@"Check on Launch"];
|
||||
[alert addButtonWithTitle:@"Don't Check on Launch"];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[alert runModal] == NSAlertFirstButtonReturn forKey:@"GBAutoUpdatesEnabled"];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:true forKey:@"GBAskedAutoUpdates"];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (IBAction)skipVersion:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:_lastVersion forKey:@"GBSkippedVersion"];
|
||||
[self.updateWindow performClose:sender];
|
||||
}
|
||||
|
||||
- (bool)executePath:(NSString *)path withArguments:(NSArray <NSString *> *)arguments
|
||||
{
|
||||
if (!_auth) {
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
task.launchPath = path;
|
||||
task.arguments = arguments;
|
||||
[task launch];
|
||||
[task waitUntilExit];
|
||||
return task.terminationStatus == 0 && task.terminationReason == NSTaskTerminationReasonExit;
|
||||
}
|
||||
|
||||
char *argv[arguments.count + 1];
|
||||
argv[arguments.count] = NULL;
|
||||
for (unsigned i = 0; i < arguments.count; i++) {
|
||||
argv[i] = (char *)arguments[i].UTF8String;
|
||||
}
|
||||
|
||||
return AuthorizationExecuteWithPrivileges(_auth, path.UTF8String, kAuthorizationFlagDefaults, argv, NULL) == errAuthorizationSuccess;
|
||||
}
|
||||
|
||||
- (void)deauthorize
|
||||
{
|
||||
if (_auth) {
|
||||
AuthorizationFree(_auth, kAuthorizationFlagDefaults);
|
||||
_auth = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)installUpdate:(id)sender
|
||||
{
|
||||
bool needsAuthorization = false;
|
||||
if ([self executePath:@"/usr/sbin/spctl" withArguments:@[@"--status"]]) { // Succeeds when GateKeeper is on
|
||||
// GateKeeper is on, we need to --add ourselves as root, else we might get a GateKeeper crash
|
||||
needsAuthorization = true;
|
||||
}
|
||||
else if (access(_dyld_get_image_name(0), W_OK)) {
|
||||
// We don't have write access, so we need authorization to update as root
|
||||
needsAuthorization = true;
|
||||
}
|
||||
|
||||
if (needsAuthorization && !_auth) {
|
||||
AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagPreAuthorize | kAuthorizationFlagInteractionAllowed, &_auth);
|
||||
// Make sure we can modify the bundle
|
||||
if (![self executePath:@"/usr/sbin/chown" withArguments:@[@"-R", [NSString stringWithFormat:@"%d:%d", getuid(), getgid()], [NSBundle mainBundle].bundlePath]]) {
|
||||
[self deauthorize];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[self.updateProgressSpinner startAnimation:nil];
|
||||
self.updateProgressButton.title = @"Cancel";
|
||||
self.updateProgressButton.enabled = true;
|
||||
self.updateProgressLabel.stringValue = @"Downloading update…";
|
||||
_updateState = UPDATE_DOWNLOADING;
|
||||
_updateTask = [[NSURLSession sharedSession] downloadTaskWithURL: [NSURL URLWithString:_updateURL] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
|
||||
_updateTask = nil;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Extracting update…";
|
||||
_updateState = UPDATE_EXTRACTING;
|
||||
});
|
||||
|
||||
_downloadDirectory = [[[NSFileManager defaultManager] URLForDirectory:NSItemReplacementDirectory
|
||||
inDomain:NSUserDomainMask
|
||||
appropriateForURL:[[NSBundle mainBundle] bundleURL]
|
||||
create:true
|
||||
error:nil] path];
|
||||
if (!_downloadDirectory) {
|
||||
[self deauthorize];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Failed to extract update.";
|
||||
_updateState = UPDATE_FAILED;
|
||||
self.updateProgressButton.title = @"Close";
|
||||
self.updateProgressButton.enabled = true;
|
||||
[self.updateProgressSpinner stopAnimation:nil];
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSTask *unzipTask;
|
||||
unzipTask = [[NSTask alloc] init];
|
||||
unzipTask.launchPath = @"/usr/bin/unzip";
|
||||
unzipTask.arguments = @[location.path, @"-d", _downloadDirectory];
|
||||
[unzipTask launch];
|
||||
[unzipTask waitUntilExit];
|
||||
if (unzipTask.terminationStatus != 0 || unzipTask.terminationReason != NSTaskTerminationReasonExit) {
|
||||
[self deauthorize];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Failed to extract update.";
|
||||
_updateState = UPDATE_FAILED;
|
||||
self.updateProgressButton.title = @"Close";
|
||||
self.updateProgressButton.enabled = true;
|
||||
[self.updateProgressSpinner stopAnimation:nil];
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Update ready, save your game progress and click Install.";
|
||||
_updateState = UPDATE_WAIT_INSTALL;
|
||||
self.updateProgressButton.title = @"Install";
|
||||
self.updateProgressButton.enabled = true;
|
||||
[self.updateProgressSpinner stopAnimation:nil];
|
||||
});
|
||||
}];
|
||||
[_updateTask resume];
|
||||
|
||||
self.updateProgressWindow.preventsApplicationTerminationWhenModal = false;
|
||||
[self.updateWindow beginSheet:self.updateProgressWindow completionHandler:^(NSModalResponse returnCode) {
|
||||
[self.updateWindow close];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)performUpgrade
|
||||
{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Instaling update…";
|
||||
_updateState = UPDATE_INSTALLING;
|
||||
self.updateProgressButton.enabled = false;
|
||||
[self.updateProgressSpinner startAnimation:nil];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSString *executablePath = [[NSBundle mainBundle] executablePath];
|
||||
NSString *contentsPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents"];
|
||||
NSString *contentsTempPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"TempContents"];
|
||||
NSString *updateContentsPath = [_downloadDirectory stringByAppendingPathComponent:@"SameBoy.app/Contents"];
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] moveItemAtPath:contentsPath toPath:contentsTempPath error:&error];
|
||||
if (error) {
|
||||
[self deauthorize];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
_downloadDirectory = nil;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Failed to install update.";
|
||||
_updateState = UPDATE_FAILED;
|
||||
self.updateProgressButton.title = @"Close";
|
||||
self.updateProgressButton.enabled = true;
|
||||
[self.updateProgressSpinner stopAnimation:nil];
|
||||
});
|
||||
return;
|
||||
}
|
||||
[[NSFileManager defaultManager] moveItemAtPath:updateContentsPath toPath:contentsPath error:&error];
|
||||
if (error) {
|
||||
[self deauthorize];
|
||||
[[NSFileManager defaultManager] moveItemAtPath:contentsTempPath toPath:contentsPath error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
_downloadDirectory = nil;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Failed to install update.";
|
||||
_updateState = UPDATE_FAILED;
|
||||
self.updateProgressButton.title = @"Close";
|
||||
self.updateProgressButton.enabled = true;
|
||||
[self.updateProgressSpinner stopAnimation:nil];
|
||||
});
|
||||
return;
|
||||
}
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:contentsTempPath error:nil];
|
||||
|
||||
// Remove the quarantine flag so we don't have to escape translocation
|
||||
NSString *bundlePath = [NSBundle mainBundle].bundlePath;
|
||||
removexattr(bundlePath.UTF8String, "com.apple.quarantine", 0);
|
||||
for (NSString *path in [[NSFileManager defaultManager] enumeratorAtPath:bundlePath]) {
|
||||
removexattr([bundlePath stringByAppendingPathComponent:path].UTF8String, "com.apple.quarantine", 0);
|
||||
};
|
||||
|
||||
_downloadDirectory = nil;
|
||||
atexit_b(^{
|
||||
execl(executablePath.UTF8String, executablePath.UTF8String, "--update-launch", NULL);
|
||||
});
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[NSApp terminate:nil];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
- (IBAction)updateAction:(id)sender
|
||||
{
|
||||
switch (_updateState) {
|
||||
case UPDATE_DOWNLOADING:
|
||||
[_updateTask cancelByProducingResumeData:nil];
|
||||
_updateTask = nil;
|
||||
[self.updateProgressWindow close];
|
||||
break;
|
||||
case UPDATE_WAIT_INSTALL:
|
||||
[self performUpgrade];
|
||||
break;
|
||||
case UPDATE_EXTRACTING:
|
||||
case UPDATE_INSTALLING:
|
||||
break;
|
||||
case UPDATE_FAILED:
|
||||
[self.updateProgressWindow close];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)orderFrontAboutPanel:(id)sender
|
||||
{
|
||||
// NSAboutPanelOptionApplicationIcon is not available prior to 10.13, but the key is still there and working.
|
||||
[[NSApplication sharedApplication] orderFrontStandardAboutPanelWithOptions:@{
|
||||
@"ApplicationIcon": [NSImage imageNamed:@"Icon"]
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)controller:(JOYController *)controller buttonChangedState:(JOYButton *)button
|
||||
{
|
||||
if (!button.isPressed) return;
|
||||
NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitInstanceMapping"][controller.uniqueID];
|
||||
if (!mapping) {
|
||||
mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitNameMapping"][controller.deviceName];
|
||||
}
|
||||
|
||||
JOYButtonUsage usage = ((JOYButtonUsage)[mapping[n2s(button.uniqueID)] unsignedIntValue]) ?: -1;
|
||||
if (!mapping && usage >= JOYButtonUsageGeneric0) {
|
||||
usage = GB_inline_const(JOYButtonUsage[], {JOYButtonUsageY, JOYButtonUsageA, JOYButtonUsageB, JOYButtonUsageX})[(usage - JOYButtonUsageGeneric0) & 3];
|
||||
}
|
||||
|
||||
if (usage == GBJoyKitHotkey1 || usage == GBJoyKitHotkey2) {
|
||||
if (_preferencesWindow && self.keyWindow == _preferencesWindow) {
|
||||
return;
|
||||
}
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"GBAllowBackgroundControllers"] && !self.keyWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *keyEquivalent = [[NSUserDefaults standardUserDefaults] stringForKey:usage == GBJoyKitHotkey1? @"GBJoypadHotkey1" : @"GBJoypadHotkey2"];
|
||||
NSEventModifierFlags flags = NSEventModifierFlagCommand;
|
||||
if ([keyEquivalent hasPrefix:@"^"]) {
|
||||
flags |= NSEventModifierFlagShift;
|
||||
[keyEquivalent substringFromIndex:1];
|
||||
}
|
||||
_simulatingMenuEvent = true;
|
||||
[[NSApplication sharedApplication] sendEvent:[NSEvent keyEventWithType:NSEventTypeKeyDown
|
||||
location:(NSPoint){0,}
|
||||
modifierFlags:flags
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:NULL
|
||||
characters:keyEquivalent
|
||||
charactersIgnoringModifiers:keyEquivalent
|
||||
isARepeat:false
|
||||
keyCode:0]];
|
||||
_simulatingMenuEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSWindow *)keyWindow
|
||||
{
|
||||
NSWindow *ret = [super keyWindow];
|
||||
if (!ret && _simulatingMenuEvent) {
|
||||
ret = [(Document *)self.orderedDocuments.firstObject mainWindow];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (NSWindow *)mainWindow
|
||||
{
|
||||
NSWindow *ret = [super mainWindow];
|
||||
if (!ret && _simulatingMenuEvent) {
|
||||
ret = [(Document *)self.orderedDocuments.firstObject mainWindow];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (IBAction)openDebuggerHelp:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://sameboy.github.io/debugger/"]];
|
||||
}
|
||||
|
||||
- (IBAction)openSponsor:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://github.com/sponsors/LIJI32"]];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_downloadDirectory) {
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)nop:(id)sender
|
||||
{
|
||||
}
|
||||
|
||||
/* This runs before C constructors. If we need to escape translocation, we should
|
||||
do it ASAP to minimize our launch time. */
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
if (@available(macOS 10.12, *)) {
|
||||
/* Detect and escape translocation so we can safely update ourselves */
|
||||
if ([[[NSBundle mainBundle] bundlePath] containsString:@"/AppTranslocation/"]) {
|
||||
const char *mountPath = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent].UTF8String;
|
||||
struct statfs *mntbuf;
|
||||
int mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
|
||||
for (unsigned i = 0; i < mntsize; i++) {
|
||||
if (strcmp(mntbuf[i].f_mntonname, mountPath) == 0) {
|
||||
NSBundle *origBundle = [NSBundle bundleWithPath:@(mntbuf[i].f_mntfromname)];
|
||||
|
||||
execl(origBundle.executablePath.UTF8String, origBundle.executablePath.UTF8String, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
5
bsnes/gb/Cocoa/GBBorderView.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBBorderView : NSView
|
||||
|
||||
@end
|
26
bsnes/gb/Cocoa/GBBorderView.m
Normal file
@@ -0,0 +1,26 @@
|
||||
#import "GBBorderView.h"
|
||||
|
||||
@implementation GBBorderView
|
||||
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
self.wantsLayer = true;
|
||||
}
|
||||
|
||||
- (BOOL)wantsUpdateLayer
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)updateLayer
|
||||
{
|
||||
/* Wonderful, wonderful windowserver(?) bug. Using 0,0,0 here would cause it to render garbage
|
||||
on fullscreen windows on some High Sierra machines. Any other value, including the one used
|
||||
here (which is rendered exactly the same due to rounding) works around this bug. */
|
||||
self.layer.backgroundColor = [NSColor colorWithCalibratedRed:0
|
||||
green:0
|
||||
blue:1.0 / 1024.0
|
||||
alpha:1.0].CGColor;
|
||||
}
|
||||
@end
|
40
bsnes/gb/Cocoa/GBButtons.h
Normal file
@@ -0,0 +1,40 @@
|
||||
typedef enum {
|
||||
GBRight,
|
||||
GBLeft,
|
||||
GBUp,
|
||||
GBDown,
|
||||
GBA,
|
||||
GBB,
|
||||
GBSelect,
|
||||
GBStart,
|
||||
GBRapidA,
|
||||
GBRapidB,
|
||||
GBTurbo,
|
||||
GBRewind,
|
||||
GBUnderclock,
|
||||
GBHotkey1,
|
||||
GBHotkey2,
|
||||
GBTotalButtonCount,
|
||||
GBKeyboardButtonCount = GBUnderclock + 1,
|
||||
GBPerPlayerButtonCount = GBRapidB + 1,
|
||||
} GBButton;
|
||||
|
||||
#define GBJoyKitHotkey1 JOYButtonUsageGeneric0 + 0x100
|
||||
#define GBJoyKitHotkey2 JOYButtonUsageGeneric0 + 0x101
|
||||
#define GBJoyKitRapidA JOYButtonUsageGeneric0 + 0x102
|
||||
#define GBJoyKitRapidB JOYButtonUsageGeneric0 + 0x103
|
||||
|
||||
extern NSString const *GBButtonNames[GBTotalButtonCount];
|
||||
|
||||
static inline NSString *n2s(uint64_t number)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%llx", number];
|
||||
}
|
||||
|
||||
static inline NSString *button_to_preference_name(GBButton button, unsigned player)
|
||||
{
|
||||
if (player) {
|
||||
return [NSString stringWithFormat:@"GBPlayer%d%@", player + 1, GBButtonNames[button]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"GB%@", GBButtonNames[button]];
|
||||
}
|
4
bsnes/gb/Cocoa/GBButtons.m
Normal file
@@ -0,0 +1,4 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "GBButtons.h"
|
||||
|
||||
NSString const *GBButtonNames[] = {@"Right", @"Left", @"Up", @"Down", @"A", @"B", @"Select", @"Start", @"Rapid A", @"Rapid B", @"Turbo", @"Rewind", @"Slow-Motion", @"Hotkey 1", @"Hotkey 2"};
|
5
bsnes/gb/Cocoa/GBCPUView.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBCPUView : NSView
|
||||
- (void)addSample:(double)sample;
|
||||
@end
|
126
bsnes/gb/Cocoa/GBCPUView.m
Normal file
@@ -0,0 +1,126 @@
|
||||
#import "GBCPUView.h"
|
||||
|
||||
#define SAMPLE_COUNT 0x100 // ~4 seconds
|
||||
|
||||
@implementation GBCPUView
|
||||
{
|
||||
double _samples[SAMPLE_COUNT];
|
||||
size_t _position;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
CGRect bounds = self.bounds;
|
||||
NSSize size = bounds.size;
|
||||
unsigned factor = [[self.window screen] backingScaleFactor];
|
||||
|
||||
NSBitmapImageRep *maskBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:(unsigned)size.width * factor
|
||||
pixelsHigh:(unsigned)size.height * factor
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:2
|
||||
hasAlpha:true
|
||||
isPlanar:false
|
||||
colorSpaceName:NSDeviceWhiteColorSpace
|
||||
bytesPerRow:size.width * 2 * factor
|
||||
bitsPerPixel:16];
|
||||
|
||||
|
||||
|
||||
NSGraphicsContext *mainContext = [NSGraphicsContext currentContext];
|
||||
|
||||
|
||||
NSColor *greenColor, *redColor;
|
||||
if (@available(macOS 10.10, *)) {
|
||||
greenColor = [NSColor systemGreenColor];
|
||||
redColor = [NSColor systemRedColor];
|
||||
}
|
||||
else {
|
||||
greenColor = [NSColor colorWithRed:3.0 / 16 green:0.5 blue:5.0 / 16 alpha:1.0];
|
||||
redColor = [NSColor colorWithRed:13.0 / 16 green:0.25 blue:0.25 alpha:1.0];
|
||||
}
|
||||
|
||||
|
||||
NSBitmapImageRep *colorBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:SAMPLE_COUNT
|
||||
pixelsHigh:1
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:3
|
||||
hasAlpha:false
|
||||
isPlanar:false
|
||||
colorSpaceName:NSDeviceRGBColorSpace
|
||||
bytesPerRow:SAMPLE_COUNT * 4
|
||||
bitsPerPixel:32];
|
||||
|
||||
unsigned lastFill = 0;
|
||||
NSBezierPath *line = [NSBezierPath bezierPath];
|
||||
bool isRed = false;
|
||||
{
|
||||
double sample = _samples[_position % SAMPLE_COUNT];
|
||||
[line moveToPoint:NSMakePoint(0,
|
||||
(sample * (size.height - 1) + 0.5) * factor)];
|
||||
isRed = sample == 1;
|
||||
}
|
||||
|
||||
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:colorBitmap]];
|
||||
for (unsigned i = 1; i < SAMPLE_COUNT; i++) {
|
||||
double sample = _samples[(i + _position) % SAMPLE_COUNT];
|
||||
[line lineToPoint:NSMakePoint(size.width * i * factor / (SAMPLE_COUNT - 1),
|
||||
(sample * (size.height - 1) + 0.5) * factor)];
|
||||
|
||||
if (isRed != (sample == 1)) {
|
||||
// Color changed
|
||||
[(isRed? redColor : greenColor) setFill];
|
||||
NSRectFill(CGRectMake(lastFill, 0, i - lastFill, 1));
|
||||
lastFill = i;
|
||||
|
||||
isRed ^= true;
|
||||
}
|
||||
}
|
||||
[(isRed? redColor : greenColor) setFill];
|
||||
NSRectFill(CGRectMake(lastFill, 0, SAMPLE_COUNT - lastFill, 1));
|
||||
|
||||
NSBezierPath *fill = [line copy];
|
||||
[fill lineToPoint:NSMakePoint(size.width * factor, 0)];
|
||||
[fill lineToPoint:NSMakePoint(0, 0)];
|
||||
|
||||
NSColor *strokeColor = [NSColor whiteColor];
|
||||
NSColor *fillColor = [strokeColor colorWithAlphaComponent:1 / 3.0];
|
||||
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:maskBitmap]];
|
||||
[fillColor setFill];
|
||||
[fill fill];
|
||||
|
||||
[strokeColor setStroke];
|
||||
[line setLineWidth:factor];
|
||||
[line stroke];
|
||||
|
||||
CGContextRef maskContext = CGContextRetain([NSGraphicsContext currentContext].graphicsPort);
|
||||
[NSGraphicsContext setCurrentContext:mainContext];
|
||||
CGContextSaveGState(mainContext.graphicsPort);
|
||||
|
||||
CGImageRef maskImage = CGBitmapContextCreateImage(maskContext);
|
||||
CGContextClipToMask(mainContext.graphicsPort, bounds, maskImage);
|
||||
CGImageRelease(maskImage);
|
||||
|
||||
NSImage *colors = [[NSImage alloc] initWithSize:NSMakeSize(SAMPLE_COUNT, 1)];
|
||||
[colors addRepresentation:colorBitmap];
|
||||
[colors drawInRect:bounds];
|
||||
|
||||
CGContextRestoreGState(mainContext.graphicsPort);
|
||||
CGContextRelease(maskContext);
|
||||
|
||||
|
||||
[super drawRect:dirtyRect];
|
||||
}
|
||||
|
||||
- (void)addSample:(double)sample
|
||||
{
|
||||
_samples[_position++] = sample;
|
||||
if (_position == SAMPLE_COUNT) {
|
||||
_position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
5
bsnes/gb/Cocoa/GBCenteredTextCell.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBCenteredTextCell : NSTextFieldCell
|
||||
|
||||
@end
|
29
bsnes/gb/Cocoa/GBCenteredTextCell.m
Normal file
@@ -0,0 +1,29 @@
|
||||
#import "GBCenteredTextCell.h"
|
||||
|
||||
@implementation GBCenteredTextCell
|
||||
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
|
||||
{
|
||||
double height = round([self.attributedStringValue size].height);
|
||||
cellFrame.origin.y += (cellFrame.size.height - height) / 2;
|
||||
cellFrame.size.height = height;
|
||||
[super drawInteriorWithFrame:cellFrame inView:controlView];
|
||||
}
|
||||
|
||||
|
||||
- (void)selectWithFrame:(NSRect)rect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)delegate start:(NSInteger)selStart length:(NSInteger)selLength
|
||||
{
|
||||
double height = round([self.attributedStringValue size].height);
|
||||
rect.origin.y += (rect.size.height - height) / 2;
|
||||
rect.size.height = height;
|
||||
[super selectWithFrame:rect inView:controlView editor:textObj delegate:delegate start:selStart length:selLength];
|
||||
}
|
||||
|
||||
- (void)editWithFrame:(NSRect)rect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)delegate event:(NSEvent *)event
|
||||
{
|
||||
double height = round([self.attributedStringValue size].height);
|
||||
rect.origin.y += (rect.size.height - height) / 2;
|
||||
rect.size.height = height;
|
||||
[super editWithFrame:rect inView:controlView editor:textObj delegate:delegate event:event];
|
||||
|
||||
}
|
||||
@end
|
8
bsnes/gb/Cocoa/GBCheatSearchController.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "Document.h"
|
||||
|
||||
@interface GBCheatSearchController<NSTableViewDelegate, NSTableViewDataSource, NSControlTextEditingDelegate> : NSObject
|
||||
@property IBOutlet NSWindow *window;
|
||||
@property IBOutlet NSTableView *tableView;
|
||||
+ (instancetype)controllerWithDocument:(Document *)document;
|
||||
@end
|
234
bsnes/gb/Cocoa/GBCheatSearchController.m
Normal file
@@ -0,0 +1,234 @@
|
||||
#import "GBCheatSearchController.h"
|
||||
#import "GBWarningPopover.h"
|
||||
#import "GBCheatWindowController.h"
|
||||
#import "GBPanel.h"
|
||||
|
||||
@interface GBCheatSearchController() <NSTableViewDelegate, NSTableViewDataSource>
|
||||
@property IBOutlet NSPopUpButton *dataTypeButton;
|
||||
@property IBOutlet NSPopUpButton *conditionTypeButton;
|
||||
@property IBOutlet NSTextField *operandField;
|
||||
@property IBOutlet NSTextField *conditionField;
|
||||
@property IBOutlet NSTextField *resultsLabel;
|
||||
@property (strong) IBOutlet NSButton *addCheatButton;
|
||||
@end
|
||||
|
||||
@implementation GBCheatSearchController
|
||||
{
|
||||
__weak Document *_document;
|
||||
size_t _resultCount;
|
||||
GB_cheat_search_result_t *_results;
|
||||
GBPanel *_window;
|
||||
}
|
||||
|
||||
+ (instancetype)controllerWithDocument:(Document *)document
|
||||
{
|
||||
GBCheatSearchController *ret = [[self alloc] init];
|
||||
ret->_document = document;
|
||||
NSArray *objects;
|
||||
[[NSBundle mainBundle] loadNibNamed:@"CheatSearch" owner:ret topLevelObjects:&objects];
|
||||
ret->_resultsLabel.stringValue = @"";
|
||||
ret->_resultsLabel.cell.backgroundStyle = NSBackgroundStyleRaised;
|
||||
ret->_window.ownerWindow = document.mainWindow;
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (IBAction)reset:(id)sender
|
||||
{
|
||||
_dataTypeButton.enabled = true;
|
||||
[_document performAtomicBlock:^{
|
||||
GB_cheat_search_reset(_document.gb);
|
||||
}];
|
||||
_resultCount = 0;
|
||||
if (_results) {
|
||||
free(_results);
|
||||
_results = NULL;
|
||||
}
|
||||
[_tableView reloadData];
|
||||
_resultsLabel.stringValue = @"";
|
||||
}
|
||||
|
||||
- (IBAction)search:(id)sender
|
||||
{
|
||||
// Dispatch to work around firstResponder oddities
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([sender isKindOfClass:[NSTextField class]]) {
|
||||
// Action sent by losing focus rather than pressing enter
|
||||
if (![sender currentEditor]) return;
|
||||
}
|
||||
_dataTypeButton.enabled = false;
|
||||
[_document performAtomicBlock:^{
|
||||
__block bool success = false;
|
||||
NSString *error = [_document captureOutputForBlock:^{
|
||||
success = GB_cheat_search_filter(_document.gb, _conditionField.stringValue.UTF8String, _dataTypeButton.selectedTag);
|
||||
}];
|
||||
if (!success) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[GBWarningPopover popoverWithContents:error onView:_conditionField];
|
||||
NSBeep();
|
||||
});
|
||||
return;
|
||||
}
|
||||
_resultCount = GB_cheat_search_result_count(_document.gb);
|
||||
_results = malloc(sizeof(*_results) * _resultCount);
|
||||
GB_cheat_search_get_results(_document.gb, _results);
|
||||
}];
|
||||
if (_resultCount == 0) {
|
||||
_dataTypeButton.enabled = true;
|
||||
_resultsLabel.stringValue = @"No results.";
|
||||
}
|
||||
else {
|
||||
_resultsLabel.stringValue = [NSString stringWithFormat:@"%@ result%s",
|
||||
[NSNumberFormatter localizedStringFromNumber:@(_resultCount)
|
||||
numberStyle:NSNumberFormatterDecimalStyle],
|
||||
_resultCount > 1? "s" : ""];
|
||||
}
|
||||
[_tableView reloadData];
|
||||
});
|
||||
}
|
||||
|
||||
- (IBAction)conditionChanged:(id)sender
|
||||
{
|
||||
unsigned index = [_conditionTypeButton indexOfSelectedItem];
|
||||
_conditionField.enabled = index == 11;
|
||||
_operandField.enabled = index >= 1 && index <= 6;
|
||||
switch ([_conditionTypeButton indexOfSelectedItem]) {
|
||||
case 0: _conditionField.stringValue = @"1"; break;
|
||||
case 1: _conditionField.stringValue = [NSString stringWithFormat:@"new == (%@)", _operandField.stringValue]; break;
|
||||
case 2: _conditionField.stringValue = [NSString stringWithFormat:@"new != (%@)", _operandField.stringValue]; break;
|
||||
case 3: _conditionField.stringValue = [NSString stringWithFormat:@"new > (%@)", _operandField.stringValue]; break;
|
||||
case 4: _conditionField.stringValue = [NSString stringWithFormat:@"new >= (%@)", _operandField.stringValue]; break;
|
||||
case 5: _conditionField.stringValue = [NSString stringWithFormat:@"new < (%@)", _operandField.stringValue]; break;
|
||||
case 6: _conditionField.stringValue = [NSString stringWithFormat:@"new <= (%@)", _operandField.stringValue]; break;
|
||||
case 7: _conditionField.stringValue = @"new != old"; break;
|
||||
case 8: _conditionField.stringValue = @"new == old"; break;
|
||||
case 9: _conditionField.stringValue = @"new > old"; break;
|
||||
case 10: _conditionField.stringValue = @"new < old"; break;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
return _resultCount;
|
||||
}
|
||||
|
||||
- (uint8_t *)addressForRow:(unsigned)row
|
||||
{
|
||||
uint8_t *base;
|
||||
uint32_t offset;
|
||||
if (_results[row].addr < 0xc000) {
|
||||
base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_CART_RAM, NULL, NULL);
|
||||
offset = (_results[row].addr & 0x1FFF) + _results[row].bank * 0x2000;
|
||||
}
|
||||
else if (_results[row].addr < 0xe000) {
|
||||
base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_RAM, NULL, NULL);
|
||||
offset = (_results[row].addr & 0xFFF) + _results[row].bank * 0x1000;
|
||||
}
|
||||
else {
|
||||
base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_HRAM, NULL, NULL);
|
||||
offset = (_results[row].addr & 0x7F);
|
||||
}
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
switch ([[tableView tableColumns] indexOfObject:tableColumn]) {
|
||||
case 0:
|
||||
return [NSString stringWithFormat:@"$%02x:$%04x", _results[row].bank, _results[row].addr];
|
||||
case 1:
|
||||
if (_dataTypeButton.selectedTag & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) {
|
||||
return [NSString stringWithFormat:@"$%04x", _results[row].value];
|
||||
}
|
||||
return [NSString stringWithFormat:@"$%02x", _results[row].value];
|
||||
default: {
|
||||
const uint8_t *data = [self addressForRow:row];
|
||||
GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag;
|
||||
uint16_t value = data[0];
|
||||
if (!(dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)) {
|
||||
return [NSString stringWithFormat:@"$%02x", value];
|
||||
}
|
||||
value |= data[1] << 8;
|
||||
if ((dataType & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT)) {
|
||||
value = __builtin_bswap16(value);
|
||||
}
|
||||
return [NSString stringWithFormat:@"$%04x", value];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView setObjectValue:(NSString *)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
[_document performAtomicBlock:^{
|
||||
__block bool success = false;
|
||||
__block uint16_t value;
|
||||
NSString *error = [_document captureOutputForBlock:^{
|
||||
success = !GB_debugger_evaluate(_document.gb, object.UTF8String, &value, NULL);
|
||||
}];
|
||||
if (!success) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[GBWarningPopover popoverWithContents:error onView:tableView];
|
||||
NSBeep();
|
||||
});
|
||||
return;
|
||||
}
|
||||
uint8_t *dest = [self addressForRow:row];
|
||||
GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag;
|
||||
if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT) {
|
||||
value = __builtin_bswap16(value);
|
||||
}
|
||||
dest[0] = value;
|
||||
if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) {
|
||||
dest[1] = value >> 8;
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[tableView reloadData];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)controlTextDidChange:(NSNotification *)obj
|
||||
{
|
||||
[self conditionChanged:nil];
|
||||
}
|
||||
|
||||
- (IBAction)addCheat:(id)sender
|
||||
{
|
||||
GB_cheat_search_result_t *result = _results + _tableView.selectedRow;
|
||||
uint8_t *data = [self addressForRow:_tableView.selectedRow];
|
||||
GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag;
|
||||
size_t rowToSelect = 0;
|
||||
GB_get_cheats(_document.gb, &rowToSelect);
|
||||
[_document performAtomicBlock:^{
|
||||
GB_add_cheat(_document.gb,
|
||||
(dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)? "New Cheat (Part 1)" : "New Cheat",
|
||||
result->addr, result->bank,
|
||||
*data,
|
||||
0, false,
|
||||
true);
|
||||
if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) {
|
||||
GB_add_cheat(_document.gb,
|
||||
(dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)? "New Cheat (Part 2)" : "New Cheat",
|
||||
result->addr + 1, result->bank,
|
||||
data[1],
|
||||
0, false,
|
||||
true);
|
||||
}
|
||||
GB_set_cheats_enabled(_document.gb, true);
|
||||
}];
|
||||
[_document.cheatsWindow makeKeyAndOrderFront:nil];
|
||||
[_document.cheatWindowController.cheatsTable reloadData];
|
||||
[_document.cheatWindowController.cheatsTable selectRow:rowToSelect byExtendingSelection:false];
|
||||
[_document.cheatWindowController.cheatsTable.delegate tableViewSelectionDidChange:nil];
|
||||
}
|
||||
|
||||
- (void)tableViewSelectionDidChange:(NSNotification *)notification
|
||||
{
|
||||
_addCheatButton.enabled = _tableView.numberOfSelectedRows != 0;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_results) free(_results);
|
||||
}
|
||||
|
||||
@end
|
5
bsnes/gb/Cocoa/GBCheatTextFieldCell.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBCheatTextFieldCell : NSTextFieldCell
|
||||
@property (nonatomic) bool usesAddressFormat;
|
||||
@end
|
123
bsnes/gb/Cocoa/GBCheatTextFieldCell.m
Normal file
@@ -0,0 +1,123 @@
|
||||
#import "GBCheatTextFieldCell.h"
|
||||
|
||||
@interface GBCheatTextView : NSTextView
|
||||
@property bool usesAddressFormat;
|
||||
@end
|
||||
|
||||
@implementation GBCheatTextView
|
||||
|
||||
- (bool)_internalInsertText:(NSString *)string replacementRange:(NSRange)range
|
||||
{
|
||||
if (range.location == NSNotFound) {
|
||||
range = self.selectedRange;
|
||||
}
|
||||
|
||||
NSString *new = [self.string stringByReplacingCharactersInRange:range withString:string];
|
||||
if (!self.usesAddressFormat) {
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\$[0-9A-Fa-f]{1,2}|[0-9]{1,3})$" options:0 error:NULL];
|
||||
if ([regex numberOfMatchesInString:new options:0 range:NSMakeRange(0, new.length)]) {
|
||||
[super insertText:string replacementRange:range];
|
||||
return true;
|
||||
}
|
||||
if ([regex numberOfMatchesInString:[@"$" stringByAppendingString:new] options:0 range:NSMakeRange(0, new.length + 1)]) {
|
||||
[super insertText:string replacementRange:range];
|
||||
[super insertText:@"$" replacementRange:NSMakeRange(0, 0)];
|
||||
return true;
|
||||
}
|
||||
if ([new isEqualToString:@"$"] || [string length] == 0) {
|
||||
self.string = @"$00";
|
||||
self.selectedRange = NSMakeRange(1, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\$[0-9A-Fa-f]{1,3}:)?\\$[0-9a-fA-F]{1,4}$" options:0 error:NULL];
|
||||
if ([regex numberOfMatchesInString:new options:0 range:NSMakeRange(0, new.length)]) {
|
||||
[super insertText:string replacementRange:range];
|
||||
return true;
|
||||
}
|
||||
if ([string length] == 0) {
|
||||
NSUInteger index = [new rangeOfString:@":"].location;
|
||||
if (index != NSNotFound) {
|
||||
if (range.location > index) {
|
||||
self.string = [[new componentsSeparatedByString:@":"] firstObject];
|
||||
self.selectedRange = NSMakeRange(self.string.length, 0);
|
||||
return true;
|
||||
}
|
||||
self.string = [[new componentsSeparatedByString:@":"] lastObject];
|
||||
self.selectedRange = NSMakeRange(0, 0);
|
||||
return true;
|
||||
}
|
||||
else if ([[self.string substringWithRange:range] isEqualToString:@":"]) {
|
||||
self.string = [[self.string componentsSeparatedByString:@":"] lastObject];
|
||||
self.selectedRange = NSMakeRange(0, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([new isEqualToString:@"$"] || [string length] == 0) {
|
||||
self.string = @"$0000";
|
||||
self.selectedRange = NSMakeRange(1, 4);
|
||||
return true;
|
||||
}
|
||||
if (([string isEqualToString:@"$"] || [string isEqualToString:@":"]) && range.length == 0 && range.location == 0) {
|
||||
if ([self _internalInsertText:@"$00:" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(1, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([string isEqualToString:@":"] && range.length + range.location == self.string.length) {
|
||||
if ([self _internalInsertText:@":$0" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(self.string.length - 2, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([string isEqualToString:@"$"]) {
|
||||
if ([self _internalInsertText:@"$0" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(range.location + 1, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
- (NSUndoManager *)undoManager
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if (![self _internalInsertText:string replacementRange:replacementRange]) {
|
||||
if (![self _internalInsertText:[@"$" stringByAppendingString:string] replacementRange:replacementRange]) {
|
||||
NSBeep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Private API, don't tell the police! */
|
||||
- (void)_userReplaceRange:(NSRange)range withString:(NSString *)string
|
||||
{
|
||||
[self insertText:string replacementRange:range];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GBCheatTextFieldCell
|
||||
{
|
||||
bool _drawing, _editing;
|
||||
GBCheatTextView *_fieldEditor;
|
||||
}
|
||||
|
||||
- (NSTextView *)fieldEditorForView:(NSView *)controlView
|
||||
{
|
||||
if (_fieldEditor) {
|
||||
_fieldEditor.usesAddressFormat = self.usesAddressFormat;
|
||||
return _fieldEditor;
|
||||
}
|
||||
_fieldEditor = [[GBCheatTextView alloc] initWithFrame:controlView.frame];
|
||||
_fieldEditor.fieldEditor = true;
|
||||
_fieldEditor.usesAddressFormat = self.usesAddressFormat;
|
||||
return _fieldEditor;
|
||||
}
|
||||
@end
|
16
bsnes/gb/Cocoa/GBCheatWindowController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "Document.h"
|
||||
|
||||
@interface GBCheatWindowController : NSObject <NSTableViewDelegate, NSTableViewDataSource, NSTextFieldDelegate>
|
||||
@property (nonatomic, weak) IBOutlet NSTableView *cheatsTable;
|
||||
@property (nonatomic, weak) IBOutlet NSTextField *addressField;
|
||||
@property (nonatomic, weak) IBOutlet NSTextField *valueField;
|
||||
@property (nonatomic, weak) IBOutlet NSTextField *oldValueField;
|
||||
@property (nonatomic, weak) IBOutlet NSButton *oldValueCheckbox;
|
||||
@property (nonatomic, weak) IBOutlet NSTextField *descriptionField;
|
||||
@property (nonatomic, weak) IBOutlet NSTextField *importCodeField;
|
||||
@property (nonatomic, weak) IBOutlet NSTextField *importDescriptionField;
|
||||
@property (nonatomic, weak) IBOutlet Document *document;
|
||||
- (void)cheatsUpdated;
|
||||
@end
|
244
bsnes/gb/Cocoa/GBCheatWindowController.m
Normal file
@@ -0,0 +1,244 @@
|
||||
#import "GBCheatWindowController.h"
|
||||
#import "GBWarningPopover.h"
|
||||
#import "GBCheatTextFieldCell.h"
|
||||
|
||||
@implementation GBCheatWindowController
|
||||
|
||||
+ (NSString *)addressStringFromCheat:(const GB_cheat_t *)cheat
|
||||
{
|
||||
if (cheat->bank != GB_CHEAT_ANY_BANK) {
|
||||
return [NSString stringWithFormat:@"$%x:$%04x", cheat->bank, cheat->address];
|
||||
}
|
||||
return [NSString stringWithFormat:@"$%04x", cheat->address];
|
||||
}
|
||||
|
||||
+ (NSString *)actionDescriptionForCheat:(const GB_cheat_t *)cheat
|
||||
{
|
||||
if (cheat->use_old_value) {
|
||||
return [NSString stringWithFormat:@"[%@]($%02x) = $%02x", [self addressStringFromCheat:cheat], cheat->old_value, cheat->value];
|
||||
}
|
||||
return [NSString stringWithFormat:@"[%@] = $%02x", [self addressStringFromCheat:cheat], cheat->value];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return 0;
|
||||
size_t cheatCount;
|
||||
GB_get_cheats(gb, &cheatCount);
|
||||
return cheatCount + 1;
|
||||
}
|
||||
|
||||
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return nil;
|
||||
size_t cheatCount;
|
||||
GB_get_cheats(gb, &cheatCount);
|
||||
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
if (row >= cheatCount && columnIndex == 0) {
|
||||
return [[NSCell alloc] init];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
size_t cheatCount;
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return nil;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
if (row >= cheatCount) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return @YES;
|
||||
|
||||
case 1:
|
||||
return @NO;
|
||||
|
||||
case 2:
|
||||
return @"Add Cheat…";
|
||||
|
||||
case 3:
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return @NO;
|
||||
|
||||
case 1:
|
||||
return @(cheats[row]->enabled);
|
||||
|
||||
case 2:
|
||||
return @(cheats[row]->description);
|
||||
|
||||
case 3:
|
||||
return [GBCheatWindowController actionDescriptionForCheat:cheats[row]];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (IBAction)importCheat:(id)sender
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
|
||||
[self.document performAtomicBlock:^{
|
||||
if (GB_import_cheat(gb,
|
||||
self.importCodeField.stringValue.UTF8String,
|
||||
self.importDescriptionField.stringValue.UTF8String,
|
||||
true)) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.importCodeField.stringValue = @"";
|
||||
self.importDescriptionField.stringValue = @"";
|
||||
[self.cheatsTable reloadData];
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
});
|
||||
}
|
||||
else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSBeep();
|
||||
[GBWarningPopover popoverWithContents:@"This code is not a valid GameShark or Game Genie code" onView:self.importCodeField];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
size_t cheatCount;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
[self.document performAtomicBlock:^{
|
||||
if (columnIndex == 1) {
|
||||
if (row >= cheatCount) {
|
||||
GB_add_cheat(gb, "New Cheat", 0, 0, 0, 0, false, true);
|
||||
}
|
||||
else {
|
||||
GB_update_cheat(gb, cheats[row], cheats[row]->description, cheats[row]->address, cheats[row]->bank, cheats[row]->value, cheats[row]->old_value, cheats[row]->use_old_value, !cheats[row]->enabled);
|
||||
}
|
||||
}
|
||||
else if (row < cheatCount) {
|
||||
GB_remove_cheat(gb, cheats[row]);
|
||||
}
|
||||
}];
|
||||
[self.cheatsTable reloadData];
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
}
|
||||
|
||||
- (void)tableViewSelectionDidChange:(NSNotification *)notification
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
|
||||
size_t cheatCount;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
unsigned row = self.cheatsTable.selectedRow;
|
||||
const GB_cheat_t *cheat = NULL;
|
||||
if (row >= cheatCount) {
|
||||
static const GB_cheat_t template = {
|
||||
.address = 0,
|
||||
.bank = 0,
|
||||
.value = 0,
|
||||
.old_value = 0,
|
||||
.use_old_value = false,
|
||||
.enabled = false,
|
||||
.description = "New Cheat",
|
||||
};
|
||||
cheat = &template;
|
||||
}
|
||||
else {
|
||||
cheat = cheats[row];
|
||||
}
|
||||
|
||||
self.addressField.stringValue = [GBCheatWindowController addressStringFromCheat:cheat];
|
||||
self.valueField.stringValue = [NSString stringWithFormat:@"$%02x", cheat->value];
|
||||
self.oldValueField.stringValue = [NSString stringWithFormat:@"$%02x", cheat->old_value];
|
||||
self.oldValueCheckbox.state = cheat->use_old_value;
|
||||
self.descriptionField.stringValue = @(cheat->description);
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
((GBCheatTextFieldCell *)self.addressField.cell).usesAddressFormat = true;
|
||||
}
|
||||
|
||||
- (void)controlTextDidChange:(NSNotification *)obj
|
||||
{
|
||||
[self updateCheat:nil];
|
||||
}
|
||||
|
||||
- (IBAction)updateCheat:(id)sender
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
|
||||
uint16_t address = 0;
|
||||
uint16_t bank = GB_CHEAT_ANY_BANK;
|
||||
if ([self.addressField.stringValue rangeOfString:@":"].location != NSNotFound) {
|
||||
sscanf(self.addressField.stringValue.UTF8String, "$%hx:$%hx", &bank, &address);
|
||||
}
|
||||
else {
|
||||
sscanf(self.addressField.stringValue.UTF8String, "$%hx", &address);
|
||||
}
|
||||
|
||||
uint8_t value = 0;
|
||||
if ([self.valueField.stringValue characterAtIndex:0] == '$') {
|
||||
sscanf(self.valueField.stringValue.UTF8String, "$%02hhx", &value);
|
||||
}
|
||||
else {
|
||||
sscanf(self.valueField.stringValue.UTF8String, "%hhd", &value);
|
||||
}
|
||||
|
||||
uint8_t oldValue = 0;
|
||||
if ([self.oldValueField.stringValue characterAtIndex:0] == '$') {
|
||||
sscanf(self.oldValueField.stringValue.UTF8String, "$%02hhx", &oldValue);
|
||||
}
|
||||
else {
|
||||
sscanf(self.oldValueField.stringValue.UTF8String, "%hhd", &oldValue);
|
||||
}
|
||||
|
||||
size_t cheatCount;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
unsigned row = self.cheatsTable.selectedRow;
|
||||
|
||||
[self.document performAtomicBlock:^{
|
||||
if (row >= cheatCount) {
|
||||
GB_add_cheat(gb,
|
||||
self.descriptionField.stringValue.UTF8String,
|
||||
address,
|
||||
bank,
|
||||
value,
|
||||
oldValue,
|
||||
self.oldValueCheckbox.state,
|
||||
false);
|
||||
}
|
||||
else {
|
||||
GB_update_cheat(gb,
|
||||
cheats[row],
|
||||
self.descriptionField.stringValue.UTF8String,
|
||||
address,
|
||||
bank,
|
||||
value,
|
||||
oldValue,
|
||||
self.oldValueCheckbox.state,
|
||||
cheats[row]->enabled);
|
||||
}
|
||||
}];
|
||||
[self.cheatsTable reloadData];
|
||||
}
|
||||
|
||||
- (void)cheatsUpdated
|
||||
{
|
||||
[self.cheatsTable reloadData];
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
}
|
||||
|
||||
@end
|
5
bsnes/gb/Cocoa/GBColorTextCell.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBColorTextCell : NSTextFieldCell
|
||||
|
||||
@end
|