mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 18:31:26 -10:00
Compare commits
1424
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34bcb03ef8 | ||
|
|
eb738b3ef7 | ||
|
|
f04debfb36 | ||
|
|
aa8fb89a17 | ||
|
|
44e5f89e41 | ||
|
|
fee0b900de | ||
|
|
6b209223ee | ||
|
|
cb06c73b6a | ||
|
|
7ab8a96903 | ||
|
|
a58376404d | ||
|
|
cfe89f411b | ||
|
|
91c9417d3e | ||
|
|
f37c519b79 | ||
|
|
4dd194f4d6 | ||
|
|
b38367b22f | ||
|
|
72517ff9a2 | ||
|
|
c3e212094e | ||
|
|
9e9378dcb6 | ||
|
|
9b9041513d | ||
|
|
51aac78080 | ||
|
|
3dd21f6cb6 | ||
|
|
a42b27c0b8 | ||
|
|
ca73920b8e | ||
|
|
17374106d1 | ||
|
|
6da5302d34 | ||
|
|
d0a1efacb8 | ||
|
|
8168099eac | ||
|
|
ae943503cb | ||
|
|
4368db845d | ||
|
|
c25163e265 | ||
|
|
4bf9277c10 | ||
|
|
0bcdf19851 | ||
|
|
c4095d1af1 | ||
|
|
5d8f779cff | ||
|
|
6f2592e733 | ||
|
|
528a43952e | ||
|
|
62d1f1978b | ||
|
|
b9b556c7a5 | ||
|
|
16b0db8eb9 | ||
|
|
2c36ea35b4 | ||
|
|
43e540cc4c | ||
|
|
67627bd786 | ||
|
|
ea0c4b7b78 | ||
|
|
29e56bb19a | ||
|
|
57da3e1ef6 | ||
|
|
16ac19946f | ||
|
|
e319b6f941 | ||
|
|
8c88b68327 | ||
|
|
e75ed62692 | ||
|
|
748857ca2f | ||
|
|
bff8231d87 | ||
|
|
29087a3237 | ||
|
|
a228a127e2 | ||
|
|
2692240ed9 | ||
|
|
a47dcc0548 | ||
|
|
9fed19d4fc | ||
|
|
9446e61587 | ||
|
|
1ffd0d3ef8 | ||
|
|
1a94018fb4 | ||
|
|
e8ef727a19 | ||
|
|
dfdfd59367 | ||
|
|
4f7b718167 | ||
|
|
b1046b1c1c | ||
|
|
4663aed194 | ||
|
|
a56432f5fc | ||
|
|
206ce536ec | ||
|
|
d8ccf84452 | ||
|
|
bed9c13233 | ||
|
|
16993b236f | ||
|
|
94f8d547e0 | ||
|
|
b6908d10c4 | ||
|
|
a54aa24a64 | ||
|
|
d083089e1d | ||
|
|
338436d590 | ||
|
|
1d2f778b76 | ||
|
|
aad1bbbb05 | ||
|
|
1e4bede8c5 | ||
|
|
38b331dc92 | ||
|
|
d3965b1f9d | ||
|
|
986099a495 | ||
|
|
07ff605c58 | ||
|
|
a8171c118f | ||
|
|
4b9c7b19aa | ||
|
|
33d2294a49 | ||
|
|
8e558b2095 | ||
|
|
703bfab587 | ||
|
|
344502c436 | ||
|
|
ef06593ed7 | ||
|
|
a22b336bfe | ||
|
|
37b81efea4 | ||
|
|
7c6f99c68b | ||
|
|
f7b7aaead3 | ||
|
|
80dcefa0fc | ||
|
|
27a70d545d | ||
|
|
e4614f01ba | ||
|
|
e2d8502a3e | ||
|
|
dee0cf600f | ||
|
|
6181c0b2f7 | ||
|
|
0f942afaae | ||
|
|
cdde87662a | ||
|
|
4e7f8fa92a | ||
|
|
867ebfed89 | ||
|
|
0ff8a2c159 | ||
|
|
8272304cfa | ||
|
|
0522566790 | ||
|
|
59e7b10b73 | ||
|
|
eb4cfeb256 | ||
|
|
a7b1c00a84 | ||
|
|
e484a84d97 | ||
|
|
bd2bb12ad3 | ||
|
|
c890c0af1f | ||
|
|
9cda43afb2 | ||
|
|
34b4321416 | ||
|
|
3a18a88e30 | ||
|
|
686bf15879 | ||
|
|
22f0ba89a4 | ||
|
|
a3bf47991b | ||
|
|
6af1768147 | ||
|
|
0d9fbd4725 | ||
|
|
c6975fda3c | ||
|
|
52baa1f115 | ||
|
|
d684dcea1b | ||
|
|
fa7f49f1e4 | ||
|
|
cc3dc5f566 | ||
|
|
19c50412ba | ||
|
|
cdd391caa8 | ||
|
|
4860f72678 | ||
|
|
5ba33228cb | ||
|
|
b7f3fdbb98 | ||
|
|
1bffdce6ef | ||
|
|
b130d526ff | ||
|
|
4c1ed2f66a | ||
|
|
d30a73a578 | ||
|
|
fa03117eaf | ||
|
|
2eb109dc49 | ||
|
|
bef57f7559 | ||
|
|
b807c670db | ||
|
|
24b71441c0 | ||
|
|
e47581ffa5 | ||
|
|
c585314ff1 | ||
|
|
97d09ae6ad | ||
|
|
250bf919a7 | ||
|
|
f8dd06ccef | ||
|
|
67416cc8f6 | ||
|
|
7118697a35 | ||
|
|
095c1ebe2b | ||
|
|
8c89c19c7e | ||
|
|
ae3d06c54f | ||
|
|
dbbb8af17b | ||
|
|
a23830359a | ||
|
|
31e572ec03 | ||
|
|
29b5c4bf7a | ||
|
|
3811270a09 | ||
|
|
64fc95ec8c | ||
|
|
0c70672a84 | ||
|
|
67e6bcca9f | ||
|
|
8de33ab56a | ||
|
|
b786b8e230 | ||
|
|
9dc308331b | ||
|
|
628ac86c3e | ||
|
|
dcee8a302e | ||
|
|
c7673f0591 | ||
|
|
000d0c3a0d | ||
|
|
ec19f9be98 | ||
|
|
3005a67573 | ||
|
|
33d4a7efa7 | ||
|
|
6c4e03d9dc | ||
|
|
537ee433de | ||
|
|
2cff45f2c5 | ||
|
|
466e4c159f | ||
|
|
6c7de5120e | ||
|
|
b2b0ba3630 | ||
|
|
14dcff6f5f | ||
|
|
d826537485 | ||
|
|
95c0fad96f | ||
|
|
85b3a30376 | ||
|
|
3c347ae938 | ||
|
|
09b28f2219 | ||
|
|
2fb078f32b | ||
|
|
a19b3030b6 | ||
|
|
5095b1c57a | ||
|
|
ab14742f96 | ||
|
|
492c4ba10a | ||
|
|
999eb8a3f9 | ||
|
|
03aa75c39a | ||
|
|
4f096c26b2 | ||
|
|
3db9fe9383 | ||
|
|
d1e236451f | ||
|
|
6cf7cb0843 | ||
|
|
2084eb01e8 | ||
|
|
7d1365800f | ||
|
|
66ce0acc17 | ||
|
|
c29954d672 | ||
|
|
f2d5246ccb | ||
|
|
b6dcc4f5ef | ||
|
|
bd62ceeeb0 | ||
|
|
f1bf0a411c | ||
|
|
28898ca8e3 | ||
|
|
3acdf3e801 | ||
|
|
f1101bee5d | ||
|
|
e617f0cc41 | ||
|
|
7c9f73fbdc | ||
|
|
c36b47a35c | ||
|
|
8d0b0a76f2 | ||
|
|
36e5afe1be | ||
|
|
20398150d8 | ||
|
|
e085cc20ab | ||
|
|
6b5869853c | ||
|
|
a6411cc1d3 | ||
|
|
bd4427a832 | ||
|
|
6dbd7c34e6 | ||
|
|
7a3029d1e3 | ||
|
|
1bca5f128d | ||
|
|
6bbb6be880 | ||
|
|
c1c2b72ef0 | ||
|
|
1aa85d236e | ||
|
|
1afc5eec13 | ||
|
|
759c9b1148 | ||
|
|
47bb378342 | ||
|
|
0b3dad8dc0 | ||
|
|
13e601a523 | ||
|
|
5de1b684f4 | ||
|
|
c5dcaf88d8 | ||
|
|
55558cc608 | ||
|
|
addc3ef383 | ||
|
|
2c1abf78d1 | ||
|
|
77c950ccd4 | ||
|
|
b160184f5b | ||
|
|
b1b197cc9a | ||
|
|
941b7298cc | ||
|
|
f8d0a9bc7d | ||
|
|
72fa41a284 | ||
|
|
72a797f732 | ||
|
|
2b0ec7161a | ||
|
|
637a9621f1 | ||
|
|
70c5aa88f2 | ||
|
|
1857f9b928 | ||
|
|
90c23c007c | ||
|
|
fb4169ba9f | ||
|
|
1448256140 | ||
|
|
7de592bf9b | ||
|
|
783852a115 | ||
|
|
84fd7123a5 | ||
|
|
ff9d06cfe1 | ||
|
|
a158029120 | ||
|
|
96e8d5b66e | ||
|
|
85fd0b0498 | ||
|
|
5d3e6789e6 | ||
|
|
b8e5a395dd | ||
|
|
1a1c3df379 | ||
|
|
0dc0d67c76 | ||
|
|
0edb360fc2 | ||
|
|
1743e5f5d4 | ||
|
|
ed3f07284d | ||
|
|
c1b222ffd5 | ||
|
|
3503b9214b | ||
|
|
aff8cc8095 | ||
|
|
884581a836 | ||
|
|
841872aae0 | ||
|
|
98af9dd903 | ||
|
|
ea37b3cb17 | ||
|
|
3035a868ab | ||
|
|
a88c50b6f2 | ||
|
|
ac24ca9fd3 | ||
|
|
d085951767 | ||
|
|
c3f19631ce | ||
|
|
ca9eff3bc5 | ||
|
|
0a19616bc9 | ||
|
|
255e9aa21e | ||
|
|
550f459747 | ||
|
|
6da72bb1a0 | ||
|
|
c7fbefeb58 | ||
|
|
98e316bca6 | ||
|
|
78a1e5baab | ||
|
|
080ce8419a | ||
|
|
06e9248079 | ||
|
|
e04c60ed6f | ||
|
|
81d9ca8e4a | ||
|
|
bf2ca61e5a | ||
|
|
72013d4c31 | ||
|
|
416d45d060 | ||
|
|
18be4e854c | ||
|
|
ffe647be79 | ||
|
|
fff2e6d1fc | ||
|
|
23e46ae7c4 | ||
|
|
74d270270e | ||
|
|
df69d195fe | ||
|
|
6c871ac339 | ||
|
|
24afebb808 | ||
|
|
6aac8c7bde | ||
|
|
a2da77e14c | ||
|
|
7ca6b679b7 | ||
|
|
3d6bbb0b9b | ||
|
|
a912956601 | ||
|
|
a769a7ef87 | ||
|
|
991e09006e | ||
|
|
3e6c3f6f62 | ||
|
|
2ee3dd70ea | ||
|
|
c259dfb9cd | ||
|
|
2947c7972d | ||
|
|
eda8c65b58 | ||
|
|
186f8ff5b9 | ||
|
|
c86c4c3822 | ||
|
|
bea9d56feb | ||
|
|
dc6d2be515 | ||
|
|
298ec5519c | ||
|
|
7025e3443e | ||
|
|
88b87b86fc | ||
|
|
b34ca3cfed | ||
|
|
1b2eece53a | ||
|
|
e8313fa577 | ||
|
|
5a8454e956 | ||
|
|
f6b1eaa846 | ||
|
|
d20ff9b367 | ||
|
|
a3ab30cd96 | ||
|
|
48f76f7cd1 | ||
|
|
eb165123ac | ||
|
|
526076f8ff | ||
|
|
c30ce55942 | ||
|
|
9447d74da8 | ||
|
|
043e6a79a8 | ||
|
|
97416feb2a | ||
|
|
aac3bbde8e | ||
|
|
8f3ef45fc9 | ||
|
|
762997fc7d | ||
|
|
43a46641eb | ||
|
|
47bd990bca | ||
|
|
ec3313ffea | ||
|
|
f2c099a7a9 | ||
|
|
e6c6cc3864 | ||
|
|
5ee1b6d243 | ||
|
|
3577c005e2 | ||
|
|
b2891bfe21 | ||
|
|
82aa027d0d | ||
|
|
902d40f3df | ||
|
|
e82fc4ac2f | ||
|
|
71673241fd | ||
|
|
f93cb23d43 | ||
|
|
0415b69407 | ||
|
|
e4775948d7 | ||
|
|
8958de35bc | ||
|
|
c03dbea7ea | ||
|
|
9107da8c9c | ||
|
|
1abb1833aa | ||
|
|
a2e70b8c5c | ||
|
|
1029de8073 | ||
|
|
3abcb24815 | ||
|
|
13d68bdfc6 | ||
|
|
de0bbaa4f6 | ||
|
|
ce569d400e | ||
|
|
adb94dc4d2 | ||
|
|
916082d910 | ||
|
|
e52f23d45d | ||
|
|
2dfc086c94 | ||
|
|
0a53aff061 | ||
|
|
2dab381e88 | ||
|
|
83514409f3 | ||
|
|
340f39f44d | ||
|
|
418a944127 | ||
|
|
22180c0b45 | ||
|
|
2949ca2628 | ||
|
|
dbf952e031 | ||
|
|
21cc93ffd6 | ||
|
|
c06ed08e74 | ||
|
|
89a9932ac5 | ||
|
|
5b1285e608 | ||
|
|
d5d33379a3 | ||
|
|
accbc1d25d | ||
|
|
8acff8e02c | ||
|
|
89d13ab774 | ||
|
|
8850efce7f | ||
|
|
4b36e3c379 | ||
|
|
c008dfc303 | ||
|
|
8f76537b02 | ||
|
|
36ae38a532 | ||
|
|
bcf49b9630 | ||
|
|
654f3545fc | ||
|
|
37575b2fea | ||
|
|
6ddca15dc5 | ||
|
|
353c28176c | ||
|
|
4815343854 | ||
|
|
4e18f01438 | ||
|
|
abdef9f7b0 | ||
|
|
f67a42d89e | ||
|
|
52b48bd32d | ||
|
|
ad2fcfd22f | ||
|
|
507f50cd90 | ||
|
|
d91739b41d | ||
|
|
b9413a2639 | ||
|
|
e003d08249 | ||
|
|
bb94d5bcd6 | ||
|
|
c8baf8b344 | ||
|
|
b5f75af66e | ||
|
|
8caaf5c00c | ||
|
|
7db1861b59 | ||
|
|
fabdc6ab8a | ||
|
|
07107ce9b2 | ||
|
|
2a4795596f | ||
|
|
caaaf3213d | ||
|
|
e119be513b | ||
|
|
09524fb9fe | ||
|
|
9b5e7ce19d | ||
|
|
25415342ea | ||
|
|
e39a8bbed3 | ||
|
|
d224a87828 | ||
|
|
78df244bc7 | ||
|
|
6718a1aba8 | ||
|
|
9d7c5a2b17 | ||
|
|
f4ccab0f9f | ||
|
|
4bfdb9bdf0 | ||
|
|
2b9441eeb6 | ||
|
|
9b1b3e0a74 | ||
|
|
d7a6a94808 | ||
|
|
f49cad0e32 | ||
|
|
d2f853f601 | ||
|
|
d544d42448 | ||
|
|
3d027dc7bc | ||
|
|
163e9175e9 | ||
|
|
91fda5386a | ||
|
|
63e610e07d | ||
|
|
26d6e0f56f | ||
|
|
aafbfb7277 | ||
|
|
7c4e564c92 | ||
|
|
fc5895a910 | ||
|
|
51b4d62007 | ||
|
|
497173d3e2 | ||
|
|
2118cc42f0 | ||
|
|
4a8147dae2 | ||
|
|
c9763b0623 | ||
|
|
63ecfcff6b | ||
|
|
a1670f9e1d | ||
|
|
1287cfacae | ||
|
|
d8fac09281 | ||
|
|
3ac9821907 | ||
|
|
e7a923bef6 | ||
|
|
840c1802e6 | ||
|
|
772a02f56f | ||
|
|
6a803c0550 | ||
|
|
485a5989c8 | ||
|
|
10bbead9ec | ||
|
|
aea4d1d414 | ||
|
|
3a321251f7 | ||
|
|
079a3f96eb | ||
|
|
a94bf2e9e2 | ||
|
|
92e8db7ff4 | ||
|
|
81f5cf4446 | ||
|
|
842858f9b8 | ||
|
|
415b2b4933 | ||
|
|
e243601cf0 | ||
|
|
808231dd7d | ||
|
|
44093bd88c | ||
|
|
4d7324dddf | ||
|
|
83dd78a95f | ||
|
|
d31083cabc | ||
|
|
c154581d6e | ||
|
|
2fd72258f4 | ||
|
|
67051463bd | ||
|
|
930e435ffd | ||
|
|
6b62146388 | ||
|
|
1f648f58e5 | ||
|
|
e7fb0dacc5 | ||
|
|
989c010a64 | ||
|
|
9e3f07305b | ||
|
|
9e93ebde03 | ||
|
|
8774f0480d | ||
|
|
17b33317de | ||
|
|
db4fbe8fd6 | ||
|
|
9e4c6df219 | ||
|
|
9e50680685 | ||
|
|
a02c2deb69 | ||
|
|
df5679c9d1 | ||
|
|
12c9ba07f8 | ||
|
|
7ef78fd17b | ||
|
|
d7274b85f9 | ||
|
|
4f9f0b6868 | ||
|
|
98169f9f2e | ||
|
|
99e1f22d12 | ||
|
|
59769894f3 | ||
|
|
b7e46e49d3 | ||
|
|
d96295e923 | ||
|
|
47aa9a6237 | ||
|
|
e374637df2 | ||
|
|
8e71c392ab | ||
|
|
bad7254692 | ||
|
|
0af2736327 | ||
|
|
df01822c2a | ||
|
|
8e04c6c8e0 | ||
|
|
e71b9629fe | ||
|
|
c3e3337802 | ||
|
|
f70adedfaf | ||
|
|
1edd6e8297 | ||
|
|
77a71f3445 | ||
|
|
0b6a8c11f6 | ||
|
|
08f80fe190 | ||
|
|
fe8ead6609 | ||
|
|
df8f20f208 | ||
|
|
5bf2b956f6 | ||
|
|
e218c3967e | ||
|
|
d68370ade7 | ||
|
|
8c79033819 | ||
|
|
15af2bb1a2 | ||
|
|
82d8f5df74 | ||
|
|
cb12cbef45 | ||
|
|
b8a9c520f3 | ||
|
|
bffe4b787d | ||
|
|
76db58932e | ||
|
|
7f73d35753 | ||
|
|
cd5e276102 | ||
|
|
900218e3e4 | ||
|
|
af285fbdbd | ||
|
|
d78a9fe8e3 | ||
|
|
792cbf20a9 | ||
|
|
0641437803 | ||
|
|
fa5db4fcfa | ||
|
|
bea4c628ec | ||
|
|
11e2491124 | ||
|
|
09021f3141 | ||
|
|
bd4b845290 | ||
|
|
e0e7f141ad | ||
|
|
7bdaac55e5 | ||
|
|
c473601875 | ||
|
|
bd0a1440e7 | ||
|
|
6508f47625 | ||
|
|
05a12213de | ||
|
|
e90563c437 | ||
|
|
7e8005033d | ||
|
|
6be290ed8b | ||
|
|
82735a0cfd | ||
|
|
5f5dbf5139 | ||
|
|
be3f86cd65 | ||
|
|
3df8b53570 | ||
|
|
8eafa260d2 | ||
|
|
ea5342bc70 | ||
|
|
8ffb0fe407 | ||
|
|
f448150156 | ||
|
|
6c1d5263f1 | ||
|
|
58b49486ce | ||
|
|
b2a2c7b0bd | ||
|
|
df6b2d4cdd | ||
|
|
6f84fcbf6d | ||
|
|
028ae98c21 | ||
|
|
f4d11325c6 | ||
|
|
2b83c73f8f | ||
|
|
39e1ae18a4 | ||
|
|
eb1389d738 | ||
|
|
589eb7533c | ||
|
|
fbe9cc156c | ||
|
|
b319143a67 | ||
|
|
d71a6b0ba7 | ||
|
|
5d7b64fcbf | ||
|
|
39912e025b | ||
|
|
4a3f9f1d84 | ||
|
|
8195fd50ab | ||
|
|
a64468200e | ||
|
|
6ff7662c29 | ||
|
|
d3480f70f2 | ||
|
|
2907c7ab94 | ||
|
|
1a130c794a | ||
|
|
c589c72817 | ||
|
|
695bee61c8 | ||
|
|
7c8abe0f16 | ||
|
|
07c86cd9c8 | ||
|
|
cb531f8a88 | ||
|
|
86cb91f9f2 | ||
|
|
f87a72bc15 | ||
|
|
33496419f9 | ||
|
|
4321fd364d | ||
|
|
d40cf7a3cd | ||
|
|
fa90542b00 | ||
|
|
cdc6f7d907 | ||
|
|
084d237437 | ||
|
|
62f6494299 | ||
|
|
19583bc788 | ||
|
|
fff62a85e0 | ||
|
|
e52b144510 | ||
|
|
e8d21a020f | ||
|
|
8b24877f9e | ||
|
|
6efceb2017 | ||
|
|
c28bfcf959 | ||
|
|
0b472ea463 | ||
|
|
ec82cb15ce | ||
|
|
69dba707e0 | ||
|
|
f50be50b18 | ||
|
|
90a5af60c4 | ||
|
|
33c1b788df | ||
|
|
5265627b8f | ||
|
|
94ce0ad2dd | ||
|
|
0eeb895432 | ||
|
|
5d7f10d4f8 | ||
|
|
9013d398db | ||
|
|
7c556854af | ||
|
|
ce519f006d | ||
|
|
4129551341 | ||
|
|
9be888f55a | ||
|
|
b185d1bfea | ||
|
|
19a37eb04d | ||
|
|
ca2f9b788f | ||
|
|
9a1eb4e794 | ||
|
|
592282448b | ||
|
|
e6bff4f864 | ||
|
|
1cf0bacc6e | ||
|
|
1f352967c7 | ||
|
|
cf14728757 | ||
|
|
c5278e2e95 | ||
|
|
fe1e9ca996 | ||
|
|
4ed9231983 | ||
|
|
ca1a844f08 | ||
|
|
833df59d0e | ||
|
|
7cb652b5d2 | ||
|
|
cd06284f50 | ||
|
|
1305f1dbe2 | ||
|
|
b3a8824d68 | ||
|
|
b42fb8272a | ||
|
|
36c134fcb8 | ||
|
|
d648091de4 | ||
|
|
2829c293df | ||
|
|
094d117764 | ||
|
|
0c0f7b9986 | ||
|
|
f30f955058 | ||
|
|
38e803c3c3 | ||
|
|
2c4c337907 | ||
|
|
7a1c587a9c | ||
|
|
8c59d8fb6d | ||
|
|
1623d39eea | ||
|
|
73504f80a5 | ||
|
|
95315d7f8a | ||
|
|
6577d53df8 | ||
|
|
63e44beb9c | ||
|
|
944ed03553 | ||
|
|
a5a927dd71 | ||
|
|
4153aa80a9 | ||
|
|
2a574ef267 | ||
|
|
1767b7a87b | ||
|
|
db3e2ae183 | ||
|
|
340b8d3136 | ||
|
|
39649e9e11 | ||
|
|
6bc1e1c3d9 | ||
|
|
2997633d0d | ||
|
|
e0cf1301fa | ||
|
|
ed15b7e551 | ||
|
|
863604d3a5 | ||
|
|
f750a43b87 | ||
|
|
b13ee73546 | ||
|
|
377751ab28 | ||
|
|
e1d3677f58 | ||
|
|
559b07da63 | ||
|
|
b91e3c6ab1 | ||
|
|
7767fdd933 | ||
|
|
0bd8754064 | ||
|
|
bedfc47273 | ||
|
|
f376142d57 | ||
|
|
0cce8fb34c | ||
|
|
5caa85ffa5 | ||
|
|
c0c6d4b572 | ||
|
|
7516800c62 | ||
|
|
cb465d789f | ||
|
|
25fa3543f2 | ||
|
|
cb81894632 | ||
|
|
18921e720a | ||
|
|
09e18c1164 | ||
|
|
637e44d8d2 | ||
|
|
82ce160093 | ||
|
|
04e5c7e484 | ||
|
|
09586df300 | ||
|
|
534285324d | ||
|
|
af2514755b | ||
|
|
e6dc4d71b6 | ||
|
|
dae0f59911 | ||
|
|
c7f523ae46 | ||
|
|
288e1ba907 | ||
|
|
d4f15a2f96 | ||
|
|
fb3c70126e | ||
|
|
a1cae77142 | ||
|
|
868959499c | ||
|
|
9ff7df0f71 | ||
|
|
692da9d5e2 | ||
|
|
2a2c8a5ac3 | ||
|
|
8bb6861efc | ||
|
|
994e3cf708 | ||
|
|
edbddf0fd5 | ||
|
|
3e0fbbbd90 | ||
|
|
74a5975afc | ||
|
|
9304a7f137 | ||
|
|
ee675a19b5 | ||
|
|
9d92d273e4 | ||
|
|
06aeb403dd | ||
|
|
14baaf9154 | ||
|
|
609cca7fc0 | ||
|
|
4a9f1a2d56 | ||
|
|
5958f9126a | ||
|
|
599e24cf91 | ||
|
|
eea97601b5 | ||
|
|
d88f4d6488 | ||
|
|
59dc59c318 | ||
|
|
7195ec9856 | ||
|
|
f819db3ac5 | ||
|
|
6839d1c3d1 | ||
|
|
91c04a2cfe | ||
|
|
845276bac3 | ||
|
|
1106898454 | ||
|
|
1cb838afe5 | ||
|
|
dd6e706412 | ||
|
|
75df49cd03 | ||
|
|
87a52efaae | ||
|
|
94b6a418c7 | ||
|
|
347dca5e60 | ||
|
|
f7a3d65e0c | ||
|
|
455ffd827a | ||
|
|
20cab0c235 | ||
|
|
5581ecb643 | ||
|
|
9a8bfc0217 | ||
|
|
bcf2ddefba | ||
|
|
ef382c125a | ||
|
|
1a7e2f42d4 | ||
|
|
6aaa40fef3 | ||
|
|
0a5a3a9dd4 | ||
|
|
aa60444ca4 | ||
|
|
c4ede0d7ae | ||
|
|
f2b61fb399 | ||
|
|
9bab9769e4 | ||
|
|
408101f7eb | ||
|
|
0110954518 | ||
|
|
988c61f2e1 | ||
|
|
011d74bb4d | ||
|
|
cf71eda1ad | ||
|
|
a6c8af28f2 | ||
|
|
14704a3415 | ||
|
|
9bbff82c73 | ||
|
|
ce30c433ba | ||
|
|
04da71448f | ||
|
|
c17dcb1835 | ||
|
|
6e5531adcc | ||
|
|
ad6ab9b95b | ||
|
|
ad6cbfb328 | ||
|
|
9b8b7e0dce | ||
|
|
1cb5dbf99b | ||
|
|
f08f72c90a | ||
|
|
46116362c5 | ||
|
|
98e8a0f041 | ||
|
|
8cd3352af7 | ||
|
|
2c85c93136 | ||
|
|
9251ec56ce | ||
|
|
deff6c9ec1 | ||
|
|
3fa4a8dbdc | ||
|
|
bf2d996bd0 | ||
|
|
79709b2372 | ||
|
|
584b9cadd7 | ||
|
|
2f1057f3c3 | ||
|
|
374bcacddd | ||
|
|
94c7fbda6b | ||
|
|
a049152e99 | ||
|
|
7686163957 | ||
|
|
ca62bd67ed | ||
|
|
ac2b864aaa | ||
|
|
1904330ebb | ||
|
|
876922c547 | ||
|
|
4e0a879c4b | ||
|
|
b258a1d159 | ||
|
|
df33974f88 | ||
|
|
8221bc3f04 | ||
|
|
82750b238a | ||
|
|
6b0ad43fb6 | ||
|
|
d55451195e | ||
|
|
9cff51b6bb | ||
|
|
771eb9c875 | ||
|
|
12fec3026b | ||
|
|
df80f64598 | ||
|
|
ada29fd266 | ||
|
|
07ad4cf2e0 | ||
|
|
c07cfc7210 | ||
|
|
c3243cc243 | ||
|
|
2d52ffa2a4 | ||
|
|
f2156292e4 | ||
|
|
4cb0ca42e3 | ||
|
|
3737249459 | ||
|
|
fecca89447 | ||
|
|
080e40d1da | ||
|
|
4c77bc7edf | ||
|
|
334e9d4abf | ||
|
|
b1404d8bbf | ||
|
|
6fd62e6ebd | ||
|
|
f01730e722 | ||
|
|
d4bd640280 | ||
|
|
4e053b234b | ||
|
|
6b9b2a45ab | ||
|
|
698e49d595 | ||
|
|
15886a64b1 | ||
|
|
d4844ab7ed | ||
|
|
94721d06de | ||
|
|
417b12129d | ||
|
|
fc391736ec | ||
|
|
c42fc4fc6f | ||
|
|
4360340bd4 | ||
|
|
72ffa6a052 | ||
|
|
2fc8a12138 | ||
|
|
842076e3b9 | ||
|
|
44cac0de49 | ||
|
|
2dc097ecb6 | ||
|
|
966bc0a0b9 | ||
|
|
03d81a7429 | ||
|
|
d6a556cd31 | ||
|
|
1c36ff40ba | ||
|
|
60fc558a3b | ||
|
|
ce5dfe148d | ||
|
|
9a8e3ba09c | ||
|
|
06066e0c52 | ||
|
|
f10cee9f58 | ||
|
|
6922d3ca2c | ||
|
|
a10b403748 | ||
|
|
6c1a55644e | ||
|
|
64f5554c90 | ||
|
|
c2a368534f | ||
|
|
9274925ddf | ||
|
|
5725562435 | ||
|
|
5f6fe0288c | ||
|
|
d5973346ec | ||
|
|
c23c65596f | ||
|
|
7e1ca2ce51 | ||
|
|
ba1674a9d3 | ||
|
|
fb4e20e364 | ||
|
|
911302c918 | ||
|
|
2d387c4b6a | ||
|
|
d8e7b95e07 | ||
|
|
5e23c5d5e1 | ||
|
|
40d9cc3293 | ||
|
|
d191b6cedc | ||
|
|
b13c816ecb | ||
|
|
3b0866bfe1 | ||
|
|
95e0b6fe6a | ||
|
|
4cf8a32c1e | ||
|
|
e04fc5edb7 | ||
|
|
ef4431e8b1 | ||
|
|
865946b97d | ||
|
|
b024d8f44a | ||
|
|
1d3f2c1da8 | ||
|
|
49bb57478c | ||
|
|
278c78e4f4 | ||
|
|
0ba4e49106 | ||
|
|
789c13f792 | ||
|
|
667e257d64 | ||
|
|
3f7728d328 | ||
|
|
3fb6b7c51c | ||
|
|
16e428c5ae | ||
|
|
04dcb4cf60 | ||
|
|
2de73b50fe | ||
|
|
04541c7e27 | ||
|
|
514a90805d | ||
|
|
0e66e63086 | ||
|
|
da58874390 | ||
|
|
52aa0ac031 | ||
|
|
80511c9337 | ||
|
|
4e922b976e | ||
|
|
bfe496e22a | ||
|
|
1a898ac834 | ||
|
|
b5b4a88775 | ||
|
|
73cd575ea1 | ||
|
|
bff65254a1 | ||
|
|
be27e65df2 | ||
|
|
2e7cfc5cf1 | ||
|
|
4a3287457d | ||
|
|
e07f3a41cb | ||
|
|
b4a628b3e5 | ||
|
|
d2ee8e873b | ||
|
|
eb6295e375 | ||
|
|
cc774b83d4 | ||
|
|
020c7e70fd | ||
|
|
f4b455dd98 | ||
|
|
b0d9c53688 | ||
|
|
b30a801f25 | ||
|
|
260673fcea | ||
|
|
6f0888e30b | ||
|
|
0a81104723 | ||
|
|
4cd9c847f3 | ||
|
|
14c4e553dd | ||
|
|
2cf4f7e4e7 | ||
|
|
09b76c601a | ||
|
|
173d41522e | ||
|
|
d64196eff0 | ||
|
|
45fa09d9cb | ||
|
|
2e1d2116b1 | ||
|
|
a17249eef6 | ||
|
|
1ce3b3486d | ||
|
|
404b205f31 | ||
|
|
a2ea205239 | ||
|
|
b9d98a3aa3 | ||
|
|
5990dbce08 | ||
|
|
de12c0ae0c | ||
|
|
69db392407 | ||
|
|
a43429f658 | ||
|
|
32b2ed5093 | ||
|
|
4ca0f86c74 | ||
|
|
8fffa4b5e9 | ||
|
|
aa1bc354cb | ||
|
|
b42fb9c97c | ||
|
|
c7ae91edef | ||
|
|
9f60839faf | ||
|
|
9d859066f7 | ||
|
|
6b3d5b39ba | ||
|
|
9fd95d8ba6 | ||
|
|
b5258c494a | ||
|
|
b8826835e2 | ||
|
|
c930d1a32e | ||
|
|
18e63d9700 | ||
|
|
dfd04a45fe | ||
|
|
7b79b04bad | ||
|
|
20a22e6a31 | ||
|
|
c409dde698 | ||
|
|
302192f7fe | ||
|
|
8885bb0c35 | ||
|
|
cdf6a21276 | ||
|
|
b2ca49edfe | ||
|
|
eda4cdffa7 | ||
|
|
1d77af86e7 | ||
|
|
ae49a7ca24 | ||
|
|
c321432392 | ||
|
|
d2204fdb11 | ||
|
|
7b324b7153 | ||
|
|
f00ca7c7f9 | ||
|
|
bf21913708 | ||
|
|
92cb2140aa | ||
|
|
599260f2e5 | ||
|
|
4c44934d7a | ||
|
|
b08d6c9837 | ||
|
|
ce5badaf78 | ||
|
|
2c18b8129c | ||
|
|
83e95705ea | ||
|
|
fd7f291b87 | ||
|
|
1d16bb2a04 | ||
|
|
2bf5828c17 | ||
|
|
bd5fb3896b | ||
|
|
a42e9ff90f | ||
|
|
2a4dded277 | ||
|
|
45e374221c | ||
|
|
b4f37f46cc | ||
|
|
ecd7f61956 | ||
|
|
11483057e5 | ||
|
|
4382b577ae | ||
|
|
fe6fafdbfb | ||
|
|
20e36e8190 | ||
|
|
65d0576a91 | ||
|
|
b3a342c796 | ||
|
|
7e35461c08 | ||
|
|
0a22d601fd | ||
|
|
4f4832f67f | ||
|
|
214b2dc053 | ||
|
|
c323917db9 | ||
|
|
5575e65eb6 | ||
|
|
a410654575 | ||
|
|
ea17916de7 | ||
|
|
db8abecc68 | ||
|
|
621e1692c9 | ||
|
|
aa5447c072 | ||
|
|
280c275c4e | ||
|
|
5ed2b6070e | ||
|
|
a614a8ecfc | ||
|
|
b5eca62785 | ||
|
|
a69b0e337e | ||
|
|
5a25de0885 | ||
|
|
4c4d5c2310 | ||
|
|
e99b4716c6 | ||
|
|
e7a79cf1c8 | ||
|
|
378df6c06a | ||
|
|
c005602e8f | ||
|
|
3f65b059f6 | ||
|
|
1c773fb3ca | ||
|
|
ffab766a38 | ||
|
|
8bebea455a | ||
|
|
c2b98654fc | ||
|
|
8d58adc848 | ||
|
|
5ab36f0629 | ||
|
|
4437766a2a | ||
|
|
787630e9de | ||
|
|
a62d13468c | ||
|
|
a42dba8316 | ||
|
|
00948ec261 | ||
|
|
c6c4f54f79 | ||
|
|
3b06c0a18e | ||
|
|
62efff7b97 | ||
|
|
9f9b4e8430 | ||
|
|
ff3de3a2b4 | ||
|
|
98876e99bb | ||
|
|
033402c261 | ||
|
|
43ceefde5f | ||
|
|
322060024c | ||
|
|
bb9d6fa4c5 | ||
|
|
d96a8d031a | ||
|
|
1a407d3fb3 | ||
|
|
5fce4b3408 | ||
|
|
4b4b8657a0 | ||
|
|
31ebefefe1 | ||
|
|
62226e71e7 | ||
|
|
7be17c9656 | ||
|
|
b7dc661fe7 | ||
|
|
33be5b0372 | ||
|
|
73034ed9d2 | ||
|
|
c58195f20d | ||
|
|
1cf11d31fe | ||
|
|
34469c72b4 | ||
|
|
5b6ff638e3 | ||
|
|
df40777e5f | ||
|
|
070edd9ad4 | ||
|
|
438945c691 | ||
|
|
4547b5775f | ||
|
|
5535311087 | ||
|
|
6dbf200cc3 | ||
|
|
778cb6f473 | ||
|
|
1cf0d17449 | ||
|
|
a9261477ba | ||
|
|
a86ba780ec | ||
|
|
484d810896 | ||
|
|
2e59f68e22 | ||
|
|
45ae61d17d | ||
|
|
66b62ee4f0 | ||
|
|
41f619c1ff | ||
|
|
b33ad0d271 | ||
|
|
d3f78a9354 | ||
|
|
85cc7caf18 | ||
|
|
c10927a7ae | ||
|
|
5ee68a653f | ||
|
|
f1f7b32980 | ||
|
|
8aa66b7ed0 | ||
|
|
de8c63e263 | ||
|
|
0779085d30 | ||
|
|
15e9942eee | ||
|
|
ca0e1cb2c1 | ||
|
|
7c623b7314 | ||
|
|
ade14624e8 | ||
|
|
c722aa6e49 | ||
|
|
260072b97f | ||
|
|
23e41970f2 | ||
|
|
581e808733 | ||
|
|
2ce5010f26 | ||
|
|
357449a95f | ||
|
|
5d990772b5 | ||
|
|
e760c58522 | ||
|
|
679094c6f1 | ||
|
|
5be84cace3 | ||
|
|
0ada262dcd | ||
|
|
9203388d6c | ||
|
|
f516809959 | ||
|
|
f49f8d6aea | ||
|
|
4c2ebf53b6 | ||
|
|
e41b44ff1d | ||
|
|
1bcb937fe3 | ||
|
|
d0600a697e | ||
|
|
3dfad4b251 | ||
|
|
486f35d1bf | ||
|
|
27e6507a5e | ||
|
|
0b07eedcfc | ||
|
|
1ab3a289c7 | ||
|
|
7f1d65c765 | ||
|
|
2c9f289188 | ||
|
|
59789a3c25 | ||
|
|
5a984a95ba | ||
|
|
7af854a57c | ||
|
|
130bac0c83 | ||
|
|
5bbb00d589 | ||
|
|
d9c9647919 | ||
|
|
54c73bdbc3 | ||
|
|
c6726f10f3 | ||
|
|
81071bb69a | ||
|
|
aff9bcf08e | ||
|
|
caeecf111e | ||
|
|
f9bc01cca6 | ||
|
|
8333d15f12 | ||
|
|
07ae236642 | ||
|
|
8ece00541f | ||
|
|
acbac94685 | ||
|
|
26f45732da | ||
|
|
547adbfaba | ||
|
|
6ac6a38bf1 | ||
|
|
59eeb39b8c | ||
|
|
ae7bb818cc | ||
|
|
ceda6a9869 | ||
|
|
157de87f15 | ||
|
|
6fb90421f9 | ||
|
|
8bb14d1a1f | ||
|
|
f8c714a4e1 | ||
|
|
6a9922eaa3 | ||
|
|
ea35421a4f | ||
|
|
948d0590b4 | ||
|
|
dd56493543 | ||
|
|
01c50727ac | ||
|
|
032d6a15a9 | ||
|
|
ac0aae23fa | ||
|
|
8dbea5eeb8 | ||
|
|
03ddd51063 | ||
|
|
03591b33ce | ||
|
|
ace67bf6ea | ||
|
|
de6c5582ce | ||
|
|
5bf9db07a8 | ||
|
|
40fba4f304 | ||
|
|
0d8fc66bc8 | ||
|
|
107946d012 | ||
|
|
9eaba0acc2 | ||
|
|
e7add258b0 | ||
|
|
d3f89c1042 | ||
|
|
89bdef89dc | ||
|
|
1e2b6460a3 | ||
|
|
a6831ef217 | ||
|
|
e0395ab51a | ||
|
|
5334c44451 | ||
|
|
27d57ab1b0 | ||
|
|
1d998e4709 | ||
|
|
5492df3a43 | ||
|
|
9dad552a4e | ||
|
|
9fa373b493 | ||
|
|
932c05c64b | ||
|
|
1dad62d7ae | ||
|
|
bce17561ed | ||
|
|
bac77085da | ||
|
|
816e792770 | ||
|
|
634a8a06fc | ||
|
|
2cc153abea | ||
|
|
a1cee67e15 | ||
|
|
60fff3f82f | ||
|
|
1c712a7448 | ||
|
|
facac997f1 | ||
|
|
8d05393ba0 | ||
|
|
03fa181c2d | ||
|
|
6ab508415c | ||
|
|
92931ff541 | ||
|
|
ee0811b097 | ||
|
|
76f2d72d30 | ||
|
|
a5ac021076 | ||
|
|
f693d49f95 | ||
|
|
c2b5fe7f28 | ||
|
|
2f5c690175 | ||
|
|
8ed93bb0e4 | ||
|
|
f266583a47 | ||
|
|
1d08e8543f | ||
|
|
03418796ab | ||
|
|
b93a3902dc | ||
|
|
c14af70287 | ||
|
|
3e4a289cc5 | ||
|
|
5b504bcd4e | ||
|
|
d53074c9ea | ||
|
|
f8f3cd33ce | ||
|
|
4964fccd7e | ||
|
|
5f46aa1444 | ||
|
|
16d5f8830e | ||
|
|
bbafbf1ffd | ||
|
|
2fdcd1e772 | ||
|
|
2b680f861c | ||
|
|
c9f9e1b2f0 | ||
|
|
1d3ff1b6c0 | ||
|
|
8d2674eaf2 | ||
|
|
458c9f30fb | ||
|
|
e1dd3784e2 | ||
|
|
417eb20a3e | ||
|
|
648751445a | ||
|
|
5b4199aca2 | ||
|
|
29a74af3bd | ||
|
|
60554601bd | ||
|
|
c112f093a8 | ||
|
|
c400a8a2ba | ||
|
|
0c240c398e | ||
|
|
d6e47f35d4 | ||
|
|
045276d7bf | ||
|
|
22758e9a4a | ||
|
|
05e70efc4f | ||
|
|
61091ad95a | ||
|
|
5c5a2f6a07 | ||
|
|
c9d8cb47d0 | ||
|
|
c449de9710 | ||
|
|
f8fb23b9f2 | ||
|
|
0d7edb9d0a | ||
|
|
99a59efdbf | ||
|
|
04cf483161 | ||
|
|
213238ce38 | ||
|
|
baf7746986 | ||
|
|
e8bd7363c8 | ||
|
|
ca2a9ca725 | ||
|
|
0169a5477c | ||
|
|
328327bea6 | ||
|
|
8951441311 | ||
|
|
f439a5c5a4 | ||
|
|
fef0e7e1f8 | ||
|
|
49fb506628 | ||
|
|
b754fa56b9 | ||
|
|
c67f7b66aa | ||
|
|
71c296391d | ||
|
|
b75a354505 | ||
|
|
a8cb9aabf1 | ||
|
|
99b427f224 | ||
|
|
17bd4a2fa8 | ||
|
|
81a5d228d4 | ||
|
|
ce8cf62cd8 | ||
|
|
46d5c81b57 | ||
|
|
802f09b947 | ||
|
|
6848eff404 | ||
|
|
82ec8af3aa | ||
|
|
30cbebf527 | ||
|
|
ee689cbb9f | ||
|
|
b065d75beb | ||
|
|
1a212868a0 | ||
|
|
174cff3eac | ||
|
|
67677e06b8 | ||
|
|
16668f3fb9 | ||
|
|
d3f615fe30 | ||
|
|
cea600b265 | ||
|
|
7b47965509 | ||
|
|
14395bc5cd | ||
|
|
87db55b4ac | ||
|
|
3fcb731621 | ||
|
|
82eadd3983 | ||
|
|
d20aa57508 | ||
|
|
4cb9e5cc04 | ||
|
|
bd21cd0c48 | ||
|
|
6e9d3223c8 | ||
|
|
ba826df963 | ||
|
|
6987914a2c | ||
|
|
bb78e74646 | ||
|
|
f693413e26 | ||
|
|
87366d11ca | ||
|
|
d7e3b61210 | ||
|
|
4f6b907e3a | ||
|
|
a2eaccfc48 | ||
|
|
864e218e20 | ||
|
|
319067c537 | ||
|
|
f18bd8af24 | ||
|
|
3942de94f6 | ||
|
|
5d6dc2e1a6 | ||
|
|
478c86d3a6 | ||
|
|
173041e03a | ||
|
|
1fa84b4f7d | ||
|
|
ef97279a67 | ||
|
|
b064a84fd0 | ||
|
|
edecb1ca73 | ||
|
|
3040fb8c7a | ||
|
|
a55b94b08a | ||
|
|
b898b04168 | ||
|
|
b12b56d13f | ||
|
|
ca91f8f49f | ||
|
|
989f799766 | ||
|
|
4a418a6691 | ||
|
|
c6243cbfd9 | ||
|
|
1a9867593b | ||
|
|
e74af5ad53 | ||
|
|
7ab516e715 | ||
|
|
6442307c27 | ||
|
|
fd1e10d29e | ||
|
|
1e534cfc9f | ||
|
|
05abf8b041 | ||
|
|
fceaf9eb06 | ||
|
|
d4186ba774 | ||
|
|
6fd1f8fbb0 | ||
|
|
9592e67af2 | ||
|
|
67916a4efb | ||
|
|
edc7f9e5d5 | ||
|
|
3b0e5d8c44 | ||
|
|
0a67a788e4 | ||
|
|
1f4a30395b | ||
|
|
61cf5bef9b | ||
|
|
01c1b308ca | ||
|
|
892c6f5c61 | ||
|
|
09e379214a | ||
|
|
f595e94e82 | ||
|
|
1adf52bb04 | ||
|
|
a141e5d4f4 | ||
|
|
20beb2eec1 | ||
|
|
782de278e5 | ||
|
|
e535cf566b | ||
|
|
c081e83aae | ||
|
|
beb9288c73 | ||
|
|
4fa09480c4 | ||
|
|
ef1e1e5551 | ||
|
|
09e32c0b3c | ||
|
|
c72015394d | ||
|
|
04a8262712 | ||
|
|
cd598a1cf8 | ||
|
|
2c6576b162 | ||
|
|
444ae43aa4 | ||
|
|
56870dd5c5 | ||
|
|
330882cad4 | ||
|
|
a11b95ef56 | ||
|
|
120385b819 | ||
|
|
4e5b68149a | ||
|
|
3f203b4d94 | ||
|
|
c94427ef2c | ||
|
|
6158846438 | ||
|
|
3e6022b000 | ||
|
|
3bcda9ae1f | ||
|
|
7b2c7b6ccc | ||
|
|
537ddd9b4a | ||
|
|
942817b4f6 | ||
|
|
e8fe940287 | ||
|
|
eb086dab3e | ||
|
|
40187b0bbc | ||
|
|
8d1a03d087 | ||
|
|
50c22d9457 | ||
|
|
ee6d863f57 | ||
|
|
fe7a8aa3e9 | ||
|
|
b6986087a3 | ||
|
|
c1cc83e363 | ||
|
|
791b7cc7b8 | ||
|
|
add8662737 | ||
|
|
10e7aba7c0 | ||
|
|
f59134d191 | ||
|
|
adcc3327ae | ||
|
|
ed84ac348e | ||
|
|
607bc02c79 | ||
|
|
38fb41909b | ||
|
|
a3e458ba49 | ||
|
|
043c1aef11 | ||
|
|
10e88b7f57 | ||
|
|
4ec4de1d43 | ||
|
|
9bce334c65 | ||
|
|
795bb86148 | ||
|
|
d87babfd92 | ||
|
|
e43e7e8534 | ||
|
|
b3b825470d | ||
|
|
c74eb9a88b | ||
|
|
fc92dba498 | ||
|
|
1876e3f219 | ||
|
|
5ffcdb5de4 | ||
|
|
151081e533 | ||
|
|
637d0fb1dd | ||
|
|
75ae6ba4db | ||
|
|
e41b115a59 | ||
|
|
08793c9231 | ||
|
|
311cf769df | ||
|
|
1e22118b39 | ||
|
|
89046b536a | ||
|
|
27a1bb564e | ||
|
|
cb11e6bcd2 | ||
|
|
1f1d6ceecf | ||
|
|
be12b629a1 | ||
|
|
c57e59d76a | ||
|
|
3c1cf4e963 | ||
|
|
c74f540ed5 | ||
|
|
16883beeb0 | ||
|
|
a34bcd60ed | ||
|
|
4f58758234 | ||
|
|
204bb600ab | ||
|
|
c0a120106b | ||
|
|
f7de25b73c | ||
|
|
af2696e71d | ||
|
|
a51197eaae | ||
|
|
0567e9286f | ||
|
|
a03452eaf1 | ||
|
|
325442207c | ||
|
|
bf93beb33e | ||
|
|
b2b504cca3 | ||
|
|
c72376b0c6 | ||
|
|
69f33c5d95 | ||
|
|
0591b7ef49 | ||
|
|
9942bf7e19 | ||
|
|
1471cfac38 | ||
|
|
90a2644d62 | ||
|
|
6a1aa4c5d3 | ||
|
|
5ed8fb87b1 | ||
|
|
c1307fc213 | ||
|
|
9f27973147 | ||
|
|
2a1deb1a76 | ||
|
|
41e370fd2e | ||
|
|
5d96e49354 | ||
|
|
efdd4fae68 | ||
|
|
1acfaa8157 | ||
|
|
02670f5558 | ||
|
|
789b694519 | ||
|
|
5d570f6d84 | ||
|
|
2022f6a792 | ||
|
|
941129f460 | ||
|
|
1a060aa6d7 | ||
|
|
127976cd74 | ||
|
|
fb30819765 | ||
|
|
e9cc4601eb | ||
|
|
1e40f71ff0 | ||
|
|
780035657a | ||
|
|
3648b47570 | ||
|
|
20cd5111ac | ||
|
|
e92dccb21b | ||
|
|
2081647443 | ||
|
|
98f72f9378 | ||
|
|
a481999a24 | ||
|
|
d840f9d0c7 | ||
|
|
c2b6417372 | ||
|
|
9cc654909c | ||
|
|
42394bf723 | ||
|
|
37c6413fa0 | ||
|
|
e55718caa7 | ||
|
|
59f3ef6fab | ||
|
|
f7bbea248c | ||
|
|
94412da2de | ||
|
|
31fdcfdfbb | ||
|
|
ed974844e4 | ||
|
|
5886bf4c80 | ||
|
|
a33502d5aa | ||
|
|
418c47e426 | ||
|
|
384b4b9413 | ||
|
|
8248ac2516 | ||
|
|
e108f555c3 | ||
|
|
925e8df36e | ||
|
|
8f4972aab9 | ||
|
|
e0314eecd0 | ||
|
|
5b29d5449b | ||
|
|
8c939d0050 | ||
|
|
26c189aa73 | ||
|
|
5ffe4b3168 | ||
|
|
22f92bad55 | ||
|
|
84a16c72ff | ||
|
|
0a7800d3ea | ||
|
|
9f26c51d47 | ||
|
|
bf6d3aac07 | ||
|
|
9aff8d9b62 | ||
|
|
02ecdf6cf7 | ||
|
|
d637ccd8ed | ||
|
|
25e0209026 | ||
|
|
86cdb905db | ||
|
|
4e410f56e6 | ||
|
|
5bc8837298 | ||
|
|
4cc9118b4d | ||
|
|
1258067264 | ||
|
|
e1da184702 | ||
|
|
fa30cd9028 | ||
|
|
4274a6da76 | ||
|
|
8f034b08d4 | ||
|
|
43b68c5b22 | ||
|
|
3160bdaa00 | ||
|
|
4e1334dbd2 | ||
|
|
60afa1431a | ||
|
|
64153da3bd | ||
|
|
bcf007376d |
No files matched your search
@@ -2,3 +2,6 @@ root = true
|
||||
|
||||
[*.{h,cpp}]
|
||||
indent_style = tab
|
||||
|
||||
[*.sdr]
|
||||
indent_style = tab
|
||||
+5
-30
@@ -1,33 +1,3 @@
|
||||
*.o
|
||||
*.a
|
||||
.dirstamp
|
||||
libtool
|
||||
ltmain.sh
|
||||
m4/libtool.m4
|
||||
m4/ltoptions.m4
|
||||
m4/ltsugar.m4
|
||||
m4/ltversion.m4
|
||||
m4/lt~obsolete.m4
|
||||
compile
|
||||
.deps/
|
||||
code/.deps/
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
config.*
|
||||
code/fs2_open_*
|
||||
code/wxFRED2_*
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
missing
|
||||
.svn
|
||||
*.layout
|
||||
projects/Xcode/Frameworks/
|
||||
|
||||
#========
|
||||
|
||||
#OS junk files
|
||||
[Tt]humbs.db
|
||||
*.DS_Store
|
||||
@@ -281,3 +251,8 @@ documentation/doxygen/*
|
||||
|
||||
.idea/*
|
||||
projects/*
|
||||
/.vs
|
||||
CMakeSettings.json
|
||||
|
||||
# Weird files created by Linux
|
||||
.fuse_hidden*
|
||||
@@ -1,6 +1,3 @@
|
||||
[submodule "cmake/external/cotire"]
|
||||
path = cmake/external/cotire
|
||||
url = https://github.com/sakra/cotire.git
|
||||
[submodule "cmake/external/rpavlik-cmake-modules"]
|
||||
path = cmake/external/rpavlik-cmake-modules
|
||||
url = https://github.com/asarium/cmake-modules.git
|
||||
+66
-35
@@ -6,18 +6,16 @@ cache:
|
||||
- $HOME/cmake
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
packages: &global_deps
|
||||
- ninja-build
|
||||
- libopenal-dev
|
||||
- libogg-dev
|
||||
- libvorbis-dev
|
||||
- libtheora-dev
|
||||
- libreadline6-dev
|
||||
- libpng12-dev
|
||||
- libjpeg62-dev
|
||||
- liblua5.1-0-dev
|
||||
- libjansson-dev
|
||||
- libsdl2-dev
|
||||
- valgrind
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "scp-fs2open/fs2open.github.com"
|
||||
@@ -25,25 +23,6 @@ addons:
|
||||
build_command: "ci/travis/script.sh"
|
||||
# must match TRAVIS_BRANCH check below
|
||||
branch_pattern: coverity_scan
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "Wdt4Ccefo7a0ZDjEJQJgpghh7n72FtNJuKSAPUvoz4gtEX6Ct9J8yJI1t9V3jE3CTbbLJ21/Q6eZRDfT7UfNJe5DdepoJsP9DeFhKMWqQCq+AChqQWlm0KeZAffJoJreL8vXYhnRYcLT9ceZHEH6AqwN9TPV+xJziGPISAkYNZ8="
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: "/tmp/builds/*"
|
||||
on:
|
||||
condition: '"$RELEASE_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: bintray
|
||||
user: sirknightly
|
||||
key:
|
||||
secure: "CZtvDW/zPf1Nxru21i8Wd+9hgiBRA8VowWBX0gmCOGgRq9WHISttKQQmBWGHuyVZ3rYvtE4Va2bR+2qRN+TFNkUUuOCOQkdBJTCal9nS3G/LprEmsOashG0Q5PTfMMBnlKzKxaxGJW6UhFj2GySmHEAjsFLVpuNWGJeeZgZQ3UE="
|
||||
file: ci/bintray.json
|
||||
on:
|
||||
condition: '"$NIGHTLY_BUILD" == true'
|
||||
tags: true
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
@@ -51,27 +30,81 @@ env:
|
||||
# also note that fork's don't get access to secure keys
|
||||
# you have to test using a branch in the main repo
|
||||
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
|
||||
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
|
||||
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
|
||||
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
|
||||
# These declarations set FS2DOWNLOADS_USER and FS2DOWNLOADS_PASSWORD
|
||||
- secure: "h6GbMX2jLsW1bS9fCM9fthOSJ1nfQQIRWi6EUH2p8u4NFLD5Bfi/C8JhQPKHUzyo3wvKkSHl+PsW7bgr1oXLusRwAur/dtv2N3imqvtbfIz305b00hZlsvbcYmQmUzQFSAdOGShK57JJ5aKQKccaUBP25KqB7Q+JaqBRdaMBS54="
|
||||
- secure: "fUDAPAUUaaYZy8I4zU3SJ0JcK7aw4eb6eTdaEr7LyNyTMSfPgwY6P1MrbSQC0lJNQIUQ5ffjdxE5g7D7OYpoJF9L14ni4UY8t2QASt7kmpgcYihmjeuYy8FQXgmFG8CTxiWBPKTybZJ7voQcvIvRaNG7b2wM9PMfc5lRIondB6c="
|
||||
deploy:
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "Wdt4Ccefo7a0ZDjEJQJgpghh7n72FtNJuKSAPUvoz4gtEX6Ct9J8yJI1t9V3jE3CTbbLJ21/Q6eZRDfT7UfNJe5DdepoJsP9DeFhKMWqQCq+AChqQWlm0KeZAffJoJreL8vXYhnRYcLT9ceZHEH6AqwN9TPV+xJziGPISAkYNZ8="
|
||||
skip_cleanup: true
|
||||
file_glob: true
|
||||
file: "/tmp/builds/*"
|
||||
on:
|
||||
condition: '"$RELEASE_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: '"$NIGHTLY_BUILD" == true'
|
||||
tags: true
|
||||
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
script: bash ci/travis/ftp_deploy.sh
|
||||
on:
|
||||
condition: $TEST_BUILD = true
|
||||
all_branches: true
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# note that gcc Debug MUST be 1st for Coverity
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: CONFIGURATION="Debug"
|
||||
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
- *global_deps
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Debug" CC=clang CXX=clang++
|
||||
env: CONFIGURATION="Debug" CC=clang-3.6 CXX=clang++-3.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise
|
||||
packages:
|
||||
- clang-3.6
|
||||
- libc++-dev
|
||||
- *global_deps
|
||||
- os: osx
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Debug"
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: CONFIGURATION="Release"
|
||||
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
- *global_deps
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Release" CC=clang CXX=clang++
|
||||
env: CONFIGURATION="Release" CC=clang-3.6 CXX=clang++-3.6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise
|
||||
packages:
|
||||
- clang-3.6
|
||||
- libc++-dev
|
||||
- *global_deps
|
||||
- os: osx
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Release"
|
||||
before_install:
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
@@ -89,5 +122,3 @@ before_script:
|
||||
- "./ci/travis/before_script.sh"
|
||||
script:
|
||||
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
|
||||
before_deploy:
|
||||
- "./ci/travis/before_deploy.sh"
|
||||
+10
-9
@@ -53,7 +53,7 @@ endif()
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/finder")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire/CMake")
|
||||
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire")
|
||||
|
||||
IF(RESET_INSTALL_PREFIX)
|
||||
IF(NOT $ENV{FS2PATH} STREQUAL "")
|
||||
@@ -81,6 +81,8 @@ ENDIF(WIN32)
|
||||
|
||||
OPTION(FSO_BUILD_TOOLS "Build tools related to FSO" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_TESTS "Build unit tests" OFF)
|
||||
|
||||
OPTION(FSO_DEVELOPMENT_MODE "Generate binaries in development mode, only use if you know what you're doing!" OFF)
|
||||
|
||||
OPTION(FSO_BUILD_WXFRED2 "Build wxFRED2 binary" OFF)
|
||||
@@ -106,21 +108,16 @@ SET(FSO_RUN_ARGUMENTS "" CACHE STRING "Additional arguments passed to a generate
|
||||
|
||||
option(FSO_INSTALL_DEBUG_FILES "Install some debug files (currently only PDB files on windows)" OFF)
|
||||
|
||||
OPTION(COTIRE_ENABLE "Enable cotire, this speeds up builds but may cause issues while developing (default = OFF)" OFF)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
|
||||
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
|
||||
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
|
||||
MARK_AS_ADVANCED(FORCE FSO_USE_LUAJIT)
|
||||
MARK_AS_ADVANCED(FORCE FSO_DEVELOPMENT_MODE)
|
||||
MARK_AS_ADVANCED(FORCE FSO_FATAL_WARNINGS)
|
||||
MARK_AS_ADVANCED(FORCE COTIRE_ENABLE)
|
||||
mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
|
||||
|
||||
IF(COTIRE_ENABLE)
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
ENDIF(COTIRE_ENABLE)
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
|
||||
INCLUDE(globals)
|
||||
INCLUDE(toolchain)
|
||||
@@ -154,6 +151,10 @@ IF(FSO_BUILD_WXFRED2)
|
||||
ADD_SUBDIRECTORY(wxfred2)
|
||||
ENDIF(FSO_BUILD_WXFRED2)
|
||||
|
||||
if(FSO_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_VERSION}" VERSION_GREATER "3.5")
|
||||
# Default to using Freespace2 as startup project if CMake supports it.
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Freespace2)
|
||||
@@ -183,4 +184,4 @@ elseif(UNIX)
|
||||
ENDIF()
|
||||
message(STATUS "Building FSO tools: ${FSO_BUILD_TOOLS}")
|
||||
message(STATUS "Building wxFRED: ${FSO_BUILD_WXFRED2}")
|
||||
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
|
||||
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
|
||||
@@ -1,10 +1,13 @@
|
||||
FreeSpace2 *S*ource *C*ode *P*roject
|
||||
==
|
||||
[](https://travis-ci.org/scp-fs2open/fs2open.github.com)
|
||||
[](https://travis-ci.org/scp-fs2open/fs2open.github.com)
|
||||
[](https://ci.appveyor.com/project/SirKnightly/fs2open-github-com/branch/master)
|
||||
[](https://scan.coverity.com/projects/870)
|
||||
|
||||
Building
|
||||
--
|
||||
Before you do anything, make sure you have updated your git submodules, either by running `git submodule update --init --recursive` or by cloning the repository with the `--recursive` flag.<br/>
|
||||
<br/>
|
||||
For building you will need [CMake](http://www.cmake.org/cmake/resources/software.html). Version 3.4 is required. Once you have installed CMake you should create a build directory where the project/make files should be created, **do not create them inside the source tree!**<br>
|
||||
<br>
|
||||
On Windows you can use the `cmake-gui` executable to get a nice GUI, on Unix just use `cmake`. Use the newly created directory as build directory (change to this directory on Unix) and run cmake. On Windows this can be done by clicking the `Configure` button. Choose your compiler version and hit `Generate` when configuring is done. <br>
|
||||
@@ -14,6 +17,7 @@ Depending on the makefile generator used build the `all` or `ALL_BUILD` target t
|
||||
* `FSO_BUILD_WXFRED2`: Build the wxfred2 project, requires wxWidgets
|
||||
* `FSO_FREESPACE_PATH`: Sets the path of your FreeSpace install, can be used to automatically run the generated executables with the correct working directory, this is an optional variable. By default this will use the value of the `FS2PATH` environment variable.
|
||||
* `FSO_BUILD_TOOLS`: Build some tools related to FSO
|
||||
* `CMAKE_BUILD_TYPE`: Sets the binary build type between `Debug` and `Release` (default)
|
||||
|
||||
#### Windows only variables
|
||||
* `FSO_BUILD_FRED2`: Build FRED2, requires a Visual Studio version that ships with MFC
|
||||
@@ -35,4 +39,4 @@ You should only use these variables if you know what you're doing
|
||||
* `MSVC_SIMD_INSTRUCTIONS`: The instruction set the executables will be optimized for.
|
||||
|
||||
### Generating an installation package
|
||||
CMake can automaticall generate installation packages of the project. To do this you will just need to run the `package` target of the build system and the package will be placed inside your build directory. On Windows you will have to install [NSIS](http://nsis.sourceforge.net/Main_Page) to use this.
|
||||
CMake can automatically generate installation packages of the project. To do this you will just need to run the `package` target of the build system and the package will be placed inside your build directory. On Windows you will have to install [NSIS](http://nsis.sourceforge.net/Main_Page) to use this.
|
||||
+38
-17
@@ -5,19 +5,18 @@ configuration:
|
||||
clone_depth: 10
|
||||
environment:
|
||||
matrix:
|
||||
- VS_VERSION: 12
|
||||
- BuildID: 0
|
||||
CMAKE_GENERATOR: Visual Studio 12 2013
|
||||
PlatformToolset: v120_xp
|
||||
- VS_VERSION: 14
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
- BuildID: 1
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
|
||||
PlatformToolset: v140_xp
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/check_release.ps1
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/before_build.ps1
|
||||
build_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/build.ps1
|
||||
|
||||
test_script:
|
||||
- ps: . $Env:APPVEYOR_BUILD_FOLDER/ci/appveyor/test.ps1
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
@@ -26,15 +25,37 @@ deploy:
|
||||
on:
|
||||
ReleaseBuild: true # deploy on release push only
|
||||
|
||||
- provider: BinTray
|
||||
username: sirknightly
|
||||
api_key:
|
||||
secure: pYWqfiZhIWvFYdjVWPXNaHobmnkXIWa4+LwoiyMTEiu4Z0CiCAW0ZrMfTKVkORKz
|
||||
subject: scp-fs2open
|
||||
repo: FSO
|
||||
package: nightly
|
||||
version: $(VersionName)
|
||||
publish: true
|
||||
override: true
|
||||
- provider: FTP
|
||||
protocol: sftp
|
||||
host: scp.indiegames.us
|
||||
username:
|
||||
secure: SFivQZfatqWHXK1ijYK3GQ==
|
||||
password:
|
||||
secure: q6Zk/412o1ri+NEya1dl1Q==
|
||||
folder: public_html/builds/nightly/$(VersionName)
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: ftp
|
||||
host: swc.fs2downloads.com
|
||||
username:
|
||||
secure: EXg2ADoKzMduZF90ip2Q0g==
|
||||
password:
|
||||
secure: x0LL0uY9yBAQ7JTARhQ6AA==
|
||||
folder: swc.fs2downloads.com/builds/nightly/$(VersionName)
|
||||
beta: true
|
||||
on:
|
||||
NightlyBuild: true # deploy on nightly push only
|
||||
|
||||
- provider: FTP
|
||||
protocol: ftp
|
||||
host: swc.fs2downloads.com
|
||||
username:
|
||||
secure: EXg2ADoKzMduZF90ip2Q0g==
|
||||
password:
|
||||
secure: x0LL0uY9yBAQ7JTARhQ6AA==
|
||||
folder: swc.fs2downloads.com/builds/test/$(VersionName)
|
||||
beta: true
|
||||
on:
|
||||
TestBuild: true # deploy on test build push only
|
||||
@@ -1,5 +0,0 @@
|
||||
New-Item build -type directory
|
||||
Set-Location -Path build
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 -G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
+131
-8
@@ -1,12 +1,132 @@
|
||||
|
||||
write "$env:DeployBuild"
|
||||
write "$env:DeployConfig"
|
||||
class BuildConfig {
|
||||
[string]$Generator
|
||||
[string]$PackageType
|
||||
[string]$Toolset
|
||||
[string]$SimdType
|
||||
[Bool]$SourcePackage
|
||||
}
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:DeployBuild)) {
|
||||
# Release build
|
||||
if (![System.Convert]::ToBoolean($env:DeployConfig)) {
|
||||
exit 0 # End the build
|
||||
$NightlyConfigurations = @(
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015 Win64";
|
||||
PackageType="Win64";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
SourcePackage=$false;
|
||||
},
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015";
|
||||
PackageType="Win32";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
)
|
||||
$ReleaseConfigurations = @(
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015";
|
||||
PackageType="Win32";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
SourcePackage=$true;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015";
|
||||
PackageType="Win32-AVX";
|
||||
Toolset="v140_xp";
|
||||
SimdType="AVX";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015 Win64";
|
||||
PackageType="Win64";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015 Win64";
|
||||
PackageType="Win64-AVX";
|
||||
Toolset="v140_xp";
|
||||
SimdType="AVX";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
)
|
||||
|
||||
$BuildConfigurations = $null
|
||||
|
||||
# Default values
|
||||
$ReleaseBuild = $false
|
||||
$NightlyBuild = $false
|
||||
$TestBuild = $false
|
||||
|
||||
# Set to true to test either the release or the nightly part of this script
|
||||
$ReleaseTest = $false
|
||||
$NightlyTest = $false
|
||||
$TestBuildTest = $false
|
||||
|
||||
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
|
||||
# Tag matches
|
||||
$ReleaseBuild = $true
|
||||
$PackageName = "fs2_open_$($matches[1])"
|
||||
$BuildConfigurations = $ReleaseConfigurations
|
||||
}
|
||||
|
||||
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
|
||||
# Tag matches
|
||||
$NightlyBuild = $true
|
||||
$PackageName = "nightly_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
}
|
||||
|
||||
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
|
||||
# Tag matches
|
||||
$TestBuild = $true
|
||||
$PackageName = "test_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
$BuildConfigurations = $NightlyConfigurations
|
||||
|
||||
# Override the revision string so that the builds are named correctly
|
||||
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
|
||||
}
|
||||
|
||||
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
|
||||
$buildID = [convert]::ToInt32($env:BuildID) * 2
|
||||
if ($Env:Configuration -eq "Release") {
|
||||
$buildID = $buildID + 1
|
||||
}
|
||||
|
||||
$DeployBuild = $false
|
||||
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
|
||||
$DeployBuild = $true
|
||||
}
|
||||
|
||||
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
|
||||
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
|
||||
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
|
||||
|
||||
New-Item build -type directory
|
||||
Set-Location -Path build
|
||||
|
||||
if ($DeployBuild) {
|
||||
# Release build
|
||||
if ($buildID -ge $BuildConfigurations.Length) {
|
||||
# Not needed
|
||||
exit 0
|
||||
}
|
||||
|
||||
$buildConfig = $BuildConfigurations[$buildID]
|
||||
|
||||
if ($buildConfig.SourcePackage -eq $True) {
|
||||
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
|
||||
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
|
||||
}
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
|
||||
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
|
||||
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
|
||||
|
||||
$Configs = @("Release", "FastDebug")
|
||||
foreach ($config in $Configs) {
|
||||
@@ -17,9 +137,12 @@ if ([System.Convert]::ToBoolean($env:DeployBuild)) {
|
||||
}
|
||||
}
|
||||
|
||||
7z a "$($env:PackageName)-builds-Win32.zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
|
||||
Push-AppveyorArtifact "$($env:PackageName)-builds-Win32.zip"
|
||||
7z a "$($PackageName)-builds-$($buildConfig.PackageType).zip" "$env:APPVEYOR_BUILD_FOLDER/../install/*"
|
||||
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
|
||||
} else {
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
|
||||
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
|
||||
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
|
||||
|
||||
if (! ($?)) {
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
# Default values
|
||||
Set-AppveyorBuildVariable 'ReleaseBuild' 'false'
|
||||
Set-AppveyorBuildVariable 'NightlyBuild' 'false'
|
||||
Set-AppveyorBuildVariable 'DeployBuild' 'false'
|
||||
Set-AppveyorBuildVariable 'PackagePrefix' ''
|
||||
Set-AppveyorBuildVariable 'VersionName' ''
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)")) {
|
||||
# Tag matches
|
||||
Set-AppveyorBuildVariable 'ReleaseBuild' 'true'
|
||||
Set-AppveyorBuildVariable 'PackageName' "fs2_open_$($matches[1])"
|
||||
}
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)")) {
|
||||
# Tag matches
|
||||
Set-AppveyorBuildVariable 'NightlyBuild' 'true'
|
||||
Set-AppveyorBuildVariable 'PackageName' "nightly_$($matches[1])"
|
||||
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
|
||||
}
|
||||
|
||||
if (($Env:Configuration -eq "Release") -And ($Env:VS_VERSION -eq "14")) {
|
||||
Set-AppveyorBuildVariable 'DeployConfig' 'true'
|
||||
} else {
|
||||
Set-AppveyorBuildVariable 'DeployConfig' 'false'
|
||||
}
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild)) {
|
||||
Set-AppveyorBuildVariable 'DeployBuild' 'true'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
|
||||
# Skip tests for deployment
|
||||
exit 0
|
||||
} else {
|
||||
write "Running unit tests..."
|
||||
# Run unit tests
|
||||
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
|
||||
|
||||
if (! ($?)) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
@@ -6,21 +6,38 @@ mkdir -p build
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
PARENT_DIR="$(basename $PWD)"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
|
||||
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
|
||||
|
||||
if [[ "$CC" =~ ^clang.*$ ]]; then
|
||||
CXXFLAGS="$CXXFLAGS -stdlib=libc++"
|
||||
fi
|
||||
|
||||
export CXXFLAGS
|
||||
export CFLAGS
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON"
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
mkdir -p $config
|
||||
cd $config
|
||||
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release" \
|
||||
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
|
||||
-DFSO_BUILD_APPIMAGE=ON -DAPPIMAGE_ASSISTANT="$HOME/AppImageAssistant" \
|
||||
-DFSO_BUILD_INCLUDED_LIBS=ON ../..
|
||||
-DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON ../..
|
||||
cd ..
|
||||
done
|
||||
else
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION ..
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
|
||||
else
|
||||
cmake -G "Xcode" ..
|
||||
fi
|
||||
fi
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
RELEASE_BUILD=false
|
||||
NIGHTLY_BUILD=false
|
||||
TEST_BUILD=false
|
||||
|
||||
BUILD_DEPLOYMENT=false
|
||||
BUILD_CONFIGS="Release FastDebug"
|
||||
VERSION_NAME=""
|
||||
@@ -9,25 +11,45 @@ PACKAGE_NAME=""
|
||||
|
||||
RELEASE_PATTERN="^release_(.*)$"
|
||||
NIGHTLY_PATTERN="^nightly_(.*)$"
|
||||
TEST_BUILD_PATTERN="^test\/(.*)$"
|
||||
|
||||
if [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
|
||||
# These are for testing
|
||||
NIGHTLY_TEST=false
|
||||
RELEASE_TEST=false
|
||||
TEST_BUILD_TEST=false
|
||||
|
||||
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
|
||||
echo "This is a release tag!";
|
||||
RELEASE_BUILD=true;
|
||||
PACKAGE_NAME="fs2_open_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
|
||||
if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
|
||||
echo "This is a nightly tag!";
|
||||
NIGHTLY_BUILD=true;
|
||||
VERSION_NAME="${BASH_REMATCH[1]}"
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
|
||||
echo "This is a test build branch!";
|
||||
TEST_BUILD=true;
|
||||
if [ "$TEST_BUILD_TEST" = true ]; then
|
||||
VERSION_NAME="test";
|
||||
PACKAGE_NAME="test_test";
|
||||
else
|
||||
VERSION_NAME="${BASH_REMATCH[1]}";
|
||||
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
|
||||
fi
|
||||
|
||||
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ]); then
|
||||
# Override the revision string so that the builds are named correctly
|
||||
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
|
||||
fi
|
||||
|
||||
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
|
||||
BUILD_DEPLOYMENT=true;
|
||||
fi
|
||||
|
||||
if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CC" = "clang" ]); then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc.*$ ]])); then
|
||||
echo "Skipping non-release compiler";
|
||||
exit 0;
|
||||
fi
|
||||
@@ -40,7 +62,8 @@ fi
|
||||
|
||||
export RELEASE_BUILD
|
||||
export NIGHTLY_BUILD
|
||||
export TEST_BUILD
|
||||
export BUILD_DEPLOYMENT
|
||||
export BUILD_CONFIGS
|
||||
export VERSION_NAME
|
||||
export PACKAGE_NAME
|
||||
export PACKAGE_NAME
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
|
||||
# Before
|
||||
echo "Before:"
|
||||
curl -V
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
|
||||
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
|
||||
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
|
||||
mkdir /tmp/curl
|
||||
cd /tmp/curl
|
||||
sudo apt-get update
|
||||
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
|
||||
apt-get source curl
|
||||
sudo apt-get build-dep curl
|
||||
|
||||
cd curl-*
|
||||
export DEB_BUILD_OPTIONS="nocheck"
|
||||
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
|
||||
|
||||
cd ..
|
||||
dpkg -l | grep curl
|
||||
ls -al
|
||||
sudo dpkg -i libcurl3*.deb
|
||||
sudo dpkg -i curl*.deb
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew install curl --with-libssh2
|
||||
export PATH="/usr/local/opt/curl/bin:$PATH"
|
||||
fi
|
||||
|
||||
# After
|
||||
echo "After:"
|
||||
curl -V
|
||||
fi
|
||||
|
||||
cd /tmp/builds
|
||||
|
||||
for file in *; do
|
||||
if [ "$TEST_BUILD" = true ]; then
|
||||
# Upload to fs2downloads
|
||||
curl -k "ftp://swc.fs2downloads.com/swc.fs2downloads.com/builds/test/$VERSION_NAME/" --user "$FS2DOWNLOADS_USER:$FS2DOWNLOADS_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
else
|
||||
# Upload to indiegames
|
||||
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
|
||||
# Upload to fs2downloads
|
||||
curl -k "ftp://swc.fs2downloads.com/swc.fs2downloads.com/builds/nightly/$VERSION_NAME/" --user "$FS2DOWNLOADS_USER:$FS2DOWNLOADS_PASSWORD" -T "$file" --ftp-create-dirs
|
||||
fi
|
||||
done
|
||||
@@ -22,7 +22,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
chmod a+x ./AppImageAssistant
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
gem install xcpretty xcpretty-travis-formatter thefox-pastebin
|
||||
gem install xcpretty
|
||||
|
||||
brew update
|
||||
brew outdated cmake || brew upgrade cmake
|
||||
|
||||
@@ -8,11 +8,11 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cd "$config"
|
||||
ninja install appimage
|
||||
ninja appimage
|
||||
cd ..
|
||||
done
|
||||
|
||||
ls -al /tmp/release
|
||||
cp `find /tmp/release -name '*.AppImage' -print` /tmp/release
|
||||
(cd /tmp/release && tar -cvzf /tmp/builds/$PACKAGE_NAME-builds-Linux.tar.gz *.AppImage)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cd build
|
||||
@@ -20,7 +20,7 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cmake --build . --config "$config" --target install | tee build.log \
|
||||
| xcpretty -f `xcpretty-travis-formatter`
|
||||
| xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
if [ "$XCODE_RET" -ne "0" ]; then
|
||||
tar -cvzf build.log.tar.gz build.log
|
||||
|
||||
+6
-3
@@ -5,13 +5,16 @@ set -e
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
ninja
|
||||
ninja all
|
||||
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty -f `xcpretty-travis-formatter`
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
if [ "$XCODE_RET" -ne "0" ]; then
|
||||
tar -cvzf build.log.tar.gz build.log
|
||||
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
liblsan Invalid read
|
||||
Memcheck:Addr8
|
||||
obj:/usr/lib64/liblsan.so.0.0.0
|
||||
obj:/usr/lib64/liblsan.so.0.0.0
|
||||
obj:/usr/lib64/liblsan.so.0.0.0
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
}
|
||||
{
|
||||
Travis memleak
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
fun:_dl_signal_error
|
||||
fun:_dl_open
|
||||
fun:dlopen_doit
|
||||
fun:_dl_catch_error
|
||||
fun:_dlerror_run
|
||||
fun:dlopen@@GLIBC_2.2.5
|
||||
obj:/usr/lib/x86_64-linux-gnu/libmirclient.so.7
|
||||
fun:call_init.part.0
|
||||
fun:call_init
|
||||
fun:_dl_init
|
||||
fun:dl_open_worker
|
||||
fun:_dl_catch_error
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
HERE=$(dirname $(readlink -f "${0}"))
|
||||
export LD_LIBRARY_PATH="${HERE}"/lib:$PATH
|
||||
export LD_LIBRARY_PATH="${HERE}"/lib:"$LD_LIBRARY_PATH"
|
||||
"${HERE}"/bin/$<TARGET_FILE_NAME:Freespace2> $@
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
include(WriteCompilerDetectionHeader)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(REQUIRED_CXX_FEATURES cxx_rvalue_references cxx_nullptr)
|
||||
|
||||
get_property(CMAKE_CXX_KNOWN_FEATURES GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
|
||||
|
||||
@@ -27,6 +27,7 @@ int main( int argc, char* argv[] )
|
||||
int SSE = false;
|
||||
int SSE2 = false;
|
||||
int AVX = false;
|
||||
int AVX2 = false;
|
||||
|
||||
int info[4];
|
||||
cpuid(info, 0);
|
||||
@@ -40,8 +41,14 @@ int main( int argc, char* argv[] )
|
||||
|
||||
AVX = (info[2] & ((int)1 << 28)) != 0;
|
||||
}
|
||||
if (nIds >= 7){
|
||||
cpuid(info,0x00000007);
|
||||
AVX2 = (info[1] & ((int)1 << 5)) != 0;
|
||||
}
|
||||
|
||||
if(AVX)
|
||||
if (AVX2)
|
||||
std::cout << "AVX2";
|
||||
else if(AVX)
|
||||
std::cout << "AVX";
|
||||
else if(SSE2)
|
||||
std::cout << "SSE2";
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
# Sample toolchain file for building for Windows from a Linux system.
|
||||
#
|
||||
# Typical usage:
|
||||
# *) install cross compiler: `sudo apt-get install mingw-w64 g++-mingw-w64`
|
||||
# *) cd build
|
||||
# *) cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-Ubuntu-mingw64.cmake ..
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
|
||||
|
||||
# cross compilers to use for C and C++
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
|
||||
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
|
||||
|
||||
# target environment on the build host system
|
||||
# set 1st to dir with the cross compiler's C/C++ headers/libs
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
|
||||
|
||||
# modify default behavior of FIND_XXX() commands to
|
||||
# search for headers/libs in the target environment and
|
||||
# don't search for programs in the build host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
Vendored
-1
Submodule cmake/external/cotire deleted from 40a46bf2fb.
Vendored
+4054
File diff suppressed because it is too large.
Load diff
@@ -1,33 +1,16 @@
|
||||
|
||||
include(CheckIncludeFile)
|
||||
|
||||
add_library(speech INTERFACE)
|
||||
|
||||
if (WIN32)
|
||||
find_package(WindowsSDK REQUIRED)
|
||||
|
||||
foreach(dir ${WINDOWSSDK_DIRS})
|
||||
get_windowssdk_library_dirs("${dir}" LIB_DIRS)
|
||||
CHECK_INCLUDE_FILE_CXX("sapi.h" HAVE_SAPI_H)
|
||||
|
||||
find_library(SPEECH_LIBRARY
|
||||
NAMES sapi
|
||||
PATHS ${LIB_DIRS}
|
||||
NO_DEFAULT_PATH)
|
||||
|
||||
if (SPEECH_LIBRARY)
|
||||
set(SDK_DIR "${dir}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if (NOT SPEECH_LIBRARY)
|
||||
message(SEND_ERROR "Text to speech library could not be found! Either install it or disable the speech option.")
|
||||
return()
|
||||
if (NOT HAVE_SAPI_H)
|
||||
message(SEND_ERROR "sapi.h could not be found on your platform. Please disable speech support.")
|
||||
endif()
|
||||
|
||||
get_windowssdk_include_dirs("${SDK_DIR}" INCLUDE_DIRS)
|
||||
|
||||
target_include_directories(speech INTERFACE ${INCLUDE_DIRS})
|
||||
else()
|
||||
message(SEND_ERROR "Text to Speech is not supported on this platform!")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(speech INTERFACE -DFS2_SPEECH)
|
||||
target_compile_definitions(speech INTERFACE -DFS2_SPEECH)
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
#ifndef __FREDRC_H
|
||||
#define __FREDRC_H
|
||||
|
||||
#define ABOUT_LINE_1 "FRED2_OPEN - FreeSpace Editor, Version @FSO_PRODUCT_VERSION_STRING@ OpenGL"
|
||||
#define MAINFRAME_CONTENTS "FRED2_OPEN @FSO_PRODUCT_VERSION_STRING@ - FreeSpace2 Mission Editor\nUntitled\nFRED2\nFreeSpace2 Missions (*.fs2)\n.fs2\nFreeSpace2Mission\nFreeSpace2 Mission"
|
||||
|
||||
#endif // __FREDRC_H
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
include(platformChecks)
|
||||
|
||||
include(Cxx11)
|
||||
include(platformChecks)
|
||||
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/project.h.in ${GENERATED_SOURCE_DIR}/project.h)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/fred_rc.h.in ${GENERATED_SOURCE_DIR}/fred_rc.h)
|
||||
@@ -1,3 +1,9 @@
|
||||
|
||||
SET(BINARY_DESTINATION ".")
|
||||
SET(LIBRAY_DESTINATION "${BINARY_DESTINATION}")
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(IS_64BIT TRUE)
|
||||
else()
|
||||
set(IS_64BIT FALSE)
|
||||
endif()
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
MESSAGE(STATUS "Doing Mac OSX specific things...")
|
||||
target_compile_definitions(platform INTERFACE APPLE_APP)
|
||||
SET(EXE_GUI_TYPE MACOSX_BUNDLE)
|
||||
|
||||
FIND_LIBRARY(COCOA_LIBRARY Cocoa)
|
||||
@@ -9,3 +10,25 @@ if (NOT COCOA_LIBRARY)
|
||||
endif()
|
||||
|
||||
target_link_libraries(platform INTERFACE ${COCOA_LIBRARY})
|
||||
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
|
||||
|
||||
SET(CMAKE_SKIP_RPATH FALSE)
|
||||
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
SET(CMAKE_INSTALL_RPATH @loader_path/../Frameworks/)
|
||||
|
||||
# Set the path where library dependencies are copied to
|
||||
SET(LIBRAY_DESTINATION "../Frameworks")
|
||||
|
||||
set(PLATFORM_MAC TRUE CACHE INTERNAL "" FORCE)
|
||||
|
||||
# Generate and don't strip debug symbols
|
||||
# These settings don't seem to generate debug symbols for code and Freespace2
|
||||
# so those settings are set manually in code and Freespace2's CMakeLists.txt files
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS "YES")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP "NO")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT "NO")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO")
|
||||
|
||||
# Generate .dSYM file
|
||||
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
|
||||
@@ -7,4 +7,4 @@ if (NOT EXECINFO_LIB)
|
||||
message(FATAL_ERROR "Couldn't find libexecinfo! Please install it and rerun the configuration.")
|
||||
else()
|
||||
target_link_libraries(platform INTERFACE "${EXECINFO_LIB}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,2 +1,18 @@
|
||||
|
||||
target_compile_definitions(platform INTERFACE SCP_SOLARIS)
|
||||
|
||||
find_library(SOCKET_LIB socket)
|
||||
|
||||
if (NOT SOCKET_LIB)
|
||||
message(FATAL_ERROR "Couldn't find libsocket! Please install it and rerun the configuration.")
|
||||
else()
|
||||
target_link_libraries(platform INTERFACE "${SOCKET_LIB}")
|
||||
endif()
|
||||
|
||||
find_library(NSL_LIB nsl)
|
||||
|
||||
if (NOT NSL_LIB)
|
||||
message(FATAL_ERROR "Couldn't find libnsl! Please install it and rerun the configuration.")
|
||||
else()
|
||||
target_link_libraries(platform INTERFACE "${NSL_LIB}")
|
||||
endif()
|
||||
@@ -4,3 +4,10 @@ INCLUDE(util)
|
||||
MESSAGE(STATUS "Configuring UNIX specific things and stuff...")
|
||||
|
||||
target_compile_definitions(platform INTERFACE SCP_UNIX USE_OPENAL)
|
||||
|
||||
# Set RPATH
|
||||
set(CMAKE_SKIP_BUILD_RPATH TRUE)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH "\$ORIGIN")
|
||||
|
||||
set(PLATFORM_UNIX TRUE CACHE INTERNAL "" FORCE)
|
||||
@@ -1,20 +1,27 @@
|
||||
|
||||
MESSAGE(STATUS "Configuring Windows specific things and stuff...")
|
||||
|
||||
target_link_libraries(platform INTERFACE
|
||||
comctl32.lib
|
||||
msacm32.lib
|
||||
odbc32.lib
|
||||
odbccp32.lib
|
||||
vfw32.lib
|
||||
winmm.lib
|
||||
wsock32.lib
|
||||
Psapi.lib
|
||||
SET(WIN32_LIBS
|
||||
comctl32
|
||||
msacm32
|
||||
odbc32
|
||||
odbccp32
|
||||
vfw32
|
||||
winmm
|
||||
wsock32
|
||||
psapi
|
||||
)
|
||||
|
||||
IF (MINGW)
|
||||
SET(WIN32_LIBS ${WIN32_LIBS} mingw32)
|
||||
ENDIF (MINGW)
|
||||
|
||||
target_link_libraries(platform INTERFACE ${WIN32_LIBS})
|
||||
|
||||
target_compile_definitions(platform INTERFACE WIN32 USE_OPENAL _WINDOWS)
|
||||
|
||||
# Specify minimum Windows version for the headers (currently this is XP)
|
||||
target_compile_definitions(platform INTERFACE NTDDI_VERSION=0x05010000 _WIN32_WINNT=0x0501)
|
||||
|
||||
SET(EXE_GUI_TYPE WIN32)
|
||||
set(PLATFORM_WINDOWS TRUE CACHE INTERNAL "" FORCE)
|
||||
@@ -7,11 +7,39 @@ include(CheckLibraryExists)
|
||||
include(CheckPrototypeDefinition)
|
||||
include(CheckStructHasMember)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckCXXSymbolExists)
|
||||
include(CheckTypeSize)
|
||||
|
||||
CHECK_INCLUDE_FILE("execinfo.h" HAVE_EXECINFO_H)
|
||||
CHECK_INCLUDE_FILE_CXX("cxxabi.h" HAVE_CXXAPI_H)
|
||||
|
||||
CHECK_TYPE_SIZE("max_align_t" MAX_ALIGN_T)
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
set(CMAKE_REQUIRED_FLAGS "-std=c++11") # required for g++ <= 5
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
|
||||
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES "type_traits")
|
||||
CHECK_TYPE_SIZE("std::is_trivially_copyable<int>" STD_IS_TRIVIALLY_COPYABLE LANGUAGE CXX)
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
|
||||
CHECK_TYPE_SIZE("char32_t" CHAR32_T LANGUAGE CXX)
|
||||
CHECK_TYPE_SIZE("U'b'" UNICODE_CHAR_LITERAL LANGUAGE CXX)
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS)
|
||||
|
||||
|
||||
CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP)
|
||||
CHECK_FUNCTION_EXISTS(strncasecmp HAVE_STRNCASECMP)
|
||||
|
||||
CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP)
|
||||
CHECK_FUNCTION_EXISTS(_strnicmp HAVE__STRNICMP)
|
||||
|
||||
CHECK_FUNCTION_EXISTS(strlwr HAVE_STRLWR)
|
||||
|
||||
CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
|
||||
|
||||
set(PLATFORM_CHECK_HEADER "${GENERATED_SOURCE_DIR}/platformChecks.h")
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/platformChecks.h.in "${PLATFORM_CHECK_HEADER}")
|
||||
@@ -5,5 +5,24 @@
|
||||
|
||||
#cmakedefine HAVE_EXECINFO_H
|
||||
#cmakedefine HAVE_CXXAPI_H
|
||||
#cmakedefine HAVE_MAX_ALIGN_T
|
||||
#cmakedefine HAVE_STD_MAX_ALIGN_T
|
||||
|
||||
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE
|
||||
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE_ARRAY
|
||||
|
||||
#cmakedefine01 IS_64BIT
|
||||
|
||||
#cmakedefine01 HAVE_STRCASECMP
|
||||
#cmakedefine01 HAVE_STRNCASECMP
|
||||
#cmakedefine01 HAVE__STRICMP
|
||||
#cmakedefine01 HAVE__STRNICMP
|
||||
|
||||
#cmakedefine01 HAVE_STRLWR
|
||||
|
||||
#cmakedefine01 HAVE_STRINGS_H
|
||||
|
||||
#cmakedefine01 HAVE_CHAR32_T
|
||||
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
|
||||
|
||||
#endif // __PLATFORM_CHECKS_H__
|
||||
@@ -5,6 +5,11 @@ IF(FSO_CMAKE_DEBUG)
|
||||
INCLUDE(debug-vars)
|
||||
ENDIF(FSO_CMAKE_DEBUG)
|
||||
|
||||
set(PLATFORM_WINDOWS FALSE CACHE INTERNAL "" FORCE)
|
||||
set(PLATFORM_UNIX FALSE CACHE INTERNAL "" FORCE)
|
||||
set(PLATFORM_LINUX FALSE CACHE INTERNAL "" FORCE)
|
||||
set(PLATFORM_MAC FALSE CACHE INTERNAL "" FORCE)
|
||||
|
||||
IF(WIN32)
|
||||
INCLUDE(platform-win32)
|
||||
ELSEIF(UNIX)
|
||||
@@ -16,7 +21,9 @@ ELSEIF(UNIX)
|
||||
INCLUDE(platform-solaris)
|
||||
ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
include(platform-darwin)
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
set(PLATFORM_LINUX TRUE CACHE INTERNAL "" FORCE)
|
||||
ENDIF()
|
||||
ELSE(WIN32)
|
||||
MESSAGE(STATUS "This platform is not supported, good luck!")
|
||||
ENDIF(WIN32)
|
||||
+64
-16
@@ -4,16 +4,28 @@ include(CheckCXXCompilerFlag)
|
||||
|
||||
MESSAGE(STATUS "Doing configuration specific to clang...")
|
||||
|
||||
unset(COMPILER_FLAGS)
|
||||
option(CLANG_ENABLE_LEAK_CHECK "Enable -fsanitize=leak" OFF)
|
||||
option(CLANG_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
|
||||
|
||||
# These are the default values
|
||||
set(C_BASE_FLAGS "-march=native -pipe")
|
||||
set(CXX_BASE_FLAGS "-march=native -pipe")
|
||||
|
||||
# For C and C++, the values can be overwritten independently
|
||||
if(DEFINED ENV{CXXFLAGS})
|
||||
set(COMPILER_FLAGS $ENV{CXXFLAGS})
|
||||
set(CXX_BASE_FLAGS $ENV{CXXFLAGS})
|
||||
endif()
|
||||
if(DEFINED ENV{CFLAGS})
|
||||
set(C_BASE_FLAGS $ENV{CFLAGS})
|
||||
endif()
|
||||
|
||||
if(NOT COMPILER_FLAGS)
|
||||
set(COMPILER_FLAGS "-march=native -pipe")
|
||||
endif()
|
||||
# Initialize with an empty string to make sure we always get a clean start
|
||||
set(COMPILER_FLAGS "")
|
||||
|
||||
# This is a slight hack since our flag setup is a bit more complicated
|
||||
_enable_extra_compiler_warnings_flags()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
globally_enable_extra_compiler_warnings()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Omit "argument unused during compilation" when clang is used with ccache.
|
||||
@@ -26,12 +38,40 @@ if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdiagnostics-color")
|
||||
endif()
|
||||
|
||||
# Omit "deprecated conversion from string constant to 'char*'" warnings.
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-write-strings")
|
||||
# Start with an empty list
|
||||
set(SANITIZE_FLAGS)
|
||||
|
||||
if(CLANG_ENABLE_ADDRESS_SANITIZER)
|
||||
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
|
||||
CHECK_C_COMPILER_FLAG("-fsanitize=address" SUPPORTS_SANITIZE_ADDRESS)
|
||||
|
||||
if (SUPPORTS_SANITIZE_ADDRESS)
|
||||
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "address")
|
||||
endif()
|
||||
endif()
|
||||
if (CLANG_ENABLE_LEAK_CHECK)
|
||||
check_linker_flag("-fsanitize=leak" SUPPORTS_FSANITIZE_LEAK)
|
||||
|
||||
if (SUPPORTS_FSANITIZE_LEAK)
|
||||
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "leak")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" "," SANITIZE_FLAGS "${SANITIZE_FLAGS}")
|
||||
if (NOT "${SANITIZE_FLAGS}" STREQUAL "")
|
||||
set(SANITIZE_FLAGS "-fsanitize=${SANITIZE_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-function")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
# Dear Clang, please tell us if a function does not return a value since that part of the standard is stupid!
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-char-subscripts")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
|
||||
|
||||
@@ -44,13 +84,9 @@ set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Werror")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS ${COMPILER_FLAGS})
|
||||
set(CMAKE_C_FLAGS ${COMPILER_FLAGS})
|
||||
# Always use the base flags and add our compiler flags at the bacl
|
||||
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
@@ -61,5 +97,17 @@ set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "")
|
||||
|
||||
if (SANITIZE_FLAGS)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g -rdynamic")
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
target_compile_options(compiler INTERFACE "-Werror")
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed width format macros are available
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
|
||||
+83
-22
@@ -5,20 +5,35 @@ include(util)
|
||||
|
||||
MESSAGE(STATUS "Doing configuration specific to gcc...")
|
||||
|
||||
option(GCC_ENABLE_LEAK_CHECK "Enable the -fsanitize=leak" OFF)
|
||||
option(GCC_ENABLE_LEAK_CHECK "Enable -fsanitize=leak" OFF)
|
||||
option(GCC_ENABLE_ADDRESS_SANITIZER "Enable -fsanitize=address" OFF)
|
||||
option(GCC_ENABLE_SANITIZE_UNDEFINED "Enable -fsanitize=undefined" OFF)
|
||||
|
||||
unset(COMPILER_FLAGS)
|
||||
# These are the default values
|
||||
set(C_BASE_FLAGS "-march=native -pipe")
|
||||
set(CXX_BASE_FLAGS "-march=native -pipe")
|
||||
|
||||
# For C and C++, the values can be overwritten independently
|
||||
if(DEFINED ENV{CFLAGS})
|
||||
set(C_BASE_FLAGS $ENV{CFLAGS})
|
||||
endif()
|
||||
if(DEFINED ENV{CXXFLAGS})
|
||||
set(COMPILER_FLAGS $ENV{CXXFLAGS})
|
||||
set(CXX_BASE_FLAGS $ENV{CXXFLAGS})
|
||||
endif()
|
||||
|
||||
if(NOT COMPILER_FLAGS)
|
||||
set(COMPILER_FLAGS "-march=native -pipe")
|
||||
endif()
|
||||
# Initialize with an empty string to make sure we always get a clean start
|
||||
set(COMPILER_FLAGS "")
|
||||
|
||||
# This is a slight hack since our flag setup is a bit more complicated
|
||||
_enable_extra_compiler_warnings_flags()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${_flags}")
|
||||
|
||||
globally_enable_extra_compiler_warnings()
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -funroll-loops -fsigned-char -Wno-unknown-pragmas")
|
||||
|
||||
# Place each function and data in its own section so the linker can
|
||||
# perform dead code elimination
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdata-sections -ffunction-sections")
|
||||
|
||||
if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
|
||||
# Force color diagnostics for Ninja generator
|
||||
CHECK_C_COMPILER_FLAG(-fdiagnostics-color SUPPORTS_DIAGNOSTIC_COLOR)
|
||||
@@ -28,11 +43,46 @@ if ("${CMAKE_GENERATOR}" STREQUAL "Ninja")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Omit "deprecated conversion from string constant to 'char*'" warnings.
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-write-strings")
|
||||
# Start with an empty list
|
||||
set(SANITIZE_FLAGS)
|
||||
|
||||
if(GCC_ENABLE_ADDRESS_SANITIZER)
|
||||
set(CMAKE_REQUIRED_FLAGS "-fsanitize=address")
|
||||
CHECK_C_COMPILER_FLAG("-fsanitize=address" SUPPORTS_SANITIZE_ADDRESS)
|
||||
|
||||
if (SUPPORTS_SANITIZE_ADDRESS)
|
||||
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "address")
|
||||
endif()
|
||||
endif()
|
||||
if (GCC_ENABLE_LEAK_CHECK)
|
||||
check_linker_flag("-fsanitize=leak" SUPPORTS_FSANITIZE_LEAK)
|
||||
|
||||
if (SUPPORTS_FSANITIZE_LEAK)
|
||||
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "leak")
|
||||
endif()
|
||||
endif()
|
||||
if (GCC_ENABLE_SANITIZE_UNDEFINED)
|
||||
check_linker_flag("-fsanitize=undefined" SUPPORTS_SANITIZE_UNDEFINED)
|
||||
|
||||
if (SUPPORTS_SANITIZE_UNDEFINED)
|
||||
set(SANITIZE_FLAGS ${SANITIZE_FLAGS} "undefined")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" "," SANITIZE_FLAGS "${SANITIZE_FLAGS}")
|
||||
if (NOT "${SANITIZE_FLAGS}" STREQUAL "")
|
||||
set(SANITIZE_FLAGS "-fsanitize=${SANITIZE_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-function")
|
||||
|
||||
# Dear GCC, please tell us if a function does not return a value since that part of the standard is stupid!
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
|
||||
@@ -41,13 +91,9 @@ set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variabl
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Werror")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS ${COMPILER_FLAGS})
|
||||
set(CMAKE_C_FLAGS ${COMPILER_FLAGS})
|
||||
# Always use the base flags and add our compiler flags at the bacl
|
||||
set(CMAKE_CXX_FLAGS "${CXX_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${C_BASE_FLAGS} ${COMPILER_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
set(CMAKE_C_FLAGS_RELEASE ${COMPILER_FLAGS_RELEASE})
|
||||
@@ -57,17 +103,32 @@ set(CMAKE_C_FLAGS_DEBUG ${COMPILER_FLAGS_DEBUG})
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "")
|
||||
|
||||
if (GCC_ENABLE_LEAK_CHECK)
|
||||
check_linker_flag("-fsanitize=leak" SUPPORTS_FSANITIZE_LEAK)
|
||||
IF (MINGW)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++ -Wl,--enable-auto-import")
|
||||
ENDIF(MINGW)
|
||||
|
||||
if (SUPPORTS_FSANITIZE_LEAK)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=leak")
|
||||
endif()
|
||||
if (SANITIZE_FLAGS)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g -rdynamic")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-g")
|
||||
IF(NOT MINGW)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -rdynamic")
|
||||
# Allow the linker to perform dead code elimination; this is considered
|
||||
# experimental for COFF and PE formats and thus disabled for Windows builds
|
||||
# (https://sourceware.org/binutils/docs/ld/Options.html)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
ENDIF(NOT MINGW)
|
||||
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-zignore")
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
target_compile_options(compiler INTERFACE "-Werror")
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed width format macros are available
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
|
||||
+41
-27
@@ -8,36 +8,41 @@ MESSAGE(STATUS "Doing configuration specific to visual studio...")
|
||||
set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS Debug)
|
||||
|
||||
option(MSVC_USE_RUNTIME_DLL "Use the dynamically linked version of the runtime" OFF)
|
||||
option(MSVC_RELEASE_DEBUGGING "Set options that allow to debug release builds" OFF)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE MSVC_USE_RUNTIME_DLL)
|
||||
MARK_AS_ADVANCED(FORCE MSVC_RELEASE_DEBUGGING)
|
||||
|
||||
# These are the warnings we disable
|
||||
set(WARNING_FLAGS
|
||||
/wd"4100" # unreferenced formal parameters
|
||||
/wd"4127" # constant conditional (assert)
|
||||
/wd"4201" # nonstandard extension used: nameless struct/union (happens a lot in Windows include headers)
|
||||
/wd"4290" # C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
|
||||
/wd"4390" # empty control statement (triggered by nprintf and mprintf's inside of one-line if's, etc)
|
||||
/wd"4410" # illegal size for operand... ie... fxch st(1)
|
||||
/wd"4511" # copy constructor could not be generated (happens a lot in Windows include headers)
|
||||
/wd"4512" # assignment operator could not be generated (happens a lot in Windows include headers)
|
||||
/wd"4514" # unreferenced inline function removed
|
||||
/wd"4611" # _setjmp warning. Since we use setjmp alot, and we don't really use constructors or destructors, this warning doesn't really apply to us.
|
||||
/wd"4663" # C++ language change (template specification)
|
||||
/wd"4710" # is inline function not expanded (who cares?)
|
||||
/wd"4711" # tells us an inline function was expanded (who cares?)
|
||||
/wd"4786" # is identifier truncated to 255 characters (happens all the time in Microsoft #includes) -- Goober5000"
|
||||
/wd"4996" # deprecated strcpy, strcat, sprintf, etc. (from MSVC 2005) - taylor
|
||||
/wd"4311" # Disables warnings about casting pointer types to ints. The funny thing is these warnings can't be resolved, just disabled... - m!m
|
||||
/wd"4302" # Same as above - m!m
|
||||
/wd"4366" # The result of the unary '&' operator may be unaligned - m!m
|
||||
$<$<CONFIG:Release>:/wd"4101"> # In release mode there are unreferenced variables because debug needs them
|
||||
/wd4100 # unreferenced formal parameters
|
||||
/wd4127 # constant conditional (assert)
|
||||
/wd4201 # nonstandard extension used: nameless struct/union (happens a lot in Windows include headers)
|
||||
/wd4290 # C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
|
||||
/wd4390 # empty control statement (triggered by nprintf and mprintf's inside of one-line if's, etc)
|
||||
/wd4410 # illegal size for operand... ie... fxch st(1)
|
||||
/wd4511 # copy constructor could not be generated (happens a lot in Windows include headers)
|
||||
/wd4512 # assignment operator could not be generated (happens a lot in Windows include headers)
|
||||
/wd4514 # unreferenced inline function removed
|
||||
/wd4611 # _setjmp warning. Since we use setjmp alot, and we don't really use constructors or destructors, this warning doesn't really apply to us.
|
||||
/wd4663 # C++ language change (template specification)
|
||||
/wd4710 # is inline function not expanded (who cares?)
|
||||
/wd4711 # tells us an inline function was expanded (who cares?)
|
||||
/wd4786 # is identifier truncated to 255 characters (happens all the time in Microsoft #includes) -- Goober5000"
|
||||
/wd4996 # deprecated strcpy, strcat, sprintf, etc. (from MSVC 2005) - taylor
|
||||
/wd4311 # Disables warnings about casting pointer types to ints. The funny thing is these warnings can't be resolved, just disabled... - m!m
|
||||
/wd4302 # Same as above - m!m
|
||||
/wd4366 # The result of the unary '&' operator may be unaligned - m!m
|
||||
/wd4592 # "symbol will be dynamically initialized" is being generated by a compiler bug, see https://stackoverflow.com/a/34027257 for an explanation - m!m
|
||||
$<$<CONFIG:Release>:/wd4101> # In release mode there are unreferenced variables because debug needs them
|
||||
/wd4995 # "'vsprintf': name was marked as #pragma deprecated" is being caused by our custom definition of vsprintf. I have no idea what causes this or how to fix it - m!m
|
||||
)
|
||||
|
||||
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
|
||||
|
||||
# Base
|
||||
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo")
|
||||
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo")
|
||||
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /DYNAMICBASE:NO /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "")
|
||||
@@ -50,11 +55,15 @@ set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "/LTCG")
|
||||
|
||||
globally_enable_extra_compiler_warnings()
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("/Zo" MSVC_COMPILER_SUPPORTS_ARCH_ZO)
|
||||
if (MSVC_RELEASE_DEBUGGING)
|
||||
CHECK_CXX_COMPILER_FLAG("/Zo" MSVC_COMPILER_SUPPORTS_ARCH_ZO)
|
||||
|
||||
if (MSVC_COMPILER_SUPPORTS_ARCH_ZO)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zo")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zo")
|
||||
if (MSVC_COMPILER_SUPPORTS_ARCH_ZO)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zo")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zo")
|
||||
endif()
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG")
|
||||
endif()
|
||||
|
||||
IF(MSVC_USE_RUNTIME_DLL)
|
||||
@@ -81,7 +90,7 @@ ENDIF(MSVC_USE_RUNTIME_DLL)
|
||||
INCLUDE(MSVCMultipleProcessCompile)
|
||||
|
||||
# Visual Studio supports compiling for multiple vector instruction sets
|
||||
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX)
|
||||
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX AVX2)
|
||||
|
||||
if (NOT DEFINED MSVC_SIMD_INSTRUCTIONS)
|
||||
detect_simd_instructions(MSVC_DETECTED_SIMD_INSTRUCTIONS)
|
||||
@@ -127,4 +136,9 @@ else()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE
|
||||
_CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX)
|
||||
_CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX "$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>")
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
target_compile_options(compiler INTERFACE "/WX")
|
||||
endif()
|
||||
@@ -20,7 +20,7 @@ ENDIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# Copy release settings to FastDebug
|
||||
set(CMAKE_C_FLAGS_FASTDEBUG "${CMAKE_C_FLAGS_RELEASE}")
|
||||
set(CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_FASTDEBUG "${CMAKE_EXE_LINKER_RELEASE}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_FASTDEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_FASTDEBUG "${CMAKE_STATIC_LINKER_FLAGS_RELEASE}")
|
||||
|
||||
if (MSVC)
|
||||
@@ -30,4 +30,4 @@ if (MSVC)
|
||||
|
||||
string(REPLACE "/MD" "/MDd" CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_FASTDEBUG}")
|
||||
string(REPLACE "/MT" "/MTd" CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_FASTDEBUG}")
|
||||
endif()
|
||||
endif()
|
||||
+50
-22
@@ -66,13 +66,33 @@ ENDIF(EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${FILE}\")
|
||||
SET(${OUTVAR} "${CMAKE_COMMAND}" -P ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${NAME} PARENT_SCOPE)
|
||||
ENDFUNCTION(EP_CHECK_FILE_EXISTS)
|
||||
|
||||
MACRO(COPY_FILES_TO_TARGET _target)
|
||||
FOREACH(file IN LISTS TARGET_COPY_FILES)
|
||||
MACRO(COPY_FILE_TO_TARGET _target _file)
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${file}" "$<TARGET_FILE_DIR:${_target}>"
|
||||
COMMENT "copying '${file}'..."
|
||||
COMMAND cp -a "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
)
|
||||
else()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_file}" "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "copying '${_file}'..."
|
||||
)
|
||||
endif()
|
||||
endmacro(COPY_FILE_TO_TARGET)
|
||||
|
||||
MACRO(COPY_FILES_TO_TARGET _target)
|
||||
if(UNIX)
|
||||
ADD_CUSTOM_COMMAND(
|
||||
TARGET ${_target} POST_BUILD
|
||||
COMMAND mkdir -p "$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/"
|
||||
COMMENT "Creating '$<TARGET_FILE_DIR:${_target}>/${LIBRAY_DESTINATION}/'..."
|
||||
)
|
||||
endif()
|
||||
|
||||
FOREACH(file IN LISTS TARGET_COPY_FILES)
|
||||
COPY_FILE_TO_TARGET("${_target}" "${file}")
|
||||
ENDFOREACH(file)
|
||||
ENDMACRO(COPY_FILES_TO_TARGET)
|
||||
|
||||
@@ -96,7 +116,7 @@ function(CONVERT_OLD_LIBRARIES)
|
||||
else("${lib}" STREQUAL "debug")
|
||||
# Expecting normal library
|
||||
if(is_debug)
|
||||
list(APPEND out_list "$<$<CONFIG:Debug>:${lib}>")
|
||||
list(APPEND out_list "$<$<CONFIG:Debug>:${lib}>" "$<$<CONFIG:FastDebug>:${lib}>")
|
||||
elseif(is_optimized)
|
||||
list(APPEND out_list "$<$<CONFIG:Release>:${lib}>")
|
||||
else(is_debug)
|
||||
@@ -121,28 +141,26 @@ macro(set_if_not_defined VAR VALUE)
|
||||
endmacro(set_if_not_defined)
|
||||
|
||||
macro(configure_cotire target)
|
||||
IF(COTIRE_ENABLE)
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
|
||||
# add ignored paths for the precompiled header here
|
||||
set_target_properties(code PROPERTIES COTIRE_PREFIX_HEADER_IGNORE_PATH
|
||||
"${CMAKE_SOURCE_DIR};${CMAKE_BINARY_DIR}")
|
||||
|
||||
IF(DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
cotire(${target} CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES})
|
||||
ELSE(DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
cotire(${target})
|
||||
ENDIF(DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
ENDIF(COTIRE_ENABLE)
|
||||
cotire(${target})
|
||||
endmacro(configure_cotire)
|
||||
|
||||
macro(add_target_copy_files)
|
||||
INSTALL(FILES ${ARGN}
|
||||
DESTINATION ${BINARY_DESTINATION}
|
||||
)
|
||||
foreach(file ${ARGN})
|
||||
if (IS_DIRECTORY "${file}")
|
||||
INSTALL(DIRECTORY ${file}
|
||||
DESTINATION ${LIBRAY_DESTINATION}
|
||||
)
|
||||
else()
|
||||
INSTALL(FILES ${file}
|
||||
DESTINATION ${LIBRAY_DESTINATION}
|
||||
)
|
||||
endif()
|
||||
|
||||
SET(TARGET_COPY_FILES ${TARGET_COPY_FILES} ${ARGN} CACHE INTERNAL "" FORCE)
|
||||
SET(TARGET_COPY_FILES ${TARGET_COPY_FILES} ${file} CACHE INTERNAL "" FORCE)
|
||||
endforeach()
|
||||
endmacro(add_target_copy_files)
|
||||
|
||||
function(detect_simd_instructions _out_var)
|
||||
@@ -167,3 +185,13 @@ function (check_linker_flag _flag _out_var)
|
||||
SET(CMAKE_REQUIRED_FLAGS "${_flag}")
|
||||
CHECK_C_COMPILER_FLAG("" ${_out_var})
|
||||
endfunction(check_linker_flag)
|
||||
|
||||
# Suppresses warnings for the specified target
|
||||
function(suppress_warnings _target)
|
||||
if (MSVC)
|
||||
target_compile_options(${_target} PRIVATE "/W0")
|
||||
else()
|
||||
# Assume everything else uses GCC style options
|
||||
target_compile_options(${_target} PRIVATE "-w")
|
||||
endif()
|
||||
endfunction(suppress_warnings)
|
||||
+3
-3
@@ -7,8 +7,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
|
||||
endif()
|
||||
|
||||
set_if_not_defined(FSO_VERSION_MAJOR 3)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 7)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 5)
|
||||
set_if_not_defined(FSO_VERSION_MINOR 8)
|
||||
set_if_not_defined(FSO_VERSION_BUILD 1)
|
||||
|
||||
# A numeric revision e.g. the CI build number
|
||||
set_if_not_defined(FSO_VERSION_REVISION 0)
|
||||
@@ -35,7 +35,7 @@ ELSE()
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_VERSION_MAJOR}_${FSO_VERSION_MINOR}_${FSO_VERSION_BUILD}_${FSO_VERSION_REVISION_STR}")
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
IF(IS_64BIT)
|
||||
# This is a 64-bit builds
|
||||
SET(FSO_BINARY_SUFFIX "${FSO_BINARY_SUFFIX}_x64")
|
||||
ENDIF()
|
||||
|
||||
+17
-6
@@ -19,28 +19,33 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${FREESPACE_HEADERS})
|
||||
TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR})
|
||||
TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
|
||||
|
||||
target_link_libraries(code PUBLIC gl_12)
|
||||
target_link_libraries(code PUBLIC OpenGL)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${OPENAL_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC openal)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC oggvorbis)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${SDL_LIBS})
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ffmpeg)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC utfcpp)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC platform)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC compiler)
|
||||
|
||||
target_link_libraries(code PUBLIC md5)
|
||||
|
||||
IF (FSO_USE_SPEECH)
|
||||
find_package(Speech REQUIRED)
|
||||
target_link_libraries(code PUBLIC speech)
|
||||
ENDIF(FSO_USE_SPEECH)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
|
||||
|
||||
# Headers for standalone "gui" on UNIX
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
|
||||
ENDIF(UNIX)
|
||||
|
||||
@@ -50,7 +55,13 @@ IF(FSO_BUILD_TOOLS)
|
||||
ADD_SUBDIRECTORY(cfileextractor)
|
||||
ENDIF(FSO_BUILD_TOOLS)
|
||||
|
||||
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_header.h")
|
||||
|
||||
include(util)
|
||||
configure_cotire(code)
|
||||
|
||||
include(../cmake/Cxx11.cmake)
|
||||
# Ensure that Xcode generates debug symbols on macOS for Debug builds
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT[variant=Debug] "NO")
|
||||
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN[variant=Debug] "NO")
|
||||
+13
-73
@@ -18,8 +18,9 @@
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "object/waypoint.h"
|
||||
#include "physics/physics.h"
|
||||
#include "ship/ship_flags.h"
|
||||
|
||||
struct ship_weapon;
|
||||
class ship_weapon;
|
||||
class ship_subsys;
|
||||
class object;
|
||||
class ship_info;
|
||||
@@ -27,48 +28,13 @@ class ship_info;
|
||||
#define AI_DEFAULT_CLASS 3 // default AI class for new ships (Fred)
|
||||
|
||||
typedef struct ai_flag_name {
|
||||
int flag;
|
||||
AI::AI_Flags flag;
|
||||
char flag_name[TOKEN_LENGTH];
|
||||
int flag_list;
|
||||
} ai_flag_name;
|
||||
|
||||
#define MAX_AI_FLAG_NAMES 2
|
||||
extern ai_flag_name Ai_flag_names[];
|
||||
|
||||
#define AIF_FORMATION_WING (1 << 0) // Fly in formation as part of wing.
|
||||
#define AIF_AWAITING_REPAIR (1 << 1) // Awaiting a repair ship.
|
||||
#define AIF_BEING_REPAIRED (1 << 2) // Currently docked with repair ship.
|
||||
#define AIF_REPAIRING (1 << 3) // Repairing a ship (or going to repair a ship)
|
||||
#define AIF_SEEK_LOCK (1 << 4) // set if should focus on gaining aspect lock, not hitting with lasers
|
||||
#define AIF_FORMATION_OBJECT (1 << 5) // Fly in formation off a specific object.
|
||||
#define AIF_TEMPORARY_IGNORE (1 << 6) // Means current ignore_objnum is only temporary, not an order from the player.
|
||||
#define AIF_USE_EXIT_PATH (1 << 7) // Used by path code, to flag path as an exit path
|
||||
#define AIF_USE_STATIC_PATH (1 << 8) // Used by path code, use fixed path, don't try to recreate
|
||||
#define AIF_TARGET_COLLISION (1 << 9) // Collided with aip->target_objnum last frame. Avoid that ship for half a second or so.
|
||||
#define AIF_UNLOAD_SECONDARIES (1 << 10) // Fire secondaries as fast as possible!
|
||||
#define AIF_ON_SUBSYS_PATH (1 << 11) // Current path leads to a subsystem
|
||||
#define AIF_AVOID_SHOCKWAVE_SHIP (1 << 12) // Avoid an existing shockwave from a ship.
|
||||
#define AIF_AVOID_SHOCKWAVE_WEAPON (1 << 13) // Avoid an expected shockwave from a weapon. shockwave_object field contains object index.
|
||||
#define AIF_AVOID_SHOCKWAVE_STARTED (1 << 14) // Already started avoiding shockwave, don't keep deciding whether to avoid.
|
||||
#define AIF_ATTACK_SLOWLY (1 << 15) // Move slowly while attacking.
|
||||
#define AIF_REPAIR_OBSTRUCTED (1 << 16) // Ship wants to be repaired, but path is obstructed.
|
||||
#define AIF_KAMIKAZE (1 << 17) // Crash into target
|
||||
#define AIF_NO_DYNAMIC (1 << 18) // Not allowed to get dynamic goals
|
||||
#define AIF_AVOIDING_SMALL_SHIP (1 << 19) // Avoiding a player ship.
|
||||
#define AIF_AVOIDING_BIG_SHIP (1 << 20) // Avoiding a large ship.
|
||||
#define AIF_BIG_SHIP_COLLIDE_RECOVER_1 (1 << 21) // Collided into a big ship. Recovering by flying away.
|
||||
#define AIF_BIG_SHIP_COLLIDE_RECOVER_2 (1 << 22) // Collided into a big ship. Fly towards big ship sphere perimeter.
|
||||
#define AIF_STEALTH_PURSUIT (1 << 23) // AI is trying to fight stealth ship
|
||||
|
||||
// Goober5000
|
||||
#define AIF_UNLOAD_PRIMARIES (1 << 24) // Fire primaries as fast as possible!
|
||||
#define AIF_TRYING_UNSUCCESSFULLY_TO_WARP (1 << 25) // Trying to warp, but can't warp at the moment
|
||||
|
||||
#define AIF_FREE_AFTERBURNER_USE (1 << 26) // Use afterburners while following waypoints or flying towards objects
|
||||
|
||||
#define AIF_AVOID_SHOCKWAVE (AIF_AVOID_SHOCKWAVE_SHIP | AIF_AVOID_SHOCKWAVE_WEAPON)
|
||||
#define AIF_FORMATION (AIF_FORMATION_WING | AIF_FORMATION_OBJECT)
|
||||
|
||||
// dock_orient_and_approach() modes.
|
||||
#define DOA_APPROACH 1 // Approach the current point on the path (aip->path_cur)
|
||||
#define DOA_DOCK 2 // Dock with goal object.
|
||||
@@ -100,19 +66,6 @@ extern ai_flag_name Ai_flag_names[];
|
||||
#define AIG_TYPE_PLAYER_WING 4 // from player direct to wing
|
||||
#define AIG_TYPE_DYNAMIC 5 // created on the fly
|
||||
|
||||
// flags for AI_GOALS
|
||||
#define AIGF_DOCKER_INDEX_VALID (1<<0) // when set, index field for docker is valid
|
||||
#define AIGF_DOCKEE_INDEX_VALID (1<<1) // when set, index field for dockee is valid
|
||||
#define AIGF_GOAL_ON_HOLD (1<<2) // when set, this goal cannot currently be satisfied, although it could be in the future
|
||||
#define AIGF_SUBSYS_NEEDS_FIXUP (1<<3) // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
|
||||
#define AIGF_GOAL_OVERRIDE (1<<4) // paired with AIG_TYPE_DYNAMIC to mean this goal overrides any other goal
|
||||
#define AIGF_PURGE (1<<5) // purge this goal next time we process
|
||||
#define AIGF_GOALS_PURGED (1<<6) // this goal has already caused other goals to get purged
|
||||
#define AIGF_DEPART_SOUND_PLAYED (1<<7) // Goober5000 - replacement for AL's hack ;)
|
||||
#define AIGF_TARGET_OWN_TEAM (1<<8) // Goober5000 - removes standard precautions against AI ships taking traitorous actions
|
||||
|
||||
#define AIGF_DOCK_INDEXES_VALID (AIGF_DOCKER_INDEX_VALID|AIGF_DOCKEE_INDEX_VALID)
|
||||
|
||||
// Flags to ai_turn_towards_vector().
|
||||
#define AITTV_FAST (1<<0) // Turn fast, not slowed down based on skill level.
|
||||
#define AITTV_VIA_SEXP (1<<1) // Goober5000 - via sexp
|
||||
@@ -120,23 +73,13 @@ extern ai_flag_name Ai_flag_names[];
|
||||
|
||||
#define KAMIKAZE_HULL_ON_DEATH -1000.0f // Hull strength ship gets set to if it crash-dies.
|
||||
|
||||
// flags for possible ai overrides
|
||||
#define AIORF_FULL (1<<0) // Full sexp control
|
||||
#define AIORF_ROLL (1<<1) // Sexp forced roll maneuver
|
||||
#define AIORF_PITCH (1<<2) // Sexp forced pitch change
|
||||
#define AIORF_HEADING (1<<3) // Sexp forced heading change
|
||||
#define AIORF_FULL_LAT (1<<4) // full control over up/side/forward movement
|
||||
#define AIORF_UP (1<<5) // vertical movement
|
||||
#define AIORF_SIDEWAYS (1<<6) // horizontal movement
|
||||
#define AIORF_FORWARD (1<<7) // forward movement
|
||||
|
||||
// structure for AI goals
|
||||
typedef struct ai_goal {
|
||||
int signature; // Unique identifier. All goals ever created (per mission) have a unique signature.
|
||||
int ai_mode; // one of the AIM_* modes for this goal
|
||||
int ai_submode; // maybe need a submode
|
||||
int type; // one of the AIG_TYPE_* values above
|
||||
int flags; // one of the AIGF_* values above
|
||||
flagset<AI::Goal_Flags> flags; // one of the AIGF_* values above
|
||||
fix time; // time at which this goal was issued.
|
||||
int priority; // how important is this goal -- number 0 - 100
|
||||
|
||||
@@ -227,10 +170,8 @@ typedef struct ai_class {
|
||||
int ai_chance_to_use_missiles_on_plr[NUM_SKILL_LEVELS];
|
||||
float ai_max_aim_update_delay[NUM_SKILL_LEVELS];
|
||||
float ai_turret_max_aim_update_delay[NUM_SKILL_LEVELS];
|
||||
int ai_profile_flags; //Holds the state of flags that are set
|
||||
int ai_profile_flags_set; //Holds which flags are set and which are just left alone
|
||||
int ai_profile_flags2;
|
||||
int ai_profile_flags2_set;
|
||||
flagset<AI::Profile_Flags> ai_profile_flags; //Holds the state of flags that are set
|
||||
flagset<AI::Profile_Flags> ai_profile_flags_set; //Holds which flags are set and which are just left alone
|
||||
|
||||
//SUSHI: These are optional overrides to an AI class to prevent the automatic scaling based on AI class index
|
||||
int ai_aburn_use_factor[NUM_SKILL_LEVELS];
|
||||
@@ -327,7 +268,7 @@ extern pnode *Ppfp; // Free pointer in path points.
|
||||
#define MAX_IGNORE_NEW_OBJECTS 7
|
||||
|
||||
typedef struct ai_info {
|
||||
int ai_flags; // Special flags for AI behavior.
|
||||
flagset<AI::AI_Flags> ai_flags; // Special flags for AI behavior.
|
||||
int shipnum; // Ship using this slot, -1 means none.
|
||||
int type; //
|
||||
int wing; // Member of what wing? -1 means none.
|
||||
@@ -460,8 +401,7 @@ typedef struct ai_info {
|
||||
int ai_chance_to_use_missiles_on_plr;
|
||||
float ai_max_aim_update_delay;
|
||||
float ai_turret_max_aim_update_delay;
|
||||
int ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
|
||||
int ai_profile_flags2;
|
||||
flagset<AI::Profile_Flags> ai_profile_flags; //Holds AI_Profiles flags (possibly overriden by AI class) that actually apply to AI
|
||||
|
||||
|
||||
union {
|
||||
@@ -545,7 +485,7 @@ typedef struct ai_info {
|
||||
vec3d artillery_lock_pos; // base position of the lock point on (in model's frame of reference)
|
||||
float lethality; // measure of how dangerous ship is to enemy BIG|HUGE ships (likelyhood of targeting)
|
||||
|
||||
int ai_override_flags; // flags for marking ai overrides from sexp or lua systems
|
||||
flagset<AI::Maneuver_Override_Flags> ai_override_flags; // flags for marking ai overrides from sexp or lua systems
|
||||
control_info ai_override_ci; // ai override control info
|
||||
int ai_override_timestamp; // mark for when to end the current override
|
||||
} ai_info;
|
||||
@@ -619,7 +559,7 @@ void set_wingnum(int objnum, int wingnum);
|
||||
char *ai_get_goal_target_name(const char *name, int *index);
|
||||
|
||||
extern void init_ai_system(void);
|
||||
extern void ai_attack_object(object *attacker, object *attacked, ship_subsys *ssp);
|
||||
extern void ai_attack_object(object *attacker, object *attacked, ship_subsys *ssp, int ship_info_index = -1);
|
||||
extern void ai_evade_object(object *evader, object *evaded);
|
||||
extern void ai_ignore_object(object *ignorer, object *ignored, int ignore_new);
|
||||
extern void ai_ignore_wing(object *ignorer, int wingnum);
|
||||
@@ -628,7 +568,7 @@ extern void ai_stay_still(object *still_objp, vec3d *view_pos);
|
||||
extern void ai_do_default_behavior(object *obj);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum, int method);
|
||||
extern void ai_ship_destroy(int shipnum, Ship::Exit_Flags method);
|
||||
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = NULL, int sexp_flags = 0);
|
||||
extern void init_ai_object(int objnum);
|
||||
extern void ai_init(void); // Call this one to parse ai.tbl.
|
||||
@@ -689,7 +629,7 @@ extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
|
||||
extern void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip);
|
||||
|
||||
extern int is_instructor(object *objp);
|
||||
extern int find_enemy(int objnum, float range, int max_attackers);
|
||||
extern int find_enemy(int objnum, float range, int max_attackers, int ship_info_index = -1);
|
||||
|
||||
float ai_get_weapon_speed(ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, vec3d *gun_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
@@ -711,7 +651,7 @@ extern int find_danger_weapon(object *sobjp, float dtime, float *atime, float do
|
||||
void ai_set_mode_warp_out(object *objp, ai_info *aip);
|
||||
|
||||
// prototyped by Goober5000
|
||||
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers);
|
||||
int get_nearest_objnum(int objnum, int enemy_team_mask, int enemy_wing, float range, int max_attackers, int ship_info_index);
|
||||
|
||||
// moved to header file by Goober5000
|
||||
void ai_announce_ship_dying(object *dying_objp);
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
#ifndef AI_FLAGS_H
|
||||
#define AI_FLAGS_H
|
||||
|
||||
#include "globalincs/flagset.h"
|
||||
|
||||
namespace AI {
|
||||
FLAG_LIST(AI_Flags) {
|
||||
Formation_wing, // Fly in formation as part of wing.
|
||||
Awaiting_repair, // Awaiting a repair ship.
|
||||
Being_repaired, // Currently docked with repair ship.
|
||||
Repairing, // Repairing a ship (or going to repair a ship)
|
||||
Seek_lock, // set if should focus on gaining aspect lock, not hitting with lasers
|
||||
Formation_object, // Fly in formation off a specific object.
|
||||
Temporary_ignore, // Means current ignore_objnum is only temporary, not an order from the player.
|
||||
Use_exit_path, // Used by path code, to flag path as an exit path
|
||||
Use_static_path, // Used by path code, use fixed path, don't try to recreate
|
||||
Target_collision, // Collided with aip->target_objnum last frame. Avoid that ship for half a second or so.
|
||||
Unload_secondaries, // Fire secondaries as fast as possible!
|
||||
On_subsys_path, // Current path leads to a subsystem
|
||||
Avoid_shockwave_ship, // Avoid an existing shockwave from a ship.
|
||||
Avoid_shockwave_weapon, // Avoid an expected shockwave from a weapon. shockwave_object field contains object index.
|
||||
Avoid_shockwave_started, // Already started avoiding shockwave, don't keep deciding whether to avoid.
|
||||
Attack_slowly, // Move slowly while attacking.
|
||||
Repair_obstructed, // Ship wants to be repaired, but path is obstructed.
|
||||
Kamikaze, // Crash into target
|
||||
No_dynamic, // Not allowed to get dynamic goals
|
||||
Avoiding_small_ship, // Avoiding a player ship.
|
||||
Avoiding_big_ship, // Avoiding a large ship.
|
||||
Big_ship_collide_recover_1, // Collided into a big ship. Recovering by flying away.
|
||||
Big_ship_collide_recover_2, // Collided into a big ship. Fly towards big ship sphere perimeter.
|
||||
Stealth_pursuit, // AI is trying to fight stealth ship
|
||||
Unload_primaries, // Fire primaries as fast as possible!
|
||||
Trying_unsuccessfully_to_warp, // Trying to warp, but can't warp at the moment
|
||||
Free_afterburner_use, // Use afterburners while following waypoints or flying towards objects
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
FLAG_LIST(Goal_Flags) {
|
||||
Docker_index_valid, // when set, index field for docker is valid
|
||||
Dockee_index_valid, // when set, index field for dockee is valid
|
||||
Goal_on_hold, // when set, this goal cannot currently be satisfied, although it could be in the future
|
||||
Subsys_needs_fixup, // when set, the subsystem index (for a destroy subsystem goal) is invalid and must be gotten from the subsys name stored in docker.name field!!
|
||||
Goal_override, // paired with AIG_TYPE_DYNAMIC to mean this goal overrides any other goal
|
||||
Purge, // purge this goal next time we process
|
||||
Goals_purged, // this goal has already caused other goals to get purged
|
||||
Depart_sound_played,// Goober5000 - replacement for AL's hack ;)
|
||||
Target_own_team,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
FLAG_LIST(Maneuver_Override_Flags) {
|
||||
Full, // Full sexp control
|
||||
Roll, // Sexp forced roll maneuver
|
||||
Pitch, // Sexp forced pitch change
|
||||
Heading, // Sexp forced heading change
|
||||
Full_lat, // full control over up/side/forward movement
|
||||
Up, // vertical movement
|
||||
Sideways, // horizontal movement
|
||||
Forward, // forward movement
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
FLAG_LIST(Profile_Flags) {
|
||||
Advanced_turret_fov_edge_checks,
|
||||
Ai_aims_from_ship_center,
|
||||
Ai_can_slow_down_attacking_big_ships,
|
||||
Ai_guards_specific_ship_in_wing,
|
||||
All_ships_manage_shields,
|
||||
Allow_multi_event_scoring,
|
||||
Allow_primary_link_at_start,
|
||||
Allow_rapid_secondary_dumbfire,
|
||||
Allow_turrets_target_weapons_freely,
|
||||
Allow_vertical_dodge,
|
||||
Aspect_invulnerability_fix,
|
||||
Aspect_lock_countermeasure,
|
||||
Assist_scoring_scales_with_damage,
|
||||
Beams_damage_weapons,
|
||||
Big_ships_can_attack_beam_turrets_on_untargeted_ships,
|
||||
Disable_linked_fire_penalty,
|
||||
Disable_weapon_damage_scaling,
|
||||
Dont_insert_random_turret_fire_delay,
|
||||
Fix_ai_class_bug,
|
||||
Fix_ai_path_order_bug,
|
||||
Fix_heat_seeker_stealth_bug,
|
||||
Fix_linked_primary_bug,
|
||||
Force_beam_turret_fov,
|
||||
Glide_decay_requires_thrust,
|
||||
Hack_improve_non_homing_swarm_turret_fire_accuracy,
|
||||
Huge_turret_weapons_ignore_bombs,
|
||||
Include_beams_in_stat_calcs,
|
||||
Kill_scoring_scales_with_damage,
|
||||
Multi_allow_empty_primaries,
|
||||
Multi_allow_empty_secondaries,
|
||||
Navigation_subsys_governs_warp,
|
||||
No_min_dock_speed_cap,
|
||||
No_special_player_avoid,
|
||||
No_warp_camera,
|
||||
Perform_fewer_scream_checks,
|
||||
Player_weapon_scale_fix,
|
||||
Prevent_targeting_bombs_beyond_range,
|
||||
Require_turret_to_have_target_in_fov,
|
||||
Shockwaves_damage_small_ship_subsystems,
|
||||
Smart_afterburner_management,
|
||||
Smart_primary_weapon_selection,
|
||||
Smart_secondary_weapon_selection,
|
||||
Smart_shield_management,
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turred_tagged_only_targeting,
|
||||
Turrets_ignore_target_radius,
|
||||
Use_additive_weapon_velocity,
|
||||
Use_newtonian_dampening,
|
||||
Use_only_single_fov_for_turrets,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
+126
-74
@@ -28,28 +28,17 @@ static char Default_profile_name[NAME_LENGTH];
|
||||
|
||||
|
||||
// utility
|
||||
void set_flag(ai_profile_t *profile, char *name, int flag, int type)
|
||||
void set_flag(ai_profile_t *profile, const char *name, AI::Profile_Flags flag)
|
||||
{
|
||||
if (optional_string(name))
|
||||
{
|
||||
bool val;
|
||||
stuff_boolean(&val);
|
||||
|
||||
if (type == AIP_FLAG) {
|
||||
if (val)
|
||||
profile->flags |= flag;
|
||||
else
|
||||
profile->flags &= ~flag;
|
||||
} else {
|
||||
if (val)
|
||||
profile->flags2 |= flag;
|
||||
else
|
||||
profile->flags2 &= ~flag;
|
||||
}
|
||||
profile->flags.set(flag, val);
|
||||
}
|
||||
}
|
||||
|
||||
char *AI_path_types[] = {
|
||||
const char *AI_path_types[] = {
|
||||
"normal",
|
||||
"alt1",
|
||||
};
|
||||
@@ -152,12 +141,12 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
// base profile, so zero it out
|
||||
if (profile == &Ai_profiles[0])
|
||||
{
|
||||
memset(profile, 0, sizeof(ai_profile_t));
|
||||
profile->reset();
|
||||
}
|
||||
// brand new profile, so set it to the base defaults
|
||||
else
|
||||
{
|
||||
memcpy(profile, &Ai_profiles[0], sizeof(ai_profile_t));
|
||||
*profile = Ai_profiles[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,93 +345,93 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
}
|
||||
|
||||
if (optional_string("$Detail Distance Multiplier:"))
|
||||
parse_float_list(profile->detail_distance_mult, NUM_SKILL_LEVELS);
|
||||
parse_float_list(profile->detail_distance_mult, MAX_DETAIL_LEVEL + 1);
|
||||
|
||||
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS, AIP_FLAG);
|
||||
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships);
|
||||
|
||||
set_flag(profile, "$smart primary weapon selection:", AIPF_SMART_PRIMARY_WEAPON_SELECTION, AIP_FLAG);
|
||||
set_flag(profile, "$smart primary weapon selection:", AI::Profile_Flags::Smart_primary_weapon_selection);
|
||||
|
||||
set_flag(profile, "$smart secondary weapon selection:", AIPF_SMART_SECONDARY_WEAPON_SELECTION, AIP_FLAG);
|
||||
set_flag(profile, "$smart secondary weapon selection:", AI::Profile_Flags::Smart_secondary_weapon_selection);
|
||||
|
||||
set_flag(profile, "$smart shield management:", AIPF_SMART_SHIELD_MANAGEMENT, AIP_FLAG);
|
||||
set_flag(profile, "$smart shield management:", AI::Profile_Flags::Smart_shield_management);
|
||||
|
||||
set_flag(profile, "$smart afterburner management:", AIPF_SMART_AFTERBURNER_MANAGEMENT, AIP_FLAG);
|
||||
set_flag(profile, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
|
||||
|
||||
set_flag(profile, "$allow rapid secondary dumbfire:", AIPF_ALLOW_RAPID_SECONDARY_DUMBFIRE, AIP_FLAG);
|
||||
set_flag(profile, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
|
||||
|
||||
set_flag(profile, "$huge turret weapons ignore bombs:", AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS, AIP_FLAG);
|
||||
set_flag(profile, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
|
||||
|
||||
set_flag(profile, "$don't insert random turret fire delay:", AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY, AIP_FLAG);
|
||||
set_flag(profile, "$don't insert random turret fire delay:", AI::Profile_Flags::Dont_insert_random_turret_fire_delay);
|
||||
|
||||
set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY, AIP_FLAG);
|
||||
set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AI::Profile_Flags::Hack_improve_non_homing_swarm_turret_fire_accuracy);
|
||||
|
||||
set_flag(profile, "$shockwaves damage small ship subsystems:", AIPF_SHOCKWAVES_DAMAGE_SMALL_SHIP_SUBSYSTEMS, AIP_FLAG);
|
||||
set_flag(profile, "$shockwaves damage small ship subsystems:", AI::Profile_Flags::Shockwaves_damage_small_ship_subsystems);
|
||||
|
||||
set_flag(profile, "$navigation subsystem governs warpout capability:", AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP, AIP_FLAG);
|
||||
set_flag(profile, "$navigation subsystem governs warpout capability:", AI::Profile_Flags::Navigation_subsys_governs_warp);
|
||||
|
||||
set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AIPF_NO_MIN_DOCK_SPEED_CAP, AIP_FLAG);
|
||||
set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AI::Profile_Flags::No_min_dock_speed_cap);
|
||||
|
||||
set_flag(profile, "$disable linked fire penalty:", AIPF_DISABLE_LINKED_FIRE_PENALTY, AIP_FLAG);
|
||||
set_flag(profile, "$disable linked fire penalty:", AI::Profile_Flags::Disable_linked_fire_penalty);
|
||||
|
||||
set_flag(profile, "$disable weapon damage scaling:", AIPF_DISABLE_WEAPON_DAMAGE_SCALING, AIP_FLAG);
|
||||
set_flag(profile, "$disable weapon damage scaling:", AI::Profile_Flags::Disable_weapon_damage_scaling);
|
||||
|
||||
set_flag(profile, "$use additive weapon velocity:", AIPF_USE_ADDITIVE_WEAPON_VELOCITY, AIP_FLAG);
|
||||
set_flag(profile, "$use additive weapon velocity:", AI::Profile_Flags::Use_additive_weapon_velocity);
|
||||
|
||||
set_flag(profile, "$use newtonian dampening:", AIPF_USE_NEWTONIAN_DAMPENING, AIP_FLAG);
|
||||
set_flag(profile, "$use newtonian dampening:", AI::Profile_Flags::Use_newtonian_dampening);
|
||||
|
||||
set_flag(profile, "$include beams for kills and assists:", AIPF_INCLUDE_BEAMS_IN_STAT_CALCS, AIP_FLAG);
|
||||
set_flag(profile, "$include beams for kills and assists:", AI::Profile_Flags::Include_beams_in_stat_calcs);
|
||||
|
||||
set_flag(profile, "$score kills based on damage caused:", AIPF_KILL_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
|
||||
set_flag(profile, "$score kills based on damage caused:", AI::Profile_Flags::Kill_scoring_scales_with_damage);
|
||||
|
||||
set_flag(profile, "$score assists based on damage caused:", AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
|
||||
set_flag(profile, "$score assists based on damage caused:", AI::Profile_Flags::Assist_scoring_scales_with_damage);
|
||||
|
||||
set_flag(profile, "$allow event and goal scoring in multiplayer:", AIPF_ALLOW_MULTI_EVENT_SCORING, AIP_FLAG);
|
||||
set_flag(profile, "$allow event and goal scoring in multiplayer:", AI::Profile_Flags::Allow_multi_event_scoring);
|
||||
|
||||
set_flag(profile, "$fix linked primary weapon decision bug:", AIPF_FIX_LINKED_PRIMARY_BUG, AIP_FLAG);
|
||||
set_flag(profile, "$fix linked primary weapon decision bug:", AI::Profile_Flags::Fix_linked_primary_bug);
|
||||
|
||||
set_flag(profile, "$prevent turrets targeting too distant bombs:", AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE, AIP_FLAG);
|
||||
set_flag(profile, "$prevent turrets targeting too distant bombs:", AI::Profile_Flags::Prevent_targeting_bombs_beyond_range);
|
||||
|
||||
set_flag(profile, "$smart subsystem targeting for turrets:", AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS, AIP_FLAG);
|
||||
set_flag(profile, "$smart subsystem targeting for turrets:", AI::Profile_Flags::Smart_subsystem_targeting_for_turrets);
|
||||
|
||||
set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AIPF_FIX_HEAT_SEEKER_STEALTH_BUG, AIP_FLAG);
|
||||
set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AI::Profile_Flags::Fix_heat_seeker_stealth_bug);
|
||||
|
||||
set_flag(profile, "$multi allow empty primaries:", AIPF_MULTI_ALLOW_EMPTY_PRIMARIES, AIP_FLAG);
|
||||
set_flag(profile, "$multi allow empty primaries:", AI::Profile_Flags::Multi_allow_empty_primaries);
|
||||
|
||||
set_flag(profile, "$multi allow empty secondaries:", AIPF_MULTI_ALLOW_EMPTY_SECONDARIES, AIP_FLAG);
|
||||
set_flag(profile, "$multi allow empty secondaries:", AI::Profile_Flags::Multi_allow_empty_secondaries);
|
||||
|
||||
set_flag(profile, "$allow turrets target weapons freely:", AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY, AIP_FLAG);
|
||||
set_flag(profile, "$allow turrets target weapons freely:", AI::Profile_Flags::Allow_turrets_target_weapons_freely);
|
||||
|
||||
set_flag(profile, "$use only single fov for turrets:", AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS, AIP_FLAG);
|
||||
set_flag(profile, "$use only single fov for turrets:", AI::Profile_Flags::Use_only_single_fov_for_turrets);
|
||||
|
||||
set_flag(profile, "$allow vertical dodge:", AIPF_ALLOW_VERTICAL_DODGE, AIP_FLAG);
|
||||
set_flag(profile, "$allow vertical dodge:", AI::Profile_Flags::Allow_vertical_dodge);
|
||||
|
||||
set_flag(profile, "$force beam turrets to use normal fov:", AIPF_FORCE_BEAM_TURRET_FOV, AIP_FLAG);
|
||||
set_flag(profile, "$force beam turrets to use normal fov:", AI::Profile_Flags::Force_beam_turret_fov);
|
||||
|
||||
set_flag(profile, "$fix ai class bug:", AIPF_FIX_AI_CLASS_BUG, AIP_FLAG);
|
||||
set_flag(profile, "$fix ai class bug:", AI::Profile_Flags::Fix_ai_class_bug);
|
||||
|
||||
set_flag(profile, "$turrets ignore targets radius in range checks:", AIPF2_TURRETS_IGNORE_TARGET_RADIUS, AIP_FLAG2);
|
||||
set_flag(profile, "$turrets ignore targets radius in range checks:", AI::Profile_Flags::Turrets_ignore_target_radius);
|
||||
|
||||
set_flag(profile, "$no extra collision avoidance vs player:", AIPF2_NO_SPECIAL_PLAYER_AVOID, AIP_FLAG2);
|
||||
set_flag(profile, "$no extra collision avoidance vs player:", AI::Profile_Flags::No_special_player_avoid);
|
||||
|
||||
set_flag(profile, "$perform fewer checks for death screams:", AIPF2_PERFORM_FEWER_SCREAM_CHECKS, AIP_FLAG2);
|
||||
set_flag(profile, "$perform fewer checks for death screams:", AI::Profile_Flags::Perform_fewer_scream_checks);
|
||||
|
||||
set_flag(profile, "$advanced turret fov edge checks:", AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS, AIP_FLAG2);
|
||||
set_flag(profile, "$advanced turret fov edge checks:", AI::Profile_Flags::Advanced_turret_fov_edge_checks);
|
||||
|
||||
set_flag(profile, "$require turrets to have target in fov:", AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV, AIP_FLAG2);
|
||||
set_flag(profile, "$require turrets to have target in fov:", AI::Profile_Flags::Require_turret_to_have_target_in_fov);
|
||||
|
||||
set_flag(profile, "$all ships manage shields:", AIPF2_ALL_SHIPS_MANAGE_SHIELDS, AIP_FLAG2);
|
||||
set_flag(profile, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields);
|
||||
|
||||
set_flag(profile, "$ai aims from ship center:", AIPF2_AI_AIMS_FROM_SHIP_CENTER, AIP_FLAG2);
|
||||
set_flag(profile, "$ai aims from ship center:", AI::Profile_Flags::Ai_aims_from_ship_center);
|
||||
|
||||
set_flag(profile, "$allow primary link at mission start:", AIPF2_ALLOW_PRIMARY_LINK_AT_START, AIP_FLAG2);
|
||||
set_flag(profile, "$allow primary link at mission start:", AI::Profile_Flags::Allow_primary_link_at_start);
|
||||
|
||||
set_flag(profile, "$allow beams to damage bombs:", AIPF2_BEAMS_DAMAGE_WEAPONS, AIP_FLAG2);
|
||||
set_flag(profile, "$allow beams to damage bombs:", AI::Profile_Flags::Beams_damage_weapons);
|
||||
|
||||
set_flag(profile, "$disable weapon damage scaling for player:", AIPF2_PLAYER_WEAPON_SCALE_FIX, AIP_FLAG2);
|
||||
set_flag(profile, "$disable weapon damage scaling for player:", AI::Profile_Flags::Player_weapon_scale_fix);
|
||||
|
||||
set_flag(profile, "$countermeasures affect aspect seekers:", AIPF2_ASPECT_LOCK_COUNTERMEASURE, AIP_FLAG2);
|
||||
set_flag(profile, "$countermeasures affect aspect seekers:", AI::Profile_Flags::Aspect_lock_countermeasure);
|
||||
|
||||
set_flag(profile, "$ai guards specific ship in wing:", AIPF2_AI_GUARDS_SPECIFIC_SHIP_IN_WING, AIP_FLAG2);
|
||||
set_flag(profile, "$ai guards specific ship in wing:", AI::Profile_Flags::Ai_guards_specific_ship_in_wing);
|
||||
|
||||
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
|
||||
if (optional_string("$ai path mode:"))
|
||||
@@ -457,17 +446,17 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
set_flag(profile, "$no warp camera:", AIPF2_NO_WARP_CAMERA, AIP_FLAG2);
|
||||
set_flag(profile, "$no warp camera:", AI::Profile_Flags::No_warp_camera);
|
||||
|
||||
set_flag(profile, "$fix ai path order bug:", AIPF2_FIX_AI_PATH_ORDER_BUG, AIP_FLAG2);
|
||||
set_flag(profile, "$fix ai path order bug:", AI::Profile_Flags::Fix_ai_path_order_bug);
|
||||
|
||||
set_flag(profile, "$strict turret-tagged-only targeting:", AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING, AIP_FLAG2);
|
||||
set_flag(profile, "$strict turret-tagged-only targeting:", AI::Profile_Flags::Strict_turred_tagged_only_targeting);
|
||||
|
||||
set_flag(profile, "$aspect bomb invulnerability fix:", AIPF2_ASPECT_INVULNERABILITY_FIX, AIP_FLAG2);
|
||||
set_flag(profile, "$aspect bomb invulnerability fix:", AI::Profile_Flags::Aspect_invulnerability_fix);
|
||||
|
||||
set_flag(profile, "$glide decay requires thrust:", AIPF2_GLIDE_DECAY_REQUIRES_THRUST, AIP_FLAG2);
|
||||
set_flag(profile, "$glide decay requires thrust:", AI::Profile_Flags::Glide_decay_requires_thrust);
|
||||
|
||||
set_flag(profile, "$ai can slow down when attacking big ships:", AIPF2_AI_CAN_SLOW_DOWN_ATTACKING_BIG_SHIPS, AIP_FLAG2);
|
||||
set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
profile->bay_arrive_speed_mult = 1.0f;
|
||||
profile->bay_depart_speed_mult = 1.0f;
|
||||
@@ -486,20 +475,14 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
mprintf(("Warning: \"$perform less checks for death screams\" flag is deprecated in favor of \"$perform fewer checks for death screams\"\n"));
|
||||
bool temp;
|
||||
stuff_boolean(&temp);
|
||||
if (temp)
|
||||
profile->flags2 |= AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
|
||||
else
|
||||
profile->flags2 &= ~AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
|
||||
profile->flags.set(AI::Profile_Flags::Perform_fewer_scream_checks, temp);
|
||||
}
|
||||
if (optional_string("$allow primary link delay:"))
|
||||
{
|
||||
mprintf(("Warning: \"$allow primary link delay\" flag is deprecated in favor of \"$allow primary link at mission start\"\n"));
|
||||
bool temp;
|
||||
stuff_boolean(&temp);
|
||||
if (temp)
|
||||
profile->flags2 &= ~AIPF2_ALLOW_PRIMARY_LINK_AT_START;
|
||||
else
|
||||
profile->flags2 |= AIPF2_ALLOW_PRIMARY_LINK_AT_START;
|
||||
profile->flags.set(AI::Profile_Flags::Allow_primary_link_at_start, !temp);
|
||||
}
|
||||
|
||||
|
||||
@@ -570,3 +553,72 @@ int ai_profile_lookup(char *name)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ai_profile_t::reset()
|
||||
{
|
||||
memset(profile_name, 0, sizeof(profile_name));
|
||||
|
||||
flags.reset();
|
||||
|
||||
ai_path_mode = 0;
|
||||
bay_arrive_speed_mult = 0;
|
||||
bay_depart_speed_mult = 0;
|
||||
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
|
||||
max_incoming_asteroids[i] = 0;
|
||||
max_allowed_player_homers[i] = 0;
|
||||
max_attackers[i] = 0;
|
||||
predict_position_delay[i] = 0;
|
||||
in_range_time[i] = 0;
|
||||
shield_manage_delay[i] = 0;
|
||||
|
||||
link_energy_levels_always[i] = 0;
|
||||
link_energy_levels_maybe[i] = 0;
|
||||
|
||||
link_ammo_levels_always[i] = 0;
|
||||
link_ammo_levels_maybe[i] = 0;
|
||||
primary_ammo_burst_mult[i] = 0;
|
||||
|
||||
cmeasure_life_scale[i] = 0;
|
||||
cmeasure_fire_chance[i] = 0;
|
||||
weapon_energy_scale[i] = 0;
|
||||
shield_energy_scale[i] = 0;
|
||||
afterburner_recharge_scale[i] = 0;
|
||||
player_damage_scale[i] = 0;
|
||||
|
||||
subsys_damage_scale[i] = 0;
|
||||
beam_friendly_damage_cap[i] = 0;
|
||||
turn_time_scale[i] = 0;
|
||||
glide_attack_percent[i] = 0;
|
||||
circle_strafe_percent[i] = 0;
|
||||
glide_strafe_percent[i] = 0;
|
||||
random_sidethrust_percent[i] = 0;
|
||||
stalemate_time_thresh[i] = 0;
|
||||
stalemate_dist_thresh[i] = 0;
|
||||
max_aim_update_delay[i] = 0;
|
||||
turret_max_aim_update_delay[i] = 0;
|
||||
|
||||
ship_fire_delay_scale_hostile[i] = 0;
|
||||
ship_fire_delay_scale_friendly[i] = 0;
|
||||
|
||||
ship_fire_secondary_delay_scale_hostile[i] = 0;
|
||||
ship_fire_secondary_delay_scale_friendly[i] = 0;
|
||||
|
||||
max_turret_ownage_target[i] = 0;
|
||||
max_turret_ownage_player[i] = 0;
|
||||
|
||||
kill_percentage_scale[i] = 0;
|
||||
assist_percentage_scale[i] = 0;
|
||||
|
||||
assist_award_percentage_scale[i] = 0;
|
||||
|
||||
repair_penalty[i] = 0;
|
||||
delay_bomb_arm_timer[i] = 0;
|
||||
chance_to_use_missiles_on_plr[i] = 0;
|
||||
player_autoaim_fov[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= MAX_DETAIL_LEVEL; ++i) {
|
||||
detail_distance_mult[i] = 0;
|
||||
}
|
||||
}
|
||||
+7
-62
@@ -12,63 +12,7 @@
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
|
||||
// flag int defines
|
||||
#define AIP_FLAG 1
|
||||
#define AIP_FLAG2 2
|
||||
|
||||
// flags
|
||||
#define AIPF_SMART_SHIELD_MANAGEMENT (1 << 0)
|
||||
#define AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS (1 << 1)
|
||||
#define AIPF_SMART_PRIMARY_WEAPON_SELECTION (1 << 2)
|
||||
#define AIPF_SMART_SECONDARY_WEAPON_SELECTION (1 << 3)
|
||||
#define AIPF_ALLOW_RAPID_SECONDARY_DUMBFIRE (1 << 4)
|
||||
#define AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS (1 << 5)
|
||||
#define AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY (1 << 6)
|
||||
#define AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY (1 << 7)
|
||||
#define AIPF_SHOCKWAVES_DAMAGE_SMALL_SHIP_SUBSYSTEMS (1 << 8)
|
||||
#define AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP (1 << 9)
|
||||
#define AIPF_NO_MIN_DOCK_SPEED_CAP (1 << 10)
|
||||
#define AIPF_DISABLE_LINKED_FIRE_PENALTY (1 << 11)
|
||||
#define AIPF_DISABLE_WEAPON_DAMAGE_SCALING (1 << 12)
|
||||
#define AIPF_USE_ADDITIVE_WEAPON_VELOCITY (1 << 13)
|
||||
#define AIPF_USE_NEWTONIAN_DAMPENING (1 << 14)
|
||||
#define AIPF_INCLUDE_BEAMS_IN_STAT_CALCS (1 << 15)
|
||||
#define AIPF_KILL_SCORING_SCALES_WITH_DAMAGE (1 << 16)
|
||||
#define AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE (1 << 17)
|
||||
#define AIPF_ALLOW_MULTI_EVENT_SCORING (1 << 18)
|
||||
#define AIPF_SMART_AFTERBURNER_MANAGEMENT (1 << 19)
|
||||
#define AIPF_FIX_LINKED_PRIMARY_BUG (1 << 20)
|
||||
#define AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE (1 << 21)
|
||||
#define AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS (1 << 22)
|
||||
#define AIPF_FIX_HEAT_SEEKER_STEALTH_BUG (1 << 23)
|
||||
#define AIPF_MULTI_ALLOW_EMPTY_PRIMARIES (1 << 24)
|
||||
#define AIPF_MULTI_ALLOW_EMPTY_SECONDARIES (1 << 25)
|
||||
#define AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY (1 << 26)
|
||||
#define AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS (1 << 27)
|
||||
#define AIPF_ALLOW_VERTICAL_DODGE (1 << 28) //Allows AI ships to evade weapons vertically as well as horizontally
|
||||
#define AIPF_FORCE_BEAM_TURRET_FOV (1 << 29)
|
||||
#define AIPF_FIX_AI_CLASS_BUG (1 << 30)
|
||||
|
||||
// flags2
|
||||
#define AIPF2_TURRETS_IGNORE_TARGET_RADIUS (1 << 0)
|
||||
#define AIPF2_NO_SPECIAL_PLAYER_AVOID (1 << 1)
|
||||
#define AIPF2_PERFORM_FEWER_SCREAM_CHECKS (1 << 2)
|
||||
#define AIPF2_ALL_SHIPS_MANAGE_SHIELDS (1 << 3)
|
||||
#define AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS (1 << 4)
|
||||
#define AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV (1 << 5)
|
||||
#define AIPF2_AI_AIMS_FROM_SHIP_CENTER (1 << 6)
|
||||
#define AIPF2_ALLOW_PRIMARY_LINK_AT_START (1 << 7)
|
||||
#define AIPF2_BEAMS_DAMAGE_WEAPONS (1 << 8)
|
||||
#define AIPF2_PLAYER_WEAPON_SCALE_FIX (1 << 9)
|
||||
#define AIPF2_NO_WARP_CAMERA (1 << 10)
|
||||
#define AIPF2_ASPECT_LOCK_COUNTERMEASURE (1 << 11)
|
||||
#define AIPF2_AI_GUARDS_SPECIFIC_SHIP_IN_WING (1 << 12)
|
||||
#define AIPF2_FIX_AI_PATH_ORDER_BUG (1 << 13)
|
||||
#define AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING (1 << 14)
|
||||
#define AIPF2_ASPECT_INVULNERABILITY_FIX (1 << 15)
|
||||
#define AIPF2_GLIDE_DECAY_REQUIRES_THRUST (1 << 16)
|
||||
#define AIPF2_AI_CAN_SLOW_DOWN_ATTACKING_BIG_SHIPS (1 << 17)
|
||||
#include "ai/ai_flags.h"
|
||||
|
||||
// AI Path types
|
||||
#define AI_PATH_MODE_NORMAL 0
|
||||
@@ -76,12 +20,11 @@
|
||||
|
||||
#define MAX_AI_PROFILES 5
|
||||
|
||||
typedef struct ai_profile_t {
|
||||
|
||||
class ai_profile_t {
|
||||
public:
|
||||
char profile_name[NAME_LENGTH];
|
||||
|
||||
int flags;
|
||||
int flags2;
|
||||
flagset<AI::Profile_Flags> flags;
|
||||
|
||||
// difficulty-related values
|
||||
int max_incoming_asteroids[NUM_SKILL_LEVELS]; // max number of asteroids thrown at friendlies
|
||||
@@ -159,13 +102,15 @@ typedef struct ai_profile_t {
|
||||
float bay_arrive_speed_mult;
|
||||
float bay_depart_speed_mult;
|
||||
|
||||
} ai_profile_t;
|
||||
void reset();
|
||||
};
|
||||
|
||||
|
||||
extern int Num_ai_profiles;
|
||||
extern int Default_ai_profile;
|
||||
extern ai_profile_t Ai_profiles[MAX_AI_PROFILES];
|
||||
|
||||
#define AI_PROFILES_INDEX(ai_p) ((int)((ai_p) - Ai_profiles))
|
||||
|
||||
void ai_profiles_init();
|
||||
|
||||
|
||||
+33
-33
@@ -350,8 +350,8 @@ void ai_big_avoid_ship()
|
||||
// reset path following information
|
||||
void ai_big_subsys_path_cleanup(ai_info *aip)
|
||||
{
|
||||
if ( aip->ai_flags & AIF_ON_SUBSYS_PATH ) {
|
||||
aip->ai_flags &= ~AIF_ON_SUBSYS_PATH;
|
||||
if ( aip->ai_flags[AI::AI_Flags::On_subsys_path] ) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::On_subsys_path);
|
||||
aip->path_goal_dist = -1;
|
||||
aip->path_start = -1;
|
||||
aip->path_cur = -1;
|
||||
@@ -438,7 +438,7 @@ int ai_big_maybe_follow_subsys_path(int do_dot_check)
|
||||
Assert(aip->target_objnum >= 0);
|
||||
ai_find_path(Pl_objp, aip->target_objnum, subsys_path_num, 0, 1);
|
||||
if ( aip->path_start >= 0 ) {
|
||||
aip->ai_flags |= AIF_ON_SUBSYS_PATH;
|
||||
aip->ai_flags.set(AI::AI_Flags::On_subsys_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -593,7 +593,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
} // end if ( Pl_objp->phys_info.speed < 3.0f )
|
||||
|
||||
//Maybe enter glide strafe (check every 8 seconds, on a different schedule for each ship)
|
||||
if ((sip->can_glide == true) && !(aip->ai_flags & AIF_KAMIKAZE) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
|
||||
if ((sip->can_glide == true) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && static_randf((Missiontime + static_rand(aip->shipnum)) >> 19) < aip->ai_glide_strafe_percent) {
|
||||
aip->previous_mode = aip->mode;
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
@@ -604,7 +604,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
|
||||
// see if Pl_objp needs to reposition to get a good shot at subsystem which is being attacked
|
||||
if ( ai_big_maybe_follow_subsys_path() ) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
return;
|
||||
@@ -641,19 +641,19 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
ship *shipp = &Ships[Pl_objp->instance];
|
||||
if ((aip->ai_flags & AIF_FREE_AFTERBURNER_USE) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
}
|
||||
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
|
||||
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
} else {
|
||||
// AL 12-31-97: Move at least as quickly as your target is moving...
|
||||
accelerate_ship(aip, MAX(1.0f - dot_to_enemy, Objects[aip->target_objnum].phys_info.fspeed/sip->max_speed));
|
||||
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
}
|
||||
@@ -676,19 +676,19 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
if (dist_to_enemy < ATTACK_STOP_DISTANCE) {
|
||||
// accelerate_ship(aip, accel * 0.5f);
|
||||
accelerate_ship(aip, -1.0f);
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
} else {
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
ship *shipp = &Ships[Pl_objp->instance];
|
||||
if ((aip->ai_flags & AIF_FREE_AFTERBURNER_USE) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
}
|
||||
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
|
||||
} else if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
}
|
||||
@@ -754,10 +754,10 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
|
||||
if (current_bank > -1) {
|
||||
weapon_info *swip = &Weapon_info[tswp->secondary_bank_weapons[current_bank]];
|
||||
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags & WIF_PUNCTURE )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
if(!(En_objp->flags[Object::Object_Flags::Protected]) || ((aip->goals[0].ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)) && swip->wi_flags[Weapon::Info_Flags::Puncture] )) { //override lockdown on protected ships when using anti subsystem weapons - Valathil
|
||||
// If ship is protected and very low on hits, don't fire missiles.
|
||||
if (!(En_objp->flags[Object::Object_Flags::Protected]) || (En_objp->hull_strength > 10*swip->damage)) {
|
||||
if (aip->ai_flags & AIF_UNLOAD_SECONDARIES) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Unload_secondaries]) {
|
||||
if (timestamp_until(swp->next_secondary_fire_stamp[current_bank]) > swip->fire_wait*1000.0f) {
|
||||
swp->next_secondary_fire_stamp[current_bank] = timestamp((int) (swip->fire_wait*1000.0f));
|
||||
}
|
||||
@@ -765,7 +765,7 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
|
||||
|
||||
if (timestamp_elapsed(swp->next_secondary_fire_stamp[current_bank])) {
|
||||
float firing_range;
|
||||
if (swip->wi_flags2 & WIF2_LOCAL_SSM)
|
||||
if (swip->wi_flags[Weapon::Info_Flags::Local_ssm])
|
||||
firing_range=swip->lssm_lock_range;
|
||||
else
|
||||
firing_range = MIN((swip->max_speed * swip->lifetime), swip->weapon_range);
|
||||
@@ -786,13 +786,13 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
|
||||
|
||||
int current_bank_adjusted = MAX_SHIP_PRIMARY_BANKS + current_bank;
|
||||
|
||||
if ((aip->ai_flags & AIF_UNLOAD_SECONDARIES) || (swip->burst_flags & WBF_FAST_FIRING)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Unload_secondaries]) || (swip->burst_flags[Weapon::Burst_Flags::Fast_firing])) {
|
||||
if (swip->burst_shots > swp->burst_counter[current_bank_adjusted]) {
|
||||
t = swip->burst_delay;
|
||||
swp->burst_counter[current_bank_adjusted]++;
|
||||
} else {
|
||||
t = swip->fire_wait;
|
||||
if ((swip->burst_shots > 0) && (swip->burst_flags & WBF_RANDOM_LENGTH)) {
|
||||
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
|
||||
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
|
||||
} else {
|
||||
swp->burst_counter[current_bank_adjusted] = 0;
|
||||
@@ -804,7 +804,7 @@ void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *f
|
||||
swp->burst_counter[current_bank_adjusted]++;
|
||||
} else {
|
||||
t = set_secondary_fire_delay(aip, temp_shipp, swip, false);
|
||||
if ((swip->burst_shots > 0) && (swip->burst_flags & WBF_RANDOM_LENGTH)) {
|
||||
if ((swip->burst_shots > 0) && (swip->burst_flags[Weapon::Burst_Flags::Random_length])) {
|
||||
swp->burst_counter[current_bank_adjusted] = myrand() % swip->burst_shots;
|
||||
} else {
|
||||
swp->burst_counter[current_bank_adjusted] = 0;
|
||||
@@ -881,7 +881,7 @@ void ai_big_chase()
|
||||
dist_to_enemy = vm_vec_normalized_dir(&vec_to_enemy, &enemy_pos, &player_pos); // - En_objp->radius;
|
||||
dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
|
||||
|
||||
if (aip->ai_flags & AIF_TARGET_COLLISION) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
if ( ai_big_strafe_maybe_retreat(dist_to_enemy, &enemy_pos) ) {
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
@@ -894,7 +894,7 @@ void ai_big_chase()
|
||||
}
|
||||
}
|
||||
|
||||
if (aip->ai_flags & AIF_KAMIKAZE) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
//nprintf(("AI", "Kamikaze: %7.3f %7.3f\n", dot_to_enemy, dist_to_enemy));
|
||||
accelerate_ship(aip, 1.0f);
|
||||
if ((dist_to_enemy < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
@@ -904,7 +904,7 @@ void ai_big_chase()
|
||||
}
|
||||
|
||||
// If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
|
||||
if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags & AIF_SEEK_LOCK)) {
|
||||
if ((dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags[AI::AI_Flags::Seek_lock])) {
|
||||
update_aspect_lock_information(aip, &vec_to_enemy, dist_to_enemy - En_objp->radius, En_objp->radius);
|
||||
} else if (aip->targeted_subsys != NULL) {
|
||||
Assert(aip->targeted_subsys != NULL);
|
||||
@@ -931,7 +931,7 @@ void ai_big_chase()
|
||||
case SM_SUPER_ATTACK:
|
||||
if (vm_vec_dist_quick(&Pl_objp->pos, &predicted_enemy_pos) > 100.0f + En_objp->radius * 2.0f) {
|
||||
if (maybe_avoid_big_ship(Pl_objp, En_objp, aip, &predicted_enemy_pos, 10.0f)) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
return;
|
||||
@@ -953,7 +953,7 @@ void ai_big_chase()
|
||||
//
|
||||
|
||||
if (((aip->submode != SM_ATTACK) && (aip->submode != SM_SUPER_ATTACK) && (aip->submode != SM_ATTACK_FOREVER) && (aip->submode != SM_EVADE_WEAPON)) || (aip->mode == AIM_STRAFE)){
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags & AIF_KAMIKAZE)) {
|
||||
if ((Pl_objp->phys_info.flags & PF_AFTERBURNER_ON) && !(aip->ai_flags[AI::AI_Flags::Kamikaze])) {
|
||||
afterburners_stop(Pl_objp);
|
||||
}
|
||||
}
|
||||
@@ -1198,7 +1198,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
|
||||
// If just acquired target, or target is not in reasonable cone, don't refine believed enemy position.
|
||||
vm_vec_normalized_dir(&vec_to_enemy, enemy_pos, &player_pos);
|
||||
*dot_to_enemy=vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
|
||||
if ((*dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags & AIF_SEEK_LOCK)) {
|
||||
if ((*dot_to_enemy < 0.25f) || (aip->target_time < 1.0f) || (aip->ai_flags[AI::AI_Flags::Seek_lock])) {
|
||||
predicted_enemy_pos=*enemy_pos;
|
||||
} else {
|
||||
vec3d gun_pos, pnt;
|
||||
@@ -1206,7 +1206,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
|
||||
float weapon_speed;
|
||||
|
||||
// Compute position of gun in absolute space and use that as fire position.
|
||||
if (po->n_guns > 0 && !(The_mission.ai_profile->flags2 & AIPF2_AI_AIMS_FROM_SHIP_CENTER)) {
|
||||
if (po->n_guns > 0 && !(The_mission.ai_profile->flags[AI::Profile_Flags::Ai_aims_from_ship_center])) {
|
||||
pnt = po->gun_banks[0].pnt[0];
|
||||
vm_vec_unrotate(&gun_pos, &pnt, &Pl_objp->orient);
|
||||
vm_vec_add2(&gun_pos, &Pl_objp->pos);
|
||||
@@ -1254,10 +1254,10 @@ int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
|
||||
|
||||
// Inside 2 sec retreat, setting goal point to box point + 300m
|
||||
// If collision, use std collision resolution.
|
||||
if ( !(aip->ai_flags & AIF_KAMIKAZE) && ((aip->ai_flags & AIF_TARGET_COLLISION) || (time_to_target < STRAFE_RETREAT_COLLIDE_TIME) || (dist_normal_to_target < STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty)) ) {
|
||||
if (aip->ai_flags & AIF_TARGET_COLLISION) {
|
||||
if ( !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && ((aip->ai_flags[AI::AI_Flags::Target_collision]) || (time_to_target < STRAFE_RETREAT_COLLIDE_TIME) || (dist_normal_to_target < STRAFE_RETREAT_COLLIDE_DIST + speed_to_dist_penalty)) ) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
// use standard collision resolution
|
||||
aip->ai_flags &= ~AIF_TARGET_COLLISION;
|
||||
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
|
||||
} else {
|
||||
// too close for comfort so fly to box point + 300
|
||||
@@ -1301,7 +1301,7 @@ void ai_big_strafe_attack()
|
||||
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
|
||||
return;
|
||||
|
||||
if (aip->ai_flags & AIF_KAMIKAZE) {
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
if (target_dist < 1200.0f) {
|
||||
ai_turn_towards_vector(&target_pos, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
@@ -1313,7 +1313,7 @@ void ai_big_strafe_attack()
|
||||
}
|
||||
}
|
||||
|
||||
if (!(aip->ai_flags & AIF_SEEK_LOCK) || (aip->aspect_locked_time < 2.0f)) {
|
||||
if (!(aip->ai_flags[AI::AI_Flags::Seek_lock]) || (aip->aspect_locked_time < 2.0f)) {
|
||||
t = ai_endangered_by_weapon(aip);
|
||||
if ( t > 0.0f && t < 1.5f ) {
|
||||
// set up goal_point for avoid path to turn towards
|
||||
@@ -1351,7 +1351,7 @@ void ai_big_strafe_attack()
|
||||
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
|
||||
|
||||
fix last_hit = Missiontime - aip->last_hit_time;
|
||||
if ( aip->ai_profile_flags2 & AIPF2_AI_CAN_SLOW_DOWN_ATTACKING_BIG_SHIPS ) {
|
||||
if ( aip->ai_profile_flags[AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships] ) {
|
||||
// Slow down if we've not been hit for a while
|
||||
if ( target_dist > 1200 || last_hit < F1_0*6) {
|
||||
accel = 1.0f;
|
||||
@@ -1622,7 +1622,7 @@ void ai_big_strafe_position()
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
|
||||
//Maybe use AIS_STRAFE_GLIDE_ATTACK
|
||||
if ((sip->can_glide == true) && !(aip->ai_flags & AIF_KAMIKAZE) && (frand() < aip->ai_glide_strafe_percent)) {
|
||||
if ((sip->can_glide == true) && !(aip->ai_flags[AI::AI_Flags::Kamikaze]) && (frand() < aip->ai_glide_strafe_percent)) {
|
||||
aip->submode = AIS_STRAFE_GLIDE_ATTACK;
|
||||
aip->submode_parm1 = 0;
|
||||
} else {
|
||||
@@ -1809,8 +1809,8 @@ void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
|
||||
// the ai will not always go after different ships firing beams at them.
|
||||
// Approx 1/4 chance we'll go after the other ship's beam.
|
||||
|
||||
bool attack_turret_on_different_ship = (aip->ai_profile_flags & AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS)
|
||||
&& (Weapon_info[Weapons[weapon_objp->instance].weapon_info_index].wi_flags & WIF_BEAM) && (frand()*100 < 25.0f);
|
||||
bool attack_turret_on_different_ship = (aip->ai_profile_flags[AI::Profile_Flags::Big_ships_can_attack_beam_turrets_on_untargeted_ships])
|
||||
&& (Weapon_info[Weapons[weapon_objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Beam]) && (frand()*100 < 25.0f);
|
||||
|
||||
// unless we're making an exception, we should only attack a turret if it sits on the current target
|
||||
if ( !attack_turret_on_different_ship )
|
||||
|
||||
+465
-514
File diff suppressed because it is too large.
Load diff
+131
-82
@@ -59,6 +59,7 @@ int Ai_goal_signature;
|
||||
int Num_ai_dock_names = 0;
|
||||
char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
|
||||
|
||||
// Used in objecttypes.tbl to define custom ship types
|
||||
ai_goal_list Ai_goal_names[] =
|
||||
{
|
||||
{ "Attack ship", AI_GOAL_CHASE, 0 },
|
||||
@@ -85,6 +86,7 @@ ai_goal_list Ai_goal_names[] =
|
||||
{ "Play dead", AI_GOAL_PLAY_DEAD, 0 },
|
||||
{ "Attack weapon", AI_GOAL_CHASE_WEAPON, 0 },
|
||||
{ "Fly to ship", AI_GOAL_FLY_TO_SHIP, 0 },
|
||||
{ "Attack ship class", AI_GOAL_CHASE_SHIP_CLASS, 0 },
|
||||
};
|
||||
|
||||
int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
|
||||
@@ -96,34 +98,34 @@ int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
|
||||
const char *Ai_goal_text(int goal)
|
||||
{
|
||||
switch(goal) {
|
||||
case 1:
|
||||
case AI_GOAL_CHASE:
|
||||
case AI_GOAL_CHASE_WING:
|
||||
case AI_GOAL_CHASE_SHIP_CLASS:
|
||||
return XSTR( "attack ", 474);
|
||||
case 2:
|
||||
case AI_GOAL_DOCK:
|
||||
return XSTR( "dock ", 475);
|
||||
case 3:
|
||||
case AI_GOAL_WAYPOINTS:
|
||||
case AI_GOAL_WAYPOINTS_ONCE:
|
||||
return XSTR( "waypoints", 476);
|
||||
case 4:
|
||||
return XSTR( "waypoints", 476);
|
||||
case 6:
|
||||
case AI_GOAL_DESTROY_SUBSYSTEM:
|
||||
return XSTR( "destroy ", 477);
|
||||
case 7:
|
||||
case AI_GOAL_FORM_ON_WING:
|
||||
return XSTR( "form on ", 478);
|
||||
case 8:
|
||||
case AI_GOAL_UNDOCK:
|
||||
return XSTR( "undock ", 479);
|
||||
case 9:
|
||||
return XSTR( "attack ", 474);
|
||||
case 10:
|
||||
case AI_GOAL_GUARD:
|
||||
case AI_GOAL_GUARD_WING:
|
||||
return XSTR( "guard ", 480);
|
||||
case 11:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
return XSTR( "disable ", 481);
|
||||
case 12:
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
return XSTR( "disarm ", 482);
|
||||
case 15:
|
||||
return XSTR( "guard ", 480);
|
||||
case 16:
|
||||
case AI_GOAL_EVADE_SHIP:
|
||||
return XSTR( "evade ", 483);
|
||||
case 19:
|
||||
case AI_GOAL_REARM_REPAIR:
|
||||
return XSTR( "rearm ", 484);
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
return XSTR( "rendezvous with ", -1);
|
||||
}
|
||||
|
||||
// Avoid compiler warning
|
||||
@@ -238,7 +240,7 @@ void ai_remove_ship_goal( ai_info *aip, int index )
|
||||
aip->goals[index].ai_mode = AI_GOAL_NONE;
|
||||
aip->goals[index].signature = -1;
|
||||
aip->goals[index].priority = -1;
|
||||
aip->goals[index].flags = 0; // must reset the flags since not doing so will screw up goal sorting.
|
||||
aip->goals[index].flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
|
||||
|
||||
if ( index == aip->active_goal )
|
||||
aip->active_goal = AI_GOAL_NONE;
|
||||
@@ -287,7 +289,7 @@ void ai_clear_wing_goals( int wingnum )
|
||||
wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
|
||||
wingp->ai_goals[i].signature = -1;
|
||||
wingp->ai_goals[i].priority = -1;
|
||||
wingp->ai_goals[i].flags = 0;
|
||||
wingp->ai_goals[i].flags.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -347,7 +349,7 @@ void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp )
|
||||
wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
|
||||
wingp->ai_goals[i].signature = -1;
|
||||
wingp->ai_goals[i].priority = -1;
|
||||
wingp->ai_goals[i].flags = 0;
|
||||
wingp->ai_goals[i].flags.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -408,31 +410,41 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
if ( purge_goal->target_name == NULL )
|
||||
continue;
|
||||
|
||||
// determine if the purge goal is acting either on the ship or the ship's wing.
|
||||
purge_wing = wing_name_lookup( purge_goal->target_name, 1 );
|
||||
|
||||
// if the target of the purge goal is a ship (purge_wing will be -1), then if the names
|
||||
// don't match, we can continue; if the wing is valid, don't process if the wing numbers
|
||||
// are different.
|
||||
if ( purge_wing == -1 ) {
|
||||
if ( stricmp(purge_goal->target_name, name ) )
|
||||
// goals operating on ship classes are handled slightly differently
|
||||
if ( purge_ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
|
||||
// if the target of the purge goal is the same class of ship we are concerned about, then we have a match;
|
||||
// if it is not, then we can continue (see standard ship check below)
|
||||
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) )
|
||||
continue;
|
||||
} else if ( purge_wing != wingnum )
|
||||
continue;
|
||||
}
|
||||
// standard goals operating on either wings or ships
|
||||
else {
|
||||
// determine if the purge goal is acting either on the ship or the ship's wing.
|
||||
purge_wing = wing_name_lookup( purge_goal->target_name, 1 );
|
||||
|
||||
// if the target of the purge goal is a ship (purge_wing will be -1), then if the names
|
||||
// don't match, we can continue; if the wing is valid, don't process if the wing numbers
|
||||
// are different.
|
||||
if ( purge_wing == -1 ) {
|
||||
if ( stricmp(purge_goal->target_name, name ) )
|
||||
continue;
|
||||
} else if ( purge_wing != wingnum )
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
// ignore goals should get rid of any kind of attack goal
|
||||
case AI_GOAL_IGNORE:
|
||||
case AI_GOAL_IGNORE_NEW:
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
purge_goal->flags |= AIGF_PURGE;
|
||||
if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS | AI_GOAL_DESTROY_SUBSYSTEM) )
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
break;
|
||||
|
||||
// disarm/disable goals should remove attacks from certain ships types
|
||||
case AI_GOAL_DISARM_SHIP:
|
||||
case AI_GOAL_DISABLE_SHIP:
|
||||
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING) ) {
|
||||
if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_CHASE_SHIP_CLASS) ) {
|
||||
int ai_ship_type;
|
||||
|
||||
// for wings we grab the ship type of the wing leader
|
||||
@@ -452,7 +464,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// being disarmed/disabled
|
||||
for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
|
||||
if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
|
||||
purge_goal->flags |= AIGF_PURGE;
|
||||
purge_goal->flags.set(AI::Goal_Flags::Purge);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -601,7 +613,8 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
|
||||
|
||||
aigp->docker.index = docker_index;
|
||||
aigp->dockee.index = dockee_index;
|
||||
aigp->flags |= AIGF_DOCK_INDEXES_VALID;
|
||||
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
|
||||
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
|
||||
}
|
||||
|
||||
// these functions deal with adding goals sent from the player. They are slightly different
|
||||
@@ -739,7 +752,8 @@ void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipn
|
||||
if ( mode == AI_GOAL_DOCK ) {
|
||||
aigp->docker.name = Ships[aip->shipnum].ship_name;
|
||||
aigp->dockee.name = shipname;
|
||||
aigp->flags &= ~AIGF_DOCK_INDEXES_VALID;
|
||||
aigp->flags.remove(AI::Goal_Flags::Dockee_index_valid);
|
||||
aigp->flags.remove(AI::Goal_Flags::Docker_index_valid);
|
||||
}
|
||||
ai_add_goal_sub_scripting(AIG_TYPE_PLAYER_SHIP, mode, submode, priority, shipname, aigp);
|
||||
|
||||
@@ -818,7 +832,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->target_name = NULL;
|
||||
aigp->time = Missiontime;
|
||||
aigp->type = type;
|
||||
aigp->flags = 0;
|
||||
aigp->flags.reset();
|
||||
|
||||
op = get_operator_const( text );
|
||||
|
||||
@@ -851,7 +865,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
// store the name of the subsystem in the docker.name field for now -- this field must get
|
||||
// fixed up when the goal is valid since we need to locate the subsystem on the ship's model
|
||||
aigp->docker.name = ai_get_goal_target_name(CTEXT(CDR(CDR(node))), &dummy);
|
||||
aigp->flags |= AIGF_SUBSYS_NEEDS_FIXUP;
|
||||
aigp->flags.set(AI::Goal_Flags::Subsys_needs_fixup);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(CDR(node)))) );
|
||||
break;
|
||||
|
||||
@@ -905,7 +919,8 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->target_name = ai_get_goal_target_name( CTEXT(CDR(node)), &aigp->target_name_index );
|
||||
aigp->docker.name = ai_add_dock_name(CTEXT(CDR(CDR(node))));
|
||||
aigp->dockee.name = ai_add_dock_name(CTEXT(CDR(CDR(CDR(node)))));
|
||||
aigp->flags &= ~AIGF_DOCK_INDEXES_VALID;
|
||||
aigp->flags.remove(AI::Goal_Flags::Dockee_index_valid);
|
||||
aigp->flags.remove(AI::Goal_Flags::Docker_index_valid);
|
||||
aigp->priority = atoi( CTEXT(CDR(CDR(CDR(CDR(node))))) );
|
||||
|
||||
aigp->ai_mode = AI_GOAL_DOCK;
|
||||
@@ -934,9 +949,10 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
break;
|
||||
|
||||
case OP_AI_CHASE:
|
||||
case OP_AI_CHASE_WING:
|
||||
case OP_AI_CHASE_SHIP_CLASS:
|
||||
case OP_AI_GUARD:
|
||||
case OP_AI_GUARD_WING:
|
||||
case OP_AI_CHASE_WING:
|
||||
case OP_AI_EVADE_SHIP:
|
||||
case OP_AI_STAY_NEAR_SHIP:
|
||||
case OP_AI_IGNORE:
|
||||
@@ -965,6 +981,8 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->ai_mode = AI_GOAL_GUARD_WING;
|
||||
} else if ( op == OP_AI_CHASE_WING ) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE_WING;
|
||||
} else if (op == OP_AI_CHASE_SHIP_CLASS) {
|
||||
aigp->ai_mode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
} else if ( op == OP_AI_STAY_NEAR_SHIP ) {
|
||||
aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
|
||||
} else if ( op == OP_AI_IGNORE ) {
|
||||
@@ -986,13 +1004,13 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
}
|
||||
|
||||
// Goober5000 - we now have an extra optional chase argument to allow chasing our own team
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
|
||||
if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_CHASE_SHIP_CLASS || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
|
||||
if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
|
||||
aigp->flags |= AIGF_TARGET_OWN_TEAM;
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
}
|
||||
if ( op == OP_AI_DESTROY_SUBSYS ) {
|
||||
if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
|
||||
aigp->flags |= AIGF_TARGET_OWN_TEAM;
|
||||
aigp->flags.set(AI::Goal_Flags::Target_own_team);
|
||||
}
|
||||
|
||||
// Goober5000 - since none of the goals act on the actor,
|
||||
@@ -1004,7 +1022,7 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags = 0;
|
||||
aigp->flags.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1032,7 +1050,7 @@ int ai_find_goal_index( ai_goal* aigp, int mode, int submode, int priority )
|
||||
|
||||
/* Remove a goal from the given goals structure
|
||||
* Returns the index of the goal that it clears out.
|
||||
* This is importnat so that if active_goal == index you can set AI_GOAL_NONE
|
||||
* This is important so that if active_goal == index you can set AI_GOAL_NONE
|
||||
*/
|
||||
int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
{
|
||||
@@ -1134,6 +1152,10 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_CHASE_WING;
|
||||
break;
|
||||
case OP_AI_CHASE_SHIP_CLASS:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_CHASE_SHIP_CLASS;
|
||||
break;
|
||||
case OP_AI_EVADE_SHIP:
|
||||
priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
|
||||
goalmode = AI_GOAL_EVADE_SHIP;
|
||||
@@ -1166,7 +1188,7 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
aigp[goalindex].ai_mode = AI_GOAL_NONE;
|
||||
aigp[goalindex].signature = -1;
|
||||
aigp[goalindex].priority = -1;
|
||||
aigp[goalindex].flags = 0; // must reset the flags since not doing so will screw up goal sorting.
|
||||
aigp[goalindex].flags.reset(); // must reset the flags since not doing so will screw up goal sorting.
|
||||
|
||||
return goalindex;
|
||||
}
|
||||
@@ -1264,7 +1286,8 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int doc
|
||||
|
||||
aigp->time = Missiontime;
|
||||
aigp->type = AIG_TYPE_DYNAMIC;
|
||||
aigp->flags = AIGF_GOAL_OVERRIDE;
|
||||
aigp->flags.reset();
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
|
||||
switch ( goal_type ) {
|
||||
|
||||
@@ -1302,7 +1325,7 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int doc
|
||||
aigp->ai_submode = 0;
|
||||
aigp->target_name = name;
|
||||
aigp->priority = PLAYER_PRIORITY_MIN-1; // make the priority always less than what the player's is
|
||||
aigp->flags &= ~AIGF_GOAL_OVERRIDE; // don't override this goal. rearm repair requests should happen in order
|
||||
aigp->flags.remove(AI::Goal_Flags::Goal_override); // don't override this goal. rearm repair requests should happen in order
|
||||
ai_goal_fixup_dockpoints( aip, aigp );
|
||||
break;
|
||||
|
||||
@@ -1413,7 +1436,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
if (sindex < 0)
|
||||
return AI_GOAL_NOT_ACHIEVABLE;
|
||||
|
||||
aigp->flags |= AIGF_GOAL_OVERRIDE;
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_override);
|
||||
return AI_GOAL_ACHIEVABLE;
|
||||
}
|
||||
|
||||
@@ -1431,6 +1454,18 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
return AI_GOAL_ACHIEVABLE;
|
||||
}
|
||||
|
||||
// chasing all ships of a certain ship class is achievable if there are ships of that class present;
|
||||
// if not, the status is not known because more ships of that class could arrive in the future
|
||||
// (c.f. AI_GOAL_CHASE_WING subsequent to the next switch statement)
|
||||
if ( aigp->ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
|
||||
for (objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
|
||||
if ((objp->type == OBJ_SHIP) && !strcmp(aigp->target_name, Ship_info[Ships[objp->instance].ship_info_index].name)) {
|
||||
return AI_GOAL_ACHIEVABLE;
|
||||
}
|
||||
}
|
||||
return AI_GOAL_NOT_KNOWN;
|
||||
}
|
||||
|
||||
|
||||
return_val = AI_GOAL_SATISFIED;
|
||||
|
||||
@@ -1456,7 +1491,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
// can't determine the status of this goal if ship not valid
|
||||
// or we haven't found a valid subsystem index yet
|
||||
if ( (sindex == -1) || (aigp->flags & AIGF_SUBSYS_NEEDS_FIXUP) ) {
|
||||
if ( (sindex == -1) || (aigp->flags[AI::Goal_Flags::Subsys_needs_fixup]) ) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1573,7 +1608,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
wing *wingp = &Wings[sindex];
|
||||
|
||||
if ( wingp->flags & WF_WING_GONE )
|
||||
if ( wingp->flags[Ship::Wing_Flags::Gone] )
|
||||
return AI_GOAL_NOT_ACHIEVABLE;
|
||||
else if ( wingp->total_arrived_count == 0 )
|
||||
return AI_GOAL_NOT_KNOWN;
|
||||
@@ -1605,7 +1640,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
else
|
||||
{
|
||||
Int3(); // get ALLENDER
|
||||
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
|
||||
status = SHIP_STATUS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -1620,15 +1655,15 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
|
||||
// if the goal is an ignore/disable/disarm goal, then
|
||||
// Goober5000 - see note at PURGE_GOALS_ALL_SHIPS... this is bizarre
|
||||
if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags & AIGF_GOALS_PURGED))
|
||||
if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags[AI::Goal_Flags::Goals_purged]))
|
||||
{
|
||||
if (aigp->ai_mode & PURGE_GOALS_ALL_SHIPS) {
|
||||
ai_goal_purge_all_invalid_goals(aigp);
|
||||
aigp->flags |= AIGF_GOALS_PURGED;
|
||||
aigp->flags.set(AI::Goal_Flags::Goals_purged);
|
||||
}
|
||||
else if (aigp->ai_mode & PURGE_GOALS_ONE_SHIP) {
|
||||
ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
|
||||
aigp->flags |= AIGF_GOALS_PURGED;
|
||||
aigp->flags.set(AI::Goal_Flags::Goals_purged);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1636,21 +1671,21 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// only enter this calculation if the ship we are docking with has arrived. If the ship is gone, then
|
||||
// this goal will get removed.
|
||||
if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
|
||||
if (!(aigp->flags & AIGF_DOCKER_INDEX_VALID)) {
|
||||
if (!(aigp->flags[AI::Goal_Flags::Docker_index_valid])) {
|
||||
modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
|
||||
Assert( modelnum >= 0 );
|
||||
index = model_find_dock_name_index(modelnum, aigp->docker.name);
|
||||
aigp->docker.index = index;
|
||||
aigp->flags |= AIGF_DOCKER_INDEX_VALID;
|
||||
aigp->flags.set(AI::Goal_Flags::Docker_index_valid);
|
||||
}
|
||||
|
||||
if (!(aigp->flags & AIGF_DOCKEE_INDEX_VALID)) {
|
||||
if (!(aigp->flags[AI::Goal_Flags::Dockee_index_valid])) {
|
||||
sindex = ship_name_lookup(aigp->target_name);
|
||||
if ( sindex != -1 ) {
|
||||
modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
|
||||
index = model_find_dock_name_index(modelnum, aigp->dockee.name);
|
||||
aigp->dockee.index = index;
|
||||
aigp->flags |= AIGF_DOCKEE_INDEX_VALID;
|
||||
aigp->flags.set(AI::Goal_Flags::Dockee_index_valid);
|
||||
} else
|
||||
aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
|
||||
}
|
||||
@@ -1700,7 +1735,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
else if (obstacle_objp != goal_objp)
|
||||
{
|
||||
// if this goal isn't on hold yet, then issue the undock goal
|
||||
if ( !(aigp->flags & AIGF_GOAL_ON_HOLD) )
|
||||
if ( !(aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
|
||||
ai_add_goal_ship_internal( aip, AI_GOAL_UNDOCK, Ships[obstacle_objp->instance].ship_name, -1, -1, 0 );
|
||||
|
||||
// return NOT_KNOWN which will place the goal on hold until the undocking is complete.
|
||||
@@ -1725,12 +1760,12 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// if the ship has arrived, and the goal is destroy subsystem, then check to see that we
|
||||
// have fixed up the subsystem name (of the subsystem to destroy) into an index into
|
||||
// the ship's subsystem list
|
||||
if ( aigp->flags & AIGF_SUBSYS_NEEDS_FIXUP ) {
|
||||
if ( aigp->flags[AI::Goal_Flags::Subsys_needs_fixup] ) {
|
||||
sindex = ship_name_lookup( aigp->target_name );
|
||||
|
||||
if ( sindex != -1 ) {
|
||||
aigp->ai_submode = ship_get_subsys_index( &Ships[sindex], aigp->docker.name );
|
||||
aigp->flags &= ~AIGF_SUBSYS_NEEDS_FIXUP;
|
||||
aigp->flags.remove(AI::Goal_Flags::Subsys_needs_fixup);
|
||||
} else {
|
||||
Int3();
|
||||
return AI_GOAL_NOT_ACHIEVABLE; // force this goal to be invalid
|
||||
@@ -1802,7 +1837,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
}
|
||||
|
||||
// if desitnation currently being repaired, then goal is stil active
|
||||
if ( Ai_info[Ships[sindex].ai_index].ai_flags & AIF_BEING_REPAIRED )
|
||||
if ( Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Being_repaired] )
|
||||
return AI_GOAL_ACHIEVABLE;
|
||||
|
||||
// if the destination ship is dying or departing (but not completed yet), the mark goal as
|
||||
@@ -1811,11 +1846,11 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
return AI_GOAL_NOT_ACHIEVABLE;
|
||||
|
||||
// if the destination object is no longer awaiting repair, then remove the item
|
||||
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags & AIF_AWAITING_REPAIR) )
|
||||
if ( !(Ai_info[Ships[sindex].ai_index].ai_flags[AI::AI_Flags::Awaiting_repair]) )
|
||||
return AI_GOAL_NOT_ACHIEVABLE;
|
||||
|
||||
// not repairing anything means that he can do this goal!!!
|
||||
if ( !(aip->ai_flags & AIF_REPAIRING) )
|
||||
if ( !(aip->ai_flags[AI::AI_Flags::Repairing]) )
|
||||
return AI_GOAL_ACHIEVABLE;
|
||||
|
||||
// test code!!!
|
||||
@@ -1852,17 +1887,17 @@ int ai_goal_priority_compare(const void *a, const void *b)
|
||||
// If the flag is set, don't push the goal higher in the list even if priority
|
||||
// is higher since goal cannot currently be achieved.
|
||||
|
||||
if ( (ga->flags & AIGF_GOAL_ON_HOLD) && !(gb->flags & AIGF_GOAL_ON_HOLD) )
|
||||
if ( (ga->flags[AI::Goal_Flags::Goal_on_hold]) && !(gb->flags[AI::Goal_Flags::Goal_on_hold]) )
|
||||
return 1;
|
||||
else if ( !(ga->flags & AIGF_GOAL_ON_HOLD) && (gb->flags & AIGF_GOAL_ON_HOLD) )
|
||||
else if ( !(ga->flags[AI::Goal_Flags::Goal_on_hold]) && (gb->flags[AI::Goal_Flags::Goal_on_hold]) )
|
||||
return -1;
|
||||
|
||||
// check whether or not the goal override flag is set. If it is set, then push this goal higher
|
||||
// in the list
|
||||
|
||||
else if ( (ga->flags & AIGF_GOAL_OVERRIDE) && !(gb->flags & AIGF_GOAL_OVERRIDE) )
|
||||
else if ( (ga->flags[AI::Goal_Flags::Goal_override]) && !(gb->flags[AI::Goal_Flags::Goal_override]) )
|
||||
return -1;
|
||||
else if ( !(ga->flags & AIGF_GOAL_OVERRIDE) && (gb->flags & AIGF_GOAL_OVERRIDE) )
|
||||
else if ( !(ga->flags[AI::Goal_Flags::Goal_override]) && (gb->flags[AI::Goal_Flags::Goal_override]) )
|
||||
return 1;
|
||||
|
||||
// now normal priority processing
|
||||
@@ -1917,7 +1952,7 @@ void validate_mission_goals(int objnum, ai_info *aip)
|
||||
continue;
|
||||
|
||||
// purge any goals which should get purged
|
||||
if ( aigp->flags & AIGF_PURGE ) {
|
||||
if ( aigp->flags[AI::Goal_Flags::Purge] ) {
|
||||
ai_remove_ship_goal( aip, i );
|
||||
continue;
|
||||
}
|
||||
@@ -1931,19 +1966,19 @@ void validate_mission_goals(int objnum, ai_info *aip)
|
||||
}
|
||||
|
||||
// if the status is achievable, and the on_hold flag is set, clear the flagb
|
||||
if ( (state == AI_GOAL_ACHIEVABLE) && (aigp->flags & AIGF_GOAL_ON_HOLD) )
|
||||
aigp->flags &= ~AIGF_GOAL_ON_HOLD;
|
||||
if ( (state == AI_GOAL_ACHIEVABLE) && (aigp->flags[AI::Goal_Flags::Goal_on_hold]) )
|
||||
aigp->flags.remove(AI::Goal_Flags::Goal_on_hold);
|
||||
|
||||
// if the goal is not known, then set the ON_HOLD flag so that it doesn't get counted as
|
||||
// a goal to be pursued
|
||||
if ( state == AI_GOAL_NOT_KNOWN )
|
||||
aigp->flags |= AIGF_GOAL_ON_HOLD; // put this goal on hold until it becomes true
|
||||
if (state == AI_GOAL_NOT_KNOWN)
|
||||
aigp->flags.set(AI::Goal_Flags::Goal_on_hold); // put this goal on hold until it becomes true
|
||||
}
|
||||
|
||||
// if we had an active goal, and that goal is now in hold, make the mode AIM_NONE. If a new valid
|
||||
// goal is produced after prioritizing, then the mode will get reset immediately. Otherwise, setting
|
||||
// the mode to none will force ship to do default behavior.
|
||||
if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags & AIGF_GOAL_ON_HOLD) )
|
||||
if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags[AI::Goal_Flags::Goal_on_hold]) )
|
||||
aip->mode = AIM_NONE;
|
||||
|
||||
// if the active goal is a rearm/repair goal, the put all other valid goals (which are not repair goals)
|
||||
@@ -1952,7 +1987,7 @@ void validate_mission_goals(int objnum, ai_info *aip)
|
||||
for ( i = 1; i < MAX_AI_GOALS; i++ ) {
|
||||
if ( (aip->goals[i].ai_mode == AI_GOAL_NONE) || (aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR) )
|
||||
continue;
|
||||
aip->goals[i].flags |= AIGF_GOAL_ON_HOLD;
|
||||
aip->goals[i].flags.set(AI::Goal_Flags::Goal_on_hold);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2020,7 +2055,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
|
||||
// if the first goal in the list has the ON_HOLD flag, set, there is no current valid goal
|
||||
// to pursue.
|
||||
if ( aip->goals[0].flags & AIGF_GOAL_ON_HOLD )
|
||||
if ( aip->goals[0].flags[AI::Goal_Flags::Goal_on_hold] )
|
||||
return;
|
||||
|
||||
// Kind of a hack for now. active_goal means the goal currently being pursued.
|
||||
@@ -2038,7 +2073,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
// if this object was flying in formation off of another object, remove the flag that tells him
|
||||
// to do this. The form-on-my-wing command is removed from the goal list as soon as it is called, so
|
||||
// we are safe removing this bit here.
|
||||
aip->ai_flags &= ~AIF_FORMATION_OBJECT;
|
||||
aip->ai_flags.remove(AI::AI_Flags::Formation_object);
|
||||
|
||||
// Goober5000 - we may want to use AI for the player
|
||||
// AL 3-7-98: If this is a player ship, and the goal is not a formation goal, then do a quick out
|
||||
@@ -2116,7 +2151,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
|
||||
// be sure that we have indices for docking points here! If we ever had names, they should
|
||||
// get fixed up in goal_achievable so that the points can be checked there for validity
|
||||
Assert (current_goal->flags & AIGF_DOCK_INDEXES_VALID);
|
||||
Assert (current_goal->flags[AI::Goal_Flags::Dockee_index_valid] && current_goal->flags[AI::Goal_Flags::Docker_index_valid]);
|
||||
ai_dock_with_object( objp, current_goal->docker.index, other_obj, current_goal->dockee.index, AIDO_DOCK );
|
||||
break;
|
||||
}
|
||||
@@ -2198,7 +2233,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
|
||||
if (aip->target_objnum != -1) {
|
||||
// Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
|
||||
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].ai_bools & STI_AI_PROTECTED_ON_CRIPPLE)
|
||||
if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].flags[Ship::Type_Info_Flags::AI_protected_on_cripple])
|
||||
Objects[aip->target_objnum].flags.set(Object::Object_Flags::Protected);
|
||||
}
|
||||
} else // Just in case this ship had been protected, unprotect it.
|
||||
@@ -2210,7 +2245,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
|
||||
case AI_GOAL_CHASE_WING:
|
||||
wingnum = wing_name_lookup( current_goal->target_name );
|
||||
Assert( wingnum >= 0 );
|
||||
Assertion( wingnum >= 0, "The target of AI_GOAL_CHASE_WING must refer to a valid wing!" );
|
||||
ai_attack_wing(objp, wingnum);
|
||||
break;
|
||||
|
||||
@@ -2218,6 +2253,13 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
ai_attack_object( objp, NULL, NULL );
|
||||
break;
|
||||
|
||||
// chase-ship-class is chase-any but restricted to a subset of ships
|
||||
case AI_GOAL_CHASE_SHIP_CLASS:
|
||||
shipnum = ship_info_lookup( current_goal->target_name );
|
||||
Assertion( shipnum >= 0, "The target of AI_GOAL_CHASE_SHIP_CLASS must refer to a valid ship class!" );
|
||||
ai_attack_object( objp, NULL, NULL, shipnum );
|
||||
break;
|
||||
|
||||
case AI_GOAL_WARP: {
|
||||
mission_do_departure( objp, true );
|
||||
break;
|
||||
@@ -2347,15 +2389,22 @@ void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, c
|
||||
flag = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Warning(LOCATION, "unhandled FRED reference type %d in ai_update_goal_references", type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (flag) // is this a valid goal to parse for this conversion?
|
||||
if (!stricmp(goals[i].target_name, old_name)) {
|
||||
{
|
||||
if (!stricmp(goals[i].target_name, old_name))
|
||||
{
|
||||
if (*new_name == '<') // target was just deleted..
|
||||
goals[i].ai_mode = AI_GOAL_NONE;
|
||||
else
|
||||
goals[i].target_name = ai_get_goal_target_name(new_name, &dummy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -26,6 +26,7 @@ struct ai_goal;
|
||||
// Fred. If the goal you add doesn't have a target (such as chase_any), then you don't have
|
||||
// to worry about doing this. Also add it to list in Fred\Management.cpp, and let Hoffoss know!
|
||||
// WMC - Oh and add them to Ai_goal_names plz. TY! :)
|
||||
// Goober5000 - As well as Ai_goal_text and Ai_goal_list, if appropriate
|
||||
#define AI_GOAL_CHASE (1<<1) // 0x00000002
|
||||
#define AI_GOAL_DOCK (1<<2) // 0x00000004 // used for undocking as well
|
||||
#define AI_GOAL_WAYPOINTS (1<<3) // 0x00000008
|
||||
@@ -51,10 +52,12 @@ struct ai_goal;
|
||||
// resume regular goals
|
||||
#define AI_GOAL_STAY_STILL (1<<20) // 0x00100000
|
||||
#define AI_GOAL_PLAY_DEAD (1<<21) // 0x00200000
|
||||
#define AI_GOAL_CHASE_WEAPON (1<<22) // 0x00400000
|
||||
|
||||
// added by SCP
|
||||
#define AI_GOAL_CHASE_WEAPON (1<<22) // 0x00400000
|
||||
#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
|
||||
#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
|
||||
#define AI_GOAL_CHASE_SHIP_CLASS (1<<25) // 0x02000000
|
||||
|
||||
// now the masks for ship types
|
||||
|
||||
|
||||
+123
-179
@@ -14,7 +14,7 @@
|
||||
#include "network/multi.h"
|
||||
#include "network/multimsgs.h"
|
||||
#include "object/objectdock.h"
|
||||
#include "parse/scripting.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "render/3d.h"
|
||||
#include "ship/ship.h"
|
||||
#include "ship/shipfx.h"
|
||||
@@ -47,7 +47,7 @@ float Player_lethality_bump[NUM_SKILL_LEVELS] = {
|
||||
0.0f, 0.0f, 0.0f, 0.0f, 0.0f
|
||||
};
|
||||
|
||||
char *Turret_target_order_names[NUM_TURRET_ORDER_TYPES] = {
|
||||
const char *Turret_target_order_names[NUM_TURRET_ORDER_TYPES] = {
|
||||
"Bombs",
|
||||
"Ships",
|
||||
"Asteroids",
|
||||
@@ -158,7 +158,7 @@ bool is_object_radius_in_turret_fov(object *objp, ship_subsys *ss, vec3d *tvec,
|
||||
fix_elevation = true;
|
||||
}
|
||||
|
||||
if (tp->flags & MSS_FLAG_TURRET_ALT_MATH) {
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
|
||||
vec3d temp_vec2;
|
||||
vm_vec_rotate(&temp_vec2, &temp_vec, &ss->world_to_turret_matrix);
|
||||
|
||||
@@ -256,54 +256,46 @@ int turret_select_best_weapon(ship_subsys *turret, object *target)
|
||||
|
||||
/**
|
||||
* Returns true if all weapons in swp have the specified flag
|
||||
*
|
||||
* @note doesn't work for WIF2
|
||||
*/
|
||||
bool all_turret_weapons_have_flags(ship_weapon *swp, int flags)
|
||||
bool all_turret_weapons_have_flags(ship_weapon *swp, flagset<Weapon::Info_Flags> flags)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
if(!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags & flags))
|
||||
if(!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags & flags).any_set())
|
||||
return false;
|
||||
}
|
||||
for(i = 0; i < swp->num_secondary_banks; i++)
|
||||
{
|
||||
if(!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags & flags))
|
||||
if(!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags & flags).any_set())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all weapons in swp have the specified flag
|
||||
*
|
||||
* @note does work for WIF2, but not WIF
|
||||
*/
|
||||
bool all_turret_weapons_have_flags2(ship_weapon *swp, int flags)
|
||||
bool all_turret_weapons_have_flags(ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
if(!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags2 & flags))
|
||||
return false;
|
||||
}
|
||||
for(i = 0; i < swp->num_secondary_banks; i++)
|
||||
{
|
||||
if(!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags2 & flags))
|
||||
return false;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
if (!(Weapon_info[swp->primary_bank_weapons[i]].wi_flags[flags]))
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < swp->num_secondary_banks; i++)
|
||||
{
|
||||
if (!(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags[flags]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any of the weapons in swp have flags
|
||||
*
|
||||
* @note doesn't work for WIF2
|
||||
*/
|
||||
bool turret_weapon_has_flags(ship_weapon *swp, int flags)
|
||||
bool turret_weapon_has_flags(ship_weapon *swp, Weapon::Info_Flags flags)
|
||||
{
|
||||
Assert(swp != NULL);
|
||||
|
||||
@@ -311,42 +303,14 @@ bool turret_weapon_has_flags(ship_weapon *swp, int flags)
|
||||
for(i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
if(swp->primary_bank_weapons[i] >=0) {
|
||||
if(Weapon_info[swp->primary_bank_weapons[i]].wi_flags & flags)
|
||||
if(Weapon_info[swp->primary_bank_weapons[i]].wi_flags[flags])
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < swp->num_secondary_banks; i++)
|
||||
{
|
||||
if(swp->secondary_bank_weapons[i] >=0) {
|
||||
if(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags & flags)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any of the weapons in swp have flags
|
||||
*
|
||||
* @note does work for WIF2, but not WIF
|
||||
*/
|
||||
bool turret_weapon_has_flags2(ship_weapon *swp, int flags)
|
||||
{
|
||||
Assert(swp != NULL);
|
||||
|
||||
int i = 0;
|
||||
for(i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
if(swp->primary_bank_weapons[i] >=0) {
|
||||
if(Weapon_info[swp->primary_bank_weapons[i]].wi_flags2 & flags)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < swp->num_secondary_banks; i++)
|
||||
{
|
||||
if(swp->secondary_bank_weapons[i] >=0) {
|
||||
if(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags2 & flags)
|
||||
if(Weapon_info[swp->secondary_bank_weapons[i]].wi_flags[flags])
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -357,11 +321,12 @@ bool turret_weapon_has_flags2(ship_weapon *swp, int flags)
|
||||
/**
|
||||
* Just gloms all the flags from all the weapons into one variable. More efficient if all you need to do is test for the existence of a flag.
|
||||
*/
|
||||
int turret_weapon_aggregate_flags(ship_weapon *swp)
|
||||
flagset<Weapon::Info_Flags> turret_weapon_aggregate_flags(ship_weapon *swp)
|
||||
{
|
||||
Assert(swp != NULL);
|
||||
|
||||
int i = 0, flags = 0;
|
||||
int i = 0;
|
||||
flagset<Weapon::Info_Flags> flags;
|
||||
for (i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
if (swp->primary_bank_weapons[i] >= 0) {
|
||||
@@ -378,30 +343,6 @@ int turret_weapon_aggregate_flags(ship_weapon *swp)
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just gloms all the flags from all the weapons into one variable. More efficient if all you need to do is test for the existence of a flag.
|
||||
*/
|
||||
int turret_weapon_aggregate_flags2(ship_weapon *swp)
|
||||
{
|
||||
Assert(swp != NULL);
|
||||
|
||||
int i = 0, flags2 = 0;
|
||||
for (i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
if (swp->primary_bank_weapons[i] >= 0) {
|
||||
flags2 |= Weapon_info[swp->primary_bank_weapons[i]].wi_flags2;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < swp->num_secondary_banks; i++)
|
||||
{
|
||||
if (swp->secondary_bank_weapons[i] >= 0) {
|
||||
flags2 |= Weapon_info[swp->secondary_bank_weapons[i]].wi_flags2;
|
||||
}
|
||||
}
|
||||
|
||||
return flags2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any of the weapons in swp have the subtype specified
|
||||
*
|
||||
@@ -473,7 +414,7 @@ float longest_turret_weapon_range(ship_weapon *swp)
|
||||
for(i = 0; i < swp->num_primary_banks; i++)
|
||||
{
|
||||
wip = &Weapon_info[swp->primary_bank_weapons[i]];
|
||||
if (wip->wi_flags2 & WIF2_LOCAL_SSM)
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
|
||||
weapon_range = wip->lssm_lock_range;
|
||||
else
|
||||
weapon_range = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
|
||||
@@ -484,7 +425,7 @@ float longest_turret_weapon_range(ship_weapon *swp)
|
||||
for(i = 0; i < swp->num_secondary_banks; i++)
|
||||
{
|
||||
wip = &Weapon_info[swp->secondary_bank_weapons[i]];
|
||||
if (wip->wi_flags2 & WIF2_LOCAL_SSM)
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
|
||||
weapon_range = wip->lssm_lock_range;
|
||||
else
|
||||
weapon_range = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
|
||||
@@ -537,7 +478,7 @@ int valid_turret_enemy(object *objp, object *turret_parent)
|
||||
}
|
||||
|
||||
// Goober5000 - don't fire at cargo containers (now specified in ship_types)
|
||||
if ( (sip->class_type >= 0) && !(Ship_types[sip->class_type].ai_bools & STI_AI_TURRETS_ATTACK) ) {
|
||||
if ( (sip->class_type >= 0) && !(Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::AI_turrets_attack]) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -549,15 +490,15 @@ int valid_turret_enemy(object *objp, object *turret_parent)
|
||||
weapon *wp = &Weapons[objp->instance];
|
||||
weapon_info *wip = &Weapon_info[wp->weapon_info_index];
|
||||
|
||||
if (wip->subtype == WP_LASER && !(wip->wi_flags3 & WIF3_TURRET_INTERCEPTABLE)) { // If the thing can't be shot down, don't try. -MageKing17
|
||||
if (wip->subtype == WP_LASER && !(wip->wi_flags[Weapon::Info_Flags::Turret_Interceptable])) { // If the thing can't be shot down, don't try. -MageKing17
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (!((wip->wi_flags & WIF_BOMB) || (wip->wi_flags3 & WIF3_TURRET_INTERCEPTABLE)) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
|
||||
if ( (!((wip->wi_flags[Weapon::Info_Flags::Bomb]) || (wip->wi_flags[Weapon::Info_Flags::Turret_Interceptable])) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Allow_turrets_target_weapons_freely]) ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (wip->wi_flags2 & WIF2_LOCAL_SSM) && (wp->lssm_stage == 3) ) {
|
||||
if ( (wip->wi_flags[Weapon::Info_Flags::Local_ssm]) && (wp->lssm_stage == 3) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -657,8 +598,8 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
|
||||
// however if this is removed turrets still track targets but don't fire at them (which looks silly)
|
||||
if (eeo->eeo_flags & EEOF_TAGGED_ONLY) {
|
||||
if (!ship_is_tagged(objp) &&
|
||||
( (The_mission.ai_profile->flags2 & AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING) ||
|
||||
( !(objp->type == OBJ_WEAPON) && !(turret_weapon_has_flags(&eeo->turret_subsys->weapons, WIF_SPAWN))) )) {
|
||||
( (The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turred_tagged_only_targeting]) ||
|
||||
( !(objp->type == OBJ_WEAPON) && !(turret_weapon_has_flags(&eeo->turret_subsys->weapons, Weapon::Info_Flags::Spawn))) )) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -715,7 +656,7 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
|
||||
// check if bomb is homing on the turret parent ship
|
||||
bool check_weapon = true;
|
||||
|
||||
if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
|
||||
if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Prevent_targeting_bombs_beyond_range]) && (dist > eeo->weapon_travel_dist)) {
|
||||
check_weapon = false;
|
||||
}
|
||||
|
||||
@@ -842,12 +783,12 @@ void evaluate_obj_as_target(object *objp, eval_enemy_obj_struct *eeo)
|
||||
int is_target_beam_valid(ship_weapon *swp, object *objp)
|
||||
{
|
||||
// check if turret has beam weapon
|
||||
if (all_turret_weapons_have_flags(swp, WIF_BEAM)) {
|
||||
if (all_turret_weapons_have_flags(swp, Weapon::Info_Flags::Beam)) {
|
||||
if (objp->flags[Object::Object_Flags::Beam_protected]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (all_turret_weapons_have_flags(swp, WIF_HUGE)) {
|
||||
if (all_turret_weapons_have_flags(swp, Weapon::Info_Flags::Huge)) {
|
||||
if (objp->type == OBJ_SHIP && !(Ship_info[Ships[objp->instance].ship_info_index].is_big_or_huge()) ) {
|
||||
return 0;
|
||||
}
|
||||
@@ -889,7 +830,7 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
//wip=&Weapon_info[tp->turret_weapon_type];
|
||||
//weapon_travel_dist = MIN(wip->lifetime * wip->max_speed, wip->weapon_range);
|
||||
|
||||
//if (wip->wi_flags2 & WIF2_LOCAL_SSM)
|
||||
//if (wip->wi_flags[Weapon::Info_Flags::Local_ssm])
|
||||
// weapon_travel_dist=wip->lssm_lock_range;
|
||||
|
||||
// Set flag based on strength of weapons subsystem. If weapons subsystem is destroyed, don't let turrets fire at bombs
|
||||
@@ -960,8 +901,8 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
n_tgt_priorities = Weapon_info[priority_weapon_idx].num_targeting_priorities;
|
||||
}
|
||||
|
||||
if (n_tgt_priorities > 0) {
|
||||
|
||||
if (n_tgt_priorities > 0)
|
||||
{
|
||||
for(int i = 0; i < n_tgt_priorities; i++) {
|
||||
// courtesy of WMC...
|
||||
ai_target_priority *tt;
|
||||
@@ -1008,10 +949,8 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
}
|
||||
}
|
||||
|
||||
if( ( (tt->wif_flags != 0) || (tt->wif2_flags != 0) || (tt->wif3_flags != 0) ) && (ptr->type == OBJ_WEAPON) ) {
|
||||
if( ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags & tt->wif_flags ) == tt->wif_flags)
|
||||
&& ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags2 & tt->wif2_flags ) == tt->wif2_flags)
|
||||
&& ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags3 & tt->wif3_flags ) == tt->wif3_flags) ) {
|
||||
if( (tt->wif_flags.any_set()) && (ptr->type == OBJ_WEAPON) ) {
|
||||
if( ( (Weapon_info[Weapons[ptr->instance].weapon_info_index].wi_flags & tt->wif_flags ) == tt->wif_flags) ) {
|
||||
found_something = true;
|
||||
}
|
||||
}
|
||||
@@ -1087,7 +1026,11 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
return return_objnum;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
flagset<Weapon::Info_Flags> tmp_flagset;
|
||||
const Weapon::Info_Flags weapon_flags[] = { Weapon::Info_Flags::Huge, Weapon::Info_Flags::Flak, Weapon::Info_Flags::Homing_aspect, Weapon::Info_Flags::Homing_heat, Weapon::Info_Flags::Homing_javelin, Weapon::Info_Flags::Spawn };
|
||||
tmp_flagset.set_multiple(std::begin(weapon_flags), std::end(weapon_flags));
|
||||
|
||||
for(int i = 0; i < NUM_TURRET_ORDER_TYPES; i++)
|
||||
{
|
||||
@@ -1101,14 +1044,14 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
case 0:
|
||||
//Return if a bomb is found
|
||||
//don't fire anti capital ship turrets at bombs.
|
||||
if ( !((aip->ai_profile_flags & AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS) && big_only_flag) )
|
||||
if ( !((aip->ai_profile_flags[AI::Profile_Flags::Huge_turret_weapons_ignore_bombs]) && big_only_flag) )
|
||||
{
|
||||
// Missile_obj_list
|
||||
for( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
|
||||
objp = &Objects[mo->objnum];
|
||||
|
||||
Assert(objp->type == OBJ_WEAPON);
|
||||
if ((Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_BOMB) || (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags3 & WIF3_TURRET_INTERCEPTABLE))
|
||||
if ((Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Bomb]) || (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Turret_Interceptable]))
|
||||
{
|
||||
evaluate_obj_as_target(objp, &eeo);
|
||||
}
|
||||
@@ -1151,7 +1094,8 @@ int get_nearest_turret_objnum(int turret_parent_objnum, ship_subsys *turret_subs
|
||||
// - lasers
|
||||
// - dumbfire type missiles
|
||||
// - AAA beams
|
||||
if ( !all_turret_weapons_have_flags(swp, WIF_HUGE | WIF_FLAK | WIF_HOMING | WIF_SPAWN) ) {
|
||||
|
||||
if ( !all_turret_weapons_have_flags(swp, tmp_flagset) ) {
|
||||
// Asteroid_obj_list
|
||||
for ( ao = GET_FIRST(&Asteroid_obj_list); ao != END_OF_LIST(&Asteroid_obj_list); ao = GET_NEXT(ao) ) {
|
||||
objp = &Objects[ao->objnum];
|
||||
@@ -1192,12 +1136,12 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
|
||||
|
||||
enemy_team_mask = iff_get_attackee_mask(obj_team(&Objects[objnum]));
|
||||
|
||||
bool big_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, WIF_HUGE);
|
||||
bool small_only_flag = all_turret_weapons_have_flags2(&turret_subsys->weapons, WIF2_SMALL_ONLY);
|
||||
bool tagged_only_flag = all_turret_weapons_have_flags2(&turret_subsys->weapons, WIF2_TAGGED_ONLY) || (turret_subsys->weapons.flags & SW_FLAG_TAGGED_ONLY);
|
||||
bool big_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, Weapon::Info_Flags::Huge);
|
||||
bool small_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, Weapon::Info_Flags::Small_only);
|
||||
bool tagged_only_flag = all_turret_weapons_have_flags(&turret_subsys->weapons, Weapon::Info_Flags::Tagged_only) || (turret_subsys->weapons.flags[Ship::Weapon_Flags::Tagged_Only]);
|
||||
|
||||
bool beam_flag = turret_weapon_has_flags(&turret_subsys->weapons, WIF_BEAM);
|
||||
bool flak_flag = turret_weapon_has_flags(&turret_subsys->weapons, WIF_FLAK);
|
||||
bool beam_flag = turret_weapon_has_flags(&turret_subsys->weapons, Weapon::Info_Flags::Beam);
|
||||
bool flak_flag = turret_weapon_has_flags(&turret_subsys->weapons, Weapon::Info_Flags::Flak);
|
||||
bool laser_flag = turret_weapon_has_subtype(&turret_subsys->weapons, WP_LASER);
|
||||
bool missile_flag = turret_weapon_has_subtype(&turret_subsys->weapons, WP_MISSILE);
|
||||
|
||||
@@ -1205,7 +1149,7 @@ int find_turret_enemy(ship_subsys *turret_subsys, int objnum, vec3d *tpos, vec3d
|
||||
ai_info *aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
|
||||
sip = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
|
||||
|
||||
if ((Ship_types[sip->class_type].ship_bools & STI_TURRET_TGT_SHIP_TGT) && (aip->target_objnum != -1)) {
|
||||
if ((Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Turret_tgt_ship_tgt]) && (aip->target_objnum != -1)) {
|
||||
int target_objnum = aip->target_objnum;
|
||||
|
||||
if (Objects[target_objnum].signature == aip->target_signature) {
|
||||
@@ -1339,7 +1283,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
|
||||
if (use_angles) {
|
||||
model_instance_find_world_dir(gvec, &tp->turret_norm, Ships[objp->instance].model_instance_num, tp->turret_gun_sobj, &objp->orient);
|
||||
} else if (tp->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION) {
|
||||
} else if (tp->flags[Model::Subsystem_Flags::Share_fire_direction]) {
|
||||
vec3d avg, tmp_pos, tmp_target, enemy_point, turret_norm;
|
||||
vm_vec_avg_n(&avg, tp->turret_num_firing_points, tp->turret_firing_point);
|
||||
|
||||
@@ -1377,7 +1321,7 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
vec3d target_moving_direction = ssp->last_aim_enemy_vel;
|
||||
|
||||
//Try to guess where the enemy will be, and store that spot in predicted_enemy_pos
|
||||
if (The_mission.ai_profile->flags & AIPF_USE_ADDITIVE_WEAPON_VELOCITY) {
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_additive_weapon_velocity]) {
|
||||
vm_vec_scale_sub2(&target_moving_direction, &objp->phys_info.vel, wip->vel_inherit_amount);
|
||||
}
|
||||
|
||||
@@ -1473,7 +1417,7 @@ int aifft_rotate_turret(ship *shipp, int parent_objnum, ship_subsys *ss, object
|
||||
target_moving_direction = ss->last_aim_enemy_vel;
|
||||
|
||||
//Try to guess where the enemy will be, and store that spot in predicted_enemy_pos
|
||||
if (The_mission.ai_profile->flags & AIPF_USE_ADDITIVE_WEAPON_VELOCITY) {
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_additive_weapon_velocity]) {
|
||||
vm_vec_scale_sub2(&target_moving_direction, &objp->phys_info.vel, wip->vel_inherit_amount);
|
||||
}
|
||||
|
||||
@@ -1507,10 +1451,10 @@ int aifft_rotate_turret(ship *shipp, int parent_objnum, ship_subsys *ss, object
|
||||
tp, &Objects[parent_objnum].orient,
|
||||
&ss->submodel_info_1.angs, &ss->submodel_info_2.angs,
|
||||
&Objects[parent_objnum].pos, predicted_enemy_pos, shipp->objnum);
|
||||
} else if ((tp->flags & MSS_FLAG_TURRET_RESET_IDLE) &&(timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
} else if ((tp->flags[Model::Subsystem_Flags::Turret_reset_idle]) &&(timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(Ship_info[shipp->ship_info_index].model_num, tp, &Objects[parent_objnum].orient, &ss->submodel_info_1.angs, &ss->submodel_info_2.angs, &Objects[parent_objnum].pos, predicted_enemy_pos, shipp->objnum, true);
|
||||
}
|
||||
} else if ((ss->system_info->flags & MSS_FLAG_TURRET_RESET_IDLE) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
} else if ((ss->system_info->flags[Model::Subsystem_Flags::Turret_reset_idle]) && (timestamp_elapsed(ss->rotation_timestamp))) {
|
||||
ret_val = model_rotate_gun(Ship_info[shipp->ship_info_index].model_num, ss->system_info, &Objects[parent_objnum].orient, &ss->submodel_info_1.angs, &ss->submodel_info_2.angs, &Objects[parent_objnum].pos, predicted_enemy_pos, shipp->objnum, true);
|
||||
}
|
||||
|
||||
@@ -1521,7 +1465,7 @@ int aifft_rotate_turret(ship *shipp, int parent_objnum, ship_subsys *ss, object
|
||||
|
||||
// return 0 by default (to preserve retail behavior) but allow for a per-subsystem option
|
||||
// for using the turret normals for firing
|
||||
if (ss->system_info->flags & MSS_FLAG_FIRE_ON_NORMAL)
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Fire_on_normal])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -1546,7 +1490,7 @@ float aifft_compute_turret_dot(object *objp, object *enemy_objp, vec3d *abs_gunp
|
||||
vm_vec_unrotate(&turret_norm, &turret_subsysp->system_info->turret_norm, &objp->orient);
|
||||
float dot_return = vm_vec_dot(&turret_norm, &vector_out);
|
||||
|
||||
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
|
||||
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags[AI::Profile_Flags::Smart_subsystem_targeting_for_turrets]) {
|
||||
if (dot_return > turret_subsysp->system_info->turret_fov) {
|
||||
// target is in sight and in fov
|
||||
return dot_return;
|
||||
@@ -1675,7 +1619,7 @@ ship_subsys *aifft_find_turret_subsys(object *objp, ship_subsys *ssp, object *en
|
||||
int idx;
|
||||
float dot_fov_modifier = 0.0f;
|
||||
|
||||
if (Ai_info[shipp->ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
|
||||
if (Ai_info[shipp->ai_index].ai_profile_flags[AI::Profile_Flags::Smart_subsystem_targeting_for_turrets]) {
|
||||
if (ssp->system_info->turret_fov < 0)
|
||||
dot_fov_modifier = ssp->system_info->turret_fov;
|
||||
}
|
||||
@@ -1733,7 +1677,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
turret->weapons.burst_counter[weapon_num]++;
|
||||
} else {
|
||||
wait *= wip->fire_wait;
|
||||
if ((wip->burst_shots > 0) && (wip->burst_flags & WBF_RANDOM_LENGTH)) {
|
||||
if ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Random_length])) {
|
||||
turret->weapons.burst_counter[weapon_num] = (myrand() % wip->burst_shots);
|
||||
} else {
|
||||
turret->weapons.burst_counter[weapon_num] = 0;
|
||||
@@ -1747,13 +1691,13 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
fs_dest = &turret->weapons.next_secondary_fire_stamp[weapon_num - MAX_SHIP_PRIMARY_BANKS];
|
||||
|
||||
//Check for the new cooldown flag
|
||||
if(!((wip->wi_flags2 & WIF2_SAME_TURRET_COOLDOWN) || ((wip->burst_shots > 0) && (wip->burst_flags & WBF_FAST_FIRING))))
|
||||
if(!((wip->wi_flags[Weapon::Info_Flags::Same_turret_cooldown]) || ((wip->burst_shots > 0) && (wip->burst_flags[Weapon::Burst_Flags::Fast_firing]))))
|
||||
{
|
||||
|
||||
// make side even for team vs. team
|
||||
if (MULTI_TEAM) {
|
||||
// flak guns need to fire more rapidly
|
||||
if (wip->wi_flags & WIF_FLAK) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
|
||||
if (aip->ai_class_autoscale)
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
|
||||
@@ -1764,7 +1708,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
}
|
||||
} else {
|
||||
// flak guns need to fire more rapidly
|
||||
if (wip->wi_flags & WIF_FLAK) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
if (Ships[aip->shipnum].team == Player_ship->team) {
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly * 0.5f;
|
||||
} else {
|
||||
@@ -1773,7 +1717,7 @@ void turret_set_next_fire_timestamp(int weapon_num, weapon_info *wip, ship_subsy
|
||||
if (aip->ai_class_autoscale)
|
||||
wait += (Num_ai_classes - aip->ai_class - 1) * 40.0f;
|
||||
|
||||
} else if (wip->wi_flags & WIF_HUGE) {
|
||||
} else if (wip->wi_flags[Weapon::Info_Flags::Huge]) {
|
||||
// make huge weapons fire independently of team
|
||||
wait *= aip->ai_ship_fire_delay_scale_friendly;
|
||||
if (aip->ai_class_autoscale)
|
||||
@@ -1842,7 +1786,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
object *objp;
|
||||
bool last_shot_in_salvo = true;
|
||||
|
||||
if (turret->system_info->flags & MSS_FLAG_TURRET_SALVO)
|
||||
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo])
|
||||
{
|
||||
if ((turret->turret_next_fire_pos + 1) == (turret->system_info->turret_num_firing_points))
|
||||
{
|
||||
@@ -1869,12 +1813,12 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
object *tobjp = &Objects[turret->turret_enemy_objnum];
|
||||
|
||||
// should not get this far. check if ship is protected from beam and weapon is type beam
|
||||
if ( (wip->wi_flags & WIF_BEAM) && (tobjp->flags[Object::Object_Flags::Beam_protected]) ) {
|
||||
if ( (wip->wi_flags[Weapon::Info_Flags::Beam]) && (tobjp->flags[Object::Object_Flags::Beam_protected]) ) {
|
||||
Int3();
|
||||
return 0;
|
||||
}
|
||||
// should not get this far. check if ship is protected from flak and weapon is type flak
|
||||
else if ( (wip->wi_flags & WIF_FLAK) && (tobjp->flags[Object::Object_Flags::Flak_protected]) ) {
|
||||
else if ( (wip->wi_flags[Weapon::Info_Flags::Flak]) && (tobjp->flags[Object::Object_Flags::Flak_protected]) ) {
|
||||
Int3();
|
||||
return 0;
|
||||
}
|
||||
@@ -1900,9 +1844,9 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
|
||||
|
||||
// if this weapon is a beam weapon, handle it specially
|
||||
if (wip->wi_flags & WIF_BEAM) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
|
||||
// if this beam isn't free to fire
|
||||
if (!(turret->weapons.flags & SW_FLAG_BEAM_FREE)) {
|
||||
if (!(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
return false;
|
||||
}
|
||||
beam_fire_info fire_info;
|
||||
@@ -1914,7 +1858,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
fire_info.beam_info_override = NULL;
|
||||
fire_info.shooter = &Objects[parent_objnum];
|
||||
fire_info.target = &Objects[turret->turret_enemy_objnum];
|
||||
if (wip->wi_flags2 & WIF2_ANTISUBSYSBEAM)
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
|
||||
fire_info.target_subsys = turret->targeted_subsys;
|
||||
else
|
||||
fire_info.target_subsys = NULL;
|
||||
@@ -1938,14 +1882,14 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
return true;
|
||||
}
|
||||
// don't fire swam, but set up swarm info instead
|
||||
else if ((wip->wi_flags & WIF_SWARM) || (wip->wi_flags & WIF_CORKSCREW)) {
|
||||
else if ((wip->wi_flags[Weapon::Info_Flags::Swarm]) || (wip->wi_flags[Weapon::Info_Flags::Corkscrew])) {
|
||||
ship_weapon *swp = &turret->weapons;
|
||||
if (swp->current_secondary_bank < 0) {
|
||||
swp->current_secondary_bank = 0;
|
||||
}
|
||||
int bank_to_fire = swp->current_secondary_bank;
|
||||
if ((turret->system_info->flags2 & MSS_FLAG2_TURRET_USE_AMMO) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
|
||||
if (!(turret->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS)) {
|
||||
if ((turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
|
||||
if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns])) {
|
||||
swp->current_secondary_bank++;
|
||||
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
|
||||
swp->current_secondary_bank = 0;
|
||||
@@ -1964,7 +1908,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
// now do anything else
|
||||
else {
|
||||
for (int i = 0; i < wip->shots; i++) {
|
||||
if (turret->system_info->flags2 & MSS_FLAG2_TURRET_USE_AMMO) {
|
||||
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_use_ammo]) {
|
||||
ship_weapon *swp;
|
||||
swp = &turret->weapons;
|
||||
int bank_to_fire, num_slots = turret->system_info->turret_num_firing_points;
|
||||
@@ -1988,7 +1932,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
bank_to_fire = swp->current_primary_bank;
|
||||
|
||||
if (turret->system_info->flags & MSS_FLAG_TURRET_SALVO) {
|
||||
if (turret->system_info->flags[Model::Subsystem_Flags::Turret_salvo]) {
|
||||
points = num_slots;
|
||||
} else {
|
||||
points = 1;
|
||||
@@ -1996,7 +1940,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
if (swp->primary_bank_ammo[bank_to_fire] >= 0) {
|
||||
swp->primary_bank_ammo[bank_to_fire] -= points;
|
||||
} else if (!(turret->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS) && (swp->primary_bank_ammo[bank_to_fire] < 0)) {
|
||||
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->primary_bank_ammo[bank_to_fire] < 0)) {
|
||||
swp->current_primary_bank++;
|
||||
if (swp->current_primary_bank >= swp->num_primary_banks) {
|
||||
swp->current_primary_bank = 0;
|
||||
@@ -2032,7 +1976,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
if (swp->secondary_bank_ammo[bank_to_fire] >= 0) {
|
||||
swp->secondary_bank_ammo[bank_to_fire]--;
|
||||
} else if (!(turret->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
|
||||
} else if (!(turret->system_info->flags[Model::Subsystem_Flags::Use_multiple_guns]) && (swp->secondary_bank_ammo[bank_to_fire] < 0)) {
|
||||
swp->current_secondary_bank++;
|
||||
if (swp->current_secondary_bank >= swp->num_secondary_banks) {
|
||||
swp->current_secondary_bank = 0;
|
||||
@@ -2069,7 +2013,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
|
||||
|
||||
// if the gun is a flak gun
|
||||
if (wip->wi_flags & WIF_FLAK) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Flak]) {
|
||||
// show a muzzle flash
|
||||
flak_muzzle_flash(turret_pos, turret_fvec, &Objects[parent_ship->objnum].phys_info, turret_weapon_class);
|
||||
|
||||
@@ -2097,7 +2041,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
|
||||
subsys_index = ship_get_index_from_subsys(turret, parent_objnum );
|
||||
Assert( subsys_index != -1 );
|
||||
if(wip->wi_flags & WIF_FLAK){
|
||||
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
|
||||
send_flak_fired_packet( parent_objnum, subsys_index, weapon_objnum, flak_range );
|
||||
} else {
|
||||
send_turret_fired_packet( parent_objnum, subsys_index, weapon_objnum );
|
||||
@@ -2107,7 +2051,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
if ( wip->launch_snd != -1 ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( parent_objnum != OBJ_INDEX(Player_obj) || (turret->flags[Ship::Subsystem_Flags::Play_sound_for_player]) ) {
|
||||
snd_play_3d( &Snds[wip->launch_snd], turret_pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), turret_pos, &View_position );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2121,7 +2065,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
}
|
||||
//Not useful -WMC
|
||||
else if (!(parent_aip->ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
|
||||
else if (!(parent_aip->ai_profile_flags[AI::Profile_Flags::Dont_insert_random_turret_fire_delay]) && last_shot_in_salvo)
|
||||
{
|
||||
float wait = 1000.0f * frand_range(0.9f, 1.1f);
|
||||
turret->turret_next_fire_stamp = timestamp((int) wait);
|
||||
@@ -2147,7 +2091,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
}
|
||||
|
||||
// if fixed fp make sure to use constant fp
|
||||
if (tsi->turret->system_info->flags & MSS_FLAG_TURRET_FIXED_FP)
|
||||
if (tsi->turret->system_info->flags[Model::Subsystem_Flags::Turret_fixed_fp])
|
||||
tsi->turret->turret_next_fire_pos = tsi->weapon_num;
|
||||
|
||||
// change firing point
|
||||
@@ -2155,13 +2099,13 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
tsi->turret->turret_next_fire_pos++;
|
||||
|
||||
//check if this really is a swarm. If not, how the hell did it get here?
|
||||
Assert((Weapon_info[tsi->weapon_class].wi_flags & WIF_SWARM) || (Weapon_info[tsi->weapon_class].wi_flags & WIF_CORKSCREW));
|
||||
Assert((Weapon_info[tsi->weapon_class].wi_flags[Weapon::Info_Flags::Swarm]) || (Weapon_info[tsi->weapon_class].wi_flags[Weapon::Info_Flags::Corkscrew]));
|
||||
|
||||
|
||||
// *If it's a non-homer, then use the last fire direction instead of turret orientation to fix inaccuracy
|
||||
// problems with non-homing swarm weapons -Et1
|
||||
if ( (Weapon_info[tsi->weapon_class].subtype == WP_LASER) || ((The_mission.ai_profile->flags & AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY)
|
||||
&& !(Weapon_info[tsi->weapon_class].wi_flags & WIF_HOMING)) )
|
||||
if ( (Weapon_info[tsi->weapon_class].subtype == WP_LASER) || ((The_mission.ai_profile->flags[AI::Profile_Flags::Hack_improve_non_homing_swarm_turret_fire_accuracy])
|
||||
&& !(Weapon_info[tsi->weapon_class].is_homing())) )
|
||||
{
|
||||
turret_fvec = tsi->turret->turret_last_fire_direction;
|
||||
}
|
||||
@@ -2194,7 +2138,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
if ( Weapon_info[tsi->weapon_class].launch_snd != -1 ) {
|
||||
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
|
||||
if ( tsi->parent_objnum != OBJ_INDEX(Player_obj) ) {
|
||||
snd_play_3d( &Snds[Weapon_info[tsi->weapon_class].launch_snd], &turret_pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(Weapon_info[tsi->weapon_class].launch_snd), &turret_pos, &View_position );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2250,7 +2194,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
|
||||
// Check turret free
|
||||
if (ss->weapons.flags & SW_FLAG_TURRET_LOCK) {
|
||||
if (ss->weapons.flags[Ship::Weapon_Flags::Turret_Lock]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2273,7 +2217,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
|
||||
// If beam weapon, check beam free
|
||||
if ( all_turret_weapons_have_flags(swp, WIF_BEAM) && !(swp->flags & SW_FLAG_BEAM_FREE) ) {
|
||||
if ( all_turret_weapons_have_flags(swp, Weapon::Info_Flags::Beam) && !(swp->flags[Ship::Weapon_Flags::Beam_Free]) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2311,7 +2255,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
|
||||
//aip = &Ai_info[Ships[objp->instance].ai_index];
|
||||
// Wanderer - make sure turrets already have all the data
|
||||
if ( !(tp->flags & MSS_FLAG_TURRET_MATRIX) )
|
||||
if ( !(tp->flags[Model::Subsystem_Flags::Turret_matrix]) )
|
||||
{
|
||||
if (!(tp->turret_gun_sobj == tp->subobj_num))
|
||||
{
|
||||
@@ -2323,14 +2267,14 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
vec3d gvec, gpos;
|
||||
ship_get_global_turret_info(&Objects[parent_objnum], tp, &gpos, &gvec);
|
||||
|
||||
if (tp->flags & MSS_FLAG_TURRET_ALT_MATH) {
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_alt_math]) {
|
||||
vm_matrix_x_matrix( &ss->world_to_turret_matrix, &Objects[parent_objnum].orient, &tp->turret_matrix );
|
||||
}
|
||||
|
||||
// Rotate the turret even if time hasn't elapsed, since it needs to turn to face its target.
|
||||
int use_angles = aifft_rotate_turret(shipp, parent_objnum, ss, objp, lep, &predicted_enemy_pos, &gvec);
|
||||
|
||||
if ((tp->flags & MSS_FLAG_FIRE_ON_TARGET) && (ss->points_to_target >= 0.0f))
|
||||
if ((tp->flags[Model::Subsystem_Flags::Fire_on_target]) && (ss->points_to_target >= 0.0f))
|
||||
{
|
||||
// value probably needs tweaking... could perhaps be made into table option?
|
||||
if (ss->points_to_target > 0.010f)
|
||||
@@ -2348,7 +2292,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
//WMC - build a list of valid weapons. Fire spawns if there are any.
|
||||
float dist_to_enemy = 0.0f;
|
||||
if(lep != NULL) {
|
||||
if (The_mission.ai_profile->flags2 & AIPF2_TURRETS_IGNORE_TARGET_RADIUS)
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Turrets_ignore_target_radius])
|
||||
dist_to_enemy = MAX(0,vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos));
|
||||
else
|
||||
dist_to_enemy = MAX(0,vm_vec_normalized_dir(&v2e, &predicted_enemy_pos, &gpos) - lep->radius);
|
||||
@@ -2364,7 +2308,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
for(i = 0; i < (MAX_SHIP_WEAPONS); i++)
|
||||
{
|
||||
//WMC - Only fire more than once if we have multiple guns flag set.
|
||||
if(num_valid > 0 && !(tp->flags & MSS_FLAG_USE_MULTIPLE_GUNS))
|
||||
if(num_valid > 0 && !(tp->flags[Model::Subsystem_Flags::Use_multiple_guns]))
|
||||
break;
|
||||
|
||||
if(i < MAX_SHIP_PRIMARY_BANKS)
|
||||
@@ -2396,7 +2340,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
|
||||
//If this is a spawning type weapon, shoot it!
|
||||
//If 'smart spawn' just use it like normal weapons
|
||||
if ( (wip->wi_flags & WIF_SPAWN) && !(wip->wi_flags2 & WIF2_SMART_SPAWN) )
|
||||
if ( (wip->wi_flags[Weapon::Info_Flags::Spawn]) && !(wip->wi_flags[Weapon::Info_Flags::Smart_spawn]) )
|
||||
{
|
||||
if (( num_ships_nearby >= 3 ) || ((num_ships_nearby >= 2) && (frand() < 0.1f))) {
|
||||
turret_fire_weapon(i, ss, parent_objnum, &gpos, &ss->turret_last_fire_direction);
|
||||
@@ -2409,7 +2353,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
|
||||
|
||||
if(wip->wi_flags2 & WIF2_LOCAL_SSM)
|
||||
if(wip->wi_flags[Weapon::Info_Flags::Local_ssm])
|
||||
{
|
||||
weapon_firing_range=wip->lssm_lock_range;
|
||||
WeaponMinRange = 0.0f;
|
||||
@@ -2421,7 +2365,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
|
||||
|
||||
if (wip->wi_flags & WIF_BEAM) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Beam]) {
|
||||
if ( !((shipp->tag_left > 0) || (shipp->level2_tag_left > 0)) ) {
|
||||
if (Nebula_sec_range)
|
||||
{
|
||||
@@ -2439,7 +2383,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
{
|
||||
if( (dist_to_enemy <= weapon_firing_range) && (dist_to_enemy >= WeaponMinRange) )
|
||||
{
|
||||
if ( wip->wi_flags & WIF_HUGE ) {
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Huge] ) {
|
||||
if ( lep->type != OBJ_SHIP ) {
|
||||
continue;
|
||||
}
|
||||
@@ -2448,13 +2392,13 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
}
|
||||
|
||||
if ( wip->wi_flags2 & WIF2_SMALL_ONLY ) {
|
||||
if ( wip->wi_flags[Weapon::Info_Flags::Small_only] ) {
|
||||
if ( (lep->type == OBJ_SHIP) && (Ship_info[Ships[lep->instance].ship_info_index].is_big_or_huge()) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool tagged_only = ((wip->wi_flags2 & WIF2_TAGGED_ONLY) || (ss->weapons.flags & SW_FLAG_TAGGED_ONLY));
|
||||
bool tagged_only = ((wip->wi_flags[Weapon::Info_Flags::Tagged_only]) || (ss->weapons.flags[Ship::Weapon_Flags::Tagged_Only]));
|
||||
|
||||
if (lep->type == OBJ_SHIP) {
|
||||
// Check if we're targeting a protected ship
|
||||
@@ -2465,13 +2409,13 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
|
||||
// Check if we're targeting a beam protected ship with a beam weapon
|
||||
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags & WIF_BEAM) ) {
|
||||
if ( (lep->flags[Object::Object_Flags::Beam_protected]) && (wip->wi_flags[Weapon::Info_Flags::Beam]) ) {
|
||||
ss->turret_enemy_objnum = -1;
|
||||
ss->turret_time_enemy_in_range = 0.0f;
|
||||
continue;
|
||||
}
|
||||
// Check if we're targeting a flak protected ship with a flak weapon
|
||||
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags & WIF_FLAK) ) {
|
||||
else if ( (lep->flags[Object::Object_Flags::Flak_protected]) && (wip->wi_flags[Weapon::Info_Flags::Flak]) ) {
|
||||
ss->turret_enemy_objnum = -1;
|
||||
ss->turret_time_enemy_in_range = 0.0f;
|
||||
continue;
|
||||
@@ -2497,7 +2441,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
else
|
||||
{
|
||||
// check tagged-only for non-ship targets
|
||||
if (tagged_only && (!(lep->type == OBJ_WEAPON) || (The_mission.ai_profile->flags2 & AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING))) {
|
||||
if (tagged_only && (!(lep->type == OBJ_WEAPON) || (The_mission.ai_profile->flags[AI::Profile_Flags::Strict_turred_tagged_only_targeting]))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -2599,7 +2543,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
|
||||
// Do salvo thing separately - to prevent messing up things
|
||||
int number_of_firings;
|
||||
if (tp->flags & MSS_FLAG_TURRET_SALVO)
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_salvo])
|
||||
{
|
||||
number_of_firings = tp->turret_num_firing_points;
|
||||
ss->turret_next_fire_pos = 0;
|
||||
@@ -2611,7 +2555,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
|
||||
for(i = 0; i < number_of_firings; i++)
|
||||
{
|
||||
if (tp->flags & MSS_FLAG_TURRET_FIXED_FP)
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_fixed_fp])
|
||||
{
|
||||
int ffp_pos = 0;
|
||||
int ffp_bank;
|
||||
@@ -2637,7 +2581,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
dist_to_enemy = vm_vec_normalize(&v2e);
|
||||
dot = vm_vec_dot(&v2e, &gvec);
|
||||
|
||||
if (tp->flags & MSS_FLAG_TURRET_SALVO)
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_salvo])
|
||||
wip = get_turret_weapon_wip(&ss->weapons, valid_weapons[0]);
|
||||
else
|
||||
wip = get_turret_weapon_wip(&ss->weapons, valid_weapons[i]);
|
||||
@@ -2653,7 +2597,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
|
||||
// if the weapon is a flak gun, add some jitter to its aim so it fires in a "cone"
|
||||
// to make a cool visual effect and make them less lethal
|
||||
if(wip->wi_flags & WIF_FLAK){
|
||||
if(wip->wi_flags[Weapon::Info_Flags::Flak]){
|
||||
flak_jitter_aim(&tv2e, dist_to_enemy, ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS), wip);
|
||||
}
|
||||
|
||||
@@ -2664,11 +2608,11 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
//turret_weapon_class = tp->turret_weapon_type;
|
||||
bool in_sight = false;
|
||||
|
||||
if (The_mission.ai_profile->flags & AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS) {
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Use_only_single_fov_for_turrets]) {
|
||||
// we have already passed the FOV test of the turret so...
|
||||
in_sight = true;
|
||||
} else {
|
||||
if (wip->wi_flags & WIF_HOMING_HEAT) {
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Homing_heat]) {
|
||||
if (dot > AICODE_TURRET_HEATSEEK_ANGLE) {
|
||||
in_sight = true;
|
||||
}
|
||||
@@ -2679,7 +2623,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
}
|
||||
|
||||
if ( !(wip->wi_flags & WIF_HOMING) )
|
||||
if ( !(wip->is_homing()) )
|
||||
{
|
||||
if ((dist_to_enemy < 75.0f) || in_sight)
|
||||
{
|
||||
@@ -2687,7 +2631,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
ok_to_fire = true;
|
||||
}
|
||||
}
|
||||
else if ( wip->wi_flags & WIF_HOMING_HEAT )
|
||||
else if ( wip->wi_flags[Weapon::Info_Flags::Homing_heat] )
|
||||
{ // if heat seekers
|
||||
if ((dist_to_enemy < 50.0f) || in_sight)
|
||||
{
|
||||
@@ -2695,7 +2639,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
ok_to_fire = true;
|
||||
}
|
||||
}
|
||||
else if ( wip->wi_flags & WIF_HOMING_ASPECT )
|
||||
else if ( wip->wi_flags[Weapon::Info_Flags::Homing_aspect] )
|
||||
{ // if aspect seeker
|
||||
if ((dist_to_enemy < 50.0f) || in_sight)
|
||||
{
|
||||
@@ -2706,7 +2650,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
ok_to_fire = true;
|
||||
}
|
||||
}
|
||||
else if ( wip->wi_flags & WIF_HOMING_JAVELIN )
|
||||
else if ( wip->wi_flags[Weapon::Info_Flags::Homing_javelin] )
|
||||
{ // if javelin heat seeker
|
||||
if ((dist_to_enemy < 50.0f) || in_sight)
|
||||
{
|
||||
@@ -2721,7 +2665,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
}
|
||||
|
||||
if ( ok_to_fire && (tp->flags & MSS_FLAG_TURRET_HULL_CHECK) ) {
|
||||
if ( ok_to_fire && (tp->flags[Model::Subsystem_Flags::Turret_hull_check]) ) {
|
||||
int model_num = Ship_info[shipp->ship_info_index].model_num;
|
||||
vec3d end;
|
||||
vm_vec_scale_add(&end, &gpos, &gvec, model_get_radius(model_num));
|
||||
@@ -2752,7 +2696,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
}
|
||||
|
||||
//Wait until the animation is done to actually fire
|
||||
if (tp->flags & MSS_FLAG_TURRET_ANIM_WAIT && (ss->turret_animation_position != MA_POS_READY))
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_anim_wait] && (ss->turret_animation_position != MA_POS_READY))
|
||||
{
|
||||
ok_to_fire = false;
|
||||
}
|
||||
@@ -2764,13 +2708,13 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
Num_turrets_fired++;
|
||||
|
||||
//Pass along which gun we are using
|
||||
if (tp->flags & MSS_FLAG_TURRET_SALVO)
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_salvo])
|
||||
turret_fire_weapon(valid_weapons[0], ss, parent_objnum, &gpos, &tv2e, &predicted_enemy_pos);
|
||||
else
|
||||
turret_fire_weapon(valid_weapons[i], ss, parent_objnum, &gpos, &tv2e, &predicted_enemy_pos);
|
||||
} else {
|
||||
// make sure salvo fire mode does not turn into autofire
|
||||
if ((tp->flags & MSS_FLAG_TURRET_SALVO) && ((i + 1) == number_of_firings)) {
|
||||
if ((tp->flags[Model::Subsystem_Flags::Turret_salvo]) && ((i + 1) == number_of_firings)) {
|
||||
ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
|
||||
turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, parent_aip);
|
||||
}
|
||||
@@ -2790,7 +2734,7 @@ void ai_fire_from_turret(ship *shipp, ship_subsys *ss, int parent_objnum)
|
||||
|
||||
// If nothing is OK to fire (lost track of the target?)
|
||||
// reset the target (so we don't continue to track what we can't hit)
|
||||
if (tp->flags2 & MSS_FLAG2_TURRET_ONLY_TARGET_IF_CAN_FIRE)
|
||||
if (tp->flags[Model::Subsystem_Flags::Turret_only_target_if_can_fire])
|
||||
{
|
||||
ss->turret_enemy_objnum = -1; // Reset enemy objnum, find a new one next frame.
|
||||
ss->turret_time_enemy_in_range = 0.0f;
|
||||
@@ -2874,7 +2818,7 @@ bool turret_adv_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mo
|
||||
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
|
||||
{
|
||||
bool in_fov = false;
|
||||
if (ss->system_info->flags & MSS_FLAG_TURRET_ALT_MATH)
|
||||
if (ss->system_info->flags[Model::Subsystem_Flags::Turret_alt_math])
|
||||
in_fov = turret_adv_fov_test(ss, gvec, v2e, size_mod);
|
||||
else
|
||||
in_fov = turret_std_fov_test(ss, gvec, v2e, size_mod);
|
||||
|
||||
+17
-5
@@ -19,8 +19,8 @@
|
||||
#include "io/timer.h"
|
||||
#include "pcxutils/pcxutils.h"
|
||||
#include "render/3d.h"
|
||||
|
||||
|
||||
#include "graphics/material.h"
|
||||
#include "tracing/Monitor.h"
|
||||
|
||||
static color Color_xparent;
|
||||
|
||||
@@ -505,7 +505,10 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
|
||||
else {
|
||||
g3_rotate_vertex(&image_vertex,instance->world_pos);
|
||||
Assert(instance->radius != 0.0f);
|
||||
g3_draw_bitmap(&image_vertex, 0, instance->radius*1.5f, TMAP_FLAG_TEXTURED | TMAP_HTL_2D);
|
||||
//g3_draw_bitmap(&image_vertex, 0, instance->radius*1.5f, TMAP_FLAG_TEXTURED | TMAP_HTL_2D);
|
||||
material mat_params;
|
||||
material_set_unlit(&mat_params, bitmap_id, 1.0f, false, false);
|
||||
g3_render_rect_screen_aligned_2d(&mat_params, &image_vertex, 0, instance->radius*1.5f);
|
||||
}
|
||||
|
||||
instance->last_bitmap = bitmap_id;
|
||||
@@ -684,7 +687,7 @@ void anim_read_header(anim *ptr, CFILE *fp)
|
||||
* @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good.
|
||||
* @return Pointer to anim that is loaded if sucess, NULL if failure.
|
||||
*/
|
||||
anim *anim_load(char *real_filename, int cf_dir_type, int file_mapped)
|
||||
anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
|
||||
{
|
||||
anim *ptr;
|
||||
CFILE *fp;
|
||||
@@ -730,6 +733,10 @@ anim *anim_load(char *real_filename, int cf_dir_type, int file_mapped)
|
||||
|
||||
anim_read_header(ptr, fp);
|
||||
|
||||
if (ptr->width < 0 || ptr->height < 0) {
|
||||
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", name);
|
||||
}
|
||||
|
||||
if(ptr->num_keys > 0){
|
||||
ptr->keys = (key_frame*)vm_malloc(sizeof(key_frame) * ptr->num_keys);
|
||||
Assert(ptr->keys != NULL);
|
||||
@@ -758,7 +765,7 @@ anim *anim_load(char *real_filename, int cf_dir_type, int file_mapped)
|
||||
}
|
||||
|
||||
// couldn't memory-map file... must be in a packfile, so stream manually
|
||||
if ( file_mapped && !ptr->cfile_ptr ) {
|
||||
if ( file_mapped == PAGE_FROM_MEM && !ptr->cfile_ptr ) {
|
||||
ptr->flags &= ~ANF_MEM_MAPPED;
|
||||
ptr->flags |= ANF_STREAMED;
|
||||
ptr->cfile_ptr = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type);
|
||||
@@ -966,6 +973,11 @@ void anim_display_info(char *real_filename)
|
||||
}
|
||||
|
||||
anim_read_header(&A, fp);
|
||||
|
||||
if (A.width < 0 || A.height < 0) {
|
||||
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", filename);
|
||||
}
|
||||
|
||||
// read the keyframe frame nums and offsets
|
||||
key_frame_nums = (int*)vm_malloc(sizeof(int)*A.num_keys);
|
||||
Assert(key_frame_nums != NULL);
|
||||
|
||||
@@ -40,9 +40,8 @@ typedef struct {
|
||||
|
||||
enum
|
||||
{
|
||||
PAGE_FROM_MEM = 0,
|
||||
PAGE_FROM_DISK = 1,
|
||||
PAGE_FROM_DISK_FORCED = 2
|
||||
PAGE_FROM_DISK = 0,
|
||||
PAGE_FROM_MEM = 1
|
||||
};
|
||||
|
||||
extern int Anim_paused;
|
||||
@@ -59,7 +58,7 @@ int anim_stop_playing(anim_instance* anim_instance);
|
||||
int anim_show_next_frame(anim_instance *instance, float frametime);
|
||||
void anim_release_all_instances(int screen_id = 0);
|
||||
void anim_release_render_instance(anim_instance* instance);
|
||||
anim *anim_load(char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_MEM);
|
||||
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_DISK);
|
||||
int anim_free(anim *ptr);
|
||||
int anim_playing(anim_instance *ai);
|
||||
int anim_write_frames_out(char *filename);
|
||||
|
||||
@@ -512,7 +512,14 @@ int unpack_pixel(anim_instance *ai, ubyte *data, ubyte pix, int aabitmap, int bp
|
||||
bit_16 = (ushort)pix;
|
||||
break;
|
||||
case 8:
|
||||
bit_8 = pix;
|
||||
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
|
||||
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
|
||||
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
|
||||
if (pix >= 15) {
|
||||
bit_8 = 0;
|
||||
} else {
|
||||
bit_8 = (ubyte)(pix * 17);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Int3();
|
||||
@@ -596,7 +603,14 @@ int unpack_pixel_count(anim_instance *ai, ubyte *data, ubyte pix, int count = 0,
|
||||
bit_16 = (ushort)pix;
|
||||
break;
|
||||
case 8 :
|
||||
bit_8 = pix;
|
||||
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
|
||||
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
|
||||
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
|
||||
if (pix >= 15) {
|
||||
bit_8 = 0;
|
||||
} else {
|
||||
bit_8 = (ubyte)(pix * 17);
|
||||
}
|
||||
break;
|
||||
default :
|
||||
Int3();
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "fireball/fireballs.h"
|
||||
#include "freespace.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "globalincs/compatibility.h"
|
||||
#include "globalincs/linklist.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "hud/hud.h"
|
||||
@@ -33,7 +32,7 @@
|
||||
#include "object/objcollide.h"
|
||||
#include "object/object.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "parse/scripting.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "particle/particle.h"
|
||||
#include "render/3d.h"
|
||||
#include "ship/ship.h"
|
||||
@@ -1181,7 +1180,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
}
|
||||
}
|
||||
|
||||
void asteroid_render(object * obj, draw_list *scene)
|
||||
void asteroid_render(object * obj, model_draw_list *scene)
|
||||
{
|
||||
if (Asteroids_enabled) {
|
||||
int num;
|
||||
@@ -1313,7 +1312,7 @@ void asteriod_explode_sound(object *objp, int type, int play_loud)
|
||||
range_factor = 1.0f;
|
||||
}
|
||||
|
||||
snd_play_3d( &Snds[sound_index], &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
|
||||
snd_play_3d( gamesnd_get_game_sound(sound_index), &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1569,8 +1568,12 @@ void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
vec3d tempv = dir_vec;
|
||||
vm_vec_random_cone(&dir_vec, &tempv, (360.0f / total_roids / 2));
|
||||
|
||||
// Make the roid inherit half of the parent's velocity
|
||||
vm_vec_copy_normalize(&parent_vel, &pasteroid_obj->phys_info.vel);
|
||||
// Make the roid inherit half of parent's directional movement
|
||||
if (!IS_VEC_NULL(&pasteroid_obj->phys_info.vel)) {
|
||||
vm_vec_copy_normalize(&parent_vel, &pasteroid_obj->phys_info.vel);
|
||||
} else {
|
||||
vm_vec_rand_vec_quick(&parent_vel);
|
||||
}
|
||||
vm_vec_scale(&parent_vel, 0.5f);
|
||||
|
||||
// Make the hit position affect the direction, but only a little
|
||||
@@ -1917,7 +1920,7 @@ void asteroid_parse_tbl()
|
||||
char impact_ani_file[MAX_FILENAME_LEN];
|
||||
|
||||
// How did we get here without having any species defined?
|
||||
Assertion(Species_info.size() > 0,
|
||||
Assertion(!Species_info.empty(),
|
||||
"Cannot parse asteroids/debris if there "
|
||||
"are no species for them to belong to."
|
||||
);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
class object;
|
||||
class polymodel;
|
||||
struct collision_info_struct;
|
||||
class draw_list;
|
||||
class model_draw_list;
|
||||
|
||||
#define MAX_ASTEROIDS 512
|
||||
|
||||
@@ -152,7 +152,7 @@ void asteroid_init();
|
||||
void asteroid_level_init();
|
||||
void asteroid_level_close();
|
||||
void asteroid_create_all();
|
||||
void asteroid_render(object * obj, draw_list *scene);
|
||||
void asteroid_render(object * obj, model_draw_list *scene);
|
||||
void asteroid_delete( object *asteroid_objp );
|
||||
void asteroid_process_pre( object *asteroid_objp );
|
||||
void asteroid_process_post( object *asteroid_objp);
|
||||
|
||||
@@ -335,7 +335,7 @@ bool StartAutopilot()
|
||||
{
|
||||
if (Ships[i].objnum != -1 &&
|
||||
(Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry])
|
||||
)
|
||||
)
|
||||
{
|
||||
@@ -368,7 +368,7 @@ bool StartAutopilot()
|
||||
{
|
||||
if (Ships[i].objnum != -1 &&
|
||||
(Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry])
|
||||
)
|
||||
)
|
||||
{
|
||||
@@ -423,7 +423,7 @@ bool StartAutopilot()
|
||||
|
||||
// snap wings into formation
|
||||
if (The_mission.flags[Mission::Mission_Flags::Use_ap_cinematics] && // only if using cinematics
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) // only if in a wing
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry]) // only if in a wing
|
||||
&& Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
|
||||
{
|
||||
ai_info *aip = &Ai_info[Ships[i].ai_index];
|
||||
@@ -434,7 +434,7 @@ bool StartAutopilot()
|
||||
if (leader_objp != &Objects[Ships[i].objnum])
|
||||
{
|
||||
// not leader.. get our position relative to leader
|
||||
get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
|
||||
get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags[AI::AI_Flags::Formation_object]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -501,7 +501,7 @@ bool StartAutopilot()
|
||||
{
|
||||
for (i = 0; i < MAX_WINGS; i++)
|
||||
{
|
||||
if (Wings[i].flags & WF_NAV_CARRY )
|
||||
if (Wings[i].flags[Ship::Wing_Flags::Nav_carry] )
|
||||
{
|
||||
//ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );
|
||||
|
||||
@@ -540,7 +540,7 @@ bool StartAutopilot()
|
||||
if (Ships[i].objnum != -1)
|
||||
{
|
||||
if (Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY))
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry]))
|
||||
for (j = 0; j < MAX_AI_GOALS; j++)
|
||||
{
|
||||
if (Ai_info[Ships[i].ai_index].goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
|
||||
@@ -915,7 +915,7 @@ void EndAutoPilot()
|
||||
if (Ships[i].objnum != -1 &&
|
||||
(
|
||||
Ships[i].flags[Ship::Ship_Flags::Navpoint_carry] ||
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY )
|
||||
(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry] )
|
||||
)
|
||||
)
|
||||
{
|
||||
@@ -950,7 +950,7 @@ void EndAutoPilot()
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags = 0;
|
||||
aigp->flags.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -962,7 +962,7 @@ void EndAutoPilot()
|
||||
{
|
||||
for (i = 0; i < MAX_WINGS; i++)
|
||||
{
|
||||
if (Wings[i].flags & WF_NAV_CARRY )
|
||||
if (Wings[i].flags[Ship::Wing_Flags::Nav_carry] )
|
||||
{
|
||||
for (j = 0; j < MAX_AI_GOALS; j++)
|
||||
{
|
||||
@@ -974,7 +974,7 @@ void EndAutoPilot()
|
||||
aigp->ai_mode = AI_GOAL_NONE;
|
||||
aigp->signature = -1;
|
||||
aigp->priority = -1;
|
||||
aigp->flags = 0;
|
||||
aigp->flags.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1045,7 +1045,7 @@ void nav_warp(bool prewarp=false)
|
||||
{
|
||||
if (Ships[i].objnum != -1
|
||||
&& (Ships[i].flags[Ship::Ship_Flags::Navpoint_carry]
|
||||
|| (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)))
|
||||
|| (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags[Ship::Wing_Flags::Nav_carry])))
|
||||
{
|
||||
vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos);
|
||||
Objects[Ships[i].objnum].phys_info.vel = velocity;
|
||||
@@ -1272,7 +1272,7 @@ void NavSystem_Init()
|
||||
|
||||
// ********************************************************************************************
|
||||
|
||||
void parse_autopilot_table(char *filename)
|
||||
void parse_autopilot_table(const char *filename)
|
||||
{
|
||||
SCP_vector<SCP_string> lines;
|
||||
|
||||
@@ -1315,7 +1315,7 @@ void parse_autopilot_table(char *filename)
|
||||
Cmdline_autopilot_interruptable = 0;
|
||||
|
||||
// No Nav selected message
|
||||
char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
|
||||
const char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
|
||||
"$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:",
|
||||
"$Support Present:", "$Support Working:" };
|
||||
for (int i = 0; i < NP_NUM_MESSAGES; i++)
|
||||
|
||||
@@ -118,7 +118,7 @@ void NavSystem_Do();
|
||||
void NavSystem_Init();
|
||||
|
||||
// parse autopilot.tbl
|
||||
void parse_autopilot_table(char *filename);
|
||||
void parse_autopilot_table(const char *filename);
|
||||
|
||||
// Finds a Nav point by name
|
||||
int FindNav(char *Nav);
|
||||
|
||||
@@ -31,6 +31,7 @@ union bm_extra_info {
|
||||
int keyframe; //!< used for animations -- keyframe info
|
||||
float total_time; //!< used for animations -- total animation time (not always derived from num_frames/fps)
|
||||
ubyte fps; //!< used for animations -- frames per second
|
||||
bool is_array; //!< Flag for if all frames of an animation have the same size which means that it can be put into a texture array
|
||||
|
||||
struct {
|
||||
// stuff for static animations
|
||||
@@ -89,7 +90,7 @@ struct bitmap_entry {
|
||||
#endif
|
||||
};
|
||||
|
||||
extern bitmap_entry bm_bitmaps[MAX_BITMAPS];
|
||||
extern bitmap_entry* bm_bitmaps;
|
||||
|
||||
// image specific lock functions
|
||||
void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
|
||||
+144
-37
@@ -24,17 +24,19 @@
|
||||
#include "debugconsole/console.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/grinternal.h"
|
||||
#include "io/key.h"
|
||||
#include "io/timer.h"
|
||||
#include "jpgutils/jpgutils.h"
|
||||
#include "network/multiutil.h"
|
||||
#include "palman/palman.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "pcxutils/pcxutils.h"
|
||||
#include "pngutils/pngutils.h"
|
||||
#include "ship/ship.h"
|
||||
#include "tgautils/tgautils.h"
|
||||
#include "tracing/Monitor.h"
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
@@ -55,7 +57,6 @@ MONITOR(SizeBitmapPage)
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Definition of public variables (declared as extern in bmpman.h).
|
||||
int UNLITMAP = -1;
|
||||
int GLOWMAP = -1;
|
||||
int SPECMAP = -1;
|
||||
int SPECGLOSSMAP = -1;
|
||||
@@ -83,17 +84,19 @@ const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[
|
||||
void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
|
||||
void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
|
||||
|
||||
int MAX_BITMAPS = DEFAULT_MAX_BITMAPS;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Declaration of protected variables (defined in cmdline.cpp).
|
||||
extern int Cmdline_cache_bitmaps;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Definition of public variables (declared as extern in bm_internal.h).
|
||||
bitmap_entry bm_bitmaps[MAX_BITMAPS];
|
||||
bitmap_entry* bm_bitmaps = nullptr;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Definition of private variables at file scope (static).
|
||||
static int bm_inited = 0;
|
||||
static bool bm_inited = false;
|
||||
static uint Bm_next_signature = 0x1234;
|
||||
static int bm_next_handle = 1;
|
||||
static int Bm_low_mem = 0;
|
||||
@@ -419,7 +422,7 @@ DCF(bmpman, "Shows/changes bitmap caching parameters and usage") {
|
||||
}
|
||||
|
||||
if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
|
||||
dc_printf("Total RAM usage: %d bytes\n", bm_texture_ram);
|
||||
dc_printf("Total RAM usage: " SIZE_T_ARG " bytes\n", bm_texture_ram);
|
||||
|
||||
if (Bm_max_ram > 1024 * 1024) {
|
||||
dc_printf("\tMax RAM allowed: %.1f MB\n", i2fl(Bm_max_ram) / (1024.0f*1024.0f));
|
||||
@@ -435,14 +438,14 @@ DCF(bmpman, "Shows/changes bitmap caching parameters and usage") {
|
||||
|
||||
|
||||
if (dc_optional_string("flush")) {
|
||||
dc_printf("Total RAM usage before flush: %d bytes\n", bm_texture_ram);
|
||||
dc_printf("Total RAM usage before flush: " SIZE_T_ARG " bytes\n", bm_texture_ram);
|
||||
int i;
|
||||
for (i = 0; i < MAX_BITMAPS; i++) {
|
||||
if (bm_bitmaps[i].type != BM_TYPE_NONE) {
|
||||
bm_free_data(i);
|
||||
}
|
||||
}
|
||||
dc_printf("Total RAM after flush: %d bytes\n", bm_texture_ram);
|
||||
dc_printf("Total RAM after flush: " SIZE_T_ARG " bytes\n", bm_texture_ram);
|
||||
} else if (dc_optional_string("ram")) {
|
||||
dc_stuff_int(&Bm_max_ram);
|
||||
|
||||
@@ -480,7 +483,11 @@ void bm_close() {
|
||||
for (i = 0; i<MAX_BITMAPS; i++) {
|
||||
bm_free_data(i); // clears flags, bbp, data, etc
|
||||
}
|
||||
bm_inited = 0;
|
||||
if (bm_bitmaps != nullptr) {
|
||||
delete[] bm_bitmaps;
|
||||
bm_bitmaps = nullptr;
|
||||
}
|
||||
bm_inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +498,7 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
|
||||
Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
|
||||
}
|
||||
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int n = -1;
|
||||
|
||||
@@ -525,6 +532,7 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
|
||||
bm_bitmaps[n].bm.h = (short)h;
|
||||
bm_bitmaps[n].bm.rowsize = (short)w;
|
||||
bm_bitmaps[n].bm.bpp = (ubyte)bpp;
|
||||
bm_bitmaps[n].bm.true_bpp = (ubyte)bpp;
|
||||
bm_bitmaps[n].bm.flags = (ubyte)flags;
|
||||
bm_bitmaps[n].bm.data = 0;
|
||||
bm_bitmaps[n].bm.palette = NULL;
|
||||
@@ -870,7 +878,7 @@ int bm_get_info(int handle, int *w, int * h, ubyte * flags, int *nframes, int *f
|
||||
if (h) *h = bmp->h;
|
||||
if (flags) *flags = bmp->flags;
|
||||
|
||||
if (bm_is_anim(bitmapnum) == true) {
|
||||
if (bm_is_anim(bitmapnum)) {
|
||||
if (nframes) {
|
||||
*nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
|
||||
}
|
||||
@@ -941,7 +949,7 @@ void bm_get_palette(int handle, ubyte *pal, char *name) {
|
||||
}
|
||||
|
||||
uint bm_get_signature(int handle) {
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_signature().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
|
||||
@@ -966,7 +974,7 @@ int bm_get_tcache_type(int num) {
|
||||
}
|
||||
|
||||
BM_TYPE bm_get_type(int handle) {
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_type().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
|
||||
@@ -988,16 +996,17 @@ bool bm_has_alpha_channel(int handle) {
|
||||
}
|
||||
|
||||
void bm_init() {
|
||||
Assertion(!bm_inited, "bmpman cannot be initialized more than once!");
|
||||
|
||||
int i;
|
||||
|
||||
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", sizeof(bm_bitmaps) / 1024));
|
||||
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
|
||||
|
||||
if (!bm_inited) {
|
||||
bm_inited = 1;
|
||||
atexit(bm_close);
|
||||
if (bm_bitmaps == nullptr) {
|
||||
bm_bitmaps = new bitmap_entry[MAX_BITMAPS];
|
||||
}
|
||||
|
||||
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", (sizeof(bm_bitmaps[0]) * MAX_BITMAPS) / 1024));
|
||||
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
|
||||
|
||||
for (i = 0; i<MAX_BITMAPS; i++) {
|
||||
bm_bitmaps[i].filename[0] = '\0';
|
||||
bm_bitmaps[i].type = BM_TYPE_NONE;
|
||||
@@ -1021,6 +1030,8 @@ void bm_init() {
|
||||
|
||||
bm_free_data(i); // clears flags, bbp, data, etc
|
||||
}
|
||||
|
||||
bm_inited = true;
|
||||
}
|
||||
|
||||
int bm_is_compressed(int num) {
|
||||
@@ -1202,8 +1213,7 @@ int bm_load(const char *real_filename) {
|
||||
CFILE *img_cfp = NULL;
|
||||
int handle = -1;
|
||||
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// if no file was passed then get out now
|
||||
if ((real_filename == NULL) || (strlen(real_filename) <= 0))
|
||||
@@ -1508,8 +1518,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
size_t img_size = 0;
|
||||
char clean_name[MAX_FILENAME_LEN];
|
||||
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// set output param defaults before going any further
|
||||
if (nframes != nullptr)
|
||||
@@ -1618,6 +1627,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
#endif
|
||||
anim_read_header(&the_anim, img_cfp);
|
||||
|
||||
if (the_anim.width < 0 || the_anim.height < 0) {
|
||||
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", real_filename);
|
||||
}
|
||||
|
||||
anim_frames = the_anim.total_frames;
|
||||
anim_fps = the_anim.fps;
|
||||
if (anim_fps == 0) {
|
||||
@@ -1696,6 +1709,8 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
}
|
||||
|
||||
int first_handle = bm_get_next_handle();
|
||||
// if all images of the animation have the same size then we can use a texture array
|
||||
bool is_array = true;
|
||||
|
||||
for (i = 0; i < anim_frames; i++) {
|
||||
memset(&bm_bitmaps[n + i], 0, sizeof(bitmap_entry));
|
||||
@@ -1782,8 +1797,39 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
bm_bitmaps[n + i].info.ani.apng.is_apng = false;
|
||||
}
|
||||
|
||||
if (bm_bitmaps[n].bm.w != bm_bitmaps[n + i].bm.w || bm_bitmaps[n].bm.h != bm_bitmaps[n + i].bm.h) {
|
||||
// We found a frame with a different size than the first frame -> this can't be used as a texture array
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that are of different sizes (currently at frame %d)."
|
||||
"Performance could be improved by making all images the same size.", filename, i + 1);
|
||||
}
|
||||
if (bm_bitmaps[n].comp_type != bm_bitmaps[n + i].comp_type) {
|
||||
// Different compression type
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that are of different compression formats (currently at frame %d)."
|
||||
"Performance could be improved by making all images the same compression format.", filename, i + 1);
|
||||
}
|
||||
if (bm_bitmaps[n].bm.true_bpp != bm_bitmaps[n + i].bm.true_bpp) {
|
||||
// We found a frame with an incompatible pixel format
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that are of different pixel formats (currently at frame %d)."
|
||||
"Performance could be improved by making all images the same pixel format.", filename, i + 1);
|
||||
}
|
||||
if (bm_bitmaps[n].num_mipmaps != bm_bitmaps[n + i].num_mipmaps) {
|
||||
// We found a frame with a different number of mipmaps
|
||||
is_array = false;
|
||||
|
||||
Warning(LOCATION, "Animation '%s' has images that have a different number of mipmaps (currently at frame %d)."
|
||||
"Performance could be improved by giving all frames the same number of mipmaps.", filename, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Set array flag of first frame
|
||||
bm_bitmaps[n].info.ani.is_array = is_array;
|
||||
|
||||
if (nframes != nullptr)
|
||||
*nframes = anim_frames;
|
||||
|
||||
@@ -1892,7 +1938,7 @@ bitmap * bm_lock(int handle, int bpp, ubyte flags, bool nodebug) {
|
||||
bitmap *bmp;
|
||||
bitmap_entry *be;
|
||||
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
|
||||
@@ -2158,7 +2204,7 @@ void bm_lock_apng(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int
|
||||
cumulative_frame_delay += the_apng->frame.delay;
|
||||
be->info.ani.apng.frame_delay = cumulative_frame_delay;
|
||||
|
||||
nprintf(("apng", "locking apng frame: %s (%i|%i|%i) (%f) %lu\n", be->filename, bpp, bmp->bpp, bm->true_bpp, be->info.ani.apng.frame_delay, be->mem_taken));
|
||||
nprintf(("apng", "locking apng frame: %s (%i|%i|%i) (%f) " SIZE_T_ARG "\n", be->filename, bpp, bmp->bpp, bm->true_bpp, be->info.ani.apng.frame_delay, be->mem_taken));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2234,6 +2280,9 @@ void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
|
||||
// Unload any existing data
|
||||
bm_free_data(bitmapnum);
|
||||
|
||||
// JPEG actually only support 24 bits per pixel so we enforce that here
|
||||
bpp = 24;
|
||||
|
||||
d_size = (bpp >> 3);
|
||||
|
||||
// allocate bitmap data
|
||||
@@ -2279,7 +2328,7 @@ void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
|
||||
data = (ubyte *)bm_malloc(bitmapnum, be->mem_taken);
|
||||
bmp->bpp = bpp;
|
||||
bmp->data = (ptr_u)data;
|
||||
bmp->palette = (bpp == 8) ? gr_palette : NULL;
|
||||
bmp->palette = NULL;
|
||||
memset(data, 0, be->mem_taken);
|
||||
|
||||
Assert(&be->bm == bmp);
|
||||
@@ -2294,7 +2343,7 @@ void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
|
||||
// this will populate filename[] whether it's EFF or not
|
||||
EFF_FILENAME_CHECK;
|
||||
|
||||
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), 0, be->dir_type);
|
||||
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), (flags & BMP_MASK_BITMAP) != 0, be->dir_type);
|
||||
|
||||
if (pcx_error != PCX_ERROR_NONE) {
|
||||
mprintf(("Couldn't load PCX!!! (%s)\n", filename));
|
||||
@@ -2373,7 +2422,7 @@ void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
|
||||
Assert(byte_size);
|
||||
Assert(be->mem_taken > 0);
|
||||
|
||||
data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
|
||||
data = (ubyte*)bm_malloc(bitmapnum, static_cast<size_t>(bmp->w * bmp->h * byte_size));
|
||||
|
||||
if (data) {
|
||||
memset(data, 0, be->mem_taken);
|
||||
@@ -2458,8 +2507,7 @@ int bm_make_render_target(int width, int height, int flags) {
|
||||
int bpp = 32;
|
||||
int size = 0;
|
||||
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// Find an open slot (starting from the end)
|
||||
for (n = -1, i = MAX_BITMAPS - 1; i >= 0; i--) {
|
||||
@@ -2577,6 +2625,8 @@ void bm_page_in_start() {
|
||||
}
|
||||
|
||||
void bm_page_in_stop() {
|
||||
TRACE_SCOPE(tracing::PageInStop);
|
||||
|
||||
int i;
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -2593,6 +2643,7 @@ void bm_page_in_stop() {
|
||||
for (i = 0; i < MAX_BITMAPS; i++) {
|
||||
if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_DYNAMIC) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_STATIC)) {
|
||||
if (bm_bitmaps[i].preloaded) {
|
||||
TRACE_SCOPE(tracing::PageInSingleBitmap);
|
||||
if (bm_preloading) {
|
||||
if (!gr_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded == 2))) {
|
||||
mprintf(("Out of VRAM. Done preloading.\n"));
|
||||
@@ -2829,12 +2880,16 @@ int bm_release(int handle, int clear_render_targets) {
|
||||
}
|
||||
|
||||
// be sure that all frames of an ani are unloaded - taylor
|
||||
if (bm_is_anim(n) == true) {
|
||||
if (bm_is_anim(n)) {
|
||||
int i, first = be->info.ani.first_frame, total = bm_bitmaps[first].info.ani.num_frames;
|
||||
|
||||
// The graphics system requires that the bitmap information for the whole animation is still valid when the data
|
||||
// is freed so we first free all the data and then clear the bitmaps data
|
||||
for (i = 0; i < total; i++) {
|
||||
bm_free_data(first + i, true); // clears flags, bbp, data, etc
|
||||
}
|
||||
|
||||
for (i = 0; i < total; i++) {
|
||||
memset(&bm_bitmaps[first + i], 0, sizeof(bitmap_entry));
|
||||
|
||||
bm_bitmaps[first + i].type = BM_TYPE_NONE;
|
||||
@@ -2883,8 +2938,7 @@ int bm_release(int handle, int clear_render_targets) {
|
||||
}
|
||||
|
||||
int bm_reload(int bitmap_handle, const char* filename) {
|
||||
if (!bm_inited)
|
||||
bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
// if no file was passed then get out now
|
||||
if ((filename == NULL) || (strlen(filename) <= 0))
|
||||
@@ -2994,6 +3048,8 @@ void bm_set_low_mem(int mode) {
|
||||
}
|
||||
|
||||
bool bm_set_render_target(int handle, int face) {
|
||||
GR_DEBUG_SCOPE("Set render target");
|
||||
|
||||
int n = handle % MAX_BITMAPS;
|
||||
|
||||
if (n >= 0) {
|
||||
@@ -3062,10 +3118,7 @@ bool bm_set_render_target(int handle, int face) {
|
||||
|
||||
gr_reset_clip();
|
||||
|
||||
if (gr_screen.mode == GR_OPENGL) {
|
||||
extern void opengl_setup_viewport();
|
||||
opengl_setup_viewport();
|
||||
}
|
||||
gr_setup_viewport();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3077,6 +3130,10 @@ int bm_unload(int handle, int clear_render_targets, bool nodebug) {
|
||||
bitmap_entry *be;
|
||||
bitmap *bmp;
|
||||
|
||||
if (handle == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int n = handle % MAX_BITMAPS;
|
||||
|
||||
Assert((n >= 0) && (n < MAX_BITMAPS));
|
||||
@@ -3191,7 +3248,7 @@ int bm_unload_fast(int handle, int clear_render_targets) {
|
||||
void bm_unlock(int handle) {
|
||||
bitmap_entry *be;
|
||||
|
||||
if (!bm_inited) bm_init();
|
||||
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
|
||||
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
|
||||
@@ -3247,3 +3304,53 @@ int find_block_of(int n)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool bm_is_texture_array(const int handle) {
|
||||
int bitmapnum = handle % MAX_BITMAPS;
|
||||
|
||||
if (!bm_is_anim(bitmapnum)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This will return the index of the first animation frame
|
||||
int n = bm_get_cache_slot(handle, 0);
|
||||
bitmap_entry *be = &bm_bitmaps[n];
|
||||
|
||||
return be->info.ani.is_array;
|
||||
}
|
||||
|
||||
int bm_get_base_frame(const int handle, int* num_frames) {
|
||||
// If the bitmap is no animation then num_frames will still be at least 1
|
||||
auto animation_begin = bm_get_info(handle, nullptr, nullptr, nullptr, num_frames);
|
||||
|
||||
if (animation_begin < 0) {
|
||||
// Some kind of error
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!bm_is_texture_array(animation_begin)) {
|
||||
// If this is not a texture array then we just treat it like a single frame animation
|
||||
animation_begin = handle;
|
||||
if (num_frames != nullptr) {
|
||||
*num_frames = 1;
|
||||
}
|
||||
}
|
||||
return animation_begin;
|
||||
}
|
||||
int bm_get_array_index(const int handle) {
|
||||
return handle - bm_get_base_frame(handle, nullptr);
|
||||
}
|
||||
|
||||
int bmpman_count_bitmaps() {
|
||||
if (!bm_inited)
|
||||
return -1;
|
||||
|
||||
int total_bitmaps = 0;
|
||||
for (int i = 0; i < MAX_BITMAPS; i++) {
|
||||
if (bm_bitmaps[i].type != BM_TYPE_NONE) {
|
||||
total_bitmaps++;
|
||||
}
|
||||
}
|
||||
|
||||
return total_bitmaps;
|
||||
}
|
||||
+45
-2
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief How many bitmaps the game can handle
|
||||
* @brief How many bitmaps the game can handle by default
|
||||
*
|
||||
* @attention MAX_BITMAPS shouldn't need to be bumped again. With the fixed bm_release() and it's proper use even the
|
||||
* largest missions should stay under this number. With the largest retail missions and wasteful content we should
|
||||
@@ -45,7 +45,9 @@
|
||||
* If anything we could/should reduce MAX_BITMAPS in the future. Where it's at now should accomidate even the
|
||||
* largest mods. -- Taylor
|
||||
*/
|
||||
#define MAX_BITMAPS 4750
|
||||
#define DEFAULT_MAX_BITMAPS 4750
|
||||
|
||||
extern int MAX_BITMAPS;
|
||||
|
||||
// Flag positions for bitmap.flags
|
||||
// ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ******
|
||||
@@ -56,6 +58,7 @@
|
||||
#define BMP_TEX_DXT3 (1<<4) //!< dxt3 compressed 8r8g8b4a (32bit)
|
||||
#define BMP_TEX_DXT5 (1<<5) //!< dxt5 compressed 8r8g8b8a (32bit)
|
||||
#define BMP_TEX_CUBEMAP (1<<6) //!< a texture made for cubic environment map
|
||||
#define BMP_MASK_BITMAP (1<<7) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations
|
||||
|
||||
// Combined flags
|
||||
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 ) //!< Compressed textures
|
||||
@@ -698,4 +701,44 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
|
||||
*/
|
||||
int bm_get_anim_frame(const int frame1_handle, float elapsed_time, const float divisor = 0.0f, const bool loop = false);
|
||||
|
||||
/**
|
||||
* @brief Determines if the given handle could be used in a texture array
|
||||
*
|
||||
* @param handle The handle to query the value for
|
||||
* @return @c true if all frames have the same size, @c false otherwise. Always returns @c true for single images
|
||||
*/
|
||||
bool bm_is_texture_array(const int handle);
|
||||
|
||||
/**
|
||||
* @brief Gets the base frame of the specified animation
|
||||
*
|
||||
* @details The base frame is the frame of the animation that should be used to determine if two animation frames can be
|
||||
* used in the same draw call. Use this if you want to optimize your draw calls to make use of texture arrays.
|
||||
*
|
||||
* @param handle The handle of the animation to check. This may also be a single frame bitmap
|
||||
* @param num_frames Optionally return the number of frames in the animation
|
||||
* @return The bitmap handle of the base frame or -1 on error
|
||||
*/
|
||||
int bm_get_base_frame(const int handle, int* num_frames = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Get the array index of the specified bitmap
|
||||
*
|
||||
* This should be used when passing the array index to the GPU (e.g. when building uniform structs or streaming particle
|
||||
* data)
|
||||
*
|
||||
* @param handle The handle of the bitmap
|
||||
* @return The index into the array
|
||||
*/
|
||||
int bm_get_array_index(const int handle);
|
||||
|
||||
/**
|
||||
* @brief Counts how many slots are used in bm_bitmaps
|
||||
*
|
||||
* This needs to iterate through all the slots in order to determine whether or not they're used, so shouldn't be used frivolously.
|
||||
*
|
||||
* @return The number of used slots
|
||||
*/
|
||||
int bmpman_count_bitmaps();
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "globalincs/linklist.h"
|
||||
#include "globalincs/systemvars.h" //VM_FREECAMERA etc
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "hud/hud.h" //hud_get_draw
|
||||
#include "math/vecmat.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
@@ -26,7 +26,7 @@ camid Main_camera;
|
||||
|
||||
//*************************CLASS: camera*************************
|
||||
//This is where the camera class beings! :D
|
||||
camera::camera(char *in_name, int in_signature)
|
||||
camera::camera(const char *in_name, int in_signature)
|
||||
{
|
||||
set_name(in_name);
|
||||
sig = in_signature;
|
||||
@@ -78,7 +78,7 @@ void camera::reset()
|
||||
}
|
||||
}
|
||||
|
||||
void camera::set_name(char *in_name)
|
||||
void camera::set_name(const char *in_name)
|
||||
{
|
||||
if(in_name != NULL)
|
||||
strncpy(name, in_name, NAME_LENGTH-1);
|
||||
@@ -885,14 +885,14 @@ int cam_get_next_sig()
|
||||
return next_sig++;
|
||||
}
|
||||
|
||||
camid cam_create(char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
|
||||
{
|
||||
matrix ori;
|
||||
vm_vector_2_matrix_norm(&ori, n_norm);
|
||||
return cam_create(n_name, n_pos, &ori, n_object, n_object_host_submodel);
|
||||
}
|
||||
|
||||
camid cam_create(char *n_name, vec3d *n_pos, matrix *n_ori, object *n_object, int n_object_host_submodel)
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, matrix *n_ori, object *n_object, int n_object_host_submodel)
|
||||
{
|
||||
camera *cam = NULL;
|
||||
camid cid;
|
||||
|
||||
@@ -43,13 +43,13 @@ protected:
|
||||
vec3d c_pos;
|
||||
matrix c_ori;
|
||||
public:
|
||||
camera(char *in_name=NULL, int in_signature=-1);
|
||||
camera(const char *in_name=NULL, int in_signature=-1);
|
||||
~camera();
|
||||
void clear();
|
||||
void reset();
|
||||
|
||||
//Set
|
||||
void set_name(char *in_name);
|
||||
void set_name(const char *in_name);
|
||||
|
||||
void set_object_host(object *objp, int n_object_host_submodel = -1);
|
||||
void set_object_target(object *objp, int n_object_target_submodel = -1);
|
||||
@@ -158,8 +158,8 @@ extern float Sexp_fov;
|
||||
void cam_init();
|
||||
void cam_close();
|
||||
void cam_do_frame(float frametime);
|
||||
camid cam_create(char *n_name=NULL, vec3d *n_pos=NULL, matrix *n_ori=NULL, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
camid cam_create(char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
camid cam_create(const char *n_name=NULL, vec3d *n_pos=NULL, matrix *n_ori=NULL, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object=NULL, int n_submodel_parent=-1);
|
||||
void cam_delete(camid cid);
|
||||
bool cam_set_camera(camid cid);
|
||||
void cam_reset_camera();
|
||||
|
||||
+13
-10
@@ -14,6 +14,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@@ -23,7 +24,6 @@
|
||||
#endif
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
#include <sys/stat.h>
|
||||
#include <glob.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
@@ -69,7 +69,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_VOICE_SPECIAL, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "special", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf", CF_TYPE_DATA },
|
||||
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
|
||||
@@ -82,12 +82,13 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
|
||||
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .dds .fs2 .txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA },
|
||||
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
|
||||
};
|
||||
|
||||
|
||||
@@ -128,12 +129,14 @@ static void dump_opened_files()
|
||||
}
|
||||
}
|
||||
|
||||
static void cfile_close()
|
||||
void cfile_close()
|
||||
{
|
||||
mprintf(("Still opened files:\n"));
|
||||
dump_opened_files();
|
||||
|
||||
cf_free_secondary_filelist();
|
||||
|
||||
cfile_inited = 0;
|
||||
}
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
@@ -239,8 +242,6 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
|
||||
Cfile_cdrom_dir = cdrom_dir;
|
||||
cf_build_secondary_filelist(Cfile_cdrom_dir);
|
||||
|
||||
atexit(cfile_close);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -608,7 +609,7 @@ static void mkdir_recursive(const char *path) {
|
||||
while ((pos = tmp.find_first_of(DIR_SEPARATOR_CHAR, pre)) != std::string::npos) {
|
||||
dir = tmp.substr(0, pos++);
|
||||
pre = pos;
|
||||
if (dir.size() == 0) continue; // if leading / first time is 0 length
|
||||
if (dir.empty()) continue; // if leading / first time is 0 length
|
||||
|
||||
_mkdir(dir.c_str());
|
||||
}
|
||||
@@ -621,6 +622,7 @@ void cf_create_directory( int dir_type )
|
||||
int num_dirs = 0;
|
||||
int dir_tree[CF_MAX_PATH_TYPES];
|
||||
char longname[MAX_PATH_LEN];
|
||||
struct stat statbuf;
|
||||
|
||||
Assertion( CF_TYPE_SPECIFIED(dir_type), "Invalid dir_type passed to cf_create_directory." );
|
||||
|
||||
@@ -634,13 +636,14 @@ void cf_create_directory( int dir_type )
|
||||
|
||||
} while( current_dir != CF_TYPE_ROOT );
|
||||
|
||||
|
||||
int i;
|
||||
|
||||
for (i=num_dirs-1; i>=0; i-- ) {
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, dir_tree[i], NULL );
|
||||
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
|
||||
mkdir_recursive(longname);
|
||||
if (stat(longname, &statbuf) != 0) {
|
||||
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
|
||||
mkdir_recursive(longname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -78,8 +78,9 @@ typedef struct {
|
||||
#define CF_TYPE_INTEL_ANIMS 34
|
||||
#define CF_TYPE_SCRIPTS 35
|
||||
#define CF_TYPE_FICTION 36
|
||||
#define CF_TYPE_FREDDOCS 37
|
||||
|
||||
#define CF_MAX_PATH_TYPES 37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
#define CF_MAX_PATH_TYPES 38 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
|
||||
|
||||
|
||||
// TRUE if type is specified and valid
|
||||
@@ -116,6 +117,7 @@ extern char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN];
|
||||
|
||||
//================= LOW-LEVEL FUNCTIONS ==================
|
||||
int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
|
||||
void cfile_close();
|
||||
|
||||
// Call this if pack files got added or removed or the
|
||||
// cdrom changed. This will refresh the list of filenames
|
||||
|
||||
@@ -161,10 +161,15 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
default:
|
||||
Int3();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't seek beyond the end of the file
|
||||
CAP(goal_position, cb->lib_offset, cb->lib_offset + cb->size);
|
||||
|
||||
int result = fseek(cb->fp, (long)goal_position, SEEK_SET );
|
||||
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
|
||||
cb->raw_position = goal_position - cb->lib_offset;
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
@@ -200,6 +205,7 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
}
|
||||
|
||||
if ( (cb->raw_position+size) > cb->size ) {
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
size = cb->size - cb->raw_position;
|
||||
if ( size < 1 ) {
|
||||
return 0;
|
||||
@@ -219,6 +225,7 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
size_t bytes_read = fread( buf, 1, size, cb->fp );
|
||||
if ( bytes_read > 0 ) {
|
||||
cb->raw_position += bytes_read;
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
}
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
@@ -249,7 +256,8 @@ int cfread_lua_number(double *buf, CFILE *cfile)
|
||||
|
||||
long orig_pos = ftell(cb->fp);
|
||||
int items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
|
||||
cb->raw_position += ftell(cb->fp)-orig_pos;
|
||||
cb->raw_position += ftell(cb->fp)-orig_pos;
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
|
||||
+171
-69
@@ -30,6 +30,7 @@
|
||||
#include <fnmatch.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
@@ -38,12 +39,13 @@
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "localization/localize.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "parse/parselo.h"
|
||||
|
||||
#define CF_ROOTTYPE_PATH 0
|
||||
#define CF_ROOTTYPE_PACK 1
|
||||
|
||||
// for a defined and specifically set location to get/send pilot/campaign files
|
||||
char *Pilot_file_path = NULL;
|
||||
SCP_string Pilot_file_path;
|
||||
|
||||
// Created by:
|
||||
// specifying hard drive tree
|
||||
@@ -77,12 +79,13 @@ static int Num_path_roots = 0;
|
||||
|
||||
// Created by searching all roots in order. This means Files is then sorted by precedence.
|
||||
typedef struct cf_file {
|
||||
char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
|
||||
int root_index; // Where in Roots this is located
|
||||
int pathtype_index; // Where in Paths this is located
|
||||
time_t write_time; // When it was last written
|
||||
int size; // How big it is in bytes
|
||||
int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
|
||||
char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
|
||||
int root_index; // Where in Roots this is located
|
||||
int pathtype_index; // Where in Paths this is located
|
||||
time_t write_time; // When it was last written
|
||||
int size; // How big it is in bytes
|
||||
int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
|
||||
char* real_name; // For real files, the full path
|
||||
} cf_file;
|
||||
|
||||
#define CF_NUM_FILES_PER_BLOCK 512
|
||||
@@ -115,6 +118,7 @@ cf_file *cf_create_file()
|
||||
if ( File_blocks[block] == NULL ) {
|
||||
File_blocks[block] = (cf_file_block *)vm_malloc( sizeof(cf_file_block) );
|
||||
Assert( File_blocks[block] != NULL);
|
||||
memset(File_blocks[block], 0, sizeof(cf_file_block));
|
||||
}
|
||||
|
||||
Num_files++;
|
||||
@@ -428,7 +432,7 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
|
||||
// If it wasn't set before, set the pilot path
|
||||
if (Pilot_file_path == NULL)
|
||||
if (Pilot_file_path.empty())
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
@@ -455,7 +459,7 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
|
||||
// set the default player location to here
|
||||
if (Pilot_file_path == NULL)
|
||||
if (Pilot_file_path.empty())
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
@@ -485,7 +489,7 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
|
||||
// If the path wasn't set before use the working directory
|
||||
if ( Pilot_file_path == NULL )
|
||||
if ( Pilot_file_path.empty() )
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
//======================================================
|
||||
@@ -534,6 +538,10 @@ void cf_search_root_path(int root_index)
|
||||
mprintf(( "Searching root '%s' ... ", root->path ));
|
||||
|
||||
char search_path[CF_MAX_PATHNAME_LENGTH];
|
||||
#ifdef SCP_UNIX
|
||||
// This map stores the mapping between a specific path type and the actual path that we use for it
|
||||
SCP_unordered_map<int, SCP_string> pathTypeToRealPath;
|
||||
#endif
|
||||
|
||||
for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ ) {
|
||||
|
||||
@@ -552,6 +560,7 @@ void cf_search_root_path(int root_index)
|
||||
}
|
||||
|
||||
#if defined _WIN32
|
||||
SCP_string search_directory = search_path;
|
||||
strcat_s( search_path, "*.*" );
|
||||
|
||||
intptr_t find_handle;
|
||||
@@ -576,6 +585,11 @@ void cf_search_root_path(int root_index)
|
||||
file->size = find.size;
|
||||
file->pack_offset = 0; // Mark as a non-packed file
|
||||
|
||||
SCP_string file_name;
|
||||
sprintf(file_name, "%s%s%s", search_directory.c_str(), DIR_SEPARATOR_STR, find.name);
|
||||
|
||||
file->real_name = vm_strdup(file_name.c_str());
|
||||
|
||||
num_files++;
|
||||
//mprintf(( "Found file '%s'\n", file->name_ext ));
|
||||
}
|
||||
@@ -588,21 +602,80 @@ void cf_search_root_path(int root_index)
|
||||
_findclose( find_handle );
|
||||
}
|
||||
#elif defined SCP_UNIX
|
||||
DIR *dirp;
|
||||
struct dirent *dir;
|
||||
DIR *dirp = nullptr;
|
||||
SCP_string search_dir;
|
||||
{
|
||||
if (i == CF_TYPE_ROOT) {
|
||||
// Don't search for the same name for the root case since we would be searching in other mod directories in that case
|
||||
dirp = opendir (search_path);
|
||||
search_dir.assign(search_path);
|
||||
} else {
|
||||
// On Unix we can have a different case for the search paths so we also need to account for that
|
||||
// We do that by looking at the parent of search_path and enumerating all directories and the check if any of
|
||||
// them are a case-insensitive match
|
||||
SCP_string directory_name;
|
||||
|
||||
auto parentPathIter = pathTypeToRealPath.find(Pathtypes[i].parent_index);
|
||||
|
||||
if (parentPathIter == pathTypeToRealPath.end()) {
|
||||
// No parent known yet, use the standard dirname
|
||||
char dirname_copy[CF_MAX_PATHNAME_LENGTH];
|
||||
memcpy(dirname_copy, search_path, sizeof(search_path));
|
||||
// According to the documentation of directory_name and basename, the return value does not need to be freed
|
||||
directory_name.assign(dirname(dirname_copy));
|
||||
} else {
|
||||
// we have a valid parent path -> use that
|
||||
directory_name = parentPathIter->second;
|
||||
}
|
||||
|
||||
char basename_copy[CF_MAX_PATHNAME_LENGTH];
|
||||
memcpy(basename_copy, search_path, sizeof(search_path));
|
||||
// According to the documentation of dirname and basename, the return value does not need to be freed
|
||||
auto search_name = basename(basename_copy);
|
||||
|
||||
auto parentDirP = opendir(directory_name.c_str());
|
||||
|
||||
if (parentDirP) {
|
||||
struct dirent *dir = nullptr;
|
||||
while ((dir = readdir (parentDirP)) != nullptr) {
|
||||
|
||||
if (stricmp(search_name, dir->d_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SCP_string fn;
|
||||
sprintf(fn, "%s/%s", directory_name.c_str(), dir->d_name);
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn.c_str(), &buf) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
// Found a case insensitive match
|
||||
dirp = opendir(fn.c_str());
|
||||
search_dir = fn;
|
||||
// We also need to store this in our mapping since we may need it in the future
|
||||
pathTypeToRealPath.insert(std::make_pair(i, fn));
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(parentDirP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dirp = opendir (search_path);
|
||||
if ( dirp ) {
|
||||
struct dirent *dir = nullptr;
|
||||
while ((dir = readdir (dirp)) != NULL)
|
||||
{
|
||||
if (!fnmatch ("*.*", dir->d_name, 0))
|
||||
{
|
||||
char fn[MAX_PATH];
|
||||
snprintf(fn, MAX_PATH-1, "%s%s", search_path, dir->d_name);
|
||||
fn[MAX_PATH-1] = 0;
|
||||
SCP_string fn;
|
||||
sprintf(fn, "%s/%s", search_dir.c_str(), dir->d_name);
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn, &buf) == -1) {
|
||||
if (stat(fn.c_str(), &buf) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -626,6 +699,8 @@ void cf_search_root_path(int root_index)
|
||||
|
||||
file->pack_offset = 0; // Mark as a non-packed file
|
||||
|
||||
file->real_name = vm_strdup(fn.c_str());
|
||||
|
||||
num_files++;
|
||||
//mprintf(( "Found file '%s'\n", file->name_ext ));
|
||||
}
|
||||
@@ -827,6 +902,14 @@ void cf_free_secondary_filelist()
|
||||
// Init the file blocks
|
||||
for (i=0; i<CF_MAX_FILE_BLOCKS; i++ ) {
|
||||
if ( File_blocks[i] ) {
|
||||
// Free file paths
|
||||
for (auto& f : File_blocks[i]->files) {
|
||||
if (f.real_name) {
|
||||
vm_free(f.real_name);
|
||||
f.real_name = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
vm_free( File_blocks[i] );
|
||||
File_blocks[i] = NULL;
|
||||
}
|
||||
@@ -985,17 +1068,14 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
*offset = (size_t)f->pack_offset;
|
||||
|
||||
if (pack_filename) {
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
|
||||
if (f->pack_offset < 1) {
|
||||
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
|
||||
// This is a real file, return the actual file path
|
||||
strncpy( pack_filename, f->real_name, max_out );
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
|
||||
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
|
||||
|
||||
strcat_s( pack_filename, max_out, f->name_ext );
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,19 +1093,14 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
*offset = (size_t)f->pack_offset;
|
||||
|
||||
if (pack_filename) {
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strcpy( pack_filename, r->path );
|
||||
|
||||
if (f->pack_offset < 1) {
|
||||
if ( strlen(Pathtypes[f->pathtype_index].path) ) {
|
||||
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
|
||||
// This is a real file, return the actual file path
|
||||
strncpy( pack_filename, f->real_name, max_out );
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
|
||||
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
|
||||
}
|
||||
|
||||
strcat_s( pack_filename, max_out, f->name_ext );
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1260,17 +1335,14 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
*offset = f->pack_offset;
|
||||
|
||||
if (pack_filename) {
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
|
||||
if (f->pack_offset < 1) {
|
||||
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
|
||||
// This is a real file, return the actual file path
|
||||
strncpy( pack_filename, f->real_name, max_out );
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
|
||||
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
|
||||
|
||||
strcat_s( pack_filename, max_out, f->name_ext );
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,20 +1363,14 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
*offset = f->pack_offset;
|
||||
|
||||
if (pack_filename) {
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strcpy( pack_filename, r->path );
|
||||
|
||||
if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
strncpy( pack_filename, f->real_name, max_out );
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if ( strlen(Pathtypes[f->pathtype_index].path) ) {
|
||||
strcat_s( pack_filename, max_out, Pathtypes[f->pathtype_index].path );
|
||||
|
||||
if ( pack_filename[strlen(pack_filename)-1] != DIR_SEPARATOR_CHAR )
|
||||
strcat_s( pack_filename, max_out, DIR_SEPARATOR_STR );
|
||||
}
|
||||
|
||||
strcat_s( pack_filename, max_out, f->name_ext );
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1501,8 +1567,10 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
continue;
|
||||
|
||||
char fn[MAX_PATH];
|
||||
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
|
||||
fn[MAX_PATH-1] = 0;
|
||||
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
|
||||
// Make sure the string is null terminated
|
||||
fn[MAX_PATH-1] = 0;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn, &buf) == -1) {
|
||||
@@ -1537,8 +1605,7 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
}
|
||||
#endif
|
||||
|
||||
bool skip_packfiles = (Skip_packfile_search != 0);
|
||||
|
||||
bool skip_packfiles = false;
|
||||
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
|
||||
skip_packfiles = true;
|
||||
} else if (Get_file_list_child != NULL) {
|
||||
@@ -1563,6 +1630,11 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip_packfile_search && f->pack_offset != 0) {
|
||||
// If the packfile skip flag is set we skip files in VPs but still search in directories
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
|
||||
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
|
||||
|
||||
@@ -1706,8 +1778,10 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
continue;
|
||||
|
||||
char fn[MAX_PATH];
|
||||
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
|
||||
fn[MAX_PATH-1] = 0;
|
||||
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
|
||||
// Make sure the string is null terminated
|
||||
fn[MAX_PATH-1] = 0;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn, &buf) == -1) {
|
||||
@@ -1739,8 +1813,16 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
}
|
||||
#endif
|
||||
|
||||
bool skip_packfiles = false;
|
||||
if ((pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
|
||||
skip_packfiles = true;
|
||||
}
|
||||
else if (Get_file_list_child != NULL) {
|
||||
skip_packfiles = true;
|
||||
}
|
||||
|
||||
// Search all the packfiles and CD.
|
||||
if ( !Skip_packfile_search ) {
|
||||
if ( !skip_packfiles) {
|
||||
for (i=0; i<Num_files; i++ ) {
|
||||
cf_file * f = cf_get_file(i);
|
||||
|
||||
@@ -1760,6 +1842,11 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip_packfile_search && f->pack_offset != 0) {
|
||||
// If the packfile skip flag is set we skip files in VPs but still search in directories
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
|
||||
|
||||
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
|
||||
@@ -1908,8 +1995,10 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
continue;
|
||||
|
||||
char fn[MAX_PATH];
|
||||
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
|
||||
fn[MAX_PATH-1] = 0;
|
||||
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
|
||||
// Make sure the string is null terminated
|
||||
fn[MAX_PATH-1] = 0;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
if (stat(fn, &buf) == -1) {
|
||||
@@ -1943,8 +2032,16 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
}
|
||||
#endif
|
||||
|
||||
bool skip_packfiles = false;
|
||||
if ((pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS)) {
|
||||
skip_packfiles = true;
|
||||
}
|
||||
else if (Get_file_list_child != NULL) {
|
||||
skip_packfiles = true;
|
||||
}
|
||||
|
||||
// Search all the packfiles and CD.
|
||||
if ( !Skip_packfile_search ) {
|
||||
if (!skip_packfiles) {
|
||||
for (uint i=0; i<Num_files; i++ ) {
|
||||
cf_file * f = cf_get_file(i);
|
||||
|
||||
@@ -1965,6 +2062,11 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip_packfile_search && f->pack_offset != 0) {
|
||||
// If the packfile skip flag is set we skip files in VPs but still search in directories
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
|
||||
|
||||
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
|
||||
@@ -2032,7 +2134,7 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
|
||||
|
||||
// force a specific directory to search for player files
|
||||
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
|
||||
strncpy(path, Pilot_file_path, path_max);
|
||||
strncpy(path, Pilot_file_path.c_str(), path_max);
|
||||
} else {
|
||||
strncpy(path, root->path, path_max);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ void cf_free_secondary_filelist();
|
||||
|
||||
// Internal stuff
|
||||
typedef struct cf_pathtype {
|
||||
int index; // To verify that the CF_TYPE define is correctly indexed into this array
|
||||
char *path; // Path relative to FreeSpace root, has ending backslash.
|
||||
char *extensions; // Extensions used in this pathtype, separated by spaces
|
||||
int parent_index; // Index of this directory's parent. Used for creating directories when writing.
|
||||
int index; // To verify that the CF_TYPE define is correctly indexed into this array
|
||||
const char* path; // Path relative to FreeSpace root, has ending backslash.
|
||||
const char* extensions; // Extensions used in this pathtype, separated by spaces
|
||||
int parent_index; // Index of this directory's parent. Used for creating directories when writing.
|
||||
} cf_pathtype;
|
||||
|
||||
// During cfile_init, verify that Pathtypes[n].index == n for each item
|
||||
|
||||
@@ -8,7 +8,7 @@ set_target_properties(cfilearchiver
|
||||
PROPERTIES
|
||||
FOLDER "FSOTools"
|
||||
)
|
||||
TARGET_LINK_LIBRARIES(cfilearchiver PUBLIC ${SDL_LIBS})
|
||||
TARGET_LINK_LIBRARIES(cfilearchiver PUBLIC sdl2)
|
||||
TARGET_INCLUDE_DIRECTORIES(cfilearchiver PUBLIC ${GENERATED_SOURCE_DIR})
|
||||
TARGET_INCLUDE_DIRECTORIES(cfilearchiver PUBLIC ${GENERATED_SOURCE_DIR}/code)
|
||||
|
||||
|
||||
@@ -315,28 +315,16 @@ int verify_directory( char *filespec )
|
||||
|
||||
void print_instructions()
|
||||
{
|
||||
printf( "Creates a vp archive out of a FreeSpace data tree.\n\n" );
|
||||
printf( "Usage: cfilearchiver archive_name src_dir\n");
|
||||
printf( "Example: cfilearchiver freespace /tmp/freespace/data\n\n");
|
||||
printf( "Directory structure options:\n" );
|
||||
printf( " Effects (.ani .pcx .neb .tga)\n" );
|
||||
printf( " Fonts (.vf)\n" );
|
||||
printf( " Hud (.ani .pcx .tga\n" );
|
||||
printf( " Interface (.pcx .ani .tga)\n" );
|
||||
printf( " Maps (.pcx .ani .tga)\n" );
|
||||
printf( " Missions (.ntl .ssv), FS1(.fsm .fsc), FS2(.fs2 .fc2)\n" );
|
||||
printf( " Models (.pof)\n" );
|
||||
printf( " Music (.wav)\n" );
|
||||
printf( " Sounds/8b22k (.wav)\n" );
|
||||
printf( " Sounds/16b11k (.wav)\n" );
|
||||
printf( " Tables (.tbl)\n" );
|
||||
printf( " Voice/Briefing (.wav)\n" );
|
||||
printf( " Voice/Command briefings (.wav)\n" );
|
||||
printf( " Voice/Debriefing (.wav)\n" );
|
||||
printf( " Voice/Personas (.wav)\n" );
|
||||
printf( " Voice/Special (.wav)\n" );
|
||||
printf( " Voice/Training (.wav)\n" );
|
||||
|
||||
printf("Creates a vp archive out of a FreeSpace data tree.\n\n");
|
||||
printf("Usage: cfilearchiver archive_name src_dir\n");
|
||||
#ifdef _WIN32
|
||||
printf("Example: cfilearchiver freespace c:\\freespace\\data\n");
|
||||
#else
|
||||
printf("Example: cfilearchiver freespace /tmp/freespace/data\n\n");
|
||||
#endif
|
||||
printf("Creates an archive named freespace out of the freespace data tree\n");
|
||||
printf("For information about the FS2 directory structure, please consult\n");
|
||||
printf("http://www.hard-light.net/wiki/index.php/FS2_Data_Structure\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -352,16 +340,7 @@ int main(int argc, char *argv[] )
|
||||
char *p;
|
||||
|
||||
if ( argc < 3 ) {
|
||||
#ifdef _WIN32
|
||||
printf( "Usage: %s archive_name src_dir\n", argv[0] );
|
||||
printf( "Example: %s freespace c:\\freespace\\data\n", argv[0] );
|
||||
printf( "Creates an archive named freespace out of the\nfreespace data tree\n" );
|
||||
printf( "Press any key to exit...\n" );
|
||||
getch();
|
||||
return 1;
|
||||
#else
|
||||
print_instructions();
|
||||
#endif
|
||||
}
|
||||
|
||||
strcpy_s( archive, argv[1] );
|
||||
|
||||
@@ -8,7 +8,7 @@ set_target_properties(cfileextractor
|
||||
PROPERTIES
|
||||
FOLDER "FSOTools"
|
||||
)
|
||||
TARGET_LINK_LIBRARIES(cfileextractor PUBLIC ${SDL_LIBS})
|
||||
TARGET_LINK_LIBRARIES(cfileextractor PUBLIC sdl2)
|
||||
TARGET_INCLUDE_DIRECTORIES(cfileextractor PUBLIC ${GENERATED_SOURCE_DIR})
|
||||
TARGET_INCLUDE_DIRECTORIES(cfileextractor PUBLIC ${GENERATED_SOURCE_DIR}/code)
|
||||
|
||||
|
||||
+369
-118
@@ -17,12 +17,15 @@
|
||||
#include "globalincs/version.h"
|
||||
#include "hud/hudconfig.h"
|
||||
#include "network/multi.h"
|
||||
#include "parse/scripting.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "parse/sexp.h"
|
||||
#include "globalincs/version.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "cfile/cfilesystem.h"
|
||||
#include "sound/speech.h"
|
||||
#include "sound/openal.h"
|
||||
#include "io/joy.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@@ -38,6 +41,9 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
// Stupid windows workaround...
|
||||
#ifdef MessageBox
|
||||
@@ -60,6 +66,11 @@ const char *cmdline_arg_types[] =
|
||||
"STRING",
|
||||
};
|
||||
|
||||
enum class flag_output_type {
|
||||
Binary,
|
||||
Json_V1,
|
||||
};
|
||||
|
||||
// variables
|
||||
class cmdline_parm {
|
||||
public:
|
||||
@@ -78,6 +89,7 @@ public:
|
||||
float get_float();
|
||||
char *str();
|
||||
bool check_if_args_is_valid();
|
||||
bool has_param();
|
||||
};
|
||||
|
||||
static cmdline_parm Parm_list(NULL, NULL, AT_NONE);
|
||||
@@ -150,6 +162,7 @@ Flag exe_params[] =
|
||||
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
|
||||
{ "-missile_lighting", "Apply lighting to missiles" , true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-missile_lighting", },
|
||||
{ "-nonormal", "Disable normal maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-normal" },
|
||||
{ "-no_emissive_light", "Disable emissive light from ships", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_emissive_light" },
|
||||
{ "-noheight", "Disable height/parallax maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-height" },
|
||||
{ "-3dshockwave", "Enable 3D shockwaves", true, EASY_MEM_ALL_ON, EASY_DEFAULT_MEM, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dshockwave" },
|
||||
{ "-post_process", "Enable post processing", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-post_process" },
|
||||
@@ -176,7 +189,6 @@ Flag exe_params[] =
|
||||
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
|
||||
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
|
||||
|
||||
{ "-snd_preload", "Preload mission game sounds", true, EASY_MEM_ALL_ON, EASY_DEFAULT_MEM, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-snd_preload", },
|
||||
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
|
||||
{ "-nomusic", "Disable music", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomusic", },
|
||||
{ "-no_enhanced_sound", "Disable enhanced sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_enhanced_sound", },
|
||||
@@ -195,11 +207,9 @@ Flag exe_params[] =
|
||||
{ "-nomovies", "Disable video playback", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomovies", },
|
||||
{ "-noparseerrors", "Disable parsing errors", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noparseerrors", },
|
||||
{ "-query_speech", "Check if this build has speech", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-query_speech", },
|
||||
{ "-novbo", "Disable OpenGL VBO", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-novbo", },
|
||||
{ "-loadallweps", "Load all weapons, even those not used", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-loadallweps", },
|
||||
{ "-disable_fbo", "Disable OpenGL RenderTargets", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-disable_fbo", },
|
||||
{ "-disable_pbo", "Disable OpenGL Pixel Buffer Objects", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-disable_pbo", },
|
||||
{ "-no_glsl", "Disable GLSL (shader) support", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_glsl", },
|
||||
{ "-ati_swap", "Fix colour issues on some ATI cards", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-ati_swap", },
|
||||
{ "-no_3d_sound", "Use only 2D/stereo for sound effects", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_3d_sound", },
|
||||
{ "-mipmap", "Enable mipmapping", true, 0, EASY_DEFAULT_MEM, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-mipmap", },
|
||||
@@ -209,6 +219,8 @@ Flag exe_params[] =
|
||||
{ "-no_batching", "Disable batched model rendering", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
|
||||
{ "-no_geo_effects", "Disable geometry shader for effects", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
|
||||
{ "-set_cpu_affinity", "Sets processor affinity to config value", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
|
||||
{ "-nograb", "Disables mouse grabbing", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nograb", },
|
||||
{ "-noshadercache", "Disables the shader cache", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noshadercache", },
|
||||
#ifdef WIN32
|
||||
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
|
||||
#endif
|
||||
@@ -217,6 +229,7 @@ Flag exe_params[] =
|
||||
{ "-voicer", "Enable voice recognition", true, 0, EASY_DEFAULT, "Experimental", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-voicer", },
|
||||
|
||||
{ "-fps", "Show frames per second on HUD", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fps", },
|
||||
{ "-bmpmanusage", "Show how many BMPMAN slots are in use", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-bmpmanusage", },
|
||||
{ "-pos", "Show position of camera", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pos", },
|
||||
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
|
||||
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
|
||||
@@ -231,14 +244,16 @@ Flag exe_params[] =
|
||||
{ "-output_sexps", "Output SEXPs to sexps.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_sexps", },
|
||||
{ "-output_scripting", "Output scripting to scripting.html", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-output_scripting", },
|
||||
{ "-save_render_target", "Save render targets to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-save_render_target", },
|
||||
{ "-debug_window", "Display debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
|
||||
{ "-verify_vps", "Spew VP CRCs to vp_crcs.txt", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-verify_vps", },
|
||||
{ "-reparse_mainhall", "Reparse mainhall.tbl when loading halls", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-reparse_mainhall", },
|
||||
{ "-profile_frame_time","Profile engine subsystems", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_timings", },
|
||||
{ "-profile_write_file", "Write profiling information to file", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_write_file", },
|
||||
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
|
||||
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
|
||||
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
|
||||
{ "-json_pilot", "Dump pilot files in JSON format", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_pilot", },
|
||||
{ "-json_profiling", "Generate JSON profiling output", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_profiling", },
|
||||
{ "-profile_frame_time","Profile engine subsystems", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_timings", },
|
||||
{ "-debug_window", "Enable the debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
@@ -390,11 +405,9 @@ int Cmdline_stretch_menu = 0;
|
||||
|
||||
// Audio related
|
||||
cmdline_parm query_speech_arg("-query_speech", NULL, AT_NONE); // Cmdline_query_speech
|
||||
cmdline_parm snd_preload_arg("-snd_preload", NULL, AT_NONE); // Cmdline_snd_preload
|
||||
cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE); // Cmdline_voice_recognition
|
||||
|
||||
int Cmdline_query_speech = 0;
|
||||
int Cmdline_snd_preload = 0; // preload game sounds during mission load
|
||||
int Cmdline_voice_recognition = 0;
|
||||
int Cmdline_no_enhanced_sound = 0;
|
||||
|
||||
@@ -427,10 +440,8 @@ bool Cmdline_portable_mode = false;
|
||||
cmdline_parm loadallweapons_arg("-loadallweps", NULL, AT_NONE); // Cmdline_load_all_weapons
|
||||
cmdline_parm nomovies_arg("-nomovies", NULL, AT_NONE); // Cmdline_nomovies -- Allows video streaming
|
||||
cmdline_parm no_set_gamma_arg("-no_set_gamma", NULL, AT_NONE); // Cmdline_no_set_gamma
|
||||
cmdline_parm no_vbo_arg("-novbo", NULL, AT_NONE); // Cmdline_novbo
|
||||
cmdline_parm no_fbo_arg("-disable_fbo", NULL, AT_NONE); // Cmdline_no_fbo
|
||||
cmdline_parm no_pbo_arg("-disable_pbo", NULL, AT_NONE); // Cmdline_no_pbo
|
||||
cmdline_parm noglsl_arg("-no_glsl", NULL, AT_NONE); // Cmdline_noglsl -- disable GLSL support in OpenGL
|
||||
cmdline_parm mipmap_arg("-mipmap", NULL, AT_NONE); // Cmdline_mipmap
|
||||
cmdline_parm atiswap_arg("-ati_swap", NULL, AT_NONE); // Cmdline_atiswap - Fix ATI color swap issue for screenshots.
|
||||
cmdline_parm no3dsound_arg("-no_3d_sound", NULL, AT_NONE); // Cmdline_no_3d_sound - Disable use of full 3D sounds
|
||||
@@ -440,6 +451,8 @@ cmdline_parm old_collision_system("-old_collision", NULL, AT_NONE); // Cmdline_o
|
||||
cmdline_parm gl_finish ("-gl_finish", NULL, AT_NONE);
|
||||
cmdline_parm no_geo_sdr_effects("-no_geo_effects", NULL, AT_NONE);
|
||||
cmdline_parm set_cpu_affinity("-set_cpu_affinity", NULL, AT_NONE);
|
||||
cmdline_parm nograb_arg("-nograb", NULL, AT_NONE);
|
||||
cmdline_parm noshadercache_arg("-noshadercache", NULL, AT_NONE);
|
||||
#ifdef WIN32
|
||||
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
|
||||
#endif
|
||||
@@ -447,10 +460,8 @@ cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
|
||||
int Cmdline_load_all_weapons = 0;
|
||||
int Cmdline_nomovies = 0;
|
||||
int Cmdline_no_set_gamma = 0;
|
||||
int Cmdline_novbo = 0; // turn off OGL VBO support, troubleshooting
|
||||
int Cmdline_no_fbo = 0;
|
||||
int Cmdline_no_pbo = 0;
|
||||
int Cmdline_noglsl = 0;
|
||||
int Cmdline_ati_color_swap = 0;
|
||||
int Cmdline_no_3d_sound = 0;
|
||||
int Cmdline_drawelements = 0;
|
||||
@@ -458,6 +469,8 @@ char* Cmdline_keyboard_layout = NULL;
|
||||
bool Cmdline_gl_finish = false;
|
||||
bool Cmdline_no_geo_sdr_effects = false;
|
||||
bool Cmdline_set_cpu_affinity = false;
|
||||
bool Cmdline_nograb = false;
|
||||
bool Cmdline_noshadercache = false;
|
||||
#ifdef WIN32
|
||||
bool Cmdline_alternate_registry_path = false;
|
||||
#endif
|
||||
@@ -469,7 +482,7 @@ cmdline_parm dis_weapons("-dis_weapons", NULL, AT_NONE); // Cmdline_dis_weapons
|
||||
cmdline_parm noparseerrors_arg("-noparseerrors", NULL, AT_NONE); // Cmdline_noparseerrors -- turns off parsing errors -C
|
||||
cmdline_parm extra_warn_arg("-extra_warn", "Enable 'extra' warnings", AT_NONE); // Cmdline_extra_warn
|
||||
cmdline_parm fps_arg("-fps", NULL, AT_NONE); // Cmdline_show_fps
|
||||
cmdline_parm show_mem_usage_arg("-show_mem_usage", NULL, AT_NONE); // Cmdline_show_mem_usage
|
||||
cmdline_parm bmpmanusage_arg("-bmpmanusage", NULL, AT_NONE); // Cmdline_bmpman_usage
|
||||
cmdline_parm pos_arg("-pos", NULL, AT_NONE); // Cmdline_show_pos
|
||||
cmdline_parm stats_arg("-stats", NULL, AT_NONE); // Cmdline_show_stats
|
||||
cmdline_parm save_render_targets_arg("-save_render_target", NULL, AT_NONE); // Cmdline_save_render_targets
|
||||
@@ -480,11 +493,15 @@ cmdline_parm center_res_arg("-center_res", "Resolution of center monitor, format
|
||||
cmdline_parm verify_vps_arg("-verify_vps", NULL, AT_NONE); // Cmdline_verify_vps -- spew VP crcs to vp_crcs.txt
|
||||
cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_fso.cfg files", AT_NONE);
|
||||
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
|
||||
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
|
||||
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
|
||||
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
|
||||
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
|
||||
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
|
||||
cmdline_parm json_pilot("-json_pilot", NULL, AT_NONE); //Cmdline_json_pilot
|
||||
cmdline_parm json_profiling("-json_profiling", NULL, AT_NONE); //Cmdline_json_profiling
|
||||
cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_video_info
|
||||
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
|
||||
cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_window
|
||||
|
||||
|
||||
char *Cmdline_start_mission = NULL;
|
||||
@@ -496,7 +513,7 @@ int Cmdline_noparseerrors = 0;
|
||||
int Cmdline_nowarn = 0; // turn warnings off in FRED
|
||||
#endif
|
||||
int Cmdline_extra_warn = 0;
|
||||
int Cmdline_show_mem_usage = 0;
|
||||
int Cmdline_bmpman_usage = 0;
|
||||
int Cmdline_show_pos = 0;
|
||||
int Cmdline_show_stats = 0;
|
||||
int Cmdline_save_render_targets = 0;
|
||||
@@ -506,14 +523,18 @@ char *Cmdline_res = 0;
|
||||
char *Cmdline_center_res = 0;
|
||||
int Cmdline_verify_vps = 0;
|
||||
int Cmdline_reparse_mainhall = 0;
|
||||
bool Cmdline_frame_profile = false;
|
||||
bool Cmdline_profile_write_file = false;
|
||||
bool Cmdline_no_unfocus_pause = false;
|
||||
bool Cmdline_benchmark_mode = false;
|
||||
bool Cmdline_noninteractive = false;
|
||||
bool Cmdline_json_pilot = false;
|
||||
bool Cmdline_json_profiling = false;
|
||||
bool Cmdline_frame_profile = false;
|
||||
bool Cmdline_show_video_info = false;
|
||||
bool Cmdline_debug_window = false;
|
||||
|
||||
// Other
|
||||
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_NONE);
|
||||
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_STRING);
|
||||
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
|
||||
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
|
||||
|
||||
@@ -526,6 +547,7 @@ cmdline_parm deprecated_tbp_arg("-tbp", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_jpgtga_arg("-jpgtga", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_htl_arg("-nohtl", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_brieflighting_arg("-brief_lighting", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_sndpreload_arg("-snd_preload", "Deprecated", AT_NONE);
|
||||
|
||||
int Cmdline_deprecated_spec = 0;
|
||||
int Cmdline_deprecated_glow = 0;
|
||||
@@ -780,12 +802,7 @@ void os_validate_parms(int argc, char *argv[])
|
||||
if (parm_found == 0) {
|
||||
// if we got a -help, --help, -h, or -? then show the help text, otherwise show unknown option
|
||||
if (!stricmp(token, "-help") || !stricmp(token, "--help") || !stricmp(token, "-h") || !stricmp(token, "-?")) {
|
||||
if (FS_VERSION_HAS_REVIS == 0) {
|
||||
printf("FreeSpace 2 Open, version %i.%i.%i\n", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD);
|
||||
}
|
||||
else {
|
||||
printf("FreeSpace 2 Open, version %i.%i.%i.%i\n", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD, FS_VERSION_REVIS);
|
||||
}
|
||||
printf("FreeSpace 2 Open, version %s\n", FS_VERSION_FULL);
|
||||
printf("Website: http://scp.indiegames.us\n");
|
||||
printf("Mantis (bug reporting): http://scp.indiegames.us/mantis/\n\n");
|
||||
printf("Usage: fs2_open [options]\n");
|
||||
@@ -922,32 +939,45 @@ bool has_cmdline_only_flag(int argc, char *argv[])
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove old parms - needed for tests
|
||||
static void reset_cmdline_parms()
|
||||
{
|
||||
for (cmdline_parm *parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
|
||||
if (parmp->args != NULL) {
|
||||
delete[] parmp->args;
|
||||
parmp->args = NULL;
|
||||
}
|
||||
parmp->name_found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Call once to initialize the command line system
|
||||
//
|
||||
// cmdline - command line string passed to the application
|
||||
void os_init_cmdline(int argc, char *argv[])
|
||||
{
|
||||
// Tests call this multiple times, so reset the params here.
|
||||
// Otherwise e.g. the modlist just grows and grows...
|
||||
reset_cmdline_parms();
|
||||
|
||||
FILE *fp;
|
||||
|
||||
|
||||
if (!has_cmdline_only_flag(argc, argv)) {
|
||||
// Only parse the config file in the current directory if we are in legacy config mode
|
||||
if (os_is_legacy_mode()) {
|
||||
// read the cmdline_fso.cfg file from the data folder, and pass the command line arguments to
|
||||
// the the parse_parms and validate_parms line. Read these first so anything actually on
|
||||
// the command line will take precedence
|
||||
#ifdef _WIN32
|
||||
fp = fopen("data\\cmdline_fso.cfg", "rt");
|
||||
#elif defined(APPLE_APP)
|
||||
#ifdef APPLE_APP
|
||||
char resolved_path[MAX_PATH], data_path[MAX_PATH_LEN];
|
||||
|
||||
GetCurrentDirectory(MAX_PATH_LEN - 1, data_path);
|
||||
getcwd(data_path, sizeof(data_path));
|
||||
snprintf(resolved_path, MAX_PATH, "%s/data/cmdline_fso.cfg", data_path);
|
||||
|
||||
fp = fopen(resolved_path, "rt");
|
||||
#else
|
||||
fp = fopen("data/cmdline_fso.cfg", "rt");
|
||||
fp = fopen("data" DIR_SEPARATOR_STR "cmdline_fso.cfg", "rt");
|
||||
#endif
|
||||
|
||||
// if the file exists, get a single line, and deal with it
|
||||
if (fp) {
|
||||
char *buf, *p;
|
||||
@@ -961,7 +991,6 @@ void os_init_cmdline(int argc, char *argv[])
|
||||
if ((p = strrchr(buf, '\n')) != NULL) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
// append a space for the os_parse_parms() check
|
||||
strcat_s(buf, len, " ");
|
||||
@@ -971,35 +1000,35 @@ void os_init_cmdline(int argc, char *argv[])
|
||||
delete[] buf;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// parse user specific cmdline_fso config file (will supersede options in global file)
|
||||
fp = fopen(os_get_config_path("data/cmdline_fso.cfg").c_str(), "rt");
|
||||
|
||||
// parse user specific cmdline_fso config file (will supersede options in global file)
|
||||
fp = fopen(os_get_config_path("data/cmdline_fso.cfg").c_str(), "rt");
|
||||
// if the file exists, get a single line, and deal with it
|
||||
if ( fp ) {
|
||||
char *buf, *p;
|
||||
|
||||
// if the file exists, get a single line, and deal with it
|
||||
if ( fp ) {
|
||||
char *buf, *p;
|
||||
auto len = static_cast<int>(filelength( fileno(fp) )) + 2;
|
||||
buf = new char [len];
|
||||
|
||||
auto len = static_cast<int>(filelength( fileno(fp) )) + 2;
|
||||
buf = new char [len];
|
||||
if (fgets(buf, len-1, fp) != nullptr)
|
||||
{
|
||||
// replace the newline character with a NULL
|
||||
if ( (p = strrchr(buf, '\n')) != NULL ) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
if (fgets(buf, len-1, fp) != nullptr)
|
||||
{
|
||||
// replace the newline character with a NULL
|
||||
if ( (p = strrchr(buf, '\n')) != NULL ) {
|
||||
*p = '\0';
|
||||
// append a space for the os_parse_parms() check
|
||||
strcat_s(buf, len, " ");
|
||||
|
||||
os_process_cmdline(buf);
|
||||
}
|
||||
|
||||
// append a space for the os_parse_parms() check
|
||||
strcat_s(buf, len, " ");
|
||||
|
||||
os_process_cmdline(buf);
|
||||
delete [] buf;
|
||||
fclose(fp);
|
||||
}
|
||||
delete [] buf;
|
||||
fclose(fp);
|
||||
}
|
||||
} // If cmdline included PARSE_COMMAND_LINE_STRING
|
||||
|
||||
|
||||
// By parsing cmdline last, anything actually on the command line will take precedence.
|
||||
os_parse_parms(argc, argv);
|
||||
os_validate_parms(argc, argv);
|
||||
@@ -1127,6 +1156,9 @@ char *cmdline_parm::str()
|
||||
|
||||
return args;
|
||||
}
|
||||
bool cmdline_parm::has_param() {
|
||||
return args != nullptr;
|
||||
}
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
// Return a vector with all filesystem names of "parent/dir" relative to parent.
|
||||
@@ -1194,7 +1226,8 @@ static void handle_unix_modlist(char **modlist, size_t *len)
|
||||
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ","))
|
||||
{
|
||||
SCP_vector<SCP_string> this_mod_paths = unix_get_dir_names(".", cur_mod);
|
||||
if (this_mod_paths.empty()) {
|
||||
// Ignore non-existing mods for unit tests
|
||||
if (!running_unittests && this_mod_paths.empty()) {
|
||||
ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod);
|
||||
}
|
||||
mod_paths.insert(mod_paths.end(), this_mod_paths.begin(), this_mod_paths.end());
|
||||
@@ -1224,6 +1257,248 @@ static void handle_unix_modlist(char **modlist, size_t *len)
|
||||
|
||||
// external entry point into this modules
|
||||
|
||||
static json_t* json_get_v1() {
|
||||
auto root = json_object();
|
||||
|
||||
{
|
||||
auto version_obj = json_object();
|
||||
|
||||
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
|
||||
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
|
||||
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
|
||||
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
|
||||
|
||||
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
|
||||
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
|
||||
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
|
||||
|
||||
json_object_set_new(root, "version", version_obj);
|
||||
}
|
||||
{
|
||||
auto easy_array = json_array();
|
||||
|
||||
for (auto& easy_flag : easy_flags) {
|
||||
json_array_append_new(easy_array, json_string(easy_flag.name));
|
||||
}
|
||||
|
||||
json_object_set_new(root, "easy_flags", easy_array);
|
||||
}
|
||||
{
|
||||
auto flags_array = json_array();
|
||||
|
||||
for (auto& flag : exe_params) {
|
||||
auto flag_obj = json_object();
|
||||
|
||||
json_object_set_new(flag_obj, "name", json_string(flag.name));
|
||||
json_object_set_new(flag_obj, "description", json_string(flag.desc));
|
||||
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
|
||||
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
|
||||
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
|
||||
json_object_set_new(flag_obj, "type", json_string(flag.type));
|
||||
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
|
||||
|
||||
json_array_append_new(flags_array, flag_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "flags", flags_array);
|
||||
}
|
||||
{
|
||||
auto caps_array = json_array();
|
||||
|
||||
json_array_append_new(caps_array, json_string("OpenAL"));
|
||||
json_array_append_new(caps_array, json_string("No D3D"));
|
||||
json_array_append_new(caps_array, json_string("New Sound"));
|
||||
json_array_append_new(caps_array, json_string("SDL"));
|
||||
|
||||
json_object_set_new(root, "caps", caps_array);
|
||||
}
|
||||
{
|
||||
auto voices_array = json_array();
|
||||
|
||||
auto voices = speech_enumerate_voices();
|
||||
|
||||
for (auto& voice : voices) {
|
||||
json_array_append_new(voices_array, json_string(voice.c_str()));
|
||||
}
|
||||
|
||||
json_object_set_new(root, "voices", voices_array);
|
||||
}
|
||||
{
|
||||
auto resolution_array = json_array();
|
||||
|
||||
auto displays = gr_enumerate_displays();
|
||||
|
||||
for (auto& display : displays) {
|
||||
auto display_obj = json_object();
|
||||
|
||||
json_object_set_new(display_obj, "index", json_integer(display.index));
|
||||
json_object_set_new(display_obj, "name", json_string(display.name.c_str()));
|
||||
|
||||
json_object_set_new(display_obj, "x", json_integer(display.x));
|
||||
json_object_set_new(display_obj, "y", json_integer(display.y));
|
||||
json_object_set_new(display_obj, "width", json_integer(display.width));
|
||||
json_object_set_new(display_obj, "height", json_integer(display.height));
|
||||
|
||||
auto modes_array = json_array();
|
||||
|
||||
for (auto& mode : display.video_modes) {
|
||||
auto mode_obj = json_object();
|
||||
|
||||
json_object_set_new(mode_obj, "x", json_integer(mode.width));
|
||||
json_object_set_new(mode_obj, "y", json_integer(mode.height));
|
||||
json_object_set_new(mode_obj, "bits", json_integer(mode.bit_depth));
|
||||
|
||||
json_array_append_new(modes_array, mode_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(display_obj, "modes", modes_array);
|
||||
|
||||
json_array_append_new(resolution_array, display_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "displays", resolution_array);
|
||||
}
|
||||
{
|
||||
auto openal_obj = json_object();
|
||||
|
||||
auto openal_info = openal_get_platform_information();
|
||||
|
||||
json_object_set_new(openal_obj, "version_major", json_integer(openal_info.version_major));
|
||||
json_object_set_new(openal_obj, "version_minor", json_integer(openal_info.version_minor));
|
||||
|
||||
json_object_set(openal_obj, "default_playback", json_string(openal_info.default_playback_device.c_str()));
|
||||
json_object_set(openal_obj, "default_capture", json_string(openal_info.default_capture_device.c_str()));
|
||||
|
||||
{
|
||||
auto playback_array = json_array();
|
||||
|
||||
for (auto& device : openal_info.playback_devices) {
|
||||
json_array_append_new(playback_array, json_string(device.c_str()));
|
||||
}
|
||||
|
||||
json_object_set_new(openal_obj, "playback_devices", playback_array);
|
||||
}
|
||||
{
|
||||
auto capture_array = json_array();
|
||||
|
||||
for (auto& device : openal_info.capture_devices) {
|
||||
json_array_append_new(capture_array, json_string(device.c_str()));
|
||||
}
|
||||
|
||||
json_object_set_new(openal_obj, "capture_devices", capture_array);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "openal", openal_obj);
|
||||
}
|
||||
{
|
||||
auto joystick_array = json_array();
|
||||
|
||||
auto joysticks = io::joystick::getJoystickInformations();
|
||||
for (auto& info : joysticks) {
|
||||
auto joystick_obj = json_object();
|
||||
|
||||
json_object_set_new(joystick_obj, "name", json_string(info.name.c_str()));
|
||||
json_object_set_new(joystick_obj, "guid", json_string(info.guid.c_str()));
|
||||
|
||||
json_object_set_new(joystick_obj, "num_axes", json_integer(info.num_axes));
|
||||
json_object_set_new(joystick_obj, "num_balls", json_integer(info.num_balls));
|
||||
json_object_set_new(joystick_obj, "num_buttons", json_integer(info.num_buttons));
|
||||
json_object_set_new(joystick_obj, "num_hats", json_integer(info.num_hats));
|
||||
|
||||
json_object_set_new(joystick_obj, "is_haptic", json_boolean(info.is_haptic));
|
||||
|
||||
json_array_append_new(joystick_array, joystick_obj);
|
||||
}
|
||||
|
||||
json_object_set_new(root, "joysticks", joystick_array);
|
||||
}
|
||||
{
|
||||
json_object_set_new(root, "pref_path", json_string(os_get_config_path().c_str()));
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static void write_flags_file() {
|
||||
FILE *fp = fopen("flags.lch","w");
|
||||
|
||||
if (fp == NULL) {
|
||||
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
|
||||
return;
|
||||
}
|
||||
|
||||
int easy_flag_size = sizeof(EasyFlag);
|
||||
int flag_size = sizeof(Flag);
|
||||
|
||||
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
|
||||
int num_flags = sizeof(exe_params) / flag_size;
|
||||
|
||||
// Launcher will check its using structures of the same size
|
||||
fwrite(&easy_flag_size, sizeof(int), 1, fp);
|
||||
fwrite(&flag_size, sizeof(int), 1, fp);
|
||||
|
||||
fwrite(&num_easy_flags, sizeof(int), 1, fp);
|
||||
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
|
||||
|
||||
fwrite(&num_flags, sizeof(int), 1, fp);
|
||||
fwrite(&exe_params, sizeof(exe_params), 1, fp);
|
||||
|
||||
{
|
||||
// cheap and bastardly cap check for builds
|
||||
// (needs to be compatible with older Launchers, which means having
|
||||
// this implies an OpenAL build for old Launchers)
|
||||
ubyte build_caps = 0;
|
||||
|
||||
/* portej05 defined this always */
|
||||
build_caps |= BUILD_CAPS_OPENAL;
|
||||
build_caps |= BUILD_CAPS_NO_D3D;
|
||||
build_caps |= BUILD_CAPS_NEW_SND;
|
||||
build_caps |= BUILD_CAPS_SDL;
|
||||
|
||||
fwrite(&build_caps, 1, 1, fp);
|
||||
}
|
||||
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static flag_output_type get_flags_output_type() {
|
||||
Assertion(get_flags_arg.found(), "This function is only valid if -get_flags is present!");
|
||||
|
||||
if (!get_flags_arg.has_param()) {
|
||||
// Default to binary mode
|
||||
return flag_output_type::Binary;
|
||||
}
|
||||
|
||||
SCP_string type(get_flags_arg.str());
|
||||
|
||||
if (type == "binary") {
|
||||
return flag_output_type::Binary;
|
||||
} else if (type == "json_v1") {
|
||||
return flag_output_type::Json_V1;
|
||||
} else {
|
||||
// This is supposed to make it easy for the launcher to recognize an unsupported type
|
||||
printf("OUTPUT TYPE NOT SUPPORTED!\n");
|
||||
// Default to json in this case so that no flags.lch file is created
|
||||
return flag_output_type::Json_V1;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_flags() {
|
||||
auto type = get_flags_output_type();
|
||||
switch(type) {
|
||||
case flag_output_type::Binary:
|
||||
write_flags_file();
|
||||
break;
|
||||
case flag_output_type::Json_V1:
|
||||
json_t* root = json_get_v1();
|
||||
|
||||
json_dumpf(root, stdout, JSON_INDENT(4));
|
||||
json_decref(root);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetCmdlineParams()
|
||||
// Sets externed variables used for communication cmdline information
|
||||
{
|
||||
@@ -1231,47 +1506,7 @@ bool SetCmdlineParams()
|
||||
|
||||
// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
|
||||
if ( get_flags_arg.found() ) {
|
||||
FILE *fp = fopen("flags.lch","w");
|
||||
|
||||
if (fp == NULL) {
|
||||
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
|
||||
return false;
|
||||
}
|
||||
|
||||
int easy_flag_size = sizeof(EasyFlag);
|
||||
int flag_size = sizeof(Flag);
|
||||
|
||||
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
|
||||
int num_flags = sizeof(exe_params) / flag_size;
|
||||
|
||||
// Launcher will check its using structures of the same size
|
||||
fwrite(&easy_flag_size, sizeof(int), 1, fp);
|
||||
fwrite(&flag_size, sizeof(int), 1, fp);
|
||||
|
||||
fwrite(&num_easy_flags, sizeof(int), 1, fp);
|
||||
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
|
||||
|
||||
fwrite(&num_flags, sizeof(int), 1, fp);
|
||||
fwrite(&exe_params, sizeof(exe_params), 1, fp);
|
||||
|
||||
{
|
||||
// cheap and bastardly cap check for builds
|
||||
// (needs to be compatible with older Launchers, which means having
|
||||
// this implies an OpenAL build for old Launchers)
|
||||
ubyte build_caps = 0;
|
||||
|
||||
/* portej05 defined this always */
|
||||
build_caps |= BUILD_CAPS_OPENAL;
|
||||
build_caps |= BUILD_CAPS_NO_D3D;
|
||||
build_caps |= BUILD_CAPS_NEW_SND;
|
||||
build_caps |= BUILD_CAPS_SDL;
|
||||
|
||||
|
||||
fwrite(&build_caps, 1, 1, fp);
|
||||
}
|
||||
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
write_flags();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1524,6 +1759,11 @@ bool SetCmdlineParams()
|
||||
Show_framerate = 1;
|
||||
}
|
||||
|
||||
if (bmpmanusage_arg.found())
|
||||
{
|
||||
Cmdline_bmpman_usage = 1;
|
||||
}
|
||||
|
||||
if(pos_arg.found())
|
||||
{
|
||||
Cmdline_show_pos = 1;
|
||||
@@ -1613,11 +1853,7 @@ bool SetCmdlineParams()
|
||||
if ( height_arg.found() ) {
|
||||
Cmdline_height = 0;
|
||||
}
|
||||
|
||||
if ( noglsl_arg.found() ) {
|
||||
Cmdline_noglsl = 1;
|
||||
}
|
||||
|
||||
|
||||
if (fxaa_arg.found() ) {
|
||||
Cmdline_fxaa = true;
|
||||
|
||||
@@ -1640,9 +1876,6 @@ bool SetCmdlineParams()
|
||||
if ( weapon_choice_3d_arg.found() )
|
||||
Cmdline_weapon_choice_3d = 1;
|
||||
|
||||
if ( show_mem_usage_arg.found() )
|
||||
Cmdline_show_mem_usage = 1;
|
||||
|
||||
if (ingamejoin_arg.found() )
|
||||
Cmdline_ingamejoin = 1;
|
||||
|
||||
@@ -1660,11 +1893,6 @@ bool SetCmdlineParams()
|
||||
output_sexps("sexps.html");
|
||||
}
|
||||
|
||||
if ( no_vbo_arg.found() )
|
||||
{
|
||||
Cmdline_novbo = 1;
|
||||
}
|
||||
|
||||
if ( no_pbo_arg.found() )
|
||||
{
|
||||
Cmdline_no_pbo = 1;
|
||||
@@ -1695,6 +1923,16 @@ bool SetCmdlineParams()
|
||||
Cmdline_set_cpu_affinity = true;
|
||||
}
|
||||
|
||||
if (nograb_arg.found())
|
||||
{
|
||||
Cmdline_nograb = true;
|
||||
}
|
||||
|
||||
if (noshadercache_arg.found())
|
||||
{
|
||||
Cmdline_noshadercache = true;
|
||||
}
|
||||
|
||||
if (portable_mode.found())
|
||||
{
|
||||
Cmdline_portable_mode = true;
|
||||
@@ -1706,11 +1944,6 @@ bool SetCmdlineParams()
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( snd_preload_arg.found() )
|
||||
{
|
||||
Cmdline_snd_preload = 1;
|
||||
}
|
||||
|
||||
if ( env.found() ) {
|
||||
Cmdline_env = 0;
|
||||
}
|
||||
@@ -1826,14 +2059,8 @@ bool SetCmdlineParams()
|
||||
Cmdline_no_deferred_lighting = 1;
|
||||
}
|
||||
|
||||
if (frame_profile_arg.found() )
|
||||
{
|
||||
Cmdline_frame_profile = true;
|
||||
}
|
||||
|
||||
if (frame_profile_write_file.found())
|
||||
{
|
||||
Cmdline_frame_profile = true;
|
||||
Cmdline_profile_write_file = true;
|
||||
}
|
||||
|
||||
@@ -1852,6 +2079,30 @@ bool SetCmdlineParams()
|
||||
Cmdline_noninteractive = true;
|
||||
}
|
||||
|
||||
if (json_pilot.found())
|
||||
{
|
||||
Cmdline_json_pilot = true;
|
||||
}
|
||||
|
||||
if (json_profiling.found())
|
||||
{
|
||||
Cmdline_json_profiling = true;
|
||||
}
|
||||
|
||||
if (frame_profile_arg.found() )
|
||||
{
|
||||
Cmdline_frame_profile = true;
|
||||
}
|
||||
|
||||
if (debug_window_arg.found()) {
|
||||
Cmdline_debug_window = true;
|
||||
}
|
||||
|
||||
if (show_video_info.found())
|
||||
{
|
||||
Cmdline_show_video_info = true;
|
||||
}
|
||||
|
||||
//Deprecated flags - CommanderDJ
|
||||
if( deprecated_spec_arg.found() )
|
||||
{
|
||||
|
||||
@@ -80,6 +80,7 @@ extern bool Cmdline_fb_thrusters;
|
||||
extern bool Cmdline_no_batching;
|
||||
extern int Cmdline_shadow_quality;
|
||||
extern int Cmdline_no_deferred_lighting;
|
||||
extern int Cmdline_no_emissive;
|
||||
|
||||
// Game Speed related
|
||||
extern int Cmdline_cache_bitmaps;
|
||||
@@ -103,7 +104,6 @@ extern int Cmdline_stretch_menu;
|
||||
|
||||
// Audio related
|
||||
extern int Cmdline_query_speech;
|
||||
extern int Cmdline_snd_preload;
|
||||
extern int Cmdline_voice_recognition;
|
||||
extern int Cmdline_no_enhanced_sound;
|
||||
|
||||
@@ -124,10 +124,8 @@ extern bool Cmdline_portable_mode;
|
||||
extern int Cmdline_load_all_weapons;
|
||||
extern int Cmdline_nomovies; // WMC Toggles movie playing support
|
||||
extern int Cmdline_no_set_gamma;
|
||||
extern int Cmdline_novbo;
|
||||
extern int Cmdline_no_fbo;
|
||||
extern int Cmdline_no_pbo;
|
||||
extern int Cmdline_noglsl;
|
||||
extern int Cmdline_mipmap;
|
||||
extern int Cmdline_ati_color_swap;
|
||||
extern int Cmdline_no_3d_sound;
|
||||
@@ -136,6 +134,8 @@ extern char* Cmdline_keyboard_layout;
|
||||
extern bool Cmdline_gl_finish;
|
||||
extern bool Cmdline_no_geo_sdr_effects;
|
||||
extern bool Cmdline_set_cpu_affinity;
|
||||
extern bool Cmdline_nograb;
|
||||
extern bool Cmdline_noshadercache;
|
||||
#ifdef WIN32
|
||||
extern bool Cmdline_alternate_registry_path;
|
||||
#endif
|
||||
@@ -147,16 +147,20 @@ extern int Cmdline_dis_collisions;
|
||||
extern int Cmdline_dis_weapons;
|
||||
extern int Cmdline_noparseerrors;
|
||||
extern int Cmdline_extra_warn;
|
||||
extern int Cmdline_show_mem_usage;
|
||||
extern int Cmdline_bmpman_usage;
|
||||
extern int Cmdline_show_pos;
|
||||
extern int Cmdline_show_stats;
|
||||
extern int Cmdline_save_render_targets;
|
||||
extern int Cmdline_verify_vps;
|
||||
extern int Cmdline_reparse_mainhall;
|
||||
extern bool Cmdline_frame_profile;
|
||||
extern bool Cmdline_profile_write_file;
|
||||
extern bool Cmdline_no_unfocus_pause;
|
||||
extern bool Cmdline_benchmark_mode;
|
||||
extern bool Cmdline_noninteractive;
|
||||
extern bool Cmdline_json_pilot;
|
||||
extern bool Cmdline_json_profiling;
|
||||
extern bool Cmdline_frame_profile;
|
||||
extern bool Cmdline_show_video_info;
|
||||
extern bool Cmdline_debug_window;
|
||||
|
||||
#endif
|
||||
@@ -62,7 +62,7 @@ void cmeasure_select_next(ship *shipp)
|
||||
{
|
||||
new_index = (shipp->current_cmeasure + i) % Num_weapon_types;
|
||||
|
||||
if(Weapon_info[new_index].wi_flags & WIF_CMEASURE)
|
||||
if(Weapon_info[new_index].wi_flags[Weapon::Info_Flags::Cmeasure])
|
||||
{
|
||||
shipp->current_cmeasure = new_index;
|
||||
return;
|
||||
@@ -88,11 +88,11 @@ void cmeasure_maybe_alert_success(object *objp)
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_CMEASURE);
|
||||
Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Cmeasure]);
|
||||
|
||||
if ( objp->parent == OBJ_INDEX(Player_obj) ) {
|
||||
hud_start_text_flash(XSTR("Evaded", 1430), 800);
|
||||
snd_play(&Snds[ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP)]);
|
||||
snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP)));
|
||||
} else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) {
|
||||
send_countermeasure_success_packet( objp->parent );
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "missionui/missionscreencommon.h"
|
||||
#include "network/multi_pmsg.h"
|
||||
#include "network/multiutil.h"
|
||||
#include "parse/scripting.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "pilotfile/pilotfile.h"
|
||||
#include "popup/popup.h"
|
||||
#include "ui/ui.h"
|
||||
@@ -48,12 +48,12 @@
|
||||
#define CONTROL_W_COORD 2
|
||||
#define CONTROL_H_COORD 3
|
||||
|
||||
char* Conflict_background_bitmap_fname[GR_NUM_RESOLUTIONS] = {
|
||||
const char* Conflict_background_bitmap_fname[GR_NUM_RESOLUTIONS] = {
|
||||
"ControlConfig", // GR_640
|
||||
"2_ControlConfig" // GR_1024
|
||||
};
|
||||
|
||||
char* Conflict_background_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
|
||||
const char* Conflict_background_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
|
||||
"ControlConfig-m", // GR_640
|
||||
"2_ControlConfig-m" // GR_1024
|
||||
};
|
||||
@@ -369,7 +369,7 @@ static int joy_get_unscaled_reading(int raw, int axn)
|
||||
if (raw > rng)
|
||||
raw = rng;
|
||||
|
||||
return (int) ((uint) raw * (uint) F1_0 / (uint) rng); // convert to 0 - F1_0 range.
|
||||
return (int) ((std::uint64_t) raw * (std::uint64_t) F1_0 / (std::uint64_t) rng); // convert to 0 - F1_0 range, 64bit ints used to avoid uint overflow
|
||||
}
|
||||
|
||||
int joy_get_scaled_reading(int raw)
|
||||
@@ -919,7 +919,7 @@ int control_config_do_reset()
|
||||
bool cycling_presets = false;
|
||||
|
||||
// If there are presets, then we'll cycle to the next preset and reset to that
|
||||
if (Control_config_presets.size() >= 1) {
|
||||
if (!Control_config_presets.empty()) {
|
||||
cycling_presets = true;
|
||||
|
||||
if (++Defaults_cycle_pos >= Control_config_presets.size())
|
||||
@@ -1974,7 +1974,7 @@ void control_config_do_frame(float frametime)
|
||||
if (t % 2) {
|
||||
gr_set_color_fast(&Color_text_normal);
|
||||
gr_get_string_size(&w, NULL, XSTR( "?", 208));
|
||||
gr_printf_menu(x - w / 2, y - font_height / 2, XSTR( "?", 208));
|
||||
gr_printf_menu(x - w / 2, y - font_height / 2, "%s", XSTR( "?", 208));
|
||||
}
|
||||
|
||||
} else if (!(z & JOY_AXIS) && ((Conflicts[z].key >= 0) || (Conflicts[z].joy >= 0))) {
|
||||
@@ -1986,7 +1986,7 @@ void control_config_do_frame(float frametime)
|
||||
gr_set_color_fast(&Color_text_normal);
|
||||
str = XSTR( "Control conflicts with:", 209);
|
||||
gr_get_string_size(&w, NULL, str);
|
||||
gr_printf_menu(x - w / 2, y - font_height, str);
|
||||
gr_printf_menu(x - w / 2, y - font_height, "%s", str);
|
||||
|
||||
if (Control_config[i].hasXSTR) {
|
||||
strcpy_s(buf, XSTR(Control_config[i].text, CONTROL_CONFIG_XSTR + i));
|
||||
@@ -1996,12 +1996,12 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
font::force_fit_string(buf, 255, Conflict_wnd_coords[gr_screen.res][CONTROL_W_COORD]);
|
||||
gr_get_string_size(&w, NULL, buf);
|
||||
gr_printf_menu(x - w / 2, y, buf);
|
||||
gr_printf_menu(x - w / 2, y, "%s", buf);
|
||||
|
||||
} else if (*bound_string) {
|
||||
gr_set_color_fast(&Color_text_normal);
|
||||
gr_get_string_size(&w, NULL, bound_string);
|
||||
gr_printf_menu(x - w / 2, y - font_height / 2, bound_string);
|
||||
gr_printf_menu(x - w / 2, y - font_height / 2, "%s", bound_string);
|
||||
if (timestamp_elapsed(bound_timestamp)) {
|
||||
*bound_string = 0;
|
||||
}
|
||||
@@ -2009,7 +2009,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
if (Cc_lines[Num_cc_lines - 1].y + font_height > Cc_lines[Scroll_offset].y + Control_list_coords[gr_screen.res][CONTROL_H_COORD]) {
|
||||
gr_set_color_fast(&Color_white);
|
||||
gr_printf_menu(Control_more_coords[gr_screen.res][CONTROL_X_COORD], Control_more_coords[gr_screen.res][CONTROL_Y_COORD], XSTR( "More...", 210));
|
||||
gr_printf_menu(Control_more_coords[gr_screen.res][CONTROL_X_COORD], Control_more_coords[gr_screen.res][CONTROL_Y_COORD], "%s", XSTR( "More...", 210));
|
||||
}
|
||||
|
||||
conflict = 0;
|
||||
@@ -2035,7 +2035,7 @@ void control_config_do_frame(float frametime)
|
||||
if (Cc_lines[line].label) {
|
||||
strcpy_s(buf, Cc_lines[line].label);
|
||||
font::force_fit_string(buf, 255, Control_list_ctrl_w[gr_screen.res]);
|
||||
gr_printf_menu(Control_list_coords[gr_screen.res][CONTROL_X_COORD], y, buf);
|
||||
gr_printf_menu(Control_list_coords[gr_screen.res][CONTROL_X_COORD], y, "%s", buf);
|
||||
}
|
||||
|
||||
if (!(z & JOY_AXIS)) {
|
||||
@@ -2046,7 +2046,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
if ((k < 0) && (j < 0)) {
|
||||
gr_set_color_fast(&Color_grey);
|
||||
gr_printf_menu(x, y, XSTR( "None", 211));
|
||||
gr_printf_menu(x, y, "%s", XSTR( "None", 211));
|
||||
|
||||
} else {
|
||||
if (k >= 0) {
|
||||
@@ -2066,7 +2066,7 @@ void control_config_do_frame(float frametime)
|
||||
gr_set_color_fast(c);
|
||||
}
|
||||
|
||||
gr_printf_menu(x, y, buf);
|
||||
gr_printf_menu(x, y, "%s", buf);
|
||||
|
||||
Cc_lines[line].kx = x - Control_list_coords[gr_screen.res][CONTROL_X_COORD];
|
||||
gr_get_string_size(&w, NULL, buf);
|
||||
@@ -2075,7 +2075,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
if (j >= 0) {
|
||||
gr_set_color_fast(&Color_text_normal);
|
||||
gr_printf_menu(x, y, XSTR( ", ", 212));
|
||||
gr_printf_menu(x, y, "%s", XSTR( ", ", 212));
|
||||
gr_get_string_size(&w, NULL, XSTR( ", ", 212));
|
||||
x += w;
|
||||
}
|
||||
@@ -2099,7 +2099,7 @@ void control_config_do_frame(float frametime)
|
||||
}
|
||||
|
||||
font::force_fit_string(buf, 255, Control_list_key_w[gr_screen.res] + Control_list_key_x[gr_screen.res] - x);
|
||||
gr_printf_menu(x, y, buf);
|
||||
gr_printf_menu(x, y, "%s", buf);
|
||||
|
||||
Cc_lines[line].jx = x - Control_list_coords[gr_screen.res][CONTROL_X_COORD];
|
||||
gr_get_string_size(&Cc_lines[line].jw, NULL, buf);
|
||||
@@ -2115,7 +2115,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
if (j < 0) {
|
||||
gr_set_color_fast(&Color_grey);
|
||||
gr_printf_menu(x, y, XSTR( "None", 211));
|
||||
gr_printf_menu(x, y, "%s", XSTR( "None", 211));
|
||||
|
||||
} else {
|
||||
if (Conflicts_axes[z & ~JOY_AXIS] >= 0) {
|
||||
|
||||
@@ -63,7 +63,7 @@ typedef struct config_item {
|
||||
short joy_default; //!< default joystick button bound to action
|
||||
char tab; //!< what tab (category) it belongs in
|
||||
bool hasXSTR; //!< whether we should translate this with an XSTR
|
||||
char *text; //!< describes the action in the config screen
|
||||
const char *text; //!< describes the action in the config screen
|
||||
char type; //!< manner control should be checked in
|
||||
short key_id; //!< actual key bound to action
|
||||
short joy_id; //!< joystick button bound to action
|
||||
@@ -296,8 +296,8 @@ extern int Control_config_overlay_id;
|
||||
extern config_item Control_config[]; //!< Stores the keyboard configuration
|
||||
extern SCP_vector<config_item*> Control_config_presets; // tabled control presets; pointers to config_item arrays
|
||||
extern SCP_vector<SCP_string> Control_config_preset_names; // names for Control_config_presets (identical order of items)
|
||||
extern char **Scan_code_text;
|
||||
extern char **Joy_button_text;
|
||||
extern const char **Scan_code_text;
|
||||
extern const char **Joy_button_text;
|
||||
|
||||
void control_config_common_init(); //!< initialize common control config stuff - call at game startup after localization has been initialized
|
||||
void control_config_common_close(); //!< close common control config stuff - call at game shutdown
|
||||
@@ -311,7 +311,26 @@ void control_config_cancel_exit();
|
||||
void control_config_reset_defaults(int presetnum=-1);
|
||||
int translate_key_to_index(const char *key, bool find_override=true);
|
||||
char *translate_key(char *key);
|
||||
char *textify_scancode(int code);
|
||||
|
||||
/**
|
||||
* @brief Converts the specified key code to a human readable string
|
||||
*
|
||||
* @note The returned value is localized to the current language
|
||||
*
|
||||
* @param code The key code to convert
|
||||
* @return The text representation of the code. The returned value is stored in a temporary location, copy it to your
|
||||
* own buffer if you want to continue using it.
|
||||
*/
|
||||
const char *textify_scancode(int code);
|
||||
|
||||
/**
|
||||
* @note Same as textify_scancode but always returns the same value regardless of current language
|
||||
* @param code The key code to convert
|
||||
* @return The name of the key
|
||||
* @see textify_scancode
|
||||
*/
|
||||
const char *textify_scancode_universal(int code);
|
||||
|
||||
float check_control_timef(int id);
|
||||
int check_control(int id, int key = -1);
|
||||
void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr);
|
||||
|
||||
@@ -199,7 +199,7 @@ config_item Control_config[CCFG_MAX + 1] = {
|
||||
{ -1, -1, -1, false, "", CC_TYPE_TRIGGER, -1, -1, 0, false, false }
|
||||
};
|
||||
|
||||
char *Scan_code_text_german[] = {
|
||||
const char *Scan_code_text_german[] = {
|
||||
"", "Esc", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab",
|
||||
"Q", "W", "E", "R", "T", "Z", "U", "I",
|
||||
@@ -241,7 +241,7 @@ char *Scan_code_text_german[] = {
|
||||
"", "", "", "", "", "", "", "",
|
||||
};
|
||||
|
||||
char *Joy_button_text_german[] = {
|
||||
const char *Joy_button_text_german[] = {
|
||||
"Knopf 1", "Knopf 2", "Knopf 3", "Knopf 4", "Knopf 5", "Knopf 6",
|
||||
"Knopf 7", "Knopf 8", "Knopf 9", "Knopf 10", "Knopf 11", "Knopf 12",
|
||||
"Knopf 13", "Knopf 14", "Knopf 15", "Knopf 16", "Knopf 17", "Knopf 18",
|
||||
@@ -250,7 +250,7 @@ char *Joy_button_text_german[] = {
|
||||
"Knopf 31", "Knopf 32", "Hut Hinten", "Hut Vorne", "Hut Links", "Hut Rechts"
|
||||
};
|
||||
|
||||
char *Scan_code_text_french[] = {
|
||||
const char *Scan_code_text_french[] = {
|
||||
"", "\x90""chap", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "-", "=", "Fl\x82""che Ret.", "Tab",
|
||||
"Q", "W", "E", "R", "T", "Y", "U", "I",
|
||||
@@ -292,7 +292,7 @@ char *Scan_code_text_french[] = {
|
||||
"", "", "", "", "", "", "", "",
|
||||
};
|
||||
|
||||
char *Joy_button_text_french[] = {
|
||||
const char *Joy_button_text_french[] = {
|
||||
"Bouton 1", "Bouton 2", "Bouton 3", "Bouton 4", "Bouton 5", "Bouton 6",
|
||||
"Bouton 7", "Bouton 8", "Bouton 9", "Bouton 10", "Bouton 11", "Bouton 12",
|
||||
"Bouton 13", "Bouton 14", "Bouton 15", "Bouton 16", "Bouton 17", "Bouton 18",
|
||||
@@ -301,7 +301,7 @@ char *Joy_button_text_french[] = {
|
||||
"Bouton 31", "Bouton 32", "Chapeau Arri\x8Are", "Chapeau Avant", "Chapeau Gauche", "Chapeau Droite"
|
||||
};
|
||||
|
||||
char *Scan_code_text_polish[] = {
|
||||
const char *Scan_code_text_polish[] = {
|
||||
"", "Esc", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "-", "=", "Backspace", "Tab",
|
||||
"Q", "W", "E", "R", "T", "Y", "U", "I",
|
||||
@@ -343,7 +343,7 @@ char *Scan_code_text_polish[] = {
|
||||
"", "", "", "", "", "", "", "",
|
||||
};
|
||||
|
||||
char *Joy_button_text_polish[] = {
|
||||
const char *Joy_button_text_polish[] = {
|
||||
"Przyc.1", "Przyc.2", "Przyc.3", "Przyc.4", "Przyc.5", "Przyc.6",
|
||||
"Przyc.7", "Przyc.8", "Przyc.9", "Przyc.10", "Przyc.11", "Przyc.12",
|
||||
"Przyc.13", "Przyc.14", "Przyc.15", "Przyc.16", "Przyc.17", "Przyc.18",
|
||||
@@ -353,7 +353,7 @@ char *Joy_button_text_polish[] = {
|
||||
};
|
||||
|
||||
//! This is the text that is displayed on the screen for the keys a player selects
|
||||
char *Scan_code_text_english[] = {
|
||||
const char *Scan_code_text_english[] = {
|
||||
"", "Esc", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "-", "=", "Backspace", "Tab",
|
||||
"Q", "W", "E", "R", "T", "Y", "U", "I",
|
||||
@@ -395,7 +395,7 @@ char *Scan_code_text_english[] = {
|
||||
"", "", "", "", "", "", "", "",
|
||||
};
|
||||
|
||||
char *Joy_button_text_english[] = {
|
||||
const char *Joy_button_text_english[] = {
|
||||
"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6",
|
||||
"Button 7", "Button 8", "Button 9", "Button 10", "Button 11", "Button 12",
|
||||
"Button 13", "Button 14", "Button 15", "Button 16", "Button 17", "Button 18",
|
||||
@@ -404,8 +404,8 @@ char *Joy_button_text_english[] = {
|
||||
"Button 31", "Button 32", "Hat Back", "Hat Forward", "Hat Left", "Hat Right"
|
||||
};
|
||||
|
||||
char **Scan_code_text = Scan_code_text_english;
|
||||
char **Joy_button_text = Joy_button_text_english;
|
||||
const char **Scan_code_text = Scan_code_text_english;
|
||||
const char **Joy_button_text = Joy_button_text_english;
|
||||
|
||||
SCP_vector<config_item*> Control_config_presets;
|
||||
SCP_vector<SCP_string> Control_config_preset_names;
|
||||
@@ -510,8 +510,8 @@ int translate_key_to_index(const char *key, bool find_override)
|
||||
char *translate_key(char *key)
|
||||
{
|
||||
int index = -1, key_code = -1, joy_code = -1;
|
||||
char *key_text = NULL;
|
||||
char *joy_text = NULL;
|
||||
const char *key_text = NULL;
|
||||
const char *joy_text = NULL;
|
||||
|
||||
static char text[40] = {"None"};
|
||||
|
||||
@@ -553,7 +553,7 @@ char *translate_key(char *key)
|
||||
return text;
|
||||
}
|
||||
|
||||
char *textify_scancode(int code)
|
||||
const char *textify_scancode(int code)
|
||||
{
|
||||
static char text[40];
|
||||
|
||||
@@ -586,6 +586,28 @@ char *textify_scancode(int code)
|
||||
strcat_s(text, Scan_code_text[keycode]);
|
||||
return text;
|
||||
}
|
||||
|
||||
const char *textify_scancode_universal(int code)
|
||||
{
|
||||
if (code < 0)
|
||||
return "None";
|
||||
|
||||
int keycode = code & KEY_MASK;
|
||||
|
||||
static char text[40];
|
||||
*text = 0;
|
||||
if (code & KEY_ALTED && !(keycode == KEY_LALT || keycode == KEY_RALT)) {
|
||||
strcat_s(text, "Alt-");
|
||||
}
|
||||
|
||||
if (code & KEY_SHIFTED && !(keycode == KEY_LSHIFT || keycode == KEY_RSHIFT)) {
|
||||
strcat_s(text, "Shift-");
|
||||
}
|
||||
|
||||
// Always use the english version here
|
||||
strcat_s(text, Scan_code_text_english[keycode]);
|
||||
return text;
|
||||
}
|
||||
//XSTR:ON
|
||||
|
||||
void control_config_common_load_overrides();
|
||||
@@ -811,118 +833,125 @@ void control_config_common_load_overrides()
|
||||
{
|
||||
LoadEnumsIntoMaps();
|
||||
|
||||
if (cf_exists_full("controlconfigdefaults.tbl", CF_TYPE_TABLES)) {
|
||||
read_file_text("controlconfigdefaults.tbl", CF_TYPE_TABLES);
|
||||
} else {
|
||||
read_file_text_from_default(defaults_get_file("controlconfigdefaults.tbl"));
|
||||
}
|
||||
|
||||
reset_parse();
|
||||
|
||||
// start parsing
|
||||
// TODO: Split this out into more helps. Too many tabs!
|
||||
while(optional_string("#ControlConfigOverride")) {
|
||||
config_item *cfg_preset = new config_item[CCFG_MAX + 1];
|
||||
std::copy(Control_config, Control_config + CCFG_MAX + 1, cfg_preset);
|
||||
Control_config_presets.push_back(cfg_preset);
|
||||
|
||||
SCP_string preset_name;
|
||||
if (optional_string("$Name:")) {
|
||||
stuff_string_line(preset_name);
|
||||
try {
|
||||
if (cf_exists_full("controlconfigdefaults.tbl", CF_TYPE_TABLES)) {
|
||||
read_file_text("controlconfigdefaults.tbl", CF_TYPE_TABLES);
|
||||
} else {
|
||||
preset_name = "<unnamed preset>";
|
||||
read_file_text_from_default(defaults_get_file("controlconfigdefaults.tbl"));
|
||||
}
|
||||
Control_config_preset_names.push_back(preset_name);
|
||||
|
||||
while (required_string_either("#End","$Bind Name:")) {
|
||||
const int iBufferLength = 64;
|
||||
char szTempBuffer[iBufferLength];
|
||||
reset_parse();
|
||||
|
||||
required_string("$Bind Name:");
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
// start parsing
|
||||
// TODO: Split this out into more helps. Too many tabs!
|
||||
while(optional_string("#ControlConfigOverride")) {
|
||||
config_item *cfg_preset = new config_item[CCFG_MAX + 1];
|
||||
std::copy(Control_config, Control_config + CCFG_MAX + 1, cfg_preset);
|
||||
Control_config_presets.push_back(cfg_preset);
|
||||
|
||||
const size_t cCntrlAryLength = sizeof(Control_config) / sizeof(Control_config[0]);
|
||||
for (size_t i = 0; i < cCntrlAryLength; ++i) {
|
||||
config_item& r_ccConfig = cfg_preset[i];
|
||||
SCP_string preset_name;
|
||||
if (optional_string("$Name:")) {
|
||||
stuff_string_line(preset_name);
|
||||
} else {
|
||||
preset_name = "<unnamed preset>";
|
||||
}
|
||||
Control_config_preset_names.push_back(preset_name);
|
||||
|
||||
if (!strcmp(szTempBuffer, r_ccConfig.text)) {
|
||||
/**
|
||||
* short key_default;
|
||||
* short joy_default;
|
||||
* char tab;
|
||||
* bool hasXSTR;
|
||||
* char type;
|
||||
*/
|
||||
while (required_string_either("#End","$Bind Name:")) {
|
||||
const int iBufferLength = 64;
|
||||
char szTempBuffer[iBufferLength];
|
||||
|
||||
int iTemp;
|
||||
required_string("$Bind Name:");
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
|
||||
if (optional_string("$Key Default:")) {
|
||||
if (optional_string("NONE")) {
|
||||
r_ccConfig.key_default = (short)-1;
|
||||
} else {
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
r_ccConfig.key_default = (short)mKeyNameToVal[szTempBuffer];
|
||||
const size_t cCntrlAryLength = sizeof(Control_config) / sizeof(Control_config[0]);
|
||||
for (size_t i = 0; i < cCntrlAryLength; ++i) {
|
||||
config_item& r_ccConfig = cfg_preset[i];
|
||||
|
||||
if (!strcmp(szTempBuffer, r_ccConfig.text)) {
|
||||
/**
|
||||
* short key_default;
|
||||
* short joy_default;
|
||||
* char tab;
|
||||
* bool hasXSTR;
|
||||
* char type;
|
||||
*/
|
||||
|
||||
int iTemp;
|
||||
|
||||
if (optional_string("$Key Default:")) {
|
||||
if (optional_string("NONE")) {
|
||||
r_ccConfig.key_default = (short)-1;
|
||||
} else {
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
r_ccConfig.key_default = (short)mKeyNameToVal[szTempBuffer];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("$Joy Default:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.joy_default = (short)iTemp;
|
||||
}
|
||||
if (optional_string("$Joy Default:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.joy_default = (short)iTemp;
|
||||
}
|
||||
|
||||
if (optional_string("$Key Mod Shift:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.key_default |= (iTemp == 1) ? KEY_SHIFTED : 0;
|
||||
}
|
||||
if (optional_string("$Key Mod Shift:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.key_default |= (iTemp == 1) ? KEY_SHIFTED : 0;
|
||||
}
|
||||
|
||||
if (optional_string("$Key Mod Alt:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.key_default |= (iTemp == 1) ? KEY_ALTED : 0;
|
||||
}
|
||||
if (optional_string("$Key Mod Alt:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.key_default |= (iTemp == 1) ? KEY_ALTED : 0;
|
||||
}
|
||||
|
||||
if (optional_string("$Key Mod Ctrl:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.key_default |= (iTemp == 1) ? KEY_CTRLED : 0;
|
||||
}
|
||||
if (optional_string("$Key Mod Ctrl:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.key_default |= (iTemp == 1) ? KEY_CTRLED : 0;
|
||||
}
|
||||
|
||||
if (optional_string("$Category:")) {
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
r_ccConfig.tab = (char)mCCTabNameToVal[szTempBuffer];
|
||||
}
|
||||
if (optional_string("$Category:")) {
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
r_ccConfig.tab = (char)mCCTabNameToVal[szTempBuffer];
|
||||
}
|
||||
|
||||
if (optional_string("$Has XStr:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.hasXSTR = (iTemp == 1);
|
||||
}
|
||||
if (optional_string("$Has XStr:")) {
|
||||
stuff_int(&iTemp);
|
||||
r_ccConfig.hasXSTR = (iTemp == 1);
|
||||
}
|
||||
|
||||
if (optional_string("$Type:")) {
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
r_ccConfig.type = (char)mCCTypeNameToVal[szTempBuffer];
|
||||
}
|
||||
if (optional_string("$Type:")) {
|
||||
stuff_string(szTempBuffer, F_NAME, iBufferLength);
|
||||
r_ccConfig.type = (char)mCCTypeNameToVal[szTempBuffer];
|
||||
}
|
||||
|
||||
if (optional_string("+Disable")) {
|
||||
r_ccConfig.disabled = true;
|
||||
if (optional_string("+Disable")) {
|
||||
r_ccConfig.disabled = true;
|
||||
}
|
||||
if (optional_string("$Disable:")) {
|
||||
stuff_boolean(&r_ccConfig.disabled);
|
||||
}
|
||||
|
||||
// Nerf the buffer now.
|
||||
szTempBuffer[0] = '\0';
|
||||
} else if ((i + 1) == cCntrlAryLength) {
|
||||
error_display(1, "Bind Name not found: %s\n", szTempBuffer);
|
||||
advance_to_eoln(NULL);
|
||||
ignore_white_space();
|
||||
return;
|
||||
}
|
||||
if (optional_string("$Disable:")) {
|
||||
stuff_boolean(&r_ccConfig.disabled);
|
||||
}
|
||||
|
||||
// Nerf the buffer now.
|
||||
szTempBuffer[0] = '\0';
|
||||
} else if ((i + 1) == cCntrlAryLength) {
|
||||
error_display(1, "Bind Name not found: %s\n", szTempBuffer);
|
||||
advance_to_eoln(NULL);
|
||||
ignore_white_space();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required_string("#End");
|
||||
required_string("#End");
|
||||
}
|
||||
}
|
||||
|
||||
catch (const parse::ParseException& e)
|
||||
{
|
||||
mprintf(("TABLES: Unable to parse 'controlconfigdefaults.tbl'! Error message = %s.\n", e.what()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Overwrite the control config with the first preset that was found
|
||||
if (Control_config_presets.size() > 0) {
|
||||
if (!Control_config_presets.empty()) {
|
||||
std::copy(Control_config_presets[0], Control_config_presets[0] + CCFG_MAX + 1, Control_config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "cutscene/Decoder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace cutscene {
|
||||
Decoder::Decoder() : m_decoding(true) {
|
||||
}
|
||||
|
||||
Decoder::~Decoder() {
|
||||
}
|
||||
|
||||
bool Decoder::tryPopAudioData(AudioFramePtr& out) {
|
||||
auto res = m_audioQueue->try_pull_front(out);
|
||||
return res == queue_op_status::success;
|
||||
}
|
||||
|
||||
bool Decoder::tryPopSubtitleData(SubtitleFramePtr& out) {
|
||||
auto res = m_subtitleQueue->try_pull_front(out);
|
||||
return res == queue_op_status::success;
|
||||
}
|
||||
|
||||
bool Decoder::tryPopVideoFrame(VideoFramePtr& out) {
|
||||
auto res = m_videoQueue->try_pull_front(out);
|
||||
return res == queue_op_status::success;
|
||||
}
|
||||
|
||||
void Decoder::initializeQueues(size_t queueSize) {
|
||||
m_queueSize = queueSize;
|
||||
|
||||
m_videoQueue.reset(new sync_bounded_queue<VideoFramePtr>(m_queueSize));
|
||||
m_audioQueue.reset(new sync_bounded_queue<AudioFramePtr>(m_queueSize));
|
||||
m_subtitleQueue.reset(new sync_bounded_queue<SubtitleFramePtr>(m_queueSize));
|
||||
}
|
||||
|
||||
void Decoder::stopDecoder() {
|
||||
m_decoding = false;
|
||||
|
||||
m_videoQueue->close();
|
||||
m_audioQueue->close();
|
||||
m_subtitleQueue->close();
|
||||
}
|
||||
|
||||
bool Decoder::canPushAudioData() {
|
||||
return !isAudioQueueFull();
|
||||
}
|
||||
|
||||
void Decoder::pushAudioData(AudioFramePtr&& data) {
|
||||
Assertion(data, "Invalid audio data passed!");
|
||||
|
||||
try {
|
||||
m_audioQueue->push_back(std::move(data));
|
||||
}
|
||||
catch (sync_queue_is_closed&) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::canPushSubtitleData() {
|
||||
return !isSubtitleQueueFull();
|
||||
}
|
||||
void Decoder::pushSubtitleData(SubtitleFramePtr&& data) {
|
||||
Assertion(data, "Invalid audio data passed!");
|
||||
|
||||
try {
|
||||
m_subtitleQueue->push_back(std::move(data));
|
||||
}
|
||||
catch (sync_queue_is_closed&) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::canPushVideoData() {
|
||||
return !isVideoQueueFull();
|
||||
}
|
||||
|
||||
void Decoder::pushFrameData(VideoFramePtr&& frame) {
|
||||
Assertion(frame, "Invalid video data passed!");
|
||||
|
||||
try {
|
||||
m_videoQueue->push_back(std::move(frame));
|
||||
}
|
||||
catch (sync_queue_is_closed&) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "utils/boost/syncboundedqueue.h"
|
||||
|
||||
namespace cutscene {
|
||||
struct FrameSize {
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
size_t stride = 0;
|
||||
};
|
||||
|
||||
class VideoFrame {
|
||||
protected:
|
||||
VideoFrame() {}
|
||||
|
||||
public:
|
||||
virtual ~VideoFrame() {}
|
||||
|
||||
double frameTime = -1.0;
|
||||
int id = -1;
|
||||
|
||||
FrameSize ySize;
|
||||
FrameSize uvSize;
|
||||
|
||||
struct DataPointers {
|
||||
ubyte* y;
|
||||
ubyte* u;
|
||||
ubyte* v;
|
||||
};
|
||||
|
||||
virtual DataPointers getDataPointers() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Pointer type for passing frame data between threads
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
using FramePtr = std::unique_ptr<T>;
|
||||
|
||||
typedef std::unique_ptr<VideoFrame> VideoFramePtr;
|
||||
|
||||
struct MovieProperties {
|
||||
FrameSize size;
|
||||
|
||||
float fps = -1.0f;
|
||||
};
|
||||
|
||||
struct AudioFrame {
|
||||
SCP_vector<short> audioData;
|
||||
|
||||
int channels = -1;
|
||||
|
||||
int rate = -1;
|
||||
};
|
||||
typedef std::unique_ptr<AudioFrame> AudioFramePtr;
|
||||
|
||||
struct SubtitleFrame {
|
||||
double displayStartTime = -1.0;
|
||||
double displayEndTime = -1.0;
|
||||
|
||||
SCP_string text;
|
||||
};
|
||||
typedef std::unique_ptr<SubtitleFrame> SubtitleFramePtr;
|
||||
|
||||
/**
|
||||
* @brief Abstract class for decoding a video or audio stream
|
||||
*
|
||||
* A decoder maintaines two queues of decoded audio and video frames which are filled from a background thread and
|
||||
* retrieved by the main thread.
|
||||
*/
|
||||
class Decoder {
|
||||
private:
|
||||
std::unique_ptr<sync_bounded_queue<VideoFramePtr>> m_videoQueue;
|
||||
std::unique_ptr<sync_bounded_queue<AudioFramePtr>> m_audioQueue;
|
||||
std::unique_ptr<sync_bounded_queue<SubtitleFramePtr>> m_subtitleQueue;
|
||||
|
||||
bool m_decoding;
|
||||
size_t m_queueSize = 0;
|
||||
|
||||
Decoder(const Decoder&) SCP_DELETED_FUNCTION;
|
||||
|
||||
Decoder& operator=(const Decoder&) SCP_DELETED_FUNCTION;
|
||||
protected:
|
||||
Decoder();
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Decoder();
|
||||
|
||||
/**
|
||||
* @brief Initializes the decoder
|
||||
*
|
||||
* @note A implementation should initialize the datastructures required for decoding here.
|
||||
*
|
||||
* @param fileName The name of the file that should be opened
|
||||
* @return @c true if the initialization was successfull, @c false otherwise
|
||||
*/
|
||||
virtual bool initialize(const SCP_string& fileName) = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the properties of the video
|
||||
* @return The properties
|
||||
*/
|
||||
virtual MovieProperties getProperties() = 0;
|
||||
|
||||
/**
|
||||
* @brief Starts decoding the video
|
||||
*/
|
||||
virtual void startDecoding() = 0;
|
||||
|
||||
/**
|
||||
* @brief Determines if the video has audio
|
||||
* @return @c true if audio is included in the video
|
||||
*/
|
||||
virtual bool hasAudio() = 0;
|
||||
|
||||
virtual bool hasSubtitles() = 0;
|
||||
|
||||
/**
|
||||
* @brief Ends decoding of the video file
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
bool isAudioQueueFull() { return m_audioQueue->size() == m_queueSize; }
|
||||
|
||||
bool isAudioFrameAvailable() { return !m_audioQueue->empty(); }
|
||||
|
||||
size_t getAudioQueueSize() { return m_audioQueue->size(); }
|
||||
|
||||
bool tryPopAudioData(AudioFramePtr&);
|
||||
|
||||
bool isSubtitleQueueFull() { return m_subtitleQueue->size() == m_queueSize; }
|
||||
|
||||
bool isSubtitleFrameAvailable() { return !m_subtitleQueue->empty(); }
|
||||
|
||||
size_t getSubtitleQueueSize() { return m_subtitleQueue->size(); }
|
||||
|
||||
bool tryPopSubtitleData(SubtitleFramePtr&);
|
||||
|
||||
bool isVideoQueueFull() { return m_videoQueue->size() == m_queueSize; }
|
||||
|
||||
bool isVideoFrameAvailable() { return !m_videoQueue->empty(); }
|
||||
|
||||
size_t getVideoQueueSize() { return m_videoQueue->size(); }
|
||||
|
||||
bool tryPopVideoFrame(VideoFramePtr&);
|
||||
|
||||
void stopDecoder();
|
||||
|
||||
bool isDecoding() { return m_decoding; }
|
||||
|
||||
protected:
|
||||
void initializeQueues(size_t queueSize);
|
||||
|
||||
bool canPushAudioData();
|
||||
|
||||
void pushAudioData(AudioFramePtr&& data);
|
||||
|
||||
bool canPushSubtitleData();
|
||||
|
||||
void pushSubtitleData(SubtitleFramePtr&& data);
|
||||
|
||||
bool canPushVideoData();
|
||||
|
||||
void pushFrameData(VideoFramePtr&& frame);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "VideoPresenter.h"
|
||||
|
||||
#include "graphics/matrix.h"
|
||||
|
||||
using namespace cutscene;
|
||||
using namespace cutscene::player;
|
||||
|
||||
namespace {
|
||||
struct movie_vertex {
|
||||
vec2d pos;
|
||||
vec2d uv;
|
||||
};
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
VideoPresenter::VideoPresenter(const MovieProperties& props) {
|
||||
GR_DEBUG_SCOPE("Init video");
|
||||
|
||||
auto w = static_cast<int>(props.size.width);
|
||||
auto h = static_cast<int>(props.size.height);
|
||||
|
||||
// Create buffer textures
|
||||
_yTexBuffer.reset(new uint8_t[w * h]);
|
||||
_ytex = bm_create(8, w, h, _yTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
_uTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_utex = bm_create(8, w / 2, h / 2, _uTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
_vTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_vtex = bm_create(8, w / 2, h / 2, _vTexBuffer.get(), BMP_AABITMAP);
|
||||
|
||||
material_set_movie(&_render_material, _ytex, _utex, _vtex);
|
||||
}
|
||||
|
||||
VideoPresenter::~VideoPresenter() {
|
||||
GR_DEBUG_SCOPE("Deinit video");
|
||||
|
||||
bm_release(_ytex);
|
||||
bm_release(_utex);
|
||||
bm_release(_vtex);
|
||||
|
||||
_ytex = _utex = _vtex = -1;
|
||||
}
|
||||
|
||||
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
GR_DEBUG_SCOPE("Update video frame");
|
||||
auto ptrs = frame->getDataPointers();
|
||||
|
||||
memcpy(_yTexBuffer.get(), ptrs.y, frame->ySize.stride * frame->ySize.height);
|
||||
memcpy(_uTexBuffer.get(), ptrs.u, frame->uvSize.stride * frame->uvSize.height);
|
||||
memcpy(_vTexBuffer.get(), ptrs.v, frame->uvSize.stride * frame->uvSize.height);
|
||||
|
||||
gr_update_texture(_ytex, 8, _yTexBuffer.get(), (int) frame->ySize.width, (int) frame->ySize.height);
|
||||
gr_update_texture(_utex, 8, _uTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
gr_update_texture(_vtex, 8, _vTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
}
|
||||
|
||||
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
GR_DEBUG_SCOPE("Draw video frame");
|
||||
|
||||
movie_vertex vertex_data[4];
|
||||
|
||||
vertex_data[0].pos.x = x1;
|
||||
vertex_data[0].pos.y = y1;
|
||||
vertex_data[0].uv.x = 0.0f;
|
||||
vertex_data[0].uv.y = 0.0f;
|
||||
|
||||
vertex_data[1].pos.x = x1;
|
||||
vertex_data[1].pos.y = y2;
|
||||
vertex_data[1].uv.x = 0.0f;
|
||||
vertex_data[1].uv.y = 1.0f;
|
||||
|
||||
vertex_data[2].pos.x = x2;
|
||||
vertex_data[2].pos.y = y1;
|
||||
vertex_data[2].uv.x = 1.0f;
|
||||
vertex_data[2].uv.y = 0.0f;
|
||||
|
||||
vertex_data[3].pos.x = x2;
|
||||
vertex_data[3].pos.y = y2;
|
||||
vertex_data[3].uv.x = 1.0f;
|
||||
vertex_data[3].uv.y = 1.0f;
|
||||
|
||||
// Use the immediate buffer for storing our data since that is exactly what we need
|
||||
auto offset = gr_add_to_immediate_buffer(sizeof(vertex_data), vertex_data);
|
||||
|
||||
vertex_layout layout;
|
||||
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, uv));
|
||||
|
||||
gr_render_movie(&_render_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/material.h"
|
||||
#include "cutscene/Decoder.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
|
||||
class VideoPresenter {
|
||||
int _ytex = -1;
|
||||
std::unique_ptr<uint8_t[]> _yTexBuffer;
|
||||
|
||||
int _utex = -1;
|
||||
std::unique_ptr<uint8_t[]> _uTexBuffer;
|
||||
|
||||
int _vtex = -1;
|
||||
std::unique_ptr<uint8_t[]> _vTexBuffer;
|
||||
|
||||
movie_material _render_material;
|
||||
public:
|
||||
explicit VideoPresenter(const MovieProperties& props);
|
||||
|
||||
// Disallow copying
|
||||
VideoPresenter(const VideoPresenter&) = delete;
|
||||
VideoPresenter& operator=(const VideoPresenter&) = delete;
|
||||
|
||||
virtual ~VideoPresenter();
|
||||
|
||||
void uploadVideoFrame(const VideoFramePtr& frame);
|
||||
|
||||
void displayFrame(float x1, float y1, float x2, float y2);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
+197
-215
@@ -5,7 +5,7 @@
|
||||
* or otherwise commercially exploit the source or things you created based on the
|
||||
* source.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
extern int Cmdline_nomovies;
|
||||
|
||||
|
||||
char *Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
|
||||
"ViewFootage",
|
||||
"2_ViewFootage"
|
||||
const char* Cutscene_bitmap_name[GR_NUM_RESOLUTIONS] = {
|
||||
"ViewFootage",
|
||||
"2_ViewFootage"
|
||||
};
|
||||
char *Cutscene_mask_name[GR_NUM_RESOLUTIONS] = {
|
||||
"ViewFootage-m",
|
||||
"2_ViewFootage-m"
|
||||
const char* Cutscene_mask_name[GR_NUM_RESOLUTIONS] = {
|
||||
"ViewFootage-m",
|
||||
"2_ViewFootage-m"
|
||||
};
|
||||
|
||||
int Description_index;
|
||||
@@ -40,8 +40,9 @@ SCP_vector<cutscene_info> Cutscenes;
|
||||
|
||||
void cutscene_close()
|
||||
{
|
||||
for(SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
|
||||
if(cut->description != NULL) {
|
||||
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
|
||||
if (cut->description != NULL)
|
||||
{
|
||||
vm_free(cut->description);
|
||||
cut->description = NULL;
|
||||
}
|
||||
@@ -81,19 +82,24 @@ void cutscene_init()
|
||||
cutinfo.description = vm_strdup(buf);
|
||||
|
||||
if (optional_string("$cd:"))
|
||||
stuff_int(&cutinfo.cd);
|
||||
else
|
||||
cutinfo.cd = 0;
|
||||
{
|
||||
// Option isn't needed anymore. Consume the token and ignore it
|
||||
|
||||
int junk;
|
||||
stuff_int(&junk);
|
||||
}
|
||||
|
||||
cutinfo.viewable = false;
|
||||
|
||||
if (isFirstCutscene) {
|
||||
if (isFirstCutscene)
|
||||
{
|
||||
isFirstCutscene = false;
|
||||
// The original code assumes the first movie is the intro, so always viewable
|
||||
cutinfo.viewable = true;
|
||||
}
|
||||
|
||||
if (optional_string("$Always Viewable:")) {
|
||||
if (optional_string("$Always Viewable:"))
|
||||
{
|
||||
stuff_boolean(&cutinfo.viewable);
|
||||
}
|
||||
|
||||
@@ -109,44 +115,34 @@ void cutscene_init()
|
||||
}
|
||||
}
|
||||
|
||||
// function to return 0 based index of which CD a particular movie is on
|
||||
// returns -1 on failure.
|
||||
int cutscenes_get_cd_num( char *filename )
|
||||
{
|
||||
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) {
|
||||
if ( !stricmp(cut->filename, filename) ) {
|
||||
return (cut->cd - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// marks a cutscene as viewable
|
||||
void cutscene_mark_viewable(char *filename)
|
||||
void cutscene_mark_viewable(const char* filename)
|
||||
{
|
||||
char cut_file[MAX_FILENAME_LEN];
|
||||
char file[MAX_FILENAME_LEN];
|
||||
|
||||
Assert(filename!=NULL);
|
||||
Assert(filename != NULL);
|
||||
|
||||
// strip off extension
|
||||
strcpy_s( file, filename );
|
||||
char *p = strchr( file, '.' );
|
||||
if ( p ) {
|
||||
strcpy_s(file, filename);
|
||||
char* p = strchr(file, '.');
|
||||
if (p)
|
||||
{
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
// change to lower case
|
||||
strlwr(file);
|
||||
int i = 0;
|
||||
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut) {
|
||||
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut)
|
||||
{
|
||||
// change the cutscene file name to lower case
|
||||
strcpy_s(cut_file, cut->filename);
|
||||
strlwr(cut_file);
|
||||
|
||||
// see if the stripped filename matches the cutscene filename
|
||||
if ( strstr(cut_file, file) != NULL ) {
|
||||
if (strstr(cut_file, file) != NULL)
|
||||
{
|
||||
cut->viewable = true;
|
||||
return;
|
||||
}
|
||||
@@ -156,17 +152,17 @@ void cutscene_mark_viewable(char *filename)
|
||||
Warning(LOCATION, "Could not find cutscene '%s' in listing; cannot mark it viewable...", filename);
|
||||
}
|
||||
|
||||
#define NUM_BUTTONS 8
|
||||
#define NUM_BUTTONS 8
|
||||
|
||||
#define TECH_DATABASE_BUTTON 0
|
||||
#define SIMULATOR_BUTTON 1
|
||||
#define CUTSCENES_BUTTON 2
|
||||
#define CREDITS_BUTTON 3
|
||||
#define TECH_DATABASE_BUTTON 0
|
||||
#define SIMULATOR_BUTTON 1
|
||||
#define CUTSCENES_BUTTON 2
|
||||
#define CREDITS_BUTTON 3
|
||||
|
||||
#define SCROLL_UP_BUTTON 4
|
||||
#define SCROLL_DOWN_BUTTON 5
|
||||
#define PLAY_BUTTON 6
|
||||
#define EXIT_BUTTON 7
|
||||
#define SCROLL_UP_BUTTON 4
|
||||
#define SCROLL_DOWN_BUTTON 5
|
||||
#define PLAY_BUTTON 6
|
||||
#define EXIT_BUTTON 7
|
||||
|
||||
static SCP_vector<int> Cutscene_list;
|
||||
//static int Stats_scroll_offset; // not used - taylor
|
||||
@@ -177,155 +173,102 @@ static UI_BUTTON List_region;
|
||||
static UI_WINDOW Ui_window;
|
||||
|
||||
static ui_button_info Buttons[GR_NUM_RESOLUTIONS][NUM_BUTTONS] = {
|
||||
{ // GR_640
|
||||
ui_button_info("TDB_00", 7, 3, 37, 7, 0), // tech database 1
|
||||
ui_button_info("TDB_01", 7, 18, 37, 23, 1), // tech database 2
|
||||
ui_button_info("TDB_02", 7, 34, 37, 38, 2), // tech database 3
|
||||
ui_button_info("TDB_03", 7, 49, 37, 54, 3), // tech database 4
|
||||
{ // GR_640
|
||||
ui_button_info("TDB_00", 7, 3, 37, 7, 0), // tech database 1
|
||||
ui_button_info("TDB_01", 7, 18, 37, 23, 1), // tech database 2
|
||||
ui_button_info("TDB_02", 7, 34, 37, 38, 2), // tech database 3
|
||||
ui_button_info("TDB_03", 7, 49, 37, 54, 3), // tech database 4
|
||||
|
||||
ui_button_info("VFB_04", 6, 318, -1, -1, 4), // scroll up
|
||||
ui_button_info("VFB_05", 36, 318, -1, -1, 5), // scroll down
|
||||
ui_button_info("VFB_06", 578, 319, 587, 366, 6), // play
|
||||
ui_button_info("VFB_07", 574, 431, 587, 413, 7), // exit
|
||||
},
|
||||
{ // GR_1024
|
||||
ui_button_info("2_TDB_00", 12, 5, 59, 12, 0), // tech database 1
|
||||
ui_button_info("2_TDB_01", 12, 31, 59, 37, 1), // tech database 2
|
||||
ui_button_info("2_TDB_02", 12, 56, 59, 62, 2), // tech database 3
|
||||
ui_button_info("2_TDB_03", 12, 81, 59, 88, 3), // tech database 4
|
||||
ui_button_info("VFB_04", 6, 318, -1, -1, 4), // scroll up
|
||||
ui_button_info("VFB_05", 36, 318, -1, -1, 5), // scroll down
|
||||
ui_button_info("VFB_06", 578, 319, 587, 366, 6), // play
|
||||
ui_button_info("VFB_07", 574, 431, 587, 413, 7), // exit
|
||||
},
|
||||
{ // GR_1024
|
||||
ui_button_info("2_TDB_00", 12, 5, 59, 12, 0), // tech database 1
|
||||
ui_button_info("2_TDB_01", 12, 31, 59, 37, 1), // tech database 2
|
||||
ui_button_info("2_TDB_02", 12, 56, 59, 62, 2), // tech database 3
|
||||
ui_button_info("2_TDB_03", 12, 81, 59, 88, 3), // tech database 4
|
||||
|
||||
ui_button_info("2_VFB_04", 9, 509, -1, -1, 4), // scroll up
|
||||
ui_button_info("2_VFB_05", 58, 509, -1, -1, 5), // scroll down
|
||||
ui_button_info("2_VFB_06", 925, 511, 940, 586, 6), // play
|
||||
ui_button_info("2_VFB_07", 918, 689, 940, 661, 7), // exit
|
||||
}
|
||||
ui_button_info("2_VFB_04", 9, 509, -1, -1, 4), // scroll up
|
||||
ui_button_info("2_VFB_05", 58, 509, -1, -1, 5), // scroll down
|
||||
ui_button_info("2_VFB_06", 925, 511, 940, 586, 6), // play
|
||||
ui_button_info("2_VFB_07", 918, 689, 940, 661, 7), // exit
|
||||
}
|
||||
};
|
||||
|
||||
// text
|
||||
#define NUM_CUTSCENE_TEXT 6
|
||||
#define NUM_CUTSCENE_TEXT 6
|
||||
UI_XSTR Cutscene_text[GR_NUM_RESOLUTIONS][NUM_CUTSCENE_TEXT] = {
|
||||
{ // GR_640
|
||||
{"Technical Database", 1055, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][TECH_DATABASE_BUTTON].button },
|
||||
{"Mission Simulator", 1056, 37, 23, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][SIMULATOR_BUTTON].button },
|
||||
{"Cutscenes", 1057, 37, 38, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CUTSCENES_BUTTON].button },
|
||||
{"Credits", 1058, 37, 54, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CREDITS_BUTTON].button },
|
||||
|
||||
{"Play", 1335, 587, 366, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][PLAY_BUTTON].button },
|
||||
{"Exit", 1419, 587, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][EXIT_BUTTON].button },
|
||||
},
|
||||
{ // GR_1024
|
||||
{"Technical Database", 1055, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][TECH_DATABASE_BUTTON].button },
|
||||
{"Mission Simulator", 1056, 59, 37, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][SIMULATOR_BUTTON].button },
|
||||
{"Cutscenes", 1057, 59, 62, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CUTSCENES_BUTTON].button },
|
||||
{"Credits", 1058, 59, 88, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CREDITS_BUTTON].button },
|
||||
|
||||
{"Play", 1335, 940, 586, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][PLAY_BUTTON].button },
|
||||
{"Exit", 1419, 940, 661, UI_XSTR_COLOR_PINK, -1, &Buttons[1][EXIT_BUTTON].button },
|
||||
}
|
||||
{ // GR_640
|
||||
{"Technical Database", 1055, 37, 7, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][TECH_DATABASE_BUTTON].button},
|
||||
{"Mission Simulator", 1056, 37, 23, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][SIMULATOR_BUTTON].button},
|
||||
{"Cutscenes", 1057, 37, 38, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CUTSCENES_BUTTON].button},
|
||||
{"Credits", 1058, 37, 54, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][CREDITS_BUTTON].button},
|
||||
|
||||
{"Play", 1335, 587, 366, UI_XSTR_COLOR_GREEN, -1, &Buttons[0][PLAY_BUTTON].button},
|
||||
{"Exit", 1419, 587, 413, UI_XSTR_COLOR_PINK, -1, &Buttons[0][EXIT_BUTTON].button},
|
||||
},
|
||||
{ // GR_1024
|
||||
{"Technical Database", 1055, 59, 12, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][TECH_DATABASE_BUTTON].button},
|
||||
{"Mission Simulator", 1056, 59, 37, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][SIMULATOR_BUTTON].button},
|
||||
{"Cutscenes", 1057, 59, 62, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CUTSCENES_BUTTON].button},
|
||||
{"Credits", 1058, 59, 88, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][CREDITS_BUTTON].button},
|
||||
|
||||
{"Play", 1335, 940, 586, UI_XSTR_COLOR_GREEN, -1, &Buttons[1][PLAY_BUTTON].button},
|
||||
{"Exit", 1419, 940, 661, UI_XSTR_COLOR_PINK, -1, &Buttons[1][EXIT_BUTTON].button},
|
||||
}
|
||||
};
|
||||
|
||||
int Cutscene_list_coords[GR_NUM_RESOLUTIONS][4] = {
|
||||
{ // GR_640
|
||||
9, 117, 621, 198
|
||||
},
|
||||
{ // GR_1024
|
||||
14, 188, 994, 316
|
||||
}
|
||||
{ // GR_640
|
||||
9, 117, 621, 198
|
||||
},
|
||||
{ // GR_1024
|
||||
14, 188, 994, 316
|
||||
}
|
||||
};
|
||||
|
||||
int Cutscene_desc_coords[GR_NUM_RESOLUTIONS][4] = {
|
||||
{ // GR_640
|
||||
9, 378, 484, 73
|
||||
},
|
||||
{ // GR_1024
|
||||
14, 605, 775, 117
|
||||
}
|
||||
{ // GR_640
|
||||
9, 378, 484, 73
|
||||
},
|
||||
{ // GR_1024
|
||||
14, 605, 775, 117
|
||||
}
|
||||
};
|
||||
|
||||
#define MAX_TEXT_LINES 20
|
||||
#define MAX_TEXT_LINES 20
|
||||
int Cutscene_max_text_lines[GR_NUM_RESOLUTIONS] = {
|
||||
10,
|
||||
MAX_TEXT_LINES
|
||||
10,
|
||||
MAX_TEXT_LINES
|
||||
};
|
||||
#define MAX_TEXT_LINE_LEN 256
|
||||
#define MAX_TEXT_LINE_LEN 256
|
||||
|
||||
static int Text_size;
|
||||
static int Text_offset = 0;
|
||||
static int Text_line_size[MAX_TEXT_LINES];
|
||||
static const char *Text_lines[MAX_TEXT_LINES];
|
||||
static const char* Text_lines[MAX_TEXT_LINES];
|
||||
|
||||
|
||||
int cutscenes_validate_cd(char *mve_name, int prompt_for_cd)
|
||||
{
|
||||
int cd_present = 0;
|
||||
int cd_drive_num;
|
||||
int cd_mve_is_on;
|
||||
char volume_name[MAX_PATH_LEN];
|
||||
|
||||
int num_attempts = 0;
|
||||
|
||||
while(1) {
|
||||
int path_set_ok;
|
||||
|
||||
cd_mve_is_on = cutscenes_get_cd_num(mve_name);
|
||||
if ((cd_mve_is_on != 0) && (cd_mve_is_on != 1) && (cd_mve_is_on != 2)) {
|
||||
cd_present = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(volume_name, NOX("FREESPACE2_%c"), '1' + cd_mve_is_on);
|
||||
|
||||
cd_drive_num = find_freespace_cd(volume_name);
|
||||
path_set_ok = set_cdrom_path(cd_drive_num);
|
||||
|
||||
if ( path_set_ok ) {
|
||||
cd_present = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !prompt_for_cd ) {
|
||||
cd_present = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// no CD found, so prompt user
|
||||
char popup_msg[256];
|
||||
int popup_rval;
|
||||
|
||||
sprintf(popup_msg, XSTR( "Movie not found\n\nInsert FreeSpace CD #%d to continue", 203), cd_mve_is_on+1);
|
||||
|
||||
popup_rval = popup(PF_BODY_BIG, 2, POPUP_CANCEL, POPUP_OK, popup_msg);
|
||||
if ( popup_rval != 1 ) {
|
||||
cd_present = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( num_attempts++ > 5 ) {
|
||||
cd_present = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cd_present;
|
||||
}
|
||||
|
||||
void cutscenes_screen_play()
|
||||
{
|
||||
char name[MAX_FILENAME_LEN]; // *full_name
|
||||
int which_cutscene;
|
||||
|
||||
Assert( (Selected_line >= 0) && (Selected_line < (int)Cutscene_list.size()) );
|
||||
Assert((Selected_line >= 0) && (Selected_line < (int) Cutscene_list.size()));
|
||||
which_cutscene = Cutscene_list[Selected_line];
|
||||
|
||||
strcpy_s(name, Cutscenes[which_cutscene].filename );
|
||||
strcpy_s(name, Cutscenes[which_cutscene].filename);
|
||||
// full_name = cf_add_ext(name, NOX(".mve"));
|
||||
|
||||
main_hall_stop_music(true);
|
||||
main_hall_stop_ambient();
|
||||
int rval = movie_play(name);
|
||||
auto rval = movie::play(name);
|
||||
main_hall_start_music();
|
||||
|
||||
if ( !rval ) {
|
||||
if (!rval)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
if (Cmdline_nomovies)
|
||||
@@ -333,20 +276,21 @@ void cutscenes_screen_play()
|
||||
else
|
||||
sprintf(str, XSTR("Unable to play movie %s.", 204), Cutscenes[which_cutscene].name);
|
||||
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str );
|
||||
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, str);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void cutscenes_screen_scroll_line_up()
|
||||
{
|
||||
if (Selected_line) {
|
||||
if (Selected_line)
|
||||
{
|
||||
Selected_line--;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
|
||||
|
||||
if (Selected_line < Scroll_offset)
|
||||
Scroll_offset = Selected_line;
|
||||
}
|
||||
@@ -355,15 +299,17 @@ void cutscenes_screen_scroll_line_down()
|
||||
{
|
||||
int h;
|
||||
|
||||
if (Selected_line < (int)Cutscene_list.size() - 1) {
|
||||
if (Selected_line < (int) Cutscene_list.size() - 1)
|
||||
{
|
||||
Selected_line++;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
|
||||
|
||||
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
|
||||
if (Selected_line >= Scroll_offset + h){
|
||||
if (Selected_line >= Scroll_offset + h)
|
||||
{
|
||||
Scroll_offset++;
|
||||
}
|
||||
}
|
||||
@@ -372,17 +318,20 @@ void cutscenes_screen_scroll_screen_up()
|
||||
{
|
||||
int h;
|
||||
|
||||
if (Scroll_offset) {
|
||||
if (Scroll_offset)
|
||||
{
|
||||
Scroll_offset--;
|
||||
Assert(Selected_line > Scroll_offset);
|
||||
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
|
||||
while (Selected_line >= Scroll_offset + h){
|
||||
while (Selected_line >= Scroll_offset + h)
|
||||
{
|
||||
Selected_line--;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
@@ -392,21 +341,25 @@ void cutscenes_screen_scroll_screen_down()
|
||||
int h;
|
||||
|
||||
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
|
||||
if (Scroll_offset + h < (int)Cutscene_list.size()) {
|
||||
if (Scroll_offset + h < (int) Cutscene_list.size())
|
||||
{
|
||||
Scroll_offset++;
|
||||
if (Selected_line < Scroll_offset){
|
||||
if (Selected_line < Scroll_offset)
|
||||
{
|
||||
Selected_line = Scroll_offset;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
int cutscenes_screen_button_pressed(int n)
|
||||
{
|
||||
switch (n) {
|
||||
switch (n)
|
||||
{
|
||||
case TECH_DATABASE_BUTTON:
|
||||
gamesnd_play_iface(SND_SWITCH_SCREENS);
|
||||
gameseq_post_event(GS_EVENT_TECH_MENU);
|
||||
@@ -447,12 +400,13 @@ int cutscenes_screen_button_pressed(int n)
|
||||
void cutscenes_screen_init()
|
||||
{
|
||||
int i;
|
||||
ui_button_info *b;
|
||||
ui_button_info* b;
|
||||
|
||||
Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0);
|
||||
Ui_window.set_mask_bmap(Cutscene_mask_name[gr_screen.res]);
|
||||
|
||||
for (i=0; i<NUM_BUTTONS; i++) {
|
||||
for (i = 0; i < NUM_BUTTONS; i++)
|
||||
{
|
||||
b = &Buttons[gr_screen.res][i];
|
||||
|
||||
b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
|
||||
@@ -463,15 +417,17 @@ void cutscenes_screen_init()
|
||||
}
|
||||
|
||||
// add xstrs
|
||||
for(i=0; i<NUM_CUTSCENE_TEXT; i++){
|
||||
for (i = 0; i < NUM_CUTSCENE_TEXT; i++)
|
||||
{
|
||||
Ui_window.add_XSTR(&Cutscene_text[gr_screen.res][i]);
|
||||
}
|
||||
|
||||
Buttons[gr_screen.res][EXIT_BUTTON].button.set_hotkey(KEY_CTRLED | KEY_ENTER);
|
||||
Buttons[gr_screen.res][SCROLL_UP_BUTTON].button.set_hotkey(KEY_PAGEUP);
|
||||
Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
|
||||
Buttons[gr_screen.res][SCROLL_DOWN_BUTTON].button.set_hotkey(KEY_PAGEDOWN);
|
||||
|
||||
List_region.create(&Ui_window, "", Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1], Cutscene_list_coords[gr_screen.res][2], Cutscene_list_coords[gr_screen.res][3], 0, 1);
|
||||
List_region.create(&Ui_window, "", Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1],
|
||||
Cutscene_list_coords[gr_screen.res][2], Cutscene_list_coords[gr_screen.res][3], 0, 1);
|
||||
List_region.hide();
|
||||
|
||||
// set up hotkeys for buttons so we draw the correct animation frame when a key is pressed
|
||||
@@ -482,11 +438,13 @@ void cutscenes_screen_init()
|
||||
Scroll_offset = Selected_line = 0;
|
||||
Description_index = -1;
|
||||
|
||||
Cutscene_list.clear();
|
||||
|
||||
Cutscene_list.clear();
|
||||
|
||||
int u = 0;
|
||||
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut, u++) {
|
||||
if ( (*cut).viewable ) {
|
||||
for (SCP_vector<cutscene_info>::iterator cut = Cutscenes.begin(); cut != Cutscenes.end(); ++cut, u++)
|
||||
{
|
||||
if ((*cut).viewable)
|
||||
{
|
||||
Cutscene_list.push_back(u);
|
||||
}
|
||||
}
|
||||
@@ -507,7 +465,8 @@ void cutscenes_screen_do_frame()
|
||||
int select_tease_line = -1;
|
||||
|
||||
k = Ui_window.process();
|
||||
switch (k) {
|
||||
switch (k)
|
||||
{
|
||||
case KEY_DOWN: // select next line
|
||||
cutscenes_screen_scroll_line_down();
|
||||
break;
|
||||
@@ -542,96 +501,117 @@ void cutscenes_screen_do_frame()
|
||||
gameseq_post_event(GS_EVENT_OPTIONS_MENU);
|
||||
break;
|
||||
|
||||
// the "show-all" hotkey
|
||||
// the "show-all" hotkey
|
||||
case KEY_CTRLED | KEY_SHIFTED | KEY_S:
|
||||
{
|
||||
Cutscene_list.clear();
|
||||
Cutscene_list.clear();
|
||||
size_t size = Cutscenes.size();
|
||||
for (size_t t = 0; t < size; t++) {
|
||||
Cutscene_list.push_back((int)t);
|
||||
for (size_t t = 0; t < size; t++)
|
||||
{
|
||||
Cutscene_list.push_back((int) t);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} // end switch
|
||||
} // end switch
|
||||
|
||||
for (i=0; i<NUM_BUTTONS; i++){
|
||||
if (Buttons[gr_screen.res][i].button.pressed()){
|
||||
if (cutscenes_screen_button_pressed(i)){
|
||||
for (i = 0; i < NUM_BUTTONS; i++)
|
||||
{
|
||||
if (Buttons[gr_screen.res][i].button.pressed())
|
||||
{
|
||||
if (cutscenes_screen_button_pressed(i))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (List_region.button_down()) {
|
||||
if (List_region.button_down())
|
||||
{
|
||||
List_region.get_mouse_pos(NULL, &y);
|
||||
z = Scroll_offset + y / font_height;
|
||||
if ((z >= 0) && (z < (int)Cutscene_list.size()))
|
||||
if ((z >= 0) && (z < (int) Cutscene_list.size()))
|
||||
select_tease_line = z;
|
||||
}
|
||||
|
||||
if (List_region.pressed()) {
|
||||
|
||||
if (List_region.pressed())
|
||||
{
|
||||
List_region.get_mouse_pos(NULL, &y);
|
||||
z = Scroll_offset + y / font_height;
|
||||
if ((z >= 0) && (z < (int)Cutscene_list.size()))
|
||||
if ((z >= 0) && (z < (int) Cutscene_list.size()))
|
||||
Selected_line = z;
|
||||
}
|
||||
|
||||
GR_MAYBE_CLEAR_RES(Background_bitmap);
|
||||
if (Background_bitmap >= 0) {
|
||||
if (Background_bitmap >= 0)
|
||||
{
|
||||
gr_set_bitmap(Background_bitmap);
|
||||
gr_bitmap(0, 0, GR_RESIZE_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
Ui_window.draw();
|
||||
|
||||
for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
|
||||
if (Buttons[gr_screen.res][i].button.button_down()){
|
||||
for (i = TECH_DATABASE_BUTTON; i <= CREDITS_BUTTON; i++)
|
||||
{
|
||||
if (Buttons[gr_screen.res][i].button.button_down())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > CREDITS_BUTTON){
|
||||
if (i > CREDITS_BUTTON)
|
||||
{
|
||||
Buttons[gr_screen.res][CUTSCENES_BUTTON].button.draw_forced(2);
|
||||
}
|
||||
|
||||
y = 0;
|
||||
z = Scroll_offset;
|
||||
while (y + font_height <= Cutscene_list_coords[gr_screen.res][3]) {
|
||||
if (z >= (int)Cutscene_list.size()){
|
||||
while (y + font_height <= Cutscene_list_coords[gr_screen.res][3])
|
||||
{
|
||||
if (z >= (int) Cutscene_list.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (z == Selected_line){
|
||||
if (z == Selected_line)
|
||||
{
|
||||
gr_set_color_fast(&Color_text_selected);
|
||||
} else if (z == select_tease_line) {
|
||||
} else if (z == select_tease_line)
|
||||
{
|
||||
gr_set_color_fast(&Color_text_subselected);
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
gr_set_color_fast(&Color_text_normal);
|
||||
}
|
||||
|
||||
gr_printf_menu(Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1] + y, Cutscenes[Cutscene_list[z]].name);
|
||||
gr_printf_menu(Cutscene_list_coords[gr_screen.res][0], Cutscene_list_coords[gr_screen.res][1] + y,
|
||||
"%s", Cutscenes[Cutscene_list[z]].name);
|
||||
|
||||
y += font_height;
|
||||
z++;
|
||||
}
|
||||
|
||||
if (Description_index != Selected_line) {
|
||||
char *src = NULL;
|
||||
if (Description_index != Selected_line)
|
||||
{
|
||||
char* src = NULL;
|
||||
|
||||
Description_index = Selected_line;
|
||||
Text_size = 0;
|
||||
if ( Description_index < (int)Cutscene_list.size( ) &&
|
||||
(int)Cutscene_list[ Description_index ] < (int)Cutscenes.size( ) ) {
|
||||
if (Description_index < (int) Cutscene_list.size() &&
|
||||
(int) Cutscene_list[Description_index] < (int) Cutscenes.size())
|
||||
{
|
||||
src = Cutscenes[Cutscene_list[Description_index]].description;
|
||||
if (src) {
|
||||
Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines, Cutscene_max_text_lines[gr_screen.res]);
|
||||
if (src)
|
||||
{
|
||||
Text_size = split_str(src, Cutscene_desc_coords[gr_screen.res][2], Text_line_size, Text_lines,
|
||||
Cutscene_max_text_lines[gr_screen.res]);
|
||||
Assert(Text_size >= 0 && Text_size < Cutscene_max_text_lines[gr_screen.res]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Description_index >= 0) {
|
||||
if (Description_index >= 0)
|
||||
{
|
||||
int len;
|
||||
char line[MAX_TEXT_LINE_LEN + 1];
|
||||
|
||||
@@ -639,8 +619,9 @@ void cutscenes_screen_do_frame()
|
||||
|
||||
y = 0;
|
||||
z = Text_offset;
|
||||
while (y + font_height <= Cutscene_desc_coords[gr_screen.res][3]) {
|
||||
if (z >= Text_size || z >= MAX_TEXT_LINES-1)
|
||||
while (y + font_height <= Cutscene_desc_coords[gr_screen.res][3])
|
||||
{
|
||||
if (z >= Text_size || z >= MAX_TEXT_LINES - 1)
|
||||
break;
|
||||
|
||||
len = Text_line_size[z];
|
||||
@@ -649,7 +630,8 @@ void cutscenes_screen_do_frame()
|
||||
|
||||
strncpy(line, Text_lines[z], len);
|
||||
line[len] = 0;
|
||||
gr_string(Cutscene_desc_coords[gr_screen.res][0], Cutscene_desc_coords[gr_screen.res][1] + y, line, GR_RESIZE_MENU);
|
||||
gr_string(Cutscene_desc_coords[gr_screen.res][0], Cutscene_desc_coords[gr_screen.res][1] + y, line,
|
||||
GR_RESIZE_MENU);
|
||||
|
||||
y += font_height;
|
||||
z++;
|
||||
|
||||
@@ -13,25 +13,33 @@
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
typedef struct cutscene_info {
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
char name[NAME_LENGTH];
|
||||
char *description;
|
||||
int cd;
|
||||
bool viewable;
|
||||
typedef struct cutscene_info
|
||||
{
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
char name[NAME_LENGTH];
|
||||
char* description;
|
||||
bool viewable;
|
||||
} cutscene_info;
|
||||
|
||||
#if SCP_COMPILER_IS_GNU
|
||||
#pragma GCC diagnostic push
|
||||
// This suppresses a GCC bug where it thinks that the Cutscenes from the enum class below shadows a global variable
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
extern SCP_vector<cutscene_info> Cutscenes;
|
||||
#if SCP_COMPILER_IS_GNU
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// initializa table data
|
||||
void cutscene_init();
|
||||
int cutscene_get_cd_num(char *filename);
|
||||
|
||||
void cutscenes_screen_init();
|
||||
|
||||
void cutscenes_screen_close();
|
||||
|
||||
void cutscenes_screen_do_frame();
|
||||
|
||||
int cutscenes_validate_cd(char *mve_name, int prompt_for_cd = 1);
|
||||
void cutscene_mark_viewable(char *filename);
|
||||
void cutscene_mark_viewable(const char* filename);
|
||||
|
||||
#endif
|
||||
@@ -1,570 +0,0 @@
|
||||
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
extern int g_width, g_height;
|
||||
extern void *g_vBackBuf1, *g_vBackBuf2;
|
||||
|
||||
/* 16 bit decoding routines */
|
||||
|
||||
static ushort *backBuf1, *backBuf2;
|
||||
static int lookup_initialized;
|
||||
|
||||
static void dispatchDecoder16(ushort **pFrame, ubyte codeType, ubyte **pData, ubyte **pOffData, int *pDataRemain, int *curXb, int *curYb);
|
||||
static void genLoopkupTable();
|
||||
|
||||
void decodeFrame16(ubyte *pFrame, ubyte *pMap, int mapRemain, unsigned char *pData, int dataRemain)
|
||||
{
|
||||
ubyte *pOrig, *pOffData, op;
|
||||
ushort offset;
|
||||
int length = 0, i, j, xb, yb;
|
||||
|
||||
if (!lookup_initialized) {
|
||||
genLoopkupTable();
|
||||
}
|
||||
|
||||
backBuf1 = (ushort *)g_vBackBuf1;
|
||||
backBuf2 = (ushort *)g_vBackBuf2;
|
||||
|
||||
xb = g_width >> 3;
|
||||
yb = g_height >> 3;
|
||||
|
||||
offset = pData[0]|(pData[1]<<8);
|
||||
|
||||
pOffData = pData + offset;
|
||||
|
||||
pData += 2;
|
||||
|
||||
pOrig = pData;
|
||||
length = offset - 2; /*dataRemain-2;*/
|
||||
|
||||
for (j=0; j<yb; j++) {
|
||||
for (i=0; i<xb/2; i++) {
|
||||
op = (*pMap) & 0xf;
|
||||
dispatchDecoder16((ushort **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j);
|
||||
|
||||
op = ((*pMap) >> 4) & 0xf;
|
||||
dispatchDecoder16((ushort **)&pFrame, op, &pData, &pOffData, &dataRemain, &i, &j);
|
||||
|
||||
pMap++;
|
||||
mapRemain--;
|
||||
}
|
||||
|
||||
pFrame += 7*g_width*2;
|
||||
}
|
||||
|
||||
if ((length-(pData-pOrig)) != 0) {
|
||||
nprintf(("MVE", "DEBUG: junk left over: " PTRDIFF_T_ARG ",%d," PTRDIFF_T_ARG "\n",
|
||||
(pData-pOrig), length, (length-(pData-pOrig))));
|
||||
}
|
||||
}
|
||||
|
||||
static ushort GETPIXEL(unsigned char **buf, int off)
|
||||
{
|
||||
ushort val = (*buf)[0+off] | ((*buf)[1+off] << 8);
|
||||
return val;
|
||||
}
|
||||
|
||||
static ushort GETPIXELI(unsigned char **buf, int off)
|
||||
{
|
||||
ushort val = (*buf)[0+off] | ((*buf)[1+off] << 8);
|
||||
(*buf) += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void relClose(int i, int *x, int *y)
|
||||
{
|
||||
int ma, mi;
|
||||
|
||||
ma = i >> 4;
|
||||
mi = i & 0xf;
|
||||
|
||||
*x = mi - 8;
|
||||
*y = ma - 8;
|
||||
}
|
||||
|
||||
static void relFar(int i, int sign, int *x, int *y)
|
||||
{
|
||||
if (i < 56) {
|
||||
*x = sign * (8 + (i % 7));
|
||||
*y = sign * (i / 7);
|
||||
} else {
|
||||
*x = sign * (-14 + (i - 56) % 29);
|
||||
*y = sign * (8 + (i - 56) / 29);
|
||||
}
|
||||
}
|
||||
|
||||
static int close_table[512];
|
||||
static int far_p_table[512];
|
||||
static int far_n_table[512];
|
||||
|
||||
static void genLoopkupTable()
|
||||
{
|
||||
int i;
|
||||
int x, y;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
relClose(i, &x, &y);
|
||||
|
||||
close_table[i*2+0] = x;
|
||||
close_table[i*2+1] = y;
|
||||
|
||||
relFar(i, 1, &x, &y);
|
||||
|
||||
far_p_table[i*2+0] = x;
|
||||
far_p_table[i*2+1] = y;
|
||||
|
||||
relFar(i, -1, &x, &y);
|
||||
|
||||
far_n_table[i*2+0] = x;
|
||||
far_n_table[i*2+1] = y;
|
||||
}
|
||||
|
||||
lookup_initialized = 1;
|
||||
}
|
||||
|
||||
static void copyFrame(ushort *pDest, ushort *pSrc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<8; i++) {
|
||||
memcpy(pDest, pSrc, 16);
|
||||
pDest += g_width;
|
||||
pSrc += g_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow4Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, ushort *p)
|
||||
{
|
||||
ushort mask=0x0003;
|
||||
ushort shift=0;
|
||||
ushort pattern = (pat1 << 8) | pat0;
|
||||
|
||||
while (mask != 0) {
|
||||
*pFrame++ = p[(mask & pattern) >> shift];
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow4Pixels2(ushort *pFrame, unsigned char pat0, ushort *p)
|
||||
{
|
||||
unsigned char mask=0x03;
|
||||
unsigned char shift=0;
|
||||
ushort pel;
|
||||
|
||||
while (mask != 0) {
|
||||
pel = p[(mask & pat0) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow4Pixels2x1(ushort *pFrame, unsigned char pat, ushort *p)
|
||||
{
|
||||
unsigned char mask=0x03;
|
||||
unsigned char shift=0;
|
||||
ushort pel;
|
||||
|
||||
while (mask != 0) {
|
||||
pel = p[(mask & pat) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternQuadrant4Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, unsigned char pat2, unsigned char pat3, ushort *p)
|
||||
{
|
||||
unsigned long mask = 0x00000003UL;
|
||||
int shift=0;
|
||||
int i;
|
||||
unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
pFrame[i&3] = p[(pat & mask) >> shift];
|
||||
if ((i&3) == 3) {
|
||||
pFrame += g_width;
|
||||
}
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow2Pixels(ushort *pFrame, unsigned char pat, ushort *p)
|
||||
{
|
||||
unsigned char mask=0x01;
|
||||
|
||||
while (mask != 0) {
|
||||
*pFrame++ = p[(mask & pat) ? 1 : 0];
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternRow2Pixels2(ushort *pFrame, unsigned char pat, ushort *p)
|
||||
{
|
||||
ushort pel;
|
||||
unsigned char mask=0x1;
|
||||
|
||||
while (mask != 0x10) {
|
||||
pel = p[(mask & pat) ? 1 : 0];
|
||||
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 1] = pel;
|
||||
pFrame += 2;
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void patternQuadrant2Pixels(ushort *pFrame, unsigned char pat0, unsigned char pat1, ushort *p)
|
||||
{
|
||||
ushort mask = 0x0001;
|
||||
int i;
|
||||
ushort pat = (pat1 << 8) | pat0;
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
pFrame[i&3] = p[(pat & mask) ? 1 : 0];
|
||||
if ((i&3) == 3) {
|
||||
pFrame += g_width;
|
||||
}
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void dispatchDecoder16(ushort **pFrame, unsigned char codeType, unsigned char **pData, unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb)
|
||||
{
|
||||
ushort p[4];
|
||||
unsigned char pat[16];
|
||||
int i, j, k;
|
||||
int x, y;
|
||||
ushort *pDstBak;
|
||||
|
||||
pDstBak = *pFrame;
|
||||
|
||||
switch(codeType) {
|
||||
case 0x0:
|
||||
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1));
|
||||
break; // ADDED
|
||||
|
||||
case 0x1:
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
k = *(*pOffData)++;
|
||||
x = far_p_table[k*2+0];
|
||||
y = far_p_table[k*2+1];
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
(*pDataRemain)--;
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
k = *(*pOffData)++;
|
||||
x = far_n_table[k*2+0];
|
||||
y = far_n_table[k*2+1];
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
(*pDataRemain)--;
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
k = *(*pOffData)++;
|
||||
x = close_table[k*2+0];
|
||||
y = close_table[k*2+1];
|
||||
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width);
|
||||
(*pDataRemain)--;
|
||||
break;
|
||||
|
||||
case 0x5:
|
||||
x = (char)*(*pData)++;
|
||||
y = (char)*(*pData)++;
|
||||
copyFrame(*pFrame, *pFrame + (backBuf2 - backBuf1) + x + y*g_width);
|
||||
*pDataRemain -= 2;
|
||||
break;
|
||||
|
||||
case 0x6:
|
||||
nprintf(("MVE", "STUB: encoding 6 not tested\n"));
|
||||
for (i=0; i<2; i++) {
|
||||
*pFrame += 16;
|
||||
if (++*curXb == (g_width >> 3)) {
|
||||
*pFrame += 7*g_width;
|
||||
*curXb = 0;
|
||||
if (++*curYb == (g_height >> 3)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7:
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
if (!((p[0]/*|p[1]*/)&0x8000)) {
|
||||
for (i=0; i<8; i++) {
|
||||
patternRow2Pixels(*pFrame, *(*pData), p);
|
||||
(*pData)++;
|
||||
*pFrame += g_width;
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<2; i++) {
|
||||
patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow2Pixels2(*pFrame, *(*pData) >> 4, p);
|
||||
(*pData)++;
|
||||
*pFrame += 2*g_width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
if (!(p[0] & 0x8000)) {
|
||||
for (i=0; i<4; i++) {
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
(*pData) += 2;
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
if (i & 1) {
|
||||
*pFrame -= (4*g_width - 4);
|
||||
} else {
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p[2] = GETPIXEL(pData, 8);
|
||||
if (!(p[2]&0x8000)) {
|
||||
for (i=0; i<4; i++) {
|
||||
if ((i & 1) == 0) {
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
}
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
if (i & 1) {
|
||||
*pFrame -= (4*g_width - 4);
|
||||
} else {
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<8; i++) {
|
||||
if ((i & 3) == 0) {
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
}
|
||||
patternRow2Pixels(*pFrame, *(*pData), p);
|
||||
(*pData)++;
|
||||
*pFrame += g_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
*pDataRemain -= 8;
|
||||
if (!(p[0] & 0x8000)) {
|
||||
if (!(p[2] & 0x8000)) {
|
||||
for (i=0; i<8; i++) {
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
(*pData) += 2;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pDataRemain -= 16;
|
||||
} else {
|
||||
patternRow4Pixels2(*pFrame, (*pData)[0], p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, (*pData)[1], p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, (*pData)[2], p);
|
||||
*pFrame += 2*g_width;
|
||||
patternRow4Pixels2(*pFrame, (*pData)[3], p);
|
||||
(*pData) += 4;
|
||||
*pDataRemain -= 4;
|
||||
}
|
||||
} else {
|
||||
if (!(p[2] & 0x8000)) {
|
||||
for (i=0; i<8; i++) {
|
||||
pat[0] = (*pData)[0];
|
||||
(*pData) += 1;
|
||||
patternRow4Pixels2x1(*pFrame, pat[0], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pDataRemain -= 8;
|
||||
} else {
|
||||
for (i=0; i<4; i++) {
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
(*pData) += 2;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pDataRemain -= 8;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
if (!(p[0] & 0x8000)) {
|
||||
for (i=0; i<4; i++) {
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
pat[2] = (*pData)[2];
|
||||
pat[3] = (*pData)[3];
|
||||
(*pData) += 4;
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
if (i & 1) {
|
||||
*pFrame -= (4*g_width - 4);
|
||||
} else {
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p[0] = GETPIXEL(pData, 16);
|
||||
if (!(p[0] & 0x8000)) {
|
||||
for (i=0; i<4; i++) {
|
||||
if ((i&1) == 0) {
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
}
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
pat[2] = (*pData)[2];
|
||||
pat[3] = (*pData)[3];
|
||||
(*pData) += 4;
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
if (i & 1) {
|
||||
*pFrame -= (4*g_width - 4);
|
||||
} else {
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<8; i++) {
|
||||
if ((i&3) == 0) {
|
||||
p[0] = GETPIXELI(pData, 0);
|
||||
p[1] = GETPIXELI(pData, 0);
|
||||
p[2] = GETPIXELI(pData, 0);
|
||||
p[3] = GETPIXELI(pData, 0);
|
||||
}
|
||||
pat[0] = (*pData)[0];
|
||||
pat[1] = (*pData)[1];
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
(*pData) += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
for (i=0; i<8; i++) {
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
ubyte frame_tmp[16];
|
||||
memcpy(&frame_tmp, *pData, 16);
|
||||
ushort *swap_tmp;
|
||||
for (j = 0; j < 16; j += 2) {
|
||||
swap_tmp = (ushort*)(frame_tmp + j);
|
||||
*swap_tmp = INTEL_SHORT(*swap_tmp);
|
||||
}
|
||||
memcpy(*pFrame, &frame_tmp, 16);
|
||||
#else
|
||||
memcpy(*pFrame, *pData, 16);
|
||||
#endif
|
||||
*pFrame += g_width;
|
||||
*pData += 16;
|
||||
*pDataRemain -= 16;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
for (i=0; i<4; i++) {
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
p[1] = GETPIXEL(pData, 2);
|
||||
p[2] = GETPIXEL(pData, 4);
|
||||
p[3] = GETPIXEL(pData, 6);
|
||||
for (j=0; j<2; j++) {
|
||||
for (k=0; k<4; k++) {
|
||||
(*pFrame)[2*k] = p[k];
|
||||
(*pFrame)[2*k+1] = p[k];
|
||||
}
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pData += 8;
|
||||
*pDataRemain -= 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xd:
|
||||
for (i=0; i<2; i++) {
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
p[1] = GETPIXEL(pData, 2);
|
||||
for (j=0; j<4; j++) {
|
||||
for (k=0; k<4; k++) {
|
||||
(*pFrame)[k*g_width+j] = p[0];
|
||||
(*pFrame)[k*g_width+j+4] = p[1];
|
||||
}
|
||||
}
|
||||
*pFrame += 4*g_width;
|
||||
*pData += 4;
|
||||
*pDataRemain -= 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
(*pFrame)[j] = p[0];
|
||||
}
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pData += 2;
|
||||
*pDataRemain -= 2;
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
p[0] = GETPIXEL(pData, 0);
|
||||
p[1] = GETPIXEL(pData, 1);
|
||||
for (i=0; i<8; i++) {
|
||||
for (j=0; j<8; j++) {
|
||||
(*pFrame)[j] = p[(i+j)&1];
|
||||
}
|
||||
*pFrame += g_width;
|
||||
}
|
||||
*pData += 4;
|
||||
*pDataRemain -= 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*pFrame = pDstBak+8;
|
||||
}
|
||||
@@ -1,533 +0,0 @@
|
||||
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
|
||||
extern int g_width, g_height;
|
||||
extern void *g_vBackBuf1, *g_vBackBuf2;
|
||||
|
||||
static void dispatchDecoder8(ubyte **pFrame, ubyte codeType, ubyte **pData, int *pDataRemain, int *curXb, int *curYb);
|
||||
|
||||
void decodeFrame8(ubyte *pFrame, ubyte *pMap, int mapRemain, ubyte *pData, int dataRemain)
|
||||
{
|
||||
int i, j;
|
||||
int xb, yb;
|
||||
|
||||
xb = g_width >> 3;
|
||||
yb = g_height >> 3;
|
||||
|
||||
for (j = 0; j < yb; j++) {
|
||||
for (i = 0; i < (xb / 2); i++) {
|
||||
dispatchDecoder8(&pFrame, (*pMap) & 0xf, &pData, &dataRemain, &i, &j);
|
||||
|
||||
dispatchDecoder8(&pFrame, (*pMap) >> 4, &pData, &dataRemain, &i, &j);
|
||||
|
||||
pMap++;
|
||||
mapRemain--;
|
||||
}
|
||||
|
||||
pFrame += 7*g_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void relClose(int i, int *x, int *y)
|
||||
{
|
||||
int ma, mi;
|
||||
|
||||
ma = i >> 4;
|
||||
mi = i & 0xf;
|
||||
|
||||
*x = mi - 8;
|
||||
*y = ma - 8;
|
||||
}
|
||||
|
||||
static void relFar(int i, int sign, int *x, int *y)
|
||||
{
|
||||
if (i < 56) {
|
||||
*x = sign * (8 + (i % 7));
|
||||
*y = sign * (i / 7);
|
||||
} else {
|
||||
*x = sign * (-14 + (i - 56) % 29);
|
||||
*y = sign * (8 + (i - 56) / 29);
|
||||
}
|
||||
}
|
||||
|
||||
/* copies an 8x8 block from pSrc to pDest.
|
||||
pDest and pSrc are both g_width bytes wide */
|
||||
static void copyFrame(ubyte *pDest, ubyte *pSrc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
memcpy(pDest, pSrc, 8);
|
||||
pDest += g_width;
|
||||
pSrc += g_width;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next eight bytes with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat0 and pat1
|
||||
static void patternRow4Pixels(ubyte *pFrame, ubyte pat0, ubyte pat1, ubyte *p)
|
||||
{
|
||||
ushort mask = 0x0003;
|
||||
ushort shift = 0;
|
||||
ushort pattern = (pat1 << 8) | pat0;
|
||||
|
||||
while (mask != 0) {
|
||||
*pFrame++ = p[(mask & pattern) >> shift];
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next four 2x2 pixel blocks with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat0.
|
||||
static void patternRow4Pixels2(ubyte *pFrame, ubyte pat0, ubyte *p)
|
||||
{
|
||||
ubyte mask = 0x03;
|
||||
ubyte shift = 0;
|
||||
ubyte pel;
|
||||
|
||||
while (mask != 0) {
|
||||
pel = p[(mask & pat0) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame[g_width + 0] = pel;
|
||||
pFrame[g_width + 1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next four 2x1 pixel blocks with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat.
|
||||
static void patternRow4Pixels2x1(ubyte *pFrame, ubyte pat, ubyte *p)
|
||||
{
|
||||
ubyte mask = 0x03;
|
||||
ubyte shift = 0;
|
||||
ubyte pel;
|
||||
|
||||
while (mask != 0) {
|
||||
pel = p[(mask & pat) >> shift];
|
||||
pFrame[0] = pel;
|
||||
pFrame[1] = pel;
|
||||
pFrame += 2;
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the next 4x4 pixel block with p[0], p[1], p[2], or p[3],
|
||||
// depending on the corresponding two-bit value in pat0, pat1, pat2, and pat3.
|
||||
static void patternQuadrant4Pixels(ubyte *pFrame, ubyte pat0, ubyte pat1, ubyte pat2, ubyte pat3, ubyte *p)
|
||||
{
|
||||
unsigned long mask = 0x00000003UL;
|
||||
int shift=0;
|
||||
int i;
|
||||
unsigned long pat = (pat3 << 24) | (pat2 << 16) | (pat1 << 8) | pat0;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
pFrame[i&3] = p[(pat & mask) >> shift];
|
||||
|
||||
if ( (i & 3) == 3 )
|
||||
pFrame += g_width;
|
||||
|
||||
mask <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// fills the next 8 pixels with either p[0] or p[1], depending on pattern
|
||||
static void patternRow2Pixels(ubyte *pFrame, ubyte pat, ubyte *p)
|
||||
{
|
||||
ubyte mask=0x01;
|
||||
|
||||
while (mask != 0) {
|
||||
*pFrame++ = p[(mask & pat) ? 1 : 0];
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// fills the next four 2 x 2 pixel boxes with either p[0] or p[1], depending on pattern
|
||||
static void patternRow2Pixels2(ubyte *pFrame, ubyte pat, ubyte *p)
|
||||
{
|
||||
ubyte pel;
|
||||
ubyte mask=0x1;
|
||||
|
||||
while (mask != 0x10) {
|
||||
pel = p[(mask & pat) ? 1 : 0];
|
||||
|
||||
pFrame[0] = pel; // upper-left
|
||||
pFrame[1] = pel; // upper-right
|
||||
pFrame[g_width + 0] = pel; // lower-left
|
||||
pFrame[g_width + 1] = pel; // lower-right
|
||||
pFrame += 2;
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// fills pixels in the next 4 x 4 pixel boxes with either p[0] or p[1], depending on pat0 and pat1.
|
||||
static void patternQuadrant2Pixels(ubyte *pFrame, ubyte pat0, ubyte pat1, ubyte *p)
|
||||
{
|
||||
ubyte pel;
|
||||
ushort mask = 0x0001;
|
||||
int i, j;
|
||||
ushort pat = (pat1 << 8) | pat0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
pel = p[(pat & mask) ? 1 : 0];
|
||||
|
||||
pFrame[j + i * g_width] = pel;
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dispatchDecoder8(ubyte **pFrame, ubyte codeType, ubyte **pData, int *pDataRemain, int *curXb, int *curYb)
|
||||
{
|
||||
ubyte p[4];
|
||||
ubyte pat[16];
|
||||
int i, j, k;
|
||||
int x, y;
|
||||
|
||||
switch(codeType) {
|
||||
case 0x0:
|
||||
copyFrame(*pFrame, *pFrame + ((ubyte *)g_vBackBuf2 - (ubyte *)g_vBackBuf1));
|
||||
*pFrame += 8;
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
*pFrame += 8;
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
relFar(*(*pData)++, 1, &x, &y);
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
(*pDataRemain)--;
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
relFar(*(*pData)++, -1, &x, &y);
|
||||
copyFrame(*pFrame, *pFrame + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
(*pDataRemain)--;
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
relClose(*(*pData)++, &x, &y);
|
||||
copyFrame(*pFrame, *pFrame + ((ubyte *)g_vBackBuf2 - (ubyte *)g_vBackBuf1) + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
(*pDataRemain)--;
|
||||
break;
|
||||
|
||||
case 0x5:
|
||||
x = (signed char)*(*pData)++;
|
||||
y = (signed char)*(*pData)++;
|
||||
copyFrame(*pFrame, *pFrame + ((ubyte *)g_vBackBuf2 - (ubyte *)g_vBackBuf1) + x + y*g_width);
|
||||
*pFrame += 8;
|
||||
*pDataRemain -= 2;
|
||||
break;
|
||||
|
||||
case 0x6:
|
||||
for (i = 0; i < 2; i++) {
|
||||
*pFrame += 16;
|
||||
|
||||
if (++*curXb == (g_width >> 3)) {
|
||||
*pFrame += 7*g_width;
|
||||
*curXb = 0;
|
||||
|
||||
if (++*curYb == (g_height >> 3))
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7:
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
|
||||
if (p[0] <= p[1]) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
patternRow2Pixels(*pFrame, *(*pData)++, p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 2; i++) {
|
||||
patternRow2Pixels2(*pFrame, *(*pData) & 0xf, p);
|
||||
*pFrame += 2*g_width;
|
||||
|
||||
patternRow2Pixels2(*pFrame, *(*pData)++ >> 4, p);
|
||||
*pFrame += 2*g_width;
|
||||
}
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
if ( (*pData)[0] <= (*pData)[1] ) {
|
||||
// four quadrant case
|
||||
for (i = 0; i < 4; i++) {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
|
||||
// alternate between moving down and moving up and right
|
||||
if (i & 1)
|
||||
*pFrame += 4 - 4*g_width; // up and right
|
||||
else
|
||||
*pFrame += 4*g_width; // down
|
||||
}
|
||||
} else if ( (*pData)[6] <= (*pData)[7] ) {
|
||||
// split horizontal
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((i & 1) == 0) {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
}
|
||||
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
patternQuadrant2Pixels(*pFrame, pat[0], pat[1], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
} else {
|
||||
// split vertical
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((i & 3) == 0) {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
}
|
||||
|
||||
patternRow2Pixels(*pFrame, *(*pData)++, p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x9:
|
||||
if ( (*pData)[0] <= (*pData)[1] ) {
|
||||
if ( (*pData)[2] <= (*pData)[3] ) {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
} else {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame += 2*g_width;
|
||||
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame += 2*g_width;
|
||||
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame += 2*g_width;
|
||||
|
||||
patternRow4Pixels2(*pFrame, *(*pData)++, p);
|
||||
*pFrame -= (6*g_width - 8);
|
||||
}
|
||||
} else {
|
||||
if ( (*pData)[2] <= (*pData)[3] ) {
|
||||
// draw 2x1 strips
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
pat[0] = *(*pData)++;
|
||||
|
||||
patternRow4Pixels2x1(*pFrame, pat[0], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
} else {
|
||||
// draw 1x2 strips
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa:
|
||||
if ( (*pData)[0] <= (*pData)[1] ) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
pat[2] = *(*pData)++;
|
||||
pat[3] = *(*pData)++;
|
||||
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
} else {
|
||||
if ( (*pData)[12] <= (*pData)[13] ) {
|
||||
// split vertical
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((i&1) == 0) {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
}
|
||||
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
pat[2] = *(*pData)++;
|
||||
pat[3] = *(*pData)++;
|
||||
|
||||
patternQuadrant4Pixels(*pFrame, pat[0], pat[1], pat[2], pat[3], p);
|
||||
|
||||
if (i & 1)
|
||||
*pFrame -= (4*g_width - 4);
|
||||
else
|
||||
*pFrame += 4*g_width;
|
||||
}
|
||||
} else {
|
||||
// split horizontal
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((i&3) == 0) {
|
||||
p[0] = *(*pData)++;
|
||||
p[1] = *(*pData)++;
|
||||
p[2] = *(*pData)++;
|
||||
p[3] = *(*pData)++;
|
||||
}
|
||||
|
||||
pat[0] = *(*pData)++;
|
||||
pat[1] = *(*pData)++;
|
||||
|
||||
patternRow4Pixels(*pFrame, pat[0], pat[1], p);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
for (i = 0; i < 8; i++) {
|
||||
memcpy(*pFrame, *pData, 8);
|
||||
*pFrame += g_width;
|
||||
*pData += 8;
|
||||
*pDataRemain -= 8;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
(*pFrame)[2*k] = (*pData)[k];
|
||||
(*pFrame)[2*k+1] = (*pData)[k];
|
||||
}
|
||||
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pData += 4;
|
||||
*pDataRemain -= 4;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xd:
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
(*pFrame)[k*g_width+j] = (*pData)[0];
|
||||
(*pFrame)[k*g_width+j+4] = (*pData)[1];
|
||||
}
|
||||
}
|
||||
|
||||
*pFrame += 4*g_width;
|
||||
*pData += 2;
|
||||
*pDataRemain -= 2;
|
||||
}
|
||||
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
for (i = 0; i < 8; i++) {
|
||||
memset(*pFrame, **pData, 8);
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
(*pData)++;
|
||||
(*pDataRemain)--;
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
(*pFrame)[j] = (*pData)[(i+j)&1];
|
||||
}
|
||||
|
||||
*pFrame += g_width;
|
||||
}
|
||||
|
||||
*pData += 2;
|
||||
*pDataRemain -= 2;
|
||||
*pFrame -= (8*g_width - 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
#include "cutscene/ffmpeg/AudioDecoder.h"
|
||||
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
namespace {
|
||||
const int OUT_CH_LAYOUT = AV_CH_LAYOUT_STEREO;
|
||||
const int OUT_SAMPLE_RATE = 48000;
|
||||
const AVSampleFormat OUT_SAMPLE_FORMAT = AV_SAMPLE_FMT_S16;
|
||||
const int OUT_NUM_CHANNELS = av_get_channel_layout_nb_channels(OUT_CH_LAYOUT);
|
||||
|
||||
const int DEFAULT_SRC_NUM_SAMPLES = 1024;
|
||||
|
||||
SwrContext* getSWRContext(uint64_t layout, int rate, AVSampleFormat inFmt) {
|
||||
auto swr = swr_alloc();
|
||||
|
||||
av_opt_set_int(swr, "in_channel_layout", layout, 0);
|
||||
av_opt_set_int(swr, "in_sample_rate", rate, 0);
|
||||
av_opt_set_int(swr, "in_sample_fmt", inFmt, 0);
|
||||
|
||||
av_opt_set_int(swr, "out_channel_layout", OUT_CH_LAYOUT, 0);
|
||||
av_opt_set_int(swr, "out_sample_rate", OUT_SAMPLE_RATE, 0);
|
||||
av_opt_set_int(swr, "out_sample_fmt", OUT_SAMPLE_FORMAT, 0);
|
||||
|
||||
swr_init(swr);
|
||||
|
||||
return swr;
|
||||
}
|
||||
|
||||
int alloc_array_and_samples(uint8_t*** outData, int* linesize, int channels, int samples, AVSampleFormat format) {
|
||||
auto planes = av_sample_fmt_is_planar(format) ? channels : 1;
|
||||
|
||||
*outData = reinterpret_cast<uint8_t**>(av_mallocz(planes * sizeof(**outData)));
|
||||
|
||||
|
||||
auto ret = av_samples_alloc(*outData, linesize, channels, samples, format, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
av_freep(outData);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t getDelay(SwrContext* ctx, int64_t sampleRate) {
|
||||
#ifdef WITH_LIBAV
|
||||
return avresample_get_delay(ctx);
|
||||
#else
|
||||
return swr_get_delay(ctx, sampleRate);
|
||||
#endif
|
||||
}
|
||||
|
||||
int resample_convert(SwrContext* ctx, uint8_t** output,
|
||||
int out_plane_size, int out_samples, uint8_t** input,
|
||||
int in_plane_size, int in_samples) {
|
||||
#ifdef WITH_LIBAV
|
||||
return avresample_convert(ctx, output, out_plane_size, out_samples, input, in_plane_size, in_samples);
|
||||
#else
|
||||
return swr_convert(ctx, output, out_samples, (const uint8_t**) input, in_samples);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
AudioDecoder::AudioDecoder(DecoderStatus* status)
|
||||
: FFMPEGStreamDecoder(status) {
|
||||
m_audioBuffer.reserve(static_cast<size_t>(OUT_SAMPLE_RATE * OUT_NUM_CHANNELS / 2));
|
||||
|
||||
m_resampleCtx = getSWRContext(m_status->audioCodecPars.channel_layout, m_status->audioCodecPars.sample_rate,
|
||||
m_status->audioCodecPars.audio_format);
|
||||
|
||||
/*
|
||||
* compute the number of converted samples: buffering is avoided
|
||||
* ensuring that the output buffer will contain at least all the
|
||||
* converted input samples
|
||||
*/
|
||||
m_maxOutNumSamples = m_outNumSamples = static_cast<int>(av_rescale_rnd(DEFAULT_SRC_NUM_SAMPLES,
|
||||
OUT_SAMPLE_RATE,
|
||||
m_status->audioCodecPars.sample_rate,
|
||||
AV_ROUND_UP));
|
||||
|
||||
auto ret = alloc_array_and_samples(&m_outData, &m_outLinesize, OUT_NUM_CHANNELS,
|
||||
m_outNumSamples, OUT_SAMPLE_FORMAT);
|
||||
|
||||
if (ret < 0) {
|
||||
mprintf(("FFMPEG: Failed to allocate samples array!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
AudioDecoder::~AudioDecoder() {
|
||||
if (m_outData) {
|
||||
av_freep(&m_outData[0]);
|
||||
}
|
||||
av_freep(&m_outData);
|
||||
|
||||
swr_free(&m_resampleCtx);
|
||||
}
|
||||
|
||||
void AudioDecoder::flushAudioBuffer() {
|
||||
if (m_audioBuffer.empty()) {
|
||||
// Nothing to do here
|
||||
return;
|
||||
}
|
||||
|
||||
AudioFramePtr audioFrame(new AudioFrame());
|
||||
audioFrame->channels = OUT_NUM_CHANNELS;
|
||||
audioFrame->rate = OUT_SAMPLE_RATE;
|
||||
|
||||
audioFrame->audioData.assign(m_audioBuffer.begin(), m_audioBuffer.end());
|
||||
|
||||
pushFrame(std::move(audioFrame));
|
||||
m_audioBuffer.clear();
|
||||
}
|
||||
|
||||
void AudioDecoder::handleDecodedFrame(AVFrame* frame) {
|
||||
/* compute destination number of samples */
|
||||
m_outNumSamples = static_cast<int>(av_rescale_rnd(getDelay(m_resampleCtx, frame->sample_rate)
|
||||
+ frame->nb_samples, OUT_SAMPLE_RATE, frame->sample_rate,
|
||||
AV_ROUND_UP));
|
||||
|
||||
if (m_outNumSamples > m_maxOutNumSamples) {
|
||||
av_freep(&m_outData[0]);
|
||||
auto ret = av_samples_alloc(m_outData, &m_outLinesize, OUT_NUM_CHANNELS, m_outNumSamples,
|
||||
OUT_SAMPLE_FORMAT, 1);
|
||||
if (ret < 0) {
|
||||
mprintf(("FFMPEG: Failed to allocate samples!!!"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_maxOutNumSamples = m_outNumSamples;
|
||||
}
|
||||
|
||||
/* convert to destination format */
|
||||
auto ret = resample_convert(m_resampleCtx, m_outData, 0, m_outNumSamples,
|
||||
(uint8_t**) frame->data, 0, frame->nb_samples);
|
||||
if (ret < 0) {
|
||||
mprintf(("FFMPEG: Error while converting audio!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto outBufsize = av_samples_get_buffer_size(&m_outLinesize, OUT_NUM_CHANNELS, ret, OUT_SAMPLE_FORMAT, 1);
|
||||
if (outBufsize < 0) {
|
||||
mprintf(("FFMPEG: Could not get sample buffer size!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto begin = reinterpret_cast<short*>(m_outData[0]);
|
||||
auto end = reinterpret_cast<short*>(m_outData[0] + outBufsize);
|
||||
|
||||
auto size = std::distance(begin, end);
|
||||
auto newSize = m_audioBuffer.size() + size;
|
||||
|
||||
if (newSize <= m_audioBuffer.capacity()) {
|
||||
// We haven't filled the buffer yet
|
||||
m_audioBuffer.insert(m_audioBuffer.end(), begin, end);
|
||||
} else {
|
||||
flushAudioBuffer();
|
||||
m_audioBuffer.assign(begin, end);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDecoder::decodePacket(AVPacket* packet) {
|
||||
TRACE_SCOPE(tracing::CutsceneFFmpegAudioDecoder);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
int send_result;
|
||||
do {
|
||||
send_result = avcodec_send_packet(m_status->audioCodecCtx, packet);
|
||||
|
||||
while (avcodec_receive_frame(m_status->audioCodecCtx, m_decodeFrame) == 0) {
|
||||
handleDecodedFrame(m_decodeFrame);
|
||||
}
|
||||
} while (send_result == AVERROR(EAGAIN));
|
||||
#else
|
||||
int finishedFrame = 0;
|
||||
auto err = avcodec_decode_audio4(m_status->audioCodecCtx, m_decodeFrame, &finishedFrame, packet);
|
||||
|
||||
if (err >= 0 && finishedFrame) {
|
||||
handleDecodedFrame(m_decodeFrame);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AudioDecoder::finishDecoding() {
|
||||
TRACE_SCOPE(tracing::CutsceneFFmpegAudioDecoder);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
// Send flush packet
|
||||
avcodec_send_packet(m_status->audioCodecCtx, nullptr);
|
||||
|
||||
// Handle those decoders that have a delay
|
||||
while (true) {
|
||||
auto ret = avcodec_receive_frame(m_status->audioCodecCtx, m_decodeFrame);
|
||||
|
||||
if (ret == 0) {
|
||||
handleDecodedFrame(m_decodeFrame);
|
||||
}
|
||||
else {
|
||||
// Everything consumed or error
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Handle those decoders that have a delay
|
||||
AVPacket nullPacket;
|
||||
memset(&nullPacket, 0, sizeof(nullPacket));
|
||||
nullPacket.data = nullptr;
|
||||
nullPacket.size = 0;
|
||||
|
||||
while (true) {
|
||||
int finishedFrame = 1;
|
||||
auto err = avcodec_decode_audio4(m_status->audioCodecCtx, m_decodeFrame, &finishedFrame, &nullPacket);
|
||||
|
||||
if (err < 0 || !finishedFrame) {
|
||||
break;
|
||||
}
|
||||
|
||||
handleDecodedFrame(m_decodeFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Push the last bits of audio data into the queue
|
||||
flushAudioBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/ffmpeg/internal.h"
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
|
||||
class AudioDecoder: public FFMPEGStreamDecoder<AudioFrame> {
|
||||
private:
|
||||
SwrContext* m_resampleCtx;
|
||||
|
||||
uint8_t** m_outData;
|
||||
int m_outLinesize;
|
||||
|
||||
int m_maxOutNumSamples;
|
||||
int m_outNumSamples;
|
||||
|
||||
SCP_vector<short> m_audioBuffer;
|
||||
|
||||
void handleDecodedFrame(AVFrame* frame);
|
||||
|
||||
void flushAudioBuffer();
|
||||
|
||||
public:
|
||||
explicit AudioDecoder(DecoderStatus* status);
|
||||
|
||||
virtual ~AudioDecoder();
|
||||
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,457 @@
|
||||
#include <limits>
|
||||
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "libs/ffmpeg/FFmpegContext.h"
|
||||
|
||||
#include "cutscene/ffmpeg/internal.h"
|
||||
|
||||
#include "cutscene/ffmpeg/AudioDecoder.h"
|
||||
#include "cutscene/ffmpeg/VideoDecoder.h"
|
||||
#include "cutscene/ffmpeg/SubtitleDecoder.h"
|
||||
|
||||
#include "localization/localize.h"
|
||||
|
||||
using namespace libs::ffmpeg;
|
||||
|
||||
namespace {
|
||||
using namespace cutscene;
|
||||
using namespace cutscene::ffmpeg;
|
||||
|
||||
class AVPacketScope
|
||||
{
|
||||
AVPacket* _packet;
|
||||
public:
|
||||
explicit AVPacketScope(AVPacket* av_packet)
|
||||
: _packet(av_packet) {
|
||||
}
|
||||
|
||||
~AVPacketScope() {
|
||||
av_packet_unref(_packet);
|
||||
}
|
||||
};
|
||||
|
||||
const char* CHECKED_EXTENSIONS[] = {
|
||||
"webm",
|
||||
"mp4",
|
||||
"ogg",
|
||||
"mve"
|
||||
};
|
||||
|
||||
double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
|
||||
auto fps = av_q2d(av_stream_get_r_frame_rate(stream));
|
||||
|
||||
if (fps < 0.000001)
|
||||
{
|
||||
fps = av_q2d(stream->avg_frame_rate);
|
||||
}
|
||||
|
||||
if (fps < 0.000001)
|
||||
{
|
||||
fps = 1.0 / av_q2d(codecCtx->time_base);
|
||||
}
|
||||
|
||||
return fps;
|
||||
}
|
||||
|
||||
CodecContextParameters getCodecParameters(AVStream* stream) {
|
||||
CodecContextParameters paras;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
paras.width = stream->codecpar->width;
|
||||
paras.height = stream->codecpar->height;
|
||||
paras.pixel_format = (AVPixelFormat)stream->codecpar->format;
|
||||
|
||||
paras.channel_layout = stream->codecpar->channel_layout;
|
||||
paras.sample_rate = stream->codecpar->sample_rate;
|
||||
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
|
||||
|
||||
paras.codec_id = stream->codecpar->codec_id;
|
||||
#else
|
||||
paras.width = stream->codec->width;
|
||||
paras.height = stream->codec->height;
|
||||
paras.pixel_format = stream->codec->pix_fmt;
|
||||
|
||||
paras.channel_layout = stream->codec->channel_layout;
|
||||
paras.sample_rate = stream->codec->sample_rate;
|
||||
paras.audio_format = stream->codec->sample_fmt;
|
||||
|
||||
paras.codec_id = stream->codec->codec_id;
|
||||
#endif
|
||||
return paras;
|
||||
}
|
||||
|
||||
SCP_string normalizeLanguage(const char* langauge_name) {
|
||||
if (!stricmp(langauge_name, "eng")) {
|
||||
return "English";
|
||||
}
|
||||
if (!stricmp(langauge_name, "ger")) {
|
||||
return "German";
|
||||
}
|
||||
if (!stricmp(langauge_name, "spa")) {
|
||||
return "Spanish";
|
||||
}
|
||||
|
||||
// Print to log so that we can find the actual value more easily later
|
||||
mprintf(("FFmpeg log: Found unknown language value '%s'!\n", langauge_name));
|
||||
|
||||
// Default to english for everything else
|
||||
return "English";
|
||||
}
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
struct InputStream {
|
||||
std::unique_ptr<FFmpegContext> m_ctx;
|
||||
};
|
||||
|
||||
FFMPEGDecoder::FFMPEGDecoder() {
|
||||
}
|
||||
|
||||
FFMPEGDecoder::~FFMPEGDecoder() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::unique_ptr<InputStream> openStream(const SCP_string& name) {
|
||||
// Only check the root and movies folders
|
||||
int dirType;
|
||||
if (cf_exists_full(name.c_str(), CF_TYPE_ROOT)) {
|
||||
dirType = CF_TYPE_ROOT;
|
||||
} else if (cf_exists_full(name.c_str(), CF_TYPE_MOVIES)) {
|
||||
dirType = CF_TYPE_MOVIES;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<InputStream> input(new InputStream());
|
||||
|
||||
try {
|
||||
// Create the FFmpeg context
|
||||
input->m_ctx = FFmpegContext::createContext(name, dirType);
|
||||
|
||||
// This may fail, in that case return null
|
||||
if (!input->m_ctx) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
catch (const FFmpegException& e) {
|
||||
mprintf(("Error opening %s: %s\n", name.c_str(), e.what()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream) {
|
||||
std::unique_ptr<DecoderStatus> status(new DecoderStatus());
|
||||
|
||||
auto ctx = stream->m_ctx->ctx();
|
||||
|
||||
auto videoStream = av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &status->videoCodec, 0);
|
||||
if (videoStream < 0) {
|
||||
if (videoStream == AVERROR_STREAM_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: No video stream found in file!\n"));
|
||||
} else if (videoStream == AVERROR_DECODER_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: Codec for video stream could not be found!\n"));
|
||||
} else {
|
||||
mprintf(("FFmpeg: Unknown error while finding video stream!\n"));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto audioStream = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, videoStream, &status->audioCodec, 0);
|
||||
if (audioStream < 0) {
|
||||
if (audioStream == AVERROR_STREAM_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: No audio stream found in file!\n"));
|
||||
} else if (videoStream == AVERROR_DECODER_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: Codec for audio stream could not be found!\n"));
|
||||
} else {
|
||||
mprintf(("FFmpeg: Unknown error while finding audio stream!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
status->videoStreamIndex = videoStream;
|
||||
status->videoStream = ctx->streams[videoStream];
|
||||
|
||||
if (audioStream >= 0) {
|
||||
status->audioStreamIndex = audioStream;
|
||||
status->audioStream = ctx->streams[audioStream];
|
||||
}
|
||||
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
|
||||
auto test_stream = ctx->streams[i];
|
||||
|
||||
auto& pars = test_stream->codecpar;
|
||||
|
||||
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
|
||||
continue;
|
||||
}
|
||||
AVDictionaryEntry* tag = nullptr;
|
||||
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto normalized_language = normalizeLanguage(tag->value);
|
||||
|
||||
if (!stricmp(normalized_language.c_str(), current_language.lang_name)) {
|
||||
status->subtitleStreamIndex = i;
|
||||
status->subtitleStream = test_stream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
status->videoCodecPars = getCodecParameters(status->videoStream);
|
||||
|
||||
int err;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
status->videoCodecCtx = avcodec_alloc_context3(status->videoCodec);
|
||||
|
||||
// Copy codec parameters from input stream to output codec context
|
||||
err = avcodec_parameters_to_context(status->videoCodecCtx, status->videoStream->codecpar);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to copy context parameters! Error: %s\n", errorStr));
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
status->videoCodecCtx = status->videoStream->codec;
|
||||
#endif
|
||||
|
||||
err = avcodec_open2(status->videoCodecCtx, status->videoCodec, nullptr);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to open video codec! Error: %s\n", errorStr));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mprintf(("FFmpeg: Using video codec %s (%s).\n", status->videoCodec->long_name ? status->videoCodec->long_name : "<Unknown>",
|
||||
status->videoCodec->name ? status->videoCodec->name : "<Unknown>"));
|
||||
|
||||
// Now initialize audio, if this fails it's not a fatal error
|
||||
if (audioStream >= 0) {
|
||||
status->audioCodecPars = getCodecParameters(status->audioStream);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
status->audioCodecCtx = avcodec_alloc_context3(status->audioCodec);
|
||||
|
||||
err = avcodec_parameters_to_context(status->audioCodecCtx, status->audioStream->codecpar);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to copy context parameters! Error: %s\n", errorStr));
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
status->audioCodecCtx = status->audioStream->codec;
|
||||
#endif
|
||||
|
||||
err = avcodec_open2(status->audioCodecCtx, status->audioCodec, nullptr);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to open audio codec! Error: %s\n", errorStr));
|
||||
}
|
||||
|
||||
mprintf(("FFmpeg: Using audio codec %s (%s).\n", status->audioCodec->long_name ? status->audioCodec->long_name : "<Unknown>",
|
||||
status->audioCodec->name ? status->audioCodec->name : "<Unknown>"));
|
||||
}
|
||||
|
||||
if (status->subtitleStreamIndex >= 0) {
|
||||
// Not really sure if this makes sense for subtitles but it shouldn't break anything...
|
||||
status->subtitleCodecPars = getCodecParameters(status->subtitleStream);
|
||||
|
||||
status->subtitleCodec = avcodec_find_decoder(status->subtitleCodecPars.codec_id);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
status->subtitleCodecCtx = avcodec_alloc_context3(status->subtitleCodec);
|
||||
|
||||
err = avcodec_parameters_to_context(status->subtitleCodecCtx, status->subtitleStream->codecpar);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to copy context parameters! Error: %s\n", errorStr));
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
status->subtitleCodecCtx = status->subtitleStream->codec;
|
||||
#endif
|
||||
|
||||
err = avcodec_open2(status->subtitleCodecCtx, status->subtitleCodec, nullptr);
|
||||
if (err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to open subtitle codec! Error: %s\n", errorStr));
|
||||
}
|
||||
|
||||
mprintf(("FFmpeg: Using subtitle codec %s (%s).\n", status->subtitleCodec->long_name ? status->subtitleCodec->long_name : "<Unknown>",
|
||||
status->subtitleCodec->name ? status->subtitleCodec->name : "<Unknown>"));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
|
||||
// Check a list of extensions we might use
|
||||
// The actual format of the file may be whatever FFmpeg supports
|
||||
for (auto ext : CHECKED_EXTENSIONS) {
|
||||
auto fileName = name + "." + ext;
|
||||
|
||||
auto input = openStream(fileName);
|
||||
|
||||
if (input) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
|
||||
SCP_string movieName = fileName;
|
||||
// First make the file name lower case
|
||||
std::transform(movieName.begin(), movieName.end(), movieName.begin(), ::tolower);
|
||||
|
||||
// Then remove the extension
|
||||
size_t dotPos = movieName.find('.');
|
||||
if (dotPos != SCP_string::npos) {
|
||||
movieName.resize(dotPos);
|
||||
}
|
||||
|
||||
// Try to open the input stream
|
||||
auto input = openInputStream(movieName);
|
||||
if (!input) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We now have a valid input stream, try to find the correct streams
|
||||
auto status = initializeStatus(input);
|
||||
if (!status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Buffer ~ 2 seconds of video and audio
|
||||
initializeQueues(static_cast<size_t>(ceil(getFrameRate(status->videoStream, status->videoCodecCtx))) * 2);
|
||||
|
||||
// We're done, now just put the pointer into this
|
||||
std::swap(m_input, input);
|
||||
std::swap(m_status, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
MovieProperties FFMPEGDecoder::getProperties() {
|
||||
MovieProperties props;
|
||||
props.size.width = static_cast<size_t>(m_status->videoCodecPars.width);
|
||||
props.size.height = static_cast<size_t>(m_status->videoCodecPars.height);
|
||||
|
||||
props.fps = static_cast<float>(getFrameRate(m_status->videoStream, m_status->videoCodecCtx));
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
void FFMPEGDecoder::startDecoding() {
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
|
||||
|
||||
std::unique_ptr<AudioDecoder> audioDecoder;
|
||||
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
|
||||
|
||||
if (hasAudio()) {
|
||||
audioDecoder.reset(new AudioDecoder(m_status.get()));
|
||||
}
|
||||
if (hasSubtitles()) {
|
||||
subtitleDecoder.reset(new SubtitleDecoder(m_status.get()));
|
||||
}
|
||||
|
||||
auto ctx = m_input->m_ctx->ctx();
|
||||
AVPacket packet;
|
||||
while (isDecoding()) {
|
||||
auto read_err = av_read_frame(ctx, &packet);
|
||||
AVPacketScope scope(&packet);
|
||||
|
||||
if (avio_feof(ctx->pb) != 0) {
|
||||
// EOF!!
|
||||
break;
|
||||
} else if (read_err < 0) {
|
||||
if (read_err == AVERROR_EOF) {
|
||||
// Finished reading -> break out of loop
|
||||
break;
|
||||
} else {
|
||||
// Some kind of other error, try to continue reading
|
||||
char errorStr[512];
|
||||
av_strerror(read_err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to read frame! Error: %s\n", errorStr));
|
||||
|
||||
// Skip packet
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.stream_index == m_status->videoStreamIndex) {
|
||||
videoDecoder->decodePacket(&packet);
|
||||
|
||||
VideoFramePtr ptr;
|
||||
while((ptr = videoDecoder->getFrame()) != nullptr) {
|
||||
pushFrameData(std::move(ptr));
|
||||
}
|
||||
} else if (audioDecoder && packet.stream_index == m_status->audioStreamIndex) {
|
||||
audioDecoder->decodePacket(&packet);
|
||||
|
||||
AudioFramePtr ptr;
|
||||
while ((ptr = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(ptr));
|
||||
}
|
||||
} else if (subtitleDecoder && packet.stream_index == m_status->subtitleStreamIndex) {
|
||||
subtitleDecoder->decodePacket(&packet);
|
||||
|
||||
SubtitleFramePtr ptr;
|
||||
while((ptr = subtitleDecoder->getFrame()) != nullptr) {
|
||||
pushSubtitleData(std::move(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDecoding()) {
|
||||
// If we are still alive then read the last frames from the decoders
|
||||
videoDecoder->finishDecoding();
|
||||
VideoFramePtr video_ptr;
|
||||
while ((video_ptr = videoDecoder->getFrame()) != nullptr) {
|
||||
pushFrameData(std::move(video_ptr));
|
||||
}
|
||||
|
||||
if (audioDecoder) {
|
||||
audioDecoder->finishDecoding();
|
||||
AudioFramePtr audio_frame;
|
||||
while ((audio_frame = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(audio_frame));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stopDecoder();
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasAudio() {
|
||||
return m_status->audioStreamIndex >= 0;
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasSubtitles() {
|
||||
return m_status->subtitleStreamIndex >= 0;
|
||||
}
|
||||
|
||||
void FFMPEGDecoder::close() {
|
||||
if (m_status) {
|
||||
m_status = nullptr;
|
||||
}
|
||||
|
||||
if (m_input) {
|
||||
// This will delete the InputStream pointer and free all data
|
||||
m_input = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/Decoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
struct InputStream;
|
||||
|
||||
struct DecoderStatus;
|
||||
|
||||
class FFMPEGDecoder: public Decoder {
|
||||
private:
|
||||
std::unique_ptr<InputStream> m_input;
|
||||
|
||||
std::unique_ptr<DecoderStatus> m_status;
|
||||
|
||||
public:
|
||||
FFMPEGDecoder();
|
||||
|
||||
virtual ~FFMPEGDecoder();
|
||||
|
||||
bool initialize(const SCP_string& fileName) SCP_OVERRIDE;
|
||||
|
||||
MovieProperties getProperties() SCP_OVERRIDE;
|
||||
|
||||
void startDecoding() SCP_OVERRIDE;
|
||||
|
||||
bool hasAudio() SCP_OVERRIDE;
|
||||
|
||||
bool hasSubtitles() SCP_OVERRIDE;
|
||||
|
||||
void close() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
//
|
||||
//
|
||||
|
||||
#include "SubtitleDecoder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
return pts * av_q2d(time_base);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
|
||||
SubtitleDecoder::SubtitleDecoder(cutscene::ffmpeg::DecoderStatus* status) : FFMPEGStreamDecoder(status) {
|
||||
}
|
||||
SubtitleDecoder::~SubtitleDecoder() {
|
||||
|
||||
}
|
||||
void SubtitleDecoder::decodePacket(AVPacket* packet) {
|
||||
int finishedFrame = 0;
|
||||
AVSubtitle subtitle;
|
||||
auto result = avcodec_decode_subtitle2(m_status->subtitleCodecCtx, &subtitle, &finishedFrame, packet);
|
||||
|
||||
if (result >= 0 && finishedFrame) {
|
||||
pushSubtitleFrame(packet, &subtitle);
|
||||
|
||||
avsubtitle_free(&subtitle);
|
||||
}
|
||||
}
|
||||
void SubtitleDecoder::finishDecoding() {
|
||||
|
||||
}
|
||||
void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle) {
|
||||
if (subtitle->format != 1) {
|
||||
// Non-text subtitles are not supported yet.
|
||||
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
|
||||
return;
|
||||
}
|
||||
if (subtitle->num_rects < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t pts = subtitle->pts;
|
||||
if (pts == AV_NOPTS_VALUE) {
|
||||
pts = packet->pts;
|
||||
}
|
||||
if (pts == AV_NOPTS_VALUE) {
|
||||
// Still no valid timestamp...
|
||||
return;
|
||||
}
|
||||
auto packet_time = getFrameTime(pts, m_status->subtitleStream->time_base);
|
||||
|
||||
auto start_time = packet_time + (subtitle->start_display_time / 1000.0);
|
||||
auto end_time = packet_time + (subtitle->end_display_time / 1000.0);
|
||||
if (subtitle->end_display_time == 0 && m_status->subtitleStream->time_base.num != 0) {
|
||||
end_time = packet_time + getFrameTime(packet->duration, m_status->subtitleStream->time_base);
|
||||
}
|
||||
|
||||
SCP_string processed_text;
|
||||
// For now we only use the first subtitle rectangle
|
||||
auto subtitle_rect = subtitle->rects[0];
|
||||
if (subtitle_rect->type == SUBTITLE_BITMAP) {
|
||||
// Same as above, non-text subtitles are not supported yet.
|
||||
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
|
||||
return;
|
||||
} else if (subtitle_rect->type == SUBTITLE_TEXT) {
|
||||
// Subtitle does not need to be processed any further
|
||||
processed_text = subtitle_rect->text;
|
||||
} else if (subtitle_rect->type == SUBTITLE_ASS) {
|
||||
SCP_string ass_text = subtitle_rect->ass;
|
||||
|
||||
// We are not interested in any of the other information contained in the ASS line but we still need to figure
|
||||
// out where our text starts
|
||||
auto comma_pos = ass_text.find(',');
|
||||
for (auto i = 0; i < 8 && comma_pos != SCP_string::npos; ++i) {
|
||||
comma_pos = ass_text.find(',', comma_pos + 1);
|
||||
}
|
||||
Assertion(comma_pos != SCP_string::npos, "Received an ill-formed ASS line from FFmpeg! Text was '%s'.", subtitle_rect->ass);
|
||||
|
||||
// This + 1 is safe since comma_pos points to a valid character so the next character is at worst the end of the string
|
||||
processed_text = ass_text.substr(comma_pos + 1);
|
||||
|
||||
// ASS has a special sequence for new lines that needs to be converted to an actual new line
|
||||
auto newline_pos = processed_text.find("\\N");
|
||||
while(newline_pos != SCP_string::npos) {
|
||||
processed_text.replace(newline_pos, 2, "\n");
|
||||
|
||||
newline_pos = processed_text.find("\\N");
|
||||
}
|
||||
} else {
|
||||
mprintf(("FFmpeg: Detected unknown subtitle name in movie!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove \r from string. Some subtitles use \r\n for line breaks and we only support \n
|
||||
auto ret_pos = processed_text.find('\r');
|
||||
while(ret_pos != SCP_string::npos) {
|
||||
processed_text.erase(ret_pos, 1);
|
||||
|
||||
ret_pos = processed_text.find('\r');
|
||||
}
|
||||
|
||||
SubtitleFramePtr frame(new SubtitleFrame());
|
||||
frame->text = processed_text;
|
||||
|
||||
frame->displayStartTime = start_time;
|
||||
frame->displayEndTime = end_time;
|
||||
|
||||
pushFrame(std::move(frame));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/ffmpeg/internal.h"
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
|
||||
class SubtitleDecoder: public FFMPEGStreamDecoder<SubtitleFrame> {
|
||||
public:
|
||||
explicit SubtitleDecoder(DecoderStatus* status);
|
||||
|
||||
virtual ~SubtitleDecoder();
|
||||
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
#include "cutscene/ffmpeg/VideoDecoder.h"
|
||||
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
namespace {
|
||||
const AVPixelFormat DESTINATION_FORMAT = AV_PIX_FMT_YUV420P;
|
||||
|
||||
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt) {
|
||||
return sws_getContext(width, height, fmt, width, height, DESTINATION_FORMAT,
|
||||
SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
return pts * av_q2d(time_base);
|
||||
}
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
class FFMPEGVideoFrame: public VideoFrame {
|
||||
public:
|
||||
FFMPEGVideoFrame() : frame(nullptr) {
|
||||
}
|
||||
|
||||
virtual ~FFMPEGVideoFrame() {
|
||||
if (frame != nullptr) {
|
||||
av_freep(&frame->data[0]);
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
}
|
||||
|
||||
virtual DataPointers getDataPointers() {
|
||||
DataPointers ptrs;
|
||||
ptrs.y = frame->data[0];
|
||||
ptrs.u = frame->data[1];
|
||||
ptrs.v = frame->data[2];
|
||||
|
||||
return ptrs;
|
||||
}
|
||||
|
||||
AVFrame* frame;
|
||||
};
|
||||
|
||||
VideoDecoder::VideoDecoder(DecoderStatus* status)
|
||||
: FFMPEGStreamDecoder(status),
|
||||
m_frameId(0) {
|
||||
m_swsCtx = getSWSContext(m_status->videoCodecPars.width, m_status->videoCodecPars.height,
|
||||
m_status->videoCodecPars.pixel_format);
|
||||
}
|
||||
|
||||
VideoDecoder::~VideoDecoder() {
|
||||
sws_freeContext(m_swsCtx);
|
||||
}
|
||||
|
||||
void VideoDecoder::convertAndPushPicture(const AVFrame* frame) {
|
||||
// Allocate a picture to hold the YUV data
|
||||
AVFrame* yuvFrame = av_frame_alloc();
|
||||
av_frame_copy(yuvFrame, frame);
|
||||
yuvFrame->format = DESTINATION_FORMAT;
|
||||
|
||||
av_image_alloc(yuvFrame->data,
|
||||
yuvFrame->linesize,
|
||||
m_status->videoCodecPars.width,
|
||||
m_status->videoCodecPars.height,
|
||||
DESTINATION_FORMAT,
|
||||
1);
|
||||
|
||||
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(new FFMPEGVideoFrame());
|
||||
|
||||
if (m_status->videoCodecPars.pixel_format == DESTINATION_FORMAT) {
|
||||
av_image_copy(yuvFrame->data,
|
||||
yuvFrame->linesize,
|
||||
(const uint8_t**) (frame->data),
|
||||
frame->linesize,
|
||||
DESTINATION_FORMAT,
|
||||
m_status->videoCodecPars.width,
|
||||
m_status->videoCodecPars.height);
|
||||
} else {
|
||||
// Convert frame to YUV
|
||||
sws_scale(
|
||||
m_swsCtx,
|
||||
(uint8_t const* const*) frame->data,
|
||||
frame->linesize,
|
||||
0,
|
||||
m_status->videoCodecPars.height,
|
||||
yuvFrame->data,
|
||||
yuvFrame->linesize
|
||||
);
|
||||
}
|
||||
|
||||
videoFramePtr->id = ++m_frameId;
|
||||
videoFramePtr->frameTime = getFrameTime(av_frame_get_best_effort_timestamp(frame), m_status->videoStream->time_base);
|
||||
videoFramePtr->frame = yuvFrame;
|
||||
|
||||
videoFramePtr->ySize.height = static_cast<size_t>(m_status->videoCodecPars.height);
|
||||
videoFramePtr->ySize.width = static_cast<size_t>(m_status->videoCodecPars.width);
|
||||
videoFramePtr->ySize.stride = static_cast<size_t>(yuvFrame->linesize[0]);
|
||||
|
||||
// 420P means that the UV channels have half the width and height
|
||||
videoFramePtr->uvSize.height = static_cast<size_t>(m_status->videoCodecPars.height / 2);
|
||||
videoFramePtr->uvSize.width = static_cast<size_t>(m_status->videoCodecPars.width / 2);
|
||||
videoFramePtr->uvSize.stride = static_cast<size_t>(yuvFrame->linesize[1]);
|
||||
|
||||
pushFrame(VideoFramePtr(videoFramePtr.release()));
|
||||
}
|
||||
|
||||
void VideoDecoder::decodePacket(AVPacket* packet) {
|
||||
TRACE_SCOPE(tracing::CutsceneFFmpegVideoDecoder);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
int send_result;
|
||||
do {
|
||||
send_result = avcodec_send_packet(m_status->videoCodecCtx, packet);
|
||||
|
||||
while(avcodec_receive_frame(m_status->videoCodecCtx, m_decodeFrame) == 0) {
|
||||
convertAndPushPicture(m_decodeFrame);
|
||||
}
|
||||
} while (send_result == AVERROR(EAGAIN));
|
||||
#else
|
||||
int finishedFrame = 0;
|
||||
auto result = avcodec_decode_video2(m_status->videoCodecCtx, m_decodeFrame, &finishedFrame, packet);
|
||||
|
||||
if (result >= 0 && finishedFrame) {
|
||||
convertAndPushPicture(m_decodeFrame);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VideoDecoder::finishDecoding() {
|
||||
TRACE_SCOPE(tracing::CutsceneFFmpegVideoDecoder);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
// Send flush packet
|
||||
avcodec_send_packet(m_status->videoCodecCtx, nullptr);
|
||||
|
||||
// Handle those decoders that have a delay
|
||||
while (true) {
|
||||
auto ret = avcodec_receive_frame(m_status->videoCodecCtx, m_decodeFrame);
|
||||
|
||||
if (ret == 0) {
|
||||
convertAndPushPicture(m_decodeFrame);
|
||||
} else {
|
||||
// Everything consumed or error
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Handle those decoders that have a delay
|
||||
AVPacket nullPacket;
|
||||
memset(&nullPacket, 0, sizeof(nullPacket));
|
||||
nullPacket.data = nullptr;
|
||||
nullPacket.size = 0;
|
||||
|
||||
while (true) {
|
||||
int finishedFrame = 1;
|
||||
auto err = avcodec_decode_video2(m_status->videoCodecCtx, m_decodeFrame, &finishedFrame, &nullPacket);
|
||||
|
||||
if (err < 0 || !finishedFrame) {
|
||||
break;
|
||||
}
|
||||
|
||||
convertAndPushPicture(m_decodeFrame);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "cutscene/ffmpeg/internal.h"
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
class VideoDecoder: public FFMPEGStreamDecoder<VideoFrame> {
|
||||
private:
|
||||
int m_frameId;
|
||||
SwsContext* m_swsCtx;
|
||||
|
||||
void convertAndPushPicture(const AVFrame* frame);
|
||||
|
||||
public:
|
||||
explicit VideoDecoder(DecoderStatus* status);
|
||||
|
||||
virtual ~VideoDecoder();
|
||||
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
#include "cutscene/ffmpeg/internal.h"
|
||||
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
DecoderStatus::DecoderStatus() {}
|
||||
|
||||
DecoderStatus::~DecoderStatus() {
|
||||
videoStreamIndex = -1;
|
||||
videoStream = nullptr;
|
||||
videoCodec = nullptr;
|
||||
|
||||
if (videoCodecCtx != nullptr) {
|
||||
avcodec_close(videoCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&videoCodecCtx);
|
||||
#endif
|
||||
videoCodecCtx = nullptr;
|
||||
}
|
||||
|
||||
audioStreamIndex = -1;
|
||||
audioStream = nullptr;
|
||||
audioCodec = nullptr;
|
||||
|
||||
if (audioCodecCtx != nullptr) {
|
||||
avcodec_close(audioCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&audioCodecCtx);
|
||||
#endif
|
||||
audioCodecCtx = nullptr;
|
||||
}
|
||||
|
||||
subtitleStreamIndex = -1;
|
||||
subtitleStream = nullptr;
|
||||
subtitleCodec = nullptr;
|
||||
|
||||
if (subtitleCodecCtx != nullptr) {
|
||||
avcodec_close(subtitleCodecCtx);
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
avcodec_free_context(&subtitleCodecCtx);
|
||||
#endif
|
||||
subtitleCodecCtx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ffmpeg
|
||||
} // namespace cutscene
|
||||
@@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "libs/ffmpeg/FFmpegHeaders.h"
|
||||
|
||||
#include "cutscene/Decoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
struct CodecContextParameters {
|
||||
int width = -1;
|
||||
int height = -1;
|
||||
AVPixelFormat pixel_format = AV_PIX_FMT_NONE;
|
||||
|
||||
uint64_t channel_layout = 0;
|
||||
int sample_rate = -1;
|
||||
AVSampleFormat audio_format = AV_SAMPLE_FMT_NONE;
|
||||
|
||||
AVCodecID codec_id = AV_CODEC_ID_NONE;
|
||||
};
|
||||
|
||||
struct DecoderStatus {
|
||||
int videoStreamIndex = -1;
|
||||
AVStream* videoStream = nullptr;
|
||||
CodecContextParameters videoCodecPars;
|
||||
AVCodec* videoCodec = nullptr;
|
||||
AVCodecContext* videoCodecCtx = nullptr;
|
||||
|
||||
int audioStreamIndex = -1;
|
||||
AVStream* audioStream = nullptr;
|
||||
CodecContextParameters audioCodecPars;
|
||||
AVCodec* audioCodec = nullptr;
|
||||
AVCodecContext* audioCodecCtx = nullptr;
|
||||
|
||||
int subtitleStreamIndex = -1;
|
||||
AVStream* subtitleStream = nullptr;
|
||||
CodecContextParameters subtitleCodecPars;
|
||||
AVCodec* subtitleCodec = nullptr;
|
||||
AVCodecContext* subtitleCodecCtx = nullptr;
|
||||
|
||||
DecoderStatus();
|
||||
|
||||
~DecoderStatus();
|
||||
|
||||
private:
|
||||
DecoderStatus(const DecoderStatus&) SCP_DELETED_FUNCTION;
|
||||
|
||||
DecoderStatus& operator=(const DecoderStatus&) SCP_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
template<typename Frame>
|
||||
class FFMPEGStreamDecoder {
|
||||
protected:
|
||||
typedef Frame frame_type;
|
||||
|
||||
DecoderStatus* m_status = nullptr;
|
||||
|
||||
AVFrame* m_decodeFrame = nullptr;
|
||||
|
||||
SCP_queue<FramePtr<frame_type>> m_decodedFrames;
|
||||
|
||||
void pushFrame(FramePtr<frame_type>&& frame);
|
||||
public:
|
||||
explicit FFMPEGStreamDecoder(DecoderStatus* status);
|
||||
virtual ~FFMPEGStreamDecoder();
|
||||
|
||||
FFMPEGStreamDecoder(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
|
||||
FFMPEGStreamDecoder& operator=(const FFMPEGStreamDecoder&) SCP_DELETED_FUNCTION;
|
||||
|
||||
virtual void decodePacket(AVPacket* packet) = 0;
|
||||
|
||||
virtual void finishDecoding() = 0;
|
||||
|
||||
virtual FramePtr<frame_type> getFrame();
|
||||
};
|
||||
|
||||
template <typename Frame>
|
||||
void FFMPEGStreamDecoder<Frame>::pushFrame(FramePtr<frame_type>&& frame)
|
||||
{
|
||||
m_decodedFrames.push(std::move(frame));
|
||||
}
|
||||
|
||||
template <typename Frame>
|
||||
FFMPEGStreamDecoder<Frame>::FFMPEGStreamDecoder(DecoderStatus* status):m_status(status)
|
||||
{
|
||||
m_decodeFrame = av_frame_alloc();
|
||||
}
|
||||
|
||||
template <typename Frame>
|
||||
FFMPEGStreamDecoder<Frame>::~FFMPEGStreamDecoder()
|
||||
{
|
||||
av_frame_free(&m_decodeFrame);
|
||||
}
|
||||
|
||||
template <typename Frame>
|
||||
FramePtr<typename FFMPEGStreamDecoder<Frame>::frame_type> FFMPEGStreamDecoder<Frame>::getFrame()
|
||||
{
|
||||
if (m_decodedFrames.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto frame = std::move(m_decodedFrames.front());
|
||||
m_decodedFrames.pop();
|
||||
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
+208
-95
@@ -13,64 +13,215 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "io/cursor.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "cfile/cfile.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "cutscene/cutscenes.h" // cutscene_mark_viewable()
|
||||
#include "cutscene/movie.h"
|
||||
#include "cutscene/mvelib.h"
|
||||
#include "cutscene/oggplayer.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "cutscene/player.h" // cutscene_mark_viewable()
|
||||
#include "tracing/categories.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "io/timer.h"
|
||||
#include "io/key.h"
|
||||
#include "mod_table/mod_table.h"
|
||||
|
||||
extern int Game_mode;
|
||||
extern int Is_standalone;
|
||||
|
||||
const char *movie_ext_list[] = { ".ogg", ".mve" };
|
||||
const int NUM_MOVIE_EXT = sizeof(movie_ext_list) / sizeof(char*);
|
||||
namespace {
|
||||
|
||||
using namespace cutscene;
|
||||
|
||||
#define MOVIE_NONE -1
|
||||
#define MOVIE_OGG 0
|
||||
#define MOVIE_MVE 1
|
||||
struct PlaybackState {
|
||||
bool playing = true;
|
||||
|
||||
// This module links freespace movie calls to the actual API calls the play the movie.
|
||||
// This module handles all the different requires of OS and gfx API and finding the file to play
|
||||
vec2d posTopLeft;
|
||||
vec2d posBottomRight;
|
||||
|
||||
int subtitle_font = -1;
|
||||
};
|
||||
|
||||
// filename - file to search for
|
||||
// out_name - output, full path to file
|
||||
// returns non-zero if file is found
|
||||
int movie_find(char *filename, char *out_name)
|
||||
{
|
||||
char full_path[MAX_PATH];
|
||||
char tmp_name[MAX_PATH];
|
||||
size_t size, offset = 0;
|
||||
void processEvents(PlaybackState* state) {
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
|
||||
if (out_name == NULL)
|
||||
return MOVIE_NONE;
|
||||
os_poll();
|
||||
|
||||
|
||||
memset( full_path, 0, sizeof(full_path) );
|
||||
memset( tmp_name, 0, sizeof(tmp_name) );
|
||||
|
||||
// remove extension
|
||||
strcpy_s( tmp_name, filename );
|
||||
char *p = strrchr(tmp_name, '.');
|
||||
if ( p ) *p = 0;
|
||||
|
||||
int rc = cf_find_file_location_ext(tmp_name, NUM_MOVIE_EXT, movie_ext_list, CF_TYPE_ANY, sizeof(full_path) - 1, full_path, &size, &offset, 0);
|
||||
|
||||
if (rc == MOVIE_NONE)
|
||||
return MOVIE_NONE;
|
||||
|
||||
strcpy( out_name, full_path );
|
||||
|
||||
return rc;
|
||||
int k = key_inkey();
|
||||
switch (k) {
|
||||
case KEY_ESC:
|
||||
case KEY_ENTER:
|
||||
case KEY_SPACEBAR:
|
||||
state->playing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
float print_string(float x, float y, const char* fmt, Args... params) {
|
||||
SCP_string text;
|
||||
sprintf(text, fmt, params...);
|
||||
|
||||
gr_string(x, y, text.c_str(), GR_RESIZE_NONE);
|
||||
|
||||
return y + font::get_current_font()->getHeight();
|
||||
}
|
||||
|
||||
void showVideoInfo(const PlayerState& state) {
|
||||
gr_set_color_fast(&Color_white);
|
||||
font::set_font(font::FONT1);
|
||||
|
||||
float y = 200.f;
|
||||
float x = 100.f;
|
||||
y = print_string(x, y, "Movie FPS: %f", state.props.fps);
|
||||
y = print_string(x, y, "Size: %dx%d", state.props.size.width, state.props.size.height);
|
||||
|
||||
y = gr_screen.max_h - 200.f;
|
||||
|
||||
size_t audio_queue_size = state.decoder->getAudioQueueSize();
|
||||
if (state.hasAudio) {
|
||||
ALint queued;
|
||||
OpenAL_ErrorPrint(alGetSourcei(state.audioSid, AL_BUFFERS_QUEUED, &queued));
|
||||
audio_queue_size += queued;
|
||||
}
|
||||
|
||||
y = print_string(x, y, "Audio Queue size: " SIZE_T_ARG, audio_queue_size);
|
||||
y = print_string(x, y, "Video Queue size: " SIZE_T_ARG, state.decoder->getVideoQueueSize());
|
||||
y += font::get_current_font()->getHeight();
|
||||
// Estimate the size of the video buffer
|
||||
// We use YUV420p frames so one pixel uses 1.5 bytes of storage
|
||||
size_t single_frame_size = (size_t) (state.props.size.width * state.props.size.height * 1.5);
|
||||
size_t total_size = single_frame_size * state.decoder->getVideoQueueSize();
|
||||
print_string(x, y, "Video buffer size: " SIZE_T_ARG "B", total_size);
|
||||
}
|
||||
|
||||
void displayVideo(Player* player, PlaybackState* state) {
|
||||
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
|
||||
GR_DEBUG_SCOPE("Display Video");
|
||||
|
||||
gr_clear();
|
||||
player->draw(state->posTopLeft.x, state->posTopLeft.y, state->posBottomRight.x, state->posBottomRight.y);
|
||||
|
||||
auto subtitle = player->getCurrentSubtitle();
|
||||
if (!subtitle.empty() && state->subtitle_font >= 0) {
|
||||
gr_set_color_fast(&Color_bright_white);
|
||||
font::set_font(state->subtitle_font);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
gr_get_string_size(&width, &height, subtitle.c_str());
|
||||
|
||||
// Offset the subtitle by 20% of the viewport size from the bottom
|
||||
auto y_offset = static_cast<int>((state->posBottomRight.y - state->posTopLeft.y) * 0.1);
|
||||
|
||||
auto center_x = (state->posBottomRight.x - state->posTopLeft.x) / 2;
|
||||
|
||||
auto text_x = center_x - width / 2;
|
||||
auto text_y = state->posBottomRight.y - y_offset - height;
|
||||
|
||||
gr_string(text_x, text_y, subtitle.c_str(), GR_RESIZE_NONE);
|
||||
}
|
||||
|
||||
if (Cmdline_show_video_info) {
|
||||
showVideoInfo(player->getInternalState());
|
||||
}
|
||||
|
||||
gr_flip();
|
||||
}
|
||||
void determine_display_positions(Player* player, PlaybackState* state) {
|
||||
auto& props = player->getMovieProperties();
|
||||
|
||||
float screen_ratio = (float) gr_screen.center_w / (float) gr_screen.center_h;
|
||||
float movie_ratio = (float) props.size.width / (float) props.size.height;
|
||||
|
||||
float scale_by;
|
||||
if (screen_ratio > movie_ratio) {
|
||||
scale_by = (float) gr_screen.center_h / (float) props.size.height;
|
||||
} else {
|
||||
scale_by = (float) gr_screen.center_w / (float) props.size.width;
|
||||
}
|
||||
|
||||
float screenX;
|
||||
float screenY;
|
||||
|
||||
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
|
||||
screenX = ((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f;
|
||||
screenY = ((gr_screen.center_h / 2.0f + gr_screen.center_offset_y) / scale_by) - (static_cast<int>(props.size.height) / 2.0f) + 0.5f;
|
||||
} else {
|
||||
// centers on 1024x768, fills on 640x480
|
||||
screenX = i2fl(((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x);
|
||||
screenY = i2fl(((gr_screen.center_h - static_cast<int>(props.size.height)) / 2) + gr_screen.center_offset_y);
|
||||
}
|
||||
|
||||
// set additional values for screen width/height and UV coords
|
||||
float screenXW = screenX + static_cast<int>(props.size.width);
|
||||
float screenYH = screenY + static_cast<int>(props.size.height);
|
||||
|
||||
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
|
||||
// Apply scaling
|
||||
screenX *= scale_by;
|
||||
screenY *= scale_by;
|
||||
|
||||
screenXW *= scale_by;
|
||||
screenYH *= scale_by;
|
||||
}
|
||||
|
||||
state->posTopLeft.x = screenX;
|
||||
state->posTopLeft.y = screenY;
|
||||
|
||||
state->posBottomRight.x = screenXW;
|
||||
state->posBottomRight.y = screenYH;
|
||||
}
|
||||
|
||||
void initialize_player_state(Player* player, PlaybackState* state) {
|
||||
determine_display_positions(player, state);
|
||||
|
||||
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
|
||||
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
// Compute the maximum time we will sleep to make sure we can still maintain the movie FPS
|
||||
// and not waste too much CPU time
|
||||
// We will sleep at most half the time a frame would be displayed
|
||||
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * player->getMovieProperties().fps)) * 1000.);
|
||||
|
||||
auto lastDisplayTimestamp = timer_get_microseconds();
|
||||
while (state->playing) {
|
||||
TRACE_SCOPE(tracing::CutsceneStep);
|
||||
|
||||
auto timestamp = timer_get_microseconds();
|
||||
|
||||
auto passed = timestamp - lastDisplayTimestamp;
|
||||
lastDisplayTimestamp = timestamp;
|
||||
|
||||
// Play as long as the player reports that there is more to display
|
||||
state->playing = player->update(passed);
|
||||
|
||||
displayVideo(player, state);
|
||||
|
||||
processEvents(state);
|
||||
|
||||
if (passed < sleepTime) {
|
||||
auto sleep = sleepTime - passed;
|
||||
|
||||
os_sleep(static_cast<uint>(sleep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace movie {
|
||||
// Play one movie
|
||||
bool movie_play(char *name)
|
||||
{
|
||||
bool play(const char* name) {
|
||||
// mark the movie as viewable to the player when in a campaign
|
||||
// do this before anything else so that we're sure the movie is available
|
||||
// to the player even if it's not going to play right now
|
||||
@@ -78,25 +229,7 @@ bool movie_play(char *name)
|
||||
cutscene_mark_viewable(name);
|
||||
}
|
||||
|
||||
extern int Is_standalone;
|
||||
|
||||
if (Cmdline_nomovies || Is_standalone)
|
||||
return false;
|
||||
|
||||
|
||||
char full_name[MAX_PATH];
|
||||
int rc = 0;
|
||||
|
||||
memset(full_name, 0, sizeof(full_name));
|
||||
|
||||
rc = movie_find(name, full_name);
|
||||
|
||||
if (rc == MOVIE_NONE) {
|
||||
strcpy_s(full_name, name);
|
||||
char *p = strrchr(full_name, '.');
|
||||
if ( p ) *p = 0;
|
||||
|
||||
mprintf(("Movie Error: Unable to open '%s' movie in any supported format.\n", full_name));
|
||||
if (Cmdline_nomovies || Is_standalone) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -116,38 +249,17 @@ bool movie_play(char *name)
|
||||
// clear third buffer (may not be one, but that's ok)
|
||||
gr_clear();
|
||||
|
||||
if (rc == MOVIE_OGG) {
|
||||
THEORAFILE *movie_ogg = theora_open(name);
|
||||
auto player = cutscene::Player::newPlayer(name);
|
||||
if (player) {
|
||||
PlaybackState state;
|
||||
initialize_player_state(player.get(), &state);
|
||||
|
||||
if (movie_ogg) {
|
||||
// start playing ...
|
||||
theora_play(movie_ogg);
|
||||
movie_display_loop(player.get(), &state);
|
||||
|
||||
// ... done playing, close the movie
|
||||
theora_close(movie_ogg);
|
||||
} else {
|
||||
// uh-oh, movie is invalid... Abory, Retry, Fail?
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
io::mouse::CursorManager::get()->popStatus();
|
||||
return false;
|
||||
}
|
||||
} else if (rc == MOVIE_MVE) {
|
||||
MVESTREAM *movie_mve = mve_open(name);
|
||||
|
||||
if (movie_mve) {
|
||||
// start playing ...
|
||||
mve_init(movie_mve);
|
||||
mve_play(movie_mve);
|
||||
|
||||
// ... done playing, close the movie
|
||||
mve_shutdown();
|
||||
mve_close(movie_mve);
|
||||
} else {
|
||||
// uh-oh, movie is invalid... Abory, Retry, Fail?
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
io::mouse::CursorManager::get()->popStatus();
|
||||
return false;
|
||||
}
|
||||
player->stopPlayback();
|
||||
} else {
|
||||
// uh-oh, movie is invalid... Abory, Retry, Fail?
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
}
|
||||
|
||||
// show the mouse cursor again
|
||||
@@ -156,8 +268,9 @@ bool movie_play(char *name)
|
||||
return true;
|
||||
}
|
||||
|
||||
void movie_play_two(char *name1, char *name2)
|
||||
{
|
||||
if ( movie_play(name1) )
|
||||
movie_play(name2);
|
||||
void play_two(const char* name1, const char* name2) {
|
||||
if (play(name1)) {
|
||||
play(name2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,12 @@
|
||||
#ifndef _MOVIE_HEADER_FILE
|
||||
#define _MOVIE_HEADER_FILE
|
||||
|
||||
extern const char *movie_ext_list[];
|
||||
extern const int NUM_MOVIE_EXT;
|
||||
namespace movie {
|
||||
|
||||
bool movie_play(char *name);
|
||||
void movie_play_two(char *name1, char *name2);
|
||||
bool play(const char* name);
|
||||
|
||||
void play_two(const char* name1, const char* name2);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
|
||||
static int audio_exp_table[256] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47, 51, 56, 61,
|
||||
66, 72, 79, 86, 94, 102, 112, 122, 133, 145, 158, 173, 189, 206, 225, 245,
|
||||
267, 292, 318, 348, 379, 414, 452, 493, 538, 587, 640, 699, 763, 832, 908, 991,
|
||||
1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, 2175, 2373, 2590, 2826, 3084, 3365, 3672, 4008,
|
||||
4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, 8794, 9597, 10472, 11428, 12471, 13609, 14851, 16206,
|
||||
17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, -29973, -26728, -23186, -19322, -15105, -10503, -5481, -1,
|
||||
1, 1, 5481, 10503, 15105, 19322, 23186, 26728, 29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298,
|
||||
-17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, -8794, -8059, -7385, -6767, -6202, -5683, -5208, -4772,
|
||||
-4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180,
|
||||
-1081, -991, -908, -832, -763, -699, -640, -587, -538, -493, -452, -414, -379, -348, -318, -292,
|
||||
-267, -245, -225, -206, -189, -173, -158, -145, -133, -122, -112, -102, -94, -86, -79, -72,
|
||||
-66, -61, -56, -51, -47, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33,
|
||||
-32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17,
|
||||
-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
|
||||
};
|
||||
|
||||
static int getWord(unsigned char **fin)
|
||||
{
|
||||
int value = ((*fin)[1] << 8) | (*fin)[0];
|
||||
*fin += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void sendWord(short **fout, int nOffset)
|
||||
{
|
||||
*(*fout)++ = (short)nOffset;
|
||||
}
|
||||
|
||||
static void processSwath(short *fout, unsigned char *data, int swath, int *offsets)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<swath; i++) {
|
||||
offsets[i&1] += audio_exp_table[data[i]];
|
||||
sendWord(&fout, offsets[i&1]);
|
||||
}
|
||||
}
|
||||
|
||||
void mveaudio_uncompress(short *buffer, unsigned char *data)
|
||||
{
|
||||
int nCurOffsets[2];
|
||||
int swath;
|
||||
|
||||
data += 4;
|
||||
swath = getWord(&data) / 2;
|
||||
nCurOffsets[0] = getWord(&data);
|
||||
nCurOffsets[1] = getWord(&data);
|
||||
sendWord(&buffer, nCurOffsets[0]);
|
||||
sendWord(&buffer, nCurOffsets[1]);
|
||||
processSwath(buffer, data, swath, nCurOffsets);
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "cutscene/mvelib.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
|
||||
static const char MVE_HEADER[] = "Interplay MVE File\x1A";
|
||||
static const short MVE_HDRCONST1 = 0x001A;
|
||||
static const short MVE_HDRCONST2 = 0x0100;
|
||||
static const short MVE_HDRCONST3 = 0x1133;
|
||||
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// public MVEFILE functions
|
||||
// -----------------------------------------------------------
|
||||
|
||||
// utility functions for mvefile and mveplayer
|
||||
short mve_get_short(ubyte *data)
|
||||
{
|
||||
short value;
|
||||
value = data[0] | (data[1] << 8);
|
||||
return value;
|
||||
}
|
||||
|
||||
ushort mve_get_ushort(ubyte *data)
|
||||
{
|
||||
ushort value;
|
||||
value = data[0] | (data[1] << 8);
|
||||
return value;
|
||||
}
|
||||
|
||||
int mve_get_int(ubyte *data)
|
||||
{
|
||||
int value;
|
||||
value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
||||
return value;
|
||||
}
|
||||
|
||||
// open an MVE file
|
||||
MVEFILE *mvefile_open(char *filename)
|
||||
{
|
||||
int cf_opened = 0;
|
||||
int mve_valid = 1;
|
||||
char lower_name[MAX_FILENAME_LEN];
|
||||
char buffer[20];
|
||||
MVEFILE *file;
|
||||
|
||||
// create the file
|
||||
file = (MVEFILE *)vm_malloc(sizeof(MVEFILE));
|
||||
|
||||
// set defaults
|
||||
file->stream = NULL;
|
||||
file->cur_chunk = NULL;
|
||||
file->buf_size = 0;
|
||||
file->cur_fill = 0;
|
||||
file->next_segment = 0;
|
||||
|
||||
// lower case filename for checking
|
||||
strncpy(lower_name, filename, strlen(filename)+1);
|
||||
strlwr(lower_name);
|
||||
|
||||
char *p = strchr( lower_name, '.' );
|
||||
if ( p ) *p = 0;
|
||||
|
||||
strcat_s( lower_name, ".mve" );
|
||||
|
||||
// NOTE: CF_TYPE *must* be ANY to get movies off of the CDs
|
||||
// assume lower case filename for *nix
|
||||
file->stream = cfopen(lower_name, "rb", CFILE_NORMAL, CF_TYPE_ANY);
|
||||
if ( file->stream ) {
|
||||
cf_opened = 1;
|
||||
}
|
||||
|
||||
if (!cf_opened) {
|
||||
mvefile_close(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// initialize the buffer
|
||||
file->cur_chunk = (ubyte *)vm_malloc(100 + 1024);
|
||||
file->buf_size = 100 + 1024;
|
||||
|
||||
// verify the file's header
|
||||
cfread_string(buffer, 20, file->stream);
|
||||
|
||||
if (strcmp(buffer, MVE_HEADER))
|
||||
mve_valid = 0;
|
||||
|
||||
if (cfread_short(file->stream) != MVE_HDRCONST1)
|
||||
mve_valid = 0;
|
||||
|
||||
if (cfread_short(file->stream) != MVE_HDRCONST2)
|
||||
mve_valid = 0;
|
||||
|
||||
if (cfread_short(file->stream) != MVE_HDRCONST3)
|
||||
mve_valid = 0;
|
||||
|
||||
if (!mve_valid) {
|
||||
mvefile_close(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// now, prefetch the next chunk
|
||||
mvefile_fetch_next_chunk(file);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
// close a MVE file
|
||||
void mvefile_close(MVEFILE *file)
|
||||
{
|
||||
// free the stream
|
||||
if (file->stream)
|
||||
cfclose(file->stream);
|
||||
|
||||
file->stream = NULL;
|
||||
|
||||
// free the buffer
|
||||
if (file->cur_chunk)
|
||||
vm_free(file->cur_chunk);
|
||||
|
||||
file->cur_chunk = NULL;
|
||||
|
||||
// not strictly necessary
|
||||
file->buf_size = 0;
|
||||
file->cur_fill = 0;
|
||||
file->next_segment = 0;
|
||||
|
||||
// free the struct
|
||||
vm_free(file);
|
||||
}
|
||||
|
||||
// get the size of the next segment
|
||||
int mvefile_get_next_segment_size(MVEFILE *file)
|
||||
{
|
||||
// if nothing is cached, fail
|
||||
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
|
||||
return -1;
|
||||
|
||||
// if we don't have enough data to get a segment, fail
|
||||
if (file->cur_fill - file->next_segment < 4)
|
||||
return -1;
|
||||
|
||||
// otherwise, get the data length
|
||||
return mve_get_short(file->cur_chunk + file->next_segment);
|
||||
}
|
||||
|
||||
// get type of next segment in chunk (0xff if no more segments in chunk)
|
||||
ubyte mvefile_get_next_segment_major(MVEFILE *file)
|
||||
{
|
||||
// if nothing is cached, fail
|
||||
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
|
||||
return 0xff;
|
||||
|
||||
// if we don't have enough data to get a segment, fail
|
||||
if (file->cur_fill - file->next_segment < 4)
|
||||
return 0xff;
|
||||
|
||||
// otherwise, get the data length
|
||||
return file->cur_chunk[file->next_segment + 2];
|
||||
}
|
||||
|
||||
// get subtype (version) of next segment in chunk (0xff if no more segments in chunk)
|
||||
ubyte mvefile_get_next_segment_minor(MVEFILE *file)
|
||||
{
|
||||
// if nothing is cached, fail
|
||||
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
|
||||
return 0xff;
|
||||
|
||||
// if we don't have enough data to get a segment, fail
|
||||
if (file->cur_fill - file->next_segment < 4)
|
||||
return 0xff;
|
||||
|
||||
// otherwise, get the data length
|
||||
return file->cur_chunk[file->next_segment + 3];
|
||||
}
|
||||
|
||||
// see next segment (return NULL if no next segment)
|
||||
ubyte *mvefile_get_next_segment(MVEFILE *file)
|
||||
{
|
||||
// if nothing is cached, fail
|
||||
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
|
||||
return NULL;
|
||||
|
||||
// if we don't have enough data to get a segment, fail
|
||||
if (file->cur_fill - file->next_segment < 4)
|
||||
return NULL;
|
||||
|
||||
// otherwise, get the data length
|
||||
return file->cur_chunk + file->next_segment + 4;
|
||||
}
|
||||
|
||||
// advance to next segment
|
||||
void mvefile_advance_segment(MVEFILE *file)
|
||||
{
|
||||
// if nothing is cached, fail
|
||||
if (file->cur_chunk == NULL || file->next_segment >= file->cur_fill)
|
||||
return;
|
||||
|
||||
// if we don't have enough data to get a segment, fail
|
||||
if (file->cur_fill - file->next_segment < 4)
|
||||
return;
|
||||
|
||||
// else, advance to next segment
|
||||
file->next_segment += (4 + mve_get_ushort(file->cur_chunk + file->next_segment));
|
||||
}
|
||||
|
||||
// fetch the next chunk (return 0 if at end of stream)
|
||||
int mvefile_fetch_next_chunk(MVEFILE *file)
|
||||
{
|
||||
ubyte buffer[4];
|
||||
ubyte *new_buffer;
|
||||
ushort length;
|
||||
|
||||
// fail if not open
|
||||
if (file->stream == NULL)
|
||||
return 0;
|
||||
|
||||
// fail if we can't read the next segment descriptor
|
||||
if (cfread(buffer, 1, 4, file->stream) < 4)
|
||||
return 0;
|
||||
|
||||
// pull out the next length
|
||||
length = mve_get_short(buffer);
|
||||
|
||||
// setup a new buffer if needed --
|
||||
// only allocate new buffer is old one is too small
|
||||
if (length > file->buf_size) {
|
||||
// allocate new buffer
|
||||
new_buffer = (ubyte *)vm_malloc(100 + length);
|
||||
|
||||
// copy old data
|
||||
if (file->cur_chunk && file->cur_fill)
|
||||
memcpy(new_buffer, file->cur_chunk, file->cur_fill);
|
||||
|
||||
// free old buffer
|
||||
if (file->cur_chunk) {
|
||||
vm_free(file->cur_chunk);
|
||||
file->cur_chunk = NULL;
|
||||
}
|
||||
|
||||
// install new buffer
|
||||
file->cur_chunk = new_buffer;
|
||||
file->buf_size = 100 + length;
|
||||
}
|
||||
|
||||
// read the chunk
|
||||
if (length > 0) {
|
||||
if (cfread(file->cur_chunk, 1, length, file->stream) < length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->cur_fill = length;
|
||||
file->next_segment = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// public MVESTREAM functions
|
||||
// -----------------------------------------------------------
|
||||
|
||||
// open an MVE stream
|
||||
MVESTREAM *mve_open(char *filename)
|
||||
{
|
||||
MVESTREAM *stream;
|
||||
|
||||
// allocate
|
||||
stream = (MVESTREAM *)vm_malloc(sizeof(MVESTREAM));
|
||||
|
||||
// defaults
|
||||
stream->movie = NULL;
|
||||
|
||||
// open
|
||||
stream->movie = mvefile_open(filename);
|
||||
|
||||
if (stream->movie == NULL) {
|
||||
mve_close(stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
// close an MVE stream
|
||||
void mve_close(MVESTREAM *stream)
|
||||
{
|
||||
// close MVEFILE
|
||||
if (stream->movie)
|
||||
mvefile_close(stream->movie);
|
||||
|
||||
stream->movie = NULL;
|
||||
|
||||
vm_free(stream);
|
||||
}
|
||||
|
||||
// play next chunk
|
||||
int mve_play_next_chunk(MVESTREAM *stream)
|
||||
{
|
||||
ubyte major, minor;
|
||||
ubyte *data;
|
||||
int len;
|
||||
|
||||
// loop over segments
|
||||
major = mvefile_get_next_segment_major(stream->movie);
|
||||
while (major != 0xff) {
|
||||
// check whether to handle the segment
|
||||
if (major < 32) {
|
||||
minor = mvefile_get_next_segment_minor(stream->movie);
|
||||
len = mvefile_get_next_segment_size(stream->movie);
|
||||
data = mvefile_get_next_segment(stream->movie);
|
||||
|
||||
switch (major) {
|
||||
case 0x00:
|
||||
mve_end_movie();
|
||||
break;
|
||||
case 0x01:
|
||||
mve_end_chunk();
|
||||
break;
|
||||
case 0x02:
|
||||
mve_timer_create(data);
|
||||
break;
|
||||
case 0x03:
|
||||
mve_audio_createbuf(minor, data);
|
||||
break;
|
||||
case 0x04:
|
||||
mve_audio_play();
|
||||
break;
|
||||
case 0x05:
|
||||
if (!mve_video_createbuf(minor, data))
|
||||
return 0;
|
||||
break;
|
||||
case 0x07:
|
||||
mve_video_display();
|
||||
break;
|
||||
case 0x08:
|
||||
mve_audio_data(major, data);
|
||||
break;
|
||||
case 0x09:
|
||||
mve_audio_data(major, data);
|
||||
break;
|
||||
case 0x0a:
|
||||
if (!mve_video_init(data))
|
||||
return 0;
|
||||
break;
|
||||
case 0x0c:
|
||||
mve_video_palette(data);
|
||||
break;
|
||||
case 0x0f:
|
||||
mve_video_codemap(data, len);
|
||||
break;
|
||||
case 0x11:
|
||||
mve_video_data(data, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// advance to next segment
|
||||
mvefile_advance_segment(stream->movie);
|
||||
major = mvefile_get_next_segment_major(stream->movie);
|
||||
}
|
||||
|
||||
if (!mvefile_fetch_next_chunk(stream->movie))
|
||||
return 0;
|
||||
|
||||
// return status
|
||||
return 1;
|
||||
}
|
||||
Loaded 100 of 1073 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user