Compare commits
723
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4652dc5c4a | ||
|
|
357e6c86f1 | ||
|
|
67963389ef | ||
|
|
4009bb8a84 | ||
|
|
8fb6d94000 | ||
|
|
8d3685415d | ||
|
|
50b38b856f | ||
|
|
dad88caf01 | ||
|
|
699659d4bf | ||
|
|
21e7d24ed3 | ||
|
|
1cdb7be810 | ||
|
|
09314f1fd3 | ||
|
|
e7b90271ca | ||
|
|
95f10ed733 | ||
|
|
d51de976b1 | ||
|
|
8acd433ec6 | ||
|
|
b9c8afbbc1 | ||
|
|
7d5f528e1a | ||
|
|
786a4254d2 | ||
|
|
09ac50f2d5 | ||
|
|
2dc3c0cbe4 | ||
|
|
4c2a70bab6 | ||
|
|
46f76597fc | ||
|
|
b23640222c | ||
|
|
3f6862908e | ||
|
|
0934cce225 | ||
|
|
7c50fcc79e | ||
|
|
0f4ab63101 | ||
|
|
8b2f38307b | ||
|
|
3863d5a4ed | ||
|
|
94574c485a | ||
|
|
f857926ec3 | ||
|
|
adf4cccd4a | ||
|
|
bf8e194685 | ||
|
|
a2e508208c | ||
|
|
f5888609a8 | ||
|
|
c6cd72c528 | ||
|
|
82e0c053d0 | ||
|
|
3b29227dbc | ||
|
|
079bb35b1f | ||
|
|
95051b6525 | ||
|
|
ce2f93d234 | ||
|
|
13a171f199 | ||
|
|
3da352488e | ||
|
|
2386047c2f | ||
|
|
baa550037a | ||
|
|
ec3ca1a055 | ||
|
|
da77f60b71 | ||
|
|
0c1998abe4 | ||
|
|
64260623bf | ||
|
|
b53447bed5 | ||
|
|
4959a58de3 | ||
|
|
9141ff453b | ||
|
|
f955ab984c | ||
|
|
435b9ce9aa | ||
|
|
1ec7528dac | ||
|
|
e7822aad8e | ||
|
|
8140e83e46 | ||
|
|
cc0899290e | ||
|
|
3012139028 | ||
|
|
c590b87cff | ||
|
|
5cabd026ae | ||
|
|
7ccd938f9b | ||
|
|
88a210e82e | ||
|
|
74e619df37 | ||
|
|
10a97b9c63 | ||
|
|
159043803c | ||
|
|
bd2fbfcb67 | ||
|
|
64600826b7 | ||
|
|
80deb4bbbd | ||
|
|
00c8bb8ce6 | ||
|
|
09ed8b948c | ||
|
|
e2daefbb6a | ||
|
|
39bf17aafe | ||
|
|
4836cd94ab | ||
|
|
9d41ca2515 | ||
|
|
18421ffbfe | ||
|
|
3f0921d983 | ||
|
|
ed7318c270 | ||
|
|
623e1e3998 | ||
|
|
558e3d0cb3 | ||
|
|
d0db547dd0 | ||
|
|
be4bb00390 | ||
|
|
a8cc85531c | ||
|
|
2dea0d27bf | ||
|
|
61a0220c1a | ||
|
|
c080bbe301 | ||
|
|
e1d1b39567 | ||
|
|
2aae8ad9ca | ||
|
|
1b6d1af951 | ||
|
|
5c3617c05f | ||
|
|
a9a943fbfe | ||
|
|
b094a9e352 | ||
|
|
4bd18afb12 | ||
|
|
0b24e703a1 | ||
|
|
1a1be7a393 | ||
|
|
a2d8f60d12 | ||
|
|
5d25fdb035 | ||
|
|
c255e3a1db | ||
|
|
d7c144646f | ||
|
|
27077aa21f | ||
|
|
632dcf7b41 | ||
|
|
a25bbdc9c9 | ||
|
|
47d886306e | ||
|
|
edda658fa4 | ||
|
|
1ab20f1b56 | ||
|
|
0e9093a74b | ||
|
|
f52eaea76c | ||
|
|
c3fcf2f417 | ||
|
|
8d04eba21d | ||
|
|
8d42c0ce77 | ||
|
|
829503568e | ||
|
|
746fdb5409 | ||
|
|
67da892fe9 | ||
|
|
dc191487e0 | ||
|
|
5c0c405800 | ||
|
|
60166e6ba1 | ||
|
|
cb0b59600a | ||
|
|
b9f3be4df2 | ||
|
|
cf86fbd238 | ||
|
|
3fdb369128 | ||
|
|
db7defff5a | ||
|
|
451cbec0b9 | ||
|
|
5c69e295ab | ||
|
|
5065a92d55 | ||
|
|
5483e8e2c0 | ||
|
|
e8949a2612 | ||
|
|
db71a0b24d | ||
|
|
d3d5422768 | ||
|
|
5185f753e5 | ||
|
|
eb897d0f1b | ||
|
|
50fc80a1c3 | ||
|
|
301e15c44d | ||
|
|
b6f886a7c5 | ||
|
|
0b085286d3 | ||
|
|
29d3d9bb52 | ||
|
|
bf05a3ef30 | ||
|
|
6280ac3b0a | ||
|
|
cc9df27569 | ||
|
|
ac51acdafe | ||
|
|
6fec169347 | ||
|
|
4af006e869 | ||
|
|
256ef4d341 | ||
|
|
698f2ffc2c | ||
|
|
4879a35eb8 | ||
|
|
fd7e850789 | ||
|
|
0cf07c38da | ||
|
|
1f073b2d75 | ||
|
|
3037214932 | ||
|
|
18d6d9783a | ||
|
|
267add3227 | ||
|
|
a170627f52 | ||
|
|
5c244eaca7 | ||
|
|
6bcadccf09 | ||
|
|
ccb3bac48c | ||
|
|
0a7ecf82a9 | ||
|
|
1c6929dd84 | ||
|
|
1d3d9040f2 | ||
|
|
8f1069628e | ||
|
|
f8c585a9d1 | ||
|
|
9651051990 | ||
|
|
a54a62d0d7 | ||
|
|
100caa0f5c | ||
|
|
bb87aa2944 | ||
|
|
2e2968d1bc | ||
|
|
0457262472 | ||
|
|
f23c359114 | ||
|
|
81e74dcb97 | ||
|
|
8ead941c6c | ||
|
|
ece03cabba | ||
|
|
4b7f68f920 | ||
|
|
2dae86a6f2 | ||
|
|
85058c2156 | ||
|
|
ea2f4c5572 | ||
|
|
48033816a8 | ||
|
|
b517ef3182 | ||
|
|
6fef16353e | ||
|
|
84ea3f9e8e | ||
|
|
6bb6b0a301 | ||
|
|
465d6c6c18 | ||
|
|
ef384e85dd | ||
|
|
7ee04879e2 | ||
|
|
4c73200f58 | ||
|
|
31aabe9786 | ||
|
|
4ea55a61b8 | ||
|
|
0209b80a22 | ||
|
|
0511dfb6ca | ||
|
|
b558df3340 | ||
|
|
89602cfcab | ||
|
|
b4557993c9 | ||
|
|
f119d7c988 | ||
|
|
b3d8d0aea9 | ||
|
|
a977cba772 | ||
|
|
489d40d87d | ||
|
|
3a468a9a3b | ||
|
|
a2e220d3f4 | ||
|
|
febc02b50b | ||
|
|
311404f56b | ||
|
|
d929cdf7c8 | ||
|
|
2b930ad95f | ||
|
|
3c60f3966b | ||
|
|
c59d399ab8 | ||
|
|
f69e40fa26 | ||
|
|
e9dcc5717e | ||
|
|
5bec3d5db7 | ||
|
|
6ec2b47345 | ||
|
|
ebda16beae | ||
|
|
c29a26f183 | ||
|
|
2014e9cf75 | ||
|
|
33f2e1d4b7 | ||
|
|
eb037542b4 | ||
|
|
039b42ad53 | ||
|
|
33b4718744 | ||
|
|
71ba9b6b47 | ||
|
|
1957917270 | ||
|
|
b9ccddf47d | ||
|
|
cd0ba51b5a | ||
|
|
1f23d88c7a | ||
|
|
46e43ab09c | ||
|
|
96950b6b4e | ||
|
|
5f94ef4478 | ||
|
|
c4193eddc5 | ||
|
|
c8962a0e77 | ||
|
|
b6a749e5db | ||
|
|
7dbbe9809e | ||
|
|
79a3e32d5d | ||
|
|
c5a4e954f9 | ||
|
|
7b862768b0 | ||
|
|
af8d8dae9f | ||
|
|
d9d5823fdb | ||
|
|
82dda33800 | ||
|
|
3876e38636 | ||
|
|
6bc1357d6a | ||
|
|
37218e7fe0 | ||
|
|
678e11eade | ||
|
|
f72313fe45 | ||
|
|
06374ef78a | ||
|
|
bdde1ec6b8 | ||
|
|
d2176fe4f0 | ||
|
|
fb9eef904a | ||
|
|
48903998a5 | ||
|
|
f2dca0265f | ||
|
|
1147ed9858 | ||
|
|
19d93f4ffd | ||
|
|
15bfffa1d3 | ||
|
|
18a9a47c33 | ||
|
|
6838e69ebe | ||
|
|
26b3b64794 | ||
|
|
aadd2bdd59 | ||
|
|
d0e24e31ca | ||
|
|
4fb7f20c7b | ||
|
|
6ddae70c5a | ||
|
|
b38160d6c2 | ||
|
|
231c998cc0 | ||
|
|
127d31a85c | ||
|
|
a8419bbaa0 | ||
|
|
0fc430ceb3 | ||
|
|
e59a50b64c | ||
|
|
2042b629e9 | ||
|
|
440b9ed749 | ||
|
|
9936088286 | ||
|
|
4d8a6c1952 | ||
|
|
af69cf9251 | ||
|
|
1d5550b1e8 | ||
|
|
ec3f6639b7 | ||
|
|
727b99effd | ||
|
|
8afff3aaca | ||
|
|
b281517429 | ||
|
|
54ec9f272e | ||
|
|
a159691097 | ||
|
|
ca70f7b19c | ||
|
|
7b4227d2a9 | ||
|
|
f89efa2558 | ||
|
|
6f4824b648 | ||
|
|
45debeb5c9 | ||
|
|
a01f452eba | ||
|
|
e452734bc1 | ||
|
|
d1779b93fa | ||
|
|
fe9aac7e29 | ||
|
|
f3d887ebcf | ||
|
|
336500c8ae | ||
|
|
ee3fa58bfa | ||
|
|
a4c3eddc2f | ||
|
|
e0f6cb2cbd | ||
|
|
1ad6a9412e | ||
|
|
5af3e0d494 | ||
|
|
b1ee828457 | ||
|
|
0d60649715 | ||
|
|
220b27159b | ||
|
|
b06a0a7d47 | ||
|
|
d66af8e16b | ||
|
|
ad366ecdd0 | ||
|
|
22cb4d689c | ||
|
|
b38ea463aa | ||
|
|
056d1b2d90 | ||
|
|
37693916d9 | ||
|
|
889e8b43eb | ||
|
|
9db2db2340 | ||
|
|
1bb612f3c9 | ||
|
|
e886ab77af | ||
|
|
fbb3c1d4c3 | ||
|
|
73a69b2e8f | ||
|
|
63a0acac24 | ||
|
|
75ba49ff4a | ||
|
|
b31ddb1ffc | ||
|
|
458a1495c8 | ||
|
|
eb029faf2e | ||
|
|
d65eb6ed4f | ||
|
|
97ec2e5d37 | ||
|
|
97d65b137a | ||
|
|
a9f0e86aa3 | ||
|
|
88679b7cb2 | ||
|
|
9ec62a61ac | ||
|
|
44befb7e9a | ||
|
|
be388f7b49 | ||
|
|
34ef034345 | ||
|
|
ba4623b009 | ||
|
|
a0a7b86508 | ||
|
|
6d7927927c | ||
|
|
837c8a46d6 | ||
|
|
22aeb64ff9 | ||
|
|
e4b08064b7 | ||
|
|
1e6b4c16cc | ||
|
|
d6eb8f7125 | ||
|
|
dc6850e479 | ||
|
|
2d623e179b | ||
|
|
884d665c1c | ||
|
|
2842fe7ec6 | ||
|
|
954e6022d9 | ||
|
|
955c50a9f3 | ||
|
|
dc82c980b1 | ||
|
|
408ed17521 | ||
|
|
f4050e9adb | ||
|
|
badae01357 | ||
|
|
38d9939eb7 | ||
|
|
f5a3caf536 | ||
|
|
027445afb1 | ||
|
|
63a3900b79 | ||
|
|
f542a78347 | ||
|
|
4d32dde83e | ||
|
|
927170ce73 | ||
|
|
875a0f0765 | ||
|
|
3ad88ef15c | ||
|
|
7a6cadb176 | ||
|
|
4feca23240 | ||
|
|
2e52bebd3d | ||
|
|
aa218d5be7 | ||
|
|
94f009991a | ||
|
|
c3b9ce3fdc | ||
|
|
1517cf9a7c | ||
|
|
f0f46296f2 | ||
|
|
1d1981fcde | ||
|
|
2f538fe2e4 | ||
|
|
8e01b2e5c8 | ||
|
|
cd14ca800e | ||
|
|
cb59fe14e9 | ||
|
|
9fd9290cd3 | ||
|
|
1dd99aac74 | ||
|
|
9e376f373e | ||
|
|
d4e51b77d1 | ||
|
|
61181836b0 | ||
|
|
4e26c8afa5 | ||
|
|
7684028f99 | ||
|
|
1d6be8fe4b | ||
|
|
c70cf40af3 | ||
|
|
5715d4e605 | ||
|
|
821a705a7d | ||
|
|
86f2a1fd39 | ||
|
|
86f218329a | ||
|
|
66094de38a | ||
|
|
c00cff2afd | ||
|
|
b2cc8d404c | ||
|
|
a0a04ab62f | ||
|
|
a3a59e689e | ||
|
|
a6f29d6a5a | ||
|
|
9be618d791 | ||
|
|
6bf7ae9074 | ||
|
|
e3d63c65c1 | ||
|
|
5d2a9fa1cf | ||
|
|
0078b72b03 | ||
|
|
b1ee37a066 | ||
|
|
ebf6382e7f | ||
|
|
8e23ef224a | ||
|
|
6706ffc321 | ||
|
|
e755b06e35 | ||
|
|
9ef22712c0 | ||
|
|
7b903d35e2 | ||
|
|
7f281a50c5 | ||
|
|
1354d63b85 | ||
|
|
e745cdcac8 | ||
|
|
bf7666939a | ||
|
|
7e89037db3 | ||
|
|
6ffaa77f58 | ||
|
|
7a1f46d1be | ||
|
|
cf59ae5f89 | ||
|
|
9c06dd36a0 | ||
|
|
d5d082ec37 | ||
|
|
17723d290a | ||
|
|
8de7e5a9e4 | ||
|
|
b8e99e75e5 | ||
|
|
46dc22dd63 | ||
|
|
69d78e0a87 | ||
|
|
ab3d41432a | ||
|
|
73e10cac0c | ||
|
|
c6242233a7 | ||
|
|
6b8335780f | ||
|
|
21f469b260 | ||
|
|
07a0df5fdc | ||
|
|
d4f1768bbd | ||
|
|
96e7e4949f | ||
|
|
24d3062c66 | ||
|
|
6cd212aac2 | ||
|
|
064031bc12 | ||
|
|
4c8d4ebab6 | ||
|
|
462a07680b | ||
|
|
081def30db | ||
|
|
6776b08bce | ||
|
|
6cb507f4fa | ||
|
|
de05af052f | ||
|
|
c767918729 | ||
|
|
fbc8bc2502 | ||
|
|
c38f42cb19 | ||
|
|
42d8bbc92f | ||
|
|
a09905792d | ||
|
|
f113eb4f52 | ||
|
|
f726748ebe | ||
|
|
371c957025 | ||
|
|
83aa907b13 | ||
|
|
71b144918c | ||
|
|
e618a05b08 | ||
|
|
d0f3ffd12f | ||
|
|
6d18d6a496 | ||
|
|
b0810558a7 | ||
|
|
6ae2e4003c | ||
|
|
8545f1cbdc | ||
|
|
e0530fedad | ||
|
|
b220cbf336 | ||
|
|
f68a3439d3 | ||
|
|
6f58d9ab68 | ||
|
|
c3428236f8 | ||
|
|
6856a0950c | ||
|
|
dc7d8515d3 | ||
|
|
e100093ead | ||
|
|
e5808257ca | ||
|
|
283ec3960a | ||
|
|
0ec37ac6ea | ||
|
|
0ef0b84308 | ||
|
|
62c30d8895 | ||
|
|
4e86cb16a2 | ||
|
|
76f401de95 | ||
|
|
5947779502 | ||
|
|
61c97ccaab | ||
|
|
12d6a88c60 | ||
|
|
984b41a1ae | ||
|
|
d06b8bd731 | ||
|
|
0dad96b876 | ||
|
|
def296095b | ||
|
|
750b1fea80 | ||
|
|
4c87078807 | ||
|
|
052698afa3 | ||
|
|
9e2b04d5db | ||
|
|
5641e06a19 | ||
|
|
88ec6dbcee | ||
|
|
1b614c94a7 | ||
|
|
37c5913f69 | ||
|
|
2eca668593 | ||
|
|
aec1da9d16 | ||
|
|
548b441f1f | ||
|
|
98bc285d98 | ||
|
|
553c180bee | ||
|
|
537252440e | ||
|
|
13a0877d38 | ||
|
|
50691b79f1 | ||
|
|
ad229dabdb | ||
|
|
bdff33a420 | ||
|
|
4b21821aa4 | ||
|
|
6b47b5db50 | ||
|
|
a10ca5236b | ||
|
|
be2dab9a1a | ||
|
|
02711cdee1 | ||
|
|
c6b10402f4 | ||
|
|
58ea6ce17e | ||
|
|
8cc00c371a | ||
|
|
8e2985d8d0 | ||
|
|
8d3b15641f | ||
|
|
033e9f926a | ||
|
|
da58503b47 | ||
|
|
cffee2b7f8 | ||
|
|
32801319fa | ||
|
|
afbe013811 | ||
|
|
862e4717f6 | ||
|
|
d3fa27ae4a | ||
|
|
b487cf2bcf | ||
|
|
0fc3aa5818 | ||
|
|
276874f882 | ||
|
|
1fdd270480 | ||
|
|
07cb6048a0 | ||
|
|
61d79f76b2 | ||
|
|
7335d07e30 | ||
|
|
9f99b71112 | ||
|
|
5c3921a99c | ||
|
|
9fc397b8bc | ||
|
|
ddc8061268 | ||
|
|
c0698a3872 | ||
|
|
1ed3521091 | ||
|
|
0dda920448 | ||
|
|
5f7580b69e | ||
|
|
3ef1b3ecaa | ||
|
|
931811da14 | ||
|
|
7624ded512 | ||
|
|
a5252939dd | ||
|
|
808ac0c557 | ||
|
|
4e138b244e | ||
|
|
3fcd1bdbc9 | ||
|
|
f857e63d5d | ||
|
|
b462c838f6 | ||
|
|
4d658bf273 | ||
|
|
67721c416b | ||
|
|
0b5f7787be | ||
|
|
a554c8f923 | ||
|
|
6592191624 | ||
|
|
164592b16d | ||
|
|
81f879e7ff | ||
|
|
1af8b3de61 | ||
|
|
c33fef606f | ||
|
|
a9fc6ef1b2 | ||
|
|
d530bfcd65 | ||
|
|
c96f4330d2 | ||
|
|
26a2a0f481 | ||
|
|
11b9790e6c | ||
|
|
1dfcf8c087 | ||
|
|
5c7ad0d51e | ||
|
|
587ae86341 | ||
|
|
926f2ef2a0 | ||
|
|
d262e02f8c | ||
|
|
f6b63473a0 | ||
|
|
1ad45edd6e | ||
|
|
e79de3b117 | ||
|
|
f783a5a1cd | ||
|
|
7848d5c237 | ||
|
|
cec735a81b | ||
|
|
753702e32e | ||
|
|
7bd7503951 | ||
|
|
d0c38956bf | ||
|
|
77bca2baee | ||
|
|
46e8c8a5a5 | ||
|
|
4d58e5d080 | ||
|
|
168084d672 | ||
|
|
740ed90d95 | ||
|
|
61c17f15b4 | ||
|
|
99035f312f | ||
|
|
aafc916bb6 | ||
|
|
c5eb1e999b | ||
|
|
7c15452c1e | ||
|
|
4bc849ccdb | ||
|
|
58481a035b | ||
|
|
66b3de8e5c | ||
|
|
257afe0cd3 | ||
|
|
aafea3b1c1 | ||
|
|
346a159157 | ||
|
|
54028d8cbb | ||
|
|
621b702ed4 | ||
|
|
26ea8a1b92 | ||
|
|
6e7bf99af8 | ||
|
|
df9d9d8673 | ||
|
|
b3cee1dfcc | ||
|
|
f40c382903 | ||
|
|
e4cfb808bf | ||
|
|
61d14a16e8 | ||
|
|
521e87ea41 | ||
|
|
2b735ffd55 | ||
|
|
4f72b0a98b | ||
|
|
474f5f5203 | ||
|
|
205cf29aff | ||
|
|
bf9074a76e | ||
|
|
44e1edb50c | ||
|
|
41d0dce6e9 | ||
|
|
598422b701 | ||
|
|
b58a1ccfcc | ||
|
|
60efd643d1 | ||
|
|
0596eeb6fe | ||
|
|
3d5c64feb7 | ||
|
|
610984f40e | ||
|
|
1e271b7352 | ||
|
|
07c78caf01 | ||
|
|
d153209d8a | ||
|
|
48186245fe | ||
|
|
f7c274591a | ||
|
|
d1a20e58b6 | ||
|
|
1e02c31524 | ||
|
|
66fab48a5b | ||
|
|
ae06652148 | ||
|
|
bd6c8d3f3c | ||
|
|
e88abec2a6 | ||
|
|
6de8b529d2 | ||
|
|
7301cdaa6c | ||
|
|
6969dfcdd1 | ||
|
|
edaf5a386f | ||
|
|
302f08dd57 | ||
|
|
68f5a614ef | ||
|
|
5db43031f2 | ||
|
|
873ade757a | ||
|
|
3c8dc9de32 | ||
|
|
4694b59cec | ||
|
|
4f1ada7a2f | ||
|
|
104a9cbffd | ||
|
|
45a52cff90 | ||
|
|
bf79b5d2aa | ||
|
|
e74c60f61d | ||
|
|
89921e5ec2 | ||
|
|
1b7ebd6fc2 | ||
|
|
165cc6028f | ||
|
|
8dc835bf52 | ||
|
|
8241641502 | ||
|
|
6de122c9f8 | ||
|
|
b267ad09ac | ||
|
|
e0dd371d61 | ||
|
|
f8f45a0cbd | ||
|
|
bf8ba050ce | ||
|
|
5fe7d1d993 | ||
|
|
cdcd8849f1 | ||
|
|
4c215aa5bb | ||
|
|
ab5c343c7d | ||
|
|
96cbf11270 | ||
|
|
c734e410f5 | ||
|
|
1eed9ea2db | ||
|
|
7d436e0051 | ||
|
|
ed8c72852f | ||
|
|
94af8d32c9 | ||
|
|
5fe96a4091 | ||
|
|
d1e86aefb9 | ||
|
|
ecd53b4222 | ||
|
|
9f02febf43 | ||
|
|
a2ff2811e3 | ||
|
|
ccf46a6c77 | ||
|
|
6ca215a9fd | ||
|
|
520411782e | ||
|
|
c56e94316d | ||
|
|
461563c6e6 | ||
|
|
164615a9e3 | ||
|
|
1040b32f3e | ||
|
|
d0719260e7 | ||
|
|
33d98d8217 | ||
|
|
e1f077a11b | ||
|
|
bd93d9cd11 | ||
|
|
004d1bbc7a | ||
|
|
99eb254e10 | ||
|
|
72c45f4ce1 | ||
|
|
3d3f2f5dd5 | ||
|
|
be37865b74 | ||
|
|
5bce47e487 | ||
|
|
ccf2009726 | ||
|
|
0253cb84a7 | ||
|
|
4d7017bd07 | ||
|
|
cb4bd6e80d | ||
|
|
7ed33e261e | ||
|
|
a7e7eb36be | ||
|
|
962db5d4d4 | ||
|
|
b59db8dd14 | ||
|
|
680e7a7bda | ||
|
|
5e67ce5067 | ||
|
|
4051c728fc | ||
|
|
ae4dbece0a | ||
|
|
6551687708 | ||
|
|
bd690e183d | ||
|
|
550dd08f19 | ||
|
|
eafe7a834a | ||
|
|
6e8c87921b | ||
|
|
ccf4ac2080 | ||
|
|
98188524d7 | ||
|
|
7477a9996d | ||
|
|
ab2625ec73 | ||
|
|
df5da69be6 | ||
|
|
5618ae9694 | ||
|
|
8a4236fba5 | ||
|
|
d5104ac117 | ||
|
|
8c8e2de4f6 | ||
|
|
cb6252b15f | ||
|
|
864eec2391 | ||
|
|
56ad570231 | ||
|
|
33e0611ccf | ||
|
|
c12679e815 | ||
|
|
f3415b6691 | ||
|
|
c6f9ce9639 | ||
|
|
11cd407f33 | ||
|
|
4055bf94ff | ||
|
|
3274360961 | ||
|
|
2bf69f8f1f | ||
|
|
e531993e00 | ||
|
|
f370c4683c | ||
|
|
a905ebba69 | ||
|
|
2b0df61b0a | ||
|
|
ee182aa083 | ||
|
|
6fc7990d6b | ||
|
|
ab47675a8a | ||
|
|
4d703fd433 | ||
|
|
9e591c6f0d | ||
|
|
7ecb92ae94 | ||
|
|
2429011d65 | ||
|
|
f48c30df8b | ||
|
|
5465f1b364 | ||
|
|
e5875c6d73 | ||
|
|
5dc53e24e7 | ||
|
|
d3e9575b75 | ||
|
|
a22eec22dc | ||
|
|
dad518a6bf | ||
|
|
db5f8abac1 | ||
|
|
a933ea551c | ||
|
|
6ceabdb746 | ||
|
|
834def4b70 | ||
|
|
06b9fcc0a4 | ||
|
|
3ecbdb5ae8 | ||
|
|
36d35fc196 | ||
|
|
78473d9a1b | ||
|
|
5847e8b63a | ||
|
|
c18091798a | ||
|
|
9e84266b60 | ||
|
|
720478670e | ||
|
|
0b1335645a | ||
|
|
706a54df6e | ||
|
|
83a76757d6 | ||
|
|
d8cdf58222 | ||
|
|
c9469cc1ea |
@@ -0,0 +1,46 @@
|
|||||||
|
# Normalize every text file to LF in the repository.
|
||||||
|
# The build runs under Linux/MinGW containers, so LF is also used in the
|
||||||
|
# working tree; Windows editors and toolchains handle LF fine.
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
# Windows-only files that must keep CRLF in the working tree.
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
*.sln text eol=crlf
|
||||||
|
*.vcproj text eol=crlf
|
||||||
|
*.vcxproj text eol=crlf
|
||||||
|
*.props text eol=crlf
|
||||||
|
*.filters text eol=crlf
|
||||||
|
|
||||||
|
# Files that must keep LF even if a Windows editor rewrites them.
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.in text eol=lf
|
||||||
|
*.cmake text eol=lf
|
||||||
|
*.mk text eol=lf
|
||||||
|
Makefile text eol=lf
|
||||||
|
Dockerfile text eol=lf
|
||||||
|
|
||||||
|
# Binary files - never touch the contents.
|
||||||
|
*.bin binary
|
||||||
|
*.ico binary
|
||||||
|
*.ttf binary
|
||||||
|
*.otf binary
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.bmp binary
|
||||||
|
*.zip binary
|
||||||
|
*.7z binary
|
||||||
|
*.gz binary
|
||||||
|
*.dll binary
|
||||||
|
*.exe binary
|
||||||
|
*.lib binary
|
||||||
|
*.a binary
|
||||||
|
*.o binary
|
||||||
|
*.obj binary
|
||||||
|
*.pdb binary
|
||||||
|
|
||||||
|
# Vendored code is stored and checked out byte-for-byte as upstream ships it,
|
||||||
|
# so re-importing a library never produces line-ending-only diffs.
|
||||||
|
src/spice2x/external/** -text
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Game and version
|
||||||
|
*name of game, version of game*
|
||||||
|
|
||||||
|
## Version of spice2x
|
||||||
|
*please remember to test the LATEST beta version before posting a bug about it*
|
||||||
|
|
||||||
|
## Describe the issue
|
||||||
|
*what's the issue?*
|
||||||
|
|
||||||
|
## Attached log.txt file, if available
|
||||||
|
> [!WARNING]
|
||||||
|
> Please make sure you remove any personally identifiable information from the log file.
|
||||||
|
> Please set `-loglevel` to `all` before launching the game for more verbose logs.
|
||||||
|
|
||||||
|
## A note on issue management
|
||||||
|
|
||||||
|
`Closed as not planned` means exactly that - it's closed, because it's not on our plans to address them any time soon. It doesn't mean your issue is invalid, it just means it's not a priority, and we can always revisit them later.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: Documentation update
|
||||||
|
about: For suggesting edits to the wiki page.
|
||||||
|
title: ''
|
||||||
|
labels: documentation
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
on: [push, pull_request]
|
||||||
|
name: Continuous Integration
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
fw-ci:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./src/spice2x
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
- name: Calculate commit SHA
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
calculatedSha=$(git rev-parse --short ${{ github.sha }})
|
||||||
|
echo "sha=$calculatedSha" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "bin=${{ github.workspace }}/src/spice2x/bin" >> "$GITHUB_OUTPUT"
|
||||||
|
- name: Compile
|
||||||
|
run: |
|
||||||
|
docker build --pull "$PWD/external/docker" -t spicetools/deps --platform linux/x86_64
|
||||||
|
docker build --build-context gitroot="$PWD/../../.git" . -t spicetools/spice:latest
|
||||||
|
docker run --name spice-build spicetools/spice:latest
|
||||||
|
mkdir -p "$PWD/bin"
|
||||||
|
docker cp spice-build:/src/src/spice2x/bin/. "$PWD/bin"
|
||||||
|
docker rm spice-build
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: spice2x-ci-${{ steps.vars.outputs.sha }}
|
||||||
|
path: ${{ steps.vars.outputs.bin }}
|
||||||
|
if-no-files-found: error
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
name: Draft Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Build and Draft Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./src/spice2x
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Clean leftover build artifacts
|
||||||
|
run: |
|
||||||
|
rm -rf .ccache dist bin cmake-build-*
|
||||||
|
- name: Compile
|
||||||
|
run: ./build_docker.sh
|
||||||
|
- name: Determine release name from dist filename
|
||||||
|
run: |
|
||||||
|
dist=$(basename "$(ls dist/spice2x-*.zip | grep -v -- '-full.zip')")
|
||||||
|
# strip the ".zip" to get the base name, e.g. spice2x-26-06-28
|
||||||
|
name="${dist%.zip}"
|
||||||
|
# the tag is the date portion, e.g. 26-06-28
|
||||||
|
tag="${name#spice2x-}"
|
||||||
|
echo "RELEASE_NAME=$name" >> $GITHUB_ENV
|
||||||
|
echo "RELEASE_TAG=$tag" >> $GITHUB_ENV
|
||||||
|
- name: Create draft release
|
||||||
|
uses: softprops/action-gh-release@v3
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
|
prerelease: true
|
||||||
|
tag_name: ${{ env.RELEASE_TAG }}
|
||||||
|
name: ${{ env.RELEASE_NAME }}
|
||||||
|
target_commitish: main
|
||||||
|
generate_release_notes: true
|
||||||
|
files: |
|
||||||
|
src/spice2x/dist/spice2x-*.zip
|
||||||
Generated
+350
@@ -0,0 +1,350 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="BackendCodeEditorSettings">
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstexprIfDiscardedBranch/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefinitionsOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedOverridenMethod/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppModulePartitionWithSeveralPartitionUnits/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOverrideWithDifferentVisibility/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReferenceToOverriddenVirtualFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseDesignatedInitializers/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseInternalLinkage/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
-1
@@ -1,4 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
<component name="CMakePythonSetting">
|
||||||
|
<option name="pythonIntegrationState" value="YES" />
|
||||||
|
</component>
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$/src/spice2x">
|
||||||
|
<contentRoot DIR="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+2
-2
@@ -2,10 +2,10 @@
|
|||||||
<configuration default="false" name="Clion[Init]" type="ShConfigurationType" activateToolWindowBeforeRun="false">
|
<configuration default="false" name="Clion[Init]" type="ShConfigurationType" activateToolWindowBeforeRun="false">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="clion init" />
|
<option name="SCRIPT_OPTIONS" value="clion init" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/spice2x/" />
|
||||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Deploy[Debug_x64]" type="ShConfigurationType">
|
<configuration default="false" name="Deploy[Debug_x64]" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Deploy[Debug_x86]" type="ShConfigurationType">
|
<configuration default="false" name="Deploy[Debug_x86]" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Deploy[Extra_x64]" type="ShConfigurationType">
|
<configuration default="false" name="Deploy[Extra_x64]" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Deploy[Extra_x86]" type="ShConfigurationType">
|
<configuration default="false" name="Deploy[Extra_x86]" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Deploy[Release_x64]" type="ShConfigurationType">
|
<configuration default="false" name="Deploy[Release_x64]" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Deploy[Release_x86]" type="ShConfigurationType">
|
<configuration default="false" name="Deploy[Release_x86]" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Distribute[Release]" type="ShConfigurationType">
|
<configuration default="false" name="Distribute[Release]" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="" />
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmake.sh" />
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
<option name="SCRIPT_OPTIONS" value="distribute all" />
|
<option name="SCRIPT_OPTIONS" value="distribute all" />
|
||||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_cfg" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_cfg" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_cfg" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_cfg" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_spice" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_spice" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_spice" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_spice" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_spice64" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_spice64" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_spice64" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_spice64" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt64" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt64" />
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld64" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld64" />
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_spice_laa" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_spice_laa" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_spice_laa" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_spice_laa" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
||||||
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_stubs_cpusbxpkm" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_stubs_cpusbxpkm" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_stubs_cpusbxpkm" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_cpusbxpkm" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_stubs_nvEncodeAPI64" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_stubs_nvEncodeAPI64" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_stubs_nvEncodeAPI64" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_nvEncodeAPI64" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_stubs_nvcuda" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_stubs_nvcuda" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_stubs_nvcuda" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_nvcuda" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="spicetools_stubs_nvcuvid" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="spicetools" TARGET_NAME="spicetools_stubs_nvcuvid" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
<configuration default="false" name="spicetools_stubs_nvcuvid" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_nvcuvid" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
<module classpath="CIDR" type="CPP_MODULE" version="4" />
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
## Contributing
|
||||||
|
Baseline rules for patch submissions are as follows. Any patches violating the rules below will not be accepted.
|
||||||
|
|
||||||
|
To contribute, fork the repo (just the main branch), make changes in your fork, and contribute to upstream by opening a pull request to the main repo.
|
||||||
|
|
||||||
|
### Adding support for games
|
||||||
|
|
||||||
|
* No BomberGirl, as long as the Free To Play service is still alive.
|
||||||
|
* No support for that one touch screen game that dispenses plushies of mouse character (`O26`).
|
||||||
|
* No support for eaCloud ("Konasute") games.
|
||||||
|
* For a new game that was never supported (not a new version of a game, but rather a new series): please wait 1 year after official AC release in Japan.
|
||||||
|
* For new version of an already supported game: proceed with caution and use generally-accepted community guidelines.
|
||||||
|
|
||||||
|
### Pull requests that will not be accepted
|
||||||
|
|
||||||
|
* Performing decryption of encrypted files.
|
||||||
|
* Including (bundling), distributing, or linking to game data, or making it easier to find/download game data.
|
||||||
|
* Any features that [phone home](https://en.wikipedia.org/wiki/Phoning_home)
|
||||||
|
* This includes automatic updaters.
|
||||||
|
* Exception: we have allowed the "patch import from URL" feature, but this has only been done under very careful considerations and plenty of warnings to the user.
|
||||||
|
* Built-in EA server that saves data. They should live in a separate project.
|
||||||
|
* Any additions to built-in patches (modifications / removals are OK if we have a good reason).
|
||||||
|
* Changes to the software license terms.
|
||||||
|
* Localization / translation for UI text. It becomes too difficult to manage by the maintainers.
|
||||||
|
* Bundling third party DLL binary; e.g., Discord Social SDK, PC light control integration, and so on. These should be built as hook DLLs instead, optionally with [Spice SDK](https://github.com/spice2x/spice2x.github.io/wiki/Spice-SDK).
|
||||||
|
|
||||||
|
### Avoiding regressions
|
||||||
|
|
||||||
|
The biggest risk in making code changes to spice is the risk of regressions. There is a **lot** of shared code used by many different games, reaching back game versions that are more than a decade old. It is practically impossible to test all supported games and versions.
|
||||||
|
|
||||||
|
Additionally, there's a lot of code that get exercised on specific hardware - including hardware that you probably don't have access to (e.g., ICCA reader, real cabinet I/O, specific model of a IIDX controller, particular brand of touch screens...)
|
||||||
|
|
||||||
|
Therefore, when making code changes, please be extremely careful about containing / scoping your changes. Make targeted bug fixes scoped to handful of game versions and hardware configuration. When adding new features, make it off by default, unless there is a really good reason to make it the default. If you make a new default, add an option that disables it so that users can opt out as needed.
|
||||||
|
|
||||||
|
#### Config file compatibility
|
||||||
|
|
||||||
|
Do not change the names of buttons binds, analogs, strings for command line parameters, etc - since they are used as unique identifiers in config files. If they are changed, you will introduce an incompatibility with previous versions of config file.
|
||||||
|
|
||||||
|
### Code quality requirements
|
||||||
|
|
||||||
|
* Test for regressions, at least in and around the component you are modifying:
|
||||||
|
* All currently supported games / versions must continue to work.
|
||||||
|
* Backwards compatibility must be preserved, unless there is a really good reason to break it. This includes (but not limited to): global/local config files, command line parameters, game patches, device interop (e.g., card readers), and SpiceAPI / Companion interop.
|
||||||
|
* Reasonable level of compatibility with the last release of original spicetools is expected. The stated goal of spice2x is to be a drop-in replacement for spicetools.
|
||||||
|
* Simply put, if someone has an existing install of spicetools/spice2x, copying over new version of spice2x should not result in vastly different behavior or major loss of functionality.
|
||||||
|
* Make sure you compile with the included Docker script and ensure you do not introduce **any** new compiler warnings or build breaks. The Docker script is the standard build environment, your custom Linux build environment or MSVC can be used during development, but you must validate the final build using Docker.
|
||||||
|
* Do not make code changes in unrelated areas; i.e., do not run code linters and auto-formatters for parts of the code that you didn't modify.
|
||||||
|
* Try to submit smaller chunks of code, instead one gigantic patch. For example, don't submit a patch for "Improve feature XYZ"; instead, submit "Change how A works to prepare for feature XYZ" "Refactor B for feature XYZ" "Add feature B to enable feature XYZ".
|
||||||
|
* Write to the log for anything useful - it helps immensely with troubleshooting and debugging. At the same time though, avoid spamming the log for something trivial.
|
||||||
|
|
||||||
|
### UI text
|
||||||
|
spice2x has a global audience; majority of the user base do not speak English as their first language.
|
||||||
|
|
||||||
|
Use simple English, avoid colloquialism, and use concise language, even if it's slightly technical.
|
||||||
|
|
||||||
|
### Using OS APIs
|
||||||
|
|
||||||
|
Avoid making permanent changes to user's OS configuration. For example, spice must not make a call to set power profile to Maximum Performance, or switch default audio device. Making the reverse call to restore settings on game shutdown is **not** good enough; there is no guarantee that spice will gracefully shutdown, since games (or spice) can crash. This is to avoid inadvertently putting user's PC into a bad state, which can be seen as malware-like behavior.
|
||||||
|
|
||||||
|
Watch out for legacy OS compatibility. Currently, the minimum support floor is Windows 7. If you use any Windows API, make sure it's supported in Windows 7. If you need to use API that is not present in Windows 7, you must not directly link against it, otherwise spice will fail to launch on older OSes. Take a look at Windows 8 touch code (win8.cpp) for examples on how to discover OS APIs via pointers.
|
||||||
|
|
||||||
|
### Code style requirements
|
||||||
|
* Indents are four spaces.
|
||||||
|
* Try to keep under 100 characters per line. This includes comments and string literals.
|
||||||
|
* Avoid making unnecessary formatting or whitespace changes in a PR; e.g., watch out for text editor automatically stripping trailing whitespace. It pollutes the diff and slows down code review.
|
||||||
|
* For signed/unsigned integer types, prefer `cstdint` types; e.g., use `int32_t`, `uint64_t` and not `int` and `unsigned long long`.
|
||||||
|
* Always use \{ curly braces \} when appropriate; do not omit them even when it's optional; such as `for` `if` `else`, etc.
|
||||||
|
|
||||||
|
OK:
|
||||||
|
```c
|
||||||
|
if (conditional) {
|
||||||
|
DoSomething();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Not OK:
|
||||||
|
```c
|
||||||
|
if (conditional)
|
||||||
|
DoSomething();
|
||||||
|
```
|
||||||
|
|
||||||
|
Not OK:
|
||||||
|
```c
|
||||||
|
if (conditional) DoSomething();
|
||||||
|
```
|
||||||
|
|
||||||
|
* Opening curly braces should appear at the end, not in a line on its own.
|
||||||
|
|
||||||
|
OK:
|
||||||
|
```c
|
||||||
|
if (conditional) {
|
||||||
|
DoSomething();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Not OK:
|
||||||
|
```c
|
||||||
|
if (conditional)
|
||||||
|
{
|
||||||
|
DoSomething();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Please give [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) a read. A few things to point out in spice codebase:
|
||||||
|
* We don't use GSL.
|
||||||
|
* Don't throw exceptions.
|
||||||
|
* Stick to smart pointers. For interfacing with C Win32 API and raw buffers, use `unique_plain_ptr`.
|
||||||
|
* Writing in C is also completely acceptable.
|
||||||
|
* Other than that, there are no strict rules for code formatting, but please attempt to emulate the style around the code you are modifying.
|
||||||
@@ -1,298 +1,65 @@
|
|||||||
SpiceTools
|
<br/><br/><br/><br/><br/><br/><br/><br/>
|
||||||
==========
|
|
||||||
This is a loader for various arcade games developed by 573.
|
|
||||||
The project is using CMake as it's build system, with a custom build
|
|
||||||
script for making packages ready for distribution and to keep it easy
|
|
||||||
for people not knowing how to use CMake.
|
|
||||||
|
|
||||||
## Building/Distribution
|
# This is the GitHub page for code development. If you just want to download the latest spice2x EXE, visit the homepage instead:
|
||||||
|
|
||||||
We're currently using Arch Linux for building the binaries.
|
# 🌶️🌶️ [https://spice2x.github.io/](https://spice2x.github.io/) 🌶️🌶️
|
||||||
You'll need:
|
|
||||||
- MinGW-64 packages (can be found in the AUR)
|
|
||||||
- bash
|
|
||||||
- git
|
|
||||||
- zip
|
|
||||||
- upx (optional)
|
|
||||||
|
|
||||||
For any other GNU/Linux distributions (or Windows lol), you're on your
|
# If you have problems, read [Known Issues (FAQ)](https://github.com/spice2x/spice2x.github.io/wiki/Known-issues) wiki page first, most of your questions are already answered.
|
||||||
own.
|
|
||||||
|
|
||||||
To build the project, run:
|
<br/><br/><br/><br/><br/><br/><br/><br/>
|
||||||
|
|
||||||
$ ./build_all.sh
|
# spice2x
|
||||||
|
|
||||||
## Build Configuration
|
## Overview
|
||||||
|
|
||||||
You can tweak some settings at the beginning of the build script. You
|
spice2x is a continuation of SpiceTools project. Original development of [SpiceTools](https://github.com/spicetools/spicetools) has stalled in 2022; spice2x is led by a new group of developers.
|
||||||
might want to modify the paths of the toolchains if yours differ. It's
|
|
||||||
also possible to disable UPX compression and source distribution for
|
|
||||||
example.
|
|
||||||
|
|
||||||
If you're not using an IDE and want to run the build script from command
|
spice2x team does not provide any tools to circumvent software copy protection, nor distribute any copyright-protected game data.
|
||||||
line manually each time you make a change, you can set CLEAN_BUILD to 0
|
|
||||||
so it will only compile what's needed. When modifying the resources you
|
|
||||||
should build from scratch, since CMake isn't able to track changes of
|
|
||||||
those files (e.g. changelog.txt, licenses.txt).
|
|
||||||
|
|
||||||
You can put your custom build script under "build_all.local.sh" if you
|
[Features](https://github.com/spice2x/spice2x.github.io/wiki/spice2x-features)
|
||||||
don't want git to track the changes you made to the build settings.
|
|
||||||
|
|
||||||
## Debug Build
|
[List of supported games](https://github.com/spice2x/spice2x.github.io/wiki/List-of-supported-games)
|
||||||
|
|
||||||
To get proper stackstraces, you need to build with the DEBUG setting
|
## How do I set up game data & start playing?
|
||||||
enabled. This will set the CMake build type to debug and the script
|
|
||||||
will try to make use of cv2pdb.
|
|
||||||
Check external/cv2pdb/README.md for details on how to set it up.
|
|
||||||
It is required to use cv2pdb to generate PDB output, because at time of
|
|
||||||
writing, MinGW still didn't support Microsoft's proprietary file format.
|
|
||||||
|
|
||||||
## API
|
By policy,
|
||||||
|
|
||||||
SpiceTools is providing a TCP/JSON based API. You can enable it with the
|
* we do **NOT** provide links on where to acquire game data
|
||||||
`-api [PORT]` option. It's recommended to also set a password with
|
* we do **NOT** provide tools or instructions on decrypting data
|
||||||
`-apipass [PASS]`.
|
* we do **NOT** provide guides on setting up & basic troubleshooting
|
||||||
|
|
||||||
The protocol is meant to be simple, easy to use and with few overhead.
|
please do not ask for these, as it will never happen here.
|
||||||
To connect to the API, just open a TCP connection to the host computer
|
|
||||||
at the specified port.
|
|
||||||
To make a request you write the UTF-8 encoded JSON contents to the
|
|
||||||
socket. To mark the end of the request, you need to terminate the JSON
|
|
||||||
string with `0x00`. The server returns its answer on the same way,
|
|
||||||
UTF-8 encoded JSON terminated with NULL.
|
|
||||||
|
|
||||||
To save space, by default the JSONs are without whitespace. To enable
|
## Submitting to the Issue Tracker
|
||||||
pretty printing, use `-apipretty`.
|
|
||||||
|
|
||||||
If you want to test the API server without running a game, you can
|
**Please file bugs if you find them!** If you just complain about something in Discord servers, we can't see them, so they'll never be fixed.
|
||||||
run it headless via `-apidebug`.
|
|
||||||
|
|
||||||
If a password is specified, both request and response are encrypted
|
Rules for filing a new issue or adding comments to existing issues in the tracker:
|
||||||
using RC4 with the key being the password encoded in UTF-8.
|
|
||||||
While only providing weak security when the password is static,
|
|
||||||
it's simple to implement and requires no authentication protocol.
|
|
||||||
The password is also able to change dynamically, see
|
|
||||||
`control.session_refresh()` for details.
|
|
||||||
|
|
||||||
If you don't want to worry about all the details, you can just use one
|
* Low effort submissions will be simply deleted, and repeated attempts will get you banned.
|
||||||
of the supplied libraries (check /api/resources). There's also a little
|
* Check the [known issues](https://github.com/spice2x/spice2x.github.io/wiki/Known-issues) page first before reporting a new issue. If you have some new information or workarounds for a known issue, you can file a documentation bug as well.
|
||||||
remote control GUI available for python.
|
* Use the search function and see if there is an existing issue.
|
||||||
|
* This is not the place to obtain a guide or receive basic troubleshooting.
|
||||||
|
* Don't file a bug demanding game XYZ to be supported.
|
||||||
|
* **Do not upload game data - any part of it, XML files included!**
|
||||||
|
* **Do not mention or link to external websites that distribute game data!**
|
||||||
|
* **Do not link to external websites that provide guides on how to run games!**
|
||||||
|
|
||||||
### WebSocket
|
New GitHub accounts are prevented from creating new issues to prevent spam. Maintainers of this project reserve the right to close or delete any issues that violate the rules above, or any low effort issues. If you ask for very basic troubleshooting help with setting up a game, we'll just delete them without warning.
|
||||||
SpiceTools opens a WebSocket server on the specified port plus one.
|
|
||||||
That means if the API is on 1337, the WebSocket server will be on 1338.
|
|
||||||
The protocol is the very same as for the normal API, but instead of
|
|
||||||
directly sending the data over TCP you need to send binary datapackets.
|
|
||||||
The included dart spiceapi library also has a WebSocket implementation.
|
|
||||||
|
|
||||||
### Example Call
|
## Contributing
|
||||||
This example inserts the a card into P1's reader slot.
|
**We encourage the community to submit bugs and suggestions via the issue tracker, and to contribute code changes by opening pull requests**
|
||||||
If you need more examples, you can check the example code.
|
|
||||||
|
|
||||||
#### Request
|
If you want to resolve any reported (or not reported) bugs, implement features, add support for new games, or fix a [known issue](https://github.com/spice2x/spice2x.github.io/wiki/Known-issues) - feel free to reach out via the Issue tracker or by opening a Pull Request. All submitted code is assumed to be GPLv3 compliant.
|
||||||
```JSON
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"module": "card",
|
|
||||||
"function": "insert",
|
|
||||||
"params": [0, "E004010000000000"]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
#### Response
|
|
||||||
```JSON
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"errors": [],
|
|
||||||
"data": []
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Modules
|
We explicitly do **NOT** have a Discord server for dicussions - we try to do everything out in the open on this GitHub repo. That being said we haven't opened a Discussions tab here because we know it's going to be immediately filled with support requests.
|
||||||
|
|
||||||
For the sake of simplifying this documentation, I will describe functions
|
Please see [CONTRIBUTING page](https://github.com/spice2x/spice2x.github.io/blob/main/CONTRIBUTING.md) for a full list of guidelines when submitting code.
|
||||||
as if they were called via a normal programming language. That means,
|
|
||||||
besides `module`/`function` needing to be set accordingly, the `params` field
|
|
||||||
must contain all the parameters described below. Some of them are optional.
|
|
||||||
The returning data will always be in the `data` field of the response.
|
|
||||||
|
|
||||||
Errors will be reported as strings in the `errors` field. Sometimes, you can
|
### AI-Use Policy
|
||||||
receive more than one error. The error messages may be changed/improved in the
|
|
||||||
future, so you shouldn't rely on them. If the error list is empty, the function
|
|
||||||
executed successfully.
|
|
||||||
|
|
||||||
The `id` of the response will always match the `id` of the request. The API
|
Use AI tools at your discretion, but remember that a human will review every issue and pull request. Please ensure submissions are accurate, relevant, and worth the reviewer’s time.
|
||||||
server itself doesn't expect any logic of your ID choices, however you can use
|
|
||||||
them to make sure your answers aren't arriving out of order. Currently it
|
|
||||||
doesn't matter since the TCP protocol doesn't allow for out of order data,
|
|
||||||
however this may change when/if support for UDP is being introduced. The only
|
|
||||||
restriction is that the ID has to be a valid 64-bit unsigned integer.
|
|
||||||
|
|
||||||
#### Card
|
## Additional information
|
||||||
- insert(index: uint, card_id: hex)
|
|
||||||
- inserts a card which gets read by the emulated card readers for the game
|
|
||||||
- index has to be either 0 (for P1) or 1 (for P2)
|
|
||||||
- card_id has to be a valid 16-character hex string
|
|
||||||
|
|
||||||
#### Coin
|
Please read [README.md](https://github.com/spice2x/spice2x.github.io/blob/main/src/spice2x/README.md) inside `src/spice2x`.
|
||||||
- get()
|
|
||||||
- returns the amount of unprocessed coins in queue
|
|
||||||
- not equal to the amount of coins shown ingame since the game may drain it
|
|
||||||
- set(amount: int)
|
|
||||||
- sets the amount of coins in queue for the game to process
|
|
||||||
- insert(amount: int)
|
|
||||||
- adds the amount to the coins in queue
|
|
||||||
- amount is optional and defaults to 1
|
|
||||||
- blocker_get()
|
|
||||||
- returns the current coin blocker state (false: open, true: closed)
|
|
||||||
|
|
||||||
#### Info
|
|
||||||
- avs()
|
|
||||||
- returns a dict including the AVS model, dest, spec, rev and ext
|
|
||||||
- launcher()
|
|
||||||
- returns a dict including the version, compile date/time, system time and
|
|
||||||
the arguments used to start the process
|
|
||||||
- memory()
|
|
||||||
- returns a dict including total, total used and bytes used by the process
|
|
||||||
for both physical and virtual RAM
|
|
||||||
|
|
||||||
#### Keypads
|
|
||||||
For all functions in this module, the keypad parameter must be
|
|
||||||
either 0 (for P1) or 1 (for P2). Accepted keypad characters are "0" to "9" for
|
|
||||||
the single digit numbers, "A" for the double zero and "D" for the decimal key.
|
|
||||||
- write(keypad: uint, input: str)
|
|
||||||
- writes all characters in input sequentially to the keypad
|
|
||||||
- this should be used for things like PIN input
|
|
||||||
- set(keypad: uint, key: char, ...)
|
|
||||||
- clears all overrides, then applies each given key as override
|
|
||||||
- if a key is overridden, it shows up as pressed in-game
|
|
||||||
- get(keypad: uint)
|
|
||||||
- returns all pressed keys of the specified keypad
|
|
||||||
|
|
||||||
#### Analogs/Buttons/Lights
|
|
||||||
All of those three modules have equally named methods for you to call.
|
|
||||||
- read()
|
|
||||||
- returns an array of state objects containing name, state and a bool
|
|
||||||
- the bool indicates if the object is active (e.g. the button was overridden)
|
|
||||||
- write([name: str, state: float], ...)
|
|
||||||
- applies the states as an override value
|
|
||||||
- the device binding via the config will be ignored while an override is set
|
|
||||||
- if an override value is set, the object will be marked as active
|
|
||||||
- write_reset([name: str], ...)
|
|
||||||
- removes the override value from the objects specified by name
|
|
||||||
- if no names were passed, all overrides will be removed
|
|
||||||
|
|
||||||
##### Additional API for lights
|
|
||||||
- read(name: string, ...)
|
|
||||||
- same as read(), but you can specify light names
|
|
||||||
- write_reset(name: str, ...)
|
|
||||||
- same as write_reset(), but it accepts a flat list of strings
|
|
||||||
|
|
||||||
#### Touch
|
|
||||||
- read()
|
|
||||||
- returns an array of state objects containing id, x and y
|
|
||||||
- write([id: uint, x: int, y: int], ...)
|
|
||||||
- adds the given touch points having an unknown ID
|
|
||||||
- overrides old touch points when the ID matches
|
|
||||||
- write_reset(id: uint, ...)
|
|
||||||
- removes the touch points matching one of the given IDs
|
|
||||||
|
|
||||||
#### Control
|
|
||||||
This module only functions if a password is being used to communicate,
|
|
||||||
with the single exception of session_refresh().
|
|
||||||
- raise(signal: str)
|
|
||||||
- raises a signal to the current process
|
|
||||||
- signal is a string and must be one of the following values:
|
|
||||||
"SIGABRT", "SIGFPE", "SIGILL", "SIGINT", "SIGSEGV", "SIGTERM"
|
|
||||||
- the signal will be raised while the message is being processed
|
|
||||||
- exit(code: int)
|
|
||||||
- code is optional and defaults to 0
|
|
||||||
- the process will end while the message is being processed
|
|
||||||
- restart()
|
|
||||||
- spawns a new instance with the same arguments as passed to the main executable
|
|
||||||
- session_refresh()
|
|
||||||
- generates a new secure password and applies it after the response
|
|
||||||
- can be used to increase the security by using the password as some kind of
|
|
||||||
session token
|
|
||||||
- recommended to call directly after connecting and once in a while for
|
|
||||||
persistent connections
|
|
||||||
- shutdown()
|
|
||||||
- tries to force shutdown the computer
|
|
||||||
- reboot()
|
|
||||||
- tries to force reboot the computer
|
|
||||||
|
|
||||||
#### Memory
|
|
||||||
This module only functions if a password is being used to communicate.
|
|
||||||
All offsets are specified in file offsets of the corresponding `dll_name`,
|
|
||||||
which also means that your hex edits are applicable directly.
|
|
||||||
- write(dll_name: str, data: hex, offset: uint)
|
|
||||||
- writes the bytes in data to the specified offset
|
|
||||||
- read(dll_name: str, offset: uint, size: uint)
|
|
||||||
- reads bytes starting from offset and returns it
|
|
||||||
- signature(dll_name: str, signature: hex, replacement: hex, offset: uint,
|
|
||||||
usage: uint)
|
|
||||||
- tries to find the signature in the module's memory
|
|
||||||
- unknown bytes are masked out via "??" (e.g. "75??90????74")
|
|
||||||
- masking out bytes works for both the signature and the replacement
|
|
||||||
- offset is the byte difference between the offset of the found signature and
|
|
||||||
the offset where the replacement data gets written to
|
|
||||||
- usage is the number of the result being used for replacement, starting at 0
|
|
||||||
- returns the offset where the replacement data gets written to
|
|
||||||
- the replacement string can be empty, so you can only get the address of the
|
|
||||||
signature while not actually replacing anything
|
|
||||||
|
|
||||||
#### IIDX
|
|
||||||
- ticker_get()
|
|
||||||
- returns a string of the characters displayed on the 16 segment display
|
|
||||||
- ticker_set(text: str)
|
|
||||||
- sets the contents of the 16 segment display and disables writes from game
|
|
||||||
- ticker_reset()
|
|
||||||
- re-enables writes from game
|
|
||||||
- tapeled_get(name: str, ...)
|
|
||||||
- returns a list containing a dict of the current tape LED states. The dict keys are:
|
|
||||||
- `Stage Left`
|
|
||||||
- `Stage Right`
|
|
||||||
- `Cabinet Left`
|
|
||||||
- `Cabinet Right`
|
|
||||||
- `Control Panel Under`
|
|
||||||
- `Ceiling Left`
|
|
||||||
- `Title Left`
|
|
||||||
- `Title Right`
|
|
||||||
- `Ceiling Right`
|
|
||||||
- `Touch Panel Left`
|
|
||||||
- `Touch Panel Right`
|
|
||||||
- `Side Panel Left Inner`
|
|
||||||
- `Side Panel Left Outer`
|
|
||||||
- `Side Panel Left`
|
|
||||||
- `Side Panel Right Outer`
|
|
||||||
- `Side Panel Right Inner`
|
|
||||||
- `Side Panel Right`
|
|
||||||
|
|
||||||
#### LCD
|
|
||||||
- info()
|
|
||||||
- returns information about the serial LCD controller some games use
|
|
||||||
|
|
||||||
#### Resize
|
|
||||||
- image_resize_enable(enable: bool)
|
|
||||||
- enables or disables image resize state
|
|
||||||
- image_resize_set_scene(scene: int)
|
|
||||||
- sets the active scene for image resize state; set to 0 to disable resize
|
|
||||||
|
|
||||||
## Native wrapper libraries
|
|
||||||
Spicetools provides wrapper libraries in: Arduino, C++, Dart, and Python.
|
|
||||||
Python is the only one that is fully spec compliant.
|
|
||||||
Other libraries may be missing features and contain bugs; please feel free to
|
|
||||||
contribute code to fill the gaps if you work on a project using these libraries.
|
|
||||||
|
|
||||||
## License
|
|
||||||
Unless otherwise noted, all files are licensed under the GPLv3.
|
|
||||||
See the LICENSE file for the full license text.
|
|
||||||
Files not originating from this project should be placed in "external",
|
|
||||||
they each have their own license.
|
|
||||||
|
|
||||||
###### What that means for you
|
|
||||||
- If you want to distribute the binaries, you'll have to include the
|
|
||||||
sources, otherwise you're violating the GPL.
|
|
||||||
- If you want to merge some of this project's code into similar
|
|
||||||
software, that software has to be put under the GPL as well.
|
|
||||||
You'll probably have to modify a lot anyways, so you can just use the
|
|
||||||
source as some kind of documentation.
|
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
#include "capture.h"
|
|
||||||
#include <functional>
|
|
||||||
#include "external/rapidjson/document.h"
|
|
||||||
#include "hooks/graphics/graphics.h"
|
|
||||||
#include "util/crypt.h"
|
|
||||||
|
|
||||||
using namespace std::placeholders;
|
|
||||||
using namespace rapidjson;
|
|
||||||
|
|
||||||
namespace api::modules {
|
|
||||||
|
|
||||||
std::optional<uint32_t> CAPTURE_QUALITY;
|
|
||||||
std::optional<uint32_t> CAPTURE_DIVIDE;
|
|
||||||
|
|
||||||
static thread_local std::vector<uint8_t> CAPTURE_BUFFER;
|
|
||||||
|
|
||||||
Capture::Capture() : Module("capture") {
|
|
||||||
functions["get_screens"] = std::bind(&Capture::get_screens, this, _1, _2);
|
|
||||||
functions["get_jpg"] = std::bind(&Capture::get_jpg, this, _1, _2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get_screens()
|
|
||||||
*/
|
|
||||||
void Capture::get_screens(Request &req, Response &res) {
|
|
||||||
|
|
||||||
// aquire screens
|
|
||||||
std::vector<int> screens;
|
|
||||||
graphics_screens_get(screens);
|
|
||||||
|
|
||||||
// add screens to response
|
|
||||||
for (auto &screen : screens) {
|
|
||||||
res.add_data(screen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get_jpg([screen=0, quality=70, downscale=0, divide=1])
|
|
||||||
* screen: uint specifying the window
|
|
||||||
* quality: uint in range [0, 100]
|
|
||||||
* reduce: uint for dividing image size
|
|
||||||
*/
|
|
||||||
void Capture::get_jpg(Request &req, Response &res) {
|
|
||||||
CAPTURE_BUFFER.reserve(1024 * 128);
|
|
||||||
|
|
||||||
// settings
|
|
||||||
int screen = 0;
|
|
||||||
int quality = 70;
|
|
||||||
int divide = 1;
|
|
||||||
if (req.params.Size() > 0 && req.params[0].IsUint()) {
|
|
||||||
screen = req.params[0].GetUint();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CAPTURE_QUALITY.has_value()) {
|
|
||||||
quality = CAPTURE_QUALITY.value();
|
|
||||||
} else if (req.params.Size() > 1 && req.params[1].IsUint()) {
|
|
||||||
quality = req.params[1].GetUint();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CAPTURE_DIVIDE.has_value()) {
|
|
||||||
divide = CAPTURE_DIVIDE.value();
|
|
||||||
} else if (req.params.Size() > 2 && req.params[2].IsUint()) {
|
|
||||||
divide = req.params[2].GetUint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// receive JPEG data
|
|
||||||
uint64_t timestamp = 0;
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
graphics_capture_trigger(screen);
|
|
||||||
bool success = graphics_capture_receive_jpeg(screen, [] (uint8_t byte) {
|
|
||||||
CAPTURE_BUFFER.push_back(byte);
|
|
||||||
}, true, quality, true, divide, ×tamp, &width, &height);
|
|
||||||
if (!success) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode to base64
|
|
||||||
auto encoded = crypt::base64_encode(
|
|
||||||
CAPTURE_BUFFER.data(),
|
|
||||||
CAPTURE_BUFFER.size());
|
|
||||||
|
|
||||||
// clear buffer
|
|
||||||
CAPTURE_BUFFER.clear();
|
|
||||||
|
|
||||||
// add data to response
|
|
||||||
Value data;
|
|
||||||
data.SetString(encoded.c_str(), encoded.length(), res.doc()->GetAllocator());
|
|
||||||
res.add_data(timestamp);
|
|
||||||
res.add_data(width);
|
|
||||||
res.add_data(height);
|
|
||||||
res.add_data(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#include "card.h"
|
|
||||||
#include <functional>
|
|
||||||
#include "external/rapidjson/document.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
|
|
||||||
using namespace std::placeholders;
|
|
||||||
using namespace rapidjson;
|
|
||||||
|
|
||||||
|
|
||||||
namespace api::modules {
|
|
||||||
|
|
||||||
Card::Card() : Module("card") {
|
|
||||||
functions["insert"] = std::bind(&Card::insert, this, _1, _2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* insert(index, card_id)
|
|
||||||
* index: uint in range [0, 1]
|
|
||||||
* card_id: hex string of length 16
|
|
||||||
*/
|
|
||||||
void Card::insert(Request &req, Response &res) {
|
|
||||||
|
|
||||||
// check params
|
|
||||||
if (req.params.Size() < 2)
|
|
||||||
return error_params_insufficient(res);
|
|
||||||
if (!req.params[0].IsUint())
|
|
||||||
return error_type(res, "index", "uint");
|
|
||||||
if (!req.params[1].IsString())
|
|
||||||
return error_type(res, "card_id", "hex string");
|
|
||||||
if (req.params[1].GetStringLength() != 16)
|
|
||||||
return error_size(res, "card_id", 16);
|
|
||||||
|
|
||||||
// get params
|
|
||||||
auto index = req.params[0].GetUint();
|
|
||||||
auto card_hex = req.params[1].GetString();
|
|
||||||
|
|
||||||
// convert to binary
|
|
||||||
uint8_t card_bin[8] {};
|
|
||||||
if (!hex2bin(card_hex, card_bin)) {
|
|
||||||
return error_type(res, "card_id", "hex string");
|
|
||||||
}
|
|
||||||
|
|
||||||
// log
|
|
||||||
if (LOGGING) {
|
|
||||||
log_info("api::card", "inserting card: {}", card_hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert card
|
|
||||||
eamuse_card_insert(index & 1, card_bin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
#include "touch.h"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "external/rapidjson/document.h"
|
|
||||||
#include "avs/game.h"
|
|
||||||
#include "hooks/graphics/graphics.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
#include "launcher/launcher.h"
|
|
||||||
#include "touch/touch.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "games/iidx/iidx.h"
|
|
||||||
|
|
||||||
using namespace std::placeholders;
|
|
||||||
using namespace rapidjson;
|
|
||||||
|
|
||||||
|
|
||||||
namespace api::modules {
|
|
||||||
|
|
||||||
Touch::Touch() : Module("touch") {
|
|
||||||
is_sdvx = avs::game::is_model("KFC");
|
|
||||||
|
|
||||||
is_tdj_fhd = (avs::game::is_model("LDJ") && games::iidx::is_tdj_fhd());
|
|
||||||
// special case: when windowed subscreen is in use, use the original coords
|
|
||||||
if (GRAPHICS_IIDX_WSUB) {
|
|
||||||
is_tdj_fhd = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
functions["read"] = std::bind(&Touch::read, this, _1, _2);
|
|
||||||
functions["write"] = std::bind(&Touch::write, this, _1, _2);
|
|
||||||
functions["write_reset"] = std::bind(&Touch::write_reset, this, _1, _2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* read()
|
|
||||||
*/
|
|
||||||
void Touch::read(api::Request &req, Response &res) {
|
|
||||||
|
|
||||||
// get touch points
|
|
||||||
std::vector<TouchPoint> touch_points;
|
|
||||||
touch_get_points(touch_points);
|
|
||||||
|
|
||||||
// add state for each touch point
|
|
||||||
for (auto &touch : touch_points) {
|
|
||||||
Value state(kArrayType);
|
|
||||||
Value id((uint64_t) touch.id);
|
|
||||||
Value x((int64_t) touch.x);
|
|
||||||
Value y((int64_t) touch.y);
|
|
||||||
Value mouse((bool) touch.mouse);
|
|
||||||
state.PushBack(id, res.doc()->GetAllocator());
|
|
||||||
state.PushBack(x, res.doc()->GetAllocator());
|
|
||||||
state.PushBack(y, res.doc()->GetAllocator());
|
|
||||||
state.PushBack(mouse, res.doc()->GetAllocator());
|
|
||||||
res.add_data(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* write([id: uint, x: int, y: int], ...)
|
|
||||||
*/
|
|
||||||
void Touch::write(Request &req, Response &res) {
|
|
||||||
|
|
||||||
// get all touch points
|
|
||||||
std::vector<TouchPoint> touch_points;
|
|
||||||
for (Value ¶m : req.params.GetArray()) {
|
|
||||||
|
|
||||||
// check params
|
|
||||||
if (param.Size() < 3) {
|
|
||||||
error_params_insufficient(res);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!param[0].IsUint()) {
|
|
||||||
error_type(res, "id", "uint");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!param[1].IsInt()) {
|
|
||||||
error_type(res, "x", "int");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!param[2].IsInt()) {
|
|
||||||
error_type(res, "y", "int");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// TODO: optional mouse parameter
|
|
||||||
|
|
||||||
// get params
|
|
||||||
auto touch_id = param[0].GetUint();
|
|
||||||
auto touch_x = param[1].GetInt();
|
|
||||||
auto touch_y = param[2].GetInt();
|
|
||||||
|
|
||||||
apply_touch_errata(touch_x, touch_y);
|
|
||||||
|
|
||||||
touch_points.emplace_back(TouchPoint {
|
|
||||||
.id = touch_id,
|
|
||||||
.x = touch_x,
|
|
||||||
.y = touch_y,
|
|
||||||
.mouse = false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply touch points
|
|
||||||
touch_write_points(&touch_points);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* write_reset(id: uint, ...)
|
|
||||||
*/
|
|
||||||
void Touch::write_reset(Request &req, Response &res) {
|
|
||||||
|
|
||||||
// get all IDs
|
|
||||||
std::vector<DWORD> touch_point_ids;
|
|
||||||
for (Value ¶m : req.params.GetArray()) {
|
|
||||||
|
|
||||||
// check params
|
|
||||||
if (!param.IsUint()) {
|
|
||||||
error_type(res, "id", "uint");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remember touch ID
|
|
||||||
auto touch_id = param.GetUint();
|
|
||||||
touch_point_ids.emplace_back(touch_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove all IDs
|
|
||||||
touch_remove_points(&touch_point_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Touch::apply_touch_errata(int &x, int &y) {
|
|
||||||
int x_raw = x;
|
|
||||||
int y_raw = y;
|
|
||||||
|
|
||||||
if (is_tdj_fhd) {
|
|
||||||
// deal with TDJ FHD resolution mismatch (upgrade 720p to 1080p)
|
|
||||||
// we don't know what screen is being shown on the companion and the API doesn't specify
|
|
||||||
// the target of the touch events so just assume it's the sub screen
|
|
||||||
x = x_raw * 1920 / 1280;
|
|
||||||
y = y_raw * 1080 / 720;
|
|
||||||
} else if (is_sdvx) {
|
|
||||||
// for exceed gear, they are both 1080p screens, but need to apply transformation
|
|
||||||
x = 1080 - y_raw;
|
|
||||||
y = x_raw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "api/module.h"
|
|
||||||
#include "api/request.h"
|
|
||||||
|
|
||||||
namespace api::modules {
|
|
||||||
|
|
||||||
class Touch : public Module {
|
|
||||||
public:
|
|
||||||
Touch();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_sdvx;
|
|
||||||
bool is_tdj_fhd;
|
|
||||||
|
|
||||||
// function definitions
|
|
||||||
void read(Request &req, Response &res);
|
|
||||||
void write(Request &req, Response &res);
|
|
||||||
void write_reset(Request &req, Response &res);
|
|
||||||
void apply_touch_errata(int &x, int &y);
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
part of spiceapi;
|
|
||||||
|
|
||||||
Future<void> cardInsert(Connection con, int unit, String cardID) {
|
|
||||||
var req = Request("card", "insert");
|
|
||||||
req.addParam(unit);
|
|
||||||
req.addParam(cardID);
|
|
||||||
return con.request(req);
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
part of spiceapi;
|
|
||||||
|
|
||||||
Future<void> cardInsert(Connection con, int unit, String cardID) {
|
|
||||||
var req = Request("card", "insert");
|
|
||||||
req.addParam(unit);
|
|
||||||
req.addParam(cardID);
|
|
||||||
return con.request(req);
|
|
||||||
}
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
#define HEADSOCKET_IMPLEMENTATION
|
|
||||||
#include "external/headsocket.h"
|
|
||||||
|
|
||||||
#include "websocket.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "util/rc4.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "controller.h"
|
|
||||||
|
|
||||||
using namespace headsocket;
|
|
||||||
|
|
||||||
namespace api {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Client class declaration
|
|
||||||
*/
|
|
||||||
class WebSocketClient : public web_socket_client {
|
|
||||||
|
|
||||||
// required class header
|
|
||||||
HEADSOCKET_CLIENT(WebSocketClient, web_socket_client);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ClientState *state = nullptr;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool async_received_data(const data_block &db, uint8_t *ptr, size_t length) override;
|
|
||||||
|
|
||||||
void on_accept() override;
|
|
||||||
void on_disconnect() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Server class declaration
|
|
||||||
*/
|
|
||||||
class WebSocketServer : public web_socket_server<WebSocketClient> {
|
|
||||||
HEADSOCKET_SERVER(WebSocketServer, web_socket_server);
|
|
||||||
public:
|
|
||||||
WebSocketController *websocket;
|
|
||||||
};
|
|
||||||
|
|
||||||
void api::WebSocketServer::init() {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Controller state so we don't have to import headsocket stuff in our header
|
|
||||||
*/
|
|
||||||
struct WebSocketControllerState {
|
|
||||||
std::shared_ptr<WebSocketServer> server;
|
|
||||||
};
|
|
||||||
|
|
||||||
WebSocketController::WebSocketController(Controller *controller, uint16_t port) {
|
|
||||||
this->controller = controller;
|
|
||||||
|
|
||||||
// create state
|
|
||||||
this->state = new WebSocketControllerState();
|
|
||||||
|
|
||||||
// start server
|
|
||||||
this->state->server = WebSocketServer::create(port);
|
|
||||||
this->state->server->websocket = this;
|
|
||||||
if (this->state->server->is_running()) {
|
|
||||||
log_info("api::websocket", "server listening on port: {}", port);
|
|
||||||
} else {
|
|
||||||
log_warning("api::websocket", "server failed to listen on port: {}", port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WebSocketController::~WebSocketController() {
|
|
||||||
|
|
||||||
// stop server
|
|
||||||
this->state->server->stop();
|
|
||||||
|
|
||||||
// delete state
|
|
||||||
delete this->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketController::free_socket() {
|
|
||||||
this->state->server->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::on_accept() {
|
|
||||||
web_socket_client::on_accept();
|
|
||||||
|
|
||||||
// get pointer to server
|
|
||||||
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
|
|
||||||
if (!srv || !srv->websocket) {
|
|
||||||
log_fatal("api::websocket", "on_accept has no server");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for init
|
|
||||||
state = new ClientState();
|
|
||||||
srv->websocket->controller->init_state(state);
|
|
||||||
|
|
||||||
// log connection
|
|
||||||
log_info("api::websocket", "client connected");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::on_disconnect() {
|
|
||||||
|
|
||||||
// log disconnection
|
|
||||||
log_info("api::websocket", "client disconnected");
|
|
||||||
|
|
||||||
// get pointer to server
|
|
||||||
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
|
|
||||||
if (!srv || !srv->websocket) {
|
|
||||||
log_fatal("api::websocket", "on_disconnect has no server");
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up state
|
|
||||||
srv->websocket->controller->free_state(state);
|
|
||||||
delete state;
|
|
||||||
state = nullptr;
|
|
||||||
|
|
||||||
// call super
|
|
||||||
web_socket_client::on_disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is where business actually happens, gets called on every datablock receive
|
|
||||||
*/
|
|
||||||
bool WebSocketClient::async_received_data(const data_block &db, uint8_t *ptr, size_t length) {
|
|
||||||
|
|
||||||
// get pointer to server
|
|
||||||
auto srv = reinterpret_cast<WebSocketServer *>(server().get());
|
|
||||||
if (!srv || !srv->websocket) {
|
|
||||||
log_fatal("api::websocket", "received datablock without server");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check state
|
|
||||||
if (!state) {
|
|
||||||
log_fatal("api::websocket", "client with no state received datablock");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check datablock type
|
|
||||||
switch (db.op) {
|
|
||||||
case opcode::binary: {
|
|
||||||
|
|
||||||
// allocate buffers
|
|
||||||
std::vector<char> in(ptr, ptr + length);
|
|
||||||
std::vector<char> out;
|
|
||||||
|
|
||||||
// crypt in-data
|
|
||||||
if (state->cipher) {
|
|
||||||
state->cipher->crypt(reinterpret_cast<uint8_t *>(in.data()), in.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// process request
|
|
||||||
srv->websocket->controller->process_request(state, &in, &out);
|
|
||||||
|
|
||||||
// crypt out-data
|
|
||||||
if (state->cipher) {
|
|
||||||
state->cipher->crypt(reinterpret_cast<uint8_t *>(out.data()), out.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// send answer
|
|
||||||
push(out.data(), out.size());
|
|
||||||
|
|
||||||
// check for password change
|
|
||||||
srv->websocket->controller->process_password_change(state);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log_warning("api::websocket", "datablock received with non-binary type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// always consume the datablock, nomnom
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
docker build --pull "$PWD/external/docker" -t spicetools/deps --platform linux/x86_64
|
|
||||||
docker build --build-context gitroot="$PWD/../../.git" . -t spicetools/spice:latest
|
|
||||||
docker run --rm -v "$PWD/dist:/src/src/spice2x/dist" -v "$PWD/bin:/src/src/spice2x/bin" -v "$PWD/.ccache:/src/src/spice2x/.ccache" spicetools/spice "$@"
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#include "configurator.h"
|
|
||||||
|
|
||||||
#include "overlay/overlay.h"
|
|
||||||
|
|
||||||
namespace cfg {
|
|
||||||
|
|
||||||
// globals
|
|
||||||
bool CONFIGURATOR_STANDALONE = false;
|
|
||||||
ConfigType CONFIGURATOR_TYPE = ConfigType::Config;
|
|
||||||
|
|
||||||
Configurator::Configurator() {
|
|
||||||
CONFIGURATOR_STANDALONE = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Configurator::~Configurator() {
|
|
||||||
CONFIGURATOR_STANDALONE = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Configurator::run() {
|
|
||||||
|
|
||||||
// create instance
|
|
||||||
overlay::ENABLED = true;
|
|
||||||
overlay::create_software(this->wnd.hWnd);
|
|
||||||
overlay::OVERLAY->set_active(true);
|
|
||||||
overlay::OVERLAY->hotkeys_enable = false;
|
|
||||||
ImGui::GetIO().MouseDrawCursor = false;
|
|
||||||
|
|
||||||
// run window
|
|
||||||
this->wnd.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
#include "configurator_wnd.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include "build/defs.h"
|
|
||||||
#include "launcher/shutdown.h"
|
|
||||||
#include "overlay/overlay.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "cfg/configurator.h"
|
|
||||||
|
|
||||||
#include "icon.h"
|
|
||||||
|
|
||||||
static const char *CLASS_NAME = "ConfiguratorWindow";
|
|
||||||
static std::string WINDOW_TITLE;
|
|
||||||
static int WINDOW_SIZE_X = 800;
|
|
||||||
static int WINDOW_SIZE_Y = 600;
|
|
||||||
static HICON WINDOW_ICON = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(MAINICON));
|
|
||||||
|
|
||||||
cfg::ConfiguratorWindow::ConfiguratorWindow() {
|
|
||||||
|
|
||||||
// register the window class
|
|
||||||
WNDCLASS wc {};
|
|
||||||
wc.lpfnWndProc = ConfiguratorWindow::window_proc;
|
|
||||||
wc.hInstance = GetModuleHandle(NULL);
|
|
||||||
wc.lpszClassName = CLASS_NAME;
|
|
||||||
wc.hbrBackground = NULL;
|
|
||||||
wc.hIcon = WINDOW_ICON;
|
|
||||||
RegisterClass(&wc);
|
|
||||||
|
|
||||||
// determine window title
|
|
||||||
if (cfg::CONFIGURATOR_TYPE == cfg::ConfigType::Config) {
|
|
||||||
WINDOW_TITLE = "spice2x config (" + to_string(VERSION_STRING_CFG) + ")";
|
|
||||||
WINDOW_SIZE_X = 800;
|
|
||||||
WINDOW_SIZE_Y = 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
// open window
|
|
||||||
this->hWnd = CreateWindowEx(
|
|
||||||
0,
|
|
||||||
CLASS_NAME,
|
|
||||||
WINDOW_TITLE.c_str(),
|
|
||||||
WS_OVERLAPPEDWINDOW,
|
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
GetModuleHandle(NULL),
|
|
||||||
(LPVOID) this);
|
|
||||||
|
|
||||||
if (this->hWnd) {
|
|
||||||
overlay::USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg::ConfiguratorWindow::~ConfiguratorWindow() {
|
|
||||||
|
|
||||||
// close window
|
|
||||||
DestroyWindow(this->hWnd);
|
|
||||||
|
|
||||||
// unregister class
|
|
||||||
UnregisterClass(CLASS_NAME, GetModuleHandle(NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
void cfg::ConfiguratorWindow::run() {
|
|
||||||
|
|
||||||
// show window
|
|
||||||
SetWindowPos(this->hWnd, HWND_TOP, 0, 0, WINDOW_SIZE_X, WINDOW_SIZE_Y, 0);
|
|
||||||
ShowWindow(this->hWnd, SW_SHOWNORMAL);
|
|
||||||
UpdateWindow(this->hWnd);
|
|
||||||
|
|
||||||
// draw overlay in 60 FPS
|
|
||||||
SetTimer(this->hWnd, 1, 1000 / 60, nullptr);
|
|
||||||
|
|
||||||
// window loop
|
|
||||||
BOOL ret;
|
|
||||||
MSG msg;
|
|
||||||
while ((ret = GetMessage(&msg, nullptr, 0, 0)) != 0) {
|
|
||||||
if (ret == -1) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT CALLBACK cfg::ConfiguratorWindow::window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
||||||
switch (uMsg) {
|
|
||||||
case WM_CHAR: {
|
|
||||||
|
|
||||||
// input characters if overlay is active
|
|
||||||
if (overlay::OVERLAY && overlay::OVERLAY->has_focus()) {
|
|
||||||
overlay::OVERLAY->input_char((unsigned int) wParam);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_CREATE: {
|
|
||||||
|
|
||||||
// set user data of window to class pointer
|
|
||||||
auto create_struct = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
|
||||||
SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(create_struct->lpCreateParams));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_CLOSE:
|
|
||||||
case WM_DESTROY: {
|
|
||||||
|
|
||||||
// exit process
|
|
||||||
launcher::shutdown();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_TIMER: {
|
|
||||||
|
|
||||||
// update overlay
|
|
||||||
if (overlay::OVERLAY) {
|
|
||||||
overlay::OVERLAY->update();
|
|
||||||
overlay::OVERLAY->set_active(true);
|
|
||||||
overlay::OVERLAY->new_frame();
|
|
||||||
overlay::OVERLAY->render();
|
|
||||||
}
|
|
||||||
|
|
||||||
// repaint window
|
|
||||||
InvalidateRect(hWnd, nullptr, TRUE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WM_ERASEBKGND: {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case WM_PAINT: {
|
|
||||||
|
|
||||||
// render overlay
|
|
||||||
if (overlay::OVERLAY) {
|
|
||||||
|
|
||||||
// get pixel data
|
|
||||||
int width, height;
|
|
||||||
uint32_t *pixel_data = overlay::OVERLAY->sw_get_pixel_data(&width, &height);
|
|
||||||
if (width > 0 && height > 0) {
|
|
||||||
|
|
||||||
// create bitmap
|
|
||||||
HBITMAP bitmap = CreateBitmap(width, height, 1, 8 * sizeof(uint32_t), pixel_data);
|
|
||||||
|
|
||||||
// prepare paint
|
|
||||||
PAINTSTRUCT paint{};
|
|
||||||
HDC hdc = BeginPaint(hWnd, &paint);
|
|
||||||
HDC hdcMem = CreateCompatibleDC(hdc);
|
|
||||||
SetBkMode(hdc, TRANSPARENT);
|
|
||||||
|
|
||||||
// draw bitmap
|
|
||||||
SelectObject(hdcMem, bitmap);
|
|
||||||
BitBlt(hdc, paint.rcPaint.left, paint.rcPaint.top,
|
|
||||||
paint.rcPaint.right - paint.rcPaint.left,
|
|
||||||
paint.rcPaint.bottom - paint.rcPaint.top,
|
|
||||||
hdcMem, paint.rcPaint.left, paint.rcPaint.top, SRCCOPY);
|
|
||||||
|
|
||||||
// delete bitmap
|
|
||||||
DeleteObject(bitmap);
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
DeleteDC(hdcMem);
|
|
||||||
EndPaint(hWnd, &paint);
|
|
||||||
} else {
|
|
||||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
namespace cfg {
|
|
||||||
|
|
||||||
class ConfiguratorWindow {
|
|
||||||
public:
|
|
||||||
|
|
||||||
HWND hWnd;
|
|
||||||
|
|
||||||
ConfiguratorWindow();
|
|
||||||
~ConfiguratorWindow();
|
|
||||||
|
|
||||||
void run();
|
|
||||||
|
|
||||||
static LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Vendored
-17
@@ -1,17 +0,0 @@
|
|||||||
FROM ghcr.io/archlinux/archlinux:base-devel
|
|
||||||
|
|
||||||
RUN pacman --noconfirm -Syu git \
|
|
||||||
bash \
|
|
||||||
zip \
|
|
||||||
upx \
|
|
||||||
ninja \
|
|
||||||
cmake \
|
|
||||||
unzip \
|
|
||||||
mingw-w64-crt \
|
|
||||||
mingw-w64-winpthreads \
|
|
||||||
mingw-w64-gcc \
|
|
||||||
mingw-w64-headers \
|
|
||||||
mingw-w64-binutils \
|
|
||||||
ccache
|
|
||||||
RUN useradd user -m && echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
|
||||||
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay-bin.git --depth=1 && cd yay-bin && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
|
|
||||||
Vendored
-2191
File diff suppressed because it is too large
Load Diff
-360
@@ -1,360 +0,0 @@
|
|||||||
// dear imgui: Renderer for DirectX9
|
|
||||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
|
||||||
|
|
||||||
// Implemented features:
|
|
||||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
|
||||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
|
||||||
// https://github.com/ocornut/imgui
|
|
||||||
|
|
||||||
// CHANGELOG
|
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
|
||||||
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
|
||||||
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
|
||||||
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
|
||||||
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
|
|
||||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
|
||||||
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
|
|
||||||
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
|
||||||
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
|
|
||||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
|
||||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
|
||||||
|
|
||||||
#include "imgui_impl_dx9.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
// DirectX
|
|
||||||
#include <d3d9.h>
|
|
||||||
|
|
||||||
#include "imgui.h"
|
|
||||||
|
|
||||||
// allow std::min use
|
|
||||||
#ifdef min
|
|
||||||
#undef min
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// DirectX data
|
|
||||||
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
|
|
||||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
|
|
||||||
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
|
|
||||||
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
|
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
|
||||||
|
|
||||||
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
|
||||||
|
|
||||||
// Render function.
|
|
||||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
|
||||||
void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data) {
|
|
||||||
|
|
||||||
// Avoid rendering when minimized
|
|
||||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Create and grow buffers if needed
|
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) {
|
|
||||||
if (g_pVB) {
|
|
||||||
g_pVB->Release();
|
|
||||||
g_pVB = NULL;
|
|
||||||
}
|
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
|
||||||
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(ImDrawVert),
|
|
||||||
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX,
|
|
||||||
D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) {
|
|
||||||
if (g_pIB) {
|
|
||||||
g_pIB->Release();
|
|
||||||
g_pIB = NULL;
|
|
||||||
}
|
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
|
||||||
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx),
|
|
||||||
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
|
|
||||||
sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
|
|
||||||
D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backup the DX9 state
|
|
||||||
IDirect3DStateBlock9 *d3d9_state_block = NULL;
|
|
||||||
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
|
||||||
D3DMATRIX last_world, last_view, last_projection;
|
|
||||||
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
|
||||||
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
|
||||||
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
|
||||||
|
|
||||||
// Copy all vertices into a single contiguous buffer
|
|
||||||
ImDrawVert *vtx_dst;
|
|
||||||
ImDrawIdx *idx_dst;
|
|
||||||
if (g_pVB->Lock(0, (UINT) (draw_data->TotalVtxCount * sizeof(ImDrawVert)), (void **) &vtx_dst,
|
|
||||||
D3DLOCK_DISCARD) < 0)
|
|
||||||
return;
|
|
||||||
if (g_pIB->Lock(0, (UINT) (draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void **) &idx_dst,
|
|
||||||
D3DLOCK_DISCARD) < 0)
|
|
||||||
return;
|
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
|
||||||
const ImDrawList *cmd_list = draw_data->CmdLists[n];
|
|
||||||
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
|
||||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
|
||||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
|
||||||
idx_dst += cmd_list->IdxBuffer.Size;
|
|
||||||
}
|
|
||||||
g_pVB->Unlock();
|
|
||||||
g_pIB->Unlock();
|
|
||||||
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(ImDrawVert));
|
|
||||||
g_pd3dDevice->SetIndices(g_pIB);
|
|
||||||
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
|
||||||
|
|
||||||
// Setup viewport
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
vp.X = vp.Y = 0;
|
|
||||||
vp.Width = (DWORD) draw_data->DisplaySize.x;
|
|
||||||
vp.Height = (DWORD) draw_data->DisplaySize.y;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
g_pd3dDevice->SetViewport(&vp);
|
|
||||||
|
|
||||||
g_pd3dDevice->SetPixelShader(nullptr);
|
|
||||||
g_pd3dDevice->SetVertexShader(nullptr);
|
|
||||||
|
|
||||||
D3DCAPS9 caps {};
|
|
||||||
if (FAILED(g_pd3dDevice->GetDeviceCaps(&caps))) {
|
|
||||||
caps.NumSimultaneousRTs = 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDirect3DSurface9 *back_buffer = nullptr;
|
|
||||||
IDirect3DSurface9 *depth_stencil = nullptr;
|
|
||||||
IDirect3DSurface9 *render_targets[8];
|
|
||||||
|
|
||||||
// save all previous render target state
|
|
||||||
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
|
||||||
if (FAILED(g_pd3dDevice->GetRenderTarget(target, &render_targets[target]))) {
|
|
||||||
render_targets[target] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the previous depth stencil
|
|
||||||
if (FAILED(g_pd3dDevice->GetDepthStencilSurface(&depth_stencil))) {
|
|
||||||
depth_stencil = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the back buffer as the current render target
|
|
||||||
if (SUCCEEDED(g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer))) {
|
|
||||||
g_pd3dDevice->SetRenderTarget(0, back_buffer);
|
|
||||||
g_pd3dDevice->SetDepthStencilSurface(nullptr);
|
|
||||||
|
|
||||||
for (size_t target = 1; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
|
||||||
g_pd3dDevice->SetRenderTarget(target, nullptr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
back_buffer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
|
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
|
||||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
||||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
||||||
|
|
||||||
// Setup orthographic projection matrix
|
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
|
||||||
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
|
|
||||||
{
|
|
||||||
float L = draw_data->DisplayPos.x + 0.5f;
|
|
||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
|
||||||
float T = draw_data->DisplayPos.y + 0.5f;
|
|
||||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
|
||||||
D3DMATRIX mat_identity = {{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}};
|
|
||||||
D3DMATRIX mat_projection =
|
|
||||||
{{{
|
|
||||||
2.0f / (R - L), 0.0f, 0.0f, 0.0f,
|
|
||||||
0.0f, 2.0f / (T - B), 0.0f, 0.0f,
|
|
||||||
0.0f, 0.0f, 0.5f, 0.0f,
|
|
||||||
(L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
|
|
||||||
}}};
|
|
||||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
|
||||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
|
||||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render command lists
|
|
||||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
|
||||||
int global_vtx_offset = 0;
|
|
||||||
int global_idx_offset = 0;
|
|
||||||
ImVec2 clip_off = draw_data->DisplayPos;
|
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
|
||||||
const ImDrawList *cmd_list = draw_data->CmdLists[n];
|
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
|
|
||||||
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
|
|
||||||
if (pcmd->UserCallback != NULL) {
|
|
||||||
pcmd->UserCallback(cmd_list, pcmd);
|
|
||||||
} else {
|
|
||||||
const RECT r = {(LONG) (pcmd->ClipRect.x - clip_off.x), (LONG) (pcmd->ClipRect.y - clip_off.y),
|
|
||||||
(LONG) (pcmd->ClipRect.z - clip_off.x), (LONG) (pcmd->ClipRect.w - clip_off.y)};
|
|
||||||
auto texture = reinterpret_cast<IDirect3DBaseTexture9 *>(pcmd->TextureId);
|
|
||||||
g_pd3dDevice->SetTexture(0, texture);
|
|
||||||
g_pd3dDevice->SetScissorRect(&r);
|
|
||||||
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
|
|
||||||
pcmd->VtxOffset + global_vtx_offset, 0,
|
|
||||||
(UINT) cmd_list->VtxBuffer.Size,
|
|
||||||
pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
|
||||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (back_buffer) {
|
|
||||||
back_buffer->Release();
|
|
||||||
back_buffer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore previous depth stencil
|
|
||||||
if (depth_stencil) {
|
|
||||||
g_pd3dDevice->SetDepthStencilSurface(depth_stencil);
|
|
||||||
depth_stencil->Release();
|
|
||||||
depth_stencil = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore all render target state
|
|
||||||
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
|
||||||
auto render_target = render_targets[target];
|
|
||||||
|
|
||||||
if (render_target) {
|
|
||||||
g_pd3dDevice->SetRenderTarget(target, render_target);
|
|
||||||
render_target->Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore the DX9 transform
|
|
||||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
|
||||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
|
||||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
|
||||||
|
|
||||||
// restore the DX9 state
|
|
||||||
d3d9_state_block->Apply();
|
|
||||||
d3d9_state_block->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device) {
|
|
||||||
|
|
||||||
// Setup back-end capabilities flags
|
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
io.BackendRendererName = "imgui_impl_dx9";
|
|
||||||
|
|
||||||
// We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
|
||||||
|
|
||||||
g_pd3dDevice = device;
|
|
||||||
g_pd3dDevice->AddRef();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplDX9_Shutdown() {
|
|
||||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
|
||||||
|
|
||||||
if (g_pd3dDevice) {
|
|
||||||
g_pd3dDevice->Release();
|
|
||||||
g_pd3dDevice = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ImGui_ImplDX9_CreateFontsTexture() {
|
|
||||||
// Build texture atlas
|
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
|
||||||
unsigned char *pixels;
|
|
||||||
int width, height, bytes_per_pixel;
|
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
|
||||||
|
|
||||||
// Upload texture to graphics system
|
|
||||||
g_FontTexture = NULL;
|
|
||||||
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
|
|
||||||
D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
|
|
||||||
return false;
|
|
||||||
D3DLOCKED_RECT tex_locked_rect;
|
|
||||||
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
|
||||||
return false;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
memcpy((unsigned char *) tex_locked_rect.pBits + tex_locked_rect.Pitch * y,
|
|
||||||
pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
|
|
||||||
g_FontTexture->UnlockRect(0);
|
|
||||||
|
|
||||||
// Store our identifier
|
|
||||||
io.Fonts->TexID = (ImTextureID) g_FontTexture;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImGui_ImplDX9_CreateDeviceObjects() {
|
|
||||||
if (!g_pd3dDevice) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ImGui_ImplDX9_CreateFontsTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplDX9_InvalidateDeviceObjects() {
|
|
||||||
if (!g_pd3dDevice)
|
|
||||||
return;
|
|
||||||
if (g_pVB) {
|
|
||||||
g_pVB->Release();
|
|
||||||
g_pVB = NULL;
|
|
||||||
}
|
|
||||||
if (g_pIB) {
|
|
||||||
g_pIB->Release();
|
|
||||||
g_pIB = NULL;
|
|
||||||
}
|
|
||||||
if (g_FontTexture) {
|
|
||||||
g_FontTexture->Release();
|
|
||||||
g_FontTexture = NULL;
|
|
||||||
ImGui::GetIO().Fonts->TexID = 0;
|
|
||||||
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplDX9_NewFrame() {
|
|
||||||
if (!g_FontTexture) {
|
|
||||||
ImGui_ImplDX9_CreateDeviceObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
IDirect3DSwapChain9 *swap_chain = nullptr;
|
|
||||||
if (SUCCEEDED(g_pd3dDevice->GetSwapChain(0, &swap_chain))) {
|
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
|
|
||||||
D3DPRESENT_PARAMETERS present_params {};
|
|
||||||
|
|
||||||
if (SUCCEEDED(swap_chain->GetPresentParameters(&present_params))) {
|
|
||||||
if (present_params.BackBufferWidth != 0 && present_params.BackBufferHeight != 0) {
|
|
||||||
io.DisplaySize.x = static_cast<float>(present_params.BackBufferWidth);
|
|
||||||
io.DisplaySize.y = static_cast<float>(present_params.BackBufferHeight);
|
|
||||||
} else {
|
|
||||||
RECT rect {};
|
|
||||||
GetClientRect(present_params.hDeviceWindow, &rect);
|
|
||||||
|
|
||||||
io.DisplaySize.x = static_cast<float>(rect.right - rect.left);
|
|
||||||
io.DisplaySize.y = static_cast<float>(rect.bottom - rect.top);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
swap_chain->Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-25
@@ -1,25 +0,0 @@
|
|||||||
// dear imgui: Renderer for DirectX9
|
|
||||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
|
||||||
|
|
||||||
// Implemented features:
|
|
||||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
|
||||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
|
||||||
// https://github.com/ocornut/imgui
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "imgui.h"
|
|
||||||
|
|
||||||
struct IDirect3DDevice9;
|
|
||||||
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device);
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data);
|
|
||||||
|
|
||||||
// Use if you want to reset your rendering device without losing ImGui state.
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
|
||||||
Vendored
-4693
File diff suppressed because it is too large
Load Diff
Vendored
-10
@@ -1,10 +0,0 @@
|
|||||||
zlib License
|
|
||||||
|
|
||||||
Copyright (c) 2011-2016 Stephan Brumme
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
|
||||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
|
||||||
If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
Vendored
-665
@@ -1,665 +0,0 @@
|
|||||||
// //////////////////////////////////////////////////////////
|
|
||||||
// toojpeg.cpp
|
|
||||||
// written by Stephan Brumme, 2018-2019
|
|
||||||
// see https://create.stephan-brumme.com/toojpeg/
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "toojpeg.h"
|
|
||||||
|
|
||||||
// - the "official" specifications: https://www.w3.org/Graphics/JPEG/itu-t81.pdf and https://www.w3.org/Graphics/JPEG/jfif3.pdf
|
|
||||||
// - Wikipedia has a short description of the JFIF/JPEG file format: https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format
|
|
||||||
// - the popular STB Image library includes Jon's JPEG encoder as well: https://github.com/nothings/stb/blob/master/stb_image_write.h
|
|
||||||
// - the most readable JPEG book (from a developer's perspective) is Miano's "Compressed Image File Formats" (1999, ISBN 0-201-60443-4),
|
|
||||||
// used copies are really cheap nowadays and include a CD with C++ sources as well (plus great format descriptions of GIF & PNG)
|
|
||||||
// - much more detailled is Mitchell/Pennebaker's "JPEG: Still Image Data Compression Standard" (1993, ISBN 0-442-01272-1)
|
|
||||||
// which contains the official JPEG standard, too - fun fact: I bought a signed copy in a second-hand store without noticing
|
|
||||||
|
|
||||||
namespace // anonymous namespace to hide local functions / constants / etc.
|
|
||||||
{
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// data types
|
|
||||||
using uint8_t = unsigned char;
|
|
||||||
using uint16_t = unsigned short;
|
|
||||||
using int16_t = short;
|
|
||||||
using int32_t = int; // at least four bytes
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// constants
|
|
||||||
|
|
||||||
// quantization tables from JPEG Standard, Annex K
|
|
||||||
const uint8_t DefaultQuantLuminance[8*8] =
|
|
||||||
{ 16, 11, 10, 16, 24, 40, 51, 61, // there are a few experts proposing slightly more efficient values,
|
|
||||||
12, 12, 14, 19, 26, 58, 60, 55, // e.g. https://www.imagemagick.org/discourse-server/viewtopic.php?t=20333
|
|
||||||
14, 13, 16, 24, 40, 57, 69, 56, // btw: Google's Guetzli project optimizes the quantization tables per image
|
|
||||||
14, 17, 22, 29, 51, 87, 80, 62,
|
|
||||||
18, 22, 37, 56, 68,109,103, 77,
|
|
||||||
24, 35, 55, 64, 81,104,113, 92,
|
|
||||||
49, 64, 78, 87,103,121,120,101,
|
|
||||||
72, 92, 95, 98,112,100,103, 99 };
|
|
||||||
const uint8_t DefaultQuantChrominance[8*8] =
|
|
||||||
{ 17, 18, 24, 47, 99, 99, 99, 99,
|
|
||||||
18, 21, 26, 66, 99, 99, 99, 99,
|
|
||||||
24, 26, 56, 99, 99, 99, 99, 99,
|
|
||||||
47, 66, 99, 99, 99, 99, 99, 99,
|
|
||||||
99, 99, 99, 99, 99, 99, 99, 99,
|
|
||||||
99, 99, 99, 99, 99, 99, 99, 99,
|
|
||||||
99, 99, 99, 99, 99, 99, 99, 99,
|
|
||||||
99, 99, 99, 99, 99, 99, 99, 99 };
|
|
||||||
|
|
||||||
// 8x8 blocks are processed in zig-zag order
|
|
||||||
// most encoders use a zig-zag "forward" table, I switched to its inverse for performance reasons
|
|
||||||
// note: ZigZagInv[ZigZag[i]] = i
|
|
||||||
const uint8_t ZigZagInv[8*8] =
|
|
||||||
{ 0, 1, 8,16, 9, 2, 3,10, // ZigZag[] = 0, 1, 5, 6,14,15,27,28,
|
|
||||||
17,24,32,25,18,11, 4, 5, // 2, 4, 7,13,16,26,29,42,
|
|
||||||
12,19,26,33,40,48,41,34, // 3, 8,12,17,25,30,41,43,
|
|
||||||
27,20,13, 6, 7,14,21,28, // 9,11,18,24,31,40,44,53,
|
|
||||||
35,42,49,56,57,50,43,36, // 10,19,23,32,39,45,52,54,
|
|
||||||
29,22,15,23,30,37,44,51, // 20,22,33,38,46,51,55,60,
|
|
||||||
58,59,52,45,38,31,39,46, // 21,34,37,47,50,56,59,61,
|
|
||||||
53,60,61,54,47,55,62,63 }; // 35,36,48,49,57,58,62,63
|
|
||||||
|
|
||||||
// static Huffman code tables from JPEG standard Annex K
|
|
||||||
// - CodesPerBitsize tables define how many Huffman codes will have a certain bitsize (plus 1 because there nothing with zero bits),
|
|
||||||
// e.g. DcLuminanceCodesPerBitsize[2] = 5 because there are 5 Huffman codes being 2+1=3 bits long
|
|
||||||
// - Values tables are a list of values ordered by their Huffman code bitsize,
|
|
||||||
// e.g. AcLuminanceValues => Huffman(0x01,0x02 and 0x03) will have 2 bits, Huffman(0x00) will have 3 bits, Huffman(0x04,0x11 and 0x05) will have 4 bits, ...
|
|
||||||
|
|
||||||
// Huffman definitions for first DC/AC tables (luminance / Y channel)
|
|
||||||
const uint8_t DcLuminanceCodesPerBitsize[16] = { 0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 }; // sum = 12
|
|
||||||
const uint8_t DcLuminanceValues [12] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; // => 12 codes
|
|
||||||
const uint8_t AcLuminanceCodesPerBitsize[16] = { 0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,125 }; // sum = 162
|
|
||||||
const uint8_t AcLuminanceValues [162] = // => 162 codes
|
|
||||||
{ 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08, // 16*10+2 symbols because
|
|
||||||
0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24,0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28, // upper 4 bits can be 0..F
|
|
||||||
0x29,0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59, // while lower 4 bits can be 1..A
|
|
||||||
0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89, // plus two special codes 0x00 and 0xF0
|
|
||||||
0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6, // order of these symbols was determined empirically by JPEG committee
|
|
||||||
0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,
|
|
||||||
0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA };
|
|
||||||
// Huffman definitions for second DC/AC tables (chrominance / Cb and Cr channels)
|
|
||||||
const uint8_t DcChrominanceCodesPerBitsize[16] = { 0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; // sum = 12
|
|
||||||
const uint8_t DcChrominanceValues [12] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; // => 12 codes (identical to DcLuminanceValues)
|
|
||||||
const uint8_t AcChrominanceCodesPerBitsize[16] = { 0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,119 }; // sum = 162
|
|
||||||
const uint8_t AcChrominanceValues [162] = // => 162 codes
|
|
||||||
{ 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, // same number of symbol, just different order
|
|
||||||
0xA1,0xB1,0xC1,0x09,0x23,0x33,0x52,0xF0,0x15,0x62,0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,0x1A,0x26, // (which is more efficient for AC coding)
|
|
||||||
0x27,0x28,0x29,0x2A,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,0x57,0x58,
|
|
||||||
0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x82,0x83,0x84,0x85,0x86,0x87,
|
|
||||||
0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,
|
|
||||||
0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,
|
|
||||||
0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA };
|
|
||||||
const int16_t CodeWordLimit = 2048; // +/-2^11, maximum value after DCT
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// structs
|
|
||||||
|
|
||||||
// represent a single Huffman code
|
|
||||||
struct BitCode
|
|
||||||
{
|
|
||||||
BitCode() = default; // undefined state, must be initialized at a later time
|
|
||||||
BitCode(uint16_t code_, uint8_t numBits_)
|
|
||||||
: code(code_), numBits(numBits_) {}
|
|
||||||
uint16_t code; // JPEG's Huffman codes are limited to 16 bits
|
|
||||||
uint8_t numBits; // number of valid bits
|
|
||||||
};
|
|
||||||
|
|
||||||
// wrapper for bit output operations
|
|
||||||
struct BitWriter
|
|
||||||
{
|
|
||||||
// user-supplied callback that writes/stores one byte
|
|
||||||
TooJpeg::WRITE_ONE_BYTE output;
|
|
||||||
// initialize writer
|
|
||||||
explicit BitWriter(TooJpeg::WRITE_ONE_BYTE output_) : output(output_) {}
|
|
||||||
|
|
||||||
// store the most recently encoded bits that are not written yet
|
|
||||||
struct BitBuffer
|
|
||||||
{
|
|
||||||
int32_t data = 0; // actually only at most 24 bits are used
|
|
||||||
uint8_t numBits = 0; // number of valid bits (the right-most bits)
|
|
||||||
} buffer;
|
|
||||||
|
|
||||||
// write Huffman bits stored in BitCode, keep excess bits in BitBuffer
|
|
||||||
BitWriter& operator<<(const BitCode& data)
|
|
||||||
{
|
|
||||||
// append the new bits to those bits leftover from previous call(s)
|
|
||||||
buffer.numBits += data.numBits;
|
|
||||||
buffer.data <<= data.numBits;
|
|
||||||
buffer.data |= data.code;
|
|
||||||
|
|
||||||
// write all "full" bytes
|
|
||||||
while (buffer.numBits >= 8)
|
|
||||||
{
|
|
||||||
// extract highest 8 bits
|
|
||||||
buffer.numBits -= 8;
|
|
||||||
auto oneByte = uint8_t(buffer.data >> buffer.numBits);
|
|
||||||
output(oneByte);
|
|
||||||
|
|
||||||
if (oneByte == 0xFF) // 0xFF has a special meaning for JPEGs (it's a block marker)
|
|
||||||
output(0); // therefore pad a zero to indicate "nope, this one ain't a marker, it's just a coincidence"
|
|
||||||
|
|
||||||
// note: I don't clear those written bits, therefore buffer.bits may contain garbage in the high bits
|
|
||||||
// if you really want to "clean up" (e.g. for debugging purposes) then uncomment the following line
|
|
||||||
//buffer.bits &= (1 << buffer.numBits) - 1;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write all non-yet-written bits, fill gaps with 1s (that's a strange JPEG thing)
|
|
||||||
void flush()
|
|
||||||
{
|
|
||||||
// at most seven set bits needed to "fill" the last byte: 0x7F = binary 0111 1111
|
|
||||||
*this << BitCode(0x7F, 7); // I should set buffer.numBits = 0 but since there are no single bits written after flush() I can safely ignore it
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: all the following BitWriter functions IGNORE the BitBuffer and write straight to output !
|
|
||||||
// write a single byte
|
|
||||||
BitWriter& operator<<(uint8_t oneByte)
|
|
||||||
{
|
|
||||||
output(oneByte);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write an array of bytes
|
|
||||||
template <typename T, int Size>
|
|
||||||
BitWriter& operator<<(T (&manyBytes)[Size])
|
|
||||||
{
|
|
||||||
for (auto c : manyBytes)
|
|
||||||
output(c);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// start a new JFIF block
|
|
||||||
void addMarker(uint8_t id, uint16_t length)
|
|
||||||
{
|
|
||||||
output(0xFF); output(id); // ID, always preceded by 0xFF
|
|
||||||
output(uint8_t(length >> 8)); // length of the block (big-endian, includes the 2 length bytes as well)
|
|
||||||
output(uint8_t(length & 0xFF));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// functions / templates
|
|
||||||
|
|
||||||
// same as std::min()
|
|
||||||
template <typename Number>
|
|
||||||
Number minimum(Number value, Number maximum)
|
|
||||||
{
|
|
||||||
return value <= maximum ? value : maximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// restrict a value to the interval [minimum, maximum]
|
|
||||||
template <typename Number, typename Limit>
|
|
||||||
Number clamp(Number value, Limit minValue, Limit maxValue)
|
|
||||||
{
|
|
||||||
if (value <= minValue) return minValue; // never smaller than the minimum
|
|
||||||
if (value >= maxValue) return maxValue; // never bigger than the maximum
|
|
||||||
return value; // value was inside interval, keep it
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert from RGB to YCbCr, constants are similar to ITU-R, see https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion
|
|
||||||
float rgb2y (float r, float g, float b) { return +0.299f * r +0.587f * g +0.114f * b; }
|
|
||||||
float rgb2cb(float r, float g, float b) { return -0.16874f * r -0.33126f * g +0.5f * b; }
|
|
||||||
float rgb2cr(float r, float g, float b) { return +0.5f * r -0.41869f * g -0.08131f * b; }
|
|
||||||
|
|
||||||
// forward DCT computation "in one dimension" (fast AAN algorithm by Arai, Agui and Nakajima: "A fast DCT-SQ scheme for images")
|
|
||||||
void DCT(float block[8*8], uint8_t stride) // stride must be 1 (=horizontal) or 8 (=vertical)
|
|
||||||
{
|
|
||||||
const auto SqrtHalfSqrt = 1.306562965f; // sqrt((2 + sqrt(2)) / 2) = cos(pi * 1 / 8) * sqrt(2)
|
|
||||||
const auto InvSqrt = 0.707106781f; // 1 / sqrt(2) = cos(pi * 2 / 8)
|
|
||||||
const auto HalfSqrtSqrt = 0.382683432f; // sqrt(2 - sqrt(2)) / 2 = cos(pi * 3 / 8)
|
|
||||||
const auto InvSqrtSqrt = 0.541196100f; // 1 / sqrt(2 - sqrt(2)) = cos(pi * 3 / 8) * sqrt(2)
|
|
||||||
|
|
||||||
// modify in-place
|
|
||||||
auto& block0 = block[0 ];
|
|
||||||
auto& block1 = block[1 * stride];
|
|
||||||
auto& block2 = block[2 * stride];
|
|
||||||
auto& block3 = block[3 * stride];
|
|
||||||
auto& block4 = block[4 * stride];
|
|
||||||
auto& block5 = block[5 * stride];
|
|
||||||
auto& block6 = block[6 * stride];
|
|
||||||
auto& block7 = block[7 * stride];
|
|
||||||
|
|
||||||
// based on https://dev.w3.org/Amaya/libjpeg/jfdctflt.c , the original variable names can be found in my comments
|
|
||||||
auto add07 = block0 + block7; auto sub07 = block0 - block7; // tmp0, tmp7
|
|
||||||
auto add16 = block1 + block6; auto sub16 = block1 - block6; // tmp1, tmp6
|
|
||||||
auto add25 = block2 + block5; auto sub25 = block2 - block5; // tmp2, tmp5
|
|
||||||
auto add34 = block3 + block4; auto sub34 = block3 - block4; // tmp3, tmp4
|
|
||||||
|
|
||||||
auto add0347 = add07 + add34; auto sub07_34 = add07 - add34; // tmp10, tmp13 ("even part" / "phase 2")
|
|
||||||
auto add1256 = add16 + add25; auto sub16_25 = add16 - add25; // tmp11, tmp12
|
|
||||||
|
|
||||||
block0 = add0347 + add1256; block4 = add0347 - add1256; // "phase 3"
|
|
||||||
|
|
||||||
auto z1 = (sub16_25 + sub07_34) * InvSqrt; // all temporary z-variables kept their original names
|
|
||||||
block2 = sub07_34 + z1; block6 = sub07_34 - z1; // "phase 5"
|
|
||||||
|
|
||||||
auto sub23_45 = sub25 + sub34; // tmp10 ("odd part" / "phase 2")
|
|
||||||
auto sub12_56 = sub16 + sub25; // tmp11
|
|
||||||
auto sub01_67 = sub16 + sub07; // tmp12
|
|
||||||
|
|
||||||
auto z5 = (sub23_45 - sub01_67) * HalfSqrtSqrt;
|
|
||||||
auto z2 = sub23_45 * InvSqrtSqrt + z5;
|
|
||||||
auto z3 = sub12_56 * InvSqrt;
|
|
||||||
auto z4 = sub01_67 * SqrtHalfSqrt + z5;
|
|
||||||
auto z6 = sub07 + z3; // z11 ("phase 5")
|
|
||||||
auto z7 = sub07 - z3; // z13
|
|
||||||
block1 = z6 + z4; block7 = z6 - z4; // "phase 6"
|
|
||||||
block5 = z7 + z2; block3 = z7 - z2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// run DCT, quantize and write Huffman bit codes
|
|
||||||
int16_t encodeBlock(BitWriter& writer, float block[8][8], const float scaled[8*8], int16_t lastDC,
|
|
||||||
const BitCode huffmanDC[256], const BitCode huffmanAC[256], const BitCode* codewords)
|
|
||||||
{
|
|
||||||
// "linearize" the 8x8 block, treat it as a flat array of 64 floats
|
|
||||||
auto block64 = (float*) block;
|
|
||||||
|
|
||||||
// DCT: rows
|
|
||||||
for (auto offset = 0; offset < 8; offset++)
|
|
||||||
DCT(block64 + offset*8, 1);
|
|
||||||
// DCT: columns
|
|
||||||
for (auto offset = 0; offset < 8; offset++)
|
|
||||||
DCT(block64 + offset*1, 8);
|
|
||||||
|
|
||||||
// scale
|
|
||||||
for (auto i = 0; i < 8*8; i++)
|
|
||||||
block64[i] *= scaled[i];
|
|
||||||
|
|
||||||
// encode DC (the first coefficient is the "average color" of the 8x8 block)
|
|
||||||
auto DC = int(block64[0] + (block64[0] >= 0 ? +0.5f : -0.5f)); // C++11's nearbyint() achieves a similar effect
|
|
||||||
|
|
||||||
// quantize and zigzag the other 63 coefficients
|
|
||||||
auto posNonZero = 0; // find last coefficient which is not zero (because trailing zeros are encoded differently)
|
|
||||||
int16_t quantized[8*8];
|
|
||||||
for (auto i = 1; i < 8*8; i++) // start at 1 because block64[0]=DC was already processed
|
|
||||||
{
|
|
||||||
auto value = block64[ZigZagInv[i]];
|
|
||||||
// round to nearest integer
|
|
||||||
quantized[i] = int(value + (value >= 0 ? +0.5f : -0.5f)); // C++11's nearbyint() achieves a similar effect
|
|
||||||
// remember offset of last non-zero coefficient
|
|
||||||
if (quantized[i] != 0)
|
|
||||||
posNonZero = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// same "average color" as previous block ?
|
|
||||||
auto diff = DC - lastDC;
|
|
||||||
if (diff == 0)
|
|
||||||
writer << huffmanDC[0x00]; // yes, write a special short symbol
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto bits = codewords[diff]; // nope, encode the difference to previous block's average color
|
|
||||||
writer << huffmanDC[bits.numBits] << bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode ACs (quantized[1..63])
|
|
||||||
auto offset = 0; // upper 4 bits count the number of consecutive zeros
|
|
||||||
for (auto i = 1; i <= posNonZero; i++) // quantized[0] was already written, skip all trailing zeros, too
|
|
||||||
{
|
|
||||||
// zeros are encoded in a special way
|
|
||||||
while (quantized[i] == 0) // found another zero ?
|
|
||||||
{
|
|
||||||
offset += 0x10; // add 1 to the upper 4 bits
|
|
||||||
// split into blocks of at most 16 consecutive zeros
|
|
||||||
if (offset > 0xF0) // remember, the counter is in the upper 4 bits, 0xF = 15
|
|
||||||
{
|
|
||||||
writer << huffmanAC[0xF0]; // 0xF0 is a special code for "16 zeros"
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto encoded = codewords[quantized[i]];
|
|
||||||
// combine number of zeros with the number of bits of the next non-zero value
|
|
||||||
writer << huffmanAC[offset + encoded.numBits] << encoded; // and the value itself
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send end-of-block code (0x00), only needed if there are trailing zeros
|
|
||||||
if (posNonZero < 8*8 - 1) // = 63
|
|
||||||
writer << huffmanAC[0x00];
|
|
||||||
|
|
||||||
return DC;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jon's code includes the pre-generated Huffman codes
|
|
||||||
// I don't like these "magic constants" and compute them on my own :-)
|
|
||||||
void generateHuffmanTable(const uint8_t numCodes[16], const uint8_t* values, BitCode result[256])
|
|
||||||
{
|
|
||||||
// process all bitsizes 1 thru 16, no JPEG Huffman code is allowed to exceed 16 bits
|
|
||||||
auto huffmanCode = 0;
|
|
||||||
for (auto numBits = 1; numBits <= 16; numBits++)
|
|
||||||
{
|
|
||||||
// ... and each code of these bitsizes
|
|
||||||
for (auto i = 0; i < numCodes[numBits - 1]; i++) // note: numCodes array starts at zero, but smallest bitsize is 1
|
|
||||||
result[*values++] = BitCode(huffmanCode++, numBits);
|
|
||||||
|
|
||||||
// next Huffman code needs to be one bit wider
|
|
||||||
huffmanCode <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end of anonymous namespace
|
|
||||||
|
|
||||||
// -------------------- externally visible code --------------------
|
|
||||||
|
|
||||||
namespace TooJpeg
|
|
||||||
{
|
|
||||||
// the only exported function ...
|
|
||||||
bool writeJpeg(WRITE_ONE_BYTE output, const void* pixels_, unsigned short width, unsigned short height,
|
|
||||||
bool isRGB, unsigned char quality_, bool downsample, const char* comment)
|
|
||||||
{
|
|
||||||
// reject invalid pointers
|
|
||||||
if (output == nullptr || pixels_ == nullptr)
|
|
||||||
return false;
|
|
||||||
// check image format
|
|
||||||
if (width == 0 || height == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// number of components
|
|
||||||
const auto numComponents = isRGB ? 3 : 1;
|
|
||||||
// note: if there is just one component (=grayscale), then only luminance needs to be stored in the file
|
|
||||||
// thus everything related to chrominance need not to be written to the JPEG
|
|
||||||
// I still compute a few things, like quantization tables to avoid a complete code mess
|
|
||||||
|
|
||||||
// grayscale images can't be downsampled (because there are no Cb + Cr channels)
|
|
||||||
if (!isRGB)
|
|
||||||
downsample = false;
|
|
||||||
|
|
||||||
// wrapper for all output operations
|
|
||||||
BitWriter bitWriter(output);
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// JFIF headers
|
|
||||||
const uint8_t HeaderJfif[2+2+16] =
|
|
||||||
{ 0xFF,0xD8, // SOI marker (start of image)
|
|
||||||
0xFF,0xE0, // JFIF APP0 tag
|
|
||||||
0,16, // length: 16 bytes (14 bytes payload + 2 bytes for this length field)
|
|
||||||
'J','F','I','F',0, // JFIF identifier, zero-terminated
|
|
||||||
1,1, // JFIF version 1.1
|
|
||||||
0, // no density units specified
|
|
||||||
0,1,0,1, // density: 1 pixel "per pixel" horizontally and vertically
|
|
||||||
0,0 }; // no thumbnail (size 0 x 0)
|
|
||||||
bitWriter << HeaderJfif;
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// comment (optional)
|
|
||||||
if (comment != nullptr)
|
|
||||||
{
|
|
||||||
// look for zero terminator
|
|
||||||
auto length = 0; // = strlen(comment);
|
|
||||||
while (comment[length] != 0)
|
|
||||||
length++;
|
|
||||||
|
|
||||||
// write COM marker
|
|
||||||
bitWriter.addMarker(0xFE, 2+length); // block size is number of bytes (without zero terminator) + 2 bytes for this length field
|
|
||||||
// ... and write the comment itself
|
|
||||||
for (auto i = 0; i < length; i++)
|
|
||||||
bitWriter << comment[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// adjust quantization tables to desired quality
|
|
||||||
|
|
||||||
// quality level must be in 1 ... 100
|
|
||||||
auto quality = clamp<uint16_t>(quality_, 1, 100);
|
|
||||||
// convert to an internal JPEG quality factor, formula taken from libjpeg
|
|
||||||
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
|
|
||||||
|
|
||||||
uint8_t quantLuminance [8*8];
|
|
||||||
uint8_t quantChrominance[8*8];
|
|
||||||
for (auto i = 0; i < 8*8; i++)
|
|
||||||
{
|
|
||||||
int luminance = (DefaultQuantLuminance [ZigZagInv[i]] * quality + 50) / 100;
|
|
||||||
int chrominance = (DefaultQuantChrominance[ZigZagInv[i]] * quality + 50) / 100;
|
|
||||||
|
|
||||||
// clamp to 1..255
|
|
||||||
quantLuminance [i] = clamp(luminance, 1, 255);
|
|
||||||
quantChrominance[i] = clamp(chrominance, 1, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write quantization tables
|
|
||||||
bitWriter.addMarker(0xDB, 2 + (isRGB ? 2 : 1) * (1 + 8*8)); // length: 65 bytes per table + 2 bytes for this length field
|
|
||||||
// each table has 64 entries and is preceded by an ID byte
|
|
||||||
|
|
||||||
bitWriter << 0x00 << quantLuminance; // first quantization table
|
|
||||||
if (isRGB)
|
|
||||||
bitWriter << 0x01 << quantChrominance; // second quantization table, only relevant for color images
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// write image infos (SOF0 - start of frame)
|
|
||||||
bitWriter.addMarker(0xC0, 2+6+3*numComponents); // length: 6 bytes general info + 3 per channel + 2 bytes for this length field
|
|
||||||
|
|
||||||
// 8 bits per channel
|
|
||||||
bitWriter << 0x08
|
|
||||||
// image dimensions (big-endian)
|
|
||||||
<< (height >> 8) << (height & 0xFF)
|
|
||||||
<< (width >> 8) << (width & 0xFF);
|
|
||||||
|
|
||||||
// sampling and quantization tables for each component
|
|
||||||
bitWriter << numComponents; // 1 component (grayscale, Y only) or 3 components (Y,Cb,Cr)
|
|
||||||
for (auto id = 1; id <= numComponents; id++)
|
|
||||||
bitWriter << id // component ID (Y=1, Cb=2, Cr=3)
|
|
||||||
// bitmasks for sampling: highest 4 bits: horizontal, lowest 4 bits: vertical
|
|
||||||
<< (id == 1 && downsample ? 0x22 : 0x11) // 0x11 is default YCbCr 4:4:4 and 0x22 stands for YCbCr 4:2:0
|
|
||||||
<< (id == 1 ? 0 : 1); // use quantization table 0 for Y, table 1 for Cb and Cr
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// Huffman tables
|
|
||||||
// DHT marker - define Huffman tables
|
|
||||||
bitWriter.addMarker(0xC4, isRGB ? (2+208+208) : (2+208));
|
|
||||||
// 2 bytes for the length field, store chrominance only if needed
|
|
||||||
// 1+16+12 for the DC luminance
|
|
||||||
// 1+16+162 for the AC luminance (208 = 1+16+12 + 1+16+162)
|
|
||||||
// 1+16+12 for the DC chrominance
|
|
||||||
// 1+16+162 for the AC chrominance (208 = 1+16+12 + 1+16+162, same as above)
|
|
||||||
|
|
||||||
// store luminance's DC+AC Huffman table definitions
|
|
||||||
bitWriter << 0x00 // highest 4 bits: 0 => DC, lowest 4 bits: 0 => Y (baseline)
|
|
||||||
<< DcLuminanceCodesPerBitsize
|
|
||||||
<< DcLuminanceValues;
|
|
||||||
bitWriter << 0x10 // highest 4 bits: 1 => AC, lowest 4 bits: 0 => Y (baseline)
|
|
||||||
<< AcLuminanceCodesPerBitsize
|
|
||||||
<< AcLuminanceValues;
|
|
||||||
|
|
||||||
// compute actual Huffman code tables (see Jon's code for precalculated tables)
|
|
||||||
BitCode huffmanLuminanceDC[256];
|
|
||||||
BitCode huffmanLuminanceAC[256];
|
|
||||||
generateHuffmanTable(DcLuminanceCodesPerBitsize, DcLuminanceValues, huffmanLuminanceDC);
|
|
||||||
generateHuffmanTable(AcLuminanceCodesPerBitsize, AcLuminanceValues, huffmanLuminanceAC);
|
|
||||||
|
|
||||||
// chrominance is only relevant for color images
|
|
||||||
BitCode huffmanChrominanceDC[256];
|
|
||||||
BitCode huffmanChrominanceAC[256];
|
|
||||||
if (isRGB)
|
|
||||||
{
|
|
||||||
// store luminance's DC+AC Huffman table definitions
|
|
||||||
bitWriter << 0x01 // highest 4 bits: 0 => DC, lowest 4 bits: 1 => Cr,Cb (baseline)
|
|
||||||
<< DcChrominanceCodesPerBitsize
|
|
||||||
<< DcChrominanceValues;
|
|
||||||
bitWriter << 0x11 // highest 4 bits: 1 => AC, lowest 4 bits: 1 => Cr,Cb (baseline)
|
|
||||||
<< AcChrominanceCodesPerBitsize
|
|
||||||
<< AcChrominanceValues;
|
|
||||||
|
|
||||||
// compute actual Huffman code tables (see Jon's code for precalculated tables)
|
|
||||||
generateHuffmanTable(DcChrominanceCodesPerBitsize, DcChrominanceValues, huffmanChrominanceDC);
|
|
||||||
generateHuffmanTable(AcChrominanceCodesPerBitsize, AcChrominanceValues, huffmanChrominanceAC);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// start of scan (there is only a single scan for baseline JPEGs)
|
|
||||||
bitWriter.addMarker(0xDA, 2+1+2*numComponents+3); // 2 bytes for the length field, 1 byte for number of components,
|
|
||||||
// then 2 bytes for each component and 3 bytes for spectral selection
|
|
||||||
|
|
||||||
// assign Huffman tables to each component
|
|
||||||
bitWriter << numComponents;
|
|
||||||
for (auto id = 1; id <= numComponents; id++)
|
|
||||||
// highest 4 bits: DC Huffman table, lowest 4 bits: AC Huffman table
|
|
||||||
bitWriter << id << (id == 1 ? 0x00 : 0x11); // Y: tables 0 for DC and AC; Cb + Cr: tables 1 for DC and AC
|
|
||||||
|
|
||||||
// constant values for our baseline JPEGs (which have a single sequential scan)
|
|
||||||
static const uint8_t Spectral[3] = { 0, 63, 0 }; // spectral selection: must be from 0 to 63; successive approximation must be 0
|
|
||||||
bitWriter << Spectral;
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// adjust quantization tables with AAN scaling factors to simplify DCT
|
|
||||||
float scaledLuminance [8*8];
|
|
||||||
float scaledChrominance[8*8];
|
|
||||||
for (auto i = 0; i < 8*8; i++)
|
|
||||||
{
|
|
||||||
auto row = ZigZagInv[i] / 8; // same as ZigZagInv[i] >> 3
|
|
||||||
auto column = ZigZagInv[i] % 8; // same as ZigZagInv[i] & 7
|
|
||||||
|
|
||||||
// scaling constants for AAN DCT algorithm: AanScaleFactors[0] = 1, AanScaleFactors[k=1..7] = cos(k*PI/16) * sqrt(2)
|
|
||||||
static const float AanScaleFactors[8] = { 1, 1.387039845f, 1.306562965f, 1.175875602f, 1, 0.785694958f, 0.541196100f, 0.275899379f };
|
|
||||||
auto factor = 1 / (AanScaleFactors[row] * AanScaleFactors[column] * 8);
|
|
||||||
scaledLuminance [ZigZagInv[i]] = factor / quantLuminance [i];
|
|
||||||
scaledChrominance[ZigZagInv[i]] = factor / quantChrominance[i];
|
|
||||||
// if you really want JPEGs that are bitwise identical to Jon Olick's code then you need slightly different formulas (note: sqrt(8) = 2.828427125f)
|
|
||||||
//static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; // line 240 of jo_jpeg.cpp
|
|
||||||
//scaledLuminance [ZigZagInv[i]] = 1 / (quantLuminance [i] * aasf[row] * aasf[column]); // lines 266-267 of jo_jpeg.cpp
|
|
||||||
//scaledChrominance[ZigZagInv[i]] = 1 / (quantChrominance[i] * aasf[row] * aasf[column]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// precompute JPEG codewords for quantized DCT
|
|
||||||
BitCode codewordsArray[2 * CodeWordLimit]; // note: quantized[i] is found at codewordsArray[quantized[i] + CodeWordLimit]
|
|
||||||
BitCode* codewords = &codewordsArray[CodeWordLimit]; // allow negative indices, so quantized[i] is at codewords[quantized[i]]
|
|
||||||
uint8_t numBits = 1; // each codeword has at least one bit (value == 0 is undefined)
|
|
||||||
int32_t mask = 1; // mask is always 2^numBits - 1, initial value 2^1-1 = 2-1 = 1
|
|
||||||
for (int16_t value = 1; value < CodeWordLimit; value++)
|
|
||||||
{
|
|
||||||
// numBits = position of highest set bit (ignoring the sign)
|
|
||||||
// mask = (2^numBits) - 1
|
|
||||||
if (value > mask) // one more bit ?
|
|
||||||
{
|
|
||||||
numBits++;
|
|
||||||
mask = (mask << 1) | 1; // append a set bit
|
|
||||||
}
|
|
||||||
codewords[-value] = BitCode(mask - value, numBits); // note that I use a negative index => codewords[-value] = codewordsArray[CodeWordLimit value]
|
|
||||||
codewords[+value] = BitCode( value, numBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// just convert image data from void*
|
|
||||||
auto pixels = (const uint8_t*)pixels_;
|
|
||||||
|
|
||||||
// the next two variables are frequently used when checking for image borders
|
|
||||||
const auto maxWidth = width - 1; // "last row"
|
|
||||||
const auto maxHeight = height - 1; // "bottom line"
|
|
||||||
|
|
||||||
// process MCUs (minimum codes units) => image is subdivided into a grid of 8x8 or 16x16 tiles
|
|
||||||
const auto sampling = downsample ? 2 : 1; // 1x1 or 2x2 sampling
|
|
||||||
const auto mcuSize = 8 * sampling;
|
|
||||||
|
|
||||||
// average color of the previous MCU
|
|
||||||
int16_t lastYDC = 0, lastCbDC = 0, lastCrDC = 0;
|
|
||||||
// convert from RGB to YCbCr
|
|
||||||
float Y[8][8], Cb[8][8], Cr[8][8];
|
|
||||||
|
|
||||||
for (auto mcuY = 0; mcuY < height; mcuY += mcuSize) // each step is either 8 or 16 (=mcuSize)
|
|
||||||
for (auto mcuX = 0; mcuX < width; mcuX += mcuSize)
|
|
||||||
{
|
|
||||||
// YCbCr 4:4:4 format: each MCU is a 8x8 block - the same applies to grayscale images, too
|
|
||||||
// YCbCr 4:2:0 format: each MCU represents a 16x16 block, stored as 4x 8x8 Y-blocks plus 1x 8x8 Cb and 1x 8x8 Cr block)
|
|
||||||
for (auto blockY = 0; blockY < mcuSize; blockY += 8) // iterate once (YCbCr444 and grayscale) or twice (YCbCr420)
|
|
||||||
for (auto blockX = 0; blockX < mcuSize; blockX += 8)
|
|
||||||
{
|
|
||||||
// now we finally have an 8x8 block ...
|
|
||||||
for (auto deltaY = 0; deltaY < 8; deltaY++)
|
|
||||||
{
|
|
||||||
auto column = minimum(mcuX + blockX , maxWidth); // must not exceed image borders, replicate last row/column if needed
|
|
||||||
auto row = minimum(mcuY + blockY + deltaY, maxHeight);
|
|
||||||
for (auto deltaX = 0; deltaX < 8; deltaX++)
|
|
||||||
{
|
|
||||||
// find actual pixel position within the current image
|
|
||||||
auto pixelPos = row * int(width) + column; // the cast ensures that we don't run into multiplication overflows
|
|
||||||
if (column < maxWidth)
|
|
||||||
column++;
|
|
||||||
|
|
||||||
// grayscale images have solely a Y channel which can be easily derived from the input pixel by shifting it by 128
|
|
||||||
if (!isRGB)
|
|
||||||
{
|
|
||||||
Y[deltaY][deltaX] = pixels[pixelPos] - 128.f;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RGB: 3 bytes per pixel (whereas grayscale images have only 1 byte per pixel)
|
|
||||||
auto r = pixels[3 * pixelPos ];
|
|
||||||
auto g = pixels[3 * pixelPos + 1];
|
|
||||||
auto b = pixels[3 * pixelPos + 2];
|
|
||||||
|
|
||||||
Y [deltaY][deltaX] = rgb2y (r, g, b) - 128; // again, the JPEG standard requires Y to be shifted by 128
|
|
||||||
// YCbCr444 is easy - the more complex YCbCr420 has to be computed about 20 lines below in a second pass
|
|
||||||
if (!downsample)
|
|
||||||
{
|
|
||||||
Cb[deltaY][deltaX] = rgb2cb(r, g, b); // standard RGB-to-YCbCr conversion
|
|
||||||
Cr[deltaY][deltaX] = rgb2cr(r, g, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode Y channel
|
|
||||||
lastYDC = encodeBlock(bitWriter, Y, scaledLuminance, lastYDC, huffmanLuminanceDC, huffmanLuminanceAC, codewords);
|
|
||||||
// Cb and Cr are encoded about 50 lines below
|
|
||||||
}
|
|
||||||
|
|
||||||
// grayscale images don't need any Cb and Cr information
|
|
||||||
if (!isRGB)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// ////////////////////////////////////////
|
|
||||||
// the following lines are only relevant for YCbCr420:
|
|
||||||
// average/downsample chrominance of four pixels while respecting the image borders
|
|
||||||
if (downsample)
|
|
||||||
for (short deltaY = 7; downsample && deltaY >= 0; deltaY--) // iterating loop in reverse increases cache read efficiency
|
|
||||||
{
|
|
||||||
auto row = minimum(mcuY + 2*deltaY, maxHeight); // each deltaX/Y step covers a 2x2 area
|
|
||||||
auto column = mcuX; // column is updated inside next loop
|
|
||||||
auto pixelPos = (row * int(width) + column) * 3; // numComponents = 3
|
|
||||||
|
|
||||||
// deltas (in bytes) to next row / column, must not exceed image borders
|
|
||||||
auto rowStep = (row < maxHeight) ? 3 * int(width) : 0; // always numComponents*width except for bottom line
|
|
||||||
auto columnStep = (column < maxWidth ) ? 3 : 0; // always numComponents except for rightmost pixel
|
|
||||||
|
|
||||||
for (short deltaX = 0; deltaX < 8; deltaX++)
|
|
||||||
{
|
|
||||||
// let's add all four samples (2x2 area)
|
|
||||||
auto right = pixelPos + columnStep;
|
|
||||||
auto down = pixelPos + rowStep;
|
|
||||||
auto downRight = pixelPos + columnStep + rowStep;
|
|
||||||
|
|
||||||
// note: cast from 8 bits to >8 bits to avoid overflows when adding
|
|
||||||
auto r = short(pixels[pixelPos ]) + pixels[right ] + pixels[down ] + pixels[downRight ];
|
|
||||||
auto g = short(pixels[pixelPos + 1]) + pixels[right + 1] + pixels[down + 1] + pixels[downRight + 1];
|
|
||||||
auto b = short(pixels[pixelPos + 2]) + pixels[right + 2] + pixels[down + 2] + pixels[downRight + 2];
|
|
||||||
|
|
||||||
// convert to Cb and Cr
|
|
||||||
Cb[deltaY][deltaX] = rgb2cb(r, g, b) / 4; // I still have to divide r,g,b by 4 to get their average values
|
|
||||||
Cr[deltaY][deltaX] = rgb2cr(r, g, b) / 4; // it's a bit faster if done AFTER CbCr conversion
|
|
||||||
|
|
||||||
// step forward to next 2x2 area
|
|
||||||
pixelPos += 2*3; // 2 pixels => 6 bytes (2*numComponents)
|
|
||||||
column += 2;
|
|
||||||
|
|
||||||
// reached right border ?
|
|
||||||
if (column >= maxWidth)
|
|
||||||
{
|
|
||||||
columnStep = 0;
|
|
||||||
pixelPos = ((row + 1) * int(width) - 1) * 3; // same as (row * width + maxWidth) * numComponents => current's row last pixel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end of YCbCr420 code for Cb and Cr
|
|
||||||
|
|
||||||
// encode Cb and Cr
|
|
||||||
lastCbDC = encodeBlock(bitWriter, Cb, scaledChrominance, lastCbDC, huffmanChrominanceDC, huffmanChrominanceAC, codewords);
|
|
||||||
lastCrDC = encodeBlock(bitWriter, Cr, scaledChrominance, lastCrDC, huffmanChrominanceDC, huffmanChrominanceAC, codewords);
|
|
||||||
}
|
|
||||||
|
|
||||||
bitWriter.flush(); // now image is completely encoded, write any bits still left in the buffer
|
|
||||||
|
|
||||||
// ///////////////////////////
|
|
||||||
// EOI marker
|
|
||||||
bitWriter << 0xFF << 0xD9; // this marker has no length, therefore I can't use addMarker()
|
|
||||||
return true;
|
|
||||||
} // writeJpeg()
|
|
||||||
} // namespace TooJpeg
|
|
||||||
Vendored
-62
@@ -1,62 +0,0 @@
|
|||||||
// //////////////////////////////////////////////////////////
|
|
||||||
// toojpeg.h
|
|
||||||
// written by Stephan Brumme, 2018-2019
|
|
||||||
// see https://create.stephan-brumme.com/toojpeg/
|
|
||||||
//
|
|
||||||
|
|
||||||
// This is a compact baseline JPEG/JFIF writer, written in C++ (but looks like C for the most part).
|
|
||||||
// Its interface has only one function: writeJpeg() - and that's it !
|
|
||||||
//
|
|
||||||
// basic example:
|
|
||||||
// => create an image with any content you like, e.g. 1024x768, RGB = 3 bytes per pixel
|
|
||||||
// auto pixels = new unsigned char[1024*768*3];
|
|
||||||
// => you need to define a callback that receives the compressed data byte-by-byte from my JPEG writer
|
|
||||||
// void myOutput(unsigned char oneByte) { fputc(oneByte, myFileHandle); } // save byte to file
|
|
||||||
// => let's go !
|
|
||||||
// TooJpeg::writeJpeg(myOutput, mypixels, 1024, 768);
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace TooJpeg
|
|
||||||
{
|
|
||||||
// write one byte (to disk, memory, ...)
|
|
||||||
typedef void (*WRITE_ONE_BYTE)(unsigned char);
|
|
||||||
// this callback is called for every byte generated by the encoder and behaves similar to fputc
|
|
||||||
// if you prefer stylish C++11 syntax then it can be a lambda, too:
|
|
||||||
// auto myOutput = [](unsigned char oneByte) { fputc(oneByte, output); };
|
|
||||||
|
|
||||||
// output - callback that stores a single byte (writes to disk, memory, ...)
|
|
||||||
// pixels - stored in RGB format or grayscale, stored from upper-left to lower-right
|
|
||||||
// width,height - image size
|
|
||||||
// isRGB - true if RGB format (3 bytes per pixel); false if grayscale (1 byte per pixel)
|
|
||||||
// quality - between 1 (worst) and 100 (best)
|
|
||||||
// downsample - if true then YCbCr 4:2:0 format is used (smaller size, minor quality loss) instead of 4:4:4, not relevant for grayscale
|
|
||||||
// comment - optional JPEG comment (0/NULL if no comment), must not contain ASCII code 0xFF
|
|
||||||
bool writeJpeg(WRITE_ONE_BYTE output, const void* pixels, unsigned short width, unsigned short height,
|
|
||||||
bool isRGB = true, unsigned char quality = 90, bool downsample = false, const char* comment = nullptr);
|
|
||||||
} // namespace TooJpeg
|
|
||||||
|
|
||||||
// My main inspiration was Jon Olick's Minimalistic JPEG writer
|
|
||||||
// ( https://www.jonolick.com/code.html => direct link is https://www.jonolick.com/uploads/7/9/2/1/7921194/jo_jpeg.cpp ).
|
|
||||||
// However, his code documentation is quite sparse - probably because it wasn't written from scratch and is (quote:) "based on a javascript jpeg writer",
|
|
||||||
// most likely Andreas Ritter's code: https://github.com/eugeneware/jpeg-js/blob/master/lib/encoder.js
|
|
||||||
//
|
|
||||||
// Therefore I wrote the whole lib from scratch and tried hard to add tons of comments to my code, especially describing where all those magic numbers come from.
|
|
||||||
// And I managed to remove the need for any external includes ...
|
|
||||||
// yes, that's right: my library has no (!) includes at all, not even #include <stdlib.h>
|
|
||||||
// Depending on your callback WRITE_ONE_BYTE, the library writes either to disk, or in-memory, or wherever you wish.
|
|
||||||
// Moreover, no dynamic memory allocations are performed, just a few bytes on the stack.
|
|
||||||
//
|
|
||||||
// In contrast to Jon's code, compression can be significantly improved in many use cases:
|
|
||||||
// a) grayscale JPEG images need just a single Y channel, no need to save the superfluous Cb + Cr channels
|
|
||||||
// b) YCbCr 4:2:0 downsampling is often about 20% more efficient (=smaller) than the default YCbCr 4:4:4 with only little visual loss
|
|
||||||
//
|
|
||||||
// TooJpeg 1.2+ compresses about twice as fast as jo_jpeg (and about half as fast as libjpeg-turbo).
|
|
||||||
// A few benchmark numbers can be found on my website https://create.stephan-brumme.com/toojpeg/#benchmark
|
|
||||||
//
|
|
||||||
// Last but not least you can optionally add a JPEG comment.
|
|
||||||
//
|
|
||||||
// Your C++ compiler needs to support a reasonable subset of C++11 (g++ 4.7 or Visual C++ 2013 are sufficient).
|
|
||||||
// I haven't tested the code on big-endian systems or anything that smells like an apple.
|
|
||||||
//
|
|
||||||
// USE AT YOUR OWN RISK. Because you are a brave soul :-)
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
#include "trackball.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
#include "util/detour.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "rawinput/rawinput.h"
|
|
||||||
#include "games/io.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "io.h"
|
|
||||||
|
|
||||||
namespace games::ccj {
|
|
||||||
bool MOUSE_TRACKBALL = false;
|
|
||||||
bool MOUSE_TRACKBALL_USE_TOGGLE = false;
|
|
||||||
uint8_t TRACKBALL_SENSITIVITY = 10;
|
|
||||||
|
|
||||||
static HANDLE fakeHandle = (HANDLE)0xDEADBEEFull;
|
|
||||||
static HWND hWnd = nullptr;
|
|
||||||
static WNDPROC wndProc = nullptr;
|
|
||||||
static std::thread *tbThread = nullptr;
|
|
||||||
static bool tbThreadRunning = false;
|
|
||||||
|
|
||||||
static const wchar_t *fakeDeviceName = L"VID_1241&PID_1111";
|
|
||||||
static const wchar_t *windowName = L"ChaseProject";
|
|
||||||
|
|
||||||
static decltype(GetRawInputDeviceList) *GetRawInputDeviceList_orig = nullptr;
|
|
||||||
static decltype(GetRawInputDeviceInfoW) *GetRawInputDeviceInfoW_orig = nullptr;
|
|
||||||
static decltype(SetWindowLongPtrW) *SetWindowLongPtrW_orig = nullptr;
|
|
||||||
static decltype(GetRawInputData) *GetRawInputData_orig = nullptr;
|
|
||||||
static decltype(RegisterRawInputDevices) *RegisterRawInputDevices_orig = nullptr;
|
|
||||||
|
|
||||||
static UINT WINAPI GetRawInputDeviceList_hook(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices,
|
|
||||||
UINT cbSize) {
|
|
||||||
auto result = GetRawInputDeviceList_orig(pRawInputDeviceList, puiNumDevices, cbSize);
|
|
||||||
if (result == 0xFFFFFFFF)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
if (pRawInputDeviceList == NULL) {
|
|
||||||
(*puiNumDevices)++;
|
|
||||||
} else if (result < *puiNumDevices) {
|
|
||||||
pRawInputDeviceList[result] = {fakeHandle, 0};
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT WINAPI GetRawInputDeviceInfoW_hook(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize) {
|
|
||||||
if (hDevice != fakeHandle || uiCommand != RIDI_DEVICENAME)
|
|
||||||
return GetRawInputDeviceInfoW_orig(hDevice, uiCommand, pData, pcbSize);
|
|
||||||
|
|
||||||
const auto requiredLen = (wcslen(fakeDeviceName) + 1) * sizeof(wchar_t);
|
|
||||||
|
|
||||||
if (*pcbSize < requiredLen) {
|
|
||||||
*pcbSize = requiredLen;
|
|
||||||
return 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pData == NULL) {
|
|
||||||
*pcbSize = requiredLen;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
wcscpy((wchar_t*)pData, fakeDeviceName);
|
|
||||||
return requiredLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static LONG_PTR WINAPI SetWindowLongPtrW_hook(HWND _hWnd, int nIndex, LONG_PTR dwNewLong) {
|
|
||||||
wchar_t buffer[256];
|
|
||||||
if (nIndex != GWLP_WNDPROC || GetWindowTextW(_hWnd, buffer, 256) == 0 || !wcswcs(buffer, windowName))
|
|
||||||
return SetWindowLongPtrW_orig(_hWnd, nIndex, dwNewLong);
|
|
||||||
|
|
||||||
hWnd = _hWnd;
|
|
||||||
wndProc = (WNDPROC)dwNewLong;
|
|
||||||
return SetWindowLongPtrW_orig(_hWnd, nIndex, dwNewLong);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT WINAPI GetRawInputData_hook(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader) {
|
|
||||||
if (hRawInput != fakeHandle)
|
|
||||||
return GetRawInputData_orig(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
|
|
||||||
|
|
||||||
if (pData == NULL) {
|
|
||||||
if (uiCommand == RID_HEADER)
|
|
||||||
*pcbSize = sizeof(RAWINPUTHEADER);
|
|
||||||
else
|
|
||||||
*pcbSize = sizeof(RAWINPUT);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RAWINPUTHEADER header = { RIM_TYPEMOUSE, sizeof(RAWINPUT), fakeHandle, 0 };
|
|
||||||
|
|
||||||
if (uiCommand == RID_HEADER) {
|
|
||||||
if (*pcbSize < sizeof(RAWINPUTHEADER)) {
|
|
||||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
||||||
return 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
*((RAWINPUTHEADER*)pData) = header;
|
|
||||||
return sizeof(RAWINPUTHEADER);
|
|
||||||
} else if (uiCommand == RID_INPUT) {
|
|
||||||
if (*pcbSize < sizeof(RAWINPUT)) {
|
|
||||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
||||||
return 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
RAWMOUSE rawMouse {};
|
|
||||||
|
|
||||||
if (MOUSE_TRACKBALL) {
|
|
||||||
static bool active = false;
|
|
||||||
static bool lastState = false;
|
|
||||||
|
|
||||||
static std::chrono::time_point<std::chrono::steady_clock> lastModified = std::chrono::steady_clock::now();
|
|
||||||
static std::chrono::milliseconds debounceDuration(100);
|
|
||||||
auto currentTime = std::chrono::steady_clock::now();
|
|
||||||
bool pressed = get_async_secondary_mouse() & 0x8000;
|
|
||||||
bool focused = GetForegroundWindow() == hWnd;
|
|
||||||
|
|
||||||
if (focused && MOUSE_TRACKBALL_USE_TOGGLE && pressed && (currentTime - lastModified > debounceDuration)) {
|
|
||||||
active = !active;
|
|
||||||
lastModified = currentTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (focused && ((MOUSE_TRACKBALL_USE_TOGGLE && active) || (!MOUSE_TRACKBALL_USE_TOGGLE && pressed))) {
|
|
||||||
POINT cursor;
|
|
||||||
RECT client;
|
|
||||||
|
|
||||||
GetClientRect(hWnd, &client);
|
|
||||||
int sx = client.right - client.left;
|
|
||||||
int sy = client.bottom - client.top;
|
|
||||||
|
|
||||||
GetCursorPos(&cursor);
|
|
||||||
ScreenToClient(hWnd, &cursor);
|
|
||||||
|
|
||||||
static int lastX = cursor.x;
|
|
||||||
static int lastY = cursor.y;
|
|
||||||
|
|
||||||
if (!lastState) {
|
|
||||||
lastX = cursor.x;
|
|
||||||
lastY = cursor.y;
|
|
||||||
lastState = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
rawMouse.usFlags = MOUSE_MOVE_RELATIVE;
|
|
||||||
rawMouse.lLastX = (int)((float)(cursor.x - lastX) * (float)TRACKBALL_SENSITIVITY / 20.0f);
|
|
||||||
rawMouse.lLastY = (int)((float)(lastY - cursor.y) * (float)TRACKBALL_SENSITIVITY / 20.0f);
|
|
||||||
|
|
||||||
bool updateCursor = false;
|
|
||||||
|
|
||||||
if (cursor.x <= 0) {
|
|
||||||
updateCursor = true;
|
|
||||||
cursor.x = sx - 5;
|
|
||||||
} else if (cursor.x >= sx - 1) {
|
|
||||||
updateCursor = true;
|
|
||||||
cursor.x = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor.y <= 0) {
|
|
||||||
updateCursor = true;
|
|
||||||
cursor.y = sy - 5;
|
|
||||||
} else if (cursor.y >= sy - 1) {
|
|
||||||
updateCursor = true;
|
|
||||||
cursor.y = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastX = cursor.x;
|
|
||||||
lastY = cursor.y;
|
|
||||||
|
|
||||||
if (updateCursor) {
|
|
||||||
ClientToScreen(hWnd, &cursor);
|
|
||||||
SetCursorPos(cursor.x, cursor.y);
|
|
||||||
}
|
|
||||||
} else if (lastState && !active) {
|
|
||||||
lastState = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rawMouse.usFlags = MOUSE_MOVE_RELATIVE;
|
|
||||||
|
|
||||||
auto &analogs = get_analogs();
|
|
||||||
if (analogs[Analogs::Trackball_DX].isSet() || analogs[Analogs::Trackball_DY].isSet()) {
|
|
||||||
float x = GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::Trackball_DX]) * 2.0f - 1.0f;
|
|
||||||
float y = GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::Trackball_DY]) * 2.0f - 1.0f;
|
|
||||||
rawMouse.lLastX = (long) (x * (float) TRACKBALL_SENSITIVITY);
|
|
||||||
rawMouse.lLastY = (long) (-y * (float) TRACKBALL_SENSITIVITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &buttons = get_buttons();
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Trackball_Up]))
|
|
||||||
rawMouse.lLastY = TRACKBALL_SENSITIVITY;
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Trackball_Down]))
|
|
||||||
rawMouse.lLastY = -TRACKBALL_SENSITIVITY;
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Trackball_Left]))
|
|
||||||
rawMouse.lLastX = -TRACKBALL_SENSITIVITY;
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Trackball_Right]))
|
|
||||||
rawMouse.lLastX = TRACKBALL_SENSITIVITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
*((RAWINPUT*)pData) = { header, { rawMouse } };
|
|
||||||
return sizeof(RAWINPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL WINAPI RegisterRawInputDevices_hook(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize) {
|
|
||||||
if (uiNumDevices == 2 && pRawInputDevices[1].usUsage == HID_USAGE_GENERIC_GAMEPAD)
|
|
||||||
uiNumDevices = 1;
|
|
||||||
|
|
||||||
return RegisterRawInputDevices_orig(pRawInputDevices, uiNumDevices, cbSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void trackball_hook_init() {
|
|
||||||
// avoid double init
|
|
||||||
static bool initialized = false;
|
|
||||||
if (initialized) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// announce
|
|
||||||
log_info("trackball", "init");
|
|
||||||
|
|
||||||
// user32
|
|
||||||
const auto user32Dll = "user32.dll";
|
|
||||||
detour::trampoline_try(user32Dll, "GetRawInputDeviceList",
|
|
||||||
GetRawInputDeviceList_hook, &GetRawInputDeviceList_orig);
|
|
||||||
detour::trampoline_try(user32Dll, "GetRawInputDeviceInfoW",
|
|
||||||
GetRawInputDeviceInfoW_hook, &GetRawInputDeviceInfoW_orig);
|
|
||||||
detour::trampoline_try(user32Dll, "SetWindowLongPtrW",
|
|
||||||
SetWindowLongPtrW_hook, &SetWindowLongPtrW_orig);
|
|
||||||
detour::trampoline_try(user32Dll, "GetRawInputData",
|
|
||||||
GetRawInputData_hook, &GetRawInputData_orig);
|
|
||||||
detour::trampoline_try(user32Dll, "RegisterRawInputDevices",
|
|
||||||
RegisterRawInputDevices_hook, &RegisterRawInputDevices_orig);
|
|
||||||
}
|
|
||||||
|
|
||||||
void trackball_thread_start() {
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
tbThreadRunning = true;
|
|
||||||
|
|
||||||
log_info("trackball", "thread start, use mouse: {}, toggle: {}", MOUSE_TRACKBALL, MOUSE_TRACKBALL_USE_TOGGLE);
|
|
||||||
|
|
||||||
tbThread = new std::thread([&] {
|
|
||||||
while (tbThreadRunning) {
|
|
||||||
if (hWnd && wndProc) {
|
|
||||||
wndProc(hWnd, WM_INPUT, RIM_INPUT, (LPARAM)fakeHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tbThreadRunning)
|
|
||||||
break;
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(10ms);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void trackball_thread_stop() {
|
|
||||||
tbThreadRunning = false;
|
|
||||||
if (tbThread)
|
|
||||||
tbThread->join();
|
|
||||||
|
|
||||||
log_info("trackball", "thread stop");
|
|
||||||
|
|
||||||
delete tbThread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
#include "io.h"
|
|
||||||
|
|
||||||
std::vector<Button> &games::ddr::get_buttons() {
|
|
||||||
static std::vector<Button> analogs;
|
|
||||||
|
|
||||||
if (analogs.empty()) {
|
|
||||||
analogs = GameAPI::Buttons::getButtons("Dance Dance Revolution");
|
|
||||||
|
|
||||||
GameAPI::Buttons::sortButtons(
|
|
||||||
&analogs,
|
|
||||||
"Service",
|
|
||||||
"Test",
|
|
||||||
"Coin Mech",
|
|
||||||
"P1 Start",
|
|
||||||
"P1 Panel Up",
|
|
||||||
"P1 Panel Down",
|
|
||||||
"P1 Panel Left",
|
|
||||||
"P1 Panel Right",
|
|
||||||
"P1 Menu Up",
|
|
||||||
"P1 Menu Down",
|
|
||||||
"P1 Menu Left",
|
|
||||||
"P1 Menu Right",
|
|
||||||
"P2 Start",
|
|
||||||
"P2 Panel Up",
|
|
||||||
"P2 Panel Down",
|
|
||||||
"P2 Panel Left",
|
|
||||||
"P2 Panel Right",
|
|
||||||
"P2 Menu Up",
|
|
||||||
"P2 Menu Down",
|
|
||||||
"P2 Menu Left",
|
|
||||||
"P2 Menu Right"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return analogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Light> &games::ddr::get_lights() {
|
|
||||||
static std::vector<Light> lights;
|
|
||||||
|
|
||||||
if (lights.empty()) {
|
|
||||||
lights = GameAPI::Lights::getLights("Dance Dance Revolution");
|
|
||||||
|
|
||||||
GameAPI::Lights::sortLights(
|
|
||||||
&lights,
|
|
||||||
"P1 Foot Left",
|
|
||||||
"P1 Foot Up",
|
|
||||||
"P1 Foot Right",
|
|
||||||
"P1 Foot Down",
|
|
||||||
"P2 Foot Left",
|
|
||||||
"P2 Foot Up",
|
|
||||||
"P2 Foot Right",
|
|
||||||
"P2 Foot Down",
|
|
||||||
"Spot Red",
|
|
||||||
"Spot Blue",
|
|
||||||
"Top Spot Red",
|
|
||||||
"Top Spot Blue",
|
|
||||||
"P1 Halogen Upper",
|
|
||||||
"P1 Halogen Lower",
|
|
||||||
"P2 Halogen Upper",
|
|
||||||
"P2 Halogen Lower",
|
|
||||||
"P1 Button",
|
|
||||||
"P2 Button",
|
|
||||||
"Neon",
|
|
||||||
"HD P1 Start",
|
|
||||||
"HD P1 Menu Left-Right",
|
|
||||||
"HD P1 Menu Up-Down",
|
|
||||||
"HD P2 Start",
|
|
||||||
"HD P2 Menu Left-Right",
|
|
||||||
"HD P2 Menu Up-Down",
|
|
||||||
"HD P1 Speaker F R",
|
|
||||||
"HD P1 Speaker F G",
|
|
||||||
"HD P1 Speaker F B",
|
|
||||||
"HD P1 Speaker W R",
|
|
||||||
"HD P1 Speaker W G",
|
|
||||||
"HD P1 Speaker W B",
|
|
||||||
"HD P2 Speaker F R",
|
|
||||||
"HD P2 Speaker F G",
|
|
||||||
"HD P2 Speaker F B",
|
|
||||||
"HD P2 Speaker W R",
|
|
||||||
"HD P2 Speaker W G",
|
|
||||||
"HD P2 Speaker W B",
|
|
||||||
|
|
||||||
"WHITE Speaker Top R",
|
|
||||||
"WHITE Speaker Top G",
|
|
||||||
"WHITE Speaker Top B",
|
|
||||||
"WHITE Speaker Bottom R",
|
|
||||||
"WHITE Speaker Bottom G",
|
|
||||||
"WHITE Speaker Bottom B",
|
|
||||||
"WHITE Woofer R",
|
|
||||||
"WHITE Woofer G",
|
|
||||||
"WHITE Woofer B",
|
|
||||||
|
|
||||||
"GOLD P1 Menu Start",
|
|
||||||
"GOLD P1 Menu Up",
|
|
||||||
"GOLD P1 Menu Down",
|
|
||||||
"GOLD P1 Menu Left",
|
|
||||||
"GOLD P1 Menu Right",
|
|
||||||
|
|
||||||
"GOLD P2 Menu Start",
|
|
||||||
"GOLD P2 Menu Up",
|
|
||||||
"GOLD P2 Menu Down",
|
|
||||||
"GOLD P2 Menu Left",
|
|
||||||
"GOLD P2 Menu Right",
|
|
||||||
|
|
||||||
"GOLD Title Panel Left",
|
|
||||||
"GOLD Title Panel Center",
|
|
||||||
"GOLD Title Panel Right",
|
|
||||||
|
|
||||||
"GOLD P1 Woofer Corner",
|
|
||||||
"GOLD P2 Woofer Corner",
|
|
||||||
|
|
||||||
"GOLD P1 Card Unit R",
|
|
||||||
"GOLD P1 Card Unit G",
|
|
||||||
"GOLD P1 Card Unit B",
|
|
||||||
|
|
||||||
"GOLD P2 Card Unit R",
|
|
||||||
"GOLD P2 Card Unit G",
|
|
||||||
"GOLD P2 Card Unit B",
|
|
||||||
|
|
||||||
"GOLD Top Panel Avg R",
|
|
||||||
"GOLD Top Panel Avg G",
|
|
||||||
"GOLD Top Panel Avg B",
|
|
||||||
|
|
||||||
"GOLD Monitor Side Left Avg R",
|
|
||||||
"GOLD Monitor Side Left Avg G",
|
|
||||||
"GOLD Monitor Side Left Avg B",
|
|
||||||
|
|
||||||
"GOLD Monitor Side Right Avg R",
|
|
||||||
"GOLD Monitor Side Right Avg G",
|
|
||||||
"GOLD Monitor Side Right Avg B",
|
|
||||||
|
|
||||||
"GOLD P1 Foot Up Avg R",
|
|
||||||
"GOLD P1 Foot Up Avg G",
|
|
||||||
"GOLD P1 Foot Up Avg B",
|
|
||||||
|
|
||||||
"GOLD P1 Foot Down Avg R",
|
|
||||||
"GOLD P1 Foot Down Avg G",
|
|
||||||
"GOLD P1 Foot Down Avg B",
|
|
||||||
|
|
||||||
"GOLD P1 Foot Left Avg R",
|
|
||||||
"GOLD P1 Foot Left Avg G",
|
|
||||||
"GOLD P1 Foot Left Avg B",
|
|
||||||
|
|
||||||
"GOLD P1 Foot Right Avg R",
|
|
||||||
"GOLD P1 Foot Right Avg G",
|
|
||||||
"GOLD P1 Foot Right Avg B",
|
|
||||||
|
|
||||||
"GOLD P2 Foot Up Avg R",
|
|
||||||
"GOLD P2 Foot Up Avg G",
|
|
||||||
"GOLD P2 Foot Up Avg B",
|
|
||||||
|
|
||||||
"GOLD P2 Foot Down Avg R",
|
|
||||||
"GOLD P2 Foot Down Avg G",
|
|
||||||
"GOLD P2 Foot Down Avg B",
|
|
||||||
|
|
||||||
"GOLD P2 Foot Left Avg R",
|
|
||||||
"GOLD P2 Foot Left Avg G",
|
|
||||||
"GOLD P2 Foot Left Avg B",
|
|
||||||
|
|
||||||
"GOLD P2 Foot Right Avg R",
|
|
||||||
"GOLD P2 Foot Right Avg G",
|
|
||||||
"GOLD P2 Foot Right Avg B",
|
|
||||||
|
|
||||||
"GOLD P1 Stage Corner Up-Left",
|
|
||||||
"GOLD P1 Stage Corner Up-Right",
|
|
||||||
"GOLD P1 Stage Corner Down-Left",
|
|
||||||
"GOLD P1 Stage Corner Down-Right",
|
|
||||||
|
|
||||||
"GOLD P2 Stage Corner Up-Left",
|
|
||||||
"GOLD P2 Stage Corner Up-Right",
|
|
||||||
"GOLD P2 Stage Corner Down-Left",
|
|
||||||
"GOLD P2 Stage Corner Down-Right"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lights;
|
|
||||||
}
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
#include "gitadora.h"
|
|
||||||
#include "handle.h"
|
|
||||||
#include "bi2x_hook.h"
|
|
||||||
#include <unordered_map>
|
|
||||||
#include "cfg/configurator.h"
|
|
||||||
#include "hooks/audio/mme.h"
|
|
||||||
#include "hooks/graphics/graphics.h"
|
|
||||||
#include "misc/wintouchemu.h"
|
|
||||||
#include "overlay/overlay.h"
|
|
||||||
#include "util/cpuutils.h"
|
|
||||||
#include "util/detour.h"
|
|
||||||
#include "util/libutils.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/sigscan.h"
|
|
||||||
#include "util/socd_cleaner.h"
|
|
||||||
#include "hooks/setupapihook.h"
|
|
||||||
|
|
||||||
namespace games::gitadora {
|
|
||||||
|
|
||||||
// settings
|
|
||||||
bool TWOCHANNEL = false;
|
|
||||||
std::optional<unsigned int> CAB_TYPE = std::nullopt;
|
|
||||||
bool ARENA_SINGLE_WINDOW = false;
|
|
||||||
bool P1_LEFTY = false;
|
|
||||||
bool P2_LEFTY = false;
|
|
||||||
std::optional<std::string> SUBSCREEN_OVERLAY_SIZE;
|
|
||||||
std::optional<socd::SocdAlgorithm> PICK_ALGO = socd::SocdAlgorithm::PreferRecent;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prevent GitaDora from creating folders on F drive
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef SPICE64
|
|
||||||
static DWORD WINAPI GetLogicalDrives_hook() {
|
|
||||||
return GetLogicalDrives() | 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT WINAPI GetDriveTypeA_hook(LPCSTR lpRootPathName) {
|
|
||||||
if (!strcmp(lpRootPathName, "F:\\")) {
|
|
||||||
return DRIVE_FIXED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetDriveTypeA(lpRootPathName);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL WINAPI CreateDirectoryA_hook(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) {
|
|
||||||
if (!strncmp(lpPathName, "F:/", 3)) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreateDirectoryA(lpPathName, lpSecurityAttributes);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GitaDora checks if the IP address has changed, and if it has it throws 5-1506-0000 like jubeat.
|
|
||||||
* We don't want this so we patch it out.
|
|
||||||
*/
|
|
||||||
static char __cdecl eam_network_detected_ip_change() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GitaDora checks if the server it connects to is in the 192.168.0.0/16 or 169.254.0.0/16 subnet.
|
|
||||||
* If it is, it downright refuses to use it and errors with no visible indication.
|
|
||||||
* We don't want this so we patch it out.
|
|
||||||
*/
|
|
||||||
static char __cdecl eam_network_settings_conflict() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prevent GitaDora from changing the volume setting.
|
|
||||||
*/
|
|
||||||
static long __cdecl bmsd2_set_windows_volume(int volume) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SPICE64
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Two Channel Audio Mode
|
|
||||||
* We proxy bmsd2_boot_hook and modify the last parameter which is apparently the channel count.
|
|
||||||
* Since this apparently isn't the only thing required we need a signature scan to modify a value as well.
|
|
||||||
*/
|
|
||||||
typedef int (__cdecl *bmsd2_boot_t)(long a1, int a2, long a3, char channel_count);
|
|
||||||
static bmsd2_boot_t bmsd2_boot_orig = nullptr;
|
|
||||||
static int __cdecl bmsd2_boot_hook(long a1, int a2, long a3, char channel_count) {
|
|
||||||
return bmsd2_boot_orig(a1, a2, a3, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command Line Arguments
|
|
||||||
* We hook this to override specific values.
|
|
||||||
* This currently disables the ability to specify your own in the app-config.xml (param/cmdline __type="str")
|
|
||||||
*/
|
|
||||||
static bool __cdecl sys_code_get_cmdline(const char *cmdline) {
|
|
||||||
if (strcmp(cmdline, "-d") == 0) {
|
|
||||||
return true;
|
|
||||||
} else if (strcmp(cmdline, "-DM") == 0) {
|
|
||||||
return true;
|
|
||||||
} else if (strcmp(cmdline, "-WINDOW") == 0) {
|
|
||||||
return GRAPHICS_WINDOWED;
|
|
||||||
} else if (strcmp(cmdline, "-LOGOUT") == 0) {
|
|
||||||
return false;
|
|
||||||
} else if (strcmp(cmdline, "-AOU") == 0) {
|
|
||||||
return false;
|
|
||||||
} else if (strcmp(cmdline, "-QCMODE") == 0) {
|
|
||||||
return false;
|
|
||||||
} else if (strcmp(cmdline, "-FACTORY") == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* System Setting Parameter Overrides
|
|
||||||
*/
|
|
||||||
static std::unordered_map<std::string, long> SYS_SETTINGS;
|
|
||||||
static std::unordered_map<std::string, long> SYS_DEBUG_DIPS;
|
|
||||||
|
|
||||||
static long __cdecl sys_setting_get_param(const char *param) {
|
|
||||||
|
|
||||||
// overrides
|
|
||||||
if (strcmp(param, "PRODUCTION_MODE") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "ENABLE_DISP_ID") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (CAB_TYPE.has_value() && strcmp(param, "VER_MACHINE") == 0) {
|
|
||||||
return CAB_TYPE.value() << 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
// map lookup
|
|
||||||
auto it = SYS_SETTINGS.find(param);
|
|
||||||
if (it != SYS_SETTINGS.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long __cdecl sys_setting_set_param(const char *param, long value) {
|
|
||||||
SYS_SETTINGS[std::string(param)] = value;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long __cdecl sys_debug_dip_get_param(const char *param) {
|
|
||||||
|
|
||||||
// overrides
|
|
||||||
if (strcmp(param, "sysinfo") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "jobbar1") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "jobbar2") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "serial") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "warnvpf") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "scrshot") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "eamxml") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "offset") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "autodbg") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "develop") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "effect_test") == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (strcmp(param, "voice_type2") == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// map lookup
|
|
||||||
auto it = SYS_DEBUG_DIPS.find(param);
|
|
||||||
if (it != SYS_DEBUG_DIPS.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long __cdecl sys_debug_dip_set_param(const char *param, long value) {
|
|
||||||
SYS_DEBUG_DIPS[std::string(param)] = value;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
GitaDoraGame::GitaDoraGame() : Game("GitaDora") {
|
|
||||||
}
|
|
||||||
|
|
||||||
void GitaDoraGame::pre_attach() {
|
|
||||||
Game::pre_attach();
|
|
||||||
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
if (CAB_TYPE.has_value()) {
|
|
||||||
log_info("gitadora", "cab type: {}", CAB_TYPE.value());
|
|
||||||
} else {
|
|
||||||
log_warning("gitadora", "cab type: not set");
|
|
||||||
}
|
|
||||||
|
|
||||||
log_info("gitadora", "applying processor affinity workaround to prevent hangs...");
|
|
||||||
#ifdef SPICE64
|
|
||||||
// workaround for hang on title screen, on systems with many SMT threads
|
|
||||||
// exact cause is unknown; most likely a bad assumption in some video decoder
|
|
||||||
// 0xFF (first 8 LPs) seems to work well for most people
|
|
||||||
cpuutils::set_processor_affinity(0xFF, false);
|
|
||||||
#else
|
|
||||||
// XG versions ran on ancient dual-core AMD systems
|
|
||||||
// having more cores cause random hangs on song select screen
|
|
||||||
cpuutils::set_processor_affinity(0x3, false);
|
|
||||||
|
|
||||||
// check invalid cab type
|
|
||||||
if (CAB_TYPE.has_value() && CAB_TYPE.value() == 3) {
|
|
||||||
log_fatal("gitadora", "Cabinet type 3 (SD2) not supported on XG series");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// arena model launches a tiny window yet backbuffer at 4k, resulting in unusable overlay
|
|
||||||
// force scaling to make things usable
|
|
||||||
if (!overlay::UI_SCALE_PERCENT.has_value() && is_arena_model() &&
|
|
||||||
GRAPHICS_WINDOWED && !cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
overlay::UI_SCALE_PERCENT = 250;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for guitar wail SOCD cleaning
|
|
||||||
socd::ALGORITHM = socd::SocdAlgorithm::PreferRecent;
|
|
||||||
|
|
||||||
// for guitar picking
|
|
||||||
if (PICK_ALGO.has_value()) {
|
|
||||||
log_info("gitadora", "guitar pick SOCD algorithm: {}", static_cast<int>(PICK_ALGO.value()));
|
|
||||||
} else {
|
|
||||||
log_info("gitadora", "guitar pick SOCD algorithm: legacy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GitaDoraGame::attach() {
|
|
||||||
Game::attach();
|
|
||||||
|
|
||||||
// modules
|
|
||||||
HMODULE sharepj_module = libutils::try_module("libshare-pj.dll");
|
|
||||||
HMODULE bmsd2_module = libutils::try_module("libbmsd2.dll");
|
|
||||||
HMODULE system_module = libutils::try_module("libsystem.dll");
|
|
||||||
|
|
||||||
// patches
|
|
||||||
detour::inline_hook((void *) eam_network_detected_ip_change, libutils::try_proc(
|
|
||||||
sharepj_module, "eam_network_detected_ip_change"));
|
|
||||||
detour::inline_hook((void *) eam_network_settings_conflict, libutils::try_proc(
|
|
||||||
sharepj_module, "eam_network_settings_conflict"));
|
|
||||||
detour::inline_hook((void *) bmsd2_set_windows_volume, libutils::try_proc(
|
|
||||||
bmsd2_module, "bmsd2_set_windows_volume"));
|
|
||||||
detour::inline_hook((void *) sys_code_get_cmdline, libutils::try_proc(
|
|
||||||
system_module, "sys_code_get_cmdline"));
|
|
||||||
detour::inline_hook((void *) sys_setting_get_param, libutils::try_proc(
|
|
||||||
system_module, "sys_setting_get_param"));
|
|
||||||
detour::inline_hook((void *) sys_setting_set_param, libutils::try_proc(
|
|
||||||
system_module, "sys_setting_set_param"));
|
|
||||||
detour::inline_hook((void *) sys_debug_dip_get_param, libutils::try_proc(
|
|
||||||
system_module, "sys_debug_dip_get_param"));
|
|
||||||
detour::inline_hook((void *) sys_debug_dip_set_param, libutils::try_proc(
|
|
||||||
system_module, "sys_debug_dip_set_param"));
|
|
||||||
|
|
||||||
#ifdef SPICE64
|
|
||||||
// gitadora arena model
|
|
||||||
auto aio = libutils::try_library("libaio.dll");
|
|
||||||
if (aio != nullptr) {
|
|
||||||
SETUPAPI_SETTINGS settings{};
|
|
||||||
settings.class_guid[0] = 0x86E0D1E0;
|
|
||||||
settings.class_guid[1] = 0x11D08089;
|
|
||||||
settings.class_guid[2] = 0x0008E49C;
|
|
||||||
settings.class_guid[3] = 0x731F303E;
|
|
||||||
const char property[] = "1CCF(8050)_000";
|
|
||||||
const char property_hardwareid[] = "USB\\VID_1CCF&PID_8050&MI_00\\000";
|
|
||||||
memcpy(settings.property_devicedesc, property, sizeof(property));
|
|
||||||
memcpy(settings.property_hardwareid, property_hardwareid, sizeof(property_hardwareid));
|
|
||||||
setupapihook_init(avs::game::DLL_INSTANCE);
|
|
||||||
setupapihook_add(settings);
|
|
||||||
|
|
||||||
// Gitadora IO(J32D/J33I) board emulation
|
|
||||||
devicehook_init(avs::game::DLL_INSTANCE);
|
|
||||||
devicehook_add(new GitaDoraSerialHandle());
|
|
||||||
|
|
||||||
// test/service/coin buttons
|
|
||||||
bi2x_hook_init();
|
|
||||||
|
|
||||||
// f: drive hook
|
|
||||||
detour::iat_try("GetLogicalDrives", GetLogicalDrives_hook, avs::game::DLL_INSTANCE);
|
|
||||||
detour::iat_try("GetDriveTypeA", GetDriveTypeA_hook, avs::game::DLL_INSTANCE);
|
|
||||||
detour::iat_try("CreateDirectoryA", CreateDirectoryA_hook, avs::game::DLL_INSTANCE);
|
|
||||||
|
|
||||||
// volume change prevention
|
|
||||||
hooks::audio::mme::init(avs::game::DLL_INSTANCE);
|
|
||||||
|
|
||||||
// touch hook
|
|
||||||
if (ARENA_SINGLE_WINDOW) {
|
|
||||||
wintouchemu::FORCE = true;
|
|
||||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
|
||||||
wintouchemu::hook("GITADORA", avs::game::DLL_INSTANCE);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HMODULE gdme_module = libutils::try_module("libgdme.dll");
|
|
||||||
|
|
||||||
// window patch
|
|
||||||
if (GRAPHICS_WINDOWED && !replace_pattern(
|
|
||||||
gdme_module,
|
|
||||||
"754185ED753D8B4118BF0000CB02",
|
|
||||||
"9090????9090??????????????12", 0, 0))
|
|
||||||
{
|
|
||||||
log_warning("gitadora", "windowed mode failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
HMODULE bmsd_engine_module = libutils::try_module("libbmsd-engine.dll");
|
|
||||||
HMODULE bmsd_module = libutils::try_module("libbmsd.dll");
|
|
||||||
|
|
||||||
// two channel mod
|
|
||||||
if (TWOCHANNEL) {
|
|
||||||
bmsd2_boot_orig = detour::iat_try("bmsd2_boot", bmsd2_boot_hook, bmsd_module);
|
|
||||||
|
|
||||||
if (!(replace_pattern(bmsd_engine_module, "33000000488D", "03??????????", 0, 0) ||
|
|
||||||
replace_pattern(bmsd_engine_module, "330000000F10", "03??????????", 0, 0)))
|
|
||||||
{
|
|
||||||
log_warning("gitadora", "two channel mode failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
#include "io.h"
|
|
||||||
|
|
||||||
std::vector<Button> &games::gitadora::get_buttons() {
|
|
||||||
static std::vector<Button> buttons;
|
|
||||||
|
|
||||||
if (buttons.empty()) {
|
|
||||||
buttons = GameAPI::Buttons::getButtons("GitaDora");
|
|
||||||
|
|
||||||
GameAPI::Buttons::sortButtons(&buttons,
|
|
||||||
"Service",
|
|
||||||
"Test",
|
|
||||||
"Coin",
|
|
||||||
"Headphone",
|
|
||||||
"Guitar P1 Start",
|
|
||||||
"Guitar P1 Up",
|
|
||||||
"Guitar P1 Down",
|
|
||||||
"Guitar P1 Left",
|
|
||||||
"Guitar P1 Right",
|
|
||||||
"Guitar P1 Help",
|
|
||||||
"Guitar P1 Effect 1",
|
|
||||||
"Guitar P1 Effect 2",
|
|
||||||
"Guitar P1 Effect 3",
|
|
||||||
"Guitar P1 Effect Pedal",
|
|
||||||
"Guitar P1 Button Extra 1",
|
|
||||||
"Guitar P1 Button Extra 2",
|
|
||||||
"Guitar P1 Pick Up",
|
|
||||||
"Guitar P1 Pick Down",
|
|
||||||
"Guitar P1 R",
|
|
||||||
"Guitar P1 G",
|
|
||||||
"Guitar P1 B",
|
|
||||||
"Guitar P1 Y",
|
|
||||||
"Guitar P1 P",
|
|
||||||
"Guitar P1 Knob Up",
|
|
||||||
"Guitar P1 Knob Down",
|
|
||||||
"Guitar P1 Wail Up",
|
|
||||||
"Guitar P1 Wail Down",
|
|
||||||
"Guitar P2 Start",
|
|
||||||
"Guitar P2 Up",
|
|
||||||
"Guitar P2 Down",
|
|
||||||
"Guitar P2 Left",
|
|
||||||
"Guitar P2 Right",
|
|
||||||
"Guitar P2 Help",
|
|
||||||
"Guitar P2 Effect 1",
|
|
||||||
"Guitar P2 Effect 2",
|
|
||||||
"Guitar P2 Effect 3",
|
|
||||||
"Guitar P2 Effect Pedal",
|
|
||||||
"Guitar P2 Button Extra 1",
|
|
||||||
"Guitar P2 Button Extra 2",
|
|
||||||
"Guitar P2 Pick Up",
|
|
||||||
"Guitar P2 Pick Down",
|
|
||||||
"Guitar P2 R",
|
|
||||||
"Guitar P2 G",
|
|
||||||
"Guitar P2 B",
|
|
||||||
"Guitar P2 Y",
|
|
||||||
"Guitar P2 P",
|
|
||||||
"Guitar P2 Knob Up",
|
|
||||||
"Guitar P2 Knob Down",
|
|
||||||
"Guitar P2 Wail Up",
|
|
||||||
"Guitar P2 Wail Down",
|
|
||||||
"Drum Start",
|
|
||||||
"Drum Up",
|
|
||||||
"Drum Down",
|
|
||||||
"Drum Left",
|
|
||||||
"Drum Right",
|
|
||||||
"Drum Help",
|
|
||||||
"Drum Button Extra 1",
|
|
||||||
"Drum Button Extra 2",
|
|
||||||
|
|
||||||
"Drum Left Cymbal",
|
|
||||||
"Drum Hi-Hat",
|
|
||||||
"Drum Left Pedal",
|
|
||||||
"Drum Snare",
|
|
||||||
"Drum Hi-Tom",
|
|
||||||
"Drum Bass Pedal",
|
|
||||||
"Drum Low-Tom",
|
|
||||||
"Drum Floor Tom",
|
|
||||||
"Drum Right Cymbal",
|
|
||||||
"Drum Hi-Hat Closed",
|
|
||||||
"Drum Hi-Hat Half-Open"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Analog> &games::gitadora::get_analogs() {
|
|
||||||
static std::vector<Analog> analogs;
|
|
||||||
|
|
||||||
if (analogs.empty()) {
|
|
||||||
analogs = GameAPI::Analogs::getAnalogs("GitaDora");
|
|
||||||
|
|
||||||
GameAPI::Analogs::sortAnalogs(&analogs,
|
|
||||||
"Guitar P1 Wail X",
|
|
||||||
"Guitar P1 Wail Y",
|
|
||||||
"Guitar P1 Wail Z",
|
|
||||||
"Guitar P1 Knob",
|
|
||||||
"Guitar P2 Wail X",
|
|
||||||
"Guitar P2 Wail Y",
|
|
||||||
"Guitar P2 Wail Z",
|
|
||||||
"Guitar P2 Knob"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return analogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string games::gitadora::get_buttons_help() {
|
|
||||||
// keep to max 100 characters wide
|
|
||||||
return
|
|
||||||
"guitar:\n"
|
|
||||||
"\n"
|
|
||||||
" < R G B Y P --- Pick ] \n"
|
|
||||||
"\n"
|
|
||||||
" If you normally hold your guitar left-handed (frets on right hand):\n"
|
|
||||||
" * here, hold the guitar as right-handed (frets on left hand),\n"
|
|
||||||
" and bind the buttons, pick, and wail controls\n"
|
|
||||||
" * in Options tab, turn on GitaDora Lefty Guitar\n"
|
|
||||||
" * finally, use the in-game option to turn on LEFT mode\n"
|
|
||||||
"\n"
|
|
||||||
"\n"
|
|
||||||
"drums:\n"
|
|
||||||
"\n"
|
|
||||||
" LeftCymbal RightCymbal\n"
|
|
||||||
" HiHat HiTom LowTom \n"
|
|
||||||
" Snare FloorTom \n"
|
|
||||||
" -------------------------------------------------------\n"
|
|
||||||
" Left Bass\n"
|
|
||||||
" Pedal Pedal\n"
|
|
||||||
"\n"
|
|
||||||
" For MIDI drums with Open/Closed HiHat configurations or pads with\n"
|
|
||||||
" multiple hit zones, ensure you bind all variation using the Pages\n"
|
|
||||||
" button at the bottom."
|
|
||||||
;
|
|
||||||
}
|
|
||||||
std::string games::gitadora::get_analogs_help() {
|
|
||||||
// keep to max 100 characters wide
|
|
||||||
return
|
|
||||||
"guitar:\n"
|
|
||||||
"\n"
|
|
||||||
"X axis: 0% when body is held facing monitor, 50% when flat on a table\n"
|
|
||||||
"Y axis: 50% when held horizontal, 0% when neck is raised, 100% pointing down\n"
|
|
||||||
"Z axis: 50% at rest, 100% when swinging neck toward monitor (only used in XG series)\n"
|
|
||||||
"\n"
|
|
||||||
"You need both X and Y axis for up/down wail to work correctly in-game.\n"
|
|
||||||
"If you only have Y axis, consider using digital wailing instead.\n"
|
|
||||||
"\n"
|
|
||||||
"Ensure you clear all analog bindings if you want to use digital wailing.\n"
|
|
||||||
"\n"
|
|
||||||
"If you hold your guitar left-handed (frets on the right hand),\n"
|
|
||||||
"analog bindings will likely not work as intended.\n"
|
|
||||||
"Consider using digital wailing in Buttons tab."
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Light> &games::gitadora::get_lights() {
|
|
||||||
static std::vector<Light> lights;
|
|
||||||
|
|
||||||
if (lights.empty()) {
|
|
||||||
lights = GameAPI::Lights::getLights("GitaDora");
|
|
||||||
|
|
||||||
GameAPI::Lights::sortLights(&lights,
|
|
||||||
"Guitar P1 Motor",
|
|
||||||
"Guitar P2 Motor",
|
|
||||||
|
|
||||||
"P1 Start",
|
|
||||||
"P1 Menu Up Down (DX)",
|
|
||||||
"P1 Menu Left Right (DX)",
|
|
||||||
"P1 Help (DX)",
|
|
||||||
|
|
||||||
"P2 Start",
|
|
||||||
"P2 Menu Up Down (DX)",
|
|
||||||
"P2 Menu Left Right (DX)",
|
|
||||||
"P2 Help (DX)",
|
|
||||||
|
|
||||||
"Drum Left Cymbal",
|
|
||||||
"Drum Hi-Hat",
|
|
||||||
"Drum Snare",
|
|
||||||
"Drum High Tom",
|
|
||||||
"Drum Low Tom",
|
|
||||||
"Drum Floor Tom",
|
|
||||||
"Drum Right Cymbal",
|
|
||||||
|
|
||||||
"Drum Woofer R",
|
|
||||||
"Drum Woofer G",
|
|
||||||
"Drum Woofer B",
|
|
||||||
|
|
||||||
"Drum Stage R (DX)",
|
|
||||||
"Drum Stage G (DX)",
|
|
||||||
"Drum Stage B (DX)",
|
|
||||||
|
|
||||||
"Spot Left (DX)",
|
|
||||||
"Spot Right (DX)",
|
|
||||||
"Spot Center Left (DX)",
|
|
||||||
"Spot Center Right (DX)",
|
|
||||||
|
|
||||||
"Drum Spot Rear Left (DX)",
|
|
||||||
"Drum Spot Rear Right (DX)",
|
|
||||||
|
|
||||||
"Guitar Lower Left R (DX)",
|
|
||||||
"Guitar Lower Left G (DX)",
|
|
||||||
"Guitar Lower Left B (DX)",
|
|
||||||
"Guitar Lower Right R (DX)",
|
|
||||||
"Guitar Lower Right G (DX)",
|
|
||||||
"Guitar Lower Right B (DX)",
|
|
||||||
|
|
||||||
"Guitar Left Speaker Upper R (DX)",
|
|
||||||
"Guitar Left Speaker Upper G (DX)",
|
|
||||||
"Guitar Left Speaker Upper B (DX)",
|
|
||||||
"Guitar Left Speaker Mid Up Left R (DX)",
|
|
||||||
"Guitar Left Speaker Mid Up Left G (DX)",
|
|
||||||
"Guitar Left Speaker Mid Up Left B (DX)",
|
|
||||||
"Guitar Left Speaker Mid Up Right R (DX)",
|
|
||||||
"Guitar Left Speaker Mid Up Right G (DX)",
|
|
||||||
"Guitar Left Speaker Mid Up Right B (DX)",
|
|
||||||
"Guitar Left Speaker Mid Low Left R (DX)",
|
|
||||||
"Guitar Left Speaker Mid Low Left G (DX)",
|
|
||||||
"Guitar Left Speaker Mid Low Left B (DX)",
|
|
||||||
"Guitar Left Speaker Mid Low Right R (DX)",
|
|
||||||
"Guitar Left Speaker Mid Low Right G (DX)",
|
|
||||||
"Guitar Left Speaker Mid Low Right B (DX)",
|
|
||||||
"Guitar Left Speaker Lower R (DX)",
|
|
||||||
"Guitar Left Speaker Lower G (DX)",
|
|
||||||
"Guitar Left Speaker Lower B (DX)",
|
|
||||||
|
|
||||||
"Guitar Right Speaker Upper R (DX)",
|
|
||||||
"Guitar Right Speaker Upper G (DX)",
|
|
||||||
"Guitar Right Speaker Upper B (DX)",
|
|
||||||
"Guitar Right Speaker Mid Up Left R (DX)",
|
|
||||||
"Guitar Right Speaker Mid Up Left G (DX)",
|
|
||||||
"Guitar Right Speaker Mid Up Left B (DX)",
|
|
||||||
"Guitar Right Speaker Mid Up Right R (DX)",
|
|
||||||
"Guitar Right Speaker Mid Up Right G (DX)",
|
|
||||||
"Guitar Right Speaker Mid Up Right B (DX)",
|
|
||||||
"Guitar Right Speaker Mid Low Left R (DX)",
|
|
||||||
"Guitar Right Speaker Mid Low Left G (DX)",
|
|
||||||
"Guitar Right Speaker Mid Low Left B (DX)",
|
|
||||||
"Guitar Right Speaker Mid Low Right R (DX)",
|
|
||||||
"Guitar Right Speaker Mid Low Right G (DX)",
|
|
||||||
"Guitar Right Speaker Mid Low Right B (DX)",
|
|
||||||
"Guitar Right Speaker Lower R (DX)",
|
|
||||||
"Guitar Right Speaker Lower G (DX)",
|
|
||||||
"Guitar Right Speaker Lower B (DX)",
|
|
||||||
|
|
||||||
"Title Average R (Arena)",
|
|
||||||
"Title Average G (Arena)",
|
|
||||||
"Title Average B (Arena)",
|
|
||||||
|
|
||||||
"Woofer R (Arena)",
|
|
||||||
"Woofer G (Arena)",
|
|
||||||
"Woofer B (Arena)",
|
|
||||||
|
|
||||||
"Card Reader R (Arena)",
|
|
||||||
"Card Reader G (Arena)",
|
|
||||||
"Card Reader B (Arena)"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lights;
|
|
||||||
}
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
#include "io.h"
|
|
||||||
|
|
||||||
std::vector<Button> &games::iidx::get_buttons() {
|
|
||||||
static std::vector<Button> buttons;
|
|
||||||
|
|
||||||
if (buttons.empty()) {
|
|
||||||
buttons = GameAPI::Buttons::getButtons("Beatmania IIDX");
|
|
||||||
|
|
||||||
GameAPI::Buttons::sortButtons(
|
|
||||||
&buttons,
|
|
||||||
"Service",
|
|
||||||
"Test",
|
|
||||||
"Coin Mech",
|
|
||||||
"P1 1",
|
|
||||||
"P1 2",
|
|
||||||
"P1 3",
|
|
||||||
"P1 4",
|
|
||||||
"P1 5",
|
|
||||||
"P1 6",
|
|
||||||
"P1 7",
|
|
||||||
"P1 TT+",
|
|
||||||
"P1 TT-",
|
|
||||||
"P1 TT+/-",
|
|
||||||
"P1 TT+/- Alternate",
|
|
||||||
"P1 Start",
|
|
||||||
"P2 1",
|
|
||||||
"P2 2",
|
|
||||||
"P2 3",
|
|
||||||
"P2 4",
|
|
||||||
"P2 5",
|
|
||||||
"P2 6",
|
|
||||||
"P2 7",
|
|
||||||
"P2 TT+",
|
|
||||||
"P2 TT-",
|
|
||||||
"P2 TT+/-",
|
|
||||||
"P2 TT+/- Alternate",
|
|
||||||
"P2 Start",
|
|
||||||
"EFFECT",
|
|
||||||
"VEFX",
|
|
||||||
"P1 Headphone",
|
|
||||||
"P2 Headphone"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string games::iidx::get_buttons_help() {
|
|
||||||
// keep to max 100 characters wide
|
|
||||||
return
|
|
||||||
" P1 EFCT P2 \n"
|
|
||||||
" VEFX \n"
|
|
||||||
" 2 4 6 2 4 6 \n"
|
|
||||||
" TT 1 3 5 7 1 3 5 7 TT \n"
|
|
||||||
"\n"
|
|
||||||
"For controllers, use Analog tab for turntable (TT)."
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Analog> &games::iidx::get_analogs() {
|
|
||||||
static std::vector<Analog> analogs;
|
|
||||||
|
|
||||||
if (analogs.empty()) {
|
|
||||||
analogs = GameAPI::Analogs::getAnalogs("Beatmania IIDX");
|
|
||||||
|
|
||||||
GameAPI::Analogs::sortAnalogs(
|
|
||||||
&analogs,
|
|
||||||
"Turntable P1",
|
|
||||||
"Turntable P2",
|
|
||||||
"VEFX",
|
|
||||||
"Low-EQ",
|
|
||||||
"Hi-EQ",
|
|
||||||
"Filter",
|
|
||||||
"Play Volume"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return analogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Light> &games::iidx::get_lights() {
|
|
||||||
static std::vector<Light> lights;
|
|
||||||
|
|
||||||
if (lights.empty()) {
|
|
||||||
lights = GameAPI::Lights::getLights("Beatmania IIDX");
|
|
||||||
|
|
||||||
GameAPI::Lights::sortLights(
|
|
||||||
&lights,
|
|
||||||
"P1 1",
|
|
||||||
"P1 2",
|
|
||||||
"P1 3",
|
|
||||||
"P1 4",
|
|
||||||
"P1 5",
|
|
||||||
"P1 6",
|
|
||||||
"P1 7",
|
|
||||||
"P2 1",
|
|
||||||
"P2 2",
|
|
||||||
"P2 3",
|
|
||||||
"P2 4",
|
|
||||||
"P2 5",
|
|
||||||
"P2 6",
|
|
||||||
"P2 7",
|
|
||||||
"P1 Start",
|
|
||||||
"P2 Start",
|
|
||||||
"VEFX",
|
|
||||||
"Effect",
|
|
||||||
"Spot Light 1",
|
|
||||||
"Spot Light 2",
|
|
||||||
"Spot Light 3",
|
|
||||||
"Spot Light 4",
|
|
||||||
"Spot Light 5",
|
|
||||||
"Spot Light 6",
|
|
||||||
"Spot Light 7",
|
|
||||||
"Spot Light 8",
|
|
||||||
"Neon Lamp",
|
|
||||||
"Woofer R",
|
|
||||||
"Woofer G",
|
|
||||||
"Woofer B",
|
|
||||||
"IC Card Reader P1 R",
|
|
||||||
"IC Card Reader P1 G",
|
|
||||||
"IC Card Reader P1 B",
|
|
||||||
"IC Card Reader P2 R",
|
|
||||||
"IC Card Reader P2 G",
|
|
||||||
"IC Card Reader P2 B",
|
|
||||||
"Turntable P1 R",
|
|
||||||
"Turntable P1 G",
|
|
||||||
"Turntable P1 B",
|
|
||||||
"Turntable P2 R",
|
|
||||||
"Turntable P2 G",
|
|
||||||
"Turntable P2 B",
|
|
||||||
"Turntable P1 Resistance",
|
|
||||||
"Turntable P2 Resistance",
|
|
||||||
"Stage Left Avg R",
|
|
||||||
"Stage Left Avg G",
|
|
||||||
"Stage Left Avg B",
|
|
||||||
"Stage Right Avg R",
|
|
||||||
"Stage Right Avg G",
|
|
||||||
"Stage Right Avg B",
|
|
||||||
"Cabinet Left Avg R",
|
|
||||||
"Cabinet Left Avg G",
|
|
||||||
"Cabinet Left Avg B",
|
|
||||||
"Cabinet Right Avg R",
|
|
||||||
"Cabinet Right Avg G",
|
|
||||||
"Cabinet Right Avg B",
|
|
||||||
"Control Panel Under Avg R",
|
|
||||||
"Control Panel Under Avg G",
|
|
||||||
"Control Panel Under Avg B",
|
|
||||||
"Ceiling Left Avg R",
|
|
||||||
"Ceiling Left Avg G",
|
|
||||||
"Ceiling Left Avg B",
|
|
||||||
"Title Left Avg R",
|
|
||||||
"Title Left Avg G",
|
|
||||||
"Title Left Avg B",
|
|
||||||
"Title Right Avg R",
|
|
||||||
"Title Right Avg G",
|
|
||||||
"Title Right Avg B",
|
|
||||||
"Ceiling Right Avg R",
|
|
||||||
"Ceiling Right Avg G",
|
|
||||||
"Ceiling Right Avg B",
|
|
||||||
"Touch Panel Left Avg R",
|
|
||||||
"Touch Panel Left Avg G",
|
|
||||||
"Touch Panel Left Avg B",
|
|
||||||
"Touch Panel Right Avg R",
|
|
||||||
"Touch Panel Right Avg G",
|
|
||||||
"Touch Panel Right Avg B",
|
|
||||||
"Side Panel Left Inner Avg R",
|
|
||||||
"Side Panel Left Inner Avg G",
|
|
||||||
"Side Panel Left Inner Avg B",
|
|
||||||
"Side Panel Left Outer Avg R",
|
|
||||||
"Side Panel Left Outer Avg G",
|
|
||||||
"Side Panel Left Outer Avg B",
|
|
||||||
"Side Panel Left Avg R",
|
|
||||||
"Side Panel Left Avg G",
|
|
||||||
"Side Panel Left Avg B",
|
|
||||||
"Side Panel Right Outer Avg R",
|
|
||||||
"Side Panel Right Outer Avg G",
|
|
||||||
"Side Panel Right Outer Avg B",
|
|
||||||
"Side Panel Right Inner Avg R",
|
|
||||||
"Side Panel Right Inner Avg G",
|
|
||||||
"Side Panel Right Inner Avg B",
|
|
||||||
"Side Panel Right Avg R",
|
|
||||||
"Side Panel Right Avg G",
|
|
||||||
"Side Panel Right Avg B"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lights;
|
|
||||||
}
|
|
||||||
@@ -1,900 +0,0 @@
|
|||||||
#include "games/iidx/local_camera.h"
|
|
||||||
|
|
||||||
#if SPICE64
|
|
||||||
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "mf_wrappers.h"
|
|
||||||
|
|
||||||
std::string CAMERA_CONTROL_LABELS[] = {
|
|
||||||
"Pan",
|
|
||||||
"Tilt",
|
|
||||||
"Roll",
|
|
||||||
"Zoom",
|
|
||||||
"Exposure",
|
|
||||||
"Iris",
|
|
||||||
"Focus"
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string DRAW_MODE_LABELS[] = {
|
|
||||||
"Stretch",
|
|
||||||
"Crop",
|
|
||||||
"Letterbox",
|
|
||||||
"Crop to 4:3",
|
|
||||||
"Letterbox to 4:3",
|
|
||||||
};
|
|
||||||
|
|
||||||
// static HRESULT printTextureLevelDesc(LPDIRECT3DTEXTURE9 texture) {
|
|
||||||
// HRESULT hr = S_OK;
|
|
||||||
// D3DSURFACE_DESC desc;
|
|
||||||
// hr = texture->GetLevelDesc(0, &desc);
|
|
||||||
// log_info("iidx:camhook", "Texture Desc Size: {}x{} Res Type: {} Format: {} Usage: {}", desc.Width, desc.Height, (int) desc.Type, (int) desc.Format, (int) desc.Usage);
|
|
||||||
// return hr;
|
|
||||||
// }
|
|
||||||
|
|
||||||
LONG TARGET_SURFACE_WIDTH = 1280;
|
|
||||||
LONG TARGET_SURFACE_HEIGHT = 720;
|
|
||||||
|
|
||||||
double RATIO_16_9 = 16.0 / 9.0;
|
|
||||||
double RATIO_4_3 = 4.0 / 3.0;
|
|
||||||
|
|
||||||
namespace games::iidx {
|
|
||||||
|
|
||||||
IIDXLocalCamera::IIDXLocalCamera(
|
|
||||||
std::string name,
|
|
||||||
BOOL prefer_16_by_9,
|
|
||||||
IMFActivate *pActivate,
|
|
||||||
IDirect3DDeviceManager9 *pD3DManager,
|
|
||||||
LPDIRECT3DDEVICE9EX device,
|
|
||||||
LPDIRECT3DTEXTURE9 *camera_texture_target,
|
|
||||||
LPDIRECT3DTEXTURE9 *preview_texture_target
|
|
||||||
):
|
|
||||||
m_nRefCount(1),
|
|
||||||
m_name(name),
|
|
||||||
m_prefer_16_by_9(prefer_16_by_9),
|
|
||||||
m_device(device),
|
|
||||||
m_camera_texture_target(camera_texture_target),
|
|
||||||
m_preview_texture_target(preview_texture_target),
|
|
||||||
m_camera_texture_original(*camera_texture_target),
|
|
||||||
m_preview_texture_original(*preview_texture_target)
|
|
||||||
{
|
|
||||||
InitializeCriticalSection(&m_critsec);
|
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
IMFAttributes *pAttributes = nullptr;
|
|
||||||
|
|
||||||
EnterCriticalSection(&m_critsec);
|
|
||||||
|
|
||||||
log_info("iidx:camhook", "[{}] Creating camera", m_name);
|
|
||||||
|
|
||||||
// Get friendly name for log purposes
|
|
||||||
WCHAR *pwszFriendlyName = nullptr;
|
|
||||||
UINT32 m_cchFriendlyName = 0;
|
|
||||||
hr = pActivate->GetAllocatedString(
|
|
||||||
MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
|
|
||||||
&pwszFriendlyName,
|
|
||||||
&m_cchFriendlyName
|
|
||||||
);
|
|
||||||
if (SUCCEEDED(hr) && pwszFriendlyName != nullptr) {
|
|
||||||
log_misc("iidx:camhook", "[{}] Name: {}", m_name, ws2s(pwszFriendlyName));
|
|
||||||
m_friendly_name = ws2s(pwszFriendlyName);
|
|
||||||
CoTaskMemFree(pwszFriendlyName);
|
|
||||||
pwszFriendlyName = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrive symlink of Camera for control configurations
|
|
||||||
hr = pActivate->GetAllocatedString(
|
|
||||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
|
||||||
&m_pwszSymbolicLink,
|
|
||||||
&m_cchSymbolicLink
|
|
||||||
);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] GetAllocatedString failed with {:#x}", m_name, (ULONG)hr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_misc("iidx:camhook", "[{}] Symlink: {}", m_name, GetSymLink());
|
|
||||||
|
|
||||||
// Create the media source object.
|
|
||||||
hr = pActivate->ActivateObject(IID_PPV_ARGS(&m_pSource));
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] ActivateObject failed with {:#x}", m_name, (ULONG)hr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retain reference to the camera
|
|
||||||
m_pSource->AddRef();
|
|
||||||
log_misc("iidx:camhook", "[{}] Activated", m_name);
|
|
||||||
|
|
||||||
// Create an attribute store to hold initialization settings.
|
|
||||||
hr = WrappedMFCreateAttributes(&pAttributes, 2);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] MFCreateAttributes failed with {:#x}", m_name, (ULONG)hr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = pAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, pD3DManager);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] SetUnknown(MF_SOURCE_READER_D3D_MANAGER) failed with {:#x}", m_name, (ULONG)hr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = pAttributes->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] SetUINT32(MF_SOURCE_READER_DISABLE_DXVA) failed with {:#x}", m_name, (ULONG)hr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Color space conversion
|
|
||||||
// if (SUCCEEDED(hr)) {
|
|
||||||
// hr = pAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE);
|
|
||||||
// }
|
|
||||||
// if (SUCCEEDED(hr)) {
|
|
||||||
// hr = pAttributes->SetUINT32(MF_READWRITE_DISABLE_CONVERTERS, FALSE);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Create the source reader.
|
|
||||||
hr = WrappedMFCreateSourceReaderFromMediaSource(
|
|
||||||
m_pSource,
|
|
||||||
pAttributes,
|
|
||||||
&m_pSourceReader
|
|
||||||
);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] MFCreateSourceReaderFromMediaSource failed with {:#x}", m_name, (ULONG)hr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_misc("iidx:camhook", "[{}] Created source reader", m_name);
|
|
||||||
|
|
||||||
hr = InitTargetTexture();
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] InitTargetTexture failed with {:#x}", m_name, (ULONG)hr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Camera should be still usable even if camera control is not supported
|
|
||||||
InitCameraControl();
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
m_initialized = true;
|
|
||||||
log_misc("iidx:camhook", "[{}] Initialized", m_name);
|
|
||||||
} else {
|
|
||||||
log_warning("iidx:camhook", "[{}] Failed to create camera: {:#x}", m_name, (ULONG)hr);
|
|
||||||
}
|
|
||||||
SafeRelease(&pAttributes);
|
|
||||||
LeaveCriticalSection(&m_critsec);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::StartCapture() {
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
IMFMediaType *pType = nullptr;
|
|
||||||
|
|
||||||
if (!m_initialized) {
|
|
||||||
log_warning("iidx:camhook", "[{}] Camera not initialized", m_name);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find a suitable output type.
|
|
||||||
log_misc("iidx:camhook", "[{}] Find best media type", m_name);
|
|
||||||
UINT32 bestWidth = 0;
|
|
||||||
double bestFrameRate = 0;
|
|
||||||
|
|
||||||
// The loop should terminate by MF_E_NO_MORE_TYPES
|
|
||||||
// Adding a hard limit just in case
|
|
||||||
for (DWORD i = 0; i < 1000; i++) {
|
|
||||||
hr = m_pSourceReader->GetNativeMediaType(
|
|
||||||
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
|
||||||
i,
|
|
||||||
&pType
|
|
||||||
);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
if (hr != MF_E_NO_MORE_TYPES) {
|
|
||||||
log_warning("iidx:camhook", "[{}] Cannot get media type {} {:#x}", m_name, i, (ULONG)hr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = TryMediaType(pType, &bestWidth, &bestFrameRate);
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
MediaTypeInfo info = GetMediaTypeInfo(pType);
|
|
||||||
m_mediaTypeInfos.push_back(info);
|
|
||||||
if (hr == S_OK) {
|
|
||||||
m_pAutoMediaType = pType;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Invalid media type (e.g. no conversion function)
|
|
||||||
SafeRelease(&pType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort available media types
|
|
||||||
std::sort(m_mediaTypeInfos.begin(), m_mediaTypeInfos.end(), [](const MediaTypeInfo &a, const MediaTypeInfo &b) {
|
|
||||||
if (a.width != b.width) {
|
|
||||||
return a.width > b.width;
|
|
||||||
}
|
|
||||||
if (a.height != b.height) {
|
|
||||||
return a.height > b.height;
|
|
||||||
}
|
|
||||||
if (a.frameRate != b.frameRate) {
|
|
||||||
return (int)a.frameRate > (int)b.frameRate;
|
|
||||||
}
|
|
||||||
return a.subtype.Data1 > b.subtype.Data1;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!m_pAutoMediaType) {
|
|
||||||
m_pAutoMediaType = m_mediaTypeInfos.front().p_mediaType;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMFMediaType *pSelectedMediaType = nullptr;
|
|
||||||
|
|
||||||
// Find media type specified by user configurations
|
|
||||||
if (!m_useAutoMediaType && m_selectedMediaTypeDescription.length() > 0) {
|
|
||||||
log_info("iidx:camhook", "[{}] Use media type from config {}", m_name, m_selectedMediaTypeDescription);
|
|
||||||
auto it = std::find_if(m_mediaTypeInfos.begin(), m_mediaTypeInfos.end(), [this](const MediaTypeInfo &item){
|
|
||||||
return item.description.compare(this->m_selectedMediaTypeDescription) == 0;
|
|
||||||
});
|
|
||||||
if (it != m_mediaTypeInfos.end()) {
|
|
||||||
pSelectedMediaType = (*it).p_mediaType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = S_OK;
|
|
||||||
|
|
||||||
if (!pSelectedMediaType) {
|
|
||||||
pSelectedMediaType = m_pAutoMediaType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
hr = ChangeMediaType(pSelectedMediaType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
log_info("iidx:camhook", "[{}] Creating thread", m_name);
|
|
||||||
CreateThread();
|
|
||||||
}
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::ChangeMediaType(IMFMediaType *pType) {
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
MediaTypeInfo info = GetMediaTypeInfo(pType);
|
|
||||||
log_info("iidx:camhook", "[{}] Changing media type: {}", m_name, info.description);
|
|
||||||
|
|
||||||
auto it = std::find_if(m_mediaTypeInfos.begin(), m_mediaTypeInfos.end(), [pType](const MediaTypeInfo &item) {
|
|
||||||
return item.p_mediaType == pType;
|
|
||||||
});
|
|
||||||
m_selectedMediaTypeIndex = it - m_mediaTypeInfos.begin();
|
|
||||||
m_selectedMediaTypeDescription = info.description;
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
hr = m_pSourceReader->SetCurrentMediaType(
|
|
||||||
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
|
||||||
NULL,
|
|
||||||
pType
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
m_cameraWidth = info.width;
|
|
||||||
m_cameraHeight = info.height;
|
|
||||||
UpdateDrawRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IIDXLocalCamera::UpdateDrawRect() {
|
|
||||||
double cameraRatio = (double)m_cameraWidth / m_cameraHeight;
|
|
||||||
|
|
||||||
RECT cameraRect = {0, 0, m_cameraWidth, m_cameraHeight};
|
|
||||||
RECT targetRect = {0, 0, TARGET_SURFACE_WIDTH, TARGET_SURFACE_HEIGHT};
|
|
||||||
|
|
||||||
switch (m_drawMode) {
|
|
||||||
case DrawModeStretch: {
|
|
||||||
CopyRect(&m_rcSource, &cameraRect);
|
|
||||||
CopyRect(&m_rcDest, &targetRect);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DrawModeCrop: {
|
|
||||||
if (cameraRatio > RATIO_16_9) {
|
|
||||||
// take full source height, crop left/right
|
|
||||||
LONG croppedWidth = m_cameraHeight * RATIO_16_9;
|
|
||||||
m_rcSource.left = (LONG)(m_cameraWidth - croppedWidth) / 2;
|
|
||||||
m_rcSource.top = 0;
|
|
||||||
m_rcSource.right = m_rcSource.left + croppedWidth;
|
|
||||||
m_rcSource.bottom = m_cameraHeight;
|
|
||||||
} else {
|
|
||||||
// take full source width, crop top/bottom
|
|
||||||
LONG croppedHeight = m_cameraWidth / RATIO_16_9;
|
|
||||||
m_rcSource.left = 0;
|
|
||||||
m_rcSource.top = (LONG)(m_cameraHeight - croppedHeight) / 2;
|
|
||||||
m_rcSource.right = m_cameraWidth;
|
|
||||||
m_rcSource.bottom = m_rcSource.top + croppedHeight;
|
|
||||||
}
|
|
||||||
CopyRect(&m_rcDest, &targetRect);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DrawModeLetterbox: {
|
|
||||||
CopyRect(&m_rcSource, &cameraRect);
|
|
||||||
if (cameraRatio > RATIO_16_9) {
|
|
||||||
// take full dest width, empty top/bottom
|
|
||||||
LONG boxedHeight = TARGET_SURFACE_WIDTH / cameraRatio;
|
|
||||||
m_rcDest.left = 0;
|
|
||||||
m_rcDest.top = (LONG)(TARGET_SURFACE_HEIGHT - boxedHeight) / 2;
|
|
||||||
m_rcDest.right = TARGET_SURFACE_WIDTH;
|
|
||||||
m_rcDest.bottom = m_rcDest.top + boxedHeight;
|
|
||||||
} else {
|
|
||||||
// take full dest height, empty top/bottom
|
|
||||||
LONG boxedWidth = TARGET_SURFACE_HEIGHT * cameraRatio;
|
|
||||||
m_rcDest.left = (LONG)(TARGET_SURFACE_WIDTH - boxedWidth) / 2;
|
|
||||||
m_rcDest.top = 0;
|
|
||||||
m_rcDest.right = m_rcDest.left + boxedWidth;
|
|
||||||
m_rcDest.bottom = TARGET_SURFACE_HEIGHT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DrawModeCrop4_3: {
|
|
||||||
if (cameraRatio > RATIO_4_3) {
|
|
||||||
// take full source height, crop left/right
|
|
||||||
LONG croppedWidth = m_cameraHeight * RATIO_4_3;
|
|
||||||
m_rcSource.left = (LONG)(m_cameraWidth - croppedWidth) / 2;
|
|
||||||
m_rcSource.top = 0;
|
|
||||||
m_rcSource.right = m_rcSource.left + croppedWidth;
|
|
||||||
m_rcSource.bottom = m_cameraHeight;
|
|
||||||
} else {
|
|
||||||
// take full source width, crop top/bottom
|
|
||||||
LONG croppedHeight = m_cameraWidth / RATIO_4_3;
|
|
||||||
m_rcSource.left = 0;
|
|
||||||
m_rcSource.top = (LONG)(m_cameraHeight - croppedHeight) / 2;
|
|
||||||
m_rcSource.right = m_cameraWidth;
|
|
||||||
m_rcSource.bottom = m_rcSource.top + croppedHeight;
|
|
||||||
}
|
|
||||||
CopyRect(&m_rcDest, &targetRect);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DrawModeLetterbox4_3: {
|
|
||||||
CopyRect(&m_rcSource, &cameraRect);
|
|
||||||
if (cameraRatio > RATIO_4_3) {
|
|
||||||
// take full dest width, empty top/bottom
|
|
||||||
LONG boxedHeight = TARGET_SURFACE_HEIGHT / RATIO_4_3;
|
|
||||||
m_rcDest.left = 0;
|
|
||||||
m_rcDest.top = (LONG)(TARGET_SURFACE_HEIGHT - boxedHeight) / 2;
|
|
||||||
m_rcDest.right = TARGET_SURFACE_WIDTH;
|
|
||||||
m_rcDest.bottom = m_rcDest.top + boxedHeight;
|
|
||||||
} else {
|
|
||||||
// take full dest height, empty top/bottom
|
|
||||||
LONG boxedWidth = TARGET_SURFACE_WIDTH * RATIO_4_3;
|
|
||||||
m_rcDest.left = (LONG)(TARGET_SURFACE_WIDTH - boxedWidth) / 2;
|
|
||||||
m_rcDest.top = 0;
|
|
||||||
m_rcDest.right = m_rcDest.left + boxedWidth;
|
|
||||||
m_rcDest.bottom = TARGET_SURFACE_HEIGHT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure the rects are valid
|
|
||||||
IntersectRect(&m_rcSource, &m_rcSource, &cameraRect);
|
|
||||||
IntersectRect(&m_rcDest, &m_rcDest, &targetRect);
|
|
||||||
|
|
||||||
log_info(
|
|
||||||
"iidx:camhook", "[{}] Update draw rect mode={} src=({}, {}, {}, {}) dest=({}, {}, {}, {})",
|
|
||||||
m_name,
|
|
||||||
DRAW_MODE_LABELS[m_drawMode],
|
|
||||||
m_rcSource.left,
|
|
||||||
m_rcSource.top,
|
|
||||||
m_rcSource.right,
|
|
||||||
m_rcSource.bottom,
|
|
||||||
m_rcDest.left,
|
|
||||||
m_rcDest.top,
|
|
||||||
m_rcDest.right,
|
|
||||||
m_rcDest.bottom
|
|
||||||
);
|
|
||||||
|
|
||||||
m_device->ColorFill(m_pDestSurf, &targetRect, D3DCOLOR_XRGB(0, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IIDXLocalCamera::CreateThread() {
|
|
||||||
// Create thread
|
|
||||||
m_drawThread = new std::thread([this]() {
|
|
||||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
|
|
||||||
|
|
||||||
double accumulator = 0.0;
|
|
||||||
while (this->m_active) {
|
|
||||||
this->Render();
|
|
||||||
double frameTimeMicroSec = (1000000.0 / this->m_frameRate);
|
|
||||||
int floorFrameTimeMicroSec = floor(frameTimeMicroSec);
|
|
||||||
// This maybe an overkill but who knows
|
|
||||||
accumulator += (frameTimeMicroSec - floorFrameTimeMicroSec);
|
|
||||||
if (accumulator > 1.0) {
|
|
||||||
accumulator -= 1.0;
|
|
||||||
floorFrameTimeMicroSec += 1;
|
|
||||||
}
|
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(floorFrameTimeMicroSec));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 IIDXLocalCamera::GetTexture() {
|
|
||||||
return m_texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
IAMCameraControl* IIDXLocalCamera::GetCameraControl() {
|
|
||||||
return m_pCameraControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::InitCameraControl() {
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
log_misc("iidx:camhook", "[{}] Init camera control", m_name);
|
|
||||||
|
|
||||||
hr = m_pSource->QueryInterface(IID_IAMCameraControl, (void**)&m_pCameraControl);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
// The device does not support IAMCameraControl
|
|
||||||
log_warning("iidx:camhook", "[{}] Camera control not supported", m_name);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < CAMERA_CONTROL_PROP_SIZE; i++) {
|
|
||||||
long minValue = 0;
|
|
||||||
long maxValue = 0;
|
|
||||||
long delta = 0;
|
|
||||||
long defaultValue = 0;
|
|
||||||
long defFlags = 0;
|
|
||||||
long value = 0;
|
|
||||||
long valueFlags = 0;
|
|
||||||
|
|
||||||
m_pCameraControl->GetRange(
|
|
||||||
i,
|
|
||||||
&minValue,
|
|
||||||
&maxValue,
|
|
||||||
&delta,
|
|
||||||
&defaultValue,
|
|
||||||
&defFlags
|
|
||||||
);
|
|
||||||
m_pCameraControl->Get(
|
|
||||||
i,
|
|
||||||
&value,
|
|
||||||
&valueFlags
|
|
||||||
);
|
|
||||||
m_controlProps.push_back({
|
|
||||||
minValue,
|
|
||||||
maxValue,
|
|
||||||
delta,
|
|
||||||
defaultValue,
|
|
||||||
defFlags,
|
|
||||||
value,
|
|
||||||
valueFlags,
|
|
||||||
});
|
|
||||||
|
|
||||||
CameraControlProp prop = m_controlProps.at(i);
|
|
||||||
|
|
||||||
log_misc(
|
|
||||||
"iidx:camhook", "[{}] >> {} range=({}, {}) default={} delta={} dFlags={} value={} vFlags={}",
|
|
||||||
m_name,
|
|
||||||
CAMERA_CONTROL_LABELS[i],
|
|
||||||
prop.minValue, prop.maxValue,
|
|
||||||
prop.defaultValue,
|
|
||||||
prop.delta,
|
|
||||||
prop.defFlags,
|
|
||||||
prop.value,
|
|
||||||
prop.valueFlags
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_controlOptionsInitialized = true;
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::GetCameraControlProp(int index, CameraControlProp *pProp) {
|
|
||||||
if (!m_controlOptionsInitialized) {
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto targetProp = m_controlProps.at(index);
|
|
||||||
|
|
||||||
pProp->minValue = targetProp.minValue;
|
|
||||||
pProp->maxValue = targetProp.maxValue;
|
|
||||||
pProp->defaultValue = targetProp.defaultValue;
|
|
||||||
pProp->delta = targetProp.delta;
|
|
||||||
pProp->defFlags = targetProp.defFlags;
|
|
||||||
pProp->value = targetProp.value;
|
|
||||||
pProp->valueFlags = targetProp.valueFlags;
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::SetCameraControlProp(int index, long value, long flags) {
|
|
||||||
if (!m_controlOptionsInitialized || !m_allowManualControl) {
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < 0 || index >= CAMERA_CONTROL_PROP_SIZE) {
|
|
||||||
return E_INVALIDARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto targetProp = &(m_controlProps.at(index));
|
|
||||||
HRESULT hr = m_pCameraControl->Set(index, value, flags);
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
m_pCameraControl->Get(
|
|
||||||
index,
|
|
||||||
&targetProp->value,
|
|
||||||
&targetProp->valueFlags
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::ResetCameraControlProps() {
|
|
||||||
log_info("iidx:camhook", "[{}] Reset camera control", m_name);
|
|
||||||
for (size_t i = 0; i < CAMERA_CONTROL_PROP_SIZE; i++) {
|
|
||||||
CameraControlProp prop = m_controlProps.at(i);
|
|
||||||
SetCameraControlProp(i, prop.defaultValue, prop.defFlags);
|
|
||||||
}
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string IIDXLocalCamera::GetName() {
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string IIDXLocalCamera::GetFriendlyName() {
|
|
||||||
return m_friendly_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string IIDXLocalCamera::GetSymLink() {
|
|
||||||
if (!m_pwszSymbolicLink) {
|
|
||||||
return "(unknown)";
|
|
||||||
}
|
|
||||||
return ws2s(m_pwszSymbolicLink);
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaTypeInfo IIDXLocalCamera::GetMediaTypeInfo(IMFMediaType *pType) {
|
|
||||||
MediaTypeInfo info = {};
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
MFRatio frameRate = { 0, 0 };
|
|
||||||
|
|
||||||
info.p_mediaType = pType;
|
|
||||||
|
|
||||||
// Find the video subtype.
|
|
||||||
hr = pType->GetGUID(MF_MT_SUBTYPE, &info.subtype);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
// Get the frame size.
|
|
||||||
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &info.width, &info.height);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
// Get frame rate
|
|
||||||
hr = MFGetAttributeRatio(
|
|
||||||
pType,
|
|
||||||
MF_MT_FRAME_RATE,
|
|
||||||
(UINT32*)&frameRate.Numerator,
|
|
||||||
(UINT32*)&frameRate.Denominator
|
|
||||||
);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
info.frameRate = frameRate.Numerator / frameRate.Denominator;
|
|
||||||
|
|
||||||
info.description = fmt::format(
|
|
||||||
"{}x{} @{}FPS {}",
|
|
||||||
info.width,
|
|
||||||
info.height,
|
|
||||||
(int)info.frameRate,
|
|
||||||
GetVideoFormatName(info.subtype)
|
|
||||||
);
|
|
||||||
done:
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string IIDXLocalCamera::GetVideoFormatName(GUID subtype) {
|
|
||||||
if (subtype == MFVideoFormat_YUY2) {
|
|
||||||
return "YUY2";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subtype == MFVideoFormat_NV12) {
|
|
||||||
return "NV12";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subtype == MFVideoFormat_MJPG) {
|
|
||||||
return "MJPG";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return values:
|
|
||||||
* S_OK: this is a "better" media type than the existing one
|
|
||||||
* S_FALSE: valid media type, but not "better"
|
|
||||||
* E_*: invalid media type
|
|
||||||
*/
|
|
||||||
HRESULT IIDXLocalCamera::TryMediaType(IMFMediaType *pType, UINT32 *pBestWidth, double *pBestFrameRate) {
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
UINT32 width = 0, height = 0;
|
|
||||||
GUID subtype = { 0, 0, 0, 0 };
|
|
||||||
MFRatio frameRate = { 0, 0 };
|
|
||||||
|
|
||||||
hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] Failed to get subtype: {:#x}", m_name, (ULONG)hr);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] Failed to get frame size: {:#x}", m_name, (ULONG)hr);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only support format with converters
|
|
||||||
// TODO: verify conversion support with DXVA
|
|
||||||
if (subtype != MFVideoFormat_YUY2 && subtype != MFVideoFormat_NV12) {
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Frame rate
|
|
||||||
hr = MFGetAttributeRatio(
|
|
||||||
pType,
|
|
||||||
MF_MT_FRAME_RATE,
|
|
||||||
(UINT32*)&frameRate.Numerator,
|
|
||||||
(UINT32*)&frameRate.Denominator
|
|
||||||
);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "[{}] Failed to get frame rate: {:#x}", m_name, (ULONG)hr);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
double frameRateValue = frameRate.Numerator / frameRate.Denominator;
|
|
||||||
|
|
||||||
// Filter by aspect ratio
|
|
||||||
auto aspect_ratio = 4.f / 3.f;
|
|
||||||
if (m_prefer_16_by_9) {
|
|
||||||
aspect_ratio = 16.f / 9.f;
|
|
||||||
}
|
|
||||||
if (fabs((height * aspect_ratio) - width) > 0.01f) {
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have 1280x720 already, only try for better frame rate
|
|
||||||
if ((*pBestWidth >= (UINT32)TARGET_SURFACE_WIDTH) && (width > *pBestWidth) && (frameRateValue < *pBestFrameRate)) {
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this format has better resolution / frame rate
|
|
||||||
if ((width > *pBestWidth) || (width >= (UINT32)TARGET_SURFACE_WIDTH && frameRateValue >= *pBestFrameRate)) {
|
|
||||||
// log_misc(
|
|
||||||
// "iidx:camhook", "Better media type {} ({}x{}) @({} FPS)",
|
|
||||||
// GetVideoFormatName(subtype),
|
|
||||||
// width,
|
|
||||||
// height,
|
|
||||||
// (int)frameRateValue
|
|
||||||
// );
|
|
||||||
|
|
||||||
*pBestWidth = width;
|
|
||||||
*pBestFrameRate = frameRateValue;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::InitTargetTexture() {
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
// Create a new destination texture
|
|
||||||
hr = m_device->CreateTexture(TARGET_SURFACE_WIDTH, TARGET_SURFACE_HEIGHT, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_texture, NULL);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
// Create a D3D9 surface for the destination texture so that camera sample can be drawn onto it
|
|
||||||
hr = m_texture->GetSurfaceLevel(0, &m_pDestSurf);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
// Make the game use this new texture as camera stream source
|
|
||||||
*m_camera_texture_target = m_texture;
|
|
||||||
*m_preview_texture_target = m_texture;
|
|
||||||
m_active = TRUE;
|
|
||||||
|
|
||||||
// Create texture for colour conversion
|
|
||||||
hr = m_device->CreateTexture(TARGET_SURFACE_WIDTH, TARGET_SURFACE_HEIGHT, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_conversionTexture, NULL);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
hr = m_conversionTexture->GetSurfaceLevel(0, &m_pConversionSurf);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
// Create texture for transformation
|
|
||||||
hr = m_device->CreateTexture(TARGET_SURFACE_WIDTH, TARGET_SURFACE_HEIGHT, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_transformTexture, NULL);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
hr = m_transformTexture->GetSurfaceLevel(0, &m_pTransformSurf);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
// Create texture for transformation result so that we don't have to screw our brain doing in-memory flipping
|
|
||||||
hr = m_device->CreateTexture(TARGET_SURFACE_WIDTH, TARGET_SURFACE_HEIGHT, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_transformResultTexture, NULL);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
hr = m_transformResultTexture->GetSurfaceLevel(0, &m_pTransformResultSurf);
|
|
||||||
if (FAILED(hr)) { goto done; }
|
|
||||||
|
|
||||||
// printTextureLevelDesc(m_texture);
|
|
||||||
// printTextureLevelDesc(m_texture_original);
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
log_misc("iidx:camhook", "[{}] Created texture", m_name);
|
|
||||||
} else {
|
|
||||||
log_warning("iidx:camhook", "[{}] Failed to create texture: {:#x}", m_name, (ULONG)hr);
|
|
||||||
}
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::FlushDrawCommands() {
|
|
||||||
IDirect3DQuery9* pEventQuery = nullptr;
|
|
||||||
// It is necessary to flush the command queue
|
|
||||||
// or the data is not ready for the receiver to read.
|
|
||||||
// Adapted from : https://msdn.microsoft.com/en-us/library/windows/desktop/bb172234%28v=vs.85%29.aspx
|
|
||||||
// Also see : http://www.ogre3d.org/forums/viewtopic.php?f=5&t=50486
|
|
||||||
m_device->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
|
|
||||||
if (pEventQuery) {
|
|
||||||
pEventQuery->Issue(D3DISSUE_END);
|
|
||||||
while (S_FALSE == pEventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH));
|
|
||||||
pEventQuery->Release(); // Must be released or causes a leak and reference count increment
|
|
||||||
}
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::DrawSample(IMFMediaBuffer *pSrcBuffer) {
|
|
||||||
if (!m_active) {
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// snap variables now so they don't change while inside the critical section
|
|
||||||
const auto flip_h = m_flipHorizontal;
|
|
||||||
const auto flip_v = m_flipVertical;
|
|
||||||
|
|
||||||
EnterCriticalSection(&m_critsec);
|
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
IDirect3DSurface9 *pCameraSurf = NULL;
|
|
||||||
|
|
||||||
hr = WrappedMFGetService(pSrcBuffer, MR_BUFFER_SERVICE, IID_PPV_ARGS(&pCameraSurf));
|
|
||||||
|
|
||||||
if (flip_h || flip_v) {
|
|
||||||
|
|
||||||
// Stretch Camera content to texture and perform color space conversion
|
|
||||||
hr = m_device->StretchRect(pCameraSurf, &m_rcSource, m_pConversionSurf, &m_rcDest, D3DTEXF_LINEAR);
|
|
||||||
|
|
||||||
// Copy converted camera content to dynamic texture for vertical/horizontal flipping
|
|
||||||
hr = m_device->StretchRect(m_pConversionSurf, NULL, m_pTransformSurf, NULL, D3DTEXF_NONE);
|
|
||||||
|
|
||||||
// Transform
|
|
||||||
D3DLOCKED_RECT srcLockedRect;
|
|
||||||
hr = m_pTransformSurf->LockRect(&srcLockedRect, NULL, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY);
|
|
||||||
D3DLOCKED_RECT destLockedRect;
|
|
||||||
hr = m_pTransformResultSurf->LockRect(&destLockedRect, NULL, D3DLOCK_NOSYSLOCK);
|
|
||||||
|
|
||||||
BYTE* pSrc = (BYTE*)srcLockedRect.pBits;
|
|
||||||
BYTE* pDest = (BYTE*)destLockedRect.pBits;
|
|
||||||
const int pixelSize = 4;
|
|
||||||
|
|
||||||
if (flip_v) {
|
|
||||||
pDest += destLockedRect.Pitch * (TARGET_SURFACE_HEIGHT - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int y = 0; y < TARGET_SURFACE_HEIGHT; y++) {
|
|
||||||
for (int x = 0; x < TARGET_SURFACE_WIDTH; x++) {
|
|
||||||
memcpy(
|
|
||||||
pDest + x * pixelSize,
|
|
||||||
pSrc + (flip_h ? (TARGET_SURFACE_WIDTH - x - 1) : x) * pixelSize,
|
|
||||||
pixelSize
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pSrc += srcLockedRect.Pitch;
|
|
||||||
if (flip_v) {
|
|
||||||
pDest -= destLockedRect.Pitch;
|
|
||||||
} else {
|
|
||||||
pDest += destLockedRect.Pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pTransformSurf->UnlockRect();
|
|
||||||
m_pTransformResultSurf->UnlockRect();
|
|
||||||
|
|
||||||
// Stretch camera texture to transform surface
|
|
||||||
hr = m_device->StretchRect(m_pTransformResultSurf, NULL, m_pDestSurf, NULL, D3DTEXF_NONE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// No transformation needed, stretch to destination texture directly
|
|
||||||
hr = m_device->StretchRect(pCameraSurf, &m_rcSource, m_pDestSurf, &m_rcDest, D3DTEXF_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlushDrawCommands();
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("iidx:camhook", "Error in DrawSample {:#x}", (ULONG)hr);
|
|
||||||
}
|
|
||||||
SafeRelease(&pCameraSurf);
|
|
||||||
LeaveCriticalSection(&m_critsec);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT IIDXLocalCamera::ReadSample() {
|
|
||||||
HRESULT hr;
|
|
||||||
DWORD streamIndex, flags;
|
|
||||||
LONGLONG llTimeStamp;
|
|
||||||
IMFSample *pSample = nullptr;
|
|
||||||
IMFMediaBuffer *pBuffer = nullptr;
|
|
||||||
|
|
||||||
hr = m_pSourceReader->ReadSample(
|
|
||||||
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
|
||||||
0,
|
|
||||||
&streamIndex,
|
|
||||||
&flags,
|
|
||||||
&llTimeStamp,
|
|
||||||
&pSample
|
|
||||||
);
|
|
||||||
|
|
||||||
if (pSample) {
|
|
||||||
// Draw to D3D
|
|
||||||
pSample->GetBufferByIndex(0, &pBuffer);
|
|
||||||
hr = DrawSample(pBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeRelease(&pBuffer);
|
|
||||||
SafeRelease(&pSample);
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 IIDXLocalCamera::Render() {
|
|
||||||
if (!m_active) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
HRESULT hr = ReadSample();
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return m_texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG IIDXLocalCamera::Release() {
|
|
||||||
log_info("iidx:camhook", "[{}] Release camera", m_name);
|
|
||||||
m_active = false;
|
|
||||||
|
|
||||||
ULONG uCount = InterlockedDecrement(&m_nRefCount);
|
|
||||||
|
|
||||||
*m_camera_texture_target = m_camera_texture_original;
|
|
||||||
*m_preview_texture_target = m_preview_texture_original;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_mediaTypeInfos.size(); i++) {
|
|
||||||
SafeRelease(&(m_mediaTypeInfos.at(i).p_mediaType));
|
|
||||||
}
|
|
||||||
|
|
||||||
SafeRelease(&m_pDestSurf);
|
|
||||||
SafeRelease(&m_pTransformSurf);
|
|
||||||
SafeRelease(&m_pConversionSurf);
|
|
||||||
SafeRelease(&m_pTransformResultSurf);
|
|
||||||
SafeRelease(&m_texture);
|
|
||||||
SafeRelease(&m_conversionTexture);
|
|
||||||
SafeRelease(&m_transformTexture);
|
|
||||||
SafeRelease(&m_transformResultTexture);
|
|
||||||
|
|
||||||
if (m_pSource) {
|
|
||||||
m_pSource->Shutdown();
|
|
||||||
m_pSource->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
CoTaskMemFree(m_pwszSymbolicLink);
|
|
||||||
m_pwszSymbolicLink = NULL;
|
|
||||||
m_cchSymbolicLink = 0;
|
|
||||||
|
|
||||||
if (uCount == 0) {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
// For thread safety, return a temporary variable.
|
|
||||||
return uCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-217
@@ -1,217 +0,0 @@
|
|||||||
#include "jb.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#include "avs/game.h"
|
|
||||||
#include "cfg/configurator.h"
|
|
||||||
#include "hooks/graphics/graphics.h"
|
|
||||||
#include "touch/touch.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "util/detour.h"
|
|
||||||
#include "util/libutils.h"
|
|
||||||
|
|
||||||
#define JB_BUTTON_SIZE 160
|
|
||||||
#define JB_BUTTON_GAP 37
|
|
||||||
#define JB_BUTTON_HITBOX (JB_BUTTON_SIZE + JB_BUTTON_GAP)
|
|
||||||
|
|
||||||
namespace games::jb {
|
|
||||||
|
|
||||||
// touch stuff
|
|
||||||
bool TOUCH_LEGACY_BOX = false;
|
|
||||||
static bool TOUCH_ENABLE = false;
|
|
||||||
static bool TOUCH_ATTACHED = false;
|
|
||||||
static bool IS_PORTRAIT = true;
|
|
||||||
static std::vector<TouchPoint> TOUCH_POINTS;
|
|
||||||
bool TOUCH_STATE[16];
|
|
||||||
|
|
||||||
void touch_update() {
|
|
||||||
|
|
||||||
// check if touch enabled
|
|
||||||
if (!TOUCH_ENABLE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach touch module
|
|
||||||
if (!TOUCH_ATTACHED) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find the game window.
|
|
||||||
* We check the foreground window first, then fall back to searching for the window title
|
|
||||||
* All game versions seem to have their model first in the window title
|
|
||||||
*/
|
|
||||||
HWND wnd = GetForegroundWindow();
|
|
||||||
if (!string_begins_with(GetActiveWindowTitle(), avs::game::MODEL)) {
|
|
||||||
wnd = FindWindowBeginsWith(avs::game::MODEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we have a window handle
|
|
||||||
if (!wnd) {
|
|
||||||
log_warning("jubeat", "could not find window handle for touch");
|
|
||||||
TOUCH_ENABLE = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach touch hook
|
|
||||||
log_info("jubeat", "using window handle for touch: {}", fmt::ptr(wnd));
|
|
||||||
touch_create_wnd(wnd, true);
|
|
||||||
|
|
||||||
// show cursor
|
|
||||||
if (GRAPHICS_SHOW_CURSOR) {
|
|
||||||
ShowCursor(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// earlier games use a different screen orientation
|
|
||||||
if (!avs::game::is_model("L44")) {
|
|
||||||
IS_PORTRAIT = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set attached
|
|
||||||
TOUCH_ATTACHED = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset touch state
|
|
||||||
memset(TOUCH_STATE, 0, sizeof(TOUCH_STATE));
|
|
||||||
|
|
||||||
// check touch points
|
|
||||||
// note that the IO code in device.cpp will correctly compensate for orientation, depending on the model.
|
|
||||||
TOUCH_POINTS.clear();
|
|
||||||
touch_get_points(TOUCH_POINTS);
|
|
||||||
if (TOUCH_LEGACY_BOX) {
|
|
||||||
auto offset = IS_PORTRAIT ? 580 : 0;
|
|
||||||
for (auto &tp : TOUCH_POINTS) {
|
|
||||||
|
|
||||||
// get grid coordinates
|
|
||||||
int x = tp.x * 4 / 768;
|
|
||||||
int y = (tp.y - offset) * 4 / (1360 - 580);
|
|
||||||
|
|
||||||
// set the corresponding state
|
|
||||||
int index = y * 4 + x;
|
|
||||||
if (index >= 0 && index < 16) {
|
|
||||||
TOUCH_STATE[index] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (auto &tp : TOUCH_POINTS) {
|
|
||||||
int x_relative = tp.x;
|
|
||||||
int y_relative = tp.y;
|
|
||||||
|
|
||||||
// x_relative and y_relative are relative to the top-left pixel of the first button
|
|
||||||
if (IS_PORTRAIT) {
|
|
||||||
// which is at (8, 602) in portrait:
|
|
||||||
// X: [8...759] (752 pixels wide)
|
|
||||||
// Y: [602...1353] (752 pixels high)
|
|
||||||
x_relative -= 8;
|
|
||||||
y_relative -= 602;
|
|
||||||
} else {
|
|
||||||
// and at (8, 8) in landscape
|
|
||||||
x_relative -= 8;
|
|
||||||
y_relative -= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x_relative < 0 || y_relative < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// x_hitbox and y_hitbox is relative to top-left pixel of each button
|
|
||||||
int x_index = x_relative / JB_BUTTON_HITBOX;
|
|
||||||
int x_hitbox = x_relative % JB_BUTTON_HITBOX;
|
|
||||||
int y_index = y_relative / JB_BUTTON_HITBOX;
|
|
||||||
int y_hitbox = y_relative % JB_BUTTON_HITBOX;
|
|
||||||
|
|
||||||
// check if the gap was touched
|
|
||||||
if (x_hitbox > JB_BUTTON_SIZE || y_hitbox > JB_BUTTON_SIZE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the corresponding state
|
|
||||||
int index = y_index * 4 + x_index;
|
|
||||||
if (0 <= index && index < 16) {
|
|
||||||
TOUCH_STATE[index] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* to fix "IP ADDR CHANGE" errors on boot and in-game when using weird network setups such as a VPN
|
|
||||||
*/
|
|
||||||
static BOOL __stdcall network_addr_is_changed() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* to fix lag spikes when game tries to ping "eamuse.konami.fun" every few minutes
|
|
||||||
*/
|
|
||||||
static BOOL __stdcall network_get_network_check_info() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* to fix network error on non DHCP interfaces
|
|
||||||
*/
|
|
||||||
static BOOL __cdecl network_get_dhcp_result() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl GFDbgSetReportFunc(void *func) {
|
|
||||||
log_misc("jubeat", "GFDbgSetReportFunc hook hit");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
JBGame::JBGame() : Game("Jubeat") {
|
|
||||||
}
|
|
||||||
|
|
||||||
void JBGame::pre_attach() {
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
const auto current_path = std::filesystem::current_path();
|
|
||||||
log_misc("jubeat", "current working directory: {}", current_path.string());
|
|
||||||
if (current_path.parent_path() == current_path.root_path()) {
|
|
||||||
log_warning(
|
|
||||||
"jubeat",
|
|
||||||
"\n\nInvalid path error; jubeat cannot run from a directory in the drive root\n"
|
|
||||||
"The game will overflow the stack and silently fail to boot\n\n"
|
|
||||||
"Instead, it must be at least two levels deep, for example:\n"
|
|
||||||
" c:\\jubeat\\spice.exe <- CRASH\n"
|
|
||||||
" c:\\jubeat\\contents\\spice.exe <- OK\n\n"
|
|
||||||
"To fix this, create a new directory and move ALL game files there.\n\n"
|
|
||||||
"Your current working directory: {}\n",
|
|
||||||
current_path.string());
|
|
||||||
|
|
||||||
log_fatal(
|
|
||||||
"jubeat",
|
|
||||||
"Invalid path error; jubeat cannot run from a directory in the drive root");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JBGame::attach() {
|
|
||||||
Game::attach();
|
|
||||||
|
|
||||||
// enable touch
|
|
||||||
TOUCH_ENABLE = true;
|
|
||||||
|
|
||||||
// enable debug logging of gftools
|
|
||||||
HMODULE gftools = libutils::try_module("gftools.dll");
|
|
||||||
detour::inline_hook((void *) GFDbgSetReportFunc, libutils::try_proc(
|
|
||||||
gftools, "GFDbgSetReportFunc"));
|
|
||||||
|
|
||||||
// apply patches
|
|
||||||
HMODULE network = libutils::try_module("network.dll");
|
|
||||||
detour::inline_hook((void *) network_addr_is_changed, libutils::try_proc(
|
|
||||||
network, "network_addr_is_changed"));
|
|
||||||
detour::inline_hook((void *) network_get_network_check_info, libutils::try_proc(
|
|
||||||
network, "network_get_network_check_info"));
|
|
||||||
detour::inline_hook((void *) network_get_dhcp_result, libutils::try_proc(
|
|
||||||
network, "network_get_dhcp_result"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void JBGame::detach() {
|
|
||||||
Game::detach();
|
|
||||||
|
|
||||||
// disable touch
|
|
||||||
TOUCH_ENABLE = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
#include "poke.h"
|
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include "games/nost/io.h"
|
|
||||||
#include "cfg/api.h"
|
|
||||||
#include "rawinput/rawinput.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
#include "touch/touch.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
|
|
||||||
namespace games::nost::poke {
|
|
||||||
|
|
||||||
static std::thread *THREAD = nullptr;
|
|
||||||
static volatile bool THREAD_RUNNING = false;
|
|
||||||
|
|
||||||
static const std::unordered_map<int, std::pair<LONG, LONG>> NOST_POKE_NUM {
|
|
||||||
{EAM_IO_KEYPAD_0, {760, 440}},
|
|
||||||
{EAM_IO_KEYPAD_1, {760, 385}},
|
|
||||||
{EAM_IO_KEYPAD_2, {820, 385}},
|
|
||||||
{EAM_IO_KEYPAD_3, {880, 385}},
|
|
||||||
{EAM_IO_KEYPAD_4, {760, 325}},
|
|
||||||
{EAM_IO_KEYPAD_5, {820, 325}},
|
|
||||||
{EAM_IO_KEYPAD_6, {880, 325}},
|
|
||||||
{EAM_IO_KEYPAD_7, {760, 265}},
|
|
||||||
{EAM_IO_KEYPAD_8, {820, 265}},
|
|
||||||
{EAM_IO_KEYPAD_9, {880, 265}},
|
|
||||||
{EAM_IO_KEYPAD_00, {820, 440}}, // erase button
|
|
||||||
{EAM_IO_KEYPAD_DECIMAL, {880, 440}} // also erase button
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::unordered_map<games::nost::Buttons::Button, std::pair<LONG, LONG>> NOST_POKE {
|
|
||||||
{games::nost::Buttons::Button::PokeConfirm, {1100, 525}},
|
|
||||||
{games::nost::Buttons::Button::PokeBack, {340, 100}},
|
|
||||||
{games::nost::Buttons::Button::PokeSong1, {450, 190}},
|
|
||||||
{games::nost::Buttons::Button::PokeSong2, {450, 330}},
|
|
||||||
{games::nost::Buttons::Button::PokeSong3, {450, 480}},
|
|
||||||
{games::nost::Buttons::Button::PokeSong4, {840, 190}},
|
|
||||||
{games::nost::Buttons::Button::PokeSong5, {840, 330}},
|
|
||||||
{games::nost::Buttons::Button::PokeSong6, {840, 480}},
|
|
||||||
{games::nost::Buttons::Button::PokeDifficulty1, {820, 240}},
|
|
||||||
{games::nost::Buttons::Button::PokeDifficulty2, {820, 320}},
|
|
||||||
{games::nost::Buttons::Button::PokeDifficulty3, {820, 410}},
|
|
||||||
{games::nost::Buttons::Button::PokeDifficulty4, {820, 490}},
|
|
||||||
};
|
|
||||||
|
|
||||||
void clear_touch_points(std::vector<TouchPoint> *touch_points) {
|
|
||||||
std::vector<DWORD> touch_ids;
|
|
||||||
for (auto &touch : *touch_points) {
|
|
||||||
touch_ids.emplace_back(touch.id);
|
|
||||||
}
|
|
||||||
touch_remove_points(&touch_ids);
|
|
||||||
touch_points->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
// check if already running
|
|
||||||
if (THREAD) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new thread
|
|
||||||
THREAD_RUNNING = true;
|
|
||||||
THREAD = new std::thread([] {
|
|
||||||
const DWORD touch_id = (DWORD)(0xFFFFFFFE);
|
|
||||||
|
|
||||||
const int swipe_anim_total_frames = 6;
|
|
||||||
const int swipe_anim_y = 300;
|
|
||||||
|
|
||||||
const int swipe_next_page_x_begin = 1120;
|
|
||||||
const int swipe_next_page_x_end = 1120-120;
|
|
||||||
|
|
||||||
const int swipe_prev_page_x_begin = 280-120;
|
|
||||||
const int swipe_prev_page_x_end = 280;
|
|
||||||
|
|
||||||
int next_page_anim_index = -1;
|
|
||||||
int prev_page_anim_index = -1;
|
|
||||||
std::vector<TouchPoint> touch_points;
|
|
||||||
|
|
||||||
bool touch_release = false;
|
|
||||||
|
|
||||||
// log
|
|
||||||
log_info("poke", "enabled");
|
|
||||||
|
|
||||||
// set variable to false to stop
|
|
||||||
while (THREAD_RUNNING) {
|
|
||||||
// clean up touch from last frame
|
|
||||||
if (!touch_points.empty()) {
|
|
||||||
if (touch_release) {
|
|
||||||
clear_touch_points(&touch_points);
|
|
||||||
touch_release = false;
|
|
||||||
} else {
|
|
||||||
touch_points.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &buttons = games::nost::get_buttons();
|
|
||||||
|
|
||||||
if (0 <= next_page_anim_index) {
|
|
||||||
const auto delta =
|
|
||||||
(swipe_next_page_x_end - swipe_next_page_x_begin)
|
|
||||||
* (swipe_anim_total_frames - next_page_anim_index) / swipe_anim_total_frames;
|
|
||||||
|
|
||||||
TouchPoint tp {
|
|
||||||
.id = touch_id,
|
|
||||||
.x = (LONG)swipe_next_page_x_begin + delta,
|
|
||||||
.y = (LONG)swipe_anim_y,
|
|
||||||
.mouse = true,
|
|
||||||
};
|
|
||||||
touch_points.emplace_back(tp);
|
|
||||||
next_page_anim_index--;
|
|
||||||
if (next_page_anim_index < 0) {
|
|
||||||
touch_release = true;
|
|
||||||
}
|
|
||||||
} else if (0 <= prev_page_anim_index) {
|
|
||||||
const auto delta =
|
|
||||||
(swipe_prev_page_x_end - swipe_prev_page_x_begin)
|
|
||||||
* (swipe_anim_total_frames - prev_page_anim_index) / swipe_anim_total_frames;
|
|
||||||
|
|
||||||
TouchPoint tp {
|
|
||||||
.id = touch_id,
|
|
||||||
.x = (LONG)swipe_prev_page_x_begin + delta,
|
|
||||||
.y = (LONG)swipe_anim_y,
|
|
||||||
.mouse = true,
|
|
||||||
};
|
|
||||||
touch_points.emplace_back(tp);
|
|
||||||
prev_page_anim_index--;
|
|
||||||
if (prev_page_anim_index < 0) {
|
|
||||||
touch_release = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (const auto& it : NOST_POKE) {
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(it.first))) {
|
|
||||||
TouchPoint tp {
|
|
||||||
.id = touch_id,
|
|
||||||
.x = it.second.first,
|
|
||||||
.y = it.second.second,
|
|
||||||
.mouse = true,
|
|
||||||
};
|
|
||||||
touch_points.emplace_back(tp);
|
|
||||||
touch_release = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!touch_release) {
|
|
||||||
const auto state = eamuse_get_keypad_state(0);
|
|
||||||
if (state) {
|
|
||||||
for (const auto& it : NOST_POKE_NUM) {
|
|
||||||
if (state & (1 << it.first)) {
|
|
||||||
TouchPoint tp {
|
|
||||||
.id = touch_id,
|
|
||||||
.x = it.second.first,
|
|
||||||
.y = it.second.second,
|
|
||||||
.mouse = true,
|
|
||||||
};
|
|
||||||
touch_points.emplace_back(tp);
|
|
||||||
touch_release = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// start animations for next frame
|
|
||||||
if (!touch_release) {
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(games::nost::Buttons::PokeNextPage))) {
|
|
||||||
next_page_anim_index = swipe_anim_total_frames;
|
|
||||||
}
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(games::nost::Buttons::PokePrevPage))) {
|
|
||||||
prev_page_anim_index = swipe_anim_total_frames;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!touch_points.empty()) {
|
|
||||||
touch_write_points(&touch_points);
|
|
||||||
}
|
|
||||||
|
|
||||||
// slow down
|
|
||||||
Sleep(30);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
if (!THREAD) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop old thread
|
|
||||||
THREAD_RUNNING = false;
|
|
||||||
THREAD->join();
|
|
||||||
|
|
||||||
// delete thread
|
|
||||||
delete THREAD;
|
|
||||||
THREAD = nullptr;
|
|
||||||
|
|
||||||
// log
|
|
||||||
log_info("poke", "disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#include "otoca.h"
|
|
||||||
#include "p4io.h"
|
|
||||||
#include "games/shared/printer.h"
|
|
||||||
#include "util/libutils.h"
|
|
||||||
|
|
||||||
namespace games::otoca {
|
|
||||||
|
|
||||||
OtocaGame::OtocaGame() : Game("Otoca D'or") {
|
|
||||||
}
|
|
||||||
|
|
||||||
OtocaGame::~OtocaGame() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void OtocaGame::attach() {
|
|
||||||
Game::attach();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* arkkep.dll uses LoadLibrary to access game.dll
|
|
||||||
* we preload it so that hooks (e.g. for graphics) will work
|
|
||||||
*/
|
|
||||||
libutils::try_library("game.dll");
|
|
||||||
|
|
||||||
// initialize IO hooks
|
|
||||||
p4io_hook();
|
|
||||||
games::shared::printer_attach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
#include "io.h"
|
|
||||||
|
|
||||||
std::vector<Button> &games::popn::get_buttons() {
|
|
||||||
static std::vector<Button> buttons;
|
|
||||||
|
|
||||||
if (buttons.empty()) {
|
|
||||||
buttons = GameAPI::Buttons::getButtons("Pop'n Music");
|
|
||||||
|
|
||||||
GameAPI::Buttons::sortButtons(
|
|
||||||
&buttons,
|
|
||||||
"Service",
|
|
||||||
"Test",
|
|
||||||
"Coin Mech",
|
|
||||||
"Button 1",
|
|
||||||
"Button 2",
|
|
||||||
"Button 3",
|
|
||||||
"Button 4",
|
|
||||||
"Button 5",
|
|
||||||
"Button 6",
|
|
||||||
"Button 7",
|
|
||||||
"Button 8",
|
|
||||||
"Button 9"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string games::popn::get_buttons_help() {
|
|
||||||
// keep to max 100 characters wide
|
|
||||||
return
|
|
||||||
" 2 4 6 8 \n"
|
|
||||||
" 1 3 5 7 9 "
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Light> &games::popn::get_lights() {
|
|
||||||
static std::vector<Light> lights;
|
|
||||||
|
|
||||||
if (lights.empty()) {
|
|
||||||
lights = GameAPI::Lights::getLights("Pop'n Music");
|
|
||||||
|
|
||||||
GameAPI::Lights::sortLights(
|
|
||||||
&lights,
|
|
||||||
"Button 1",
|
|
||||||
"Button 2",
|
|
||||||
"Button 3",
|
|
||||||
"Button 4",
|
|
||||||
"Button 5",
|
|
||||||
"Button 6",
|
|
||||||
"Button 7",
|
|
||||||
"Button 8",
|
|
||||||
"Button 9",
|
|
||||||
"Top LED 1",
|
|
||||||
"Top LED 2",
|
|
||||||
"Top LED 3",
|
|
||||||
"Top LED 4",
|
|
||||||
"Top LED 5",
|
|
||||||
"Top LED 6",
|
|
||||||
"Top LED 7",
|
|
||||||
"Top LED 8",
|
|
||||||
"Top LED 9",
|
|
||||||
"Top LED 10",
|
|
||||||
"Top LED 11",
|
|
||||||
"Top LED 12",
|
|
||||||
"Top LED 13",
|
|
||||||
"Top LED 14",
|
|
||||||
"Top LED 15",
|
|
||||||
"Top LED 16",
|
|
||||||
"Top LED 17",
|
|
||||||
"Top LED 18",
|
|
||||||
"Top LED 19",
|
|
||||||
"Top LED 20",
|
|
||||||
"Top LED 21",
|
|
||||||
"Top LED 22",
|
|
||||||
"Top LED 23",
|
|
||||||
"Top LED 24",
|
|
||||||
"Top LED 25",
|
|
||||||
"Top LED 26",
|
|
||||||
"Top LED 27",
|
|
||||||
"Top LED 28",
|
|
||||||
"Top LED 29",
|
|
||||||
"Top LED 30",
|
|
||||||
"Top LED 31",
|
|
||||||
"Top LED 32",
|
|
||||||
"Top LED R",
|
|
||||||
"Top LED G",
|
|
||||||
"Top LED B",
|
|
||||||
"Hi Lamp 1",
|
|
||||||
"Hi Lamp 2",
|
|
||||||
"Hi Lamp 3",
|
|
||||||
"Hi Lamp 4",
|
|
||||||
"Hi Lamp 5",
|
|
||||||
"Left Lamp 1",
|
|
||||||
"Left Lamp 2",
|
|
||||||
"Right Lamp 1",
|
|
||||||
"Right Lamp 2",
|
|
||||||
"Woofer LED R",
|
|
||||||
"Woofer LED G",
|
|
||||||
"Woofer LED B"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lights;
|
|
||||||
}
|
|
||||||
@@ -1,324 +0,0 @@
|
|||||||
#include "avs/game.h"
|
|
||||||
#include "popn.h"
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include "rawinput/rawinput.h"
|
|
||||||
#include "util/detour.h"
|
|
||||||
#include "util/fileutils.h"
|
|
||||||
#include "util/libutils.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "cfg/button.h"
|
|
||||||
#include "cfg/api.h"
|
|
||||||
#include "hooks/sleephook.h"
|
|
||||||
#include "launcher/launcher.h"
|
|
||||||
#include "launcher/logger.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
#include "io.h"
|
|
||||||
|
|
||||||
namespace games::popn {
|
|
||||||
|
|
||||||
static int __cdecl usbCheckAlive() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbCheckSecurityNew() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbCoinGet() {
|
|
||||||
return eamuse_coin_get_stock();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbCoinMode() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbEnd() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbFirmResult() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbGetKEYID() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbGetSecurity() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbLamp(uint32_t lamp_bits) {
|
|
||||||
|
|
||||||
// get lights
|
|
||||||
auto &lights = get_lights();
|
|
||||||
|
|
||||||
// bit scan
|
|
||||||
static const size_t mapping[] = {
|
|
||||||
Lights::Button1,
|
|
||||||
Lights::Button2,
|
|
||||||
Lights::Button3,
|
|
||||||
Lights::Button4,
|
|
||||||
Lights::Button5,
|
|
||||||
Lights::Button6,
|
|
||||||
Lights::Button7,
|
|
||||||
Lights::Button8,
|
|
||||||
Lights::Button9,
|
|
||||||
Lights::HiLamp1,
|
|
||||||
Lights::HiLamp2,
|
|
||||||
Lights::HiLamp3,
|
|
||||||
Lights::HiLamp4,
|
|
||||||
Lights::HiLamp5,
|
|
||||||
Lights::LeftLamp1,
|
|
||||||
Lights::LeftLamp2,
|
|
||||||
Lights::RightLamp1,
|
|
||||||
Lights::RightLamp2,
|
|
||||||
};
|
|
||||||
|
|
||||||
// sw lamps
|
|
||||||
for (size_t i = 0; i < 9; i++) {
|
|
||||||
float value = (lamp_bits & (1 << (i + 23))) ? 1.f : 0.f;
|
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i]), value);
|
|
||||||
}
|
|
||||||
// neon lamps
|
|
||||||
for (size_t i = 0; i < 5; i++) {
|
|
||||||
float value = (lamp_bits & (1 << i)) ? 1.f : 0.f;
|
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i + 9]), value);
|
|
||||||
}
|
|
||||||
// screen lamps
|
|
||||||
for (size_t i = 0; i < 4; i++) {
|
|
||||||
float value = (lamp_bits & (1 << (i + 8))) ? 1.f : 0.f;
|
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i + 14]), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// flush output
|
|
||||||
RI_MGR->devices_flush_output();
|
|
||||||
|
|
||||||
// return no error
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbPadRead(unsigned int *pad_bits) {
|
|
||||||
|
|
||||||
// get buttons
|
|
||||||
auto &buttons = get_buttons();
|
|
||||||
|
|
||||||
// reset
|
|
||||||
*pad_bits = 0;
|
|
||||||
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service))) {
|
|
||||||
*pad_bits |= 1 << 6;
|
|
||||||
}
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test))) {
|
|
||||||
*pad_bits |= 1 << 7;
|
|
||||||
}
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::CoinMech))) {
|
|
||||||
*pad_bits |= 1 << 22;
|
|
||||||
}
|
|
||||||
|
|
||||||
// buttons
|
|
||||||
static const size_t mapping[] = {
|
|
||||||
Buttons::Button1,
|
|
||||||
Buttons::Button2,
|
|
||||||
Buttons::Button3,
|
|
||||||
Buttons::Button4,
|
|
||||||
Buttons::Button5,
|
|
||||||
Buttons::Button6,
|
|
||||||
Buttons::Button7,
|
|
||||||
Buttons::Button8,
|
|
||||||
Buttons::Button9,
|
|
||||||
};
|
|
||||||
for (size_t i = 0; i < 9; i++) {
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(mapping[i]))) {
|
|
||||||
*pad_bits |= 1 << (8 + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return no error
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbPadReadLast(uint8_t *a1) {
|
|
||||||
memset(a1, 0, 40);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbSecurityInit() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbSecurityInitDone() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbSecuritySearch() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbSecuritySearchDone() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbSecuritySelect() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbSecuritySelectDone() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbSetExtIo(uint32_t rgb_bits) {
|
|
||||||
|
|
||||||
// get lights
|
|
||||||
auto &lights = get_lights();
|
|
||||||
|
|
||||||
// bit scan
|
|
||||||
static const size_t mapping[] = {
|
|
||||||
Lights::WooferLED_R,
|
|
||||||
Lights::WooferLED_G,
|
|
||||||
Lights::WooferLED_B,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 3; i++) {
|
|
||||||
float value = (rgb_bits & (1 << (i + 1)));
|
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i]), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// flush output
|
|
||||||
RI_MGR->devices_flush_output();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbStart() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbWdtReset() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbWdtStart() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __cdecl usbWdtStartDone() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static decltype(DeleteFileA)* DeleteFileA_real = nullptr;
|
|
||||||
|
|
||||||
static BOOL WINAPI DeleteFileA_hook(LPCSTR lpFileName) {
|
|
||||||
|
|
||||||
// fantasia deletes a bunch of drmfs files in dll_entry_init
|
|
||||||
if (string_begins_with(lpFileName, "D:\\L39\\contents")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DeleteFileA_real(lpFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
static decltype(mixerSetControlDetails)* mixerSetControlDetails_real = nullptr;
|
|
||||||
|
|
||||||
static MMRESULT WINAPI mixerSetControlDetails_hook(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
|
|
||||||
|
|
||||||
mixerSetControlDetails_real(hmxobj, pmxcd, fdwDetails);
|
|
||||||
return MMSYSERR_NOERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool log_hook(void *user, const std::string &data, logger::Style style, std::string &out) {
|
|
||||||
|
|
||||||
// get rid of the log spam
|
|
||||||
if (data.find(" I:CabinetSettingFile: label:") != std::string::npos) {
|
|
||||||
out.clear();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
POPNGame::POPNGame() : Game("Pop'n Music") {
|
|
||||||
logger::hook_add(log_hook, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
POPNGame::~POPNGame() {
|
|
||||||
logger::hook_remove(log_hook, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void POPNGame::pre_attach() {
|
|
||||||
Game::pre_attach();
|
|
||||||
|
|
||||||
// only needed for older versions (19-21, inclusive) but create them anyway since 21 and above are all M39
|
|
||||||
fileutils::dir_create_recursive_log("popn", "dev\\raw\\bookkeeping");
|
|
||||||
fileutils::dir_create_recursive_log("popn", "dev\\raw\\ranking");
|
|
||||||
fileutils::dir_create_recursive_log("popn", "dev\\raw\\settings");
|
|
||||||
|
|
||||||
// load without resolving references
|
|
||||||
// makes game not trigger DLLMain which results in an error due to missing EZUSB device
|
|
||||||
LoadLibraryExW((MODULE_PATH / "ezusb.dll").c_str(), nullptr, DONT_RESOLVE_DLL_REFERENCES);
|
|
||||||
}
|
|
||||||
|
|
||||||
void POPNGame::attach() {
|
|
||||||
Game::attach();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fast Boot (TM) Patch
|
|
||||||
* Game tries to create some directories and if it fails it will sleep for 1 second
|
|
||||||
* We make it sleep 1ms each time instead
|
|
||||||
*/
|
|
||||||
hooks::sleep::init(999, 1);
|
|
||||||
|
|
||||||
DeleteFileA_real = detour::iat_try("DeleteFileA", DeleteFileA_hook, avs::game::DLL_INSTANCE);
|
|
||||||
mixerSetControlDetails_real = detour::iat_try("mixerSetControlDetails", mixerSetControlDetails_hook, avs::game::DLL_INSTANCE);
|
|
||||||
|
|
||||||
// EZUSB hooks
|
|
||||||
HINSTANCE ezusb = libutils::try_library("ezusb.dll");
|
|
||||||
if (ezusb) {
|
|
||||||
detour::inline_hook((void *) usbCheckAlive,
|
|
||||||
libutils::try_proc(ezusb, "?usbCheckAlive@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbCheckSecurityNew,
|
|
||||||
libutils::try_proc(ezusb, "?usbCheckSecurityNew@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbCoinGet,
|
|
||||||
libutils::try_proc(ezusb, "?usbCoinGet@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbCoinMode,
|
|
||||||
libutils::try_proc(ezusb, "?usbCoinMode@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbEnd,
|
|
||||||
libutils::try_proc(ezusb, "?usbEnd@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbFirmResult,
|
|
||||||
libutils::try_proc(ezusb, "?usbFirmResult@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbGetKEYID,
|
|
||||||
libutils::try_proc(ezusb, "?usbGetKEYID@@YAHPAEH@Z"));
|
|
||||||
detour::inline_hook((void *) usbGetSecurity,
|
|
||||||
libutils::try_proc(ezusb, "?usbGetSecurity@@YAHHPAE@Z"));
|
|
||||||
detour::inline_hook((void *) usbLamp,
|
|
||||||
libutils::try_proc(ezusb, "?usbLamp@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbPadRead,
|
|
||||||
libutils::try_proc(ezusb, "?usbPadRead@@YAHPAK@Z"));
|
|
||||||
detour::inline_hook((void *) usbPadReadLast,
|
|
||||||
libutils::try_proc(ezusb, "?usbPadReadLast@@YAHPAE@Z"));
|
|
||||||
detour::inline_hook((void *) usbSecurityInit,
|
|
||||||
libutils::try_proc(ezusb, "?usbSecurityInit@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbSecurityInitDone,
|
|
||||||
libutils::try_proc(ezusb, "?usbSecurityInitDone@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbSecuritySearch,
|
|
||||||
libutils::try_proc(ezusb, "?usbSecuritySearch@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbSecuritySearchDone,
|
|
||||||
libutils::try_proc(ezusb, "?usbSecuritySearchDone@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbSecuritySelect,
|
|
||||||
libutils::try_proc(ezusb, "?usbSecuritySelect@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbSecuritySelectDone,
|
|
||||||
libutils::try_proc(ezusb, "?usbSecuritySelectDone@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbSetExtIo,
|
|
||||||
libutils::try_proc(ezusb, "?usbSetExtIo@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbStart,
|
|
||||||
libutils::try_proc(ezusb, "?usbStart@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbWdtReset,
|
|
||||||
libutils::try_proc(ezusb, "?usbWdtReset@@YAHXZ"));
|
|
||||||
detour::inline_hook((void *) usbWdtStart,
|
|
||||||
libutils::try_proc(ezusb, "?usbWdtStart@@YAHH@Z"));
|
|
||||||
detour::inline_hook((void *) usbWdtStartDone,
|
|
||||||
libutils::try_proc(ezusb, "?usbWdtStartDone@@YAHXZ"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "games/game.h"
|
|
||||||
|
|
||||||
namespace games::popn {
|
|
||||||
|
|
||||||
class POPNGame : public games::Game {
|
|
||||||
public:
|
|
||||||
POPNGame();
|
|
||||||
~POPNGame() override;
|
|
||||||
virtual void pre_attach() override;
|
|
||||||
virtual void attach() override;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#include "rb.h"
|
|
||||||
|
|
||||||
#include "avs/game.h"
|
|
||||||
#include "hooks/devicehook.h"
|
|
||||||
#include "hooks/audio/backends/dsound/dsound_backend.h"
|
|
||||||
#include "util/detour.h"
|
|
||||||
|
|
||||||
#include "touch.h"
|
|
||||||
|
|
||||||
static decltype(SleepEx) *SleepEx_orig;
|
|
||||||
|
|
||||||
static DWORD WINAPI SleepEx_hook(DWORD dwMilliseconds, BOOL bAltertable) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Increase touch poll from ~110 FPS to ~500 FPS
|
|
||||||
*/
|
|
||||||
if (dwMilliseconds == 8) {
|
|
||||||
static bool initialized = false;
|
|
||||||
if (!initialized) {
|
|
||||||
initialized = true;
|
|
||||||
|
|
||||||
// if we only sleep for 1ms we also don't need the high priority RB sets
|
|
||||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
|
|
||||||
}
|
|
||||||
dwMilliseconds = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// call original
|
|
||||||
return SleepEx_orig(dwMilliseconds, bAltertable);
|
|
||||||
}
|
|
||||||
|
|
||||||
games::rb::RBGame::RBGame() : Game("Reflec Beat") {
|
|
||||||
}
|
|
||||||
|
|
||||||
void games::rb::RBGame::attach() {
|
|
||||||
Game::attach();
|
|
||||||
|
|
||||||
// init stuff
|
|
||||||
devicehook_init();
|
|
||||||
|
|
||||||
// add touch device
|
|
||||||
devicehook_add(new ReflecBeatTouchDeviceHandle(false));
|
|
||||||
|
|
||||||
if (avs::game::is_model({"KBR", "LBR"})) {
|
|
||||||
// dsound.dll hook
|
|
||||||
audio_dsound_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// hooks
|
|
||||||
SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, avs::game::DLL_INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void games::rb::RBGame::detach() {
|
|
||||||
Game::detach();
|
|
||||||
devicehook_dispose();
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
#include "io.h"
|
|
||||||
|
|
||||||
std::vector<Button> &games::sdvx::get_buttons() {
|
|
||||||
static std::vector<Button> buttons;
|
|
||||||
|
|
||||||
if (buttons.empty()) {
|
|
||||||
buttons = GameAPI::Buttons::getButtons("Sound Voltex");
|
|
||||||
|
|
||||||
GameAPI::Buttons::sortButtons(
|
|
||||||
&buttons,
|
|
||||||
"Service",
|
|
||||||
"Test",
|
|
||||||
"Coin Mech",
|
|
||||||
"BT-A",
|
|
||||||
"BT-B",
|
|
||||||
"BT-C",
|
|
||||||
"BT-D",
|
|
||||||
"FX-L",
|
|
||||||
"FX-R",
|
|
||||||
"Start",
|
|
||||||
"VOL-L Left",
|
|
||||||
"VOL-L Right",
|
|
||||||
"VOL-R Left",
|
|
||||||
"VOL-R Right",
|
|
||||||
"Headphone"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string games::sdvx::get_buttons_help() {
|
|
||||||
// keep to max 100 characters wide
|
|
||||||
return
|
|
||||||
" Start\n"
|
|
||||||
"\n"
|
|
||||||
" VOL-L VOL_R\n"
|
|
||||||
"\n"
|
|
||||||
" BT-A BT-B BT-C BT-D\n"
|
|
||||||
" FX-L FX-R \n"
|
|
||||||
"\n"
|
|
||||||
"For controllers, use Analog tab for knobs."
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Analog> &games::sdvx::get_analogs() {
|
|
||||||
static std::vector<Analog> analogs;
|
|
||||||
|
|
||||||
if (analogs.empty()) {
|
|
||||||
analogs = GameAPI::Analogs::getAnalogs("Sound Voltex");
|
|
||||||
|
|
||||||
GameAPI::Analogs::sortAnalogs(
|
|
||||||
&analogs,
|
|
||||||
"VOL-L",
|
|
||||||
"VOL-R"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return analogs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Light> &games::sdvx::get_lights() {
|
|
||||||
static std::vector<Light> lights;
|
|
||||||
|
|
||||||
if (lights.empty()) {
|
|
||||||
lights = GameAPI::Lights::getLights("Sound Voltex");
|
|
||||||
|
|
||||||
GameAPI::Lights::sortLights(
|
|
||||||
&lights,
|
|
||||||
"BT-A",
|
|
||||||
"BT-B",
|
|
||||||
"BT-C",
|
|
||||||
"BT-D",
|
|
||||||
"FX-L",
|
|
||||||
"FX-R",
|
|
||||||
"Start",
|
|
||||||
"Wing Left Up R",
|
|
||||||
"Wing Left Up G",
|
|
||||||
"Wing Left Up B",
|
|
||||||
"Wing Right Up R",
|
|
||||||
"Wing Right Up G",
|
|
||||||
"Wing Right Up B",
|
|
||||||
"Wing Left Low R",
|
|
||||||
"Wing Left Low G",
|
|
||||||
"Wing Left Low B",
|
|
||||||
"Wing Right Low R",
|
|
||||||
"Wing Right Low G",
|
|
||||||
"Wing Right Low B",
|
|
||||||
"Woofer R",
|
|
||||||
"Woofer G",
|
|
||||||
"Woofer B",
|
|
||||||
"Controller R",
|
|
||||||
"Controller G",
|
|
||||||
"Controller B",
|
|
||||||
"Generator R",
|
|
||||||
"Generator G",
|
|
||||||
"Generator B",
|
|
||||||
"Pop",
|
|
||||||
"Title Left",
|
|
||||||
"Title Right",
|
|
||||||
"Volume Sound",
|
|
||||||
"Volume Headphone",
|
|
||||||
"Volume External",
|
|
||||||
"Volume Woofer",
|
|
||||||
"IC Card Reader R",
|
|
||||||
"IC Card Reader G",
|
|
||||||
"IC Card Reader B",
|
|
||||||
"Title Avg R",
|
|
||||||
"Title Avg G",
|
|
||||||
"Title Avg B",
|
|
||||||
"Upper Left Speaker Avg R",
|
|
||||||
"Upper Left Speaker Avg G",
|
|
||||||
"Upper Left Speaker Avg B",
|
|
||||||
"Upper Right Speaker Avg R",
|
|
||||||
"Upper Right Speaker Avg G",
|
|
||||||
"Upper Right Speaker Avg B",
|
|
||||||
"Left Wing Avg R",
|
|
||||||
"Left Wing Avg G",
|
|
||||||
"Left Wing Avg B",
|
|
||||||
"Right Wing Avg R",
|
|
||||||
"Right Wing Avg G",
|
|
||||||
"Right Wing Avg B",
|
|
||||||
"Lower Left Speaker Avg R",
|
|
||||||
"Lower Left Speaker Avg G",
|
|
||||||
"Lower Left Speaker Avg B",
|
|
||||||
"Lower Right Speaker Avg R",
|
|
||||||
"Lower Right Speaker Avg G",
|
|
||||||
"Lower Right Speaker Avg B",
|
|
||||||
"Control Panel Avg R",
|
|
||||||
"Control Panel Avg G",
|
|
||||||
"Control Panel Avg B",
|
|
||||||
"Woofer Avg R",
|
|
||||||
"Woofer Avg G",
|
|
||||||
"Woofer Avg B",
|
|
||||||
"V Unit Avg R",
|
|
||||||
"V Unit Avg G",
|
|
||||||
"V Unit Avg B"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lights;
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
#include "audio.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <initguid.h>
|
|
||||||
#include <audioclient.h>
|
|
||||||
#include <mmdeviceapi.h>
|
|
||||||
|
|
||||||
#include "hooks/audio/backends/mmdevice/device_enumerator.h"
|
|
||||||
#include "util/detour.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/memutils.h"
|
|
||||||
|
|
||||||
#include "audio_private.h"
|
|
||||||
#include "acm.h"
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
DEFINE_GUID(CLSID_MMDeviceEnumerator,
|
|
||||||
0xBCDE0395, 0xE52F, 0x467C,
|
|
||||||
0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// {ef985e71-d5c7-42d4-ba4d-2d073e2e96f4}
|
|
||||||
DEFINE_GUID(CLSID_DirectSoundI3DL2ReverbDMO,
|
|
||||||
0xef985e71, 0xd5c7, 0x42d4,
|
|
||||||
0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4);
|
|
||||||
|
|
||||||
// {87fc0268-9a55-4360-95aa-004a1d9de26c}
|
|
||||||
DEFINE_GUID(CLSID_DirectSoundWavesReverbDMO,
|
|
||||||
0x87fc0268, 0x9a55, 0x4360,
|
|
||||||
0x95, 0xaa, 0x00, 0x4a, 0x1d, 0x9d, 0xe2, 0x6c);
|
|
||||||
|
|
||||||
// function pointers
|
|
||||||
static decltype(CoCreateInstance) *CoCreateInstance_orig = nullptr;
|
|
||||||
|
|
||||||
namespace hooks::audio {
|
|
||||||
|
|
||||||
// public globals
|
|
||||||
bool ENABLED = true;
|
|
||||||
bool VOLUME_HOOK_ENABLED = true;
|
|
||||||
bool USE_DUMMY = false;
|
|
||||||
WAVEFORMATEXTENSIBLE FORMAT {};
|
|
||||||
std::optional<Backend> BACKEND = std::nullopt;
|
|
||||||
size_t ASIO_DRIVER_ID = 0;
|
|
||||||
bool ASIO_FORCE_UNLOAD_ON_STOP = false;
|
|
||||||
|
|
||||||
// private globals
|
|
||||||
IAudioClient *CLIENT = nullptr;
|
|
||||||
std::mutex INITIALIZE_LOCK; // for asio
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT STDAPICALLTYPE CoCreateInstance_hook(
|
|
||||||
REFCLSID rclsid,
|
|
||||||
LPUNKNOWN pUnkOuter,
|
|
||||||
DWORD dwClsContext,
|
|
||||||
REFIID riid,
|
|
||||||
LPVOID *ppv)
|
|
||||||
{
|
|
||||||
|
|
||||||
HRESULT ret;
|
|
||||||
|
|
||||||
// call original
|
|
||||||
ret = CoCreateInstance_orig(rclsid, pUnkOuter, dwClsContext, riid, ppv);
|
|
||||||
if (FAILED(ret)) {
|
|
||||||
if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) {
|
|
||||||
log_warning("audio", "CoCreateInstance failed for CLSID_MMDeviceEnumerator, hr={}", FMT_HRESULT(ret));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Windows 11 KB5052093 issue - reverb DMO went missing from dsdmo.dll (fails with 0x80040154)
|
|
||||||
if (IsEqualCLSID(rclsid, CLSID_DirectSoundI3DL2ReverbDMO) && ret == (HRESULT)0x80040154) {
|
|
||||||
log_warning(
|
|
||||||
"audio",
|
|
||||||
"CoCreateInstance for CLSID_DirectSoundI3DL2ReverbDMO failed with 0x80040154, swap with CLSID_DirectSoundWavesReverbDMO "
|
|
||||||
"(workaround for Windows 11 KB5052093 issue); REVERB EX replaced with REVERB");
|
|
||||||
ret = CoCreateInstance_orig(CLSID_DirectSoundWavesReverbDMO, pUnkOuter, dwClsContext, riid, ppv);
|
|
||||||
if (FAILED(ret)) {
|
|
||||||
log_warning("audio", "CoCreateInstance(CLSID_DirectSoundWavesReverbDMO...) failed, hr={}", FMT_HRESULT(ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if this is the audio device enumerator
|
|
||||||
if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) {
|
|
||||||
|
|
||||||
// wrap object
|
|
||||||
auto mmde = reinterpret_cast<IMMDeviceEnumerator **>(ppv);
|
|
||||||
*mmde = new WrappedIMMDeviceEnumerator(*mmde);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return original result
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace hooks::audio {
|
|
||||||
void init() {
|
|
||||||
if (!ENABLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_info("audio", "initializing");
|
|
||||||
init_low_latency();
|
|
||||||
hooks::audio::acm::init();
|
|
||||||
|
|
||||||
// general hooks
|
|
||||||
CoCreateInstance_orig = detour::iat_try("CoCreateInstance", CoCreateInstance_hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop() {
|
|
||||||
log_info("audio", "stopping");
|
|
||||||
if (CLIENT) {
|
|
||||||
CLIENT->Stop();
|
|
||||||
CLIENT->Release();
|
|
||||||
CLIENT = nullptr;
|
|
||||||
}
|
|
||||||
stop_low_latency();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <mmreg.h>
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#include <ks.h>
|
|
||||||
#include <ksmedia.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace hooks::audio {
|
|
||||||
enum class Backend {
|
|
||||||
Asio,
|
|
||||||
WaveOut,
|
|
||||||
Pipewire,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
extern bool ENABLED;
|
|
||||||
extern bool VOLUME_HOOK_ENABLED;
|
|
||||||
extern bool USE_DUMMY;
|
|
||||||
extern WAVEFORMATEXTENSIBLE FORMAT;
|
|
||||||
extern std::optional<Backend> BACKEND;
|
|
||||||
extern size_t ASIO_DRIVER_ID;
|
|
||||||
extern bool ASIO_FORCE_UNLOAD_ON_STOP;
|
|
||||||
extern bool LOW_LATENCY_SHARED_WASAPI;
|
|
||||||
|
|
||||||
void init();
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
inline std::optional<Backend> name_to_backend(const char *value) {
|
|
||||||
if (_stricmp(value, "asio") == 0) {
|
|
||||||
return Backend::Asio;
|
|
||||||
} else if (_stricmp(value, "waveout") == 0) {
|
|
||||||
return Backend::WaveOut;
|
|
||||||
} else if (_stricmp(value, "pipewire") == 0) {
|
|
||||||
return Backend::Pipewire;
|
|
||||||
} else if (_stricmp(value, "none") == 0) {
|
|
||||||
return Backend::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
#include "audio_render_client.h"
|
|
||||||
|
|
||||||
#include "audio_client.h"
|
|
||||||
#include "wasapi_private.h"
|
|
||||||
|
|
||||||
const char CLASS_NAME[] = "WrappedIAudioRenderClient";
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::QueryInterface(REFIID riid, void **ppvObj) {
|
|
||||||
if (ppvObj == nullptr) {
|
|
||||||
return E_POINTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (riid == IID_WrappedIAudioRenderClient ||
|
|
||||||
riid == IID_IAudioRenderClient)
|
|
||||||
{
|
|
||||||
this->AddRef();
|
|
||||||
*ppvObj = this;
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pReal->QueryInterface(riid, ppvObj);
|
|
||||||
}
|
|
||||||
ULONG STDMETHODCALLTYPE WrappedIAudioRenderClient::AddRef() {
|
|
||||||
return pReal->AddRef();
|
|
||||||
}
|
|
||||||
ULONG STDMETHODCALLTYPE WrappedIAudioRenderClient::Release() {
|
|
||||||
|
|
||||||
// get reference count of underlying interface
|
|
||||||
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
|
|
||||||
|
|
||||||
if (refs == 0) {
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return refs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IAudioRenderClient
|
|
||||||
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) {
|
|
||||||
static std::once_flag printed;
|
|
||||||
std::call_once(printed, []() {
|
|
||||||
log_misc("audio::wasapi", "WrappedIAudioRenderClient::GetBuffer");
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this->client->backend) {
|
|
||||||
SAFE_CALL("AudioBackend", "on_get_buffer", this->client->backend->on_get_buffer(
|
|
||||||
NumFramesRequested,
|
|
||||||
ppData));
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// call original
|
|
||||||
HRESULT ret = pReal->GetBuffer(NumFramesRequested, ppData);
|
|
||||||
|
|
||||||
// store buffer reference
|
|
||||||
if (SUCCEEDED(ret)) {
|
|
||||||
this->audio_buffer = *ppData;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_RESULT(ret);
|
|
||||||
}
|
|
||||||
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) {
|
|
||||||
static std::once_flag printed;
|
|
||||||
std::call_once(printed, []() {
|
|
||||||
log_misc("audio::wasapi", "WrappedIAudioRenderClient::ReleaseBuffer");
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this->client->backend) {
|
|
||||||
SAFE_CALL("AudioBackend", "on_release_buffer", this->client->backend->on_release_buffer(
|
|
||||||
NumFramesWritten,
|
|
||||||
dwFlags));
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix for audio pop effect
|
|
||||||
if (this->buffers_to_mute > 0 && this->client->frame_size > 0) {
|
|
||||||
|
|
||||||
// zero out = mute
|
|
||||||
memset(this->audio_buffer, 0, NumFramesWritten * this->client->frame_size);
|
|
||||||
|
|
||||||
this->buffers_to_mute--;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK_RESULT(pReal->ReleaseBuffer(NumFramesWritten, dwFlags));
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#include "util.h"
|
|
||||||
|
|
||||||
#include <audioclient.h>
|
|
||||||
|
|
||||||
#include "util/flags_helper.h"
|
|
||||||
|
|
||||||
#include "defs.h"
|
|
||||||
|
|
||||||
std::string stream_flags_str(DWORD flags) {
|
|
||||||
FLAGS_START(flags);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_CROSSPROCESS);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_LOOPBACK);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_EVENTCALLBACK);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_NOPERSIST);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_RATEADJUST);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_PREVENT_LOOPBACK_CAPTURE);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM);
|
|
||||||
FLAG(flags, AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
|
|
||||||
FLAGS_END(flags);
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <mmreg.h>
|
|
||||||
|
|
||||||
std::string stream_flags_str(DWORD flags);
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,109 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <optional>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <d3d9.h>
|
|
||||||
|
|
||||||
#include "external/toojpeg/toojpeg.h"
|
|
||||||
|
|
||||||
// order must match spice2x_AutoOrientation UI enum order
|
|
||||||
enum graphics_orientation {
|
|
||||||
ORIENTATION_CW = 0,
|
|
||||||
ORIENTATION_CCW = 1,
|
|
||||||
ORIENTATION_NORMAL = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum graphics_dx9on12_state {
|
|
||||||
DX9ON12_AUTO,
|
|
||||||
DX9ON12_FORCE_OFF,
|
|
||||||
DX9ON12_FORCE_ON,
|
|
||||||
};
|
|
||||||
|
|
||||||
// flag settings
|
|
||||||
extern bool GRAPHICS_CAPTURE_CURSOR;
|
|
||||||
extern bool GRAPHICS_LOG_HRESULT;
|
|
||||||
extern bool GRAPHICS_SDVX_FORCE_720;
|
|
||||||
extern bool GRAPHICS_SHOW_CURSOR;
|
|
||||||
extern bool GRAPHICS_WINDOWED;
|
|
||||||
extern graphics_orientation GRAPHICS_ADJUST_ORIENTATION;
|
|
||||||
extern std::vector<HWND> GRAPHICS_WINDOWS;
|
|
||||||
extern UINT GRAPHICS_FORCE_REFRESH;
|
|
||||||
extern std::optional<uint32_t> GRAPHICS_FORCE_REFRESH_SUB;
|
|
||||||
extern std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
|
||||||
extern bool GRAPHICS_FORCE_SINGLE_ADAPTER;
|
|
||||||
extern bool GRAPHICS_PREVENT_SECONDARY_WINDOW;
|
|
||||||
extern std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_FS_CUSTOM_RESOLUTION;
|
|
||||||
extern std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_FS_CUSTOM_RESOLUTION_SUB;
|
|
||||||
extern bool GRAPHICS_FS_ORIENTATION_SWAP;
|
|
||||||
extern uint32_t GRAPHICS_FS_ORIGINAL_WIDTH;
|
|
||||||
extern uint32_t GRAPHICS_FS_ORIGINAL_HEIGHT;
|
|
||||||
|
|
||||||
extern graphics_dx9on12_state GRAPHICS_9_ON_12_STATE;
|
|
||||||
extern bool GRAPHICS_9_ON_12_REQUESTED_BY_GAME;
|
|
||||||
|
|
||||||
extern std::optional<int> GRAPHICS_WINDOW_STYLE;
|
|
||||||
extern std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_WINDOW_SIZE;
|
|
||||||
extern std::optional<std::string> GRAPHICS_WINDOW_POS;
|
|
||||||
extern bool GRAPHICS_WINDOW_ALWAYS_ON_TOP;
|
|
||||||
extern bool GRAPHICS_WINDOW_BACKBUFFER_SCALE;
|
|
||||||
extern std::optional<HWND> GRAPHICS_HOOKED_WINDOW;
|
|
||||||
|
|
||||||
extern bool GRAPHICS_IIDX_WSUB;
|
|
||||||
extern std::optional<std::string> GRAPHICS_WSUB_SIZE;
|
|
||||||
extern std::optional<std::string> GRAPHICS_WSUB_POS;
|
|
||||||
extern int GRAPHICS_WSUB_WIDTH;
|
|
||||||
extern int GRAPHICS_WSUB_HEIGHT;
|
|
||||||
extern int GRAPHICS_WSUB_X;
|
|
||||||
extern int GRAPHICS_WSUB_Y;
|
|
||||||
extern bool GRAPHICS_WSUB_BORDERLESS;
|
|
||||||
extern bool GRAPHICS_WSUB_ALWAYS_ON_TOP;
|
|
||||||
extern HWND TDJ_SUBSCREEN_WINDOW;
|
|
||||||
extern HWND SDVX_SUBSCREEN_WINDOW;
|
|
||||||
extern HWND GFDM_SUBSCREEN_WINDOW;
|
|
||||||
|
|
||||||
extern bool SUBSCREEN_FORCE_REDRAW;
|
|
||||||
|
|
||||||
// settings
|
|
||||||
extern std::string GRAPHICS_DEVICEID;
|
|
||||||
extern std::string GRAPHICS_SCREENSHOT_DIR;
|
|
||||||
|
|
||||||
// Direct3D 9 settings
|
|
||||||
extern std::optional<UINT> D3D9_ADAPTER;
|
|
||||||
extern DWORD D3D9_BEHAVIOR_DISABLE;
|
|
||||||
extern bool D3D9_DEVICE_HOOK_DISABLE;
|
|
||||||
|
|
||||||
void graphics_init();
|
|
||||||
void graphics_hook_window(HWND hWnd, D3DPRESENT_PARAMETERS *pPresentationParameters);
|
|
||||||
void graphics_add_wnd_proc(WNDPROC wndProc);
|
|
||||||
void graphics_remove_wnd_proc(WNDPROC wndProc);
|
|
||||||
void graphics_hook_subscreen_window(HWND hWnd);
|
|
||||||
void graphics_screens_register(int screen);
|
|
||||||
void graphics_screens_unregister(int screen);
|
|
||||||
void graphics_screens_get(std::vector<int> &screens);
|
|
||||||
void graphics_screenshot_trigger();
|
|
||||||
bool graphics_screenshot_consume();
|
|
||||||
void graphics_capture_trigger(int screen);
|
|
||||||
bool graphics_capture_consume(int *screen);
|
|
||||||
void graphics_capture_enqueue(int screen, uint8_t *data, size_t width, size_t height);
|
|
||||||
void graphics_capture_skip(int screen);
|
|
||||||
bool graphics_capture_receive_jpeg(int screen, TooJpeg::WRITE_ONE_BYTE receiver,
|
|
||||||
bool rgb = true, int quality = 80, bool downsample = true, int divide = 0,
|
|
||||||
uint64_t *timestamp = nullptr,
|
|
||||||
int *width = nullptr, int *height = nullptr);
|
|
||||||
std::string graphics_screenshot_genpath();
|
|
||||||
|
|
||||||
// graphics_windowed.cpp
|
|
||||||
void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
||||||
void graphics_capture_initial_window(HWND hWnd);
|
|
||||||
void graphics_update_window_style(HWND hWnd);
|
|
||||||
void graphics_update_z_order(HWND hWnd, bool always_on_top);
|
|
||||||
void graphics_move_resize_window(HWND hWnd);
|
|
||||||
bool graphics_window_options_breaks_game();
|
|
||||||
bool graphics_window_decoration_change_crashes_game();
|
|
||||||
bool graphics_window_resize_breaks_game();
|
|
||||||
bool graphics_window_move_and_resize_breaks_game();
|
|
||||||
void graphics_load_windowed_subscreen_parameters();
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
#include "external/nvapi/nvapi.h"
|
|
||||||
#include "external/nvapi/NvApiDriverSettings.h"
|
|
||||||
#include "hooks/libraryhook.h"
|
|
||||||
#include "util/detour.h"
|
|
||||||
#include "util/libutils.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
|
|
||||||
#include "nvapi_hook.h"
|
|
||||||
|
|
||||||
namespace nvapi_hook {
|
|
||||||
|
|
||||||
bool BYPASS_NVAPI = false;
|
|
||||||
|
|
||||||
typedef uintptr_t *(*NvAPI_QueryInterface_t)(unsigned int);
|
|
||||||
static NvAPI_QueryInterface_t NvAPI_QueryInterface_orig = nullptr;
|
|
||||||
|
|
||||||
static uintptr_t* __cdecl NvAPI_QueryInterface_hook(unsigned int func_code);
|
|
||||||
static NvAPI_Status __cdecl NvAPI_DISP_SetDisplayConfig_hook(
|
|
||||||
NvU32 pathInfoCount, NV_DISPLAYCONFIG_PATH_INFO *pathInfo, NvU32 flags);
|
|
||||||
|
|
||||||
void initialize(HINSTANCE dll) {
|
|
||||||
|
|
||||||
#ifdef SPICE64
|
|
||||||
std::string nvapi_dll = "nvapi64.dll";
|
|
||||||
#else
|
|
||||||
std::string nvapi_dll = "nvapi.dll";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
detour::trampoline_try(
|
|
||||||
nvapi_dll.c_str(), "nvapi_QueryInterface",
|
|
||||||
NvAPI_QueryInterface_hook, &NvAPI_QueryInterface_orig);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t* __cdecl NvAPI_QueryInterface_hook(unsigned int func_code) {
|
|
||||||
if (BYPASS_NVAPI) {
|
|
||||||
log_misc(
|
|
||||||
"nvapi_hook",
|
|
||||||
"NvAPI_QueryInterface(0x{:x}) - block all calls to nvapi (-nonvapi)",
|
|
||||||
func_code);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NvAPI_DISP_SetDisplayConfig
|
|
||||||
if (func_code == 0x5D8CF8DE) {
|
|
||||||
log_misc("nvapi_hook", "NvAPI_QueryInterface(NvAPI_DISP_SetDisplayConfig) - hooked");
|
|
||||||
return (uintptr_t *)NvAPI_DISP_SetDisplayConfig_hook;
|
|
||||||
}
|
|
||||||
|
|
||||||
// all others: let the game call nvapi directly
|
|
||||||
log_misc("nvapi_hook", "NvAPI_QueryInterface(0x{:x}) - pass through to nvapi", func_code);
|
|
||||||
return NvAPI_QueryInterface_orig(func_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
NvAPI_Status __cdecl NvAPI_DISP_SetDisplayConfig_hook(
|
|
||||||
NvU32 pathInfoCount, NV_DISPLAYCONFIG_PATH_INFO *pathInfo, NvU32 flags) {
|
|
||||||
log_misc("nvapi_hook", "NvAPI_DISP_SetDisplayConfig_hook - do nothing and return");
|
|
||||||
return NVAPI_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
#include "signal.h"
|
|
||||||
|
|
||||||
#include <future>
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <dbghelp.h>
|
|
||||||
|
|
||||||
#include "acio/acio.h"
|
|
||||||
#include "external/stackwalker/stackwalker.h"
|
|
||||||
#include "hooks/libraryhook.h"
|
|
||||||
#include "launcher/shutdown.h"
|
|
||||||
#include "util/deferlog.h"
|
|
||||||
#include "util/detour.h"
|
|
||||||
#include "util/libutils.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "cfg/configurator.h"
|
|
||||||
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
// MSVC compatibility
|
|
||||||
#ifdef exception_code
|
|
||||||
#undef exception_code
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static decltype(MiniDumpWriteDump) *MiniDumpWriteDump_local = nullptr;
|
|
||||||
|
|
||||||
namespace launcher::signal {
|
|
||||||
|
|
||||||
// settings
|
|
||||||
bool DISABLE = false;
|
|
||||||
bool USE_VEH_WORKAROUND = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define V(variant) case variant: return #variant
|
|
||||||
|
|
||||||
static std::string control_code(DWORD dwCtrlType) {
|
|
||||||
switch (dwCtrlType) {
|
|
||||||
V(CTRL_C_EVENT);
|
|
||||||
V(CTRL_BREAK_EVENT);
|
|
||||||
V(CTRL_CLOSE_EVENT);
|
|
||||||
V(CTRL_LOGOFF_EVENT);
|
|
||||||
V(CTRL_SHUTDOWN_EVENT);
|
|
||||||
default:
|
|
||||||
return "Unknown(0x" + to_hex(dwCtrlType) + ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string exception_code(struct _EXCEPTION_RECORD *ExceptionRecord) {
|
|
||||||
switch (ExceptionRecord->ExceptionCode) {
|
|
||||||
V(EXCEPTION_ACCESS_VIOLATION);
|
|
||||||
V(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
|
|
||||||
V(EXCEPTION_BREAKPOINT);
|
|
||||||
V(EXCEPTION_DATATYPE_MISALIGNMENT);
|
|
||||||
V(EXCEPTION_FLT_DENORMAL_OPERAND);
|
|
||||||
V(EXCEPTION_FLT_DIVIDE_BY_ZERO);
|
|
||||||
V(EXCEPTION_FLT_INEXACT_RESULT);
|
|
||||||
V(EXCEPTION_FLT_INVALID_OPERATION);
|
|
||||||
V(EXCEPTION_FLT_OVERFLOW);
|
|
||||||
V(EXCEPTION_FLT_STACK_CHECK);
|
|
||||||
V(EXCEPTION_FLT_UNDERFLOW);
|
|
||||||
V(EXCEPTION_ILLEGAL_INSTRUCTION);
|
|
||||||
V(EXCEPTION_IN_PAGE_ERROR);
|
|
||||||
V(EXCEPTION_INT_DIVIDE_BY_ZERO);
|
|
||||||
V(EXCEPTION_INT_OVERFLOW);
|
|
||||||
V(EXCEPTION_INVALID_DISPOSITION);
|
|
||||||
V(EXCEPTION_NONCONTINUABLE_EXCEPTION);
|
|
||||||
V(EXCEPTION_PRIV_INSTRUCTION);
|
|
||||||
V(EXCEPTION_SINGLE_STEP);
|
|
||||||
V(EXCEPTION_STACK_OVERFLOW);
|
|
||||||
V(DBG_CONTROL_C);
|
|
||||||
default:
|
|
||||||
return "Unknown(0x" + to_hex(ExceptionRecord->ExceptionCode) + ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef V
|
|
||||||
|
|
||||||
static BOOL WINAPI HandlerRoutine(DWORD dwCtrlType) {
|
|
||||||
log_info("signal", "console ctrl handler called: {}", control_code(dwCtrlType));
|
|
||||||
|
|
||||||
if (dwCtrlType == CTRL_C_EVENT) {
|
|
||||||
launcher::shutdown();
|
|
||||||
} else if (dwCtrlType == CTRL_CLOSE_EVENT) {
|
|
||||||
launcher::shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) {
|
|
||||||
|
|
||||||
// ignore signal if disabled or no exception info provided
|
|
||||||
if (!launcher::signal::DISABLE && ExceptionInfo != nullptr) {
|
|
||||||
|
|
||||||
// get exception record
|
|
||||||
struct _EXCEPTION_RECORD *ExceptionRecord = ExceptionInfo->ExceptionRecord;
|
|
||||||
|
|
||||||
// print signal
|
|
||||||
log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord));
|
|
||||||
|
|
||||||
switch (ExceptionRecord->ExceptionCode) {
|
|
||||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
|
||||||
deferredlogs::defer_error_messages({
|
|
||||||
"illegal instruction exception:",
|
|
||||||
" either your CPU is too old (e.g., does not support SSE4.2 or AVX2 ",
|
|
||||||
" but perhaps the game requires it); or, a bad patch was applied."
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check ACIO init failures
|
|
||||||
if (acio::IO_INIT_IN_PROGRESS) {
|
|
||||||
deferredlogs::defer_error_messages({
|
|
||||||
"exception raised during ACIO init, this usually happens when ",
|
|
||||||
" a third party application interferes with hooks",
|
|
||||||
" please check for the following, disable them, and try launching the game again:",
|
|
||||||
" * RivaTuner Statistics Server (RTSS)",
|
|
||||||
" * MSI Afterburner",
|
|
||||||
" * kernel mode anti-cheat"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// dump deferred logs BEFORE stack trace since some errors cause stack trace logic to hang
|
|
||||||
// (e.g., ACIO init hang due to RTSS)
|
|
||||||
deferredlogs::dump_to_logger(true);
|
|
||||||
|
|
||||||
// walk the exception chain
|
|
||||||
struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord;
|
|
||||||
while (record_cause != nullptr) {
|
|
||||||
log_warning("signal", "caused by: {}", exception_code(record_cause));
|
|
||||||
record_cause = record_cause->ExceptionRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print stacktrace
|
|
||||||
StackWalker sw;
|
|
||||||
log_info("signal", "printing callstack");
|
|
||||||
if (!sw.ShowCallstack(GetCurrentThread(), ExceptionInfo->ContextRecord)) {
|
|
||||||
log_warning("signal", "failed to print callstack");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MiniDumpWriteDump_local != nullptr) {
|
|
||||||
HANDLE minidump_file = CreateFileA(
|
|
||||||
"minidump.dmp",
|
|
||||||
GENERIC_WRITE,
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
CREATE_ALWAYS,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
if (minidump_file != INVALID_HANDLE_VALUE) {
|
|
||||||
MINIDUMP_EXCEPTION_INFORMATION ExceptionParam {};
|
|
||||||
ExceptionParam.ThreadId = GetCurrentThreadId();
|
|
||||||
ExceptionParam.ExceptionPointers = ExceptionInfo;
|
|
||||||
ExceptionParam.ClientPointers = FALSE;
|
|
||||||
|
|
||||||
MiniDumpWriteDump_local(
|
|
||||||
GetCurrentProcess(),
|
|
||||||
GetCurrentProcessId(),
|
|
||||||
minidump_file,
|
|
||||||
MiniDumpNormal,
|
|
||||||
&ExceptionParam,
|
|
||||||
nullptr,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
CloseHandle(minidump_file);
|
|
||||||
} else {
|
|
||||||
log_warning("signal", "failed to create 'minidump.dmp' for minidump: 0x{:08x}",
|
|
||||||
GetLastError());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log_warning("signal", "minidump creation function not available, skipping");
|
|
||||||
}
|
|
||||||
|
|
||||||
// this will stall all UI threads for this process
|
|
||||||
show_popup_for_crash();
|
|
||||||
|
|
||||||
log_fatal("signal", "end");
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL WINAPI SetConsoleCtrlHandler_hook(PHANDLER_ROUTINE pHandlerRoutine, BOOL Add) {
|
|
||||||
static std::once_flag printed;
|
|
||||||
std::call_once(printed, []() {
|
|
||||||
log_misc("signal", "SetConsoleCtrlHandler hook hit (printing once)");
|
|
||||||
});
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter_hook(
|
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) {
|
|
||||||
|
|
||||||
static std::once_flag printed;
|
|
||||||
std::call_once(printed, []() {
|
|
||||||
log_info("signal", "SetUnhandledExceptionFilter hook hit (printing once)");
|
|
||||||
});
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PVOID WINAPI AddVectoredExceptionHandler_hook(ULONG First, PVECTORED_EXCEPTION_HANDLER Handler) {
|
|
||||||
static std::once_flag printed;
|
|
||||||
std::call_once(printed, []() {
|
|
||||||
log_info("signal", "AddVectoredExceptionHandler hook hit (printing once)");
|
|
||||||
});
|
|
||||||
|
|
||||||
return launcher::signal::USE_VEH_WORKAROUND ? INVALID_HANDLE_VALUE : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void launcher::signal::attach() {
|
|
||||||
|
|
||||||
if (launcher::signal::DISABLE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_info("signal", "attaching...");
|
|
||||||
|
|
||||||
// set a `std::terminate` handler so `std::abort()` is not called by default
|
|
||||||
std::set_terminate([]() {
|
|
||||||
log_warning("signal", "std::terminate called");
|
|
||||||
|
|
||||||
launcher::kill();
|
|
||||||
});
|
|
||||||
|
|
||||||
// NOTE: inline hooks are not used here as they have caused EXCEPTION_ACCESS_VIOLATION in the past
|
|
||||||
// when hooking these methods
|
|
||||||
|
|
||||||
// hook relevant functions
|
|
||||||
libraryhook_hook_proc("SetConsoleCtrlHandler", SetConsoleCtrlHandler_hook);
|
|
||||||
libraryhook_hook_proc("SetUnhandledExceptionFilter", SetUnhandledExceptionFilter_hook);
|
|
||||||
libraryhook_hook_proc("AddVectoredExceptionHandler", AddVectoredExceptionHandler_hook);
|
|
||||||
libraryhook_enable();
|
|
||||||
|
|
||||||
// hook in all loaded modules
|
|
||||||
detour::iat_try("SetConsoleCtrlHandler", SetConsoleCtrlHandler_hook);
|
|
||||||
detour::iat_try("SetUnhandledExceptionFilter", SetUnhandledExceptionFilter_hook);
|
|
||||||
detour::iat_try("AddVectoredExceptionHandler", AddVectoredExceptionHandler_hook);
|
|
||||||
|
|
||||||
log_info("signal", "attached");
|
|
||||||
}
|
|
||||||
|
|
||||||
void launcher::signal::init() {
|
|
||||||
|
|
||||||
// load debug help library
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
auto dbghelp = libutils::try_library("dbghelp.dll");
|
|
||||||
|
|
||||||
if (dbghelp != nullptr) {
|
|
||||||
MiniDumpWriteDump_local = libutils::try_proc<decltype(MiniDumpWriteDump) *>(
|
|
||||||
dbghelp, "MiniDumpWriteDump");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// register our console ctrl handler
|
|
||||||
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
|
|
||||||
|
|
||||||
// register our exception handler
|
|
||||||
SetUnhandledExceptionFilter(TopLevelExceptionFilter);
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
#include "superexit.h"
|
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "launcher/shutdown.h"
|
|
||||||
#include "rawinput/rawinput.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "touch/touch.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
#include "games/io.h"
|
|
||||||
#include "overlay/overlay.h"
|
|
||||||
|
|
||||||
namespace superexit {
|
|
||||||
|
|
||||||
static std::thread *THREAD = nullptr;
|
|
||||||
static bool THREAD_RUNNING = false;
|
|
||||||
|
|
||||||
bool has_focus() {
|
|
||||||
HWND fg_wnd = GetForegroundWindow();
|
|
||||||
if (fg_wnd == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (fg_wnd == SPICETOUCH_TOUCH_HWND) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
DWORD fg_pid;
|
|
||||||
GetWindowThreadProcessId(fg_wnd, &fg_pid);
|
|
||||||
return fg_pid == GetCurrentProcessId();
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
|
|
||||||
// check if already running
|
|
||||||
if (THREAD)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// create new thread
|
|
||||||
THREAD_RUNNING = true;
|
|
||||||
THREAD = new std::thread([] {
|
|
||||||
|
|
||||||
// log
|
|
||||||
log_info("superexit", "enabled");
|
|
||||||
|
|
||||||
// set variable to false to stop
|
|
||||||
while (THREAD_RUNNING) {
|
|
||||||
|
|
||||||
// check rawinput for ALT+F4
|
|
||||||
bool rawinput_exit = false;
|
|
||||||
if (RI_MGR != nullptr) {
|
|
||||||
auto devices = RI_MGR->devices_get();
|
|
||||||
for (auto &device : devices) {
|
|
||||||
switch (device.type) {
|
|
||||||
case rawinput::KEYBOARD: {
|
|
||||||
auto &key_states = device.keyboardInfo->key_states;
|
|
||||||
for (int page_index = 0; page_index < 1024; page_index += 256) {
|
|
||||||
if (key_states[page_index + VK_MENU]
|
|
||||||
&& key_states[page_index + VK_F4]) {
|
|
||||||
rawinput_exit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool async_key_exit = GetAsyncKeyState(VK_MENU) && GetAsyncKeyState(VK_F4);
|
|
||||||
|
|
||||||
bool overlay_exit = false;
|
|
||||||
auto buttons = games::get_buttons_overlay(eamuse_get_game());
|
|
||||||
if (buttons &&
|
|
||||||
(!overlay::OVERLAY || overlay::OVERLAY->hotkeys_triggered()) &&
|
|
||||||
GameAPI::Buttons::getState(RI_MGR, buttons->at(games::OverlayButtons::SuperExit))) {
|
|
||||||
overlay_exit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for exit
|
|
||||||
if (rawinput_exit || async_key_exit) {
|
|
||||||
if (has_focus()) {
|
|
||||||
log_info("superexit", "detected ALT+F4, exiting...");
|
|
||||||
launcher::shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (overlay_exit) {
|
|
||||||
if (has_focus()) {
|
|
||||||
log_info("superexit", "detected Force Exit Game overlay shortcut, exiting...");
|
|
||||||
launcher::shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// slow down
|
|
||||||
Sleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
if (!THREAD) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop old thread
|
|
||||||
THREAD_RUNNING = false;
|
|
||||||
THREAD->join();
|
|
||||||
|
|
||||||
// delete thread
|
|
||||||
delete THREAD;
|
|
||||||
THREAD = nullptr;
|
|
||||||
|
|
||||||
// log
|
|
||||||
log_info("superexit", "disabled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,408 +0,0 @@
|
|||||||
#include "impl_spice.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include "cfg/configurator.h"
|
|
||||||
#include "games/io.h"
|
|
||||||
#include "launcher/launcher.h"
|
|
||||||
#include "launcher/superexit.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
#include "overlay/overlay.h"
|
|
||||||
#include "rawinput/rawinput.h"
|
|
||||||
#include "touch/touch.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/utils.h"
|
|
||||||
#include "hooks/graphics/graphics.h"
|
|
||||||
|
|
||||||
#if !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) || \
|
|
||||||
!defined(IMGUI_DISABLE_DEFAULT_ALLOCATORS) || \
|
|
||||||
!defined(IMGUI_USE_BGRA_PACKED_COLOR) || \
|
|
||||||
!defined(IMGUI_HAS_VIEWPORT) || \
|
|
||||||
!defined(IMGUI_HAS_DOCK) || \
|
|
||||||
!defined(IMGUI_DISABLE_DEMO_WINDOWS) || \
|
|
||||||
defined(IMGUI_DISABLE_DEBUG_TOOLS)
|
|
||||||
#error "fix imconfig.h after updating imgui version"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// state
|
|
||||||
static HWND g_hWnd = nullptr;
|
|
||||||
static INT64 g_Time = 0;
|
|
||||||
static INT64 g_TicksPerSecond = 0;
|
|
||||||
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
|
||||||
|
|
||||||
bool ImGui_ImplSpice_Init(HWND hWnd) {
|
|
||||||
log_misc("imgui_impl_spice", "init");
|
|
||||||
|
|
||||||
// check if already initialized
|
|
||||||
if (g_hWnd != nullptr) {
|
|
||||||
if (g_hWnd == hWnd) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
ImGui_ImplSpice_Shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// init performance stuff
|
|
||||||
if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond))
|
|
||||||
return false;
|
|
||||||
if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// setup back-end capabilities flags
|
|
||||||
g_hWnd = hWnd;
|
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
|
|
||||||
io.BackendPlatformName = "imgui_impl_spice";
|
|
||||||
io.ConfigErrorRecoveryEnableTooltip = true;
|
|
||||||
|
|
||||||
// keyboard mapping
|
|
||||||
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
|
|
||||||
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
|
|
||||||
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
|
|
||||||
io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
|
|
||||||
io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
|
|
||||||
io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
|
|
||||||
io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
|
|
||||||
io.KeyMap[ImGuiKey_Home] = VK_HOME;
|
|
||||||
io.KeyMap[ImGuiKey_End] = VK_END;
|
|
||||||
io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
|
|
||||||
io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
|
|
||||||
io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
|
|
||||||
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
|
|
||||||
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
|
|
||||||
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
|
|
||||||
io.KeyMap[ImGuiKey_KeypadEnter] = VK_RETURN;
|
|
||||||
io.KeyMap[ImGuiKey_A] = 'A';
|
|
||||||
io.KeyMap[ImGuiKey_C] = 'C';
|
|
||||||
io.KeyMap[ImGuiKey_V] = 'V';
|
|
||||||
io.KeyMap[ImGuiKey_X] = 'X';
|
|
||||||
io.KeyMap[ImGuiKey_Y] = 'Y';
|
|
||||||
io.KeyMap[ImGuiKey_Z] = 'Z';
|
|
||||||
|
|
||||||
// get display size
|
|
||||||
ImGui_ImplSpice_UpdateDisplaySize();
|
|
||||||
|
|
||||||
// return success
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplSpice_Shutdown() {
|
|
||||||
log_misc("imgui_impl_spice", "shutdown");
|
|
||||||
|
|
||||||
// reset window handle
|
|
||||||
g_hWnd = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplSpice_UpdateDisplaySize() {
|
|
||||||
|
|
||||||
// get display size
|
|
||||||
RECT rect;
|
|
||||||
::GetClientRect(g_hWnd, &rect);
|
|
||||||
ImGui::GetIO().DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImGui_ImplSpice_UpdateMouseCursor() {
|
|
||||||
|
|
||||||
// check if cursor should be changed
|
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update cursor
|
|
||||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
|
||||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) {
|
|
||||||
|
|
||||||
// hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
|
||||||
::SetCursor(nullptr);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// show OS mouse cursor
|
|
||||||
LPTSTR win32_cursor = IDC_ARROW;
|
|
||||||
switch (imgui_cursor) {
|
|
||||||
case ImGuiMouseCursor_Arrow:
|
|
||||||
win32_cursor = IDC_ARROW;
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_TextInput:
|
|
||||||
win32_cursor = IDC_IBEAM;
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeAll:
|
|
||||||
win32_cursor = IDC_SIZEALL;
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeEW:
|
|
||||||
win32_cursor = IDC_SIZEWE;
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeNS:
|
|
||||||
win32_cursor = IDC_SIZENS;
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeNESW:
|
|
||||||
win32_cursor = IDC_SIZENESW;
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeNWSE:
|
|
||||||
win32_cursor = IDC_SIZENWSE;
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_Hand:
|
|
||||||
win32_cursor = IDC_HAND;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
::SetCursor(::LoadCursor(nullptr, win32_cursor));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ImGui_ImplSpice_UpdateMousePos() {
|
|
||||||
|
|
||||||
// get current window size
|
|
||||||
RECT rect;
|
|
||||||
if (GetClientRect(g_hWnd, &rect)) {
|
|
||||||
ImVec2 window_size(
|
|
||||||
(float)(rect.right - rect.left),
|
|
||||||
(float)(rect.bottom - rect.top));
|
|
||||||
|
|
||||||
// set OS mouse position if requested
|
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
if (io.WantSetMousePos) {
|
|
||||||
POINT pos {
|
|
||||||
.x = static_cast<long>(io.MousePos.x),
|
|
||||||
.y = static_cast<long>(io.MousePos.y),
|
|
||||||
};
|
|
||||||
::ClientToScreen(g_hWnd, &pos);
|
|
||||||
::SetCursorPos(
|
|
||||||
static_cast<int>(pos.x / io.DisplaySize.x * window_size.x),
|
|
||||||
static_cast<int>(pos.y / io.DisplaySize.y * window_size.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto active_window = ::GetForegroundWindow();
|
|
||||||
|
|
||||||
// if the main focus is a windowed subscreen, put the imgui cursor in a place that won't
|
|
||||||
// trigger any overlay, don't process anything else
|
|
||||||
const auto is_windowed_subscreen =
|
|
||||||
(GRAPHICS_IIDX_WSUB && active_window == TDJ_SUBSCREEN_WINDOW) ||
|
|
||||||
(active_window == SDVX_SUBSCREEN_WINDOW);
|
|
||||||
if (is_windowed_subscreen) {
|
|
||||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set mouse position
|
|
||||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
|
||||||
POINT pos;
|
|
||||||
if (active_window) {
|
|
||||||
if (active_window == g_hWnd
|
|
||||||
|| ::IsChild(active_window, g_hWnd)
|
|
||||||
|| ::IsChild(g_hWnd, active_window)
|
|
||||||
|| active_window == SPICETOUCH_TOUCH_HWND) {
|
|
||||||
if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos)) {
|
|
||||||
io.MousePos = ImVec2(
|
|
||||||
(float) pos.x * io.DisplaySize.x / window_size.x,
|
|
||||||
(float) pos.y * io.DisplaySize.y / window_size.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback to touch hwnd
|
|
||||||
if (io.MousePos.x == -FLT_MAX || io.MousePos.y == -FLT_MAX) {
|
|
||||||
if (SPICETOUCH_TOUCH_HWND) {
|
|
||||||
if (::GetCursorPos(&pos) && ::ScreenToClient(SPICETOUCH_TOUCH_HWND, &pos)) {
|
|
||||||
io.MousePos = ImVec2(
|
|
||||||
(float) pos.x * io.DisplaySize.x / window_size.x,
|
|
||||||
(float) pos.y * io.DisplaySize.y / window_size.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// alternatively check touch
|
|
||||||
std::vector<TouchPoint> touch_points;
|
|
||||||
touch_get_points(touch_points, true);
|
|
||||||
static size_t delay_touch = 0;
|
|
||||||
static size_t delay_touch_target = 2;
|
|
||||||
static DWORD last_touch_id = ~0u;
|
|
||||||
if (!touch_points.empty() && !is_windowed_subscreen) {
|
|
||||||
|
|
||||||
// use the first touch point
|
|
||||||
auto &tp = touch_points[0];
|
|
||||||
io.MousePos.x = tp.x * io.DisplaySize.x / window_size.x;
|
|
||||||
io.MousePos.y = tp.y * io.DisplaySize.y / window_size.y;
|
|
||||||
|
|
||||||
// update cursor position
|
|
||||||
if (!tp.mouse) {
|
|
||||||
pos.x = static_cast<long>(io.MousePos.x);
|
|
||||||
pos.y = static_cast<long>(io.MousePos.y);
|
|
||||||
::ClientToScreen(g_hWnd, &pos);
|
|
||||||
::SetCursorPos(
|
|
||||||
static_cast<long>(pos.x / io.DisplaySize.x * window_size.x),
|
|
||||||
static_cast<long>(pos.y / io.DisplaySize.y * window_size.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
// delay press
|
|
||||||
io.MouseDown[0] = delay_touch++ >= delay_touch_target && last_touch_id == tp.id;
|
|
||||||
if (last_touch_id == ~0u) {
|
|
||||||
last_touch_id = tp.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// reset
|
|
||||||
delay_touch = 0;
|
|
||||||
last_touch_id = ~0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplSpice_NewFrame() {
|
|
||||||
|
|
||||||
// check if font is built
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
IM_ASSERT(io.Fonts->IsBuilt());
|
|
||||||
|
|
||||||
// setup time step
|
|
||||||
INT64 current_time;
|
|
||||||
::QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
|
|
||||||
io.DeltaTime = (float) (current_time - g_Time) / g_TicksPerSecond;
|
|
||||||
g_Time = current_time;
|
|
||||||
|
|
||||||
// remember old state
|
|
||||||
BYTE KeysDownOld[sizeof(io.KeysDown)];
|
|
||||||
for (size_t i = 0; i < sizeof(io.KeysDown); i++) {
|
|
||||||
KeysDownOld[i] = io.KeysDown[i] ? ~0 : 0;
|
|
||||||
}
|
|
||||||
KeysDownOld[VK_SHIFT] |= KeysDownOld[VK_LSHIFT];
|
|
||||||
KeysDownOld[VK_SHIFT] |= KeysDownOld[VK_RSHIFT];
|
|
||||||
|
|
||||||
// reset keys state
|
|
||||||
io.MouseWheel = 0;
|
|
||||||
io.KeyCtrl = false;
|
|
||||||
io.KeyShift = false;
|
|
||||||
io.KeyAlt = false;
|
|
||||||
io.KeySuper = false;
|
|
||||||
memset(io.KeysDown, false, sizeof(io.KeysDown));
|
|
||||||
memset(io.MouseDown, false, sizeof(io.MouseDown));
|
|
||||||
|
|
||||||
// early quit if window not in focus
|
|
||||||
if (!superexit::has_focus()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read keyboard modifiers inputs
|
|
||||||
io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
|
||||||
io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
|
||||||
io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
|
|
||||||
io.KeySuper = (::GetKeyState(VK_LWIN) & 0x8000) != 0;
|
|
||||||
io.KeySuper |= (::GetKeyState(VK_RWIN) & 0x8000) != 0;
|
|
||||||
|
|
||||||
// apply windows mouse buttons
|
|
||||||
io.MouseDown[0] |= (get_async_primary_mouse()) != 0;
|
|
||||||
io.MouseDown[1] |= (get_async_secondary_mouse()) != 0;
|
|
||||||
io.MouseDown[2] |= (GetAsyncKeyState(VK_MBUTTON)) != 0;
|
|
||||||
|
|
||||||
// read new keys state
|
|
||||||
static long mouse_wheel_last = 0;
|
|
||||||
long mouse_wheel = 0;
|
|
||||||
if (RI_MGR != nullptr) {
|
|
||||||
auto devices = RI_MGR->devices_get();
|
|
||||||
for (auto &device : devices) {
|
|
||||||
switch (device.type) {
|
|
||||||
case rawinput::MOUSE: {
|
|
||||||
auto &mouse = device.mouseInfo;
|
|
||||||
|
|
||||||
// mouse button triggers
|
|
||||||
if (GetSystemMetrics(SM_SWAPBUTTON)) {
|
|
||||||
if (mouse->key_states[rawinput::MOUSEBTN_RIGHT]) {
|
|
||||||
io.MouseDown[0] = true;
|
|
||||||
}
|
|
||||||
if (mouse->key_states[rawinput::MOUSEBTN_LEFT]) {
|
|
||||||
io.MouseDown[1] = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mouse->key_states[rawinput::MOUSEBTN_LEFT]) {
|
|
||||||
io.MouseDown[0] = true;
|
|
||||||
}
|
|
||||||
if (mouse->key_states[rawinput::MOUSEBTN_RIGHT]) {
|
|
||||||
io.MouseDown[1] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mouse->key_states[rawinput::MOUSEBTN_MIDDLE]) {
|
|
||||||
io.MouseDown[2] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// final mouse wheel value should be all devices combined
|
|
||||||
mouse_wheel += mouse->pos_wheel;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case rawinput::KEYBOARD: {
|
|
||||||
|
|
||||||
// iterate all virtual key codes
|
|
||||||
for (size_t vKey = 0; vKey < 256; vKey++) {
|
|
||||||
|
|
||||||
// get state (combined from all pages)
|
|
||||||
auto &key_states = device.keyboardInfo->key_states;
|
|
||||||
bool state = false;
|
|
||||||
for (size_t page_index = 0; page_index < 1024; page_index += 256) {
|
|
||||||
state |= key_states[page_index + vKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
// trigger
|
|
||||||
io.KeysDown[vKey] |= state;
|
|
||||||
|
|
||||||
// generate character input, but only if WM_CHAR didn't take over the
|
|
||||||
// functionality
|
|
||||||
if (!overlay::USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT && !KeysDownOld[vKey] && state) {
|
|
||||||
UCHAR buf[2];
|
|
||||||
auto ret = ToAscii(
|
|
||||||
static_cast<UINT>(vKey),
|
|
||||||
0,
|
|
||||||
static_cast<const BYTE *>(KeysDownOld),
|
|
||||||
reinterpret_cast<LPWORD>(buf),
|
|
||||||
0);
|
|
||||||
if (ret > 0) {
|
|
||||||
for (int i = 0; i < ret; i++) {
|
|
||||||
overlay::OVERLAY->input_char(buf[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set mouse wheel
|
|
||||||
auto mouse_diff = mouse_wheel - mouse_wheel_last;
|
|
||||||
mouse_wheel_last = mouse_wheel;
|
|
||||||
io.MouseWheel = mouse_diff;
|
|
||||||
|
|
||||||
// update OS mouse position
|
|
||||||
ImGui_ImplSpice_UpdateMousePos();
|
|
||||||
|
|
||||||
if (cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
// if cursor is inside the client area, always set the OS cursor to what ImGui wants
|
|
||||||
// this is to deal with cases where mouse cursor changes outside the client rect and comes
|
|
||||||
// back into the window
|
|
||||||
// i'm sure there might be better ways to deal with this but this works so whatever, right?
|
|
||||||
RECT client_rect;
|
|
||||||
if (GetClientRect(g_hWnd, &client_rect)) {
|
|
||||||
POINT cursor;
|
|
||||||
if (GetCursorPos(&cursor) && ScreenToClient(g_hWnd, &cursor)) {
|
|
||||||
if (client_rect.left < cursor.x && cursor.x < client_rect.right &&
|
|
||||||
client_rect.top < cursor.y && cursor.y < client_rect.bottom) {
|
|
||||||
ImGui_ImplSpice_UpdateMouseCursor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// update OS mouse cursor with the cursor requested by imgui
|
|
||||||
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
|
||||||
if (g_LastMouseCursor != mouse_cursor) {
|
|
||||||
g_LastMouseCursor = mouse_cursor;
|
|
||||||
ImGui_ImplSpice_UpdateMouseCursor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,739 +0,0 @@
|
|||||||
#include "overlay.h"
|
|
||||||
|
|
||||||
#include "avs/game.h"
|
|
||||||
#include "cfg/configurator.h"
|
|
||||||
#include "games/io.h"
|
|
||||||
#include "games/gitadora/gitadora.h"
|
|
||||||
#include "games/iidx/iidx.h"
|
|
||||||
#include "hooks/graphics/graphics.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
#include "touch/touch.h"
|
|
||||||
#include "util/fileutils.h"
|
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/resutils.h"
|
|
||||||
#include "build/resource.h"
|
|
||||||
|
|
||||||
#include "external/imgui/backends/imgui_impl_dx9.h"
|
|
||||||
#include "overlay/imgui/impl_spice.h"
|
|
||||||
#include "overlay/imgui/impl_sw.h"
|
|
||||||
|
|
||||||
#include "window.h"
|
|
||||||
#ifdef SPICE64
|
|
||||||
#include "windows/camera_control.h"
|
|
||||||
#endif
|
|
||||||
#include "windows/card_manager.h"
|
|
||||||
#include "windows/screen_resize.h"
|
|
||||||
#include "windows/config.h"
|
|
||||||
#include "windows/control.h"
|
|
||||||
#include "windows/fps.h"
|
|
||||||
#include "windows/generic_sub.h"
|
|
||||||
#include "windows/iidx_seg.h"
|
|
||||||
#include "windows/iidx_sub.h"
|
|
||||||
#include "windows/gfdm_sub.h"
|
|
||||||
#include "windows/drs_dancefloor.h"
|
|
||||||
#include "windows/iopanel.h"
|
|
||||||
#include "windows/iopanel_ddr.h"
|
|
||||||
#include "windows/iopanel_gfdm.h"
|
|
||||||
#include "windows/iopanel_iidx.h"
|
|
||||||
#include "windows/sdvx_sub.h"
|
|
||||||
#include "windows/keypad.h"
|
|
||||||
#include "windows/log.h"
|
|
||||||
#include "windows/patch_manager.h"
|
|
||||||
#include "windows/exitprompt.cpp"
|
|
||||||
|
|
||||||
static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) \
|
|
||||||
{ return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); }
|
|
||||||
|
|
||||||
namespace overlay {
|
|
||||||
|
|
||||||
// settings
|
|
||||||
bool ENABLED = true;
|
|
||||||
bool AUTO_SHOW_FPS = false;
|
|
||||||
bool AUTO_SHOW_SUBSCREEN = false;
|
|
||||||
bool AUTO_SHOW_IOPANEL = false;
|
|
||||||
bool AUTO_SHOW_KEYPAD_P1 = false;
|
|
||||||
bool AUTO_SHOW_KEYPAD_P2 = false;
|
|
||||||
bool USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT = false;
|
|
||||||
bool FPS_SHOULD_FLIP = false;
|
|
||||||
std::optional<uint32_t> UI_SCALE_PERCENT;
|
|
||||||
|
|
||||||
// global
|
|
||||||
std::mutex OVERLAY_MUTEX;
|
|
||||||
std::unique_ptr<overlay::SpiceOverlay> OVERLAY = nullptr;
|
|
||||||
ImFont* DSEG_FONT = nullptr;
|
|
||||||
bool SHOW_DEBUG_LOG_WINDOW = false;
|
|
||||||
|
|
||||||
ImVec2 apply_scaling_to_vector(float x, float y) {
|
|
||||||
if (!UI_SCALE_PERCENT.has_value()) {
|
|
||||||
return ImVec2(x, y);
|
|
||||||
}
|
|
||||||
return ImVec2(apply_scaling(x), apply_scaling(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
ImVec2 apply_scaling_to_vector(const ImVec2& input) {
|
|
||||||
return apply_scaling_to_vector(input.x, input.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *ImGui_Alloc(size_t sz, void *user_data) {
|
|
||||||
void *data = malloc(sz);
|
|
||||||
if (!data) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(data, 0, sz);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ImGui_Free(void *data, void *user_data) {
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::create_d3d9(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device) {
|
|
||||||
if (!overlay::ENABLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::lock_guard<std::mutex> lock(OVERLAY_MUTEX);
|
|
||||||
|
|
||||||
if (!overlay::OVERLAY) {
|
|
||||||
overlay::OVERLAY = std::make_unique<overlay::SpiceOverlay>(hWnd, d3d, device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::create_software(HWND hWnd) {
|
|
||||||
if (!overlay::ENABLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::lock_guard<std::mutex> lock(OVERLAY_MUTEX);
|
|
||||||
|
|
||||||
if (!overlay::OVERLAY) {
|
|
||||||
overlay::OVERLAY = std::make_unique<overlay::SpiceOverlay>(hWnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::destroy(HWND hWnd) {
|
|
||||||
if (!overlay::ENABLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::lock_guard<std::mutex> lock(OVERLAY_MUTEX);
|
|
||||||
|
|
||||||
if (overlay::OVERLAY && (hWnd == nullptr || overlay::OVERLAY->uses_window(hWnd))) {
|
|
||||||
overlay::OVERLAY.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
overlay::SpiceOverlay::SpiceOverlay(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device)
|
|
||||||
: renderer(OverlayRenderer::D3D9), hWnd(hWnd), d3d(d3d), device(device) {
|
|
||||||
log_info("overlay", "initializing (D3D9)");
|
|
||||||
|
|
||||||
// increment reference counts
|
|
||||||
this->d3d->AddRef();
|
|
||||||
this->device->AddRef();
|
|
||||||
|
|
||||||
// get creation parameters
|
|
||||||
HRESULT ret;
|
|
||||||
ret = this->device->GetCreationParameters(&this->creation_parameters);
|
|
||||||
if (FAILED(ret)) {
|
|
||||||
log_fatal("overlay", "GetCreationParameters failed, hr={}", FMT_HRESULT(ret));
|
|
||||||
}
|
|
||||||
|
|
||||||
// get adapter identifier
|
|
||||||
ret = this->d3d->GetAdapterIdentifier(
|
|
||||||
creation_parameters.AdapterOrdinal,
|
|
||||||
0,
|
|
||||||
&this->adapter_identifier);
|
|
||||||
if (FAILED(ret)) {
|
|
||||||
log_fatal("overlay", "GetAdapterIdentifier failed, hr={}", FMT_HRESULT(ret));
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
this->init();
|
|
||||||
}
|
|
||||||
|
|
||||||
overlay::SpiceOverlay::SpiceOverlay(HWND hWnd)
|
|
||||||
: renderer(OverlayRenderer::SOFTWARE), hWnd(hWnd) {
|
|
||||||
log_info("overlay", "initializing (SOFTWARE)");
|
|
||||||
|
|
||||||
// init
|
|
||||||
this->init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::init() {
|
|
||||||
|
|
||||||
// init imgui
|
|
||||||
IMGUI_CHECKVERSION();
|
|
||||||
ImGui::SetAllocatorFunctions(ImGui_Alloc, ImGui_Free, nullptr);
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGui::GetIO();
|
|
||||||
|
|
||||||
// set style
|
|
||||||
ImGui::StyleColorsDark();
|
|
||||||
if (this->renderer == OverlayRenderer::SOFTWARE) {
|
|
||||||
imgui_sw::make_style_fast();
|
|
||||||
ImVec4* colors = ImGui::GetStyle().Colors;
|
|
||||||
colors[ImGuiCol_Border].w = 0;
|
|
||||||
colors[ImGuiCol_Separator].w = 0.25f;
|
|
||||||
} else {
|
|
||||||
auto &style = ImGui::GetStyle();
|
|
||||||
style.WindowRounding = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UI_SCALE_PERCENT.has_value()) {
|
|
||||||
const auto scale = static_cast<float>(UI_SCALE_PERCENT.value()) / 100.f;
|
|
||||||
ImGui::GetStyle().ScaleAllSizes(scale);
|
|
||||||
ImGui::GetIO().FontGlobalScale = scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// red theme based on:
|
|
||||||
// https://github.com/ocornut/imgui/issues/707#issuecomment-760220280
|
|
||||||
// r, g, b, a
|
|
||||||
ImVec4* colors = ImGui::GetStyle().Colors;
|
|
||||||
|
|
||||||
// note: also see bg_alpha value in each overlay window
|
|
||||||
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.0f);
|
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 1.0f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
|
|
||||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_FrameBg] = ImVec4(0.18f, 0.18f, 0.18f, 0.54f);
|
|
||||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.18f, 0.18f, 0.18f, 0.80f);
|
|
||||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.24f, 0.24f, 0.24f, 0.80f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
|
||||||
colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
|
|
||||||
colors[ImGuiCol_CheckMark] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
|
||||||
colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
|
||||||
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Button] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
|
||||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.80f, 0.17f, 0.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.17f, 0.00f, 0.90f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Header] = ImVec4(0.33f, 0.35f, 0.36f, 0.53f);
|
|
||||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.67f);
|
|
||||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.47f, 0.47f, 0.47f, 0.67f);
|
|
||||||
colors[ImGuiCol_Separator] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
|
||||||
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
|
||||||
colors[ImGuiCol_SeparatorActive] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
|
||||||
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.85f);
|
|
||||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
|
|
||||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Tab] = colors[ImGuiCol_Button];
|
|
||||||
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_ButtonHovered];
|
|
||||||
colors[ImGuiCol_TabActive] = colors[ImGuiCol_ButtonActive];
|
|
||||||
colors[ImGuiCol_TabUnfocused] = colors[ImGuiCol_Tab] * ImVec4(1.0f, 1.0f, 1.0f, 0.6f);
|
|
||||||
colors[ImGuiCol_TabUnfocusedActive] = colors[ImGuiCol_TabActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.6f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_DockingPreview] = ImVec4(0.47f, 0.47f, 0.47f, 0.47f);
|
|
||||||
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.02f);
|
|
||||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
|
||||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
|
||||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
|
||||||
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
|
||||||
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
|
|
||||||
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
|
|
||||||
|
|
||||||
// configure IO
|
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
io.UserData = this;
|
|
||||||
io.ConfigFlags = ImGuiConfigFlags_NavEnableKeyboard
|
|
||||||
| ImGuiConfigFlags_NavEnableGamepad
|
|
||||||
| ImGuiConfigFlags_NavEnableSetMousePos;
|
|
||||||
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
|
||||||
}
|
|
||||||
if (is_touch_available("SpiceOverlay::init")) {
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_IsTouchScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
// temporarily turn this off as it can cause crashes during font load failures
|
|
||||||
// turns back on in ImGui_ImplSpice_Init
|
|
||||||
io.ConfigErrorRecoveryEnableTooltip = false;
|
|
||||||
|
|
||||||
io.MouseDrawCursor = !GRAPHICS_SHOW_CURSOR;
|
|
||||||
|
|
||||||
// disable config
|
|
||||||
io.IniFilename = nullptr;
|
|
||||||
|
|
||||||
// allow CTRL+WHEEL scaling
|
|
||||||
io.FontAllowUserScaling = true;
|
|
||||||
|
|
||||||
// add default font
|
|
||||||
io.Fonts->AddFontDefault();
|
|
||||||
|
|
||||||
// add fallback fonts for missing glyph ranges
|
|
||||||
ImFontConfig config {};
|
|
||||||
config.MergeMode = true;
|
|
||||||
|
|
||||||
log_misc("overlay", "loading fonts, failures are not fatal");
|
|
||||||
add_font("simsun.ttc", &config, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
|
||||||
add_font("arial.ttf", &config, io.Fonts->GetGlyphRangesCyrillic());
|
|
||||||
add_font("meiryu.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
|
||||||
add_font("meiryo.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
|
||||||
add_font("gulim.ttc", &config, io.Fonts->GetGlyphRangesKorean());
|
|
||||||
add_font("cordia.ttf", &config, io.Fonts->GetGlyphRangesThai());
|
|
||||||
add_font("arial.ttf", &config, io.Fonts->GetGlyphRangesVietnamese());
|
|
||||||
|
|
||||||
// add special font
|
|
||||||
if (avs::game::is_model("LDJ")) {
|
|
||||||
DWORD size;
|
|
||||||
ImFontConfig config {};
|
|
||||||
config.FontDataOwnedByAtlas = false;
|
|
||||||
auto buffer = resutil::load_file(IDR_DSEGFONT, &size);
|
|
||||||
DSEG_FONT = io.Fonts->AddFontFromMemoryTTF((void *)buffer, size,
|
|
||||||
overlay::windows::IIDX_SEGMENT_FONT_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// init implementation
|
|
||||||
ImGui_ImplSpice_Init(this->hWnd);
|
|
||||||
switch (this->renderer) {
|
|
||||||
case OverlayRenderer::D3D9:
|
|
||||||
ImGui_ImplDX9_Init(this->device);
|
|
||||||
break;
|
|
||||||
case OverlayRenderer::SOFTWARE:
|
|
||||||
imgui_sw::bind_imgui_painting();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create empty frame
|
|
||||||
switch (this->renderer) {
|
|
||||||
case OverlayRenderer::D3D9:
|
|
||||||
ImGui_ImplDX9_NewFrame();
|
|
||||||
break;
|
|
||||||
case OverlayRenderer::SOFTWARE:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ImGui_ImplSpice_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
ImGui::EndFrame();
|
|
||||||
|
|
||||||
// fix navigation buttons causing crash on overlay activation
|
|
||||||
ImGui::Begin("Temp");
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
bool set_overlay_active = false;
|
|
||||||
|
|
||||||
// referenced windows
|
|
||||||
this->window_add(window_fps = new overlay::windows::FPS(this));
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && AUTO_SHOW_FPS) {
|
|
||||||
window_fps->set_active(true);
|
|
||||||
set_overlay_active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->window_add(window_main_menu = new overlay::windows::ExitPrompt(this));
|
|
||||||
|
|
||||||
// add default windows
|
|
||||||
this->window_add(window_config = new overlay::windows::Config(this));
|
|
||||||
this->window_add(window_control = new overlay::windows::Control(this));
|
|
||||||
this->window_add(window_log = new overlay::windows::Log(this));
|
|
||||||
#ifdef SPICE64
|
|
||||||
if (avs::game::is_model("LDJ")) {
|
|
||||||
this->window_add(window_camera = new overlay::windows::CameraControl(this));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
this->window_add(window_cards = new overlay::windows::CardManager(this));
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
this->window_add(window_resize = new overlay::windows::ScreenResize(this));
|
|
||||||
}
|
|
||||||
this->window_add(new overlay::windows::PatchManager(this));
|
|
||||||
|
|
||||||
{
|
|
||||||
window_keypad1 = new overlay::windows::Keypad(this, 0);
|
|
||||||
this->window_add(window_keypad1);
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && AUTO_SHOW_KEYPAD_P1) {
|
|
||||||
window_keypad1->set_active(true);
|
|
||||||
set_overlay_active = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (eamuse_get_game_keypads() > 1) {
|
|
||||||
window_keypad2 = new overlay::windows::Keypad(this, 1);
|
|
||||||
this->window_add(window_keypad2);
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && AUTO_SHOW_KEYPAD_P2) {
|
|
||||||
window_keypad2->set_active(true);
|
|
||||||
set_overlay_active = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IO panel needs to know what game is running
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
window_iopanel = nullptr;
|
|
||||||
if (avs::game::is_model("LDJ")) {
|
|
||||||
window_iopanel = new overlay::windows::IIDXIOPanel(this);
|
|
||||||
} else if (avs::game::is_model("MDX")) {
|
|
||||||
window_iopanel = new overlay::windows::DDRIOPanel(this);
|
|
||||||
} else if (avs::game::is_model({"J32", "J33", "K32", "K33", "L32", "L33", "M32"}) &&
|
|
||||||
!games::gitadora::is_arena_model()) {
|
|
||||||
window_iopanel = new overlay::windows::GitadoraIOPanel(this);
|
|
||||||
} else {
|
|
||||||
window_iopanel = new overlay::windows::IOPanel(this);
|
|
||||||
}
|
|
||||||
if (window_iopanel) {
|
|
||||||
this->window_add(window_iopanel);
|
|
||||||
if (AUTO_SHOW_IOPANEL) {
|
|
||||||
window_iopanel->set_active(true);
|
|
||||||
set_overlay_active = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// subscreens need DirectX, so don't try to initialize them in standalone
|
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
||||||
window_sub = nullptr;
|
|
||||||
if (avs::game::is_model("LDJ")) {
|
|
||||||
if (games::iidx::TDJ_MODE) {
|
|
||||||
window_sub = new overlay::windows::IIDXSubScreen(this);
|
|
||||||
} else {
|
|
||||||
window_sub = new overlay::windows::IIDXSegmentDisplay(this);
|
|
||||||
}
|
|
||||||
} else if (avs::game::is_model("REC")) {
|
|
||||||
window_sub = new overlay::windows::DRSDanceFloorDisplay(this);
|
|
||||||
} else if (avs::game::is_model("KFC")) {
|
|
||||||
window_sub = new overlay::windows::SDVXSubScreen(this);
|
|
||||||
} else if (games::gitadora::is_arena_model() && games::gitadora::ARENA_SINGLE_WINDOW) {
|
|
||||||
window_sub = new overlay::windows::GitaDoraSubScreen(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window_sub) {
|
|
||||||
this->window_add(window_sub);
|
|
||||||
if (AUTO_SHOW_SUBSCREEN) {
|
|
||||||
window_sub->set_active(true);
|
|
||||||
set_overlay_active = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set_overlay_active) {
|
|
||||||
this->set_active(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
overlay::SpiceOverlay::~SpiceOverlay() {
|
|
||||||
|
|
||||||
// imgui shutdown
|
|
||||||
ImGui_ImplSpice_Shutdown();
|
|
||||||
switch (this->renderer) {
|
|
||||||
case OverlayRenderer::D3D9:
|
|
||||||
ImGui_ImplDX9_Shutdown();
|
|
||||||
|
|
||||||
// drop references
|
|
||||||
this->device->Release();
|
|
||||||
this->d3d->Release();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case OverlayRenderer::SOFTWARE:
|
|
||||||
imgui_sw::unbind_imgui_painting();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::window_add(Window *wnd) {
|
|
||||||
this->windows.emplace_back(std::unique_ptr<Window>(wnd));
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::new_frame() {
|
|
||||||
|
|
||||||
// update implementation
|
|
||||||
ImGui_ImplSpice_NewFrame();
|
|
||||||
this->total_elapsed += ImGui::GetIO().DeltaTime;
|
|
||||||
|
|
||||||
// check if inactive
|
|
||||||
if (!this->active) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// init frame
|
|
||||||
switch (this->renderer) {
|
|
||||||
case OverlayRenderer::D3D9:
|
|
||||||
ImGui_ImplDX9_NewFrame();
|
|
||||||
break;
|
|
||||||
case OverlayRenderer::SOFTWARE:
|
|
||||||
ImGui_ImplSpice_UpdateDisplaySize();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
// build windows
|
|
||||||
for (auto &window : this->windows) {
|
|
||||||
window->build();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SHOW_DEBUG_LOG_WINDOW) {
|
|
||||||
ImGui::ShowDebugLogWindow(&SHOW_DEBUG_LOG_WINDOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
// end frame
|
|
||||||
ImGui::EndFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::render() {
|
|
||||||
|
|
||||||
// check if inactive
|
|
||||||
if (!this->active) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// imgui render
|
|
||||||
ImGui::Render();
|
|
||||||
|
|
||||||
// implementation render
|
|
||||||
switch (this->renderer) {
|
|
||||||
case OverlayRenderer::D3D9:
|
|
||||||
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
break;
|
|
||||||
case OverlayRenderer::SOFTWARE: {
|
|
||||||
|
|
||||||
// get display metrics
|
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
auto width = static_cast<size_t>(std::ceil(io.DisplaySize.x));
|
|
||||||
auto height = static_cast<size_t>(std::ceil(io.DisplaySize.y));
|
|
||||||
auto pixels = width * height;
|
|
||||||
|
|
||||||
// make sure buffer is big enough
|
|
||||||
if (this->pixel_data.size() < pixels) {
|
|
||||||
this->pixel_data.resize(pixels, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset buffer
|
|
||||||
memset(&this->pixel_data[0], 0, width * height * sizeof(uint32_t));
|
|
||||||
|
|
||||||
// render to pixel data
|
|
||||||
imgui_sw::SwOptions options {
|
|
||||||
.optimize_text = true,
|
|
||||||
.optimize_rectangles = true,
|
|
||||||
};
|
|
||||||
imgui_sw::paint_imgui(&this->pixel_data[0], width, height, options);
|
|
||||||
pixel_data_width = width;
|
|
||||||
pixel_data_height = height;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &window : this->windows) {
|
|
||||||
window->after_render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::update() {
|
|
||||||
|
|
||||||
// check overlay toggle
|
|
||||||
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
|
|
||||||
bool toggle_down_new = overlay_buttons
|
|
||||||
&& this->hotkeys_triggered()
|
|
||||||
&& GameAPI::Buttons::getState(RI_MGR, overlay_buttons->at(games::OverlayButtons::ToggleOverlay));
|
|
||||||
if (toggle_down_new && !this->toggle_down) {
|
|
||||||
toggle_active(true);
|
|
||||||
}
|
|
||||||
this->toggle_down = toggle_down_new;
|
|
||||||
|
|
||||||
// check main menu
|
|
||||||
const auto main_menu_down_new = overlay_buttons
|
|
||||||
&& this->hotkeys_triggered()
|
|
||||||
&& GameAPI::Buttons::getState(RI_MGR, overlay_buttons->at(games::OverlayButtons::ToggleMainMenu));
|
|
||||||
if (main_menu_down_new && !this->main_menu_down) {
|
|
||||||
show_main_menu();
|
|
||||||
}
|
|
||||||
this->main_menu_down = main_menu_down_new;
|
|
||||||
|
|
||||||
// update windows
|
|
||||||
for (auto &window : this->windows) {
|
|
||||||
window->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
// deactivate if no windows are shown
|
|
||||||
bool window_active = false;
|
|
||||||
for (auto &window : this->windows) {
|
|
||||||
if (window->get_active()) {
|
|
||||||
window_active = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!window_active) {
|
|
||||||
this->set_active(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool overlay::SpiceOverlay::update_cursor() {
|
|
||||||
return ImGui_ImplSpice_UpdateMouseCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::toggle_active(bool overlay_key) {
|
|
||||||
|
|
||||||
// invert active state
|
|
||||||
this->active = !this->active;
|
|
||||||
|
|
||||||
// get rid of main menu if it was visible
|
|
||||||
if (this->window_main_menu) {
|
|
||||||
this->window_main_menu->set_active(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// show FPS window if toggled with overlay key
|
|
||||||
if (overlay_key) {
|
|
||||||
this->window_fps->set_active(this->active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::show_main_menu() {
|
|
||||||
if (!this->window_main_menu) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this->window_main_menu->get_active()) {
|
|
||||||
// window already visible - close the window
|
|
||||||
this->window_main_menu->set_active(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ImGui::IsPopupOpen(0, ImGuiPopupFlags_AnyPopup)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->get_active()) {
|
|
||||||
if (!ImGui::IsAnyItemActive() && !ImGui::IsAnyItemFocused()) {
|
|
||||||
this->window_main_menu->set_active(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this->set_active(true);
|
|
||||||
this->window_main_menu->set_active(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::set_active(bool new_active) {
|
|
||||||
|
|
||||||
// toggle if different
|
|
||||||
if (this->active != new_active) {
|
|
||||||
this->toggle_active();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool overlay::SpiceOverlay::get_active() {
|
|
||||||
return this->active;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool overlay::SpiceOverlay::has_focus() {
|
|
||||||
return this->get_active() && ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool overlay::SpiceOverlay::hotkeys_triggered() {
|
|
||||||
|
|
||||||
// check if disabled first
|
|
||||||
if (!this->hotkeys_enable) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get buttons
|
|
||||||
auto buttons = games::get_buttons_overlay(eamuse_get_game());
|
|
||||||
if (!buttons) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &hotkey1 = buttons->at(games::OverlayButtons::HotkeyEnable1);
|
|
||||||
auto &hotkey2 = buttons->at(games::OverlayButtons::HotkeyEnable2);
|
|
||||||
auto &toggle = buttons->at(games::OverlayButtons::HotkeyToggle);
|
|
||||||
|
|
||||||
// check hotkey toggle
|
|
||||||
auto toggle_state = GameAPI::Buttons::getState(RI_MGR, toggle);
|
|
||||||
if (toggle_state) {
|
|
||||||
if (!this->hotkey_toggle_last) {
|
|
||||||
this->hotkey_toggle_last = true;
|
|
||||||
this->hotkey_toggle = !this->hotkey_toggle;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this->hotkey_toggle_last = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hotkey toggle overrides hotkey enable button states
|
|
||||||
if (hotkey_toggle) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check hotkey enable buttons
|
|
||||||
bool triggered = true;
|
|
||||||
if (hotkey1.isSet() && !GameAPI::Buttons::getState(RI_MGR, hotkey1)) {
|
|
||||||
triggered = false;
|
|
||||||
}
|
|
||||||
if (hotkey2.isSet() && !GameAPI::Buttons::getState(RI_MGR, hotkey2)) {
|
|
||||||
triggered = false;
|
|
||||||
}
|
|
||||||
return triggered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::reset_invalidate() {
|
|
||||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::reset_recreate() {
|
|
||||||
ImGui_ImplDX9_CreateDeviceObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::input_char(unsigned int c) {
|
|
||||||
// add character to ImGui
|
|
||||||
ImGui::GetIO().AddInputCharacter(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *overlay::SpiceOverlay::sw_get_pixel_data(int *width, int *height) {
|
|
||||||
|
|
||||||
// check if active
|
|
||||||
if (!this->active) {
|
|
||||||
*width = 0;
|
|
||||||
*height = 0;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure buffer has the right size
|
|
||||||
const size_t total_size = this->pixel_data_width * this->pixel_data_height;
|
|
||||||
if (this->pixel_data.size() < total_size) {
|
|
||||||
this->pixel_data.resize(total_size, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for empty surface
|
|
||||||
if (this->pixel_data.empty()) {
|
|
||||||
*width = 0;
|
|
||||||
*height = 0;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy and return pointer to data
|
|
||||||
*width = this->pixel_data_width;
|
|
||||||
*height = this->pixel_data_height;
|
|
||||||
return &this->pixel_data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void overlay::SpiceOverlay::add_font(const char* font, ImFontConfig* config, const ImWchar* glyphs) {
|
|
||||||
CHAR fonts_dir[MAX_PATH];
|
|
||||||
ExpandEnvironmentStringsA(R"(%SYSTEMROOT%\Fonts\)", fonts_dir, MAX_PATH);
|
|
||||||
std::filesystem::path full_path = fonts_dir;
|
|
||||||
full_path += font;
|
|
||||||
|
|
||||||
if (fileutils::file_exists(full_path)) {
|
|
||||||
log_misc("overlay", "loading font: {}", full_path.string());
|
|
||||||
ImGui::GetIO().Fonts->AddFontFromFileTTF(
|
|
||||||
full_path.string().c_str(),
|
|
||||||
13.0f,
|
|
||||||
config,
|
|
||||||
glyphs);
|
|
||||||
} else {
|
|
||||||
log_misc("overlay", "font not found: {}", full_path.string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <functional>
|
|
||||||
#include <optional>
|
|
||||||
#include <vector>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <d3d9.h>
|
|
||||||
|
|
||||||
#include "external/imgui/imgui.h"
|
|
||||||
|
|
||||||
namespace overlay {
|
|
||||||
class Window;
|
|
||||||
|
|
||||||
enum class OverlayRenderer {
|
|
||||||
D3D9,
|
|
||||||
SOFTWARE,
|
|
||||||
};
|
|
||||||
|
|
||||||
// settings
|
|
||||||
extern bool ENABLED;
|
|
||||||
extern bool AUTO_SHOW_FPS;
|
|
||||||
extern bool AUTO_SHOW_SUBSCREEN;
|
|
||||||
extern bool AUTO_SHOW_IOPANEL;
|
|
||||||
extern bool AUTO_SHOW_KEYPAD_P1;
|
|
||||||
extern bool AUTO_SHOW_KEYPAD_P2;
|
|
||||||
extern bool USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT;
|
|
||||||
extern bool FPS_SHOULD_FLIP;
|
|
||||||
extern bool SHOW_DEBUG_LOG_WINDOW;
|
|
||||||
extern std::optional<uint32_t> UI_SCALE_PERCENT;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
float apply_scaling(T input) {
|
|
||||||
if (!UI_SCALE_PERCENT.has_value()) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
return static_cast<float>(input) * UI_SCALE_PERCENT.value() / 100.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImVec2 apply_scaling_to_vector(const ImVec2& input);
|
|
||||||
ImVec2 apply_scaling_to_vector(float x, float y);
|
|
||||||
|
|
||||||
class SpiceOverlay {
|
|
||||||
public:
|
|
||||||
|
|
||||||
D3DDEVICE_CREATION_PARAMETERS creation_parameters {};
|
|
||||||
D3DADAPTER_IDENTIFIER9 adapter_identifier {};
|
|
||||||
bool hotkeys_enable = true;
|
|
||||||
|
|
||||||
// windows
|
|
||||||
Window *window_fps = nullptr;
|
|
||||||
Window *window_iopanel = nullptr;
|
|
||||||
Window *window_config = nullptr;
|
|
||||||
Window *window_keypad1 = nullptr;
|
|
||||||
Window *window_keypad2 = nullptr;
|
|
||||||
Window *window_cards = nullptr;
|
|
||||||
Window *window_control = nullptr;
|
|
||||||
Window *window_resize = nullptr;
|
|
||||||
Window *window_camera = nullptr;
|
|
||||||
Window *window_sub = nullptr;
|
|
||||||
Window *window_log = nullptr;
|
|
||||||
|
|
||||||
explicit SpiceOverlay(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
|
|
||||||
explicit SpiceOverlay(HWND hWnd);
|
|
||||||
~SpiceOverlay();
|
|
||||||
|
|
||||||
void window_add(Window *wnd);
|
|
||||||
void new_frame();
|
|
||||||
void render();
|
|
||||||
void update();
|
|
||||||
void toggle_active(bool overlay_key = false);
|
|
||||||
void show_main_menu();
|
|
||||||
void set_active(bool active);
|
|
||||||
bool get_active();
|
|
||||||
bool has_focus();
|
|
||||||
bool hotkeys_triggered();
|
|
||||||
|
|
||||||
static bool update_cursor();
|
|
||||||
static void reset_invalidate();
|
|
||||||
static void reset_recreate();
|
|
||||||
void input_char(unsigned int c);
|
|
||||||
|
|
||||||
uint32_t *sw_get_pixel_data(int *width, int *height);
|
|
||||||
|
|
||||||
inline bool uses_window(HWND hWnd) {
|
|
||||||
return this->hWnd == hWnd;
|
|
||||||
}
|
|
||||||
inline bool uses_context(IDirect3D9 *other) {
|
|
||||||
return this->d3d == other;
|
|
||||||
}
|
|
||||||
inline bool uses_device(IDirect3DDevice9 *other) {
|
|
||||||
return this->device == other;
|
|
||||||
}
|
|
||||||
inline IDirect3DDevice9 *get_device() {
|
|
||||||
return this->device;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool can_transform_touch_input() {
|
|
||||||
return (this->subscreen_mouse_handler != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool transform_touch_point(LONG *x, LONG *y) {
|
|
||||||
if (this->get_active() && this->subscreen_mouse_handler) {
|
|
||||||
return this->subscreen_mouse_handler(x, y);
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_subscreen_mouse_handler(const std::function<bool(LONG *, LONG *)> &f) {
|
|
||||||
this->subscreen_mouse_handler = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderer
|
|
||||||
OverlayRenderer renderer;
|
|
||||||
float total_elapsed = 0.f;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
HWND hWnd = nullptr;
|
|
||||||
|
|
||||||
// D3D9
|
|
||||||
IDirect3D9 *d3d = nullptr;
|
|
||||||
IDirect3DDevice9 *device = nullptr;
|
|
||||||
|
|
||||||
// software
|
|
||||||
std::vector<uint32_t> pixel_data;
|
|
||||||
size_t pixel_data_width = 0;
|
|
||||||
size_t pixel_data_height = 0;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Window>> windows;
|
|
||||||
|
|
||||||
Window *window_main_menu = nullptr;
|
|
||||||
|
|
||||||
std::function<bool(LONG *, LONG *)> subscreen_mouse_handler = nullptr;
|
|
||||||
|
|
||||||
bool active = false;
|
|
||||||
bool toggle_down = false;
|
|
||||||
bool main_menu_down = false;
|
|
||||||
bool hotkey_toggle = false;
|
|
||||||
bool hotkey_toggle_last = false;
|
|
||||||
|
|
||||||
void init();
|
|
||||||
void add_font(const char* font, ImFontConfig* config, const ImWchar* glyphs);
|
|
||||||
};
|
|
||||||
|
|
||||||
// global
|
|
||||||
extern std::mutex OVERLAY_MUTEX;
|
|
||||||
extern std::unique_ptr<overlay::SpiceOverlay> OVERLAY;
|
|
||||||
extern ImFont* DSEG_FONT;
|
|
||||||
|
|
||||||
// synchronized helpers
|
|
||||||
void create_d3d9(HWND hWnd, IDirect3D9 *d3d, IDirect3DDevice9 *device);
|
|
||||||
void create_software(HWND hWnd);
|
|
||||||
void destroy(HWND hWnd = nullptr);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,127 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include "cfg/game.h"
|
|
||||||
#include "overlay/window.h"
|
|
||||||
#include "rawinput/device.h"
|
|
||||||
#include "external/imgui/imgui_filebrowser.h"
|
|
||||||
#include "patch_manager.h"
|
|
||||||
|
|
||||||
namespace overlay::windows {
|
|
||||||
|
|
||||||
enum class ConfigTab {
|
|
||||||
CONFIG_TAB_INVALID,
|
|
||||||
CONFIG_TAB_BUTTONS,
|
|
||||||
CONFIG_TAB_ANALOGS,
|
|
||||||
CONFIG_TAB_OVERLAY,
|
|
||||||
CONFIG_TAB_LIGHTS,
|
|
||||||
CONFIG_TAB_CARDS,
|
|
||||||
CONFIG_TAB_PATCHES,
|
|
||||||
CONFIG_TAB_API,
|
|
||||||
CONFIG_TAB_OPTIONS,
|
|
||||||
CONFIG_TAB_ADVANCED,
|
|
||||||
CONFIG_TAB_DEV,
|
|
||||||
CONFIG_TAB_SEARCH,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Config : public Window {
|
|
||||||
private:
|
|
||||||
|
|
||||||
// game selection
|
|
||||||
int games_selected = -1;
|
|
||||||
std::string games_selected_name = "";
|
|
||||||
std::vector<Game> games_list;
|
|
||||||
std::vector<const char *> games_names;
|
|
||||||
|
|
||||||
// tabs ui
|
|
||||||
ConfigTab tab_selected = ConfigTab::CONFIG_TAB_INVALID;
|
|
||||||
|
|
||||||
// buttons tab
|
|
||||||
bool buttons_keyboard_state[0xFF];
|
|
||||||
bool buttons_bind_active = false;
|
|
||||||
bool buttons_many_active = false;
|
|
||||||
std::string buttons_many_active_section = "";
|
|
||||||
bool buttons_many_naive = false;
|
|
||||||
int buttons_many_delay = 0;
|
|
||||||
int buttons_many_index = -1;
|
|
||||||
|
|
||||||
void inc_buttons_many_index(int index_max);
|
|
||||||
|
|
||||||
// analogs tab
|
|
||||||
std::vector<rawinput::Device *> analogs_devices;
|
|
||||||
int analogs_devices_selected = -1;
|
|
||||||
int analogs_devices_control_selected = -1;
|
|
||||||
|
|
||||||
// lights tab
|
|
||||||
std::vector<rawinput::Device *> lights_devices;
|
|
||||||
int lights_devices_selected = -1;
|
|
||||||
int lights_devices_control_selected = -1;
|
|
||||||
|
|
||||||
// keypads tab
|
|
||||||
int keypads_selected[2] {};
|
|
||||||
char keypads_card_path[2][1024] {};
|
|
||||||
std::thread *keypads_card_select = nullptr;
|
|
||||||
bool keypads_card_select_done = false;
|
|
||||||
ImGui::FileBrowser keypads_card_select_browser[2];
|
|
||||||
char keypads_card_number[2][18] {};
|
|
||||||
|
|
||||||
// patches tab
|
|
||||||
std::unique_ptr<PatchManager> patch_manager;
|
|
||||||
|
|
||||||
// options tab
|
|
||||||
bool options_show_hidden = false;
|
|
||||||
bool options_dirty = false;
|
|
||||||
int options_category = 0;
|
|
||||||
std::string search_filter = "";
|
|
||||||
std::string search_filter_in_lower_case = "";
|
|
||||||
|
|
||||||
void build_buttons(const std::string &name, std::vector<Button> *buttons, int min = 0, int max = -1);
|
|
||||||
void build_button(
|
|
||||||
const std::string &name,
|
|
||||||
Button &primary_button,
|
|
||||||
Button *button,
|
|
||||||
const int button_it,
|
|
||||||
const int button_it_max,
|
|
||||||
const int alt_index);
|
|
||||||
|
|
||||||
void bind_button_popup(const std::string &bind_name, Button *button, const int button_it_max, const int alt_index);
|
|
||||||
void naive_button_popup(const std::string &naive_string, Button *button, const int button_it_max, const int alt_index);
|
|
||||||
void edit_button_popup(
|
|
||||||
const std::string &edit_name,
|
|
||||||
const std::string &button_display,
|
|
||||||
Button *button,
|
|
||||||
const float button_velocity,
|
|
||||||
const int alt_index);
|
|
||||||
void clear_button(Button *button, const int alt_index);
|
|
||||||
|
|
||||||
void build_analogs(const std::string &name, std::vector<Analog> *analogs);
|
|
||||||
void edit_analog_popup(Analog &analog);
|
|
||||||
|
|
||||||
void build_lights(const std::string &name, std::vector<Light> *lights);
|
|
||||||
void build_light(Light &primary_light, Light *light, const int light_index, const int alt_index);
|
|
||||||
void clear_light(Light *light, const int alt_index);
|
|
||||||
void edit_light_popup(Light &primary_light, Light *light, const int alt_index);
|
|
||||||
|
|
||||||
void build_cards();
|
|
||||||
void build_options(
|
|
||||||
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr);
|
|
||||||
void build_about();
|
|
||||||
void build_launcher();
|
|
||||||
void launch_shell(LPCSTR app, LPCSTR file=nullptr);
|
|
||||||
|
|
||||||
void build_menu(int *game_selected);
|
|
||||||
void shutdown_system(bool force, bool reboot_instead);
|
|
||||||
|
|
||||||
void set_alternating_row_colors(const int row_index);
|
|
||||||
|
|
||||||
public:
|
|
||||||
Config(SpiceOverlay *overlay);
|
|
||||||
~Config() override;
|
|
||||||
|
|
||||||
void read_card(int player = -1);
|
|
||||||
void write_card(int player);
|
|
||||||
void build_content() override;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#include <iomanip>
|
|
||||||
#include <sstream>
|
|
||||||
#include "external/fmt/include/fmt/chrono.h"
|
|
||||||
#include "fps.h"
|
|
||||||
|
|
||||||
namespace overlay::windows {
|
|
||||||
|
|
||||||
FPS::FPS(SpiceOverlay *overlay) : Window(overlay) {
|
|
||||||
this->title = "Stats";
|
|
||||||
this->flags = ImGuiWindowFlags_NoTitleBar
|
|
||||||
| ImGuiWindowFlags_NoResize
|
|
||||||
| ImGuiWindowFlags_NoCollapse
|
|
||||||
| ImGuiWindowFlags_AlwaysAutoResize
|
|
||||||
| ImGuiWindowFlags_NoFocusOnAppearing
|
|
||||||
| ImGuiWindowFlags_NoNavFocus
|
|
||||||
| ImGuiWindowFlags_NoNavInputs
|
|
||||||
| ImGuiWindowFlags_NoDocking;
|
|
||||||
this->bg_alpha = 0.5f;
|
|
||||||
this->start_time =
|
|
||||||
std::chrono::floor<std::chrono::seconds>(std::chrono::system_clock::now());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FPS::calculate_initial_window() {
|
|
||||||
// width is 114x82 px with window decoration, 98x47 for the content
|
|
||||||
int pos_x =
|
|
||||||
overlay::FPS_SHOULD_FLIP ?
|
|
||||||
overlay::apply_scaling(8) :
|
|
||||||
ImGui::GetIO().DisplaySize.x - overlay::apply_scaling(122);
|
|
||||||
this->init_pos = ImVec2(pos_x, overlay::apply_scaling(8));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FPS::build_content() {
|
|
||||||
|
|
||||||
// frame timers
|
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
|
||||||
ImGui::Text("FPS: %.1f", io.Framerate);
|
|
||||||
// ImGui::Text("FT: %.2fms", 1000 / io.Framerate);
|
|
||||||
|
|
||||||
const auto now = std::chrono::system_clock::now();
|
|
||||||
const auto now_s = std::chrono::floor<std::chrono::seconds>(now);
|
|
||||||
|
|
||||||
// current time
|
|
||||||
{
|
|
||||||
const std::time_t tt = std::chrono::system_clock::to_time_t(now_s);
|
|
||||||
std::tm local_tm{};
|
|
||||||
localtime_s(&local_tm, &tt);
|
|
||||||
ImGui::TextUnformatted(fmt::format("Time: {:%H:%M:%S}", local_tm).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// elapsed time
|
|
||||||
{
|
|
||||||
const auto uptime = now_s - this->start_time;
|
|
||||||
ImGui::TextUnformatted(
|
|
||||||
fmt::format("Up: {:%H:%M:%S}",
|
|
||||||
std::chrono::floor<std::chrono::seconds>(uptime)).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "overlay/window.h"
|
|
||||||
#include <map>
|
|
||||||
#include <functional>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <optional>
|
|
||||||
#include "external/rapidjson/document.h"
|
|
||||||
|
|
||||||
namespace overlay::windows {
|
|
||||||
|
|
||||||
enum class PatchType {
|
|
||||||
Unknown,
|
|
||||||
Memory,
|
|
||||||
Signature,
|
|
||||||
Union,
|
|
||||||
Integer,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PatchStatus {
|
|
||||||
Error,
|
|
||||||
Disabled,
|
|
||||||
Enabled,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PatchUrlStatus {
|
|
||||||
Valid,
|
|
||||||
Invalid,
|
|
||||||
Unapplied,
|
|
||||||
ValidButNoData,
|
|
||||||
Partial,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MemoryPatch {
|
|
||||||
std::string dll_name = "";
|
|
||||||
std::shared_ptr<uint8_t[]> data_disabled = nullptr;
|
|
||||||
size_t data_disabled_len = 0;
|
|
||||||
std::shared_ptr<uint8_t[]> data_enabled = nullptr;
|
|
||||||
size_t data_enabled_len = 0;
|
|
||||||
uint64_t data_offset = 0;
|
|
||||||
uint8_t *data_offset_ptr = nullptr;
|
|
||||||
bool fatal_error = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PatchData;
|
|
||||||
struct SignaturePatch {
|
|
||||||
std::string dll_name = "";
|
|
||||||
std::string signature = "", replacement = "";
|
|
||||||
uint64_t offset = 0;
|
|
||||||
int64_t usage = 0;
|
|
||||||
|
|
||||||
MemoryPatch to_memory(PatchData *patch);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UnionPatch {
|
|
||||||
std::string name = "";
|
|
||||||
std::string dll_name = "";
|
|
||||||
std::shared_ptr<uint8_t[]> data = nullptr;
|
|
||||||
size_t data_len = 0;
|
|
||||||
uint64_t offset = 0;
|
|
||||||
uint8_t* data_offset_ptr = nullptr;
|
|
||||||
bool fatal_error = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NumberPatch {
|
|
||||||
std::string dll_name = "";
|
|
||||||
uint64_t data_offset = 0;
|
|
||||||
uint8_t* data_offset_ptr = nullptr;
|
|
||||||
int32_t min;
|
|
||||||
int32_t max;
|
|
||||||
int32_t value;
|
|
||||||
size_t size_in_bytes;
|
|
||||||
bool fatal_error = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PatchData {
|
|
||||||
bool enabled;
|
|
||||||
std::string game_code;
|
|
||||||
int datecode_min = 0;
|
|
||||||
int datecode_max = 0;
|
|
||||||
std::string name, description, caution;
|
|
||||||
std::string name_in_lower_case = "";
|
|
||||||
PatchType type;
|
|
||||||
bool preset;
|
|
||||||
std::vector<MemoryPatch> patches_memory;
|
|
||||||
std::vector<UnionPatch> patches_union;
|
|
||||||
NumberPatch patch_number;
|
|
||||||
PatchStatus last_status;
|
|
||||||
std::string hash;
|
|
||||||
bool unverified = false;
|
|
||||||
std::string peIdentifier;
|
|
||||||
std::string error_reason = "";
|
|
||||||
|
|
||||||
// for union patch only
|
|
||||||
std::string selected_union_name = "";
|
|
||||||
};
|
|
||||||
|
|
||||||
extern std::optional<std::string> PATCH_MANAGER_CFG_PATH_OVERRIDE;
|
|
||||||
|
|
||||||
std::string get_game_identifier(const std::filesystem::path& dll_path, bool print_info=false);
|
|
||||||
|
|
||||||
class PatchManager : public Window {
|
|
||||||
public:
|
|
||||||
|
|
||||||
PatchManager(SpiceOverlay *overlay, bool apply_patches = false);
|
|
||||||
~PatchManager() override;
|
|
||||||
|
|
||||||
void build_content() override;
|
|
||||||
void reload_local_patches(bool apply_patches = false);
|
|
||||||
bool import_remote_patches_to_disk();
|
|
||||||
bool load_from_patches_json(bool apply_patches);
|
|
||||||
bool import_remote_patches_for_dll(const std::string& url, const std::string& dll_name);
|
|
||||||
void hard_apply_patches();
|
|
||||||
void load_embedded_patches(bool apply_patches);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// configuration
|
|
||||||
static std::filesystem::path config_path;
|
|
||||||
static bool config_dirty;
|
|
||||||
static bool setting_auto_apply;
|
|
||||||
static std::vector<std::string> setting_auto_apply_list;
|
|
||||||
static std::vector<std::string> setting_patches_enabled;
|
|
||||||
static std::map<std::string, std::string> setting_union_patches_enabled;
|
|
||||||
static std::map<std::string, int64_t> setting_int_patches_enabled;
|
|
||||||
static std::string patch_url;
|
|
||||||
static std::string patch_name_filter;
|
|
||||||
|
|
||||||
static std::filesystem::path LOCAL_PATCHES_PATH;
|
|
||||||
static std::string ACTIVE_JSON_FILE;
|
|
||||||
|
|
||||||
// patches
|
|
||||||
static std::vector<PatchData> patches;
|
|
||||||
static bool local_patches_initialized;
|
|
||||||
|
|
||||||
void config_load();
|
|
||||||
void config_save();
|
|
||||||
|
|
||||||
void append_patches(
|
|
||||||
std::string &patches_json,
|
|
||||||
bool apply_patches = false,
|
|
||||||
std::function<bool(const PatchData&)> filter = std::function<bool(const PatchData&)>(),
|
|
||||||
std::string pe_identifier_for_patch = "");
|
|
||||||
|
|
||||||
void show_patch_tooltip(const PatchData& patch);
|
|
||||||
|
|
||||||
bool is_game_id_wildcard_matched(const std::string& id_from_config);
|
|
||||||
};
|
|
||||||
|
|
||||||
PatchStatus is_patch_active(PatchData &patch);
|
|
||||||
bool apply_patch(PatchData &patch, bool active);
|
|
||||||
|
|
||||||
int64_t parse_little_endian_int(uint8_t* bytes, size_t size);
|
|
||||||
void int_to_little_endian_bytes(int64_t value, uint8_t* bytes, size_t size);
|
|
||||||
|
|
||||||
std::vector<uint8_t>* find_in_dll_map(
|
|
||||||
const std::string& dll_name, size_t offset, size_t size);
|
|
||||||
std::vector<uint8_t>* find_in_dll_map_org(
|
|
||||||
const std::string& dll_name, size_t offset, size_t size);
|
|
||||||
|
|
||||||
bool restore_bytes_from_dll_map_org(
|
|
||||||
uint8_t* destination, const std::string& dll_name, size_t offset, size_t size);
|
|
||||||
|
|
||||||
void create_dll_backup(
|
|
||||||
std::vector<std::string>& written_list, const std::filesystem::path& dll_path);
|
|
||||||
std::string fix_up_dll_name(const std::string& dll_name);
|
|
||||||
uint8_t* get_dll_offset_for_patch_apply(
|
|
||||||
const std::string& dll_name, const uint64_t data_offset, const size_t size_in_bytes);
|
|
||||||
|
|
||||||
uint64_t parse_json_data_offset(
|
|
||||||
const std::string &patch_name, const rapidjson::Value &value);
|
|
||||||
|
|
||||||
void print_auto_apply_status(PatchData &patch);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
> [!NOTE]
|
||||||
|
> Before submitting code changes...
|
||||||
|
> * Please do note that this is a GPL v3.0 open source project.
|
||||||
|
> * Please read the [CONTRIBUTING](https://github.com/spice2x/spice2x.github.io/blob/main/CONTRIBUTING.md) guide.
|
||||||
|
> * Maintainers reserve the right to reject or modify your submission without reason.
|
||||||
|
> * No new compiler warnings must be introduced. Check the CI build results.
|
||||||
|
>
|
||||||
|
> Feel free to remove this section after you have read it.
|
||||||
|
|
||||||
|
## Link to GitHub Issue or related Pull Request, if one exists
|
||||||
|
#0
|
||||||
|
|
||||||
|
## Description of change
|
||||||
|
*what does this code do?*
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
*how was the code tested?*
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "device.h"
|
|
||||||
#include "rawinput.h"
|
|
||||||
|
|
||||||
namespace rawinput::touch {
|
|
||||||
|
|
||||||
// settings
|
|
||||||
extern bool DISABLED;
|
|
||||||
extern bool INVERTED;
|
|
||||||
|
|
||||||
bool is_touchscreen(Device *device);
|
|
||||||
void enable(Device *device);
|
|
||||||
void disable(Device *device);
|
|
||||||
void update_input(Device *device);
|
|
||||||
void update_timeouts(Device *device);
|
|
||||||
void update_timeouts(RawInputManager *manager);
|
|
||||||
bool is_enabled(RawInputManager *manager);
|
|
||||||
void display_update();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
.vscode/*
|
||||||
|
|
||||||
|
# JetBrains IDEs
|
||||||
|
.idea
|
||||||
|
.idea_modules
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build*
|
||||||
|
|
||||||
|
# user config
|
||||||
|
build_all.local.sh
|
||||||
|
build_docker.local.sh
|
||||||
|
|
||||||
|
# output from build script
|
||||||
|
bin/*
|
||||||
|
dist/*
|
||||||
|
|
||||||
|
external/cv2pdb/*
|
||||||
|
|
||||||
|
.ccache/*
|
||||||
|
|
||||||
|
# Visual Studio
|
||||||
|
.vs
|
||||||
|
out
|
||||||
|
CMakeSettings.json
|
||||||
@@ -109,6 +109,12 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|||||||
# RapidJSON does this
|
# RapidJSON does this
|
||||||
add_compile_definitions(_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING)
|
add_compile_definitions(_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING)
|
||||||
|
|
||||||
|
add_compile_options("-Wno-nontrivial-memcall") # imgui, rapidjson
|
||||||
|
add_compile_options("-Wno-deprecated-builtins") # robin_hood
|
||||||
|
add_compile_options("-Wno-deprecated-declarations") # rapidjson
|
||||||
|
add_compile_options("-Wno-inconsistent-missing-override") # headsocket
|
||||||
|
add_compile_options("-Wno-microsoft-exception-spec") # gcc/clang have different noexcept specifiers on d3d9 COM interfaces
|
||||||
|
|
||||||
# warnings
|
# warnings
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunknown-warning-option")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunknown-warning-option")
|
||||||
|
|
||||||
@@ -227,6 +233,13 @@ add_compile_definitions(
|
|||||||
_WIN32_IE=0x0400
|
_WIN32_IE=0x0400
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# SPICE_XP: set by build_all.sh for the WinXP-compat toolchains. Gates out
|
||||||
|
# the DX11 overlay backend
|
||||||
|
option(SPICE_XP "Build for the WinXP-compat toolchain" OFF)
|
||||||
|
if(SPICE_XP)
|
||||||
|
add_compile_definitions(SPICE_XP=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
# acioemu log
|
# acioemu log
|
||||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DACIOEMU_LOG")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DACIOEMU_LOG")
|
||||||
|
|
||||||
@@ -239,8 +252,60 @@ add_subdirectory(external/discord-rpc EXCLUDE_FROM_ALL)
|
|||||||
add_subdirectory(external/hash-library EXCLUDE_FROM_ALL)
|
add_subdirectory(external/hash-library EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(external/imgui EXCLUDE_FROM_ALL)
|
add_subdirectory(external/imgui EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(external/minhook EXCLUDE_FROM_ALL)
|
add_subdirectory(external/minhook EXCLUDE_FROM_ALL)
|
||||||
|
add_subdirectory(external/wslay EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(external/cpu_features EXCLUDE_FROM_ALL)
|
add_subdirectory(external/cpu_features EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
# libjpeg-turbo, prebuilt into the deps image. The WinXP toolchains have their own
|
||||||
|
# sysroot and cannot see it, so those targets build without JPEG support.
|
||||||
|
add_library(spice_jpeg INTERFACE)
|
||||||
|
if(NOT SPICE_XP)
|
||||||
|
# search static archives only: the mingw package also ships an import library,
|
||||||
|
# and linking that one would pull in a libjpeg DLL at runtime
|
||||||
|
set(SPICE_JPEG_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||||
|
find_package(JPEG)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ${SPICE_JPEG_SUFFIXES})
|
||||||
|
|
||||||
|
if(JPEG_FOUND)
|
||||||
|
target_link_libraries(spice_jpeg INTERFACE JPEG::JPEG)
|
||||||
|
target_compile_definitions(spice_jpeg INTERFACE SPICE_JPEG=1)
|
||||||
|
else()
|
||||||
|
message(WARNING
|
||||||
|
"libjpeg-turbo not found: screen capture over the API is disabled")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# x264 for the API H.264 video stream, installed into the mingw sysroots by the
|
||||||
|
# deps image. The WinXP toolchains deliberately go without it and serve MJPEG only.
|
||||||
|
add_library(spice_x264 INTERFACE)
|
||||||
|
if(NOT SPICE_XP)
|
||||||
|
# search static archives only: the mingw package also ships an import library,
|
||||||
|
# and linking that one would pull in a libx264 DLL at runtime
|
||||||
|
set(SPICE_X264_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||||
|
find_library(X264_LIBRARY NAMES x264 libx264)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ${SPICE_X264_SUFFIXES})
|
||||||
|
|
||||||
|
find_path(X264_INCLUDE_DIR NAMES x264.h)
|
||||||
|
if(X264_LIBRARY AND X264_INCLUDE_DIR)
|
||||||
|
target_include_directories(spice_x264 INTERFACE "${X264_INCLUDE_DIR}")
|
||||||
|
target_link_libraries(spice_x264 INTERFACE "${X264_LIBRARY}")
|
||||||
|
target_compile_definitions(spice_x264 INTERFACE SPICE_H264=1)
|
||||||
|
else()
|
||||||
|
message(WARNING
|
||||||
|
"x264 not found: the api video stream will only offer MJPEG")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# fpng's SIMD needs the whole unit built for SSE4.1, which its runtime CPU check
|
||||||
|
# cannot undo, so keep it scalar rather than raising the CPU baseline
|
||||||
|
set_source_files_properties(external/fpng/fpng.cpp PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS "FPNG_NO_SSE=1")
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_source_files_properties(external/fpng/fpng.cpp PROPERTIES
|
||||||
|
COMPILE_OPTIONS "-fno-strict-aliasing")
|
||||||
|
endif()
|
||||||
|
|
||||||
# set link time optimizations (disabled for Debug builds for speed, disabled
|
# set link time optimizations (disabled for Debug builds for speed, disabled
|
||||||
# for RelWithDebInfo builds due to "lto1: error: two or more sections for"
|
# for RelWithDebInfo builds due to "lto1: error: two or more sections for"
|
||||||
# errors)
|
# errors)
|
||||||
@@ -259,6 +324,7 @@ set_source_files_properties(cfg/icon.rc PROPERTIES LANGUAGE RC)
|
|||||||
set_source_files_properties(cfg/Win32D.rc PROPERTIES LANGUAGE RC)
|
set_source_files_properties(cfg/Win32D.rc PROPERTIES LANGUAGE RC)
|
||||||
set_source_files_properties(build/manifest64.rc PROPERTIES LANGUAGE RC)
|
set_source_files_properties(build/manifest64.rc PROPERTIES LANGUAGE RC)
|
||||||
set_source_files_properties(build/blob.rc PROPERTIES LANGUAGE RC)
|
set_source_files_properties(build/blob.rc PROPERTIES LANGUAGE RC)
|
||||||
|
set_source_files_properties(stubs/manifest.rc PROPERTIES LANGUAGE RC)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT build/dsdmo.i686.dll
|
OUTPUT build/dsdmo.i686.dll
|
||||||
COMMAND sh -c "wget -qO- 'https://web.archive.org/web/20260212204718if_/https://download.zip.dll-files.com/d01cab97ad497201c4ad99eb6e4182b3/dsdmo.zip?token=f7cVie5KOSz-hnFUYC37Ow&expires=1770974229' | bsdtar -xvf - -C '${CMAKE_SOURCE_DIR}/build' -s '/dsdmo.dll/dsdmo.i686.dll/' dsdmo.dll"
|
COMMAND sh -c "wget -qO- 'https://web.archive.org/web/20260212204718if_/https://download.zip.dll-files.com/d01cab97ad497201c4ad99eb6e4182b3/dsdmo.zip?token=f7cVie5KOSz-hnFUYC37Ow&expires=1770974229' | bsdtar -xvf - -C '${CMAKE_SOURCE_DIR}/build' -s '/dsdmo.dll/dsdmo.i686.dll/' dsdmo.dll"
|
||||||
@@ -314,6 +380,10 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
# api
|
# api
|
||||||
api/controller.cpp
|
api/controller.cpp
|
||||||
api/websocket.cpp
|
api/websocket.cpp
|
||||||
|
api/capture_pump.cpp
|
||||||
|
api/h264_stream.cpp
|
||||||
|
api/stream_format.cpp
|
||||||
|
api/stream_server.cpp
|
||||||
api/request.cpp
|
api/request.cpp
|
||||||
api/response.cpp
|
api/response.cpp
|
||||||
api/module.cpp
|
api/module.cpp
|
||||||
@@ -329,6 +399,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
api/modules/control.cpp
|
api/modules/control.cpp
|
||||||
api/modules/touch.cpp
|
api/modules/touch.cpp
|
||||||
api/modules/iidx.cpp
|
api/modules/iidx.cpp
|
||||||
|
api/modules/sdvx.cpp
|
||||||
api/serial.cpp
|
api/serial.cpp
|
||||||
api/modules/drs.cpp
|
api/modules/drs.cpp
|
||||||
api/modules/lcd.cpp
|
api/modules/lcd.cpp
|
||||||
@@ -357,6 +428,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
cfg/configurator.cpp
|
cfg/configurator.cpp
|
||||||
cfg/configurator_wnd.cpp
|
cfg/configurator_wnd.cpp
|
||||||
cfg/screen_resize.cpp
|
cfg/screen_resize.cpp
|
||||||
|
cfg/controller_presets.cpp
|
||||||
|
|
||||||
# easrv
|
# easrv
|
||||||
easrv/easrv.cpp
|
easrv/easrv.cpp
|
||||||
@@ -375,7 +447,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
external/tinyxml2/tinyxml2.cpp
|
external/tinyxml2/tinyxml2.cpp
|
||||||
external/http-parser/http_parser.c
|
external/http-parser/http_parser.c
|
||||||
external/usbhidusage/usb-hid-usage.c
|
external/usbhidusage/usb-hid-usage.c
|
||||||
external/toojpeg/toojpeg.cpp
|
external/fpng/fpng.cpp
|
||||||
external/scard/scard.cpp
|
external/scard/scard.cpp
|
||||||
|
|
||||||
# games
|
# games
|
||||||
@@ -386,6 +458,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/shared/twtouch.cpp
|
games/shared/twtouch.cpp
|
||||||
games/popn/popn.cpp
|
games/popn/popn.cpp
|
||||||
games/popn/io.cpp
|
games/popn/io.cpp
|
||||||
|
games/popn/bi3a_hook.cpp
|
||||||
games/bbc/bbc.cpp
|
games/bbc/bbc.cpp
|
||||||
games/bbc/io.cpp
|
games/bbc/io.cpp
|
||||||
games/hpm/hpm.cpp
|
games/hpm/hpm.cpp
|
||||||
@@ -403,14 +476,19 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/iidx/mf_wrappers.cpp
|
games/iidx/mf_wrappers.cpp
|
||||||
games/sdvx/bi2x_hook.cpp
|
games/sdvx/bi2x_hook.cpp
|
||||||
games/sdvx/sdvx.cpp
|
games/sdvx/sdvx.cpp
|
||||||
|
games/sdvx/sdvx_live2d.cpp
|
||||||
games/sdvx/io.cpp
|
games/sdvx/io.cpp
|
||||||
games/sdvx/camera.cpp
|
games/sdvx/camera.cpp
|
||||||
|
games/jb/bi2x_hook.cpp
|
||||||
games/jb/jb.cpp
|
games/jb/jb.cpp
|
||||||
|
games/jb/jb_touch.cpp
|
||||||
games/jb/io.cpp
|
games/jb/io.cpp
|
||||||
games/nost/nost.cpp
|
games/nost/nost.cpp
|
||||||
games/nost/io.cpp
|
games/nost/io.cpp
|
||||||
games/nost/poke.cpp
|
games/nost/poke.cpp
|
||||||
|
games/nost/touch_mode.cpp
|
||||||
games/gitadora/gitadora.cpp
|
games/gitadora/gitadora.cpp
|
||||||
|
games/gitadora/asio.cpp
|
||||||
games/gitadora/io.cpp
|
games/gitadora/io.cpp
|
||||||
games/gitadora/handle.cpp
|
games/gitadora/handle.cpp
|
||||||
games/gitadora/j32d.cpp
|
games/gitadora/j32d.cpp
|
||||||
@@ -424,6 +502,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/rb/rb.cpp
|
games/rb/rb.cpp
|
||||||
games/rb/io.cpp
|
games/rb/io.cpp
|
||||||
games/rb/touch.cpp
|
games/rb/touch.cpp
|
||||||
|
games/rb/touch_debug.cpp
|
||||||
games/bs/bs.cpp
|
games/bs/bs.cpp
|
||||||
games/bs/io.cpp
|
games/bs/io.cpp
|
||||||
games/rf3d/rf3d.cpp
|
games/rf3d/rf3d.cpp
|
||||||
@@ -452,6 +531,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/scotto/io.cpp
|
games/scotto/io.cpp
|
||||||
games/drs/drs.cpp
|
games/drs/drs.cpp
|
||||||
games/drs/io.cpp
|
games/drs/io.cpp
|
||||||
|
games/drs/motion_cam.cpp
|
||||||
games/drs/rgb_cam.cpp
|
games/drs/rgb_cam.cpp
|
||||||
games/we/we.cpp
|
games/we/we.cpp
|
||||||
games/we/io.cpp
|
games/we/io.cpp
|
||||||
@@ -463,6 +543,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/otoca/p4io.cpp
|
games/otoca/p4io.cpp
|
||||||
games/silentscope/silentscope.cpp
|
games/silentscope/silentscope.cpp
|
||||||
games/silentscope/io.cpp
|
games/silentscope/io.cpp
|
||||||
|
games/silentscope/projector.cpp
|
||||||
games/pcm/pcm.cpp
|
games/pcm/pcm.cpp
|
||||||
games/pcm/io.cpp
|
games/pcm/io.cpp
|
||||||
games/onpara/onpara.cpp
|
games/onpara/onpara.cpp
|
||||||
@@ -488,16 +569,24 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
# hooks
|
# hooks
|
||||||
hooks/audio/acm.cpp
|
hooks/audio/acm.cpp
|
||||||
hooks/audio/audio.cpp
|
hooks/audio/audio.cpp
|
||||||
|
hooks/audio/asio_driver_scan.cpp
|
||||||
|
hooks/audio/asio_proxy.cpp
|
||||||
hooks/audio/buffer.cpp
|
hooks/audio/buffer.cpp
|
||||||
hooks/audio/mme.cpp
|
hooks/audio/mme.cpp
|
||||||
hooks/audio/util.cpp
|
hooks/audio/util.cpp
|
||||||
|
hooks/audio/xact.cpp
|
||||||
hooks/audio/backends/dsound/dsound_backend.cpp
|
hooks/audio/backends/dsound/dsound_backend.cpp
|
||||||
hooks/audio/backends/mmdevice/audio_endpoint_volume.cpp
|
hooks/audio/backends/mmdevice/audio_endpoint_volume.cpp
|
||||||
hooks/audio/backends/mmdevice/device.cpp
|
hooks/audio/backends/mmdevice/device.cpp
|
||||||
hooks/audio/backends/mmdevice/device_collection.cpp
|
hooks/audio/backends/mmdevice/device_collection.cpp
|
||||||
hooks/audio/backends/mmdevice/device_enumerator.cpp
|
hooks/audio/backends/mmdevice/device_enumerator.cpp
|
||||||
|
hooks/audio/backends/mmdevice/null_device.cpp
|
||||||
|
hooks/audio/backends/mmdevice/null_discard_backend.cpp
|
||||||
hooks/audio/backends/wasapi/audio_client.cpp
|
hooks/audio/backends/wasapi/audio_client.cpp
|
||||||
hooks/audio/backends/wasapi/audio_render_client.cpp
|
hooks/audio/backends/wasapi/audio_render_client.cpp
|
||||||
|
hooks/audio/backends/wasapi/downmix.cpp
|
||||||
|
hooks/audio/backends/wasapi/resample.cpp
|
||||||
|
hooks/audio/backends/wasapi/shared.cpp
|
||||||
hooks/audio/backends/wasapi/dummy_audio_client.cpp
|
hooks/audio/backends/wasapi/dummy_audio_client.cpp
|
||||||
hooks/audio/backends/wasapi/dummy_audio_clock.cpp
|
hooks/audio/backends/wasapi/dummy_audio_clock.cpp
|
||||||
hooks/audio/backends/wasapi/dummy_audio_render_client.cpp
|
hooks/audio/backends/wasapi/dummy_audio_render_client.cpp
|
||||||
@@ -517,19 +606,32 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
hooks/devicehook.cpp
|
hooks/devicehook.cpp
|
||||||
hooks/graphics/graphics.cpp
|
hooks/graphics/graphics.cpp
|
||||||
hooks/graphics/graphics_windowed.cpp
|
hooks/graphics/graphics_windowed.cpp
|
||||||
|
hooks/graphics/jpeg_encoder.cpp
|
||||||
|
hooks/graphics/nvapi_impl.cpp
|
||||||
hooks/graphics/nvapi_hook.cpp
|
hooks/graphics/nvapi_hook.cpp
|
||||||
hooks/graphics/nvenc_hook.cpp
|
hooks/graphics/nvenc_hook.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_backend.cpp
|
hooks/graphics/backends/d3d9/d3d9_backend.cpp
|
||||||
|
hooks/graphics/backends/d3d9/d3d9_readback.cpp
|
||||||
|
hooks/graphics/backends/d3d9/d3d9_screenshot.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_device.cpp
|
hooks/graphics/backends/d3d9/d3d9_device.cpp
|
||||||
|
hooks/graphics/backends/d3d9/d3d9_gfdm.cpp
|
||||||
|
hooks/graphics/backends/d3d9/d3d9_live2d.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_fake_swapchain.cpp
|
hooks/graphics/backends/d3d9/d3d9_fake_swapchain.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_swapchain.cpp
|
hooks/graphics/backends/d3d9/d3d9_swapchain.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_texture.cpp
|
hooks/graphics/backends/d3d9/d3d9_texture.cpp
|
||||||
|
hooks/graphics/backends/d3d11/d3d11_backend.cpp
|
||||||
|
hooks/graphics/backends/d3d11/d3d11_swapchain.cpp
|
||||||
|
hooks/graphics/backends/d3d11/d3d11_factory.cpp
|
||||||
|
hooks/graphics/backends/d3d11/d3d11_vtable_capture.cpp
|
||||||
|
hooks/graphics/backends/d3d11/d3d11_screenshot.cpp
|
||||||
hooks/input/dinput8/fake_backend.cpp
|
hooks/input/dinput8/fake_backend.cpp
|
||||||
hooks/input/dinput8/fake_device.cpp
|
hooks/input/dinput8/fake_device.cpp
|
||||||
hooks/input/dinput8/hook.cpp
|
hooks/input/dinput8/hook.cpp
|
||||||
hooks/lang.cpp
|
hooks/lang.cpp
|
||||||
hooks/libraryhook.cpp
|
hooks/libraryhook.cpp
|
||||||
hooks/networkhook.cpp
|
hooks/networkhook.cpp
|
||||||
|
hooks/icmphook_net.cpp
|
||||||
|
hooks/icmphook_iphlpapi.cpp
|
||||||
hooks/powrprof.cpp
|
hooks/powrprof.cpp
|
||||||
#hooks/rom.cpp
|
#hooks/rom.cpp
|
||||||
hooks/setupapihook.cpp
|
hooks/setupapihook.cpp
|
||||||
@@ -552,7 +654,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
misc/device.cpp
|
misc/device.cpp
|
||||||
misc/eamuse.cpp
|
misc/eamuse.cpp
|
||||||
misc/extdev.cpp
|
misc/extdev.cpp
|
||||||
misc/nativetouchhook.cpp
|
misc/hotkeys.cpp
|
||||||
misc/sciunit.cpp
|
misc/sciunit.cpp
|
||||||
misc/sde.cpp
|
misc/sde.cpp
|
||||||
misc/wintouchemu.cpp
|
misc/wintouchemu.cpp
|
||||||
@@ -563,6 +665,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
|
|
||||||
# overlay
|
# overlay
|
||||||
overlay/overlay.cpp
|
overlay/overlay.cpp
|
||||||
|
overlay/notifications.cpp
|
||||||
overlay/window.cpp
|
overlay/window.cpp
|
||||||
overlay/imgui/extensions.cpp
|
overlay/imgui/extensions.cpp
|
||||||
overlay/imgui/impl_spice.cpp
|
overlay/imgui/impl_spice.cpp
|
||||||
@@ -575,6 +678,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
overlay/windows/screen_resize.cpp
|
overlay/windows/screen_resize.cpp
|
||||||
overlay/windows/sdvx_sub.cpp
|
overlay/windows/sdvx_sub.cpp
|
||||||
overlay/windows/config.cpp
|
overlay/windows/config.cpp
|
||||||
|
overlay/windows/controller_presets.cpp
|
||||||
overlay/windows/control.cpp
|
overlay/windows/control.cpp
|
||||||
overlay/windows/eadev.cpp
|
overlay/windows/eadev.cpp
|
||||||
overlay/windows/fps.cpp
|
overlay/windows/fps.cpp
|
||||||
@@ -588,11 +692,27 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
overlay/windows/keypad.cpp
|
overlay/windows/keypad.cpp
|
||||||
overlay/windows/log.cpp
|
overlay/windows/log.cpp
|
||||||
overlay/windows/midi.cpp
|
overlay/windows/midi.cpp
|
||||||
|
overlay/windows/nostalgia_touch_piano.cpp
|
||||||
|
overlay/windows/obs.cpp
|
||||||
|
overlay/windows/obs_websocket.cpp
|
||||||
overlay/windows/patch_manager.cpp
|
overlay/windows/patch_manager.cpp
|
||||||
|
overlay/windows/popn_sub.cpp
|
||||||
overlay/windows/wnd_manager.cpp
|
overlay/windows/wnd_manager.cpp
|
||||||
|
|
||||||
|
# patcher
|
||||||
|
patcher/config.cpp
|
||||||
|
patcher/lifecycle.cpp
|
||||||
|
patcher/loader.cpp
|
||||||
|
patcher/loader_group.cpp
|
||||||
|
patcher/runtime.cpp
|
||||||
|
|
||||||
|
# external
|
||||||
|
external/easywsclient/easywsclient.cpp
|
||||||
|
|
||||||
# rawinput
|
# rawinput
|
||||||
rawinput/rawinput.cpp
|
rawinput/rawinput.cpp
|
||||||
|
rawinput/rawinput_handles.cpp
|
||||||
|
rawinput/midi.cpp
|
||||||
rawinput/sextet.cpp
|
rawinput/sextet.cpp
|
||||||
rawinput/piuio.cpp
|
rawinput/piuio.cpp
|
||||||
rawinput/touch.cpp
|
rawinput/touch.cpp
|
||||||
@@ -603,6 +723,8 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
rawinput/smxstage.h
|
rawinput/smxstage.h
|
||||||
rawinput/smxdedicab.cpp
|
rawinput/smxdedicab.cpp
|
||||||
rawinput/smxdedicab.h
|
rawinput/smxdedicab.h
|
||||||
|
rawinput/xinput.cpp
|
||||||
|
rawinput/xinput.h
|
||||||
|
|
||||||
# reader
|
# reader
|
||||||
reader/reader.cpp
|
reader/reader.cpp
|
||||||
@@ -610,12 +732,21 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
reader/structuredmessage.cpp
|
reader/structuredmessage.cpp
|
||||||
reader/crypt.cpp
|
reader/crypt.cpp
|
||||||
|
|
||||||
|
# sdk
|
||||||
|
sdk/sdk.cpp
|
||||||
|
|
||||||
# stubs
|
# stubs
|
||||||
stubs/stubs.cpp
|
stubs/stubs.cpp
|
||||||
|
|
||||||
# touch
|
# touch
|
||||||
|
touch/gdi_overlay.cpp
|
||||||
|
touch/native/inject.cpp
|
||||||
|
touch/native/inject_mouse.cpp
|
||||||
|
touch/native/inject_synthetic.cpp
|
||||||
|
touch/native/nativetouchhook.cpp
|
||||||
|
touch/native/transform.cpp
|
||||||
touch/touch.cpp
|
touch/touch.cpp
|
||||||
touch/touch_indicators.cpp
|
touch/touch_gestures.cpp
|
||||||
touch/win7.cpp
|
touch/win7.cpp
|
||||||
touch/win8.cpp
|
touch/win8.cpp
|
||||||
|
|
||||||
@@ -636,6 +767,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
util/time.cpp
|
util/time.cpp
|
||||||
util/cpuutils.cpp
|
util/cpuutils.cpp
|
||||||
util/netutils.cpp
|
util/netutils.cpp
|
||||||
|
util/precise_timer.cpp
|
||||||
util/sysutils.cpp
|
util/sysutils.cpp
|
||||||
util/lz77.cpp
|
util/lz77.cpp
|
||||||
util/tapeled.cpp
|
util/tapeled.cpp
|
||||||
@@ -647,35 +779,74 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
|
|
||||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES})
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES})
|
||||||
|
|
||||||
|
# guard against statically importing DLLs that must always be loaded dynamically:
|
||||||
|
# * DLLs users override via the modules directory (e.g. DXVK's d3d9.dll) - a
|
||||||
|
# static import loads the system copy at startup and preempts the override
|
||||||
|
# (issue #779).
|
||||||
|
# * Media Foundation DLLs (mf/mfplat/mfreadwrite) - a static import breaks
|
||||||
|
# Unity games.
|
||||||
|
# the check runs objdump on each produced binary and fails the build if any
|
||||||
|
# forbidden DLL is imported.
|
||||||
|
set(SPICE_FORBIDDEN_STATIC_IMPORTS
|
||||||
|
d3d8.dll d3d9.dll d3d10core.dll d3d11.dll dxgi.dll opengl32.dll
|
||||||
|
mf.dll mfplat.dll mfreadwrite.dll)
|
||||||
|
|
||||||
|
function(spice_guard_dll_imports target)
|
||||||
|
if(MSVC)
|
||||||
|
# objdump-based parsing assumes a GNU/LLVM toolchain
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
add_custom_command(TARGET ${target} POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-DOBJDUMP=${CMAKE_OBJDUMP}
|
||||||
|
-DTARGET_FILE=$<TARGET_FILE:${target}>
|
||||||
|
"-DFORBIDDEN=${SPICE_FORBIDDEN_STATIC_IMPORTS}"
|
||||||
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_no_static_dll_imports.cmake
|
||||||
|
VERBATIM
|
||||||
|
COMMENT "Checking ${target} for forbidden static DLL imports")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# spice.exe / spice_laa.exe shared objects
|
||||||
|
###########################################
|
||||||
|
# spice.exe and spice_laa.exe are compiled identically; the only difference is
|
||||||
|
# the large-address-aware bit, which is set at link time. Compile the sources
|
||||||
|
# once into a shared OBJECT library so spice_laa.exe only costs an extra link
|
||||||
|
# instead of a full recompile.
|
||||||
|
|
||||||
|
add_library(spicetools_spice_objs OBJECT ${SOURCE_FILES})
|
||||||
|
target_link_libraries(spicetools_spice_objs
|
||||||
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
||||||
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook wslay imm32 dwmapi CpuFeatures::cpu_features spice_jpeg spice_x264)
|
||||||
|
target_link_libraries(spicetools_spice_objs PUBLIC winscard)
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_spice_objs PROPERTIES COMPILE_FLAGS "-m32")
|
||||||
|
endif()
|
||||||
|
|
||||||
# spice.exe
|
# spice.exe
|
||||||
###########
|
###########
|
||||||
|
|
||||||
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc build/blob.rc build/dsdmo.i686.dll)
|
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc build/blob.rc build/dsdmo.i686.dll)
|
||||||
add_executable(spicetools_spice ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_spice ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_spice
|
target_link_libraries(spicetools_spice PRIVATE spicetools_spice_objs)
|
||||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
|
||||||
set_target_properties(spicetools_spice PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_spice PROPERTIES OUTPUT_NAME "spice")
|
set_target_properties(spicetools_spice PROPERTIES OUTPUT_NAME "spice")
|
||||||
|
|
||||||
IF(NOT MSVC)
|
IF(NOT MSVC)
|
||||||
set_target_properties(spicetools_spice PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
set_target_properties(spicetools_spice PROPERTIES LINK_FLAGS "-m32")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# spice_laa.exe
|
# spice_laa.exe
|
||||||
###########
|
###########
|
||||||
|
|
||||||
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc build/blob.rc build/dsdmo.i686.dll)
|
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc build/blob.rc build/dsdmo.i686.dll)
|
||||||
add_executable(spicetools_spice_laa ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_spice_laa ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_spice_laa
|
target_link_libraries(spicetools_spice_laa PRIVATE spicetools_spice_objs)
|
||||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
|
||||||
set_target_properties(spicetools_spice_laa PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice_laa PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_spice_laa PROPERTIES OUTPUT_NAME "spice_laa")
|
set_target_properties(spicetools_spice_laa PROPERTIES OUTPUT_NAME "spice_laa")
|
||||||
target_compile_definitions(spicetools_spice_laa PRIVATE SPICE32_LARGE_ADDRESS_AWARE=1)
|
|
||||||
|
|
||||||
IF(NOT MSVC)
|
IF(NOT MSVC)
|
||||||
set_target_properties(spicetools_spice_laa PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -Wl,--large-address-aware")
|
set_target_properties(spicetools_spice_laa PROPERTIES LINK_FLAGS "-m32 -Wl,--large-address-aware")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# spice_linux.exe
|
# spice_linux.exe
|
||||||
@@ -685,7 +856,7 @@ set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/W
|
|||||||
add_executable(spicetools_spice_linux ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_spice_linux ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_spice_linux
|
target_link_libraries(spicetools_spice_linux
|
||||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook wslay imm32 dwmapi CpuFeatures::cpu_features spice_jpeg spice_x264)
|
||||||
set_target_properties(spicetools_spice_linux PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice_linux PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_spice_linux PROPERTIES OUTPUT_NAME "spice_linux")
|
set_target_properties(spicetools_spice_linux PROPERTIES OUTPUT_NAME "spice_linux")
|
||||||
target_compile_definitions(spicetools_spice_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
|
target_compile_definitions(spicetools_spice_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
|
||||||
@@ -703,11 +874,15 @@ add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES})
|
|||||||
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
||||||
target_link_libraries(spicetools_spice64
|
target_link_libraries(spicetools_spice64
|
||||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook wslay imm32 dwmapi CpuFeatures::cpu_features spice_jpeg spice_x264)
|
||||||
|
target_link_libraries(spicetools_spice64 PUBLIC winscard)
|
||||||
set_target_properties(spicetools_spice64 PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice64 PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
|
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
|
||||||
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
|
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
|
||||||
|
if(NOT SPICE_XP)
|
||||||
|
target_link_libraries(spicetools_spice64 PUBLIC d3d11 dxgi)
|
||||||
|
target_compile_definitions(spicetools_spice64 PRIVATE SPICE_D3D11=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
IF(NOT MSVC)
|
IF(NOT MSVC)
|
||||||
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
@@ -722,11 +897,14 @@ add_executable(spicetools_spice64_linux ${SOURCE_FILES} ${RESOURCE_FILES})
|
|||||||
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
||||||
target_link_libraries(spicetools_spice64_linux
|
target_link_libraries(spicetools_spice64_linux
|
||||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook wslay imm32 dwmapi CpuFeatures::cpu_features spice_jpeg spice_x264)
|
||||||
set_target_properties(spicetools_spice64_linux PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice64_linux PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_spice64_linux PROPERTIES OUTPUT_NAME "spice64_linux")
|
set_target_properties(spicetools_spice64_linux PROPERTIES OUTPUT_NAME "spice64_linux")
|
||||||
target_compile_definitions(spicetools_spice64_linux PRIVATE SPICE64=1)
|
target_compile_definitions(spicetools_spice64_linux PRIVATE SPICE64=1)
|
||||||
target_compile_definitions(spicetools_spice64_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
|
target_compile_definitions(spicetools_spice64_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
|
||||||
|
# spice64_linux is never built under the WinXP toolchain, so dx11 is always on.
|
||||||
|
target_link_libraries(spicetools_spice64_linux PUBLIC d3d11 dxgi)
|
||||||
|
target_compile_definitions(spicetools_spice64_linux PRIVATE SPICE_D3D11=1)
|
||||||
|
|
||||||
IF(NOT MSVC)
|
IF(NOT MSVC)
|
||||||
set_target_properties(spicetools_spice64_linux PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
set_target_properties(spicetools_spice64_linux PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
@@ -738,9 +916,11 @@ endif()
|
|||||||
set(SOURCE_FILES ${SOURCE_FILES} launcher/options.h launcher/options.cpp)
|
set(SOURCE_FILES ${SOURCE_FILES} launcher/options.h launcher/options.cpp)
|
||||||
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
|
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
|
||||||
add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||||
|
# the configurator serves neither the API nor the video stream, so it needs no codecs
|
||||||
target_link_libraries(spicetools_cfg
|
target_link_libraries(spicetools_cfg
|
||||||
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook wslay imm32 dwmapi CpuFeatures::cpu_features)
|
||||||
|
target_link_libraries(spicetools_cfg PUBLIC winscard)
|
||||||
set_target_properties(spicetools_cfg PROPERTIES PREFIX "")
|
set_target_properties(spicetools_cfg PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
|
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
|
||||||
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
||||||
@@ -756,8 +936,8 @@ set(SOURCE_FILES ${SOURCE_FILES} launcher/options.h launcher/options.cpp)
|
|||||||
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
|
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
|
||||||
add_executable(spicetools_cfg_linux WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_cfg_linux WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_cfg_linux
|
target_link_libraries(spicetools_cfg_linux
|
||||||
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook wslay imm32 dwmapi CpuFeatures::cpu_features)
|
||||||
set_target_properties(spicetools_cfg_linux PROPERTIES PREFIX "")
|
set_target_properties(spicetools_cfg_linux PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_cfg_linux PROPERTIES OUTPUT_NAME "spicecfg_linux")
|
set_target_properties(spicetools_cfg_linux PROPERTIES OUTPUT_NAME "spicecfg_linux")
|
||||||
target_compile_definitions(spicetools_cfg_linux PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
target_compile_definitions(spicetools_cfg_linux PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
||||||
@@ -818,7 +998,8 @@ endif()
|
|||||||
|
|
||||||
# nvcuda.dll
|
# nvcuda.dll
|
||||||
set(SOURCE_FILES stubs/nvcuda.cpp)
|
set(SOURCE_FILES stubs/nvcuda.cpp)
|
||||||
add_library(spicetools_stubs_nvcuda SHARED ${SOURCE_FILES} stubs/nvcuda.def)
|
set(RESOURCE_FILES stubs/manifest.rc)
|
||||||
|
add_library(spicetools_stubs_nvcuda SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/nvcuda.def)
|
||||||
set_target_properties(spicetools_stubs_nvcuda PROPERTIES PREFIX "")
|
set_target_properties(spicetools_stubs_nvcuda PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_stubs_nvcuda PROPERTIES OUTPUT_NAME "nvcuda")
|
set_target_properties(spicetools_stubs_nvcuda PROPERTIES OUTPUT_NAME "nvcuda")
|
||||||
|
|
||||||
@@ -828,7 +1009,8 @@ endif()
|
|||||||
|
|
||||||
# nvcuvid.dll
|
# nvcuvid.dll
|
||||||
set(SOURCE_FILES stubs/nvcuvid.cpp)
|
set(SOURCE_FILES stubs/nvcuvid.cpp)
|
||||||
add_library(spicetools_stubs_nvcuvid SHARED ${SOURCE_FILES} stubs/nvcuvid.def)
|
set(RESOURCE_FILES stubs/manifest.rc)
|
||||||
|
add_library(spicetools_stubs_nvcuvid SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/nvcuvid.def)
|
||||||
set_target_properties(spicetools_stubs_nvcuvid PROPERTIES PREFIX "")
|
set_target_properties(spicetools_stubs_nvcuvid PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_stubs_nvcuvid PROPERTIES OUTPUT_NAME "nvcuvid")
|
set_target_properties(spicetools_stubs_nvcuvid PROPERTIES OUTPUT_NAME "nvcuvid")
|
||||||
|
|
||||||
@@ -838,7 +1020,8 @@ endif()
|
|||||||
|
|
||||||
# nvEncodeAPI64.dll
|
# nvEncodeAPI64.dll
|
||||||
set(SOURCE_FILES stubs/nvEncodeAPI64.cpp)
|
set(SOURCE_FILES stubs/nvEncodeAPI64.cpp)
|
||||||
add_library(spicetools_stubs_nvEncodeAPI64 SHARED ${SOURCE_FILES} stubs/nvEncodeAPI64.def)
|
set(RESOURCE_FILES stubs/manifest.rc)
|
||||||
|
add_library(spicetools_stubs_nvEncodeAPI64 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/nvEncodeAPI64.def)
|
||||||
set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES PREFIX "")
|
set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES OUTPUT_NAME "nvEncodeAPI64")
|
set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES OUTPUT_NAME "nvEncodeAPI64")
|
||||||
|
|
||||||
@@ -848,7 +1031,8 @@ endif()
|
|||||||
|
|
||||||
# cpusbxpkm.dll (32 bit)
|
# cpusbxpkm.dll (32 bit)
|
||||||
set(SOURCE_FILES stubs/cpusbxpkm.cpp)
|
set(SOURCE_FILES stubs/cpusbxpkm.cpp)
|
||||||
add_library(spicetools_stubs_cpusbxpkm SHARED ${SOURCE_FILES} stubs/cpusbxpkm.def)
|
set(RESOURCE_FILES stubs/manifest.rc)
|
||||||
|
add_library(spicetools_stubs_cpusbxpkm SHARED ${SOURCE_FILES} ${RESOURCE_FILES} stubs/cpusbxpkm.def)
|
||||||
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES PREFIX "")
|
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES OUTPUT_NAME "cpusbxpkm")
|
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES OUTPUT_NAME "cpusbxpkm")
|
||||||
|
|
||||||
@@ -856,6 +1040,36 @@ if(NOT MSVC)
|
|||||||
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# sdk_sample_v0_flat_c.dll (32 bit)
|
||||||
|
set(SOURCE_FILES sdk/sample/v0/flat_c/v0_flat_c.c)
|
||||||
|
add_library(spicetools_sdk_sample_v0_flat_c_32 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} sdk/sample/v0/flat_c/v0_flat_c.def)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_32 PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_32 PROPERTIES OUTPUT_NAME "sdk_sample_v0_flat_c")
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_32 PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# sdk_sample_v0_flat_c.dll (64 bit)
|
||||||
|
set(SOURCE_FILES sdk/sample/v0/flat_c/v0_flat_c.c)
|
||||||
|
add_library(spicetools_sdk_sample_v0_flat_c_64 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} sdk/sample/v0/flat_c/v0_flat_c.def)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_64 PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_64 PROPERTIES OUTPUT_NAME "sdk_sample_v0_flat_c")
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# sdk_sample_v0_cpp.dll (64 bit)
|
||||||
|
set(SOURCE_FILES sdk/sample/v0/cpp/v0_cpp.cpp)
|
||||||
|
add_library(spicetools_sdk_sample_v0_cpp_64 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} sdk/sample/v0/cpp/v0_cpp.def)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_cpp_64 PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_cpp_64 PROPERTIES OUTPUT_NAME "sdk_sample_v0_cpp")
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_cpp_64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
|
endif()
|
||||||
|
|
||||||
# output directories
|
# output directories
|
||||||
####################
|
####################
|
||||||
|
|
||||||
@@ -865,15 +1079,28 @@ set_target_properties(spicetools_cfg spicetools_cfg_linux
|
|||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
||||||
|
|
||||||
# output 32bit
|
# output 32bit
|
||||||
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm
|
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm spicetools_sdk_sample_v0_flat_c_32
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
|
||||||
|
|
||||||
# output 64bit
|
# output 64bit
|
||||||
set_target_properties(spicetools_spice64 spicetools_spice64_linux spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64
|
set_target_properties(spicetools_spice64 spicetools_spice64_linux spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64 spicetools_sdk_sample_v0_flat_c_64 spicetools_sdk_sample_v0_cpp_64
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64")
|
||||||
|
|
||||||
|
# forbidden static DLL import guard
|
||||||
|
###################################
|
||||||
|
# apply the check to every executable and DLL produced by this project.
|
||||||
|
get_property(spice_all_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
|
||||||
|
foreach(spice_target IN LISTS spice_all_targets)
|
||||||
|
get_target_property(spice_target_type ${spice_target} TYPE)
|
||||||
|
if(spice_target_type STREQUAL "EXECUTABLE"
|
||||||
|
OR spice_target_type STREQUAL "SHARED_LIBRARY"
|
||||||
|
OR spice_target_type STREQUAL "MODULE_LIBRARY")
|
||||||
|
spice_guard_dll_imports(${spice_target})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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, 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
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
@@ -0,0 +1,386 @@
|
|||||||
|
SpiceTools
|
||||||
|
==========
|
||||||
|
This is a loader for various arcade games developed by 573.
|
||||||
|
The project is using CMake as it's build system, with a custom build
|
||||||
|
script for making packages ready for distribution and to keep it easy
|
||||||
|
for people not knowing how to use CMake.
|
||||||
|
|
||||||
|
## Building/Distribution
|
||||||
|
|
||||||
|
We're currently using Arch Linux for building the binaries.
|
||||||
|
You'll need:
|
||||||
|
- MinGW-64 packages (can be found in the AUR)
|
||||||
|
- bash
|
||||||
|
- git
|
||||||
|
- zip
|
||||||
|
- upx (optional)
|
||||||
|
|
||||||
|
For any other GNU/Linux distributions (or Windows lol), you're on your
|
||||||
|
own.
|
||||||
|
|
||||||
|
To build the project, run:
|
||||||
|
|
||||||
|
$ ./build_all.sh
|
||||||
|
|
||||||
|
## Build Configuration
|
||||||
|
|
||||||
|
You can tweak some settings at the beginning of the build script. You
|
||||||
|
might want to modify the paths of the toolchains if yours differ. It's
|
||||||
|
also possible to disable UPX compression and source distribution for
|
||||||
|
example.
|
||||||
|
|
||||||
|
If you're not using an IDE and want to run the build script from command
|
||||||
|
line manually each time you make a change, you can set CLEAN_BUILD to 0
|
||||||
|
so it will only compile what's needed. When modifying the resources you
|
||||||
|
should build from scratch, since CMake isn't able to track changes of
|
||||||
|
those files (e.g. changelog.txt, licenses.txt).
|
||||||
|
|
||||||
|
You can put your custom build script under "build_all.local.sh" if you
|
||||||
|
don't want git to track the changes you made to the build settings.
|
||||||
|
|
||||||
|
## Debug Build
|
||||||
|
|
||||||
|
To get proper stackstraces, you need to build with the DEBUG setting
|
||||||
|
enabled. This will set the CMake build type to debug and the script
|
||||||
|
will try to make use of cv2pdb.
|
||||||
|
Check external/cv2pdb/README.md for details on how to set it up.
|
||||||
|
It is required to use cv2pdb to generate PDB output, because at time of
|
||||||
|
writing, MinGW still didn't support Microsoft's proprietary file format.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
SpiceTools is providing a TCP/JSON based API. You can enable it with the
|
||||||
|
`-api [PORT]` option. It's recommended to also set a password with
|
||||||
|
`-apipass [PASS]`.
|
||||||
|
|
||||||
|
The protocol is meant to be simple, easy to use and with few overhead.
|
||||||
|
To connect to the API, just open a TCP connection to the host computer
|
||||||
|
at the specified port.
|
||||||
|
To make a request you write the UTF-8 encoded JSON contents to the
|
||||||
|
socket. To mark the end of the request, you need to terminate the JSON
|
||||||
|
string with `0x00`. The server returns its answer on the same way,
|
||||||
|
UTF-8 encoded JSON terminated with NULL.
|
||||||
|
|
||||||
|
To save space, by default the JSONs are without whitespace. To enable
|
||||||
|
pretty printing, use `-apipretty`.
|
||||||
|
|
||||||
|
If you want to test the API server without running a game, you can
|
||||||
|
run it headless via `-apidebug`.
|
||||||
|
|
||||||
|
If a password is specified, both request and response are encrypted
|
||||||
|
using RC4 with the key being the password encoded in UTF-8.
|
||||||
|
While only providing weak security when the password is static,
|
||||||
|
it's simple to implement and requires no authentication protocol.
|
||||||
|
The password is also able to change dynamically, see
|
||||||
|
`control.session_refresh()` for details.
|
||||||
|
|
||||||
|
If you don't want to worry about all the details, you can just use one
|
||||||
|
of the supplied libraries (check /api/resources). There's also a little
|
||||||
|
remote control GUI available for python.
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
SpiceTools opens a WebSocket server on the specified port plus one.
|
||||||
|
That means if the API is on 1337, the WebSocket server will be on 1338.
|
||||||
|
The protocol is the very same as for the normal API, but instead of
|
||||||
|
directly sending the data over TCP you need to send binary datapackets.
|
||||||
|
The included dart spiceapi library also has a WebSocket implementation.
|
||||||
|
|
||||||
|
### Example Call
|
||||||
|
This example inserts the a card into P1's reader slot.
|
||||||
|
If you need more examples, you can check the example code.
|
||||||
|
|
||||||
|
#### Request
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"module": "card",
|
||||||
|
"function": "insert",
|
||||||
|
"params": [0, "E004010000000000"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### Response
|
||||||
|
```JSON
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"errors": [],
|
||||||
|
"data": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modules
|
||||||
|
|
||||||
|
For the sake of simplifying this documentation, I will describe functions
|
||||||
|
as if they were called via a normal programming language. That means,
|
||||||
|
besides `module`/`function` needing to be set accordingly, the `params` field
|
||||||
|
must contain all the parameters described below. Some of them are optional.
|
||||||
|
The returning data will always be in the `data` field of the response.
|
||||||
|
|
||||||
|
Errors will be reported as strings in the `errors` field. Sometimes, you can
|
||||||
|
receive more than one error. The error messages may be changed/improved in the
|
||||||
|
future, so you shouldn't rely on them. If the error list is empty, the function
|
||||||
|
executed successfully.
|
||||||
|
|
||||||
|
The `id` of the response will always match the `id` of the request. The API
|
||||||
|
server itself doesn't expect any logic of your ID choices, however you can use
|
||||||
|
them to make sure your answers aren't arriving out of order. Currently it
|
||||||
|
doesn't matter since the TCP protocol doesn't allow for out of order data,
|
||||||
|
however this may change when/if support for UDP is being introduced. The only
|
||||||
|
restriction is that the ID has to be a valid 64-bit unsigned integer.
|
||||||
|
|
||||||
|
#### Capture
|
||||||
|
- get_screens()
|
||||||
|
- returns the screen numbers the game has registered for capture
|
||||||
|
- get_jpg(screen: uint, quality: uint, divide: uint)
|
||||||
|
- returns the timestamp, width, height and base64 encoded JPEG of one screen
|
||||||
|
- all parameters are optional and default to screen 0, quality 70, divide 1
|
||||||
|
- divide shrinks the image by that factor before encoding
|
||||||
|
- get_streams()
|
||||||
|
- returns a dict describing the HTTP video stream, or no data at all when
|
||||||
|
`-apistream` is not enabled and there is nothing to describe
|
||||||
|
- `port` is the stream server port
|
||||||
|
- `formats` lists the wire formats this build serves, each with a `name`
|
||||||
|
(`h264` or `mjpeg`) and the `path` to request them on
|
||||||
|
- `screens` lists every capturable screen with its `width`, `height`, and
|
||||||
|
`busy`
|
||||||
|
|
||||||
|
#### Card
|
||||||
|
- get_cards()
|
||||||
|
- returns the current card ID and source for each active card reader
|
||||||
|
- each entry contains `index`, `card_id`, and `source`
|
||||||
|
- `source` is `file` or `override`
|
||||||
|
- file entries also contain `file_name`, without the full configured path
|
||||||
|
- `-card0` and `-card1` overrides do not contain `file_name`
|
||||||
|
- this function only works when an API password is configured
|
||||||
|
- insert(index: uint, card_id: hex)
|
||||||
|
- inserts a card which gets read by the emulated card readers for the game
|
||||||
|
- index has to be either 0 (for P1) or 1 (for P2)
|
||||||
|
- card_id has to be a valid 16-character hex string
|
||||||
|
|
||||||
|
#### Coin
|
||||||
|
- get()
|
||||||
|
- returns the amount of unprocessed coins in queue
|
||||||
|
- not equal to the amount of coins shown ingame since the game may drain it
|
||||||
|
- set(amount: int)
|
||||||
|
- sets the amount of coins in queue for the game to process
|
||||||
|
- insert(amount: int)
|
||||||
|
- adds the amount to the coins in queue
|
||||||
|
- amount is optional and defaults to 1
|
||||||
|
- blocker_get()
|
||||||
|
- returns the current coin blocker state (false: open, true: closed)
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
- avs()
|
||||||
|
- returns a dict including the AVS model, dest, spec, rev and ext
|
||||||
|
- launcher()
|
||||||
|
- returns a dict including the version, compile date/time, system time and
|
||||||
|
the arguments used to start the process
|
||||||
|
- memory()
|
||||||
|
- returns a dict including total, total used and bytes used by the process
|
||||||
|
for both physical and virtual RAM
|
||||||
|
|
||||||
|
#### Keypads
|
||||||
|
For all functions in this module, the keypad parameter must be
|
||||||
|
either 0 (for P1) or 1 (for P2). Accepted keypad characters are "0" to "9" for
|
||||||
|
the single digit numbers, "A" for the double zero and "D" for the decimal key.
|
||||||
|
- write(keypad: uint, input: str)
|
||||||
|
- writes all characters in input sequentially to the keypad
|
||||||
|
- this should be used for things like PIN input
|
||||||
|
- set(keypad: uint, key: char, ...)
|
||||||
|
- clears all overrides, then applies each given key as override
|
||||||
|
- if a key is overridden, it shows up as pressed in-game
|
||||||
|
- get(keypad: uint)
|
||||||
|
- returns all pressed keys of the specified keypad
|
||||||
|
|
||||||
|
#### Analogs/Buttons/Lights
|
||||||
|
All of those three modules have equally named methods for you to call.
|
||||||
|
- read()
|
||||||
|
- returns an array of state objects containing name, state and a bool
|
||||||
|
- the bool indicates if the object is active (e.g. the button was overridden)
|
||||||
|
- write([name: str, state: float], ...)
|
||||||
|
- applies the states as an override value
|
||||||
|
- the device binding via the config will be ignored while an override is set
|
||||||
|
- if an override value is set, the object will be marked as active
|
||||||
|
- write_reset([name: str], ...)
|
||||||
|
- removes the override value from the objects specified by name
|
||||||
|
- if no names were passed, all overrides will be removed
|
||||||
|
|
||||||
|
##### Additional API for lights
|
||||||
|
- read(name: string, ...)
|
||||||
|
- same as read(), but you can specify light names
|
||||||
|
- write_reset(name: str, ...)
|
||||||
|
- same as write_reset(), but it accepts a flat list of strings
|
||||||
|
|
||||||
|
#### Touch
|
||||||
|
- read()
|
||||||
|
- returns an array of state objects containing id, x and y
|
||||||
|
- write([id: uint, x: int, y: int], ...)
|
||||||
|
- adds the given touch points having an unknown ID
|
||||||
|
- overrides old touch points when the ID matches
|
||||||
|
- write_reset(id: uint, ...)
|
||||||
|
- removes the touch points matching one of the given IDs
|
||||||
|
|
||||||
|
#### Control
|
||||||
|
This module only functions if a password is being used to communicate,
|
||||||
|
with the single exception of session_refresh().
|
||||||
|
- raise(signal: str)
|
||||||
|
- raises a signal to the current process
|
||||||
|
- signal is a string and must be one of the following values:
|
||||||
|
"SIGABRT", "SIGFPE", "SIGILL", "SIGINT", "SIGSEGV", "SIGTERM"
|
||||||
|
- the signal will be raised while the message is being processed
|
||||||
|
- exit(code: int)
|
||||||
|
- code is optional and defaults to 0
|
||||||
|
- the process will end while the message is being processed
|
||||||
|
- restart()
|
||||||
|
- spawns a new instance with the same arguments as passed to the main executable
|
||||||
|
- session_refresh()
|
||||||
|
- generates a new secure password and applies it after the response
|
||||||
|
- can be used to increase the security by using the password as some kind of
|
||||||
|
session token
|
||||||
|
- recommended to call directly after connecting and once in a while for
|
||||||
|
persistent connections
|
||||||
|
- shutdown()
|
||||||
|
- tries to force shutdown the computer
|
||||||
|
- reboot()
|
||||||
|
- tries to force reboot the computer
|
||||||
|
|
||||||
|
#### Memory
|
||||||
|
This module only functions if a password is being used to communicate.
|
||||||
|
All offsets are specified in file offsets of the corresponding `dll_name`,
|
||||||
|
which also means that your hex edits are applicable directly.
|
||||||
|
- write(dll_name: str, data: hex, offset: uint)
|
||||||
|
- writes the bytes in data to the specified offset
|
||||||
|
- read(dll_name: str, offset: uint, size: uint)
|
||||||
|
- reads bytes starting from offset and returns it
|
||||||
|
- signature(dll_name: str, signature: hex, replacement: hex, offset: uint,
|
||||||
|
usage: uint)
|
||||||
|
- tries to find the signature in the module's memory
|
||||||
|
- unknown bytes are masked out via "??" (e.g. "75??90????74")
|
||||||
|
- masking out bytes works for both the signature and the replacement
|
||||||
|
- offset is the byte difference between the offset of the found signature and
|
||||||
|
the offset where the replacement data gets written to
|
||||||
|
- usage is the number of the result being used for replacement, starting at 0
|
||||||
|
- returns the offset where the replacement data gets written to
|
||||||
|
- the replacement string can be empty, so you can only get the address of the
|
||||||
|
signature while not actually replacing anything
|
||||||
|
|
||||||
|
#### IIDX
|
||||||
|
- ticker_get()
|
||||||
|
- returns a string of the characters displayed on the 16 segment display
|
||||||
|
- ticker_set(text: str)
|
||||||
|
- sets the contents of the 16 segment display and disables writes from game
|
||||||
|
- ticker_reset()
|
||||||
|
- re-enables writes from game
|
||||||
|
- tapeled_get(name: str, ...)
|
||||||
|
- returns a list containing a dict of the current tape LED states. The dict keys are:
|
||||||
|
- `Stage Left`
|
||||||
|
- `Stage Right`
|
||||||
|
- `Cabinet Left`
|
||||||
|
- `Cabinet Right`
|
||||||
|
- `Control Panel Under`
|
||||||
|
- `Ceiling Left`
|
||||||
|
- `Title Left`
|
||||||
|
- `Title Right`
|
||||||
|
- `Ceiling Right`
|
||||||
|
- `Touch Panel Left`
|
||||||
|
- `Touch Panel Right`
|
||||||
|
- `Side Panel Left Inner`
|
||||||
|
- `Side Panel Left Outer`
|
||||||
|
- `Side Panel Left`
|
||||||
|
- `Side Panel Right Outer`
|
||||||
|
- `Side Panel Right Inner`
|
||||||
|
- `Side Panel Right`
|
||||||
|
|
||||||
|
#### SDVX
|
||||||
|
- tapeled_get(name: str, ...)
|
||||||
|
- returns a list containing a dict of the current tape LED states. The dict keys are:
|
||||||
|
- `Title`
|
||||||
|
- `Upper Left Speaker`
|
||||||
|
- `Upper Right Speaker`
|
||||||
|
- `Left Wing`
|
||||||
|
- `Right Wing`
|
||||||
|
- `Control Panel`
|
||||||
|
- `Lower Left Speaker`
|
||||||
|
- `Lower Right Speaker`
|
||||||
|
- `Woofer`
|
||||||
|
- `V Unit`
|
||||||
|
|
||||||
|
#### LCD
|
||||||
|
- info()
|
||||||
|
- returns information about the serial LCD controller some games use
|
||||||
|
|
||||||
|
#### Resize
|
||||||
|
- image_resize_enable(enable: bool)
|
||||||
|
- enables or disables image resize state
|
||||||
|
- image_resize_set_scene(scene: int)
|
||||||
|
- sets the active scene for image resize state; set to 0 to disable resize
|
||||||
|
|
||||||
|
## Video Stream
|
||||||
|
|
||||||
|
Separate from the JSON API, spice can serve the mirrored screen as a video
|
||||||
|
stream over plain HTTP. Enable it with `-apistream`. It listens on the API port
|
||||||
|
plus two, in the same way the WebSocket server uses the API port plus one, so
|
||||||
|
`-api 1337` puts the stream on 1339. This means `-api` has to be enabled too.
|
||||||
|
|
||||||
|
Rather than working the port out, clients should ask the JSON API for it with
|
||||||
|
`capture.get_streams()`, which also reports which of the formats below this
|
||||||
|
build serves, the size of each screen and whether one is already taken.
|
||||||
|
|
||||||
|
Two formats are served:
|
||||||
|
|
||||||
|
http://host:1339/stream.mjpg JPEG frames, multipart/x-mixed-replace
|
||||||
|
http://host:1339/stream.h264 H.264 annex-b, no container
|
||||||
|
|
||||||
|
All accept the same optional query parameters:
|
||||||
|
|
||||||
|
- `screen` - which screen to mirror, 0-3. Defaults to the subscreen when the
|
||||||
|
game has one, otherwise the main screen.
|
||||||
|
- `fps` - frames per second, 1-60. Default 30.
|
||||||
|
- `q` - quality, 1-100. Default 70. This is the JPEG quality for `stream.mjpg`
|
||||||
|
and is mapped onto the H.264 rate factor for `stream.h264`, so the same number
|
||||||
|
does not mean the same thing for both.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
http://host:1339/stream.h264?screen=1&fps=30&q=70
|
||||||
|
|
||||||
|
See the wiki for format tradeoffs, latency tuning, testing commands and client
|
||||||
|
notes.
|
||||||
|
|
||||||
|
The stream is view only. Touch and other input still go through the JSON API,
|
||||||
|
so a companion app needs both. There is no authentication on the stream port -
|
||||||
|
anyone who can reach it can watch the screen.
|
||||||
|
|
||||||
|
WinXP builds have no video stream. Neither encoder is compiled in, so nothing
|
||||||
|
listens on the stream port even with `-apistream`, `capture.get_streams()`
|
||||||
|
returns no data, and the JSON API's JPEG screen capture is unavailable for the
|
||||||
|
same reason.
|
||||||
|
|
||||||
|
## Native wrapper libraries
|
||||||
|
Spicetools provides wrapper libraries in: Arduino, C++, Dart, and Python.
|
||||||
|
Python is the only one that is fully spec compliant.
|
||||||
|
Other libraries may be missing features and contain bugs; please feel free to
|
||||||
|
contribute code to fill the gaps if you work on a project using these libraries.
|
||||||
|
|
||||||
|
## Spice SDK (for DLL hooks / plugins)
|
||||||
|
|
||||||
|
As an alternative to Spice API, Spice SDK is available.
|
||||||
|
|
||||||
|
This is a flat C, header-only library that can be included in your DLL. Once
|
||||||
|
initialized, you can call directly into helper routines provided by Spicetools
|
||||||
|
executable, making low-latency and high-throughput interactions possible.
|
||||||
|
|
||||||
|
Check the documentation on the wiki for more details.
|
||||||
|
|
||||||
|
## License
|
||||||
|
Unless otherwise noted, all files are licensed under the GPLv3.
|
||||||
|
See the LICENSE file for the full license text.
|
||||||
|
Files not originating from this project should be placed in "external",
|
||||||
|
they each have their own license.
|
||||||
|
|
||||||
|
###### What that means for you
|
||||||
|
- If you want to distribute the binaries, you'll have to include the
|
||||||
|
sources, otherwise you're violating the GPL.
|
||||||
|
- If you want to merge some of this project's code into similar
|
||||||
|
software, that software has to be put under the GPL as well.
|
||||||
|
You'll probably have to modify a lot anyways, so you can just use the
|
||||||
|
source as some kind of documentation.
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "bmpu.h"
|
#include "bmpu.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "acio/icca/icca.h"
|
#include "acio/icca/icca.h"
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "cfg/api.h"
|
#include "cfg/api.h"
|
||||||
@@ -9,6 +11,7 @@
|
|||||||
#include "games/ftt/io.h"
|
#include "games/ftt/io.h"
|
||||||
#include "games/museca/io.h"
|
#include "games/museca/io.h"
|
||||||
#include "games/silentscope/io.h"
|
#include "games/silentscope/io.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
|
|
||||||
@@ -530,15 +533,38 @@ static bool __cdecl ac_io_bmpu_update_control_status_buffer() {
|
|||||||
STATUS_BUFFER[4] |= 0x20;
|
STATUS_BUFFER[4] |= 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
// joy stick raw input
|
// gun position, sent big endian; the game keeps the top 12 bits of each pair
|
||||||
auto &analogs = games::silentscope::get_analogs();
|
auto &analogs = games::silentscope::get_analogs();
|
||||||
|
auto &gun_x = analogs.at(games::silentscope::Analogs::GUN_X);
|
||||||
|
auto &gun_y = analogs.at(games::silentscope::Analogs::GUN_Y);
|
||||||
unsigned short joy_x = 0x7FFF;
|
unsigned short joy_x = 0x7FFF;
|
||||||
unsigned short joy_y = 0x7FFF;
|
unsigned short joy_y = 0x7FFF;
|
||||||
if (analogs.at(games::silentscope::Analogs::GUN_X).isSet()) {
|
|
||||||
joy_x = (unsigned short) (Analogs::getState(RI_MGR, analogs.at(games::silentscope::Analogs::GUN_X)) * USHRT_MAX);
|
if (gun_x.isSet() || gun_y.isSet()) {
|
||||||
}
|
if (gun_x.isSet()) {
|
||||||
if (analogs.at(games::silentscope::Analogs::GUN_Y).isSet()) {
|
joy_x = (unsigned short) (Analogs::getState(RI_MGR, gun_x) * USHRT_MAX);
|
||||||
joy_y = (unsigned short) (Analogs::getState(RI_MGR, analogs.at(games::silentscope::Analogs::GUN_Y)) * USHRT_MAX);
|
}
|
||||||
|
if (gun_y.isSet()) {
|
||||||
|
joy_y = (unsigned short) (Analogs::getState(RI_MGR, gun_y) * USHRT_MAX);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// the gun reports where it is aimed, which a relative pointer cannot express - the
|
||||||
|
// calibration screen asks for the screen centre and two corners, so read the cursor
|
||||||
|
POINT cursor {};
|
||||||
|
RECT client {};
|
||||||
|
POINT origin {};
|
||||||
|
if (NDD_MAIN_WINDOW != nullptr &&
|
||||||
|
GetCursorPos(&cursor) &&
|
||||||
|
GetClientRect(NDD_MAIN_WINDOW, &client) &&
|
||||||
|
ClientToScreen(NDD_MAIN_WINDOW, &origin) &&
|
||||||
|
client.right > 1 && client.bottom > 1)
|
||||||
|
{
|
||||||
|
const LONG x = std::clamp(cursor.x - origin.x, 0L, client.right - 1);
|
||||||
|
const LONG y = std::clamp(cursor.y - origin.y, 0L, client.bottom - 1);
|
||||||
|
joy_x = (unsigned short) (x * USHRT_MAX / (client.right - 1));
|
||||||
|
joy_y = (unsigned short) (y * USHRT_MAX / (client.bottom - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// invert X axis
|
// invert X axis
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "misc/wintouchemu.h"
|
#include "misc/wintouchemu.h"
|
||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
|
#include "touch/native/nativetouchhook.h"
|
||||||
|
|
||||||
// static stuff
|
// static stuff
|
||||||
static int ACIO_WARMUP = 0;
|
static int ACIO_WARMUP = 0;
|
||||||
@@ -140,8 +141,9 @@ static int __cdecl ac_io_update(int a1) {
|
|||||||
// flush device output
|
// flush device output
|
||||||
RI_MGR->devices_flush_output();
|
RI_MGR->devices_flush_output();
|
||||||
|
|
||||||
// update wintouchemu
|
// update touch emulation
|
||||||
wintouchemu::update();
|
wintouchemu::update();
|
||||||
|
nativetouch::refresh_contact_lifetime();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user