mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 07:28:22 -10:00
Compare commits
1581
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
322a152476 | ||
|
|
c72a062a84 | ||
|
|
422753976f | ||
|
|
374383bacb | ||
|
|
adfce4ec60 | ||
|
|
08faf52871 | ||
|
|
d99121cd52 | ||
|
|
6ff292a43c | ||
|
|
09f4f63be4 | ||
|
|
2d67fd3ef8 | ||
|
|
5666eb5014 | ||
|
|
8542e9e113 | ||
|
|
699c9e8d52 | ||
|
|
5b45a89287 | ||
|
|
741fc311cd | ||
|
|
aaa9c779c0 | ||
|
|
bfae614189 | ||
|
|
cb956961f6 | ||
|
|
6d2ebd1ed7 | ||
|
|
d7e6187ba8 | ||
|
|
62f6ee86ef | ||
|
|
56ae91c973 | ||
|
|
dfc8cbd1c9 | ||
|
|
77e61af23c | ||
|
|
7b80b0c564 | ||
|
|
a98d3bb064 | ||
|
|
741ee07249 | ||
|
|
04cefad927 | ||
|
|
3d68476505 | ||
|
|
81c63929b5 | ||
|
|
d6d03fbb14 | ||
|
|
9acd25bc28 | ||
|
|
7e00a8b10f | ||
|
|
bb0df2dc43 | ||
|
|
38f858198b | ||
|
|
a83307402a | ||
|
|
097148c2c2 | ||
|
|
fbf8a931c4 | ||
|
|
32d951b27a | ||
|
|
630e6c3e96 | ||
|
|
72ed33502b | ||
|
|
d3806b2107 | ||
|
|
c9a481f4f3 | ||
|
|
0a02f677fe | ||
|
|
d55e4343f9 | ||
|
|
e902934e89 | ||
|
|
26395f7c12 | ||
|
|
de92fe25e3 | ||
|
|
c72fa0917b | ||
|
|
bc0f47269d | ||
|
|
94469dc43f | ||
|
|
ce335dbcc2 | ||
|
|
6660d21f7e | ||
|
|
e622d81e89 | ||
|
|
10c8e16cda | ||
|
|
25029bfdf1 | ||
|
|
2255616ed5 | ||
|
|
62ab705d75 | ||
|
|
77fc335580 | ||
|
|
981b01eea2 | ||
|
|
366dc3749c | ||
|
|
e693367dd0 | ||
|
|
da53960003 | ||
|
|
687c1ba4f7 | ||
|
|
d901470880 | ||
|
|
7e74153a3d | ||
|
|
6cf75b77dc | ||
|
|
3ec0a9c35e | ||
|
|
519f60a63b | ||
|
|
252da89782 | ||
|
|
0f1b3fd6c2 | ||
|
|
58722425a3 | ||
|
|
211110d415 | ||
|
|
61a8aa5592 | ||
|
|
0692286bba | ||
|
|
72dae916a9 | ||
|
|
189ad9f694 | ||
|
|
b9f9fa0f73 | ||
|
|
dc7e88c888 | ||
|
|
b5dae2a56e | ||
|
|
969bfd0bdd | ||
|
|
63e8ae53c5 | ||
|
|
d57aaac8e4 | ||
|
|
ab981bd415 | ||
|
|
df7c91f3e7 | ||
|
|
ee73694cc8 | ||
|
|
65dcfe0a7c | ||
|
|
ae8f8baade | ||
|
|
86fcdb1502 | ||
|
|
b71fc4595c | ||
|
|
471402ec5d | ||
|
|
97fdca6b52 | ||
|
|
b50833e6fb | ||
|
|
4429cbb21c | ||
|
|
4a6d8573a0 | ||
|
|
2c6039759c | ||
|
|
f3a0d56a85 | ||
|
|
243aac1667 | ||
|
|
19fbe05cee | ||
|
|
e581a3b8a3 | ||
|
|
67a2d99a9b | ||
|
|
569f1ee237 | ||
|
|
e9a8b9d8a2 | ||
|
|
0efb98d4a9 | ||
|
|
ec99bf9c03 | ||
|
|
bd6ff021fd | ||
|
|
69213c3338 | ||
|
|
0bffac7615 | ||
|
|
ba089bd95e | ||
|
|
0a1519284f | ||
|
|
877a138192 | ||
|
|
8a34ceef91 | ||
|
|
d638cacc51 | ||
|
|
871317b5bd | ||
|
|
9b7a87d4c5 | ||
|
|
3b07636a16 | ||
|
|
8840d238d7 | ||
|
|
95128dd734 | ||
|
|
30866afbd6 | ||
|
|
2b43677c82 | ||
|
|
94a542a2a3 | ||
|
|
5c064afd95 | ||
|
|
6ee41c06d8 | ||
|
|
58fa411ad3 | ||
|
|
08c2449672 | ||
|
|
726af82c56 | ||
|
|
c11dce4a92 | ||
|
|
0121eb6123 | ||
|
|
8a325362f6 | ||
|
|
4eb0e41142 | ||
|
|
5528e4e42d | ||
|
|
968695f851 | ||
|
|
8f00c6e842 | ||
|
|
8a9edb1215 | ||
|
|
1c9e47ad3d | ||
|
|
74fd3c0637 | ||
|
|
fe0f0558c2 | ||
|
|
11ded47bd5 | ||
|
|
f8801446db | ||
|
|
7492615a31 | ||
|
|
53cfc1eae4 | ||
|
|
252facb6c4 | ||
|
|
65417be571 | ||
|
|
0da41b3943 | ||
|
|
97f9a6c91b | ||
|
|
10cd82456d | ||
|
|
7878ba0d19 | ||
|
|
a6879a1b40 | ||
|
|
cf7706eb1c | ||
|
|
09ed127d06 | ||
|
|
77c3c79143 | ||
|
|
62b74b8743 | ||
|
|
4d99a3b8b3 | ||
|
|
3a9a840633 | ||
|
|
86f67c3c84 | ||
|
|
28bb3bf914 | ||
|
|
bd4b116188 | ||
|
|
0a429e8a32 | ||
|
|
f70253e219 | ||
|
|
e901e44418 | ||
|
|
651268eeea | ||
|
|
9b7c32d0c1 | ||
|
|
d014e53505 | ||
|
|
00b0a80ad9 | ||
|
|
4a7109e1d5 | ||
|
|
1484ddbe77 | ||
|
|
48b03a1789 | ||
|
|
e790cf209a | ||
|
|
1eea298fe1 | ||
|
|
1de63cc881 | ||
|
|
c7be4734d3 | ||
|
|
fbc2a2dab2 | ||
|
|
e5be2372e1 | ||
|
|
9c69e11fe5 | ||
|
|
0173f44070 | ||
|
|
45559c13a9 | ||
|
|
34888cb1a6 | ||
|
|
b77b425f2f | ||
|
|
49b5c10295 | ||
|
|
0396d5670b | ||
|
|
bb6c00a516 | ||
|
|
4d0703ad98 | ||
|
|
27e91d8f6c | ||
|
|
3c4ab2eef1 | ||
|
|
4e7f29ea88 | ||
|
|
793a3d8dd3 | ||
|
|
49abb88385 | ||
|
|
4c2ed1501e | ||
|
|
6b425c1e6b | ||
|
|
978a58dba2 | ||
|
|
3de05aefef | ||
|
|
da951e8be4 | ||
|
|
483a6096bb | ||
|
|
0ac810e7f0 | ||
|
|
0de1e55fb7 | ||
|
|
3827bb9783 | ||
|
|
69013f1d41 | ||
|
|
3ac7864ac6 | ||
|
|
35a654660f | ||
|
|
f975edd343 | ||
|
|
9219712ff0 | ||
|
|
ead6cd9825 | ||
|
|
a32c5dad27 | ||
|
|
34d4ed5dba | ||
|
|
eb012584d6 | ||
|
|
7cadce113d | ||
|
|
17b01fa8eb | ||
|
|
45ea62a9a2 | ||
|
|
979a4b0924 | ||
|
|
e1db71fb69 | ||
|
|
c33d406942 | ||
|
|
30baac39a9 | ||
|
|
15dc45cc0a | ||
|
|
3c41b56449 | ||
|
|
50dbbc4687 | ||
|
|
e19a6f9e01 | ||
|
|
d9184545f7 | ||
|
|
5c07d181ad | ||
|
|
140fed2812 | ||
|
|
dd2fd3ee5c | ||
|
|
dd7c36e43d | ||
|
|
409c7da2d7 | ||
|
|
791e22bc1d | ||
|
|
6a93715c9b | ||
|
|
8fee9804df | ||
|
|
2dc6d64c37 | ||
|
|
a8142b8f80 | ||
|
|
53f98cda99 | ||
|
|
115d06a051 | ||
|
|
485af1bad3 | ||
|
|
0ca5ade5ef | ||
|
|
ff601db6fc | ||
|
|
686bc35cff | ||
|
|
ffe9a085b6 | ||
|
|
33df766edf | ||
|
|
9a6227e7b0 | ||
|
|
c664eac1ee | ||
|
|
a7a9514fd1 | ||
|
|
b402d9158c | ||
|
|
c1b055a685 | ||
|
|
412197d3e9 | ||
|
|
98f1d690f6 | ||
|
|
842dbb1b75 | ||
|
|
df8e85f22e | ||
|
|
73482a6d62 | ||
|
|
afa7976018 | ||
|
|
0d355982d4 | ||
|
|
7f9021cbdb | ||
|
|
1450c71e2e | ||
|
|
d80e6d0f71 | ||
|
|
f6dd3b09ab | ||
|
|
bc5ef0b28d | ||
|
|
8e618ffaec | ||
|
|
889474688c | ||
|
|
d56cb8fc62 | ||
|
|
98f196ee48 | ||
|
|
9f4ad9d1eb | ||
|
|
a69e1d7308 | ||
|
|
34d1bf03f9 | ||
|
|
9fcd96ff97 | ||
|
|
2b77721c79 | ||
|
|
95fafa50c4 | ||
|
|
cac07391ca | ||
|
|
9daeb7f417 | ||
|
|
f0ba0265fd | ||
|
|
5b77cad5ac | ||
|
|
3f024cb324 | ||
|
|
1d60d25cf5 | ||
|
|
be5c98c7e2 | ||
|
|
6212ad29f1 | ||
|
|
5ec30bdaee | ||
|
|
b9b74a3201 | ||
|
|
09c24313d7 | ||
|
|
afdaa3a3ee | ||
|
|
68dcef639d | ||
|
|
91f351b990 | ||
|
|
dd1def4f4c | ||
|
|
8b770792fb | ||
|
|
23f9cfc815 | ||
|
|
11f9175425 | ||
|
|
4fb9c27e71 | ||
|
|
4c7b7a0fef | ||
|
|
3dc1689936 | ||
|
|
94df2777e0 | ||
|
|
c9ebc33d98 | ||
|
|
9bd459d549 | ||
|
|
d9db8bdb71 | ||
|
|
f3cdfcc229 | ||
|
|
44e3f1f9b5 | ||
|
|
da5e7f1510 | ||
|
|
d830a01381 | ||
|
|
d24d536731 | ||
|
|
6d0e166dea | ||
|
|
e0301da596 | ||
|
|
a815c0247c | ||
|
|
f42eaf9637 | ||
|
|
c667668c17 | ||
|
|
8d4643bc7a | ||
|
|
01fb2c1243 | ||
|
|
408f259368 | ||
|
|
a9b8e5c043 | ||
|
|
cfb9540e2c | ||
|
|
88115c7703 | ||
|
|
8dba6770ae | ||
|
|
8f4d51b14a | ||
|
|
185aece470 | ||
|
|
0e962e269b | ||
|
|
095a2efc56 | ||
|
|
944a254551 | ||
|
|
f628999ef9 | ||
|
|
e2fb4d84d7 | ||
|
|
ff952298a2 | ||
|
|
66b3fdfed8 | ||
|
|
451c03f76a | ||
|
|
da30c5a38e | ||
|
|
5206aaabdf | ||
|
|
f6ed93f7a9 | ||
|
|
4f0e2ae9f1 | ||
|
|
c3f595ba0e | ||
|
|
d02d98681a | ||
|
|
98e37b2570 | ||
|
|
3c8b87c958 | ||
|
|
8d44946b2b | ||
|
|
98b9d5c899 | ||
|
|
2f5079fcd1 | ||
|
|
59a8a347a1 | ||
|
|
e04f1b4ca4 | ||
|
|
7da41c32e3 | ||
|
|
73770845b6 | ||
|
|
5828d7f634 | ||
|
|
45f6cdc687 | ||
|
|
13fe34a3c7 | ||
|
|
da64f285bc | ||
|
|
45f9ea2ea4 | ||
|
|
eb73328c14 | ||
|
|
380ca12b0d | ||
|
|
c7e66e26fb | ||
|
|
ff911e666d | ||
|
|
c8619ddd0d | ||
|
|
721b2da37b | ||
|
|
e9f4c1618e | ||
|
|
4eef54c10b | ||
|
|
f5ba1e470c | ||
|
|
94a00ca6ee | ||
|
|
3a8c10bec5 | ||
|
|
e92cc5161e | ||
|
|
ea73ea33ca | ||
|
|
8fe7dc4a1b | ||
|
|
f5bbb21199 | ||
|
|
c2761a6142 | ||
|
|
88b0dba208 | ||
|
|
7173299ca7 | ||
|
|
e35fc10530 | ||
|
|
46e8e735b6 | ||
|
|
e3e40ee576 | ||
|
|
f0b99e24ff | ||
|
|
e0f76e0cfa | ||
|
|
5303440dfb | ||
|
|
138a1d01d4 | ||
|
|
0814bf0ae1 | ||
|
|
39a0cfecbb | ||
|
|
b78d940136 | ||
|
|
bc03442a3c | ||
|
|
8ce1a6f490 | ||
|
|
18d2ef8580 | ||
|
|
4a86b70a69 | ||
|
|
f717c41083 | ||
|
|
92aacc8479 | ||
|
|
2ae7990c61 | ||
|
|
4e8ebedfa0 | ||
|
|
01f418f2fb | ||
|
|
0ed47de357 | ||
|
|
f5f1c97c0f | ||
|
|
b0d3957df7 | ||
|
|
332bd01f0f | ||
|
|
eb8717f051 | ||
|
|
af8ae03d9e | ||
|
|
0ca7299bbc | ||
|
|
98234c3bc2 | ||
|
|
50691c41da | ||
|
|
4a66cb190a | ||
|
|
9ba3a0ccf9 | ||
|
|
b625f51645 | ||
|
|
c2c8acbf13 | ||
|
|
ac58950ac5 | ||
|
|
8a84fffe12 | ||
|
|
0c216ede98 | ||
|
|
3e543729fc | ||
|
|
6385bf73be | ||
|
|
b7a32329db | ||
|
|
b363bda60d | ||
|
|
0b547d971e | ||
|
|
9ac04b9349 | ||
|
|
453b1ca619 | ||
|
|
e6f1332980 | ||
|
|
5840ca84d6 | ||
|
|
aa0e1c755f | ||
|
|
97469d65ef | ||
|
|
5834c01ca9 | ||
|
|
13076364d6 | ||
|
|
e2905e76ca | ||
|
|
accea7bb4d | ||
|
|
733b67ada3 | ||
|
|
de06d1e36f | ||
|
|
7e6eb25492 | ||
|
|
9de5d8d011 | ||
|
|
62d178d896 | ||
|
|
f8b210b659 | ||
|
|
d3e6ee81e1 | ||
|
|
5b01036723 | ||
|
|
66f95312ae | ||
|
|
a737c7a373 | ||
|
|
ead93f3175 | ||
|
|
48b1e3f289 | ||
|
|
8a2641181f | ||
|
|
36e8c3b623 | ||
|
|
1c2a136ef7 | ||
|
|
72272cb8cf | ||
|
|
4062f59128 | ||
|
|
24ab091671 | ||
|
|
7cd17205b5 | ||
|
|
d58bd7db69 | ||
|
|
ce11936e56 | ||
|
|
feda97c148 | ||
|
|
a0e85e7ef5 | ||
|
|
6939403262 | ||
|
|
33e8703555 | ||
|
|
8a87d20415 | ||
|
|
b324d2892c | ||
|
|
54bd7e3963 | ||
|
|
b2230f723b | ||
|
|
f75dafde4a | ||
|
|
d70f92e782 | ||
|
|
d7e042b38a | ||
|
|
941a0c3c8a | ||
|
|
edc6b94f7f | ||
|
|
1182a485ac | ||
|
|
3cd2c40331 | ||
|
|
c13cb44df4 | ||
|
|
aede65107b | ||
|
|
197767ce94 | ||
|
|
7924c66d37 | ||
|
|
3106191cea | ||
|
|
8c4ec9b91c | ||
|
|
5bfcd1d063 | ||
|
|
923265988c | ||
|
|
c485ed8199 | ||
|
|
4353d4d47f | ||
|
|
da65a66932 | ||
|
|
7df8313b8b | ||
|
|
187affe004 | ||
|
|
f29cc2ef86 | ||
|
|
97e15ca135 | ||
|
|
868418c100 | ||
|
|
e413b10ce1 | ||
|
|
bdd740eabd | ||
|
|
d24e3c9295 | ||
|
|
13be144495 | ||
|
|
8857c4561a | ||
|
|
af4a2555db | ||
|
|
ae2c4ef098 | ||
|
|
6e509868d2 | ||
|
|
d0bc3cf91d | ||
|
|
10079c88cd | ||
|
|
3aacb6cb42 | ||
|
|
b434776d53 | ||
|
|
20925f23cc | ||
|
|
64a9e3d03a | ||
|
|
fe01372f46 | ||
|
|
7134e22322 | ||
|
|
fac618c7f0 | ||
|
|
b333104f45 | ||
|
|
c0401c24e5 | ||
|
|
2ded9aa35d | ||
|
|
ad54f588bb | ||
|
|
a64ebca805 | ||
|
|
69781cec25 | ||
|
|
137457e570 | ||
|
|
b7f3ba3660 | ||
|
|
bf6cfe61d7 | ||
|
|
990838051a | ||
|
|
597104c479 | ||
|
|
2ee5d21a10 | ||
|
|
8c1d3492eb | ||
|
|
ba5fcb971a | ||
|
|
5359b12b4f | ||
|
|
0fb7345617 | ||
|
|
a34ca578ba | ||
|
|
7f03ac31ae | ||
|
|
25b396f6a0 | ||
|
|
c6e2f94d0b | ||
|
|
9de8d45f19 | ||
|
|
7f5168e9d6 | ||
|
|
490c5d8357 | ||
|
|
011ca4bb85 | ||
|
|
a4f499ce8c | ||
|
|
5578588894 | ||
|
|
dbee42bdec | ||
|
|
783e4b5ab2 | ||
|
|
cea27244dc | ||
|
|
09084395a5 | ||
|
|
886b14e595 | ||
|
|
2fca5fd965 | ||
|
|
69cb4f0136 | ||
|
|
76d36b1c5f | ||
|
|
bf37a36e89 | ||
|
|
6750f0a4cc | ||
|
|
06a21a0f9b | ||
|
|
3d653bd770 | ||
|
|
db3d92732f | ||
|
|
4fbc0d02fa | ||
|
|
c6f75e7d14 | ||
|
|
8f4d2a27db | ||
|
|
c4bb136d80 | ||
|
|
ea2656e75f | ||
|
|
d70672d7bc | ||
|
|
ccc727a148 | ||
|
|
87ac2ca6a3 | ||
|
|
e8bd6b3929 | ||
|
|
4e7756d29f | ||
|
|
fd96dd287d | ||
|
|
dea5fd9f30 | ||
|
|
5ebf48b9b0 | ||
|
|
2dc2c0643f | ||
|
|
e761d8a8e9 | ||
|
|
36b97487c6 | ||
|
|
367825b1e0 | ||
|
|
8f5a364345 | ||
|
|
07a15286b4 | ||
|
|
8e4deb0454 | ||
|
|
aed44067df | ||
|
|
83844222c4 | ||
|
|
ba5233e33b | ||
|
|
b0bb660eb2 | ||
|
|
74f258a9b3 | ||
|
|
d7d3b8c8e2 | ||
|
|
90aeb3651c | ||
|
|
6ee7679dd6 | ||
|
|
5baae08bdf | ||
|
|
646fb64c2f | ||
|
|
7544f321d6 | ||
|
|
b2ff79fb38 | ||
|
|
94c1cf65b3 | ||
|
|
0ce2908ce6 | ||
|
|
32fbe572e4 | ||
|
|
fb0ff8f1d0 | ||
|
|
2cef1d4aa1 | ||
|
|
9dfb8faea3 | ||
|
|
9651e7dca6 | ||
|
|
51557d3aa3 | ||
|
|
521a9b9461 | ||
|
|
130057c64a | ||
|
|
f63e18957b | ||
|
|
df0be20d22 | ||
|
|
cee37e7a2f | ||
|
|
90e16ffed2 | ||
|
|
c2a52174ba | ||
|
|
e389f7669d | ||
|
|
20681f1550 | ||
|
|
be8ea029da | ||
|
|
3dbcebb56e | ||
|
|
37453ae229 | ||
|
|
9d907c99fe | ||
|
|
490ef52b85 | ||
|
|
cf1cc5e862 | ||
|
|
fc0105141b | ||
|
|
9878b48dd3 | ||
|
|
af99fee8fc | ||
|
|
1cc09d5b8b | ||
|
|
d5c5cc6eb3 | ||
|
|
b5bb5097b9 | ||
|
|
f87e5bf318 | ||
|
|
48667f0cbd | ||
|
|
66637ef5cb | ||
|
|
3b2b58e2cc | ||
|
|
d5282ca697 | ||
|
|
6a099d2adc | ||
|
|
6aa1f4899f | ||
|
|
4ec7d21965 | ||
|
|
bd5a4c4348 | ||
|
|
9135a01b1d | ||
|
|
032579923e | ||
|
|
8c1e753991 | ||
|
|
6a4c74084e | ||
|
|
3799ce7d2f | ||
|
|
2e213d5c97 | ||
|
|
0c17177a1e | ||
|
|
93ced64c6f | ||
|
|
4020b7c594 | ||
|
|
13b26fd59f | ||
|
|
15bda8c4ac | ||
|
|
39ab45dc7c | ||
|
|
16a19783ae | ||
|
|
b1bc4ef44f | ||
|
|
08e664a93a | ||
|
|
aeee05c8dd | ||
|
|
1fb3a65a90 | ||
|
|
d53dc195ee | ||
|
|
5b8880daa7 | ||
|
|
b0fc9cb31a | ||
|
|
323354295f | ||
|
|
b1881a700d | ||
|
|
357cd76252 | ||
|
|
30e70db561 | ||
|
|
2c106f8c4b | ||
|
|
73bfb7a97e | ||
|
|
4bead819f9 | ||
|
|
268828f092 | ||
|
|
1614384a6a | ||
|
|
29b6af84cc | ||
|
|
cafee143c4 | ||
|
|
6e21c8a736 | ||
|
|
bb56958dfc | ||
|
|
120750ebd2 | ||
|
|
3430a1c438 | ||
|
|
1dc2e848cd | ||
|
|
305429bf8b | ||
|
|
ae149b6061 | ||
|
|
429858d02e | ||
|
|
1448277c29 | ||
|
|
b848823a2f | ||
|
|
61c533559b | ||
|
|
04b0f5bb75 | ||
|
|
fdbba84a5b | ||
|
|
e92121bed4 | ||
|
|
079ad97987 | ||
|
|
7ae276fe6a | ||
|
|
45ddc8ac44 | ||
|
|
6fa422c5e7 | ||
|
|
35c830062d | ||
|
|
243a5bb473 | ||
|
|
09abbe1789 | ||
|
|
ad52278a67 | ||
|
|
e0a9c88241 | ||
|
|
f45dcfc09a | ||
|
|
2036ebd3a0 | ||
|
|
469270d4b6 | ||
|
|
e59df5d83c | ||
|
|
880e03e5d1 | ||
|
|
c1196f8286 | ||
|
|
40cd9e4c07 | ||
|
|
a90e480b61 | ||
|
|
142ae846f4 | ||
|
|
7a827dcb0e | ||
|
|
619cb607d0 | ||
|
|
56c34eee6d | ||
|
|
379031534d | ||
|
|
64b08f51c0 | ||
|
|
adfa12a706 | ||
|
|
d71a589b0f | ||
|
|
5118d94d5d | ||
|
|
17179d5b0b | ||
|
|
bd3632d1bf | ||
|
|
eeed22b91a | ||
|
|
48873185ce | ||
|
|
e28ebc2a6c | ||
|
|
dcac9e7223 | ||
|
|
0b4ca71eba | ||
|
|
24c3c439d5 | ||
|
|
706973cb6b | ||
|
|
91a5bfa74a | ||
|
|
7e399681cd | ||
|
|
f7b0f93c00 | ||
|
|
2721c452c4 | ||
|
|
1030e29ef7 | ||
|
|
8f06e338a4 | ||
|
|
d1a6b48beb | ||
|
|
ce8fc0a373 | ||
|
|
991f131376 | ||
|
|
ed7917cb26 | ||
|
|
e6e6288423 | ||
|
|
48a6361586 | ||
|
|
8a2faa8b99 | ||
|
|
7d139f9e80 | ||
|
|
cf93aa43c5 | ||
|
|
89e3533106 | ||
|
|
a3f9febdc4 | ||
|
|
3c738312de | ||
|
|
363d6d3ba0 | ||
|
|
5578825bf3 | ||
|
|
9b5710e8c3 | ||
|
|
b527dd5449 | ||
|
|
175668e2bb | ||
|
|
cbf3052094 | ||
|
|
3507cf96d1 | ||
|
|
e624f6c1a8 | ||
|
|
371aad8f8c | ||
|
|
cb3fd31db4 | ||
|
|
e2e7eac0c6 | ||
|
|
80faaf88b0 | ||
|
|
fb0f7dd7de | ||
|
|
62aae9d793 | ||
|
|
15663a3551 | ||
|
|
6df837e7f3 | ||
|
|
512d08e443 | ||
|
|
504abeb305 | ||
|
|
2ae2f2910c | ||
|
|
3b4fbde8e6 | ||
|
|
2d01cd2366 | ||
|
|
2beb136ecf | ||
|
|
c728cc40b2 | ||
|
|
d13ddb387f | ||
|
|
666c177dec | ||
|
|
d5ba2369a2 | ||
|
|
7bf7a8fc66 | ||
|
|
a3d2320f0a | ||
|
|
9d352ddc5f | ||
|
|
299e584284 | ||
|
|
4f22b12ec6 | ||
|
|
57985b5f1a | ||
|
|
513115ceeb | ||
|
|
95acebfce8 | ||
|
|
ca5605cfb4 | ||
|
|
ea4e5f222d | ||
|
|
538afc73a2 | ||
|
|
16560326e7 | ||
|
|
68372b18a2 | ||
|
|
c6abe74f06 | ||
|
|
f1c79c2ca7 | ||
|
|
7944eda1cb | ||
|
|
1571caa95e | ||
|
|
9f97ea909a | ||
|
|
7469558e97 | ||
|
|
6747c630af | ||
|
|
d80d8dd08e | ||
|
|
5ebf806c72 | ||
|
|
6d2d092cc6 | ||
|
|
cafee9c66a | ||
|
|
8fc281c7be | ||
|
|
8cae09bfe8 | ||
|
|
5c5e48847e | ||
|
|
ae17e3f4b7 | ||
|
|
ebfc904e52 | ||
|
|
f3a3ed982f | ||
|
|
fabf05454b | ||
|
|
d309644e53 | ||
|
|
63b21893df | ||
|
|
81f4c03364 | ||
|
|
3668ce67d5 | ||
|
|
28ddf7d8d2 | ||
|
|
b2d427fb00 | ||
|
|
3a4d5788a8 | ||
|
|
7e3ca7eb46 | ||
|
|
95620e5de6 | ||
|
|
ae738abcf5 | ||
|
|
e3c815c194 | ||
|
|
daca57de4c | ||
|
|
5650199b04 | ||
|
|
b1e392be2f | ||
|
|
9f0e21f941 | ||
|
|
5258066545 | ||
|
|
f740583547 | ||
|
|
fd92813198 | ||
|
|
fc87b129ac | ||
|
|
d5509411de | ||
|
|
a1d7ec7855 | ||
|
|
7d3bc7fc58 | ||
|
|
6ed82d88a9 | ||
|
|
8b49ebf323 | ||
|
|
4bcc85e963 | ||
|
|
55c1c3ce9d | ||
|
|
2bddcf8344 | ||
|
|
235391154e | ||
|
|
758ca86f6f | ||
|
|
6406e2fbd4 | ||
|
|
1c5bf39e8d | ||
|
|
18c2dbbde9 | ||
|
|
0b3ff5e698 | ||
|
|
5c0e88dd60 | ||
|
|
1498367e48 | ||
|
|
a8747b7b93 | ||
|
|
dadf58f6b1 | ||
|
|
e9a642673c | ||
|
|
42fbc92d73 | ||
|
|
6141fc7f73 | ||
|
|
c1fd6e7026 | ||
|
|
9114d94e0c | ||
|
|
235234ea66 | ||
|
|
512887482a | ||
|
|
04fd9679bd | ||
|
|
07a2f5a155 | ||
|
|
85874105e3 | ||
|
|
248b70b780 | ||
|
|
f05a50f57b | ||
|
|
a5fc5e322d | ||
|
|
91c4884fd3 | ||
|
|
eaad5a01a2 | ||
|
|
905417b866 | ||
|
|
5061a112db | ||
|
|
b7981c0ce4 | ||
|
|
c0328bb4f5 | ||
|
|
dd2074d91d | ||
|
|
e7a8adb367 | ||
|
|
809ac2300d | ||
|
|
8ea179781a | ||
|
|
77768b3328 | ||
|
|
873162690d | ||
|
|
5c5ce5e66a | ||
|
|
7d54dd9a05 | ||
|
|
eb322476b2 | ||
|
|
aadb22c9f1 | ||
|
|
d4b0dc9cc2 | ||
|
|
b7e703553b | ||
|
|
6b97dcfe60 | ||
|
|
8099bb737b | ||
|
|
91d6d90c9b | ||
|
|
e5e5d14108 | ||
|
|
4fa43ed639 | ||
|
|
1ace8b3abc | ||
|
|
520e532c56 | ||
|
|
9a9e088861 | ||
|
|
39f24bce23 | ||
|
|
3dd9bc8aef | ||
|
|
03aa479efc | ||
|
|
31931777bc | ||
|
|
59d0c561d6 | ||
|
|
ca55f4ea9c | ||
|
|
8c223afcd0 | ||
|
|
4dc8c57d3c | ||
|
|
82f74d570b | ||
|
|
8df4835d51 | ||
|
|
5a5dbd0df2 | ||
|
|
cc876f8bc3 | ||
|
|
45d09fd49b | ||
|
|
6fcdabeb45 | ||
|
|
2e632467f4 | ||
|
|
5c599fa9ee | ||
|
|
6b654ce38a | ||
|
|
2cba774a33 | ||
|
|
32fec00e97 | ||
|
|
66c9baf893 | ||
|
|
1c04be91bb | ||
|
|
6d52cab0a4 | ||
|
|
aa60a639fb | ||
|
|
dfd9fe7610 | ||
|
|
ef0c6b5c78 | ||
|
|
a3f493d8c1 | ||
|
|
b6981875a5 | ||
|
|
7c1147541d | ||
|
|
ef6c5d4da7 | ||
|
|
be9a881cb5 | ||
|
|
cb960a3416 | ||
|
|
194d944108 | ||
|
|
8f2aec3b9a | ||
|
|
78abbf89e6 | ||
|
|
4de3451d6c | ||
|
|
8f5f77fa42 | ||
|
|
354246caf4 | ||
|
|
4797b29311 | ||
|
|
2e0253e301 | ||
|
|
0d188fe076 | ||
|
|
c463709399 | ||
|
|
25357ce8a2 | ||
|
|
9ac97f2422 | ||
|
|
9953c6a7c4 | ||
|
|
1db36b7ba5 | ||
|
|
77b6648d22 | ||
|
|
09ca5d3dd6 | ||
|
|
942f72d09a | ||
|
|
ee27db60de | ||
|
|
66c0d27270 | ||
|
|
206364a113 | ||
|
|
ac9547d610 | ||
|
|
6534c0a3f6 | ||
|
|
cdeeee688d | ||
|
|
8b5f257d0d | ||
|
|
b2652e0628 | ||
|
|
2eea0a6eb1 | ||
|
|
67c67548fd | ||
|
|
12e45e88fa | ||
|
|
e2129355bf | ||
|
|
857582a980 | ||
|
|
c4dd593dd7 | ||
|
|
30404d4b04 | ||
|
|
c8e3e01ca0 | ||
|
|
16ed58f403 | ||
|
|
5ac2571efa | ||
|
|
7dfa5b5739 | ||
|
|
0178374b98 | ||
|
|
738e4a8153 | ||
|
|
1a4181fb67 | ||
|
|
85c2b3a7f0 | ||
|
|
508b8a176b | ||
|
|
ca313ae17f | ||
|
|
87bb2cbcc7 | ||
|
|
9e673ff7fe | ||
|
|
126b6718db | ||
|
|
b0fc182fab | ||
|
|
158292afba | ||
|
|
e334c1f736 | ||
|
|
f6fa053d94 | ||
|
|
4e24fba7fa | ||
|
|
0ea638f520 | ||
|
|
d75ec93484 | ||
|
|
468a9f280a | ||
|
|
69f4fa60f5 | ||
|
|
95ed536225 | ||
|
|
96d3eebad9 | ||
|
|
3b21b2469f | ||
|
|
cbe1d20fcc | ||
|
|
3d3bbb5dc4 | ||
|
|
4c5b1c679b | ||
|
|
65941e2e84 | ||
|
|
538adf1bf6 | ||
|
|
a6d8b6b5fa | ||
|
|
7fb5f08530 | ||
|
|
ffad093153 | ||
|
|
6a73d8f9d0 | ||
|
|
a0a88128ef | ||
|
|
6fad19c8bc | ||
|
|
119b5d662b | ||
|
|
0b612c2f1a | ||
|
|
8aee62b818 | ||
|
|
1314b8634a | ||
|
|
b557985e90 | ||
|
|
4f43a2edf3 | ||
|
|
6083c89b45 | ||
|
|
eefba9159a | ||
|
|
8fed2fcfe3 | ||
|
|
d149dd18b5 | ||
|
|
a7d624f82d | ||
|
|
aaab3fa03b | ||
|
|
0d51cb0d14 | ||
|
|
1c56d9f497 | ||
|
|
dfc8cd1168 | ||
|
|
ccaa766474 | ||
|
|
741c28d785 | ||
|
|
d73a21a579 | ||
|
|
5b8f4343a3 | ||
|
|
310785a961 | ||
|
|
9029aad64d | ||
|
|
acc018507b | ||
|
|
25698b4534 | ||
|
|
a2f6897c43 | ||
|
|
0777f24f08 | ||
|
|
ed45baa843 | ||
|
|
13ff2ec907 | ||
|
|
e795327a3f | ||
|
|
3c238d61e2 | ||
|
|
2d3e7e54e8 | ||
|
|
8ba05c1c3d | ||
|
|
277962974c | ||
|
|
eab5b8b40a | ||
|
|
842554e237 | ||
|
|
563dc35dea | ||
|
|
3fc6958f88 | ||
|
|
a886a1659c | ||
|
|
99f69c903e | ||
|
|
830fd70f9e | ||
|
|
c4ff34970f | ||
|
|
f216b8bf7f | ||
|
|
0ec2c7fef0 | ||
|
|
1f70fb2bf2 | ||
|
|
304a6a3a0d | ||
|
|
ec6bea233b | ||
|
|
9e495d7f94 | ||
|
|
0344fd6e35 | ||
|
|
b8b7d41786 | ||
|
|
3410822d9d | ||
|
|
aea63832ed | ||
|
|
1ee1886a9a | ||
|
|
c0a8ceb48f | ||
|
|
6bdbbd5c40 | ||
|
|
c66839a9bf | ||
|
|
40ba3162dc | ||
|
|
e81547ae88 | ||
|
|
7577018bd3 | ||
|
|
2181512949 | ||
|
|
dff5e4c21d | ||
|
|
d7ea260607 | ||
|
|
7f7ed74bd6 | ||
|
|
0df6c22216 | ||
|
|
e8ab065bde | ||
|
|
f79b83c60b | ||
|
|
3ab6e43254 | ||
|
|
abbef793fc | ||
|
|
bd85f61971 | ||
|
|
47967cb72a | ||
|
|
7f56037369 | ||
|
|
659828c213 | ||
|
|
2c4884595e | ||
|
|
1621bd169b | ||
|
|
c496a08ab1 | ||
|
|
012e37afb9 | ||
|
|
4fc1183622 | ||
|
|
1eaa67bb5b | ||
|
|
bf74f29634 | ||
|
|
6159e13162 | ||
|
|
1bd09a91d3 | ||
|
|
8cf0e8eb1d | ||
|
|
2dcb75057c | ||
|
|
d95f173f26 | ||
|
|
47b21f6792 | ||
|
|
5ec8896c4a | ||
|
|
560b49158b | ||
|
|
c109dc6aca | ||
|
|
581e5b0242 | ||
|
|
ace3fc619e | ||
|
|
7d418d50ce | ||
|
|
ebd24341d4 | ||
|
|
e8c80dbefc | ||
|
|
68e19a19c5 | ||
|
|
f780d9e22a | ||
|
|
c5117cf55e | ||
|
|
f9704ebd89 | ||
|
|
eb738b3ef7 | ||
|
|
f04debfb36 | ||
|
|
aa8fb89a17 | ||
|
|
44e5f89e41 | ||
|
|
fee0b900de | ||
|
|
6b209223ee | ||
|
|
cb06c73b6a | ||
|
|
7ab8a96903 | ||
|
|
a58376404d | ||
|
|
cfe89f411b | ||
|
|
91c9417d3e | ||
|
|
f37c519b79 | ||
|
|
4dd194f4d6 | ||
|
|
b38367b22f | ||
|
|
72517ff9a2 | ||
|
|
c3e212094e | ||
|
|
5f7721f300 | ||
|
|
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 | ||
|
|
3c0eec27de | ||
|
|
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 | ||
|
|
4648721674 | ||
|
|
ae4a7319e5 | ||
|
|
3c7f7f9df0 | ||
|
|
e11250f7e8 | ||
|
|
24dec72f41 | ||
|
|
89c36b68c7 | ||
|
|
e66d9d1246 | ||
|
|
789135516e | ||
|
|
91b61d446f | ||
|
|
8e5aafb6e5 | ||
|
|
cb0080bfc1 | ||
|
|
a03180c46e | ||
|
|
a18fdd2112 | ||
|
|
7c81ac1d86 | ||
|
|
bc7414c403 | ||
|
|
a7418d6dde | ||
|
|
f83c2e9cdc | ||
|
|
965a327630 | ||
|
|
1448256140 | ||
|
|
7de592bf9b | ||
|
|
783852a115 | ||
|
|
c9bb3f4caa | ||
|
|
84fd7123a5 | ||
|
|
3e1b020bf5 | ||
|
|
60d6aaccec | ||
|
|
18a957e8bf | ||
|
|
ad7bddfd41 | ||
|
|
a90d859891 | ||
|
|
ff9d06cfe1 | ||
|
|
a158029120 | ||
|
|
96e8d5b66e | ||
|
|
85fd0b0498 | ||
|
|
5d3e6789e6 | ||
|
|
b8e5a395dd | ||
|
|
1a1c3df379 | ||
|
|
0dc0d67c76 | ||
|
|
0edb360fc2 | ||
|
|
1743e5f5d4 | ||
|
|
ed3f07284d | ||
|
|
c1b222ffd5 | ||
|
|
3503b9214b | ||
|
|
aff8cc8095 | ||
|
|
884581a836 | ||
|
|
841872aae0 | ||
|
|
98af9dd903 | ||
|
|
ea37b3cb17 | ||
|
|
9b1e9600ce | ||
|
|
3035a868ab | ||
|
|
a88c50b6f2 | ||
|
|
ac24ca9fd3 | ||
|
|
07a806e01f | ||
|
|
ccd33eb50f | ||
|
|
1805c77f7c | ||
|
|
d085951767 | ||
|
|
c3f19631ce | ||
|
|
ca9eff3bc5 | ||
|
|
0a19616bc9 | ||
|
|
481ebec316 | ||
|
|
99d8b19ee8 | ||
|
|
5adc3216df | ||
|
|
55f39e088d | ||
|
|
71b572b7f4 | ||
|
|
c1908669d9 | ||
|
|
255e9aa21e | ||
|
|
a9d25fd18d | ||
|
|
72c5d17739 | ||
|
|
550f459747 | ||
|
|
ecf10d8227 | ||
|
|
8ab448dd70 | ||
|
|
ea53cff723 | ||
|
|
6da72bb1a0 | ||
|
|
c7fbefeb58 | ||
|
|
98e316bca6 | ||
|
|
78a1e5baab | ||
|
|
080ce8419a | ||
|
|
06e9248079 | ||
|
|
407888641c | ||
|
|
e04c60ed6f | ||
|
|
ac554f24c2 | ||
|
|
56670b2ed7 | ||
|
|
81d9ca8e4a | ||
|
|
7e26955853 | ||
|
|
c085eef9a0 | ||
|
|
bf2ca61e5a | ||
|
|
8061125d84 | ||
|
|
72013d4c31 | ||
|
|
93b1c0df17 | ||
|
|
41f889e55d | ||
|
|
416d45d060 | ||
|
|
18be4e854c | ||
|
|
7d92178777 | ||
|
|
ac69bd5712 | ||
|
|
d6b6ea715a | ||
|
|
ffe647be79 | ||
|
|
fff2e6d1fc | ||
|
|
23e46ae7c4 | ||
|
|
74d270270e | ||
|
|
df69d195fe | ||
|
|
8c59b06b59 | ||
|
|
6c871ac339 | ||
|
|
24afebb808 | ||
|
|
e59d31d66e | ||
|
|
19c01563ca | ||
|
|
80f1f50582 | ||
|
|
a057e111ba | ||
|
|
b45998b58d | ||
|
|
6aac8c7bde | ||
|
|
a2da77e14c | ||
|
|
7ca6b679b7 | ||
|
|
3d6bbb0b9b | ||
|
|
a912956601 | ||
|
|
a769a7ef87 | ||
|
|
991e09006e | ||
|
|
3e6c3f6f62 | ||
|
|
2ee3dd70ea | ||
|
|
c259dfb9cd | ||
|
|
2947c7972d | ||
|
|
eda8c65b58 | ||
|
|
186f8ff5b9 | ||
|
|
c86c4c3822 | ||
|
|
bea9d56feb | ||
|
|
dc6d2be515 | ||
|
|
298ec5519c | ||
|
|
7025e3443e | ||
|
|
88b87b86fc | ||
|
|
b34ca3cfed | ||
|
|
1b2eece53a | ||
|
|
472a3f09f7 | ||
|
|
e8313fa577 | ||
|
|
d6c4ff374c | ||
|
|
b14c12befa | ||
|
|
2d7606740a | ||
|
|
5a8454e956 | ||
|
|
1712a42807 | ||
|
|
f6b1eaa846 | ||
|
|
d20ff9b367 | ||
|
|
a3ab30cd96 | ||
|
|
f811d7591f | ||
|
|
7e9f0c8e6f | ||
|
|
48f76f7cd1 | ||
|
|
255814dd4f | ||
|
|
e076aa6990 | ||
|
|
16d48fbf1b | ||
|
|
937de9355b | ||
|
|
947b25e2cc | ||
|
|
e6f92f316a | ||
|
|
f65de9bb43 | ||
|
|
956e908b6e | ||
|
|
0442c1c6ac | ||
|
|
1a3b14316d | ||
|
|
350e8a2cf5 | ||
|
|
4cd9993640 | ||
|
|
41137fedbd | ||
|
|
52901e7351 | ||
|
|
eb165123ac | ||
|
|
526076f8ff | ||
|
|
c30ce55942 | ||
|
|
8236a7d7f8 | ||
|
|
70e63dcf6c | ||
|
|
557ff6be1d | ||
|
|
95896e6ec7 | ||
|
|
9447d74da8 | ||
|
|
e6acd9a313 | ||
|
|
c1cb978687 | ||
|
|
043e6a79a8 | ||
|
|
97416feb2a | ||
|
|
51698af1b0 | ||
|
|
9d3659cf88 | ||
|
|
3eddce06dd | ||
|
|
9c75a2178c | ||
|
|
d26253c5f8 | ||
|
|
aac3bbde8e | ||
|
|
6b5cac174a | ||
|
|
1f39915a5e | ||
|
|
d60306288b | ||
|
|
8f3ef45fc9 | ||
|
|
762997fc7d | ||
|
|
305e71e290 | ||
|
|
befe668c8b | ||
|
|
25e87fb8a0 | ||
|
|
9a11f232f6 | ||
|
|
49a37ccf91 | ||
|
|
ee8d03b4cf | ||
|
|
16b80faaaf | ||
|
|
0f7810fdb4 | ||
|
|
f85dfbb048 | ||
|
|
96ed407dd7 | ||
|
|
cd7cf82430 | ||
|
|
cff16f7b0b | ||
|
|
1a08bfa3e7 | ||
|
|
dbc52e2aa7 | ||
|
|
b1725bae76 | ||
|
|
4b10c61a5f | ||
|
|
c18220048d | ||
|
|
08b8c1d768 | ||
|
|
0f6a61894a | ||
|
|
3345aee144 | ||
|
|
207d3e6eba | ||
|
|
8be0a19a98 | ||
|
|
b517a47f81 | ||
|
|
4afd5d9d1c | ||
|
|
7eaff0e63f | ||
|
|
755df8c38b | ||
|
|
8357964e53 | ||
|
|
e10b431735 | ||
|
|
be5d7cc2cd | ||
|
|
2e016ccffb | ||
|
|
4305649a64 | ||
|
|
27c971a92b | ||
|
|
1e1c8c7cb8 | ||
|
|
94bb727ebe | ||
|
|
43a46641eb | ||
|
|
884259fc14 | ||
|
|
0b6a3115a7 | ||
|
|
ec6a786654 | ||
|
|
47bd990bca | ||
|
|
a3744d8818 | ||
|
|
5dc0c0d98d | ||
|
|
ad6551cf38 | ||
|
|
1cdc0840be | ||
|
|
e7f619d65e | ||
|
|
ec3313ffea | ||
|
|
f2c099a7a9 | ||
|
|
3ddc93fd9d | ||
|
|
6b32bdb732 | ||
|
|
cabc6f6412 | ||
|
|
164e20ef96 | ||
|
|
d18b97014e | ||
|
|
abdf713944 | ||
|
|
e6c6cc3864 | ||
|
|
24a3369e9d | ||
|
|
cb94183629 | ||
|
|
7ecfa209ca | ||
|
|
22105d1e3e | ||
|
|
5ee1b6d243 | ||
|
|
3577c005e2 | ||
|
|
b2891bfe21 | ||
|
|
82aa027d0d | ||
|
|
588659a367 | ||
|
|
423d14c24a | ||
|
|
2f44c3242f | ||
|
|
1167a4edcb | ||
|
|
862010b4e0 | ||
|
|
95dff1dacf | ||
|
|
bc38232f3a | ||
|
|
a29708ea89 | ||
|
|
baeb9ac78b | ||
|
|
211b9c9d71 | ||
|
|
4c05a103fa | ||
|
|
540e52ffbc | ||
|
|
902d40f3df | ||
|
|
e82fc4ac2f | ||
|
|
71673241fd | ||
|
|
0fc55babaf | ||
|
|
f93cb23d43 | ||
|
|
0415b69407 | ||
|
|
4ce085cd49 | ||
|
|
3edb4575d3 | ||
|
|
26af516704 | ||
|
|
668dccf925 | ||
|
|
acdf88fdeb | ||
|
|
577c49eedb | ||
|
|
9cd3d80b81 | ||
|
|
e8316662b8 | ||
|
|
6a82c1eee7 | ||
|
|
a309cb51b1 | ||
|
|
af60cefbd5 | ||
|
|
8e2b1f354a | ||
|
|
1d3ee16198 | ||
|
|
cb7f2a5dfd | ||
|
|
18a621764c | ||
|
|
22c7e31c8a | ||
|
|
e4775948d7 | ||
|
|
00ff9e8751 | ||
|
|
ba26f6e221 | ||
|
|
ed01e155f6 | ||
|
|
cd110bb2c1 | ||
|
|
2c30dbcda6 | ||
|
|
160d49fa82 | ||
|
|
431ad4144f | ||
|
|
2555d11427 | ||
|
|
e1882fc314 | ||
|
|
2804b5d9d3 | ||
|
|
2bbe201130 | ||
|
|
bbbc08fa87 | ||
|
|
a8def1e1b3 | ||
|
|
987a442dd6 | ||
|
|
09d39da97c | ||
|
|
0a2e6f581b | ||
|
|
98cde8f21f | ||
|
|
9d22d75ba8 | ||
|
|
df095e6bdf | ||
|
|
243f7f7ce8 | ||
|
|
32b6696162 | ||
|
|
ac8befa4e6 | ||
|
|
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 | ||
|
|
e003d08249 | ||
|
|
c8baf8b344 | ||
|
|
b5f75af66e | ||
|
|
25415342ea |
No files matched your search
+100
@@ -0,0 +1,100 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^(<.*\.(h|hh|hpp)>)$' # Includes of external libraries
|
||||
Priority: 4
|
||||
- Regex: '^(<.*>)$' # standard library includes (won't match deprecated C headers)
|
||||
Priority: 5
|
||||
- Regex: '^"[^/]*\.(h)"$' # Local includes
|
||||
Priority: 1
|
||||
- Regex: '^".*\.(h)"$' # standard engine includes
|
||||
Priority: 2
|
||||
- Regex: '.*' # Catch all in case something is unhandled above
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '$'
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
...
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
---
|
||||
Checks: "-*,\
|
||||
modernize-*,\
|
||||
-modernize-raw-string-literal,\
|
||||
-modernize-use-using,\
|
||||
-modernize-make-unique,\
|
||||
performance-*,\
|
||||
-performance-type-promotion-in-math-fn,\
|
||||
misc-*,\
|
||||
-misc-macro-parentheses,\
|
||||
-misc-misplaced-widening-cast,\
|
||||
-misc-static-assert,\
|
||||
-modernize-make-unique,\
|
||||
"
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
|
||||
AnalyzeTemporaryDtors: false
|
||||
CheckOptions:
|
||||
- key: 'misc-assert-side-effect.AssertMacros'
|
||||
value: 'assert,Assert,Assertion'
|
||||
- key: 'modernize-use-emplace.ContainersWithPushBack'
|
||||
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
|
||||
...
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
build:
|
||||
image: teaci/msys$$arch
|
||||
pull: true
|
||||
shell: mingw$$arch
|
||||
commands:
|
||||
- git submodule update --init --recursive
|
||||
- if [ $$arch = 32 ]; then target=i686; fi
|
||||
- if [ $$arch = 64 ]; then target=x86_64; fi
|
||||
- pacman -S --needed --noconfirm --noprogressbar mingw-w64-${target}-pkg-config mingw-w64-${target}-cmake
|
||||
- mkdir build && cd build
|
||||
- cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=$$CONFIGURATION -DFSO_USE_SPEECH=OFF -DFSO_USE_VOICEREC=OFF -DFSO_FATAL_WARNINGS=ON -DFSO_BUILD_FRED2=OFF ..
|
||||
- make -j$(nproc) all
|
||||
|
||||
matrix:
|
||||
arch:
|
||||
- 64
|
||||
- 32
|
||||
CONFIGURATION:
|
||||
- Debug
|
||||
- Release
|
||||
+4
-33
@@ -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
|
||||
@@ -56,9 +26,6 @@ projects/Xcode/Frameworks/
|
||||
*.unsuccessfulbuild
|
||||
ipch/
|
||||
[Oo]bj/
|
||||
[Bb]in
|
||||
[Dd]ebug*/
|
||||
[Rr]elease*/
|
||||
Ankh.NoLoad
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
@@ -286,3 +253,7 @@ CMakeSettings.json
|
||||
|
||||
# Weird files created by Linux
|
||||
.fuse_hidden*
|
||||
|
||||
# This gets ignored by one of the rules above for some reason...
|
||||
!/code/scripting/lua/LuaConvert.h
|
||||
!/code/debugconsole/
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
[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
|
||||
[submodule "lib/libRocket"]
|
||||
path = lib/libRocket
|
||||
url = https://github.com/asarium/libRocket.git
|
||||
+170
-80
@@ -1,91 +1,181 @@
|
||||
language: generic
|
||||
language: bash
|
||||
sudo: required
|
||||
dist: trusty
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/cmake
|
||||
directories:
|
||||
- $HOME/cmake-3.8
|
||||
- $HOME/.ccache
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- ninja-build
|
||||
- libopenal-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"
|
||||
notification_email: [email protected]
|
||||
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
|
||||
apt:
|
||||
packages: &global_deps
|
||||
- ninja-build
|
||||
- libopenal-dev
|
||||
- libreadline6-dev
|
||||
- libpng12-dev
|
||||
- libjpeg62-dev
|
||||
- liblua5.1-0-dev
|
||||
- libjansson-dev
|
||||
- libsdl2-dev
|
||||
- libfreetype6-dev
|
||||
- valgrind
|
||||
- qt57base
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "scp-fs2open/fs2open.github.com"
|
||||
notification_email: [email protected]
|
||||
build_command: "ci/travis/script.sh"
|
||||
# must match TRAVIS_BRANCH check below
|
||||
branch_pattern: coverity_scan
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
# 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="
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
# 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"
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Debug" CC=clang CXX=clang++
|
||||
- os: osx
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Debug"
|
||||
include:
|
||||
# note that gcc Debug MUST be 1st for Coverity
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-8 CXX=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- g++-8
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- clang-4.0
|
||||
- clang-tidy-4.0
|
||||
- libc++-dev
|
||||
script:
|
||||
- ./ci/travis/script.sh
|
||||
- ./ci/travis/clang_tidy.sh
|
||||
- os: osx
|
||||
env: CONFIGURATION="Debug"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-8 CXX=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- g++-8
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=clang-4.0 CXX=clang++-4.0
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- *global_deps
|
||||
- clang-4.0
|
||||
- libc++-dev
|
||||
- os: osx
|
||||
env: CONFIGURATION="Release"
|
||||
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
# As long as Windows is still experimental on Travis CI, allow failures
|
||||
allow_failures:
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
|
||||
- os: windows
|
||||
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
|
||||
fast_finish: true
|
||||
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: CONFIGURATION="Release"
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Release" CC=clang CXX=clang++
|
||||
- os: osx
|
||||
compiler: clang
|
||||
env: CONFIGURATION="Release"
|
||||
before_install:
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
- source "./ci/travis/check_release.sh"
|
||||
- "./ci/travis/before_install.sh"
|
||||
# ugly hack; if running a coverity scan abort all except the 1st build
|
||||
# see note re gcc compiler above needing to be 1st
|
||||
# also note that branch_pattern & the TRAVIS_BRANCH check must match
|
||||
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
|
||||
# build process
|
||||
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
|
||||
- source "./ci/travis/check_release.sh"
|
||||
- "./ci/travis/before_install.sh"
|
||||
install:
|
||||
- "./ci/travis/install.sh"
|
||||
- export PATH=$HOME/cmake/bin:$PATH
|
||||
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
|
||||
- "./ci/travis/install.sh"
|
||||
- export PATH=$HOME/cmake-3.6/bin:$PATH
|
||||
before_script:
|
||||
- "./ci/travis/before_script.sh"
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
|
||||
- "./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"
|
||||
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
|
||||
+20
-8
@@ -40,6 +40,14 @@ set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available co
|
||||
|
||||
PROJECT(FS2_Open)
|
||||
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
# Currently only GCC support ccache properly without generating additional warnings
|
||||
if(CCACHE_PROGRAM AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
message(STATUS "Using ccache for compilation: ${CCACHE_PROGRAM}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}")
|
||||
endif()
|
||||
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
|
||||
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
|
||||
@@ -53,7 +61,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 "")
|
||||
@@ -76,7 +84,6 @@ IF (WIN32)
|
||||
OPTION(FSO_BUILD_FRED2 "Build FRED2 binary" ON)
|
||||
elseif(UNIX)
|
||||
option(FSO_BUILD_APPIMAGE "Build an AppImage package" OFF)
|
||||
set(APPIMAGE_ASSISTANT "" CACHE STRING "The root directory of an AppImage clone.")
|
||||
ENDIF(WIN32)
|
||||
|
||||
OPTION(FSO_BUILD_TOOLS "Build tools related to FSO" OFF)
|
||||
@@ -85,7 +92,7 @@ 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)
|
||||
OPTION(FSO_BUILD_QTFRED "Build qtFRED2 binary" OFF)
|
||||
|
||||
IF(WIN32 OR APPLE)
|
||||
# On windows and mac the default should be to always build the included libraries
|
||||
@@ -108,6 +115,8 @@ 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(ENABLE_COTIRE "Enable cotire for faster compilation. Enabled by default." ON)
|
||||
|
||||
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
|
||||
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
|
||||
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
|
||||
@@ -115,6 +124,7 @@ 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 FSO_INSTALL_DEBUG_FILES)
|
||||
mark_as_advanced(FORCE ENABLE_COTIRE)
|
||||
|
||||
# Include cotire file from https://github.com/sakra/cotire/
|
||||
include(cotire)
|
||||
@@ -134,6 +144,8 @@ if(FSO_BUILD_APPIMAGE)
|
||||
include(appimage)
|
||||
endif()
|
||||
|
||||
include(clang-tidy)
|
||||
|
||||
# This includes source code for some tools, either used in the build or also for something else
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
|
||||
@@ -147,9 +159,9 @@ IF(FSO_BUILD_FRED2)
|
||||
ADD_SUBDIRECTORY(fred2)
|
||||
ENDIF(FSO_BUILD_FRED2)
|
||||
|
||||
IF(FSO_BUILD_WXFRED2)
|
||||
ADD_SUBDIRECTORY(wxfred2)
|
||||
ENDIF(FSO_BUILD_WXFRED2)
|
||||
IF(FSO_BUILD_QTFRED)
|
||||
ADD_SUBDIRECTORY(qtfred)
|
||||
ENDIF()
|
||||
|
||||
if(FSO_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
@@ -176,12 +188,12 @@ include(doxygen)
|
||||
|
||||
# Print used options to log
|
||||
IF (WIN32)
|
||||
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
|
||||
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
|
||||
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
|
||||
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
|
||||
elseif(UNIX)
|
||||
message(STATUS "Building AppImage: ${FSO_BUILD_APPIMAGE}")
|
||||
ENDIF()
|
||||
message(STATUS "Building FSO tools: ${FSO_BUILD_TOOLS}")
|
||||
message(STATUS "Building wxFRED: ${FSO_BUILD_WXFRED2}")
|
||||
message(STATUS "Building qtFRED: ${FSO_BUILD_QTFRED}")
|
||||
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
|
||||
+37
-12
@@ -1,4 +1,5 @@
|
||||
version: 1.0.0.{build}
|
||||
image: Visual Studio 2015
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
@@ -6,11 +7,13 @@ clone_depth: 10
|
||||
environment:
|
||||
matrix:
|
||||
- BuildID: 0
|
||||
CMAKE_GENERATOR: Visual Studio 12 2013
|
||||
PlatformToolset: v120_xp
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
PlatformToolset: v140_xp
|
||||
QT_DIR: C:\Qt\5.9\msvc2015
|
||||
- BuildID: 1
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
|
||||
PlatformToolset: v140_xp
|
||||
QT_DIR: C:\Qt\5.9\msvc2015_64
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
build_script:
|
||||
@@ -25,15 +28,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
|
||||
|
||||
- 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
|
||||
+43
-5
@@ -4,6 +4,8 @@ class BuildConfig {
|
||||
[string]$PackageType
|
||||
[string]$Toolset
|
||||
[string]$SimdType
|
||||
[string]$QtDir
|
||||
[Bool]$SourcePackage
|
||||
}
|
||||
|
||||
$NightlyConfigurations = @(
|
||||
@@ -12,12 +14,16 @@ $NightlyConfigurations = @(
|
||||
PackageType="Win64";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
SourcePackage=$false;
|
||||
},
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015";
|
||||
PackageType="Win32";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
)
|
||||
$ReleaseConfigurations = @(
|
||||
@@ -26,24 +32,32 @@ $ReleaseConfigurations = @(
|
||||
PackageType="Win32";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015";
|
||||
SourcePackage=$true;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015";
|
||||
PackageType="Win32-AVX";
|
||||
Toolset="v140_xp";
|
||||
SimdType="AVX";
|
||||
QtDir="C:\Qt\5.9\msvc2015";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015 Win64";
|
||||
PackageType="Win64";
|
||||
Toolset="v140_xp";
|
||||
SimdType="SSE2";
|
||||
QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
[BuildConfig]@{
|
||||
Generator="Visual Studio 14 2015 Win64";
|
||||
PackageType="Win64-AVX";
|
||||
Toolset="v140_xp";
|
||||
SimdType="AVX";
|
||||
QtDir="C:\Qt\5.9\msvc2015_64";
|
||||
SourcePackage=$false;
|
||||
}
|
||||
)
|
||||
|
||||
@@ -52,16 +66,21 @@ $BuildConfigurations = $null
|
||||
# Default values
|
||||
$ReleaseBuild = $false
|
||||
$NightlyBuild = $false
|
||||
$DeployBuild = $false
|
||||
$TestBuild = $false
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)")) {
|
||||
# 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 ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)")) {
|
||||
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])"
|
||||
@@ -69,19 +88,31 @@ if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REP
|
||||
$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
|
||||
}
|
||||
Write-Host "$buildID"
|
||||
|
||||
if ($ReleaseBuild -Or $NightlyBuild) {
|
||||
$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
|
||||
@@ -94,9 +125,15 @@ if ($DeployBuild) {
|
||||
}
|
||||
|
||||
$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)" `
|
||||
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=ON `
|
||||
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
|
||||
|
||||
$Configs = @("Release", "FastDebug")
|
||||
@@ -112,6 +149,7 @@ if ($DeployBuild) {
|
||||
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 `
|
||||
-DFSO_BUILD_QTFRED=ON -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
|
||||
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
|
||||
|
||||
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
|
||||
|
||||
+2
-15
@@ -1,21 +1,8 @@
|
||||
|
||||
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild)) {
|
||||
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 {
|
||||
# Appveyor doesn't have OpenAL so copy our DLLs to the output FOLDER
|
||||
$arch=""
|
||||
if ($Env:CMAKE_GENERATOR -Match "Win64") {
|
||||
$arch="win64"
|
||||
} else {
|
||||
$arch="win32"
|
||||
}
|
||||
$dllPath = "$Env:APPVEYOR_BUILD_FOLDER\lib\openal\libs\$arch\OpenAL32.dll"
|
||||
$copyDestination = "$pwd\bin\$Env:CONFIGURATION\"
|
||||
|
||||
write "Copying OpenAL DLL..."
|
||||
Copy-Item "$dllPath" "$copyDestination"
|
||||
|
||||
} else {
|
||||
write "Running unit tests..."
|
||||
# Run unit tests
|
||||
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
|
||||
|
||||
@@ -8,4 +8,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
# Nothing to do here
|
||||
:
|
||||
fi
|
||||
@@ -2,6 +2,15 @@
|
||||
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
mkdir -p /tmp/builds
|
||||
if [ "$RELEASE_BUILD" = true ]; then
|
||||
# Package the source code in release builds
|
||||
PARENT_DIR="$(basename "$PWD")"
|
||||
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
@@ -15,24 +24,31 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
|
||||
export CXXFLAGS
|
||||
export CFLAGS
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON"
|
||||
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
|
||||
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/$config" \
|
||||
-DFSO_BUILD_APPIMAGE=ON -DAPPIMAGE_ASSISTANT="$HOME/AppImageAssistant" \
|
||||
-DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON ../..
|
||||
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
|
||||
cd ..
|
||||
done
|
||||
else
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
|
||||
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
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" ..
|
||||
cmake -G "Xcode" $CMAKE_OPTIONS ..
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
|
||||
else
|
||||
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
|
||||
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
|
||||
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,10 +11,12 @@ PACKAGE_NAME=""
|
||||
|
||||
RELEASE_PATTERN="^release_(.*)$"
|
||||
NIGHTLY_PATTERN="^nightly_(.*)$"
|
||||
TEST_BUILD_PATTERN="^test\/(.*)$"
|
||||
|
||||
# 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!";
|
||||
@@ -25,13 +29,27 @@ if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
|
||||
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" =~ ^gcc.*$ ]])); then
|
||||
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
|
||||
echo "Skipping non-release compiler";
|
||||
exit 0;
|
||||
fi
|
||||
@@ -40,10 +58,16 @@ if [ "$BUILD_DEPLOYMENT" = true ]; then
|
||||
echo "Skipping non-release configuration";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
echo "Skipping non-release platform"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
export RELEASE_BUILD
|
||||
export NIGHTLY_BUILD
|
||||
export TEST_BUILD
|
||||
export BUILD_DEPLOYMENT
|
||||
export BUILD_CONFIGS
|
||||
export VERSION_NAME
|
||||
|
||||
Executable
+141
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
r"""
|
||||
ClangTidy Diff Checker
|
||||
======================
|
||||
|
||||
This script reads input from a unified diff, runs clang-tidy on all changed
|
||||
files and outputs clang-tidy warnings in changed lines only. This is useful to
|
||||
detect clang-tidy regressions in the lines touched by a specific patch.
|
||||
Example usage for git/svn users:
|
||||
|
||||
git diff -U0 HEAD^ | clang-tidy-diff.py -p1
|
||||
svn diff --diff-cmd=diff -x-U0 | \
|
||||
clang-tidy-diff.py -fix -checks=-*,modernize-use-override
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=
|
||||
'Run clang-tidy against changed files, and '
|
||||
'output diagnostics only for modified '
|
||||
'lines.')
|
||||
parser.add_argument('-clang-tidy-binary', metavar='PATH',
|
||||
default='clang-tidy',
|
||||
help='path to clang-tidy binary')
|
||||
parser.add_argument('-p', metavar='NUM', default=0,
|
||||
help='strip the smallest prefix containing P slashes')
|
||||
parser.add_argument('-regex', metavar='PATTERN', default=None,
|
||||
help='custom pattern selecting file paths to check '
|
||||
'(case sensitive, overrides -iregex)')
|
||||
parser.add_argument('-iregex', metavar='PATTERN', default=
|
||||
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
|
||||
help='custom pattern selecting file paths to check '
|
||||
'(case insensitive, overridden by -regex)')
|
||||
|
||||
parser.add_argument('-fix', action='store_true', default=False,
|
||||
help='apply suggested fixes')
|
||||
parser.add_argument('-checks',
|
||||
help='checks filter, when not specified, use clang-tidy '
|
||||
'default',
|
||||
default='')
|
||||
parser.add_argument('-path', dest='build_path',
|
||||
help='Path used to read a compile command database.')
|
||||
parser.add_argument('-extra-arg', dest='extra_arg',
|
||||
action='append', default=[],
|
||||
help='Additional argument to append to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-extra-arg-before', dest='extra_arg_before',
|
||||
action='append', default=[],
|
||||
help='Additional argument to prepend to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-quiet', action='store_true', default=False,
|
||||
help='Run clang-tidy in quiet mode')
|
||||
clang_tidy_args = []
|
||||
argv = sys.argv[1:]
|
||||
if '--' in argv:
|
||||
clang_tidy_args.extend(argv[argv.index('--'):])
|
||||
argv = argv[:argv.index('--')]
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
# Extract changed lines for each file.
|
||||
filename = None
|
||||
lines_by_file = {}
|
||||
for line in sys.stdin:
|
||||
match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
|
||||
if match:
|
||||
filename = match.group(2)
|
||||
if filename == None:
|
||||
continue
|
||||
|
||||
if args.regex is not None:
|
||||
if not re.match('^%s$' % args.regex, filename):
|
||||
continue
|
||||
else:
|
||||
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(3):
|
||||
line_count = int(match.group(3))
|
||||
if line_count == 0:
|
||||
continue
|
||||
end_line = start_line + line_count - 1;
|
||||
lines_by_file.setdefault(filename, []).append([start_line, end_line])
|
||||
|
||||
if len(lines_by_file) == 0:
|
||||
print("No relevant changes found.")
|
||||
sys.exit(0)
|
||||
|
||||
line_filter_json = json.dumps(
|
||||
[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
|
||||
separators = (',', ':'))
|
||||
|
||||
quote = "";
|
||||
if sys.platform == 'win32':
|
||||
line_filter_json=re.sub(r'"', r'"""', line_filter_json)
|
||||
else:
|
||||
quote = "'";
|
||||
|
||||
# Run clang-tidy on files containing changes.
|
||||
command = [args.clang_tidy_binary]
|
||||
command.append('-line-filter=' + quote + line_filter_json + quote)
|
||||
if args.fix:
|
||||
command.append('-fix')
|
||||
if args.checks != '':
|
||||
command.append('-checks=' + quote + args.checks + quote)
|
||||
if args.quiet:
|
||||
command.append('-quiet')
|
||||
if args.build_path is not None:
|
||||
command.append('-p=%s' % args.build_path)
|
||||
command.extend(lines_by_file.keys())
|
||||
for arg in args.extra_arg:
|
||||
command.append('-extra-arg=%s' % arg)
|
||||
for arg in args.extra_arg_before:
|
||||
command.append('-extra-arg-before=%s' % arg)
|
||||
command.extend(clang_tidy_args)
|
||||
|
||||
sys.exit(subprocess.call(' '.join(command), shell=True))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if ! git rev-list $TRAVIS_COMMIT_RANGE 2>1 >/dev/null; then
|
||||
echo "\$TRAVIS_COMMIT_RANGE ($TRAVIS_COMMIT_RANGE) is not valid for this build (probably caused by a rebase)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "$TRAVIS_BUILD_DIR"
|
||||
|
||||
echo "Running clang-tidy on changed files"
|
||||
git diff -U0 --no-color $TRAVIS_COMMIT_RANGE | \
|
||||
$TRAVIS_BUILD_DIR/ci/travis/clang-tidy-diff.py -path "$TRAVIS_BUILD_DIR/build" -p1 \
|
||||
-regex 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$|tools/.*' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-4.0 2>/dev/null | \
|
||||
tee clang-tidy-output.txt
|
||||
|
||||
if [[ -n $(grep "warning: " clang-tidy-output.txt) ]] || [[ -n $(grep "error: " clang-tidy-output.txt) ]]; then
|
||||
echo "Errors or warnings were detected in the clang-tidy output!"
|
||||
exit 1
|
||||
else
|
||||
echo -e "\033[1;32m\xE2\x9C\x93 passed:\033[0m clang-tidy test succeeded";
|
||||
fi
|
||||
@@ -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
|
||||
+12
-9
@@ -4,28 +4,31 @@ set -ex
|
||||
|
||||
FILENAME=
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
if [ ! -d "$HOME/cmake/bin" ]; then
|
||||
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
|
||||
# If the cache does not currently contain CMake then download and install it
|
||||
FILENAME=cmake-3.4.3-Linux-x86_64
|
||||
mkdir -p $HOME/cmake-3.8/
|
||||
|
||||
mkdir -p $HOME/cmake/
|
||||
|
||||
wget -O /tmp/cmake.tar.gz --no-check-certificate https://www.cmake.org/files/v3.4/$FILENAME.tar.gz
|
||||
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake/ --strip-components=1
|
||||
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
|
||||
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
|
||||
fi
|
||||
export PATH=$HOME/cmake/bin:$PATH
|
||||
export PATH=$HOME/cmake-3.8/bin:$PATH
|
||||
|
||||
cd $HOME
|
||||
|
||||
if [ "${BUILD_DEPLOYMENT}" = true ]; then
|
||||
wget -c "https://github.com/probonopd/AppImageKit/releases/download/5/AppImageAssistant" # (64-bit)
|
||||
chmod a+x ./AppImageAssistant
|
||||
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./appimagetool
|
||||
|
||||
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
|
||||
chmod a+x ./linuxdeployqt
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
gem install xcpretty
|
||||
|
||||
brew update
|
||||
brew outdated cmake || brew upgrade cmake
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
choco install mingw ninja
|
||||
fi
|
||||
|
||||
cmake --version
|
||||
+34
-1
@@ -8,7 +8,40 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
for config in $BUILD_CONFIGS
|
||||
do
|
||||
cd "$config"
|
||||
ninja appimage
|
||||
|
||||
# Compile all targets
|
||||
ninja all
|
||||
|
||||
# Install Freespace2 targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Freespace2 -P cmake_install.cmake
|
||||
|
||||
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
|
||||
FILENAME="$(find /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
|
||||
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
|
||||
|
||||
: <<'END'
|
||||
# Install qtFRED targets
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
|
||||
|
||||
PREV="$(pwd)"
|
||||
cd /tmp/release/$config/qtfred
|
||||
|
||||
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
|
||||
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
|
||||
# Move our AppRun script to the right location
|
||||
mv usr/AppRun AppRun
|
||||
|
||||
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
|
||||
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
|
||||
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
|
||||
|
||||
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
|
||||
|
||||
cd "$PREV"
|
||||
END
|
||||
|
||||
cd ..
|
||||
done
|
||||
|
||||
|
||||
+14
-3
@@ -5,10 +5,15 @@ set -e
|
||||
cd build
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
ninja all
|
||||
ninja -k 20 all
|
||||
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug" ]; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
else
|
||||
./bin/unittests --gtest_shuffle
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
@@ -17,4 +22,10 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
|
||||
exit $XCODE_RET
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
|
||||
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
|
||||
cmake --build . --config "$CONFIGURATION"
|
||||
else
|
||||
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
|
||||
fi
|
||||
fi
|
||||
+16
-1
@@ -25,4 +25,19 @@
|
||||
fun:_dl_init
|
||||
fun:dl_open_worker
|
||||
fun:_dl_catch_error
|
||||
}
|
||||
}
|
||||
{
|
||||
CLang Lua unitialized value error
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:luaH_get
|
||||
fun:lua_rawget
|
||||
fun:_ZN12_GLOBAL__N_117ade_index_handlerEP9lua_State
|
||||
}
|
||||
{
|
||||
False-positive uninitialized variable warning
|
||||
Memcheck:Cond
|
||||
fun:_Z23cf_check_location_flagsjj
|
||||
fun:_Z29cf_create_default_path_stringPcjiPKcbj
|
||||
...
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=FreeSpace Open
|
||||
Exec=$<TARGET_FILE_NAME:Freespace2>
|
||||
Icon=app_icon.png
|
||||
Icon=app_icon
|
||||
Categories=Game;
|
||||
+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)
|
||||
|
||||
@@ -6,18 +6,16 @@ configure_file("${CMAKE_CURRENT_LIST_DIR}/AppRun.in" "${CMAKE_CURRENT_BINARY_DIR
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>"
|
||||
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen")
|
||||
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>" DESTINATION "." RENAME "AppRun")
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>" DESTINATION "." RENAME "AppRun"
|
||||
COMPONENT "Freespace2")
|
||||
|
||||
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/AppImage.desktop.in" "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen" @ONLY)
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop"
|
||||
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen")
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop" DESTINATION "." RENAME "fso.desktop")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop" DESTINATION "." RENAME "fso.desktop"
|
||||
COMPONENT "Freespace2")
|
||||
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION ".")
|
||||
|
||||
add_custom_target(appimage
|
||||
COMMAND "${APPIMAGE_ASSISTANT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/fs2_open_${FSO_BINARY_SUFFIX}.AppImage")
|
||||
|
||||
add_dependencies(appimage install)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION "."
|
||||
COMPONENT "Freespace2")
|
||||
@@ -0,0 +1,37 @@
|
||||
option(ENABLE_CLANG_TIDY "Enable source code checking using clang-tidy" OFF)
|
||||
|
||||
find_program(
|
||||
CLANG_TIDY_EXE
|
||||
NAMES "clang-tidy"
|
||||
DOC "Path to clang-tidy executable"
|
||||
)
|
||||
|
||||
function(enable_clang_tidy target)
|
||||
# Not enabled in this configuration
|
||||
endfunction()
|
||||
|
||||
if(NOT ENABLE_CLANG_TIDY)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${CLANG_TIDY_EXE}")
|
||||
message(SEND_ERROR "clang-tidy: Could not find clang-tidy executable (value of variable is \"${CLANG_TIDY_EXE}\".")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS "3.6.0")
|
||||
message(SEND_ERROR "Clang-tidy support requires CMake 3.6")
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "clang-tidy: Using \"${CLANG_TIDY_EXE}\"")
|
||||
|
||||
function(enable_clang_tidy target)
|
||||
SET(TIDY_OPTIONS "${CLANG_TIDY_EXE}")
|
||||
if(FSO_FATAL_WARNINGS)
|
||||
set(TIDY_OPTIONS "${TIDY_OPTIONS};-warnings-as-errors=*")
|
||||
endif()
|
||||
|
||||
set_target_properties(${target} PROPERTIES CXX_CLANG_TIDY "${TIDY_OPTIONS}")
|
||||
endfunction()
|
||||
|
||||
@@ -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";
|
||||
|
||||
Vendored
-1
Submodule cmake/external/cotire deleted from 40a46bf2fb.
Vendored
+4054
File diff suppressed because it is too large.
Load diff
@@ -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,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()
|
||||
@@ -7,6 +7,7 @@ include(CheckLibraryExists)
|
||||
include(CheckPrototypeDefinition)
|
||||
include(CheckStructHasMember)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckCXXSymbolExists)
|
||||
include(CheckTypeSize)
|
||||
|
||||
CHECK_INCLUDE_FILE("execinfo.h" HAVE_EXECINFO_H)
|
||||
@@ -14,10 +15,22 @@ 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)
|
||||
|
||||
@@ -28,5 +41,8 @@ CHECK_FUNCTION_EXISTS(strlwr HAVE_STRLWR)
|
||||
|
||||
CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
|
||||
|
||||
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
|
||||
check_symbol_exists(_snprintf "stdio.h" HAVE__SNPRINTF)
|
||||
|
||||
set(PLATFORM_CHECK_HEADER "${GENERATED_SOURCE_DIR}/platformChecks.h")
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/platformChecks.h.in "${PLATFORM_CHECK_HEADER}")
|
||||
@@ -8,6 +8,9 @@
|
||||
#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
|
||||
@@ -19,4 +22,10 @@
|
||||
|
||||
#cmakedefine01 HAVE_STRINGS_H
|
||||
|
||||
#cmakedefine01 HAVE_CHAR32_T
|
||||
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
|
||||
|
||||
#cmakedefine01 HAVE_SNPRINTF
|
||||
#cmakedefine01 HAVE__SNPRINTF
|
||||
|
||||
#endif // __PLATFORM_CHECKS_H__
|
||||
@@ -9,8 +9,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -funroll-loops -fsigned-char -Wno-
|
||||
# Omit "conversion from string literal to 'char *' is deprecated" warnings.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
|
||||
|
||||
@@ -66,21 +66,17 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} ${SANITIZE_FLAGS}")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wformat-security")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-function")
|
||||
|
||||
# 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")
|
||||
|
||||
check_cxx_compiler_flag(-Wshift-negative-value SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
||||
if(SUPPORTS_SHIFT_NEGATIVE_VALUE)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-shift-negative-value")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable")
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
|
||||
@@ -78,16 +78,23 @@ 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")
|
||||
# These two warnings cause a lot of false-positives in the FSO code base
|
||||
check_cxx_compiler_flag(-Wstringop-truncation SUPPORTS_STRINGOP_TRUNCATION)
|
||||
if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-truncation")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered")
|
||||
check_cxx_compiler_flag(-Wstringop-overflow SUPPORTS_STRINGOP_OVERFLOW)
|
||||
if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
@@ -105,6 +112,7 @@ set(CMAKE_EXE_LINKER_FLAGS "")
|
||||
|
||||
IF (MINGW)
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++ -Wl,--enable-auto-import")
|
||||
target_compile_definitions(compiler INTERFACE __USE_MINGW_ANSI_STDIO=1)
|
||||
ENDIF(MINGW)
|
||||
|
||||
if (SANITIZE_FLAGS)
|
||||
@@ -131,4 +139,4 @@ if (FSO_FATAL_WARNINGS)
|
||||
endif()
|
||||
|
||||
# Always define this to make sure that the fixed width format macros are available
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
|
||||
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS=1)
|
||||
@@ -33,7 +33,10 @@ set(WARNING_FLAGS
|
||||
/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
|
||||
/wd4723 # "potential divide by 0" is caused by some code that definitely will not divide by zero - m!m
|
||||
)
|
||||
|
||||
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
|
||||
@@ -88,7 +91,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)
|
||||
@@ -133,9 +136,9 @@ else()
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE
|
||||
_CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX "$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>")
|
||||
|
||||
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX
|
||||
"$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>" _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
|
||||
|
||||
if (FSO_FATAL_WARNINGS)
|
||||
# Make warnings fatal if the right variable is set
|
||||
target_compile_options(compiler INTERFACE "/WX")
|
||||
|
||||
@@ -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)
|
||||
|
||||
+44
-4
@@ -10,7 +10,7 @@ FUNCTION(ADD_IMPORTED_LIB NAME INCLUDES LIBS)
|
||||
|
||||
target_link_libraries(${NAME} INTERFACE "${LIBS}")
|
||||
|
||||
target_include_directories(${NAME} INTERFACE "${INCLUDES}")
|
||||
target_include_directories(${NAME} SYSTEM INTERFACE "${INCLUDES}")
|
||||
ENDFUNCTION(ADD_IMPORTED_LIB)
|
||||
|
||||
MACRO(PKG_CONFIG_LIB_RESOLVE NAME OUTVAR)
|
||||
@@ -141,10 +141,12 @@ macro(set_if_not_defined VAR VALUE)
|
||||
endmacro(set_if_not_defined)
|
||||
|
||||
macro(configure_cotire target)
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
if(ENABLE_COTIRE)
|
||||
# Disable unity build as it doesn't work well for us
|
||||
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
|
||||
|
||||
cotire(${target})
|
||||
cotire(${target})
|
||||
endif()
|
||||
endmacro(configure_cotire)
|
||||
|
||||
macro(add_target_copy_files)
|
||||
@@ -195,3 +197,41 @@ function(suppress_warnings _target)
|
||||
target_compile_options(${_target} PRIVATE "-w")
|
||||
endif()
|
||||
endfunction(suppress_warnings)
|
||||
|
||||
|
||||
function(list_target_dependencies _target _out_var)
|
||||
set(out_list)
|
||||
set(work_libs ${_target})
|
||||
list(LENGTH work_libs libs_length)
|
||||
|
||||
while(libs_length GREATER 0)
|
||||
list(GET work_libs 0 current)
|
||||
list(REMOVE_AT work_libs 0)
|
||||
list(APPEND out_list ${current})
|
||||
|
||||
get_target_property(current_libs ${current} INTERFACE_LINK_LIBRARIES)
|
||||
|
||||
if(current_libs)
|
||||
foreach(lib ${current_libs})
|
||||
if (TARGET ${lib})
|
||||
list(APPEND work_libs ${lib})
|
||||
endif (TARGET ${lib})
|
||||
endforeach(lib)
|
||||
endif(current_libs)
|
||||
|
||||
list(LENGTH work_libs libs_length)
|
||||
endwhile(libs_length GREATER 0)
|
||||
|
||||
list(REMOVE_DUPLICATES out_list)
|
||||
set(${_out_var} ${out_list} PARENT_SCOPE)
|
||||
endfunction(list_target_dependencies)
|
||||
|
||||
macro(add_file_folder FOLDER_NAME)
|
||||
string(MAKE_C_IDENTIFIER "${FOLDER_NAME}" VARIABLE_NAME)
|
||||
set(files_${VARIABLE_NAME} ${files_${VARIABLE_NAME}} ${ARGN})
|
||||
|
||||
string(REPLACE "/" "\\" FIXED_FOLDER_FILE "${FOLDER_NAME}")
|
||||
|
||||
source_group("${FIXED_FOLDER_FILE}" FILES ${ARGN})
|
||||
set(source_files ${source_files} ${ARGN})
|
||||
endmacro(add_file_folder)
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+25
-5
@@ -3,7 +3,7 @@ INCLUDE(source_groups.cmake)
|
||||
|
||||
INCLUDE(voice_rec.cmake)
|
||||
|
||||
ADD_LIBRARY(code STATIC ${file_root} ${VOICE_REC_FILES})
|
||||
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
|
||||
|
||||
target_compile_features(code PUBLIC ${REQUIRED_CXX_FEATURES})
|
||||
|
||||
@@ -21,7 +21,7 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
|
||||
|
||||
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})
|
||||
@@ -30,11 +30,19 @@ TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
|
||||
|
||||
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)
|
||||
|
||||
target_link_libraries(code PUBLIC discord-rpc)
|
||||
|
||||
target_link_libraries(code PUBLIC libRocket)
|
||||
|
||||
enable_clang_tidy(code)
|
||||
|
||||
IF (FSO_USE_SPEECH)
|
||||
find_package(Speech REQUIRED)
|
||||
target_link_libraries(code PUBLIC speech)
|
||||
@@ -53,13 +61,25 @@ IF(FSO_BUILD_TOOLS)
|
||||
ADD_SUBDIRECTORY(cfileextractor)
|
||||
ENDIF(FSO_BUILD_TOOLS)
|
||||
|
||||
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_header.h")
|
||||
if (ENABLE_COTIRE)
|
||||
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h")
|
||||
else()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
|
||||
ELSE()
|
||||
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
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")
|
||||
|
||||
+4
-9
@@ -567,9 +567,9 @@ extern void ai_dock_with_object(object *docker, int docker_index, object *dockee
|
||||
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, 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 ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum);
|
||||
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, int sexp_flags = 0);
|
||||
extern void init_ai_object(int objnum);
|
||||
extern void ai_init(void); // Call this one to parse ai.tbl.
|
||||
extern void ai_level_init(void); // Call before each level to reset AI
|
||||
@@ -587,13 +587,10 @@ extern void get_absolute_wing_pos_autopilot( vec3d *result_pos, object *leader_o
|
||||
|
||||
// Interface from goals code to AI. Set ship to guard. *objp guards *other_objp
|
||||
extern void ai_set_guard_object(object *objp, object *other_objp);
|
||||
extern void ai_set_evade_object(object *objp, object *other_objp);
|
||||
extern void ai_set_guard_wing(object *objp, int wingnum);
|
||||
extern void ai_warp_out(object *objp, vec3d *vp);
|
||||
extern void ai_attack_wing(object *attacker, int wingnum);
|
||||
extern void ai_deathroll_start(object *ship_obj);
|
||||
extern void ai_fly_in_formation(int wing_num); // Force wing to fly in formation.
|
||||
extern void ai_disband_formation(int wing_num); // Force wing to disband formation flying.
|
||||
extern int set_target_objnum(ai_info *aip, int objnum);
|
||||
extern void ai_form_on_wing(object *objp, object *goal_objp);
|
||||
extern void ai_do_stay_near(object *objp, object *other_obj, float dist);
|
||||
@@ -622,7 +619,7 @@ extern float ai_path();
|
||||
extern void evade_weapon();
|
||||
extern int might_collide_with_ship(object *obj1, object *obj2, float dot_to_enemy, float dist_to_enemy, float duration);
|
||||
extern int ai_fire_primary_weapon(object *objp); //changed to return weather it fired-Bobboau
|
||||
extern int ai_fire_secondary_weapon(object *objp, int priority1 = -1, int priority2 = -1);
|
||||
extern int ai_fire_secondary_weapon(object *objp);
|
||||
extern float ai_get_weapon_dist(ship_weapon *swp);
|
||||
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override);
|
||||
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
|
||||
@@ -646,8 +643,6 @@ extern void ai_do_objects_repairing_stuff( object *repaired_obj, object *repair_
|
||||
// Move to a position relative to a dock bay using thrusters.
|
||||
extern float dock_orient_and_approach(object *docker_objp, int docker_index, object *dockee_objp, int dockee_index, int dock_mode, rotating_dockpoint_info *rdinfo = NULL);
|
||||
|
||||
extern int find_danger_weapon(object *sobjp, float dtime, float *atime, float dot_threshhold);
|
||||
|
||||
void ai_set_mode_warp_out(object *objp, ai_info *aip);
|
||||
|
||||
// prototyped by Goober5000
|
||||
|
||||
@@ -87,6 +87,7 @@ namespace AI {
|
||||
Fix_heat_seeker_stealth_bug,
|
||||
Fix_linked_primary_bug,
|
||||
Force_beam_turret_fov,
|
||||
Free_afterburner_use,
|
||||
Glide_decay_requires_thrust,
|
||||
Hack_improve_non_homing_swarm_turret_fire_accuracy,
|
||||
Huge_turret_weapons_ignore_bombs,
|
||||
@@ -109,7 +110,9 @@ namespace AI {
|
||||
Smart_shield_management,
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turred_tagged_only_targeting,
|
||||
Support_dont_add_primaries, //Prevents support ship from equipping new primary as requested in http://scp.indiegames.us/mantis/view.php?id=3198
|
||||
Turrets_ignore_target_radius,
|
||||
Use_actual_primary_range,
|
||||
Use_additive_weapon_velocity,
|
||||
Use_newtonian_dampening,
|
||||
Use_only_single_fov_for_turrets,
|
||||
|
||||
@@ -357,6 +357,8 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
|
||||
|
||||
set_flag(profile, "$free afterburner use:", AI::Profile_Flags::Free_afterburner_use);
|
||||
|
||||
set_flag(profile, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
|
||||
|
||||
set_flag(profile, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
|
||||
@@ -433,6 +435,8 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ai guards specific ship in wing:", AI::Profile_Flags::Ai_guards_specific_ship_in_wing);
|
||||
|
||||
set_flag(profile, "$support don't add primaries:", AI::Profile_Flags::Support_dont_add_primaries);
|
||||
|
||||
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
|
||||
if (optional_string("$ai path mode:"))
|
||||
{
|
||||
@@ -458,6 +462,8 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
set_flag(profile, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
|
||||
profile->bay_arrive_speed_mult = 1.0f;
|
||||
profile->bay_depart_speed_mult = 1.0f;
|
||||
if (optional_string("$bay arrive speed multiplier:")) {
|
||||
@@ -498,7 +504,8 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
}
|
||||
|
||||
// find next valid option
|
||||
skip_to_start_of_string_either("$", "#");
|
||||
if (!skip_to_start_of_string_either("$", "#"))
|
||||
break;
|
||||
saved_Mp = Mp;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-26
@@ -64,10 +64,11 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
void ai_big_avoid_ship();
|
||||
int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
|
||||
extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
|
||||
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
|
||||
|
||||
|
||||
// Called by ai_big_pick_attack_point.
|
||||
@@ -631,7 +632,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
else
|
||||
rvec = NULL;
|
||||
|
||||
ai_turn_towards_vector(enemy_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, 0.0f, 0, rvec);
|
||||
ai_turn_towards_vector(enemy_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, 0.0f, 0, rvec);
|
||||
|
||||
// calc range of primary weapon
|
||||
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
|
||||
@@ -641,7 +642,7 @@ 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[AI::AI_Flags::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] || aip->ai_profile_flags[AI::Profile_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;
|
||||
@@ -683,7 +684,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
ship *shipp = &Ships[Pl_objp->instance];
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_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;
|
||||
@@ -707,14 +708,14 @@ extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *sw
|
||||
extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
|
||||
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time);
|
||||
|
||||
extern void maybe_cheat_fire_synaptic(object *objp, ai_info *aip);
|
||||
extern void maybe_cheat_fire_synaptic(object *objp);
|
||||
|
||||
// Determine if Pl_objp should fire weapons at current target, based on input parameters
|
||||
//
|
||||
// dist_to_enemy => distance (in m) to attack point on current target
|
||||
// dot_to_enemy => dot product between fvec of Pl_objp and vector from Pl_objp to attack point
|
||||
//
|
||||
void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *firing_pos, vec3d *enemy_pos, vec3d *enemy_vel)
|
||||
static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
{
|
||||
ai_info *aip;
|
||||
ship_weapon *swp;
|
||||
@@ -845,8 +846,6 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
|
||||
extern int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos);
|
||||
|
||||
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
|
||||
void ai_big_chase()
|
||||
{
|
||||
@@ -859,7 +858,7 @@ void ai_big_chase()
|
||||
|
||||
Assert(aip->mode == AIM_CHASE);
|
||||
|
||||
maybe_cheat_fire_synaptic(Pl_objp, aip);
|
||||
maybe_cheat_fire_synaptic(Pl_objp);
|
||||
|
||||
ai_set_positions(Pl_objp, En_objp, aip, &player_pos, &enemy_pos);
|
||||
|
||||
@@ -882,7 +881,7 @@ void ai_big_chase()
|
||||
dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
if ( ai_big_strafe_maybe_retreat(dist_to_enemy, &enemy_pos) ) {
|
||||
if ( ai_big_strafe_maybe_retreat(&enemy_pos) ) {
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
aip->submode = AIS_STRAFE_AVOID;
|
||||
@@ -1045,7 +1044,7 @@ void ai_big_chase()
|
||||
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME) ) {
|
||||
// get away, simulate crsh recovery (don't use avoid)
|
||||
// accelerate_ship(aip, -1.0f);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
|
||||
// aip->submode = SM_AVOID;
|
||||
// aip->submode_start_time = Missiontime;
|
||||
} else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME) ) {
|
||||
@@ -1144,7 +1143,7 @@ void ai_big_chase()
|
||||
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
|
||||
// a big ship
|
||||
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy, &player_pos, &predicted_enemy_pos, &En_objp->phys_info.vel);
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
|
||||
} else {
|
||||
if (flFrametime < 1.0f)
|
||||
aip->time_enemy_in_range *= (1.0f - flFrametime);
|
||||
@@ -1153,11 +1152,6 @@ void ai_big_chase()
|
||||
}
|
||||
}
|
||||
|
||||
void ai_big_ship(object *objp)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// all three parms are output parameters
|
||||
// Enemy object is En_objp
|
||||
// pos => world pos of attack point
|
||||
@@ -1228,7 +1222,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
|
||||
|
||||
// check to see if Pl_objp has gotten too close to attacking point.. if so, break off by entering
|
||||
// AIS_STRAFE_RETREAT
|
||||
int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
{
|
||||
ai_info *aip;
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
@@ -1258,7 +1252,7 @@ int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
// use standard collision resolution
|
||||
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
|
||||
} else {
|
||||
// too close for comfort so fly to box point + 300
|
||||
aip->submode = AIS_STRAFE_RETREAT1;
|
||||
@@ -1298,12 +1292,12 @@ void ai_big_strafe_attack()
|
||||
}
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
return;
|
||||
|
||||
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);
|
||||
ai_turn_towards_vector(&target_pos, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
if ((target_dist < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
@@ -1347,7 +1341,7 @@ void ai_big_strafe_attack()
|
||||
}
|
||||
|
||||
// maybe fire weapons at target
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot);
|
||||
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
|
||||
|
||||
fix last_hit = Missiontime - aip->last_hit_time;
|
||||
@@ -1493,7 +1487,7 @@ void ai_big_strafe_glide_attack()
|
||||
vm_vec_sub2(&target_pos, &En_objp->pos);
|
||||
|
||||
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot);
|
||||
}
|
||||
|
||||
// if haven't been hit in quite a while, leave strafe mode
|
||||
@@ -1517,7 +1511,7 @@ void ai_big_strafe_avoid()
|
||||
mode_time = Missiontime - aip->submode_start_time;
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
return;
|
||||
|
||||
if ( mode_time > fl2f(0.5)) {
|
||||
@@ -1704,7 +1698,7 @@ void ai_big_strafe()
|
||||
//
|
||||
// Check if weapon_objnum was fired by Pl_objp's target, and whether Pl_objp's target is a big ship, if
|
||||
// so, enter AIM_STRAFE
|
||||
int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int consider_target_only)
|
||||
int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
|
||||
{
|
||||
ai_info *aip;
|
||||
ship_info *sip;
|
||||
@@ -1778,7 +1772,7 @@ int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int consi
|
||||
// Consider attacking a turret, if a turret actually fired the weapon
|
||||
// input: ship_objp => ship that will attack the turret
|
||||
// weapon_objp =>
|
||||
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp)
|
||||
{
|
||||
ai_info *aip;
|
||||
object *parent_objp;
|
||||
|
||||
+2
-3
@@ -17,14 +17,13 @@ struct ai_info;
|
||||
struct vec3d;
|
||||
class ship_subsys;
|
||||
|
||||
void ai_big_ship(object *objp);
|
||||
void ai_big_chase();
|
||||
void ai_big_subsys_path_cleanup(ai_info *aip);
|
||||
|
||||
// strafe functions
|
||||
void ai_big_strafe();
|
||||
int ai_big_maybe_enter_strafe_mode(object *objp, int weapon_objnum, int consider_target_only=0);
|
||||
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp);
|
||||
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
|
||||
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
|
||||
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
|
||||
|
||||
|
||||
+95
-186
@@ -68,7 +68,7 @@
|
||||
#include "weapon/swarm.h"
|
||||
#include "weapon/weapon.h"
|
||||
#include <map>
|
||||
#include <limits.h>
|
||||
#include <climits>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -745,6 +745,8 @@ void parse_ai_class()
|
||||
|
||||
set_aic_flag(aicp, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
|
||||
|
||||
set_aic_flag(aicp, "$free afterburner use:", AI::Profile_Flags::Free_afterburner_use);
|
||||
|
||||
set_aic_flag(aicp, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
|
||||
|
||||
set_aic_flag(aicp, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
|
||||
@@ -764,6 +766,8 @@ void parse_ai_class()
|
||||
set_aic_flag(aicp, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields);
|
||||
|
||||
set_aic_flag(aicp, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
set_aic_flag(aicp, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
}
|
||||
|
||||
void reset_ai_class_names()
|
||||
@@ -1132,7 +1136,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
|
||||
|
||||
// If rvec != NULL, use it to match bank by calling vm_matrix_interpolate.
|
||||
// (rvec defaults to NULL)
|
||||
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, int sexp_flags)
|
||||
void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
|
||||
{
|
||||
matrix curr_orient;
|
||||
vec3d vel_in, vel_out, desired_fvec, src;
|
||||
@@ -1500,12 +1504,12 @@ void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank
|
||||
if (aip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing]) {
|
||||
if (&Objects[aip->goal_objnum] != objp) {
|
||||
float rotvel_z = objp->phys_info.rotvel.xyz.z;
|
||||
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
|
||||
objp->phys_info.rotvel.xyz.z = rotvel_z;
|
||||
}
|
||||
} else {
|
||||
// normal turn
|
||||
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1520,7 +1524,7 @@ void turn_away_from_point(object *objp, vec3d *point, float bank_override)
|
||||
vm_vec_sub(&opposite_point, &objp->pos, point);
|
||||
vm_vec_add2(&opposite_point, &objp->pos);
|
||||
|
||||
ai_turn_towards_vector(&opposite_point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, bank_override, AITTV_FAST);
|
||||
ai_turn_towards_vector(&opposite_point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, bank_override, AITTV_FAST);
|
||||
}
|
||||
|
||||
|
||||
@@ -1789,7 +1793,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
|
||||
wingnum = aip->wing;
|
||||
|
||||
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (shipp->current_max_speed < 5.0f) || (objp->phys_info.afterburner_max_vel.xyz.z <= shipp->current_max_speed) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (shipp->current_max_speed < 5.0f) || (objp->phys_info.afterburner_max_vel.xyz.z <= shipp->current_max_speed) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
lowest_max_av_ab_speed = shipp->current_max_speed;
|
||||
}
|
||||
else
|
||||
@@ -1814,7 +1818,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
|
||||
if ((oaip->mode == AIM_WAYPOINTS) && (oaip->wing == wingnum) && (oaip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing])) {
|
||||
|
||||
float cur_max;
|
||||
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= oshipp->current_max_speed) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= oshipp->current_max_speed) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use] || oaip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
cur_max = oshipp->current_max_speed;
|
||||
}
|
||||
else
|
||||
@@ -3448,35 +3452,6 @@ float compute_time_to_enemy(float dist_to_enemy, object *pobjp)
|
||||
return time_to_enemy + flFrametime;
|
||||
}
|
||||
|
||||
// Stuff *dot and *tts.
|
||||
// *dot is always computed. If dot is less than zero, the magnitude is
|
||||
// incorrect, not having been divided by distance.
|
||||
// If *dot is > 0.0f, then tts is computed. This is the time it will take object
|
||||
// *objp to get to *pos, assuming it moves right at it.
|
||||
void fds_aux(float *dot, float *tts, vec3d *pos, float dtime, object *objp)
|
||||
{
|
||||
vec3d v2s;
|
||||
|
||||
vm_vec_sub(&v2s, pos, &objp->pos);
|
||||
*dot = vm_vec_dot(&v2s, &objp->orient.vec.fvec);
|
||||
|
||||
if (*dot > 0.0f) {
|
||||
float dist;
|
||||
|
||||
dist = vm_vec_dist(&objp->pos, pos);
|
||||
|
||||
if (dist > 0.1f)
|
||||
*dot /= dist;
|
||||
else
|
||||
*dot = 1.0f;
|
||||
|
||||
if (objp->phys_info.speed > 0.1f)
|
||||
*tts = dist / objp->phys_info.speed;
|
||||
else
|
||||
*tts = dist * 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ai_set_positions(object *pl_objp, object *en_objp, ai_info *aip, vec3d *player_pos, vec3d *enemy_pos)
|
||||
{
|
||||
@@ -3814,7 +3789,7 @@ float ai_path_0()
|
||||
int path_num;
|
||||
Assert(aip->active_goal >= 0);
|
||||
ai_goal *aigp = &aip->goals[aip->active_goal];
|
||||
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
|
||||
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
|
||||
|
||||
path_num = ai_return_path_num_from_dockbay(&Objects[aip->goal_objnum], aigp->dockee.index);
|
||||
ai_find_path(Pl_objp, aip->goal_objnum, path_num, 0);
|
||||
@@ -3892,7 +3867,7 @@ float ai_path_0()
|
||||
}
|
||||
|
||||
if (dist_to_goal > 0.1f)
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, slop_vec, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, slop_vec, nullptr, 0.0f, 0);
|
||||
|
||||
// Code to control speed is MUCH less forgiving in path following than in waypoint
|
||||
// following. Must be very close to path or might hit objects.
|
||||
@@ -3957,7 +3932,7 @@ float ai_path_1()
|
||||
int path_num;
|
||||
Assert(aip->active_goal >= 0);
|
||||
ai_goal *aigp = &aip->goals[aip->active_goal];
|
||||
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
|
||||
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
|
||||
|
||||
path_num = ai_return_path_num_from_dockbay(&Objects[aip->goal_objnum], aigp->dockee.index);
|
||||
ai_find_path(Pl_objp, aip->goal_objnum, path_num, 0);
|
||||
@@ -4034,10 +4009,10 @@ float ai_path_1()
|
||||
if (r <= 1.0f) {
|
||||
vec3d midpoint;
|
||||
vm_vec_avg3(&midpoint, &gcvp, &closest_point, &closest_point);
|
||||
ai_turn_towards_vector(&midpoint, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
|
||||
ai_turn_towards_vector(&midpoint, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
|
||||
}
|
||||
else {
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4382,11 +4357,11 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
|
||||
} else {
|
||||
vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
|
||||
ai_turn_towards_vector(&perp, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&perp, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
|
||||
}
|
||||
} else {
|
||||
if (dist_to_goal > 0.1f) {
|
||||
ai_turn_towards_vector(target_pos, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(target_pos, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4440,7 +4415,7 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
ab_allowed = false;
|
||||
}
|
||||
|
||||
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
ab_allowed = false;
|
||||
}
|
||||
|
||||
@@ -5051,7 +5026,7 @@ void slide_face_ship()
|
||||
|
||||
dist = vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
|
||||
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
dot_from_enemy = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
|
||||
|
||||
@@ -5234,7 +5209,7 @@ vec3d G_predicted_pos, G_fire_pos;
|
||||
// Else
|
||||
// Select Any ol' weapon.
|
||||
// Returns primary_bank index.
|
||||
int ai_select_primary_weapon_OLD(object *objp, object *other_objp, Weapon::Info_Flags flags)
|
||||
static int ai_select_primary_weapon_OLD(const object *objp, Weapon::Info_Flags flags)
|
||||
{
|
||||
ship *shipp = &Ships[objp->instance];
|
||||
ship_weapon *swp = &shipp->weapons;
|
||||
@@ -5325,7 +5300,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
//not using the new AI, use the old version of this function instead.
|
||||
if (!(Ai_info[shipp->ai_index].ai_profile_flags[AI::Profile_Flags::Smart_primary_weapon_selection]))
|
||||
{
|
||||
return ai_select_primary_weapon_OLD(objp, other_objp, flags);
|
||||
return ai_select_primary_weapon_OLD(objp, flags);
|
||||
}
|
||||
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
|
||||
@@ -6051,8 +6026,7 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip)
|
||||
// --------------------------------------------------------------------------
|
||||
// Fire a secondary weapon.
|
||||
// Maybe choose to fire a different one.
|
||||
// priority1 and priority2 are optional parameters with defaults = -1
|
||||
int ai_fire_secondary_weapon(object *objp, int priority1, int priority2)
|
||||
int ai_fire_secondary_weapon(object *objp)
|
||||
{
|
||||
ship_weapon *swp;
|
||||
ship *shipp;
|
||||
@@ -6072,7 +6046,7 @@ int ai_fire_secondary_weapon(object *objp, int priority1, int priority2)
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
|
||||
|
||||
// Select secondary weapon.
|
||||
current_bank = swp->current_secondary_bank; //ai_select_secondary_weapon(objp, swp, priority1, priority2);
|
||||
current_bank = swp->current_secondary_bank;
|
||||
|
||||
if (current_bank == -1) {
|
||||
return rval;
|
||||
@@ -6539,14 +6513,14 @@ void ai_chase_ct()
|
||||
vm_vec_add2(&tvec, &Pl_objp->orient.vec.rvec);
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* ATTACK submode handler for chase mode.
|
||||
*/
|
||||
void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float dist_to_enemy)
|
||||
static void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos)
|
||||
{
|
||||
vec3d _pep;
|
||||
float dot_to_enemy, dot_from_enemy;
|
||||
@@ -6558,7 +6532,7 @@ void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float
|
||||
if ((dot_to_enemy > dot_from_enemy + 0.1f) || (dot_to_enemy > 0.9f))
|
||||
vm_vec_scale_add(&_pep, &Pl_objp->pos, &En_objp->orient.vec.fvec, 100.0f);
|
||||
|
||||
ai_turn_towards_vector(&_pep, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&_pep, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
accelerate_ship(aip, 0.0f);
|
||||
}
|
||||
@@ -6755,7 +6729,7 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
|
||||
|
||||
// Pl_objp (aip) tries to get behind En_objp.
|
||||
// New on 2/21/98: If this ship can move backwards and slide, maybe do that to get behind.
|
||||
void get_behind_ship(ai_info *aip, ship_info *sip, float dist_to_enemy)
|
||||
static void get_behind_ship(ai_info *aip, ship_info *sip)
|
||||
{
|
||||
vec3d new_pos;
|
||||
float dot;
|
||||
@@ -6764,7 +6738,7 @@ void get_behind_ship(ai_info *aip, ship_info *sip, float dist_to_enemy)
|
||||
vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
|
||||
|
||||
vm_vec_scale_add(&new_pos, &En_objp->pos, &En_objp->orient.vec.fvec, -100.0f); // Pick point 100 units behind.
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
dot = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
|
||||
|
||||
@@ -6783,7 +6757,7 @@ int avoid_player(object *objp, vec3d *goal_pos)
|
||||
if (aip->ai_flags[AI::AI_Flags::Avoiding_small_ship]) {
|
||||
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
|
||||
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 0.5f);
|
||||
return 1;
|
||||
}
|
||||
@@ -6981,7 +6955,7 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
|
||||
|
||||
vec3d v2g;
|
||||
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
vm_vec_normalized_dir(&v2g, &aip->avoid_goal_point, &Pl_objp->pos);
|
||||
float dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
float d2 = (1.0f + dot) * (1.0f + dot);
|
||||
@@ -7073,7 +7047,7 @@ void ai_stealth_find()
|
||||
}
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7083,9 +7057,9 @@ void ai_stealth_find()
|
||||
if (dist_to_enemy > 500.0f) {
|
||||
vec3d rvec;
|
||||
compute_desired_rvec(&rvec, &new_pos, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, &rvec);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
|
||||
} else {
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
}
|
||||
|
||||
dot_from_enemy = -vm_vec_dot(&vec_to_enemy, &En_objp->orient.vec.fvec);
|
||||
@@ -7213,7 +7187,7 @@ void ai_stealth_sweep()
|
||||
return;
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
float dot = 1.0f;
|
||||
if (dist_to_goal < 100) {
|
||||
@@ -7273,9 +7247,9 @@ void ai_chase_attack(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, f
|
||||
if (dist_to_enemy > 500.0f) {
|
||||
vec3d rvec;
|
||||
compute_desired_rvec(&rvec, predicted_enemy_pos, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0, &rvec);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0, &rvec);
|
||||
} else {
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0);
|
||||
}
|
||||
|
||||
attack_set_accel(aip, sip, dist_to_enemy, dot_to_enemy, dot_from_enemy);
|
||||
@@ -7313,7 +7287,7 @@ void ai_chase_es(ai_info *aip, ship_info *sip)
|
||||
|
||||
float bank_override = Pl_objp->phys_info.speed;
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
@@ -7339,7 +7313,7 @@ void ai_chase_ga(ai_info *aip, ship_info *sip)
|
||||
|
||||
bank_override = Pl_objp->phys_info.speed;
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
|
||||
|
||||
accelerate_ship(aip, 2.0f);
|
||||
|
||||
@@ -7504,32 +7478,6 @@ void ai_set_guard_wing(object *objp, int wingnum)
|
||||
}
|
||||
}
|
||||
|
||||
// Make object *objp guard object *other_objp.
|
||||
// To be called from the goals code.
|
||||
void ai_set_evade_object(object *objp, object *other_objp)
|
||||
{
|
||||
ship *shipp;
|
||||
ai_info *aip;
|
||||
int other_objnum;
|
||||
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
Assert(objp->instance >= 0);
|
||||
|
||||
shipp = &Ships[objp->instance];
|
||||
|
||||
Assert(shipp->ai_index >= 0);
|
||||
|
||||
aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
other_objnum = OBJ_INDEX(other_objp);
|
||||
Assert(other_objnum >= 0);
|
||||
|
||||
Assert(other_objnum != Ships[aip->shipnum].objnum); // make sure not targeting self
|
||||
aip->target_objnum = other_objnum;
|
||||
|
||||
aip->mode = AIM_EVADE;
|
||||
}
|
||||
|
||||
// Make objp guard other_objp
|
||||
// If other_objp is a member of a wing, objp will guard that whole wing
|
||||
// UNLESS objp is also a member of the wing!
|
||||
@@ -8001,7 +7949,7 @@ void ai_cruiser_chase()
|
||||
|
||||
// kamikaze - ram and explode
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
@@ -8041,7 +7989,7 @@ void ai_cruiser_chase()
|
||||
}
|
||||
|
||||
// now move as desired
|
||||
ai_turn_towards_vector(&goal_pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0, rvecp);
|
||||
ai_turn_towards_vector(&goal_pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0, rvecp);
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
// maybe switch to new mode
|
||||
@@ -8322,7 +8270,7 @@ void ai_chase()
|
||||
break;
|
||||
|
||||
case SM_EVADE_BRAKE:
|
||||
ai_chase_eb(aip, sip, &predicted_enemy_pos, dist_to_enemy);
|
||||
ai_chase_eb(aip, sip, &predicted_enemy_pos);
|
||||
break;
|
||||
|
||||
case SM_EVADE:
|
||||
@@ -8334,7 +8282,7 @@ void ai_chase()
|
||||
break;
|
||||
|
||||
case SM_GET_BEHIND:
|
||||
get_behind_ship(aip, sip, dist_to_enemy);
|
||||
get_behind_ship(aip, sip);
|
||||
break;
|
||||
|
||||
case SM_GET_AWAY: // Used to get away from opponent to prevent endless circling.
|
||||
@@ -8768,7 +8716,11 @@ void ai_chase()
|
||||
scale = (scale - 0.6f) * 1.5f;
|
||||
else
|
||||
scale = 0.0f;
|
||||
if (dist_to_enemy < pwip->max_speed * (1.0f + scale)) {
|
||||
float range = pwip->max_speed * (1.0f + scale);
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Use_actual_primary_range]) {
|
||||
range = std::min( {range, pwip->max_speed * pwip->lifetime, pwip->weapon_range} );
|
||||
}
|
||||
if (dist_to_enemy < range) {
|
||||
if(ai_fire_primary_weapon(Pl_objp) == 1){
|
||||
has_fired = 1;
|
||||
}else{
|
||||
@@ -9329,7 +9281,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
|
||||
{
|
||||
float dot, accel;
|
||||
float turn_time = Ship_info[Ships[docker_objp->instance].ship_info_index].srotation_time;
|
||||
ai_turn_towards_vector(&goal_point, docker_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_point, docker_objp, turn_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
dot = vm_vec_dot(&docker_objp->orient.vec.fvec, &away_vec);
|
||||
accel = 0.1f;
|
||||
@@ -9964,10 +9916,10 @@ void ai_big_guard()
|
||||
}
|
||||
|
||||
// got the point, now let's go there
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
|
||||
vec3d v2g;
|
||||
float dot_to_goal_point;
|
||||
|
||||
@@ -10088,9 +10040,9 @@ void ai_guard()
|
||||
|
||||
// quite far away, so try to go straight to
|
||||
compute_desired_rvec(&rvec, &goal_point, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&goal_point, Pl_objp, flFrametime, Ship_info[shipp->ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, &rvec);
|
||||
ai_turn_towards_vector(&goal_point, Pl_objp, Ship_info[shipp->ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
aip->afterburner_stop_time = Missiontime + 3*F1_0;
|
||||
@@ -10395,11 +10347,12 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
|
||||
case AIS_DOCK_2:
|
||||
case AIS_DOCK_3:
|
||||
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
|
||||
FALLTHROUGH;
|
||||
case AIS_DOCK_0:
|
||||
{
|
||||
// get them from the active goal
|
||||
Assert(aigp != NULL);
|
||||
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
|
||||
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
|
||||
docker_index = aigp->docker.index;
|
||||
dockee_index = aigp->dockee.index;
|
||||
Assert(docker_index >= 0);
|
||||
@@ -10412,6 +10365,7 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
|
||||
case AIS_UNDOCK_1:
|
||||
case AIS_UNDOCK_2:
|
||||
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
|
||||
FALLTHROUGH;
|
||||
case AIS_UNDOCK_0:
|
||||
{
|
||||
// get them from the guy I'm docked to
|
||||
@@ -10478,9 +10432,11 @@ void ai_cleanup_dock_mode_subjective(object *objp)
|
||||
case AIS_UNDOCK_0:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_UNDOCK_1:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_UNDOCK_2:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
|
||||
@@ -10490,9 +10446,11 @@ void ai_cleanup_dock_mode_subjective(object *objp)
|
||||
case AIS_DOCK_4A:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_DOCK_3:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
|
||||
FALLTHROUGH;
|
||||
case AIS_DOCK_2:
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
|
||||
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
|
||||
@@ -10707,8 +10665,8 @@ void ai_dock()
|
||||
char *goal_ship_class_name = goal_sip->name;
|
||||
char *goal_dock_path_name = model_get(goal_sip->model_num)->paths[aip->mp_index].name;
|
||||
|
||||
Warning(LOCATION, "Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
|
||||
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name);
|
||||
mprintf(("Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
|
||||
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name));
|
||||
}
|
||||
|
||||
aip->submode = AIS_DOCK_1;
|
||||
@@ -10833,7 +10791,7 @@ void ai_dock()
|
||||
|
||||
if (aip->submode == AIS_DOCK_3) {
|
||||
// Play a ship docking attach sound
|
||||
snd_play_3d( &Snds[SND_DOCK_ATTACH], &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_ATTACH), &Pl_objp->pos, &View_position );
|
||||
|
||||
// start the dock animation
|
||||
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, 1);
|
||||
@@ -10960,7 +10918,7 @@ void ai_dock()
|
||||
ai_find_path(Pl_objp, OBJ_INDEX(goal_objp), path_num, 0);
|
||||
|
||||
// Play a ship docking detach sound
|
||||
snd_play_3d( &Snds[SND_DOCK_DETACH], &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_DETACH), &Pl_objp->pos, &View_position );
|
||||
|
||||
aip->submode = AIS_UNDOCK_1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -10980,7 +10938,7 @@ void ai_dock()
|
||||
// play the depart sound, but only once, since this mode is called multiple times per frame
|
||||
if ( !(aigp->flags[AI::Goal_Flags::Depart_sound_played]))
|
||||
{
|
||||
snd_play_3d( &Snds[SND_DOCK_DEPART], &Pl_objp->pos, &View_position );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_DEPART), &Pl_objp->pos, &View_position );
|
||||
aigp->flags.set(AI::Goal_Flags::Depart_sound_played);
|
||||
}
|
||||
|
||||
@@ -11379,7 +11337,7 @@ float gwlr_1(object *objp, ai_info *aip)
|
||||
/**
|
||||
* Compute the largest radius of a ship forming on *objp's wing.
|
||||
*/
|
||||
float gwlr_object_1(object *objp, ai_info *aip)
|
||||
static float gwlr_object_1(object *objp)
|
||||
{
|
||||
float max_radius;
|
||||
object *o;
|
||||
@@ -11412,7 +11370,7 @@ float get_wing_largest_radius(object *objp, int formation_object_flag)
|
||||
aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
if (formation_object_flag) {
|
||||
return gwlr_object_1(objp, aip);
|
||||
return gwlr_object_1(objp);
|
||||
} else {
|
||||
return gwlr_1(objp, aip);
|
||||
}
|
||||
@@ -11554,53 +11512,6 @@ void render_wing_phantoms_all()
|
||||
|
||||
#endif
|
||||
|
||||
// Hook from goals code to AI.
|
||||
// Force a wing to fly in formation.
|
||||
// Sets AIF_FORMATION bit in ai_flags.
|
||||
// wingnum Wing to force to fly in formation
|
||||
void ai_fly_in_formation(int wingnum)
|
||||
{
|
||||
object *objp;
|
||||
ship *shipp;
|
||||
ship_obj *so;
|
||||
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
||||
objp = &Objects[so->objnum];
|
||||
Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
|
||||
|
||||
shipp = &Ships[objp->instance];
|
||||
Assert((shipp->ai_index >= 0) && (shipp->ai_index < MAX_AI_INFO));
|
||||
|
||||
if (Ai_info[shipp->ai_index].wing == wingnum) {
|
||||
Ai_info[shipp->ai_index].ai_flags.set(AI::AI_Flags::Formation_wing);
|
||||
Ai_info[shipp->ai_index].ai_flags.remove(AI::AI_Flags::Formation_object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hook from goals code to AI.
|
||||
// Force a wing to abandon formation flying.
|
||||
// Clears AIF_FORMATION bit in ai_flags.
|
||||
// wingnum Wing to force to fly in formation
|
||||
void ai_disband_formation(int wingnum)
|
||||
{
|
||||
object *objp;
|
||||
ship *shipp;
|
||||
ship_obj *so;
|
||||
|
||||
for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
|
||||
objp = &Objects[so->objnum];
|
||||
Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
|
||||
|
||||
shipp = &Ships[objp->instance];
|
||||
Assert((shipp->ai_index >= 0) && (shipp->ai_index < MAX_AI_INFO));
|
||||
|
||||
if (Ai_info[shipp->ai_index].wing == wingnum) {
|
||||
Ai_info[shipp->ai_index].ai_flags.remove(AI::AI_Flags::Formation_wing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Leader_chaos = 0.0f;
|
||||
int Chaos_frame = -1;
|
||||
|
||||
@@ -11802,7 +11713,7 @@ int ai_formation()
|
||||
|
||||
ship_info *sip = &Ship_info[shipp->ship_info_index];
|
||||
bool ab_allowed = false;
|
||||
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
|
||||
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
|
||||
ab_allowed = true;
|
||||
} else {
|
||||
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
|
||||
@@ -12185,7 +12096,7 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ai_preprocess_ignore_objnum(object *objp, ai_info *aip)
|
||||
static void ai_preprocess_ignore_objnum(ai_info *aip)
|
||||
{
|
||||
if (aip->ai_flags[AI::AI_Flags::Temporary_ignore])
|
||||
{
|
||||
@@ -12376,6 +12287,7 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
|
||||
case AIM_DOCK: // Ships in dock mode can evade iif they are not currently repairing or docked.
|
||||
if (object_is_docked(objp) || (aip->ai_flags[AI::AI_Flags::Repairing, AI::AI_Flags::Being_repaired]))
|
||||
break;
|
||||
FALLTHROUGH;
|
||||
case AIM_GUARD:
|
||||
// If in guard mode and far away from guard object, don't pursue guy that hit me.
|
||||
if ((aip->guard_objnum != -1) && (aip->guard_signature == Objects[aip->guard_objnum].signature)) {
|
||||
@@ -12383,6 +12295,7 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
|
||||
return;
|
||||
}
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case AIM_EVADE:
|
||||
case AIM_GET_BEHIND:
|
||||
case AIM_STAY_NEAR:
|
||||
@@ -13016,7 +12929,7 @@ void ai_execute_behavior(ai_info *aip)
|
||||
ship *shipp = &Ships[aip->shipnum];
|
||||
ship_info *sip = &Ship_info[shipp->ship_info_index];
|
||||
|
||||
if (strnicmp(shipp->ship_name, INSTRUCTOR_SHIP_NAME, strlen(INSTRUCTOR_SHIP_NAME))) {
|
||||
if (strnicmp(shipp->ship_name, INSTRUCTOR_SHIP_NAME, strlen(INSTRUCTOR_SHIP_NAME)) != 0) {
|
||||
if (sip->is_big_or_huge()) {
|
||||
aip->mode = AIM_NONE;
|
||||
} else {
|
||||
@@ -13056,7 +12969,6 @@ void ai_execute_behavior(ai_info *aip)
|
||||
case AIM_NONE:
|
||||
break;
|
||||
case AIM_BIGSHIP:
|
||||
ai_big_ship(Pl_objp);
|
||||
break;
|
||||
case AIM_PATH: {
|
||||
int path_num;
|
||||
@@ -13374,7 +13286,7 @@ void ai_warp_out(object *objp)
|
||||
case AIS_WARP_2: // Make sure won't collide with any object.
|
||||
if (timestamp_elapsed(aip->force_warp_time)
|
||||
|| (!collide_predict_large_ship(objp, objp->radius*2.0f + 100.0f)
|
||||
|| (Ship_info[shipp->ship_info_index].warpout_type == WT_HYPERSPACE
|
||||
|| (Warp_params[shipp->warpout_params_index].warp_type == WT_HYPERSPACE
|
||||
&& !collide_predict_large_ship(objp, 100000.0f)))) {
|
||||
aip->submode = AIS_WARP_3;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -13417,7 +13329,7 @@ void ai_warp_out(object *objp)
|
||||
break;
|
||||
case AIS_WARP_4: {
|
||||
// Only lets the ship warp after waiting for the warpout engage time
|
||||
if ( (Missiontime / 100) >= (aip->submode_start_time / 100 + Ship_info[shipp->ship_info_index].warpout_engage_time) ) {
|
||||
if ( (Missiontime / 100) >= (aip->submode_start_time / 100 + Warp_params[shipp->warpout_params_index].warpout_engage_time) ) {
|
||||
shipfx_warpout_start(objp);
|
||||
aip->submode = AIS_WARP_5;
|
||||
aip->submode_start_time = Missiontime;
|
||||
@@ -13433,7 +13345,7 @@ void ai_warp_out(object *objp)
|
||||
|
||||
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
|
||||
// Return nearest one.
|
||||
int ai_find_shockwave_weapon(object *objp, ai_info *aip)
|
||||
static int ai_find_shockwave_weapon(const object *objp)
|
||||
{
|
||||
missile_obj *mo;
|
||||
float nearest_dist = 999999.9f;
|
||||
@@ -13499,7 +13411,7 @@ void ai_announce_ship_dying(object *dying_objp)
|
||||
|
||||
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
|
||||
// Return nearest one.
|
||||
int ai_find_shockwave_ship(object *objp, ai_info *aip)
|
||||
static int ai_find_shockwave_ship(object *objp)
|
||||
{
|
||||
ship_obj *so;
|
||||
float nearest_dist = 999999.9f;
|
||||
@@ -13542,7 +13454,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
// If we don't currently know of a weapon to avoid, try to find one.
|
||||
// If we can't find one, then clear the bit so we don't keep coming here.
|
||||
if (aip->shockwave_object == -1) {
|
||||
int shockwave_weapon = ai_find_shockwave_weapon(objp, aip);
|
||||
int shockwave_weapon = ai_find_shockwave_weapon(objp);
|
||||
if (shockwave_weapon == -1) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
|
||||
return 0;
|
||||
@@ -13631,7 +13543,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
}
|
||||
} else if (aip->ai_flags[AI::AI_Flags::Avoid_shockwave_ship]) {
|
||||
if (aip->shockwave_object == -1) {
|
||||
int shockwave_ship = ai_find_shockwave_ship(objp, aip);
|
||||
int shockwave_ship = ai_find_shockwave_ship(objp);
|
||||
if (shockwave_ship == -1) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
|
||||
return 0;
|
||||
@@ -13861,7 +13773,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
|
||||
vec3d v2g;
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_1]) {
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
|
||||
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_1, &objp->pos);
|
||||
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
accelerate_ship(aip, dot);
|
||||
@@ -13875,7 +13787,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
|
||||
return 1;
|
||||
|
||||
} else if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_2]) {
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
|
||||
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_2, &objp->pos);
|
||||
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
accelerate_ship(aip, dot);
|
||||
@@ -13995,7 +13907,7 @@ void ai_frame(int objnum)
|
||||
if (maybe_big_ship_collide_recover_frame(Pl_objp, aip))
|
||||
return;
|
||||
|
||||
ai_preprocess_ignore_objnum(Pl_objp, aip);
|
||||
ai_preprocess_ignore_objnum(aip);
|
||||
target_objnum = set_target_objnum(aip, aip->target_objnum);
|
||||
|
||||
Assert(objnum != target_objnum);
|
||||
@@ -14150,7 +14062,7 @@ void ai_frame(int objnum)
|
||||
}
|
||||
}
|
||||
|
||||
void ai_control_info_check( object *obj, ai_info *aip )
|
||||
static void ai_control_info_check(ai_info *aip)
|
||||
{
|
||||
if(aip->ai_override_flags.none_set())
|
||||
return;
|
||||
@@ -14251,7 +14163,7 @@ void ai_process( object * obj, int ai_index, float frametime )
|
||||
|
||||
if (rfc == 1) {
|
||||
// Wanderer - sexp based override goes here - only if rfc is valid though
|
||||
ai_control_info_check(obj, aip);
|
||||
ai_control_info_check(aip);
|
||||
vec3d copy_desired_rotvel = obj->phys_info.rotvel;
|
||||
physics_read_flying_controls( &obj->orient, &obj->phys_info, &AI_ci, frametime);
|
||||
// if obj is in formation and not flight leader, don't update rotvel
|
||||
@@ -14786,10 +14698,10 @@ int firing_aspect_seeking_bomb(object *objp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *objp collided with big ship *big_objp at global point *collide_pos
|
||||
// Make it fly away from the collision point.
|
||||
// *objp collided with big ship *big_objp at some global point.
|
||||
// Make it fly away from the collision point.
|
||||
// collision_normal is NULL, when a collision is imminent and we just want to bug out.
|
||||
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal)
|
||||
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
@@ -14878,9 +14790,9 @@ void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
|
||||
|
||||
|
||||
/**
|
||||
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp at point *hitpos.
|
||||
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp
|
||||
*/
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal)
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
{
|
||||
int hitter_objnum = -2;
|
||||
object *objp_hitter = NULL;
|
||||
@@ -14922,7 +14834,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_
|
||||
// And the current object is _not_ a big ship
|
||||
if (!Ship_info[Ships[objp_ship->instance].ship_info_index].is_big_or_huge()) {
|
||||
// Recover from hitting a big ship. Note, if two big ships collide, they just pound away at each other. Oh well. Recovery looks dumb and it's very late.
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hitpos, hit_normal);
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hit_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15059,7 +14971,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_
|
||||
return;
|
||||
|
||||
if ( (hit_objp->type == OBJ_WEAPON) && !(aip->ai_flags[AI::AI_Flags::No_dynamic]) ) {
|
||||
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp), 1) )
|
||||
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp)) )
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -15179,10 +15091,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_
|
||||
|
||||
// Ship shipnum has been destroyed.
|
||||
// Cleanup.
|
||||
// the parameter 'method' is used to tell is this ship was destroyed or it departed normally.
|
||||
// This function will get called in either case, and there are things that should be done if
|
||||
// the ship actually gets destroyed which shouldn't get done if it departed.
|
||||
void ai_ship_destroy(int shipnum, Ship::Exit_Flags method)
|
||||
void ai_ship_destroy(int shipnum)
|
||||
{
|
||||
int objnum;
|
||||
object *other_objp;
|
||||
@@ -15433,7 +15342,7 @@ int ai_issue_rearm_request(object *requester_objp)
|
||||
// we aren't able to do anything!
|
||||
else {
|
||||
Assert(result == 4);
|
||||
Assertion(false, "This case should have already been caught by the is_support_allowed precheck!");
|
||||
UNREACHABLE("This case should have already been caught by the is_support_allowed precheck!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -15502,7 +15411,7 @@ int ai_return_path_num_from_dockbay(object *dockee_objp, int dockbay_index)
|
||||
/**
|
||||
* Actually go ahead and fire the synaptics.
|
||||
*/
|
||||
void cheat_fire_synaptic(object *objp, ship *shipp, ai_info *aip)
|
||||
static void cheat_fire_synaptic(object *objp, ship *shipp)
|
||||
{
|
||||
ship_weapon *swp;
|
||||
swp = &shipp->weapons;
|
||||
@@ -15524,7 +15433,7 @@ void cheat_fire_synaptic(object *objp, ship *shipp, ai_info *aip)
|
||||
// if they're near one or more enemies
|
||||
// every so often
|
||||
// fire a synaptic if they have one.
|
||||
void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
|
||||
void maybe_cheat_fire_synaptic(object *objp)
|
||||
{
|
||||
// Only do in subspace missions.
|
||||
if (!(The_mission.flags[Mission::Mission_Flags::Subspace]))
|
||||
@@ -15556,7 +15465,7 @@ void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
|
||||
int count = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &objp->pos, 1500.0f);
|
||||
|
||||
if (count > 0)
|
||||
cheat_fire_synaptic(objp, shipp, aip);
|
||||
cheat_fire_synaptic(objp, shipp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+53
-52
@@ -62,31 +62,32 @@ 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 },
|
||||
{ "Dock", AI_GOAL_DOCK, 0 },
|
||||
{ "Waypoints", AI_GOAL_WAYPOINTS, 0 },
|
||||
{ "Waypoints once", AI_GOAL_WAYPOINTS_ONCE, 0 },
|
||||
{ "Depart", AI_GOAL_WARP, 0 },
|
||||
{ "Attack subsys", AI_GOAL_DESTROY_SUBSYSTEM, 0 },
|
||||
{ "Form on wing", AI_GOAL_FORM_ON_WING, 0 },
|
||||
{ "Undock", AI_GOAL_UNDOCK, 0 },
|
||||
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
|
||||
{ "Guard ship", AI_GOAL_GUARD, 0 },
|
||||
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
|
||||
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
|
||||
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
|
||||
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
|
||||
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
|
||||
{ "Guard wing", AI_GOAL_GUARD_WING, 0 },
|
||||
{ "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
|
||||
{ "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
|
||||
{ "keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
|
||||
{ "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
|
||||
{ "Stay still", AI_GOAL_STAY_STILL, 0 },
|
||||
{ "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 },
|
||||
{ "Attack ship", AI_GOAL_CHASE, 0 },
|
||||
{ "Dock", AI_GOAL_DOCK, 0 },
|
||||
{ "Waypoints", AI_GOAL_WAYPOINTS, 0 },
|
||||
{ "Waypoints once", AI_GOAL_WAYPOINTS_ONCE, 0 },
|
||||
{ "Depart", AI_GOAL_WARP, 0 },
|
||||
{ "Attack subsys", AI_GOAL_DESTROY_SUBSYSTEM, 0 },
|
||||
{ "Form on wing", AI_GOAL_FORM_ON_WING, 0 },
|
||||
{ "Undock", AI_GOAL_UNDOCK, 0 },
|
||||
{ "Attack wing", AI_GOAL_CHASE_WING, 0 },
|
||||
{ "Guard ship", AI_GOAL_GUARD, 0 },
|
||||
{ "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
|
||||
{ "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
|
||||
{ "Attack any", AI_GOAL_CHASE_ANY, 0 },
|
||||
{ "Ignore ship", AI_GOAL_IGNORE, 0 },
|
||||
{ "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
|
||||
{ "Guard wing", AI_GOAL_GUARD_WING, 0 },
|
||||
{ "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
|
||||
{ "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
|
||||
{ "keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
|
||||
{ "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
|
||||
{ "Stay still", AI_GOAL_STAY_STILL, 0 },
|
||||
{ "Play dead", AI_GOAL_PLAY_DEAD, 0 },
|
||||
{ "Play dead (persistent)", AI_GOAL_PLAY_DEAD_PERSISTENT, 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);
|
||||
@@ -125,7 +126,7 @@ const char *Ai_goal_text(int goal)
|
||||
case AI_GOAL_REARM_REPAIR:
|
||||
return XSTR( "rearm ", 484);
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
return XSTR( "rendezvous with ", -1);
|
||||
return XSTR( "rendezvous with ", 1597);
|
||||
}
|
||||
|
||||
// Avoid compiler warning
|
||||
@@ -414,7 +415,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
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) )
|
||||
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) != 0 )
|
||||
continue;
|
||||
}
|
||||
// standard goals operating on either wings or ships
|
||||
@@ -426,7 +427,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
|
||||
// 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 ) )
|
||||
if ( stricmp(purge_goal->target_name, name ) != 0 )
|
||||
continue;
|
||||
} else if ( purge_wing != wingnum )
|
||||
continue;
|
||||
@@ -937,6 +938,11 @@ void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
|
||||
aigp->ai_mode = AI_GOAL_PLAY_DEAD;
|
||||
break;
|
||||
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
aigp->ai_mode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
break;
|
||||
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
aigp->priority = atoi( CTEXT(CDR(node)) );
|
||||
aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
@@ -1126,6 +1132,10 @@ int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp )
|
||||
goalmode = AI_GOAL_PLAY_DEAD;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_PLAY_DEAD_PERSISTENT:
|
||||
goalmode = AI_GOAL_PLAY_DEAD_PERSISTENT;
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
break;
|
||||
case OP_AI_KEEP_SAFE_DISTANCE:
|
||||
priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
|
||||
goalmode = AI_GOAL_KEEP_SAFE_DISTANCE;
|
||||
@@ -1263,7 +1273,7 @@ void ai_add_wing_goal_sexp(int sexp, int type, int wingnum)
|
||||
// this name can be a shipname or a wingname)
|
||||
// docker_point and dockee_point are used for the AI_GOAL_DOCK command to tell two ships where to dock
|
||||
// immediate means to process this order right away
|
||||
void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate )
|
||||
void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*docker_point*/, int /*dockee_point*/, int immediate )
|
||||
{
|
||||
int gindex;
|
||||
ai_goal *aigp;
|
||||
@@ -1340,25 +1350,6 @@ void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int doc
|
||||
ai_process_mission_orders( Ships[aip->shipnum].objnum, aip );
|
||||
}
|
||||
|
||||
// function to add an internal goal to a wing. Mike K says that the goal doesn't need to persist
|
||||
// across waves of the wing so we merely need to add the goal to each ship in the wing. Certain
|
||||
// goal are simply not valid for wings (like dock, undock). Immediate parameter gets passed to add_ship_goal
|
||||
// to say whether or not we should process this goal right away
|
||||
void ai_add_goal_wing_internal( wing *wingp, int goal_type, char *name, int immediate )
|
||||
{
|
||||
int i;
|
||||
|
||||
// be sure we are not trying to issue dock or undock goals to wings
|
||||
Assert ( (goal_type != AI_GOAL_DOCK) && (goal_type != AI_GOAL_UNDOCK) );
|
||||
|
||||
for (i = 0; i < wingp->current_count; i++) {
|
||||
int num = wingp->ship_index[i];
|
||||
if ( num == -1 ) // ship must have been destroyed or departed
|
||||
continue;
|
||||
ai_add_goal_ship_internal( &Ai_info[Ships[num].ai_index], goal_type, name, -1, -1, immediate);
|
||||
}
|
||||
}
|
||||
|
||||
// this function copies goals from a wing to an ai_info * from a ship.
|
||||
void ai_copy_mission_wing_goal( ai_goal *aigp, ai_info *aip )
|
||||
{
|
||||
@@ -1401,7 +1392,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
|
||||
// these orders are always achievable.
|
||||
if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
|
||||
|| (aigp->ai_mode == AI_GOAL_CHASE_ANY) || (aigp->ai_mode == AI_GOAL_STAY_STILL)
|
||||
|| (aigp->ai_mode == AI_GOAL_PLAY_DEAD) )
|
||||
|| (aigp->ai_mode == AI_GOAL_PLAY_DEAD) || (aigp->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT) )
|
||||
return AI_GOAL_ACHIEVABLE;
|
||||
|
||||
// warp (depart) only achievable if there's somewhere to depart to
|
||||
@@ -1640,7 +1631,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;
|
||||
}
|
||||
}
|
||||
@@ -1895,9 +1886,12 @@ int ai_goal_priority_compare(const void *a, const void *b)
|
||||
// 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[AI::Goal_Flags::Goal_override]) && !(gb->flags[AI::Goal_Flags::Goal_override]) )
|
||||
// Goober5000: the ONLY goals we do not override are play-dead and play-dead-persistent,
|
||||
// because the override flag needs to work in any other situation
|
||||
|
||||
else if ( (ga->flags[AI::Goal_Flags::Goal_override]) && !(gb->flags[AI::Goal_Flags::Goal_override]) && !(gb->ai_mode == AI_GOAL_PLAY_DEAD) && !(gb->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT) )
|
||||
return -1;
|
||||
else if ( !(ga->flags[AI::Goal_Flags::Goal_override]) && (gb->flags[AI::Goal_Flags::Goal_override]) )
|
||||
else if ( !(ga->flags[AI::Goal_Flags::Goal_override]) && (gb->flags[AI::Goal_Flags::Goal_override]) && !(ga->ai_mode == AI_GOAL_PLAY_DEAD) && !(ga->ai_mode == AI_GOAL_PLAY_DEAD_PERSISTENT))
|
||||
return 1;
|
||||
|
||||
// now normal priority processing
|
||||
@@ -2290,6 +2284,13 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
|
||||
aip->submode_start_time = Missiontime;
|
||||
break;
|
||||
|
||||
case AI_GOAL_PLAY_DEAD_PERSISTENT:
|
||||
// same as above, but we don't clear out ship goals
|
||||
aip->mode = AIM_PLAY_DEAD;
|
||||
aip->submode = -1;
|
||||
aip->submode_start_time = Missiontime;
|
||||
break;
|
||||
|
||||
case AI_GOAL_FORM_ON_WING:
|
||||
// for form on wing, we need to clear out all goals for this ship, and then call the form
|
||||
// on wing AI code
|
||||
|
||||
+5
-5
@@ -58,16 +58,17 @@ struct ai_goal;
|
||||
#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
|
||||
#define AI_GOAL_PLAY_DEAD_PERSISTENT (1<<26) // 0x03000000
|
||||
|
||||
// now the masks for ship types
|
||||
|
||||
// Goober5000: added AI_GOAL_STAY_NEAR_SHIP and AI_GOAL_KEEP_SAFE_DISTANCE as valid for fighters
|
||||
//WMC - Don't need these anymore. Whee!
|
||||
/*
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_FIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_DESTROY_SUBSYSTEM | AI_GOAL_CHASE_WING | AI_GOAL_GUARD | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE_ANY | AI_GOAL_IGNORE | AI_GOAL_IGNORE_NEW | AI_GOAL_GUARD_WING | AI_GOAL_EVADE_SHIP | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE )
|
||||
#define AI_GOAL_ACCEPT_BOMBER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_STEALTH ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD| AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_TRANSPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_WARP | AI_GOAL_UNDOCK | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_FREIGHTER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CRUISER ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_FREIGHTER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CORVETTE ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
@@ -75,7 +76,7 @@ struct ai_goal;
|
||||
#define AI_GOAL_ACCEPT_AWACS ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_CAPITAL ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CRUISER & ~(AI_GOAL_DOCK | AI_GOAL_UNDOCK) | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPERCAP ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_CAPITAL | AI_GOAL_STAY_NEAR_SHIP )
|
||||
#define AI_GOAL_ACCEPT_SUPPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_DOCK | AI_GOAL_UNDOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD)
|
||||
#define AI_GOAL_ACCEPT_SUPPORT ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_DOCK | AI_GOAL_UNDOCK | AI_GOAL_WAYPOINTS | AI_GOAL_WAYPOINTS_ONCE | AI_GOAL_STAY_NEAR_SHIP | AI_GOAL_KEEP_SAFE_DISTANCE | AI_GOAL_STAY_STILL | AI_GOAL_PLAY_DEAD | AI_GOAL_PLAY_DEAD_PERSISTENT )
|
||||
#define AI_GOAL_ACCEPT_ESCAPEPOD ( AI_GOAL_FLY_TO_SHIP | AI_GOAL_ACCEPT_TRANSPORT| AI_GOAL_STAY_NEAR_SHIP )
|
||||
*/
|
||||
|
||||
@@ -102,7 +103,7 @@ extern int ai_goal_num(ai_goal *goals);
|
||||
extern void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip);
|
||||
extern void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip );
|
||||
extern void ai_add_wing_goal_sexp( int sexp, int type, int wingnum );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp );
|
||||
extern void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name );
|
||||
|
||||
extern int ai_remove_goal_sexp_sub( int sexp, ai_goal* aigp );
|
||||
extern void ai_remove_wing_goal_sexp(int sexp, int wingnum);
|
||||
@@ -127,6 +128,5 @@ extern char *ai_add_dock_name(const char *str);
|
||||
extern int ai_query_goal_valid( int ship, int ai_goal_type );
|
||||
|
||||
extern void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate = 1 );
|
||||
extern void ai_add_goal_wing_internal( wing *wingp, int goal_type, char *name, int immediate = 1 );
|
||||
|
||||
#endif
|
||||
+14
-12
@@ -24,7 +24,7 @@
|
||||
#include "weapon/swarm.h"
|
||||
#include "weapon/weapon.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <climits>
|
||||
|
||||
|
||||
// How close a turret has to be point at its target before it
|
||||
@@ -243,7 +243,7 @@ int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
|
||||
* @note All non-negative return values are expressed in what I like to call "widx"s.
|
||||
* @return -1 if unable to find a weapon for the target at all.
|
||||
*/
|
||||
int turret_select_best_weapon(ship_subsys *turret, object *target)
|
||||
int turret_select_best_weapon(ship_subsys *turret, object * /*target*/)
|
||||
{
|
||||
//TODO: Fill this out with extraodinary gun-picking algorithms
|
||||
if(turret->weapons.num_primary_banks > 0)
|
||||
@@ -1290,7 +1290,9 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
model_instance_find_world_point(&tmp_pos, &avg, Ships[objp->instance].model_instance_num, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
if (targetp == nullptr) {
|
||||
Assertion(ssp->turret_enemy_objnum >= 0, "The turret enemy object number %d for %s on ship number %d is invalid.", ssp->turret_enemy_objnum, ssp->sub_name, ssp->parent_objnum);
|
||||
ship* shipp = &Ships[Objects[ssp->parent_objnum].instance];
|
||||
Assertion(ssp->turret_enemy_objnum >= 0, "The turret enemy object number %d for %s on ship name %s is invalid.", ssp->turret_enemy_objnum, ssp->sub_name,
|
||||
(shipp->has_display_name()) ? shipp->display_name.c_str() : shipp->ship_name);
|
||||
object *lep = &Objects[ssp->turret_enemy_objnum];
|
||||
|
||||
int best_weapon_tidx = turret_select_best_weapon(ssp, lep);
|
||||
@@ -1301,9 +1303,9 @@ void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos
|
||||
|
||||
weapon_info *wip = get_turret_weapon_wip(&ssp->weapons, best_weapon_tidx);
|
||||
|
||||
float weapon_system_strength = ship_get_subsystem_strength(&Ships[ssp->parent_objnum], SUBSYSTEM_WEAPONS);
|
||||
float weapon_system_strength = ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
|
||||
|
||||
turret_ai_update_aim(&Ai_info[Ships[ssp->parent_objnum].ai_index], &Objects[ssp->turret_enemy_objnum], ssp);
|
||||
turret_ai_update_aim(&Ai_info[shipp->ai_index], &Objects[ssp->turret_enemy_objnum], ssp);
|
||||
|
||||
if ((ssp->targeted_subsys != nullptr) && !(ssp->flags[Ship::Subsystem_Flags::No_SS_targeting])) {
|
||||
vm_vec_unrotate(&enemy_point, &ssp->targeted_subsys->system_info->pnt, &Objects[ssp->turret_enemy_objnum].orient);
|
||||
@@ -1874,7 +1876,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[parent_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
|
||||
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
|
||||
}
|
||||
|
||||
@@ -2009,7 +2011,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
wp->turret_subsys = turret;
|
||||
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[parent_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
|
||||
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
|
||||
|
||||
// if the gun is a flak gun
|
||||
@@ -2048,10 +2050,10 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
}
|
||||
|
||||
if ( wip->launch_snd != -1 ) {
|
||||
if ( wip->launch_snd.isValid() ) {
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2126,7 +2128,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
|
||||
|
||||
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[tsi->parent_objnum]);
|
||||
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
|
||||
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
|
||||
|
||||
// muzzle flash?
|
||||
@@ -2135,10 +2137,10 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
}
|
||||
|
||||
// maybe sound
|
||||
if ( Weapon_info[tsi->weapon_class].launch_snd != -1 ) {
|
||||
if ( Weapon_info[tsi->weapon_class].launch_snd.isValid() ) {
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-167
@@ -274,9 +274,9 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
|
||||
percent_through = instance->time_elapsed / time;
|
||||
|
||||
if(instance->direction == ANIM_DIRECT_FORWARD)
|
||||
new_frame_num = instance->start_at - 1 + fl2i(percent_through * n_frames + 0.5f);
|
||||
new_frame_num = instance->start_at - 1 + (int) lround(percent_through * n_frames);
|
||||
else
|
||||
new_frame_num = instance->start_at - 1 - fl2i(percent_through * n_frames + 0.5f);
|
||||
new_frame_num = instance->start_at - 1 - (int) lround(percent_through * n_frames);
|
||||
|
||||
frame_save = instance->frame_num;
|
||||
|
||||
@@ -519,19 +519,6 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop an anim instance that is on the anim_render_list from playing
|
||||
*/
|
||||
int anim_stop_playing(anim_instance* instance)
|
||||
{
|
||||
Assert(instance != NULL);
|
||||
|
||||
if ( anim_playing(instance) ) {
|
||||
anim_release_render_instance(instance);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free a particular animation instance that is on the anim_render_list.
|
||||
* Do not call this function to free an animation instance in general (use
|
||||
@@ -733,6 +720,10 @@ anim *anim_load(const 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);
|
||||
@@ -761,7 +752,7 @@ anim *anim_load(const 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);
|
||||
@@ -862,20 +853,6 @@ int anim_free(anim *ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return if an anim is playing or not.
|
||||
*/
|
||||
int anim_playing(anim_instance *ai)
|
||||
{
|
||||
Assert(ai != NULL);
|
||||
if ( ai->frame == NULL )
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Called at the beginning of a mission to initialize any mission dependent anim data.
|
||||
* @todo Redundant?
|
||||
@@ -892,133 +869,6 @@ void anim_level_close()
|
||||
anim_release_all_instances();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the frames of a .ani file out to disk as .pcx files.
|
||||
* @details Use naming convention: filename0000.pcx, filename0001.pcx etc.
|
||||
*
|
||||
* @return If success 0, or if failed -1
|
||||
*/
|
||||
int anim_write_frames_out(char *filename)
|
||||
{
|
||||
anim *source_anim;
|
||||
anim_instance *ai;
|
||||
char root_name[256], pcxname[256];
|
||||
char buf[64];
|
||||
int i,j;
|
||||
ubyte **row_data;
|
||||
|
||||
strcpy_s(root_name, filename);
|
||||
root_name[strlen(filename)-4] = 0;
|
||||
|
||||
source_anim = anim_load(filename);
|
||||
if ( source_anim == NULL )
|
||||
return -1;
|
||||
|
||||
ai = init_anim_instance(source_anim, 16);
|
||||
|
||||
row_data = (ubyte**)vm_malloc((source_anim->height+1) * 4);
|
||||
|
||||
for ( i = 0; i < source_anim->total_frames; i++ ) {
|
||||
anim_get_next_raw_buffer(ai, 0, 0, 16);
|
||||
strcpy_s(pcxname, root_name);
|
||||
sprintf(buf,"%04d",i);
|
||||
strcat_s(pcxname, buf);
|
||||
|
||||
for ( j = 0; j < source_anim->height; j++ ) {
|
||||
row_data[j] = &ai->frame[j*source_anim->width];
|
||||
}
|
||||
|
||||
|
||||
pcx_write_bitmap( pcxname,
|
||||
source_anim->width,
|
||||
source_anim->height,
|
||||
row_data,
|
||||
source_anim->palette);
|
||||
|
||||
printf(".");
|
||||
|
||||
}
|
||||
printf("\n");
|
||||
vm_free(row_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Display information and statistics about a .ani file.
|
||||
* @details This is called when -i switch is on when running ac.exe
|
||||
*/
|
||||
void anim_display_info(char *real_filename)
|
||||
{
|
||||
CFILE *fp;
|
||||
anim A;
|
||||
float percent;
|
||||
int i, uncompressed, compressed, *key_frame_nums=NULL, tmp;
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
|
||||
strcpy_s( filename, real_filename );
|
||||
char *p = strchr( filename, '.' );
|
||||
if ( p ) {
|
||||
*p = 0;
|
||||
}
|
||||
strcat_s( filename, ".ani" );
|
||||
|
||||
fp = cfopen(filename, "rb");
|
||||
if ( !fp ) {
|
||||
printf("Fatal error opening %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
anim_read_header(&A, fp);
|
||||
// read the keyframe frame nums and offsets
|
||||
key_frame_nums = (int*)vm_malloc(sizeof(int)*A.num_keys);
|
||||
Assert(key_frame_nums != NULL);
|
||||
if (key_frame_nums == NULL)
|
||||
return;
|
||||
|
||||
for ( i = 0; i < A.num_keys; i++ ) {
|
||||
key_frame_nums[i] = 0;
|
||||
cfread(&key_frame_nums[i], 2, 1, fp);
|
||||
cfread(&tmp, 4, 1, fp);
|
||||
}
|
||||
|
||||
cfread(&compressed, 4, 1, fp);
|
||||
|
||||
uncompressed = A.width * A.height * A.total_frames; // 8 bits per pixel
|
||||
percent = i2fl(compressed) / uncompressed * 100.0f;
|
||||
|
||||
printf("%% of uncompressed size: %.0f%%\n", percent);
|
||||
printf("Width: %d\n", A.width);
|
||||
printf("Height: %d\n", A.height);
|
||||
printf("Total Frames: %d\n", A.total_frames);
|
||||
|
||||
#ifndef NDEBUG
|
||||
printf("Key Frames: %d\n", A.num_keys);
|
||||
if ( A.num_keys > 1 && (A.total_frames != A.num_keys) ) {
|
||||
printf("key list: (");
|
||||
for ( i = 0; i < A.num_keys; i++ ) {
|
||||
if ( i < A.num_keys-1 )
|
||||
printf("%d, ", key_frame_nums[i]);
|
||||
else
|
||||
printf("%d)\n", key_frame_nums[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("FPS: %d\n", A.fps);
|
||||
|
||||
#ifndef NDEBUG
|
||||
printf("Transparent RGB: (%u,%u,%u)\n", A.xparent_r, A.xparent_g, A.xparent_b);
|
||||
#endif
|
||||
|
||||
printf("ac version: %d\n", A.version);
|
||||
|
||||
if ( key_frame_nums != NULL ) {
|
||||
vm_free(key_frame_nums);
|
||||
}
|
||||
|
||||
cfclose(fp);
|
||||
}
|
||||
|
||||
void anim_reverse_direction(anim_instance *ai)
|
||||
{
|
||||
int temp;
|
||||
@@ -1052,16 +902,6 @@ void anim_reverse_direction(anim_instance *ai)
|
||||
}
|
||||
}
|
||||
|
||||
void anim_pause(anim_instance *ai)
|
||||
{
|
||||
ai->paused = 1;
|
||||
}
|
||||
|
||||
void anim_unpause(anim_instance *ai)
|
||||
{
|
||||
ai->paused = 0;
|
||||
}
|
||||
|
||||
void anim_ignore_next_frametime()
|
||||
{
|
||||
Anim_ignore_frametime=1;
|
||||
|
||||
+3
-10
@@ -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;
|
||||
@@ -55,19 +54,13 @@ void anim_render_one(int screen_id, anim_instance *ani, float frametime);
|
||||
void anim_play_init(anim_play_struct *aps, anim *a_info, int x, int y, int max_x = -1, int max_y = -1);
|
||||
anim_instance *anim_play(anim_play_struct *aps);
|
||||
void anim_ignore_next_frametime();
|
||||
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(const 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);
|
||||
void anim_display_info(char *filename);
|
||||
void anim_read_header(anim *ptr, CFILE *fp);
|
||||
void anim_reverse_direction(anim_instance *ai); // called automatically for ping-ponging, and can also be called externally
|
||||
void anim_pause(anim_instance *ai);
|
||||
void anim_unpause(anim_instance *ai);
|
||||
|
||||
int anim_instance_is_streamed(anim_instance *ai);
|
||||
unsigned char anim_instance_get_byte(anim_instance *ai, int offset);
|
||||
|
||||
+16
-363
@@ -78,52 +78,6 @@ void free_anim_instance(anim_instance *inst)
|
||||
vm_free(inst);
|
||||
}
|
||||
|
||||
int anim_get_next_frame(anim_instance *inst)
|
||||
{
|
||||
int bm, bitmap_flags;
|
||||
int aabitmap = 0;
|
||||
int bpp = 16;
|
||||
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
if ( inst->file_offset <= 0 ) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!inst->data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
inst->frame_num++;
|
||||
if (inst->frame_num >= inst->parent->total_frames) {
|
||||
inst->data = NULL;
|
||||
inst->file_offset = inst->parent->file_offset;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bitmap_flags = 0;
|
||||
|
||||
bpp = 16;
|
||||
if(inst->aa_color != NULL){
|
||||
bitmap_flags |= BMP_AABITMAP;
|
||||
aabitmap = 1;
|
||||
bpp = 8;
|
||||
}
|
||||
|
||||
anim_check_for_palette_change(inst);
|
||||
|
||||
BM_SELECT_TEX_FORMAT();
|
||||
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
inst->file_offset = unpack_frame_from_file(inst, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
|
||||
} else {
|
||||
inst->data = unpack_frame(inst, inst->data, inst->frame, inst->parent->width*inst->parent->height, inst->parent->palette_translation, aabitmap, bpp);
|
||||
}
|
||||
|
||||
bm = bm_create(bpp, inst->parent->width, inst->parent->height, inst->frame, bitmap_flags);
|
||||
bm_unload(bm);
|
||||
return bm;
|
||||
}
|
||||
|
||||
ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp)
|
||||
{
|
||||
if ( anim_instance_is_streamed(inst) ) {
|
||||
@@ -162,321 +116,6 @@ ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap
|
||||
return inst->frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pack key frame
|
||||
*
|
||||
* @param frame Frame pixel data to pack
|
||||
* @param save Memory to store packed data to
|
||||
* @param size Number of bytes to pack
|
||||
* @param max Maximum number of packed bytes (size of buffer)
|
||||
* @param compress_type Compress type
|
||||
* @return Actual number of bytes data packed to or -1 if error
|
||||
*/
|
||||
int pack_key_frame(ubyte *frame, ubyte *save, long size, long max, int compress_type)
|
||||
{
|
||||
int last = -32768, count = 0;
|
||||
long packed_size = 1;
|
||||
|
||||
switch ( compress_type ) {
|
||||
case PACKING_METHOD_RLE_KEY:
|
||||
*save++ = PACKING_METHOD_RLE_KEY;
|
||||
while (size--) {
|
||||
if (*frame != last || count > 255) {
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 3;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
last = *frame;
|
||||
}
|
||||
|
||||
count++;
|
||||
frame++;
|
||||
}
|
||||
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case PACKING_METHOD_STD_RLE_KEY: {
|
||||
ubyte *dest_start;
|
||||
int i;
|
||||
|
||||
dest_start = save;
|
||||
count = 1;
|
||||
|
||||
last = *frame++;
|
||||
*save++ = PACKING_METHOD_STD_RLE_KEY;
|
||||
for (i=1; i < size; i++ ) {
|
||||
|
||||
if ( *frame != last ) {
|
||||
if ( count ) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
last = *frame;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
frame++;
|
||||
|
||||
if ( count == 127 ) {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
count = 0;
|
||||
}
|
||||
} // end for
|
||||
|
||||
if (count) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(packed_size == (save-dest_start) );
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
default:
|
||||
Assert(0);
|
||||
return -1;
|
||||
break;
|
||||
} // end switch
|
||||
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pack frame
|
||||
*
|
||||
* @param frame Frame pixel data to pack
|
||||
* @param frame2 Previous frame's pixel data
|
||||
* @param save Memory to store packed data to
|
||||
* @param size Number of bytes to pack
|
||||
* @param max Maximum number of packed bytes (size of buffer)
|
||||
* @param compress_type Compress type
|
||||
* @return Actual number of bytes data packed to or -1 if error
|
||||
*/
|
||||
int pack_frame(ubyte *frame, ubyte *frame2, ubyte *save, long size, long max, int compress_type)
|
||||
{
|
||||
int pixel, last = -32768, count = 0, i;
|
||||
long packed_size = 1;
|
||||
|
||||
switch ( compress_type ) {
|
||||
case PACKING_METHOD_RLE: // Hoffoss RLE regular frame
|
||||
*save++ = PACKING_METHOD_RLE;
|
||||
while (size--) {
|
||||
if (*frame != *frame2++)
|
||||
pixel = *frame;
|
||||
else
|
||||
pixel = transparent_code;
|
||||
|
||||
if (pixel != last || count > 255) {
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 3;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
last = pixel;
|
||||
}
|
||||
|
||||
frame++;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (packed_size + 3 >= max)
|
||||
return -1;
|
||||
|
||||
if (count < 3) {
|
||||
if (last == packer_code) {
|
||||
*save++ = (ubyte)packer_code;
|
||||
*save++ = (ubyte)(count - 1);
|
||||
packed_size += 2;
|
||||
|
||||
} else
|
||||
while (count--) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
}
|
||||
|
||||
} else {
|
||||
*save++ = (ubyte)(packer_code);
|
||||
*save++ = (ubyte)(count - 1);
|
||||
*save++ = (ubyte)(last);
|
||||
packed_size += 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case PACKING_METHOD_STD_RLE: { // high bit count regular RLE frame
|
||||
|
||||
ubyte *dest_start;
|
||||
|
||||
dest_start = save;
|
||||
count = 1;
|
||||
|
||||
if (*frame++ != *frame2++)
|
||||
last = *frame;
|
||||
else
|
||||
last = transparent_code;
|
||||
|
||||
*save++ = PACKING_METHOD_STD_RLE;
|
||||
for (i=1; i < size; i++ ) {
|
||||
|
||||
if (*frame != *frame2++)
|
||||
pixel = *frame;
|
||||
else
|
||||
pixel = transparent_code;
|
||||
|
||||
if ( pixel != last ) {
|
||||
if ( count ) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
last = pixel;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
frame++;
|
||||
|
||||
if ( count == 127 ) {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
count = 0;
|
||||
}
|
||||
} // end for
|
||||
|
||||
if (count) {
|
||||
|
||||
if (packed_size + 2 >= max)
|
||||
return -1;
|
||||
|
||||
if ( (count == 1) && !(last & STD_RLE_CODE) ) {
|
||||
*save++ = (ubyte)last;
|
||||
packed_size++;
|
||||
Assert( last != STD_RLE_CODE );
|
||||
}
|
||||
else {
|
||||
count |= STD_RLE_CODE;
|
||||
*save++ = (ubyte)count;
|
||||
*save++ = (ubyte)last;
|
||||
packed_size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(packed_size == (save-dest_start) );
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
default:
|
||||
Assert(0);
|
||||
return -1;
|
||||
break;
|
||||
} // end switch
|
||||
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a 24 bit value to a 16 bit value
|
||||
* @param bit_24 24 bit value
|
||||
@@ -512,7 +151,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 +242,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();
|
||||
|
||||
@@ -97,16 +97,12 @@ typedef struct anim_instance {
|
||||
int loop_count; // starts at 0, and is incremented each time it loops
|
||||
} anim_instance;
|
||||
|
||||
int pack_key_frame(ubyte *frame, ubyte *save, long size, long max, int compress_type);
|
||||
int pack_frame(ubyte *frame, ubyte *frame2, ubyte *save, long size, long max, int compress_type);
|
||||
|
||||
ubyte *unpack_frame(anim_instance *ai, ubyte *ptr, ubyte *frame, int size, ubyte *pal_translate, int aabitmap, int bpp);
|
||||
int unpack_frame_from_file(anim_instance *ai, ubyte *frame, int size, ubyte *pal_translate, int aabitmap, int bpp);
|
||||
|
||||
void anim_init();
|
||||
anim_instance *init_anim_instance(anim *ptr, int bpp);
|
||||
void free_anim_instance(anim_instance *inst);
|
||||
int anim_get_next_frame(anim_instance *inst);
|
||||
ubyte *anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp);
|
||||
void anim_set_palette(anim *a);
|
||||
void anim_check_for_palette_change(anim_instance *inst);
|
||||
|
||||
+49
-107
@@ -76,7 +76,7 @@ float Asteroid_icon_closeup_zoom;
|
||||
/**
|
||||
* Force updating of pair stuff for asteroid *objp.
|
||||
*/
|
||||
void asteroid_update_collide(object *objp)
|
||||
static void asteroid_update_collide(object *objp)
|
||||
{
|
||||
// Asteroid has wrapped, update collide objnum and flags
|
||||
Asteroids[objp->instance].collide_objnum = -1;
|
||||
@@ -87,7 +87,7 @@ void asteroid_update_collide(object *objp)
|
||||
/**
|
||||
* Clear out the ::Asteroid_obj_list
|
||||
*/
|
||||
void asteroid_obj_list_init()
|
||||
static void asteroid_obj_list_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -101,7 +101,7 @@ void asteroid_obj_list_init()
|
||||
* Add a node from the Asteroid_obj_list.
|
||||
* Only called from ::weapon_create()
|
||||
*/
|
||||
int asteroid_obj_list_add(int objnum)
|
||||
static int asteroid_obj_list_add(int objnum)
|
||||
{
|
||||
int index;
|
||||
|
||||
@@ -123,7 +123,7 @@ int asteroid_obj_list_add(int objnum)
|
||||
* Remove a node from the Asteroid_obj_list.
|
||||
* Only called from ::weapon_delete()
|
||||
*/
|
||||
void asteroid_obj_list_remove(object * obj)
|
||||
static void asteroid_obj_list_remove(object * obj)
|
||||
{
|
||||
int index = obj->instance;
|
||||
|
||||
@@ -138,7 +138,7 @@ void asteroid_obj_list_remove(object * obj)
|
||||
/**
|
||||
* Prevent speed from getting too huge so it's hard to catch up to an asteroid.
|
||||
*/
|
||||
float asteroid_cap_speed(int asteroid_info_index, float speed)
|
||||
static float asteroid_cap_speed(int asteroid_info_index, float speed)
|
||||
{
|
||||
float max, double_max;
|
||||
|
||||
@@ -164,7 +164,7 @@ float asteroid_cap_speed(int asteroid_info_index, float speed)
|
||||
* Sum together the following: 1 inside x, 2 inside y, 4 inside z
|
||||
* inside only when sum = 7
|
||||
*/
|
||||
int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
|
||||
static int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
|
||||
{
|
||||
Assert(asfieldp->has_inner_bound);
|
||||
|
||||
@@ -188,7 +188,7 @@ int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, floa
|
||||
* Check if asteroid is within inner bound
|
||||
* @return 0 if not inside or no inner bound, 1 if inside inner bound
|
||||
*/
|
||||
int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
|
||||
static int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
|
||||
|
||||
if (!asfieldp->has_inner_bound) {
|
||||
return 0;
|
||||
@@ -202,7 +202,7 @@ int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
|
||||
*
|
||||
* Moves to the other side of the inner box a distance delta from edge of box
|
||||
*/
|
||||
void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
|
||||
static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
|
||||
{
|
||||
if (!asteroid_in_inner_bound(asfieldp, pos, 0)) {
|
||||
return;
|
||||
@@ -446,7 +446,7 @@ void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
|
||||
/**
|
||||
* Load in an asteroid model
|
||||
*/
|
||||
void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
{
|
||||
int i;
|
||||
asteroid_info *asip;
|
||||
@@ -487,26 +487,12 @@ void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly choose a debris model within the current group
|
||||
*/
|
||||
int get_debris_from_same_group(int index) {
|
||||
int group_base, group_offset;
|
||||
|
||||
group_base = (index / NUM_DEBRIS_SIZES) * NUM_DEBRIS_SIZES;
|
||||
group_offset = index - group_base;
|
||||
|
||||
// group base + offset
|
||||
// offset is formed by adding 1 or 2 (since 3 in model group) and mapping back in the 0-2 range
|
||||
return group_base + ((group_offset + rand()%(NUM_DEBRIS_SIZES-1) + 1) % NUM_DEBRIS_SIZES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a weight that depends on asteroid size.
|
||||
*
|
||||
* The weight is then used to determine the frequencty of different sizes of ship debris
|
||||
*/
|
||||
int get_debris_weight(int ship_debris_index)
|
||||
static int get_debris_weight(int ship_debris_index)
|
||||
{
|
||||
int size = ship_debris_index % NUM_DEBRIS_SIZES;
|
||||
switch (size)
|
||||
@@ -626,7 +612,7 @@ void asteroid_create_all()
|
||||
}
|
||||
|
||||
/**
|
||||
* Init asteriod system for the level, called from ::game_level_init()
|
||||
* Init asteroid system for the level, called from ::game_level_init()
|
||||
*/
|
||||
void asteroid_level_init()
|
||||
{
|
||||
@@ -645,7 +631,7 @@ void asteroid_level_init()
|
||||
*
|
||||
* @return !0 if asteroid should be wrapped, 0 otherwise.
|
||||
*/
|
||||
int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
|
||||
static int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
|
||||
{
|
||||
if ( MULTIPLAYER_CLIENT )
|
||||
return 0;
|
||||
@@ -690,7 +676,7 @@ int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
|
||||
/**
|
||||
* Wrap an asteroid from one end of the asteroid field to the other
|
||||
*/
|
||||
void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
|
||||
static void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
|
||||
{
|
||||
if (objp->pos.xyz.x < asfieldp->min_bound.xyz.x) {
|
||||
objp->pos.xyz.x = asfieldp->max_bound.xyz.x + (objp->pos.xyz.x - asfieldp->min_bound.xyz.x);
|
||||
@@ -727,7 +713,7 @@ void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
|
||||
*
|
||||
* @return !0 if this asteroid is a target for any ship, otherwise return 0
|
||||
*/
|
||||
int asteroid_is_targeted(object *objp)
|
||||
static int asteroid_is_targeted(object *objp)
|
||||
{
|
||||
ship_obj *so;
|
||||
object *ship_objp;
|
||||
@@ -748,7 +734,7 @@ int asteroid_is_targeted(object *objp)
|
||||
/**
|
||||
* Create an asteroid that will hit object *objp in delta_time seconds
|
||||
*/
|
||||
void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
|
||||
static void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
|
||||
{
|
||||
vec3d predicted_center_pos;
|
||||
vec3d rand_vec;
|
||||
@@ -776,7 +762,7 @@ void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_tim
|
||||
*
|
||||
* @param count asteroids already targeted on
|
||||
*/
|
||||
void maybe_throw_asteroid(int count)
|
||||
static void maybe_throw_asteroid(int count)
|
||||
{
|
||||
if (!timestamp_elapsed(Next_asteroid_throw)) {
|
||||
return;
|
||||
@@ -850,7 +836,7 @@ void asteroid_delete( object * obj )
|
||||
* See if we should reposition the asteroid.
|
||||
* Only reposition if oustide the bounding volume and the player isn't looking towards the asteroid.
|
||||
*/
|
||||
void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
{
|
||||
// passive field does not wrap
|
||||
if (asfieldp->field_type == FT_PASSIVE) {
|
||||
@@ -903,7 +889,7 @@ void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
|
||||
}
|
||||
}
|
||||
|
||||
void lerp(float *goal, float f1, float f2, float scale)
|
||||
static void lerp(float *goal, float f1, float f2, float scale)
|
||||
{
|
||||
*goal = (f2 - f1) * scale + f1;
|
||||
}
|
||||
@@ -1207,7 +1193,7 @@ void asteroid_render(object * obj, model_draw_list *scene)
|
||||
/**
|
||||
* Create a normalized vector generally in the direction from *hitpos to other_obj->pos
|
||||
*/
|
||||
void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
|
||||
static void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
|
||||
{
|
||||
vec3d tvec, rand_vec;
|
||||
int count = 0;
|
||||
@@ -1229,7 +1215,7 @@ void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
|
||||
/**
|
||||
* Return multiplier on asteroid radius for fireball
|
||||
*/
|
||||
float asteroid_get_fireball_scale_multiplier(int num)
|
||||
static float asteroid_get_fireball_scale_multiplier(int num)
|
||||
{
|
||||
if (Asteroids[num].flags & AF_USED) {
|
||||
asteroid_info *asip = &Asteroid_info[Asteroids[num].asteroid_type];
|
||||
@@ -1258,7 +1244,7 @@ float asteroid_get_fireball_scale_multiplier(int num)
|
||||
* Create asteroid explosion
|
||||
* @return expected time for explosion anim to last, in seconds
|
||||
*/
|
||||
float asteroid_create_explosion(object *objp)
|
||||
static float asteroid_create_explosion(object *objp)
|
||||
{
|
||||
int fireball_objnum;
|
||||
float explosion_life, fireball_scale_multiplier;
|
||||
@@ -1277,7 +1263,7 @@ float asteroid_create_explosion(object *objp)
|
||||
|
||||
fireball_scale_multiplier = asteroid_get_fireball_scale_multiplier(objp->instance);
|
||||
|
||||
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), objp->radius*fireball_scale_multiplier, 0, &objp->phys_info.vel );
|
||||
fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), objp->radius*fireball_scale_multiplier, false, &objp->phys_info.vel );
|
||||
if ( fireball_objnum > -1 ) {
|
||||
explosion_life = fireball_lifeleft(&Objects[fireball_objnum]);
|
||||
} else {
|
||||
@@ -1290,37 +1276,37 @@ float asteroid_create_explosion(object *objp)
|
||||
/**
|
||||
* Play sound when asteroid explodes
|
||||
*/
|
||||
void asteriod_explode_sound(object *objp, int type, int play_loud)
|
||||
static void asteroid_explode_sound(object *objp, int type, int play_loud)
|
||||
{
|
||||
int sound_index = -1;
|
||||
gamesnd_id sound_index;
|
||||
float range_factor = 1.0f; // how many times sound should traver farther than normal
|
||||
|
||||
if (type % NUM_DEBRIS_SIZES <= 1)
|
||||
{
|
||||
sound_index = SND_ASTEROID_EXPLODE_SMALL;
|
||||
sound_index = gamesnd_id(GameSounds::ASTEROID_EXPLODE_SMALL);
|
||||
range_factor = 5.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sound_index = SND_ASTEROID_EXPLODE_LARGE;
|
||||
sound_index = gamesnd_id(GameSounds::ASTEROID_EXPLODE_LARGE);
|
||||
range_factor = 10.0f;
|
||||
}
|
||||
|
||||
Assert(sound_index != -1);
|
||||
Assert(sound_index.isValid());
|
||||
|
||||
if ( !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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the area effect for an asteroid exploding
|
||||
*
|
||||
* @param asteroid_objp object pointer to asteriod causing explosion
|
||||
* @param asteroid_objp object pointer to asteroid causing explosion
|
||||
*/
|
||||
void asteroid_do_area_effect(object *asteroid_objp)
|
||||
static void asteroid_do_area_effect(object *asteroid_objp)
|
||||
{
|
||||
object *ship_objp;
|
||||
float damage, blast;
|
||||
@@ -1382,7 +1368,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
|
||||
|
||||
explosion_life = asteroid_create_explosion(pasteroid_obj);
|
||||
|
||||
asteriod_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
|
||||
asteroid_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
|
||||
asteroid_do_area_effect(pasteroid_obj);
|
||||
|
||||
asp->final_death_time = timestamp( fl2i(explosion_life*1000.0f)/5 ); // Wait till 30% of vclip time before breaking the asteroid up.
|
||||
@@ -1401,7 +1387,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
|
||||
weapon_info *wip;
|
||||
wip = &Weapon_info[Weapons[other_obj->instance].weapon_info_index];
|
||||
// If the weapon didn't play any impact animation, play custom asteroid impact animation
|
||||
if ( wip->impact_weapon_expl_effect < 0 ) {
|
||||
if (!wip->impact_weapon_expl_effect.isValid()) {
|
||||
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, particle::PARTICLE_BITMAP, Asteroid_impact_explosion_ani );
|
||||
}
|
||||
}
|
||||
@@ -1432,35 +1418,6 @@ void asteroid_level_close()
|
||||
DCF_BOOL2(asteroids, Asteroids_enabled, "enables or disables asteroids", "Usage: asteroids [bool]\nTurns asteroid system on/off. If nothing passed, then toggles it.\n");
|
||||
|
||||
|
||||
void hud_target_asteroid()
|
||||
{
|
||||
int i;
|
||||
int start_index = 0, end_index = MAX_ASTEROIDS;
|
||||
|
||||
if (Player_ai->target_objnum != -1) {
|
||||
if (Objects[Player_ai->target_objnum].type == OBJ_ASTEROID) {
|
||||
start_index = Objects[Player_ai->target_objnum].instance+1;
|
||||
end_index = start_index-1;
|
||||
if (end_index < 0)
|
||||
end_index = MAX_ASTEROIDS;
|
||||
}
|
||||
}
|
||||
|
||||
i = start_index;
|
||||
while (i != end_index) {
|
||||
if (i == MAX_ASTEROIDS)
|
||||
i = 0;
|
||||
|
||||
if (Asteroids[i].flags & AF_USED) {
|
||||
Assert(Objects[Asteroids[i].objnum].type == OBJ_ASTEROID);
|
||||
set_target_objnum( Player_ai, Asteroids[i].objnum);
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of active asteroids
|
||||
*/
|
||||
@@ -1473,7 +1430,7 @@ int asteroid_count()
|
||||
* See if asteroid should split up.
|
||||
* We delay splitting up to allow the explosion animation to play for a bit.
|
||||
*/
|
||||
void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
static void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
{
|
||||
asteroid *asp;
|
||||
asteroid_info *asip;
|
||||
@@ -1568,8 +1525,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
|
||||
@@ -1586,31 +1547,12 @@ void asteroid_maybe_break_up(object *pasteroid_obj)
|
||||
}
|
||||
asp->final_death_time = timestamp(-1);
|
||||
}
|
||||
Script_system.RunCondition(CHA_DEATH, '\0', NULL, pasteroid_obj);
|
||||
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
|
||||
Script_system.RemHookVar("Self");
|
||||
}
|
||||
}
|
||||
|
||||
int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger)
|
||||
{
|
||||
int idx;
|
||||
vec3d asteroid_dir;
|
||||
|
||||
// just pick the first asteroid which satisfies our condition
|
||||
for(idx=0; idx<Num_asteroids; idx++){
|
||||
vm_vec_sub(&asteroid_dir, &Objects[Asteroids[idx].objnum].pos, pos);
|
||||
vm_vec_normalize_quick(&asteroid_dir);
|
||||
|
||||
// if it satisfies the condition
|
||||
if(vm_vec_dot(dir, &asteroid_dir) >= ang){
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy = false)
|
||||
static void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy = false)
|
||||
{
|
||||
float asteroid_ray_dist;
|
||||
vec3d asteroid_fvec, terminus;
|
||||
@@ -1652,7 +1594,7 @@ void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc
|
||||
*
|
||||
* @return !0 if the asteroid will collide with the escort
|
||||
*/
|
||||
int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
|
||||
static int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
|
||||
{
|
||||
mc_info mc;
|
||||
mc_info_init(&mc);
|
||||
@@ -1670,7 +1612,7 @@ int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
|
||||
* Warn if asteroid on collision path with ship
|
||||
* @return !0 if we should warn about asteroid hitting ship, otherwise return 0
|
||||
*/
|
||||
int asteroid_valid_ship_to_warn_collide(ship *shipp)
|
||||
static int asteroid_valid_ship_to_warn_collide(ship *shipp)
|
||||
{
|
||||
if ( !(Ship_info[shipp->ship_info_index].is_big_or_huge()) ) {
|
||||
return 0;
|
||||
@@ -1692,7 +1634,7 @@ int asteroid_valid_ship_to_warn_collide(ship *shipp)
|
||||
* See if asteroid will collide with a large ship on the escort list in the next
|
||||
* ASTEROID_MIN_COLLIDE_TIME seconds.
|
||||
*/
|
||||
void asteroid_update_collide_flag(object *asteroid_objp)
|
||||
static void asteroid_update_collide_flag(object *asteroid_objp)
|
||||
{
|
||||
int i, num_escorts, escort_objnum, will_collide=0;
|
||||
ship *escort_shipp;
|
||||
@@ -1731,7 +1673,7 @@ void asteroid_update_collide_flag(object *asteroid_objp)
|
||||
/**
|
||||
* Ensure that the collide objnum for the asteroid is still valid
|
||||
*/
|
||||
void asteroid_verify_collide_objnum(asteroid *asp)
|
||||
static void asteroid_verify_collide_objnum(asteroid *asp)
|
||||
{
|
||||
if ( asp->collide_objnum >= 0 ) {
|
||||
if ( Objects[asp->collide_objnum].signature != asp->collide_objsig ) {
|
||||
@@ -1811,7 +1753,7 @@ float asteroid_time_to_impact(object *asteroid_objp)
|
||||
/**
|
||||
* Read in a single asteroid section from asteroid.tbl
|
||||
*/
|
||||
void asteroid_parse_section(asteroid_info *asip)
|
||||
static void asteroid_parse_section(asteroid_info *asip)
|
||||
{
|
||||
required_string("$Name:");
|
||||
stuff_string(asip->name, F_NAME, NAME_LENGTH);
|
||||
@@ -1911,7 +1853,7 @@ to do with the debris of ships that explode, however these
|
||||
are the same debris and asteroids that get flung at a ship
|
||||
that is being protected.
|
||||
*/
|
||||
void asteroid_parse_tbl()
|
||||
static void asteroid_parse_tbl()
|
||||
{
|
||||
char impact_ani_file[MAX_FILENAME_LEN];
|
||||
|
||||
@@ -2062,7 +2004,7 @@ void asteroid_parse_tbl()
|
||||
/**
|
||||
* Return number of asteroids expected to collide with a ship.
|
||||
*/
|
||||
int count_incident_asteroids()
|
||||
static int count_incident_asteroids()
|
||||
{
|
||||
object *asteroid_objp;
|
||||
int count;
|
||||
@@ -2086,7 +2028,7 @@ int count_incident_asteroids()
|
||||
* Pick object to throw asteroids at.
|
||||
* Pick any capital or big ship inside the bounds of the asteroid field.
|
||||
*/
|
||||
int set_asteroid_throw_objnum()
|
||||
static int set_asteroid_throw_objnum()
|
||||
{
|
||||
if (Asteroid_field.num_initial_asteroids < 1)
|
||||
return -1;
|
||||
|
||||
@@ -163,7 +163,6 @@ int asteroid_collide_objnum(object *asteroid_objp);
|
||||
float asteroid_time_to_impact(object *asteroid_objp);
|
||||
void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger = 0);
|
||||
|
||||
// need to extern for multiplayer
|
||||
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
|
||||
|
||||
@@ -122,31 +122,6 @@ vec3d *NavPoint::GetPosition()
|
||||
}
|
||||
}
|
||||
|
||||
char* NavPoint::GetInternalName()
|
||||
{
|
||||
char *NavName;
|
||||
char strtmp[33];
|
||||
|
||||
if (flags & NP_WAYPOINT)
|
||||
{
|
||||
NavName = new char[strlen(((waypoint_list*)target_obj)->get_name())+5];
|
||||
memset(NavName, 0, strlen(((waypoint_list*)target_obj)->get_name())+5);
|
||||
strcpy(NavName, ((waypoint_list*)target_obj)->get_name());
|
||||
|
||||
strcat(NavName, ":");
|
||||
sprintf(strtmp, "%d", waypoint_num);
|
||||
strcat(NavName, strtmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
NavName = new char[strlen(((ship*)target_obj)->ship_name)+1];
|
||||
memset(NavName, 0, strlen(((ship*)target_obj)->ship_name)+1);
|
||||
strcpy(NavName, ((ship*)target_obj)->ship_name);
|
||||
}
|
||||
|
||||
return NavName;
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
bool CanAutopilot(vec3d targetPos, bool send_msg)
|
||||
{
|
||||
@@ -998,7 +973,6 @@ camera* nav_get_set_camera()
|
||||
return nav_camera.getCamera();
|
||||
}
|
||||
|
||||
extern int Cmdline_old_collision_sys;
|
||||
void nav_warp(bool prewarp=false)
|
||||
{
|
||||
/* ok... find our end distance - norm1 is still a unit vector in the
|
||||
@@ -1053,11 +1027,7 @@ void nav_warp(bool prewarp=false)
|
||||
}
|
||||
|
||||
// retime all collision pairs
|
||||
if ( Cmdline_old_collision_sys ) {
|
||||
obj_all_collisions_retime();
|
||||
} else {
|
||||
obj_collide_retime_cached_pairs();
|
||||
}
|
||||
obj_collide_retime_cached_pairs();
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
@@ -1231,7 +1201,7 @@ void send_autopilot_msg(char *msg, char *snd)
|
||||
audio_handle = -1;
|
||||
}
|
||||
|
||||
if (msg[0] != '\0' && strcmp(msg, "none"))
|
||||
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
|
||||
change_message("autopilot builtin message", msg, -1, 0);
|
||||
|
||||
// load sound
|
||||
@@ -1246,7 +1216,7 @@ void send_autopilot_msg(char *msg, char *snd)
|
||||
audiostream_play(audio_handle, (Master_event_music_volume * aav_music_volume), 0);
|
||||
}
|
||||
|
||||
if (msg[0] != '\0' && strcmp(msg, "none"))
|
||||
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
|
||||
message_training_queue("autopilot builtin message", timestamp(0), 5); // display message for five seconds
|
||||
}
|
||||
|
||||
@@ -1464,22 +1434,6 @@ bool AddNav_Waypoint(char *Nav, char *WP_Path, int node, int flags)
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
//Change Flags
|
||||
bool Nav_Alt_Flags(char *Nav, int flags)
|
||||
{
|
||||
flags &= ~NP_VALIDTYPE; //clear the NP_SHIP and NP_WAYPOINT bits, make sure they haven't been set
|
||||
|
||||
int nav = FindNav(Nav);
|
||||
|
||||
if (nav != -1)
|
||||
{
|
||||
Navs[nav].flags &= NP_VALIDTYPE; // Clear all bits BUT NP_SHIP or NO_WAYPOINT
|
||||
Navs[nav].flags |= flags; // merge
|
||||
}
|
||||
|
||||
return (nav != -1);
|
||||
}
|
||||
|
||||
//Get Flags
|
||||
int Nav_Get_Flags(char *Nav)
|
||||
{
|
||||
|
||||
@@ -36,7 +36,6 @@ public:
|
||||
int waypoint_num; //only used when flags & NP_WAYPOINT
|
||||
|
||||
vec3d *GetPosition();
|
||||
char* GetInternalName();
|
||||
|
||||
void clear()
|
||||
{
|
||||
@@ -129,9 +128,6 @@ void SelectNav(char *Nav);
|
||||
// Deselects any navpoint selected.
|
||||
void DeselectNav();
|
||||
|
||||
// Set A Nav point to "ZERO"
|
||||
void ZeroNav(int i);
|
||||
|
||||
// Removes a Nav
|
||||
bool DelNavPoint(char *Nav);
|
||||
bool DelNavPoint(int nav);
|
||||
@@ -140,9 +136,6 @@ bool DelNavPoint(int nav);
|
||||
bool AddNav_Ship(char *Nav, char *TargetName, int flags);
|
||||
bool AddNav_Waypoint(char *Nav, char *WP_Path, int node, int flags);
|
||||
|
||||
//Change Flags
|
||||
bool Nav_Alt_Flags(char *Nav, int flags);
|
||||
|
||||
// Sexp Accessors
|
||||
bool Nav_Set_Flag(char *Nav, int flag);
|
||||
bool Nav_UnSet_Flag(char *Nav, int flag);
|
||||
|
||||
+38
-11
@@ -23,6 +23,16 @@
|
||||
|
||||
#include "bmpman/bmpman.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
/**
|
||||
* @brief Container class for graphics API specific bitmap data
|
||||
*/
|
||||
class gr_bitmap_info {
|
||||
public:
|
||||
virtual ~gr_bitmap_info() = 0;
|
||||
};
|
||||
|
||||
union bm_extra_info {
|
||||
struct {
|
||||
// Stuff needed for animations
|
||||
@@ -31,6 +41,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
|
||||
@@ -56,9 +67,7 @@ struct bitmap_entry {
|
||||
char filename[MAX_FILENAME_LEN]; //!< filename for this bitmap
|
||||
|
||||
uint signature; //!< a unique signature identifying the data
|
||||
uint palette_checksum; //!< checksum used to be sure bitmap is in current palette
|
||||
int handle; //!< Handle = id*MAX_BITMAPS + bitmapnum
|
||||
int last_used; //!< When this bitmap was last used
|
||||
|
||||
BM_TYPE type; //!< PCX, USER, ANI, etc
|
||||
BM_TYPE comp_type; //!< What sort of compressed type, BM_TYPE_NONE if not compressed
|
||||
@@ -89,17 +98,35 @@ struct bitmap_entry {
|
||||
#endif
|
||||
};
|
||||
|
||||
extern bitmap_entry bm_bitmaps[MAX_BITMAPS];
|
||||
struct bitmap_slot {
|
||||
bitmap_entry entry;
|
||||
|
||||
gr_bitmap_info* gr_info = nullptr;
|
||||
};
|
||||
|
||||
// image specific lock functions
|
||||
void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_dds( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_png( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_apng( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_jpg( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_pcx( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_tga( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_user( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
|
||||
|
||||
const size_t BM_BLOCK_SIZE = 4096;
|
||||
|
||||
extern SCP_vector<std::array<bitmap_slot, BM_BLOCK_SIZE>> bm_blocks;
|
||||
|
||||
bitmap_slot* bm_get_slot(int handle, bool separate_ani_frames = true);
|
||||
|
||||
inline bitmap_entry* bm_get_entry(int handle, bool separate_ani_frames = true) {
|
||||
return &bm_get_slot(handle, separate_ani_frames)->entry;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* bm_get_gr_info(int handle, bool separate_ani_frames = true) {
|
||||
return static_cast<T*>(bm_get_slot(handle, separate_ani_frames)->gr_info);
|
||||
}
|
||||
|
||||
#endif // __BM_INTERNAL_H__
|
||||
+873
-834
File diff suppressed because it is too large.
Load diff
+74
-100
@@ -32,21 +32,6 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief How many bitmaps the game can handle
|
||||
*
|
||||
* @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
|
||||
* still have about 20% of the slots free. If it still goes over then it's something the artists need to fix.
|
||||
* For instance the Terran Mara fighter, with -spec and -glow and using the Shinepack, needs 117 bitmap slots alone.
|
||||
* 111 of those is just for the glowmaps. This number can be greatly reduced if the number of ani frames for another
|
||||
* LOD than LOD0 has fewer or no ani frames. A 37 frame glow ani for LOD2 is little more than a waste of resources.
|
||||
* Future reports of texture corruption should be initially approached with content as the cause and not code.
|
||||
* 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
|
||||
|
||||
// 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!! ******
|
||||
#define BMP_AABITMAP (1<<0) //!< antialiased bitmap
|
||||
@@ -56,6 +41,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
|
||||
@@ -112,6 +98,10 @@ struct bitmap
|
||||
*/
|
||||
};
|
||||
|
||||
// Forward definition for the graphics API
|
||||
struct bitmap_entry;
|
||||
struct bitmap_slot;
|
||||
|
||||
extern size_t bm_texture_ram; //!< how many bytes of textures are used.
|
||||
|
||||
extern int Bm_paging; //!< Bool type that indicates if BMPMAN is currently paging.
|
||||
@@ -123,12 +113,7 @@ extern const BM_TYPE bm_ani_type_list[]; //!< List of valid bitmap animation t
|
||||
extern const char *bm_ani_ext_list[]; //!< List of extensions for those types
|
||||
extern const int BM_ANI_NUM_TYPES; //!< Calculated number of bitmap animation types
|
||||
|
||||
extern int GLOWMAP; //!< References a map that is a fully lit version of its index -Bobboau
|
||||
extern int SPECMAP; //!< References a map that is for specular mapping -Bobboau
|
||||
extern int ENVMAP; //!< References a map that is for environment mapping -Bobboau
|
||||
extern int NORMMAP; //!< Normal mapping
|
||||
extern int HEIGHTMAP; //!< Height map for normal mapping
|
||||
extern int MISCMAP; //!< Utility map, to be utilized for various things shader authors can come up with
|
||||
|
||||
/**
|
||||
* @brief Initilizes the bitmap manager
|
||||
@@ -140,22 +125,6 @@ void bm_init();
|
||||
*/
|
||||
void bm_close();
|
||||
|
||||
/**
|
||||
* Gets the cache slot of the bitmap indexed by handle.
|
||||
*
|
||||
* @details if the bitmap is an ani, gets the first frame
|
||||
*
|
||||
* @returns The cache slot index of the bitmap if handle is valid
|
||||
*
|
||||
* @note If the handle is invalid, an Assert() fails
|
||||
*/
|
||||
int bm_get_cache_slot(int bitmap_id, int separate_ani_frames);
|
||||
|
||||
/**
|
||||
* @brief Gets the next available bitmap slot.
|
||||
*/
|
||||
int bm_get_next_handle();
|
||||
|
||||
#define BMP_FLAG_RENDER_TARGET_STATIC (1<<0)
|
||||
#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1)
|
||||
#define BMP_FLAG_CUBEMAP (1<<2)
|
||||
@@ -193,9 +162,6 @@ public:
|
||||
|
||||
bool valid();
|
||||
|
||||
float get_channel_red(float u, float v);
|
||||
float get_channel_green(float u, float v);
|
||||
float get_channel_blue(float u, float v);
|
||||
float get_channel_alpha(float u, float v);
|
||||
};
|
||||
|
||||
@@ -337,13 +303,6 @@ int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, i
|
||||
*/
|
||||
bitmap* bm_lock(int handle, int bpp, ubyte flags, bool nodebug = false);
|
||||
|
||||
/**
|
||||
* @brief Returns a unique signiature for the bitmap indexed by handle
|
||||
*
|
||||
* @details A signature will change when the bitmap's data changes
|
||||
*/
|
||||
uint bm_get_signature(int handle);
|
||||
|
||||
/**
|
||||
* @brief Returns the image type of the given bitmap handle
|
||||
*/
|
||||
@@ -409,13 +368,6 @@ void bm_get_filename(int bitmapnum, char *filename);
|
||||
*/
|
||||
const char *bm_get_filename(int handle);
|
||||
|
||||
/**
|
||||
* @brief Loads all data for all bitmaps that have been requested to be loaded
|
||||
*
|
||||
* @note This function is not defined.
|
||||
*/
|
||||
void bm_gfx_load_all();
|
||||
|
||||
/**
|
||||
* @brief Unloads all used bitmaps, should only ever be called by game_shutdown()
|
||||
*
|
||||
@@ -434,15 +386,6 @@ void bm_unload_all();
|
||||
*/
|
||||
void bm_get_palette(int handle, ubyte *pal, char *name);
|
||||
|
||||
/**
|
||||
* @brief Hack to get a pixel from a bitmap
|
||||
*
|
||||
* @details only works good in 8bpp mode
|
||||
*
|
||||
* @note This function is not defined.
|
||||
*/
|
||||
void bm_gfx_get_pixel(int bitmap, float u, float v, ubyte *r, ubyte *g, ubyte *b);
|
||||
|
||||
/**
|
||||
* @brief (DEBUG) Gets memory size, in bytes, of the locked bitmaps
|
||||
*
|
||||
@@ -501,15 +444,6 @@ void bm_page_in_xparent_texture(int bitmapnum, int num_frames = 1);
|
||||
*/
|
||||
void bm_page_in_aabitmap(int bitmapnum, int num_frames = 1);
|
||||
|
||||
/**
|
||||
* @brief Unloads the bitmap indexed by handle that was previously paged-in
|
||||
*
|
||||
* @returns 0 If the bitmap had already been released, or
|
||||
* @returns 0 If the handle is invalid, or
|
||||
* @returns 1 If successful
|
||||
*/
|
||||
bool bm_page_out(int handle);
|
||||
|
||||
/**
|
||||
* @brief Sets BMPMAN's memory mode
|
||||
*
|
||||
@@ -558,16 +492,6 @@ void BM_SELECT_ALPHA_TEX_FORMAT();
|
||||
*/
|
||||
extern void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Functional pointer that references any of the bm_set_components_32 functions.
|
||||
*
|
||||
* @details The bm_set_components functions packs the RGBA values into the ubyte array referenced by pixel, whose
|
||||
* format differs according to its bpp value and presence of an alpha channel. The RGBA values are scaled accordingly.
|
||||
*
|
||||
* @see bm_set_components
|
||||
*/
|
||||
extern void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Sets the 16bpp screen pixel to the specified RGBA value
|
||||
*
|
||||
@@ -575,13 +499,6 @@ extern void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, u
|
||||
*/
|
||||
void bm_set_components_argb_16_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Sets the 32bpp screen pixel to the specified RGBA value
|
||||
*
|
||||
* @see bm_set_components
|
||||
*/
|
||||
void bm_set_components_argb_32_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
/**
|
||||
* @brief Sets the 16bpp texture pixel to the specified RGBA value
|
||||
*
|
||||
@@ -603,15 +520,7 @@ void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, u
|
||||
*/
|
||||
void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
|
||||
|
||||
extern int UNLITMAP; //this holds a reference to a map that is optional used instead of the base map for unlit rendering
|
||||
extern int GLOWMAP; //this holds a reference to a map that is a fully lit version of its index -Bobboau
|
||||
extern int SPECMAP; //this holds a reference to a map that is for specular mapping -Bobboau
|
||||
extern int SPECGLOSSMAP; //this holds a reference to a map that is for specular mapping -Bobboau
|
||||
extern int ENVMAP; //this holds a reference to a map that is for environment mapping -Bobboau
|
||||
extern int NORMMAP; // normal mapping
|
||||
extern int HEIGHTMAP; // height map for normal mapping
|
||||
extern int AMBIENTMAP; // ambient occluion map. red channel affects ambient lighting, green channel affects diffuse and specular
|
||||
extern int MISCMAP; // Utility map, to be utilized for various things shader authors can come up with
|
||||
|
||||
/**
|
||||
* @brief Returns the compression type of the bitmap indexed by handle
|
||||
@@ -623,10 +532,6 @@ int bm_is_compressed(int handle);
|
||||
*/
|
||||
int bm_get_tcache_type(int handle);
|
||||
|
||||
/**
|
||||
* @brief Gets the size, in bytes, taken up by the bitmap indexed by handle
|
||||
*/
|
||||
size_t bm_get_size(int handle);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of mipmaps of the indexed texture
|
||||
@@ -698,4 +603,73 @@ 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();
|
||||
|
||||
/**
|
||||
* @brief Counts how many slots are available to the bmpman system
|
||||
*
|
||||
* Since the number of slots is dynamic now, this should be used for determining the total amount of available slots at
|
||||
* the moment.
|
||||
*
|
||||
* @warning This is entirely for debugging and logging purposes. It should not be used in actual engine code.
|
||||
*
|
||||
* @return The number of available slots
|
||||
*/
|
||||
int bmpman_count_available_slots();
|
||||
|
||||
/**
|
||||
* @brief Checks if the given filename is a valid effect or texture file name
|
||||
*
|
||||
* @note At least one of @c single_frame or @c animation must be true since the result would make no sense otherwise. It
|
||||
* is also valid to set both parmeters to @c true.
|
||||
*
|
||||
* @todo This currently just tries to load the file but could be improved by not actually loading the file in the future.
|
||||
*
|
||||
* @param file The file name to check
|
||||
* @param single_frame If set to @c true then single frames are valid files
|
||||
* @param animation If set to @c true then animations are valid files
|
||||
* @return @c true if the file name is valid, @c false otherwise
|
||||
*/
|
||||
bool bm_validate_filename(const SCP_string& file, bool single_frame, bool animation);
|
||||
|
||||
SDL_Surface* bm_to_sdl_surface(int handle);
|
||||
|
||||
#endif
|
||||
+6
-18
@@ -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"
|
||||
@@ -145,7 +145,7 @@ void camera::set_object_target(object *objp, int n_object_target_submodel)
|
||||
* Custom function receives the already-modified current position value.
|
||||
* It should be replaced or added to as the custom function modifier sees fit.
|
||||
*/
|
||||
void camera::set_custom_position_function(void (*n_func_custom_position)(camera *cam, vec3d *camera_pos))
|
||||
void camera::set_custom_position_function(void (*n_func_custom_position)(camera* /*cam*/, vec3d* /*camera_pos*/))
|
||||
{
|
||||
func_custom_position = n_func_custom_position;
|
||||
}
|
||||
@@ -154,7 +154,7 @@ void camera::set_custom_position_function(void (*n_func_custom_position)(camera
|
||||
* Custom function receives the already-modified current orientation value.
|
||||
* It should be replaced or added to as the custom function modifier sees fit.
|
||||
*/
|
||||
void camera::set_custom_orientation_function(void (*n_func_custom_orientation)(camera *cam, matrix *camera_ori))
|
||||
void camera::set_custom_orientation_function(void (*n_func_custom_orientation)(camera* /*cam*/, matrix* /*camera_ori*/))
|
||||
{
|
||||
func_custom_orientation = n_func_custom_orientation;
|
||||
}
|
||||
@@ -185,13 +185,6 @@ void camera::set_position(vec3d *in_position, float in_translation_time, float i
|
||||
pos_z.setAVD(in_position->xyz.z, in_translation_time, in_translation_acceleration_time, in_translation_deceleration_time, in_end_velocity);
|
||||
}
|
||||
|
||||
void camera::set_translation_velocity(vec3d *in_velocity, float in_acceleration_time)
|
||||
{
|
||||
pos_x.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.x);
|
||||
pos_y.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.y);
|
||||
pos_z.setVD(in_acceleration_time, in_acceleration_time, in_velocity->xyz.z);
|
||||
}
|
||||
|
||||
void camera::set_rotation(matrix *in_orientation, float in_rotation_time, float in_rotation_acceleration_time, float in_rotation_deceleration_time)
|
||||
{
|
||||
if(in_orientation != NULL && in_rotation_time == 0.0f && in_rotation_acceleration_time == 0.0f && in_rotation_deceleration_time == 0.0f)
|
||||
@@ -245,12 +238,7 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
|
||||
set_rotation(&temp_matrix, in_rotation_time, in_rotation_acceleration_time, in_rotation_deceleration_time);
|
||||
}
|
||||
|
||||
void camera::set_rotation_velocity(angles *in_rotation_rate, float in_acceleration_time)
|
||||
{
|
||||
Error(LOCATION, "This function is disabled until further notice.");
|
||||
}
|
||||
|
||||
void camera::do_frame(float in_frametime)
|
||||
void camera::do_frame(float /*in_frametime*/)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -802,7 +790,7 @@ void subtitle::clone(const subtitle &sub)
|
||||
post_shaded = sub.post_shaded;
|
||||
}
|
||||
|
||||
const subtitle &subtitle::operator=(const subtitle &sub)
|
||||
subtitle& subtitle::operator=(const subtitle &sub)
|
||||
{
|
||||
if (this != &sub) {
|
||||
if (image_id != -1) {
|
||||
@@ -962,7 +950,7 @@ size_t cam_get_num()
|
||||
/**
|
||||
* Looks up camera by name, returns -1 on failure
|
||||
*/
|
||||
camid cam_lookup(char *name)
|
||||
camid cam_lookup(const char* name)
|
||||
{
|
||||
size_t i, size=Cameras.size();
|
||||
for(i = 0; i < size; i++)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
class camera
|
||||
{
|
||||
friend class avd_camera;
|
||||
protected:
|
||||
char name[NAME_LENGTH];
|
||||
int sig;
|
||||
@@ -60,15 +59,13 @@ public:
|
||||
void set_fov(float in_fov, float in_fov_time = 0.0f, float in_fov_acceleration_time = 0.0f, float in_deceleration_time = 0.0f);
|
||||
|
||||
void set_position(vec3d *in_position = NULL, float in_translation_time = 0.0f, float in_translation_acceleration_time = 0.0f, float in_translation_deceleration_time = 0.0f, float in_end_velocity = 0.0f);
|
||||
void set_translation_velocity(vec3d *in_velocity, float in_acceleration_time = 0.0f);
|
||||
|
||||
void set_rotation(matrix *in_orientation = NULL, float in_rotation_time = 0.0f, float in_rotation_acceleration_time = 0.0f, float in_rotation_deceleration_time = 0.0f);
|
||||
void set_rotation(angles *in_angles, float in_rotation_time = 0.0f, float in_rotation_acceleration_time = 0.0f, float in_rotation_deceleration_time = 0.0f);
|
||||
void set_rotation_facing(vec3d *in_target, float in_rotation_time = 0.0f, float in_rotation_acceleration_time = 0.0f, float in_rotation_deceleration_time = 0.0f);
|
||||
void set_rotation_velocity(angles *in_rotation_rate, float in_acceleration_time = 0.0f);
|
||||
|
||||
//Get
|
||||
char *get_name() {return name;}
|
||||
const char* get_name() { return name; }
|
||||
int get_signature() {return sig;}
|
||||
object *get_object_host();
|
||||
int get_object_host_submodel();
|
||||
@@ -143,7 +140,7 @@ public:
|
||||
~subtitle();
|
||||
|
||||
subtitle(const subtitle &sub) { clone(sub); }
|
||||
const subtitle &operator=(const subtitle &sub);
|
||||
subtitle& operator=(const subtitle &sub);
|
||||
|
||||
void do_frame(float frametime);
|
||||
bool is_post_shaded( ) { return post_shaded; }
|
||||
@@ -163,7 +160,7 @@ camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_obje
|
||||
void cam_delete(camid cid);
|
||||
bool cam_set_camera(camid cid);
|
||||
void cam_reset_camera();
|
||||
camid cam_lookup(char *name);
|
||||
camid cam_lookup(const char* name);
|
||||
camid cam_get_camera(uint index);
|
||||
camid cam_get_current();
|
||||
size_t cam_get_num();
|
||||
|
||||
+153
-144
@@ -10,10 +10,10 @@
|
||||
|
||||
#define _CFILE_INTERNAL
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -33,21 +33,21 @@
|
||||
#include "cfile/cfilesystem.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "parse/encrypt.h"
|
||||
#include "cfilesystem.h"
|
||||
|
||||
|
||||
#include <limits>
|
||||
|
||||
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
|
||||
char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
|
||||
#ifdef SCP_UNIX
|
||||
char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN] = "";
|
||||
#endif
|
||||
|
||||
// During cfile_init, verify that Pathtypes[n].index == n for each item
|
||||
// Each path must have a valid parent that can be tracable all the way back to the root
|
||||
// Each path must have a valid parent that can be tracable all the way back to the root
|
||||
// so that we can create directories when we need to.
|
||||
//
|
||||
// Please make sure extensions are all lower-case, or we'll break unix compatibility
|
||||
//
|
||||
// clang-format off
|
||||
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
// What type this is Path Extensions Parent type
|
||||
{ CF_TYPE_INVALID, NULL, NULL, CF_TYPE_INVALID },
|
||||
@@ -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 .mp4", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",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 },
|
||||
@@ -77,8 +77,8 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", CF_TYPE_DATA },
|
||||
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS },
|
||||
{ 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 },
|
||||
@@ -88,8 +88,11 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
{ 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 },
|
||||
{ CF_TYPE_INTERFACE_MARKUP, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "markup", ".rml", CF_TYPE_INTERFACE },
|
||||
{ CF_TYPE_INTERFACE_CSS, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "css", ".rcss", CF_TYPE_INTERFACE },
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
#define CFILE_STACK_MAX 8
|
||||
|
||||
@@ -109,6 +112,7 @@ static const char *Cfile_cdrom_dir = NULL;
|
||||
static int cfget_cfile_block();
|
||||
static CFILE *cf_open_fill_cfblock(const char* source, int line, FILE * fp, int type);
|
||||
static CFILE *cf_open_packed_cfblock(const char* source, int line, FILE *fp, int type, size_t offset, size_t size);
|
||||
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const void* data, size_t size, int dir_type);
|
||||
|
||||
#if defined _WIN32
|
||||
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, HANDLE hFile, int type);
|
||||
@@ -222,14 +226,8 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
|
||||
cfile_chdir(buf);
|
||||
|
||||
// set root directory
|
||||
strncpy(Cfile_root_dir, buf, CFILE_ROOT_DIRECTORY_LEN-1);
|
||||
strncpy(Cfile_user_dir, os_get_config_path().c_str(), CFILE_ROOT_DIRECTORY_LEN-1);
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
// Initialize path of old pilot files
|
||||
extern const char* Osreg_user_dir_legacy;
|
||||
snprintf(Cfile_user_dir_legacy, CFILE_ROOT_DIRECTORY_LEN-1, "%s/%s/", getenv("HOME"), Osreg_user_dir_legacy);
|
||||
#endif
|
||||
strcpy_s(Cfile_root_dir, buf);
|
||||
strcpy_s(Cfile_user_dir, os_get_config_path().c_str());
|
||||
|
||||
for (i = 0; i < MAX_CFILE_BLOCKS; i++) {
|
||||
Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
|
||||
@@ -244,16 +242,6 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this if pack files got added or removed or the
|
||||
// cdrom changed. This will refresh the list of filenames
|
||||
// stored in packfiles and on the cdrom.
|
||||
void cfile_refresh()
|
||||
{
|
||||
cf_build_secondary_filelist(Cfile_cdrom_dir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
// Changes to a drive if valid.. 1=A, 2=B, etc
|
||||
// If flag, then changes to it.
|
||||
@@ -354,8 +342,7 @@ int cfile_push_chdir(int type)
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(Cfile_stack[Cfile_stack_pos++], OriginalDirectory,
|
||||
CFILE_ROOT_DIRECTORY_LEN - 1);
|
||||
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
|
||||
|
||||
cf_create_default_path_string(dir, sizeof(dir) - 1, type, NULL);
|
||||
|
||||
@@ -465,7 +452,7 @@ char *cf_add_ext(const char *filename, const char *ext)
|
||||
size_t elen = strlen(ext);
|
||||
Assert(flen < MAX_PATH_LEN);
|
||||
strcpy_s(path, filename);
|
||||
if ((flen < 4) || stricmp(path + flen - elen, ext)) {
|
||||
if ((flen < 4) || stricmp(path + flen - elen, ext) != 0) {
|
||||
Assert(flen + elen < MAX_PATH_LEN);
|
||||
strcat_s(path, ext);
|
||||
}
|
||||
@@ -478,17 +465,17 @@ char *cf_add_ext(const char *filename, const char *ext)
|
||||
*
|
||||
* @param filename Name of file to delete
|
||||
* @param path_type Path type (CF_TYPE_xxx)
|
||||
* @param location_flags Where to search for the location of the file to delete
|
||||
*
|
||||
* @return 0 on failure, 1 on success
|
||||
*/
|
||||
int cf_delete(const char *filename, int path_type)
|
||||
int cf_delete(const char *filename, int path_type, uint32_t location_flags)
|
||||
{
|
||||
char longname[MAX_PATH_LEN];
|
||||
|
||||
Assert(CF_TYPE_SPECIFIED(path_type));
|
||||
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1,
|
||||
path_type, filename);
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, path_type, filename, false, location_flags);
|
||||
|
||||
return (_unlink(longname) != -1);
|
||||
}
|
||||
@@ -514,12 +501,12 @@ int cf_access(const char *filename, int dir_type, int mode)
|
||||
// If offset equates to boolean true, it was found in a VP and the logic will negate the function return
|
||||
int cf_exists(const char *filename, int dir_type)
|
||||
{
|
||||
size_t offset = 1;
|
||||
|
||||
if ( (filename == NULL) || !strlen(filename) )
|
||||
return 0;
|
||||
|
||||
return (cf_find_file_location(filename, dir_type, 0, NULL, NULL, &offset) && !offset);
|
||||
auto find_res = cf_find_file_location(filename, dir_type);
|
||||
|
||||
return find_res.found && !find_res.offset;
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
@@ -530,7 +517,7 @@ int cf_exists_full(const char *filename, int dir_type)
|
||||
if ( (filename == NULL) || !strlen(filename) )
|
||||
return 0;
|
||||
|
||||
return cf_find_file_location(filename, dir_type, 0, NULL, NULL, NULL);
|
||||
return cf_find_file_location(filename, dir_type).found;
|
||||
}
|
||||
|
||||
// same as the above, but with extension check
|
||||
@@ -542,7 +529,7 @@ int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, co
|
||||
if ( (num_ext <= 0) || (ext_list == NULL) )
|
||||
return 0;
|
||||
|
||||
return (cf_find_file_location_ext(filename, num_ext, ext_list, dir_type, 0, NULL, NULL, NULL) != -1);
|
||||
return cf_find_file_location_ext(filename, num_ext, ext_list, dir_type).found;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -559,7 +546,7 @@ void cf_attrib(const char *filename, int set, int clear, int dir_type)
|
||||
fclose(fp);
|
||||
|
||||
DWORD z = GetFileAttributes(longname);
|
||||
SetFileAttributes(longname, z | set & ~clear);
|
||||
SetFileAttributes(longname, z | (set & ~clear));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -616,7 +603,7 @@ static void mkdir_recursive(const char *path) {
|
||||
|
||||
// Creates the directory path if it doesn't exist. Even creates all its
|
||||
// parent paths.
|
||||
void cf_create_directory( int dir_type )
|
||||
void cf_create_directory(int dir_type, uint32_t location_flags)
|
||||
{
|
||||
int num_dirs = 0;
|
||||
int dir_tree[CF_MAX_PATH_TYPES];
|
||||
@@ -638,7 +625,7 @@ void cf_create_directory( int dir_type )
|
||||
int i;
|
||||
|
||||
for (i=num_dirs-1; i>=0; i-- ) {
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, dir_tree[i], NULL );
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_tree[i], nullptr, false, location_flags);
|
||||
if (stat(longname, &statbuf) != 0) {
|
||||
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
|
||||
mkdir_recursive(longname);
|
||||
@@ -646,9 +633,6 @@ void cf_create_directory( int dir_type )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern int game_cd_changed();
|
||||
|
||||
// cfopen()
|
||||
//
|
||||
// parameters: *filepath ==> name of file to open (may be path+name)
|
||||
@@ -665,14 +649,13 @@ extern int game_cd_changed();
|
||||
// error ==> NULL
|
||||
//
|
||||
|
||||
CFILE *_cfopen(const char* source, int line, const char *file_path, const char *mode, int type, int dir_type, bool localize)
|
||||
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
|
||||
bool localize, uint32_t location_flags)
|
||||
{
|
||||
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
|
||||
if( strlen(file_path) > 31 )
|
||||
Error(LOCATION, "file name %s too long, \nmust be less than 31 charicters", file_path);*/
|
||||
|
||||
char longname[_MAX_PATH];
|
||||
|
||||
if ( !cfile_inited ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
@@ -684,7 +667,7 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
Assert( mode != NULL );
|
||||
|
||||
// Can only open read-only binary files in memory mapped mode.
|
||||
if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") ) {
|
||||
if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") != 0 ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
}
|
||||
@@ -694,6 +677,8 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
// the harddisk. No fancy packfile stuff here!
|
||||
|
||||
if ( strchr(mode,'w') || strchr(mode,'+') || strchr(mode,'a') ) {
|
||||
char longname[_MAX_PATH];
|
||||
|
||||
// For write-only files, require a full path or a path type
|
||||
#ifdef SCP_UNIX
|
||||
if ( strpbrk(file_path, "/") ) {
|
||||
@@ -707,9 +692,9 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
Assert( dir_type != CF_TYPE_ANY );
|
||||
|
||||
// Create the directory if necessary
|
||||
cf_create_directory( dir_type );
|
||||
cf_create_directory(dir_type, location_flags);
|
||||
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, file_path );
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_type, file_path, false, location_flags);
|
||||
}
|
||||
Assert( !(type & CFILE_MEMORY_MAPPED) );
|
||||
|
||||
@@ -759,30 +744,29 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
//================================================
|
||||
// Search for file on disk, on cdrom, or in a packfile
|
||||
|
||||
size_t offset, size;
|
||||
char copy_file_path[MAX_PATH_LEN]; // FIX change in memory from cf_find_file_location
|
||||
strcpy_s(copy_file_path, file_path);
|
||||
|
||||
|
||||
if ( cf_find_file_location( copy_file_path, dir_type, sizeof(longname) - 1, longname, &size, &offset, localize ) ) {
|
||||
auto find_res = cf_find_file_location( copy_file_path, dir_type, localize, location_flags );
|
||||
if ( find_res.found ) {
|
||||
|
||||
// Fount it, now create a cfile out of it
|
||||
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, longname));
|
||||
|
||||
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, find_res.full_name.c_str()));
|
||||
|
||||
if ( type & CFILE_MEMORY_MAPPED ) {
|
||||
|
||||
// Can't open memory mapped files out of pack files
|
||||
if ( offset == 0 ) {
|
||||
// Can't open memory mapped files out of pack or memory files
|
||||
if ( find_res.offset == 0 && find_res.data_ptr != nullptr ) {
|
||||
#if defined _WIN32
|
||||
HANDLE hFile;
|
||||
|
||||
hFile = CreateFile(longname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
hFile = CreateFile(find_res.full_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, hFile, dir_type);
|
||||
}
|
||||
#elif defined SCP_UNIX
|
||||
FILE *fp = fopen( longname, "rb" );
|
||||
FILE* fp = fopen(find_res.full_name.c_str(), "rb");
|
||||
if (fp) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, fp, dir_type);
|
||||
}
|
||||
@@ -790,18 +774,9 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
FILE *fp = fopen( longname, "rb" );
|
||||
|
||||
if ( fp ) {
|
||||
if ( offset ) {
|
||||
// Found it in a pack file
|
||||
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size );
|
||||
} else {
|
||||
// Found it in a normal file
|
||||
return cf_open_fill_cfblock(source, line, fp, dir_type);
|
||||
}
|
||||
}
|
||||
// since cfopen_special already has all the code to handle the opening we can just use that here
|
||||
return _cfopen_special(source, line, find_res.full_name.c_str(), mode, find_res.size, find_res.offset,
|
||||
find_res.data_ptr, dir_type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -820,7 +795,7 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
// returns: success ==> address of CFILE structure
|
||||
// error ==> NULL
|
||||
//
|
||||
CFILE *_cfopen_special(const char* source, int line, const char *file_path, const char *mode, const size_t size, const size_t offset, int dir_type)
|
||||
CFILE *_cfopen_special(const char* source, int line, const char *file_path, const char *mode, const size_t size, const size_t offset, const void* data, int dir_type)
|
||||
{
|
||||
if ( !cfile_inited) {
|
||||
Int3();
|
||||
@@ -836,19 +811,27 @@ CFILE *_cfopen_special(const char* source, int line, const char *file_path, cons
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// "file_path" should already be a fully qualified path, so just try to open it
|
||||
FILE *fp = fopen( file_path, "rb" );
|
||||
|
||||
if ( !fp )
|
||||
return NULL;
|
||||
|
||||
if ( offset ) {
|
||||
// it's in a pack file
|
||||
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size);
|
||||
} else {
|
||||
// it's a normal file
|
||||
return cf_open_fill_cfblock(source, line, fp, dir_type);
|
||||
// In-Memory files are a bit different from normal files so we need to handle them separately
|
||||
if (data != nullptr) {
|
||||
return cf_open_memory_fill_cfblock(source, line, data, size, dir_type);
|
||||
}
|
||||
else {
|
||||
// "file_path" should already be a fully qualified path, so just try to open it
|
||||
FILE *fp = fopen(file_path, "rb");
|
||||
|
||||
if (fp) {
|
||||
if (offset) {
|
||||
// Found it in a pack file
|
||||
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size);
|
||||
}
|
||||
else {
|
||||
// Found it in a normal file
|
||||
return cf_open_fill_cfblock(source, line, fp, dir_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -901,7 +884,7 @@ static int cfget_cfile_block()
|
||||
mprintf(("Out of cfile blocks! Currently opened files:\n"));
|
||||
dump_opened_files();
|
||||
|
||||
Assertion(false, "There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
|
||||
UNREACHABLE("There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
|
||||
"This is probably caused by a programming or scripting error where a file does not get closed."); // out of free cfile blocks
|
||||
return -1;
|
||||
}
|
||||
@@ -922,7 +905,7 @@ int cfclose( CFILE * cfile )
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
result = 0;
|
||||
if ( cb->data ) {
|
||||
if ( cb->data && cb->mem_mapped ) {
|
||||
// close memory mapped file
|
||||
#if defined _WIN32
|
||||
result = UnmapViewOfFile((void*)cb->data);
|
||||
@@ -936,7 +919,8 @@ int cfclose( CFILE * cfile )
|
||||
// FIXME: result is wrong after munmap() but it is successful
|
||||
//result = munmap(cb->data, cb->data_length);
|
||||
//Assert(result);
|
||||
munmap(cb->data, cb->data_length);
|
||||
// This const_cast is safe since the pointer returned by mmap was also non-const
|
||||
munmap(const_cast<void*>(cb->data), cb->data_length);
|
||||
if ( cb->fp != NULL)
|
||||
result = fclose(cb->fp);
|
||||
#endif
|
||||
@@ -996,6 +980,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, FILE *fp, int t
|
||||
cfp->id = cfile_block_index;
|
||||
cfp->version = 0;
|
||||
cfbp->data = NULL;
|
||||
cfbp->mem_mapped = false;
|
||||
cfbp->fp = fp;
|
||||
cfbp->dir_type = type;
|
||||
cfbp->max_read_len = 0;
|
||||
@@ -1038,6 +1023,7 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, FILE *fp, int
|
||||
cfp->version = 0;
|
||||
cfbp->data = NULL;
|
||||
cfbp->fp = fp;
|
||||
cfbp->mem_mapped = false;
|
||||
cfbp->dir_type = type;
|
||||
cfbp->max_read_len = 0;
|
||||
|
||||
@@ -1083,6 +1069,7 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, FILE *fp
|
||||
cfp->version = 0;
|
||||
cfbp->max_read_len = 0;
|
||||
cfbp->fp = NULL;
|
||||
cfbp->mem_mapped = true;
|
||||
#if defined _WIN32
|
||||
cfbp->hInFile = hFile;
|
||||
#endif
|
||||
@@ -1117,6 +1104,37 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, FILE *fp
|
||||
}
|
||||
}
|
||||
|
||||
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const void* data, size_t size, int dir_type)
|
||||
{
|
||||
int cfile_block_index;
|
||||
|
||||
cfile_block_index = cfget_cfile_block();
|
||||
if ( cfile_block_index == -1 ) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
CFILE *cfp;
|
||||
Cfile_block *cfbp;
|
||||
cfbp = &Cfile_block_list[cfile_block_index];
|
||||
|
||||
cfp = &Cfile_list[cfile_block_index];
|
||||
cfp->id = cfile_block_index;
|
||||
cfp->version = 0;
|
||||
cfbp->max_read_len = 0;
|
||||
cfbp->fp = NULL;
|
||||
cfbp->mem_mapped = false;
|
||||
cfbp->dir_type = dir_type;
|
||||
|
||||
cfbp->source_file = source;
|
||||
cfbp->line_num = line;
|
||||
|
||||
cf_init_lowlevel_read_code(cfp, 0, size, 0 );
|
||||
cfbp->data = data;
|
||||
|
||||
return cfp;
|
||||
}
|
||||
}
|
||||
|
||||
int cf_get_dir_type(CFILE *cfile)
|
||||
{
|
||||
return Cfile_block_list[cfile->id].dir_type;
|
||||
@@ -1127,7 +1145,7 @@ int cf_get_dir_type(CFILE *cfile)
|
||||
//
|
||||
//
|
||||
|
||||
void *cf_returndata(CFILE *cfile)
|
||||
const void *cf_returndata(CFILE *cfile)
|
||||
{
|
||||
Assert(cfile != NULL);
|
||||
Cfile_block *cb;
|
||||
@@ -1137,17 +1155,6 @@ void *cf_returndata(CFILE *cfile)
|
||||
return cb->data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// version number of opened file. Will be 0 unless you put something else here after you
|
||||
// open a file. Once set, you can use minimum version numbers with the read functions.
|
||||
void cf_set_version( CFILE * cfile, int version )
|
||||
{
|
||||
Assert(cfile != NULL);
|
||||
|
||||
cfile->version = version;
|
||||
}
|
||||
|
||||
// cutoff point where cfread() will throw an error when it hits this limit
|
||||
// if 'len' is 0 then this check will be disabled
|
||||
void cf_set_max_read_len( CFILE * cfile, size_t len )
|
||||
@@ -1265,22 +1272,6 @@ void cfread_vector(vec3d *vec, CFILE *file, int ver, vec3d *deflt)
|
||||
vec->xyz.y = cfread_float(file, ver, deflt ? deflt->xyz.y : 0.0f);
|
||||
vec->xyz.z = cfread_float(file, ver, deflt ? deflt->xyz.z : 0.0f);
|
||||
}
|
||||
|
||||
void cfread_angles(angles *ang, CFILE *file, int ver, angles *deflt)
|
||||
{
|
||||
if (file->version < ver) {
|
||||
if (deflt)
|
||||
*ang = *deflt;
|
||||
else
|
||||
ang->p = ang->b = ang->h = 0.0f;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ang->p = cfread_float(file, ver, deflt ? deflt->p : 0.0f);
|
||||
ang->b = cfread_float(file, ver, deflt ? deflt->b : 0.0f);
|
||||
ang->h = cfread_float(file, ver, deflt ? deflt->h : 0.0f);
|
||||
}
|
||||
|
||||
char cfread_char(CFILE *file, int ver, char deflt)
|
||||
{
|
||||
@@ -1319,6 +1310,19 @@ void cfread_string_len(char *buf,int n, CFILE *file)
|
||||
buf[len] = 0;
|
||||
}
|
||||
|
||||
SCP_string cfread_string_len(CFILE *file)
|
||||
{
|
||||
int len = cfread_int(file);
|
||||
|
||||
SCP_string str;
|
||||
str.resize(len);
|
||||
|
||||
if (len)
|
||||
cfread(&str[0], len, 1, file);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// equivalent write functions of above read functions follow
|
||||
|
||||
int cfwrite_float(float f, CFILE *file)
|
||||
@@ -1356,28 +1360,6 @@ int cfwrite_ubyte(ubyte b, CFILE *file)
|
||||
return cfwrite(&b, sizeof(b), 1, file);
|
||||
}
|
||||
|
||||
int cfwrite_vector(vec3d *vec, CFILE *file)
|
||||
{
|
||||
if(!cfwrite_float(vec->xyz.x, file)){
|
||||
return 0;
|
||||
}
|
||||
if(!cfwrite_float(vec->xyz.y, file)){
|
||||
return 0;
|
||||
}
|
||||
return cfwrite_float(vec->xyz.z, file);
|
||||
}
|
||||
|
||||
int cfwrite_angles(angles *ang, CFILE *file)
|
||||
{
|
||||
if(!cfwrite_float(ang->p, file)){
|
||||
return 0;
|
||||
}
|
||||
if(!cfwrite_float(ang->b, file)){
|
||||
return 0;
|
||||
}
|
||||
return cfwrite_float(ang->h, file);
|
||||
}
|
||||
|
||||
int cfwrite_char(char b, CFILE *file)
|
||||
{
|
||||
return cfwrite( &b, sizeof(b), 1, file);
|
||||
@@ -1418,9 +1400,7 @@ int cfilelength( CFILE * cfile )
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
// TODO: return length of memory mapped file
|
||||
Assert( !cb->data );
|
||||
|
||||
Assert(cb->fp != NULL);
|
||||
Assert( !cb->mem_mapped );
|
||||
|
||||
// cb->size gets set at cfopen
|
||||
|
||||
@@ -1519,7 +1499,6 @@ int cfputc(int c, CFILE *cfile)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// cfputs() writes a string to a file
|
||||
//
|
||||
// returns: success ==> non-negative value
|
||||
@@ -1935,3 +1914,33 @@ int cflush(CFILE *cfile)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int cfile_get_path_type(const SCP_string& dir)
|
||||
{
|
||||
SCP_string buf = dir;
|
||||
|
||||
// Remove trailing slashes; avoid buffer overflow on 1-char strings
|
||||
while (buf.size() > 0 && (buf[buf.size() - 1] == '\\' || buf[buf.size() - 1] == '/')) {
|
||||
buf.resize(buf.size() - 1);
|
||||
}
|
||||
|
||||
// Remove leading slashes
|
||||
while (buf.size() > 0 && (buf[0] == '\\' || buf[0] == '/')) {
|
||||
buf = buf.substr(1);
|
||||
}
|
||||
|
||||
// Use official DIR_SEPARATOR_CHAR
|
||||
for (char& c : buf) {
|
||||
if (c == '\\' || c == '/') {
|
||||
c = DIR_SEPARATOR_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& Pathtype : Pathtypes) {
|
||||
if (Pathtype.path != nullptr && buf == Pathtype.path) {
|
||||
return Pathtype.index;
|
||||
}
|
||||
}
|
||||
|
||||
return CF_TYPE_INVALID;
|
||||
}
|
||||
+112
-45
@@ -13,7 +13,7 @@
|
||||
#define __CFILE_H__
|
||||
|
||||
|
||||
#include <time.h>
|
||||
#include <ctime>
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -78,9 +78,12 @@ 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_TYPE_INTERFACE_MARKUP 38
|
||||
#define CF_TYPE_INTERFACE_CSS 39
|
||||
|
||||
#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 \
|
||||
40 // 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
|
||||
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
|
||||
@@ -94,8 +97,63 @@ typedef struct {
|
||||
#define CF_SORT_TIME 2
|
||||
#define CF_SORT_REVERSE 3
|
||||
|
||||
#define cfread_fix(file) (fix)cfread_int(file)
|
||||
#define cfwrite_fix(i,file) cfwrite_int(i,file)
|
||||
/**
|
||||
* @brief Contains a collection of flags for specifying from where a CFILE should be opened
|
||||
*
|
||||
* There are two types of flags. CF_LOCATION_GAME_ROOT and CF_LOCATION_USER_ROOT specify in which basic root directory
|
||||
* CFile should search for files.
|
||||
*
|
||||
* The remaining flags control what type of location may be used for the operation. It's possible to restrict the
|
||||
* location to the primary mod, the remaining mods or the top-level root directory.
|
||||
*/
|
||||
enum CFileLocationFlags {
|
||||
CF_LOCATION_ROOT_GAME = 1 << 0, //!< The game root location. This is the location of the game data (e.g. FS2 retail)
|
||||
/**
|
||||
* @brief The user directories.
|
||||
*
|
||||
* If the engine is in portable mode then using this flag exclusively will result in a failure to open files!
|
||||
*/
|
||||
CF_LOCATION_ROOT_USER = 1 << 1,
|
||||
|
||||
/**
|
||||
* @brief The memory root
|
||||
*
|
||||
* This contains all the built-in files available to the engine.
|
||||
*/
|
||||
CF_LOCATION_ROOT_MEMORY = 1 << 2,
|
||||
|
||||
/**
|
||||
* @brief Mask for extracting root type from a location bit field
|
||||
*/
|
||||
CF_LOCATION_ROOT_MASK = 0xFFFF,
|
||||
|
||||
CF_LOCATION_TYPE_ROOT = 1 << 16, //!< The basic, top-level root location
|
||||
/**
|
||||
* @brief The primary mod location.
|
||||
*
|
||||
* This is the mod that appears first on the command line. If there are no mods then the root location is considered
|
||||
* to be the primary mod
|
||||
*/
|
||||
CF_LOCATION_TYPE_PRIMARY_MOD = 1 << 17,
|
||||
/**
|
||||
* @brief The remaining mods.
|
||||
*
|
||||
* If there are no mods on the command line then this might not include any valid location.
|
||||
*/
|
||||
CF_LOCATION_TYPE_SECONDARY_MODS = 1 << 18,
|
||||
|
||||
/**
|
||||
* @brief Bitmask for extracting the type from a location bit field
|
||||
*/
|
||||
CF_LOCATION_TYPE_MASK = 0xFFFF0000,
|
||||
|
||||
/**
|
||||
* @brief A combination of all flags
|
||||
*
|
||||
* This should be used when the default behavior without any location filtering is desired.
|
||||
*/
|
||||
CF_LOCATION_ALL = CF_LOCATION_ROOT_MASK | CF_LOCATION_TYPE_MASK
|
||||
};
|
||||
|
||||
// callback function used for get_file_list() to filter files to be added to list. Return 1
|
||||
// to add file to list, or 0 to not add it.
|
||||
@@ -110,52 +168,39 @@ extern const char *Get_file_list_child;
|
||||
#define CFILE_ROOT_DIRECTORY_LEN 256
|
||||
extern char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN];
|
||||
extern char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN];
|
||||
#ifdef SCP_UNIX
|
||||
extern char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN];
|
||||
#endif
|
||||
|
||||
//================= 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
|
||||
// stored in packfiles and on the cdrom.
|
||||
void cfile_refresh();
|
||||
|
||||
// add an extension to a filename if it doesn't already have it
|
||||
char *cf_add_ext(const char *filename, const char *ext);
|
||||
|
||||
// return CF_TYPE (directory location type) of a CFILE you called cfopen() successfully on.
|
||||
int cf_get_dir_type(CFILE *cfile);
|
||||
|
||||
|
||||
// Opens the file. If no path is given, use the extension to look into the
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE *_cfopen(const char* source_file, int line, const char *filename, const char *mode,
|
||||
int type = CFILE_NORMAL, int dir_type = CF_TYPE_ANY, bool localize = false);
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
|
||||
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
|
||||
|
||||
// like cfopen(), but it accepts a fully qualified path only (ie, the result of a cf_find_file_location() call)
|
||||
// NOTE: only supports reading files!!
|
||||
CFILE *_cfopen_special(const char* source_file, int line, const char *file_path, const char *mode,
|
||||
const size_t size, const size_t offset, int dir_type = CF_TYPE_ANY);
|
||||
const size_t size, const size_t offset, const void* data, int dir_type = CF_TYPE_ANY);
|
||||
#define cfopen_special(...) _cfopen_special(LOCATION, __VA_ARGS__) // Pass source location to the function
|
||||
|
||||
// Flush the open file buffer
|
||||
int cflush(CFILE *cfile);
|
||||
|
||||
// version number of opened file. Will be 0 unless you put something else here after you
|
||||
// open a file. Once set, you can use minimum version numbers with the read functions.
|
||||
void cf_set_version( CFILE * cfile, int version );
|
||||
|
||||
// will throw an error if cfread*() functions read past this mark
|
||||
// converted to raw offsets when used, but gets passed actual length from current position
|
||||
// setting 'len' to zero will disable the check
|
||||
void cf_set_max_read_len(CFILE *cfile, size_t len);
|
||||
|
||||
// Deletes a file. Returns 0 on error, 1 if successful
|
||||
int cf_delete(const char *filename, int dir_type);
|
||||
int cf_delete(const char *filename, int dir_type, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
// Same as _access function to read a file's access bits
|
||||
int cf_access(const char *filename, int dir_type, int mode);
|
||||
@@ -189,10 +234,6 @@ int cfread(void *buf, int elsize, int nelem, CFILE *fp);
|
||||
// cfwrite() writes to the file
|
||||
int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile);
|
||||
|
||||
// Reads/writes RLE compressed data.
|
||||
int cfread_compressed(void *buf, int elsize, int nelem, CFILE *cfile);
|
||||
int cfwrite_compressed(void *param_buf, int param_elsize, int param_nelem, CFILE *cfile);
|
||||
|
||||
// Moves the file pointer
|
||||
int cfseek(CFILE *fp, int offset, int where);
|
||||
|
||||
@@ -215,7 +256,7 @@ char *cfgets(char *buf, int n, CFILE *cfile);
|
||||
int cfeof(CFILE *cfile);
|
||||
|
||||
// Return the data pointer associated with the CFILE structure (for memory mapped files)
|
||||
void *cf_returndata(CFILE *cfile);
|
||||
const void *cf_returndata(CFILE *cfile);
|
||||
|
||||
// get the 2 byte checksum of the passed filename - return 0 if operation failed, 1 if succeeded
|
||||
int cf_chksum_short(const char *filename, ushort *chksum, int max_size = -1, int cf_type = CF_TYPE_ANY );
|
||||
@@ -244,7 +285,6 @@ uint cf_add_chksum_long(uint seed, ubyte *buffer, size_t size);
|
||||
// convenient for misc checksumming purposes ------------------------------------------
|
||||
|
||||
//================= HIGH LEVEL FUNCTIONS ==================
|
||||
int cfexist(const char *filename); // Returns true if file exists on disk (1) or in hog (2).
|
||||
|
||||
// rename a file, utilizing the extension to determine where file is.
|
||||
#define CF_RENAME_SUCCESS 0 // successfully renamed the file
|
||||
@@ -262,7 +302,6 @@ int cfile_flush_dir(int type);
|
||||
// functions for reading from cfile
|
||||
// These are all high level, built up from
|
||||
// cfread.
|
||||
int cfgetc(CFILE *fp);
|
||||
char *cfgets(char *buf, size_t n, CFILE *fp);
|
||||
char cfread_char(CFILE *file, int ver = 0, char deflt = 0);
|
||||
ubyte cfread_ubyte(CFILE *file, int ver = 0, ubyte deflt = 0);
|
||||
@@ -272,7 +311,6 @@ int cfread_int(CFILE *file, int ver = 0, int deflt = 0);
|
||||
uint cfread_uint(CFILE *file, int ver = 0, uint deflt = 0);
|
||||
float cfread_float(CFILE *file, int ver = 0, float deflt = 0.0f);
|
||||
void cfread_vector(vec3d *vec, CFILE *file, int ver = 0, vec3d *deflt = NULL);
|
||||
void cfread_angles(angles *ang, CFILE *file, int ver = 0, angles *deflt = NULL);
|
||||
|
||||
// Reads variable length, null-termined string. Will only read up
|
||||
// to n characters.
|
||||
@@ -288,6 +326,13 @@ void cfread_string(char *buf,int n, CFILE *file);
|
||||
*/
|
||||
void cfread_string_len(char *buf,int n, CFILE *file);
|
||||
|
||||
/**
|
||||
* @brief Read a string from the file where the length is stored in the file
|
||||
* @param file The file to read the string from
|
||||
* @return The string that was read
|
||||
*/
|
||||
SCP_string cfread_string_len(CFILE *file);
|
||||
|
||||
// functions for writing cfiles
|
||||
int cfwrite_char(char c, CFILE *file);
|
||||
int cfwrite_float(float f, CFILE *file);
|
||||
@@ -296,8 +341,6 @@ int cfwrite_uint(uint i, CFILE *file);
|
||||
int cfwrite_short(short s, CFILE *file);
|
||||
int cfwrite_ushort(ushort s, CFILE *file);
|
||||
int cfwrite_ubyte(ubyte u, CFILE *file);
|
||||
int cfwrite_vector(vec3d *vec, CFILE *file);
|
||||
int cfwrite_angles(angles *ang, CFILE *file);
|
||||
|
||||
// writes variable length, null-termined string.
|
||||
int cfwrite_string(const char *buf, CFILE *file);
|
||||
@@ -310,12 +353,26 @@ int cfwrite_string(const char *buf, CFILE *file);
|
||||
*/
|
||||
int cfwrite_string_len(const char *buf, CFILE *file);
|
||||
|
||||
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort = CF_SORT_NONE, SCP_vector<file_list_info> *info = NULL );
|
||||
int cf_get_file_list( int max, char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
|
||||
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
|
||||
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort = CF_SORT_NONE,
|
||||
SCP_vector<file_list_info>* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_get_file_list(int max, char** list, int type, const char* filter, int sort = CF_SORT_NONE,
|
||||
file_list_info* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int type, const char* filter,
|
||||
int sort = CF_SORT_NONE, file_list_info* info = nullptr,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
void cf_sort_filenames( int n, char **list, int sort, file_list_info *info = NULL );
|
||||
void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_list_info> *info = NULL );
|
||||
|
||||
struct CFileLocation {
|
||||
bool found = false;
|
||||
SCP_string full_name;
|
||||
size_t size = 0;
|
||||
size_t offset = 0;
|
||||
const void* data_ptr = nullptr;
|
||||
|
||||
explicit CFileLocation(bool found_in = false) : found(found_in) {}
|
||||
};
|
||||
|
||||
// Searches for a file. Follows all rules and precedence and searches
|
||||
// CD's and pack files.
|
||||
// Input: filespace - Filename & extension
|
||||
@@ -325,7 +382,17 @@ void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_
|
||||
// size - File size
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns 0.
|
||||
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize = false);
|
||||
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize = false,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
struct CFileLocationExt : public CFileLocation {
|
||||
int extension_index = -1;
|
||||
|
||||
explicit CFileLocationExt(int extension_index_in = -1)
|
||||
: CFileLocation(extension_index_in >= 0), extension_index(extension_index_in)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Searches for a file. Follows all rules and precedence and searches
|
||||
// CD's and pack files. Searches all locations in order for first filename using ext filter list.
|
||||
@@ -339,7 +406,8 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns -1, else returns offset into ext_list.
|
||||
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
|
||||
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out = 0, char *pack_filename = NULL, size_t *size = NULL, size_t *offset = NULL, bool localize = false);
|
||||
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype,
|
||||
bool localize = false);
|
||||
|
||||
// Functions to change directories
|
||||
int cfile_chdir(const char *dir);
|
||||
@@ -354,6 +422,8 @@ int cfile_push_chdir(int type);
|
||||
// restore directory on top of the stack
|
||||
int cfile_pop_dir();
|
||||
|
||||
int cfile_get_path_type(const SCP_string& dir);
|
||||
|
||||
namespace cfile
|
||||
{
|
||||
// exceptions and other errors
|
||||
@@ -364,16 +434,13 @@ namespace cfile
|
||||
{
|
||||
}
|
||||
|
||||
cfile_error(const std::string &excuse) : m_excuse(excuse)
|
||||
explicit cfile_error(const std::string &excuse) : m_excuse(excuse)
|
||||
{
|
||||
}
|
||||
|
||||
~cfile_error() throw()
|
||||
{
|
||||
}
|
||||
~cfile_error() SCP_NOEXCEPT override {}
|
||||
|
||||
virtual const char *what() const throw()
|
||||
{
|
||||
const char *what() const SCP_NOEXCEPT override {
|
||||
return m_excuse.c_str();
|
||||
}
|
||||
|
||||
@@ -384,7 +451,7 @@ namespace cfile
|
||||
class max_read_length : public cfile_error
|
||||
{
|
||||
public:
|
||||
max_read_length(const std::string &excuse) : cfile_error(excuse)
|
||||
explicit max_read_length(const std::string &excuse) : cfile_error(excuse)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+59
-41
@@ -11,9 +11,9 @@
|
||||
|
||||
#define _CFILE_INTERNAL
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@@ -74,18 +74,13 @@ int cfeof(CFILE *cfile)
|
||||
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
|
||||
// cfeof() not supported for memory-mapped files
|
||||
Assert( !cb->data );
|
||||
|
||||
Assert(cb->fp != NULL);
|
||||
int result = 0;
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
auto raw_position = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(raw_position == cb->raw_position);
|
||||
if (cb->fp) {
|
||||
auto raw_position = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(raw_position == cb->raw_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cb->raw_position >= cb->size ) {
|
||||
@@ -109,14 +104,11 @@ int cftell( CFILE * cfile )
|
||||
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
|
||||
cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
// Doesn't work for memory mapped files
|
||||
Assert( !cb->data );
|
||||
|
||||
Assert(cb->fp != NULL);
|
||||
|
||||
#if defined(CHECK_POSITION) && !defined(NDEBUG)
|
||||
auto raw_position = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(raw_position == cb->raw_position);
|
||||
if (cb->fp) {
|
||||
auto raw_position = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(raw_position == cb->raw_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
|
||||
@@ -141,8 +133,7 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
|
||||
|
||||
// TODO: seek to offset in memory mapped file
|
||||
Assert( !cb->data );
|
||||
Assert( cb->fp != NULL );
|
||||
Assert( !cb->mem_mapped );
|
||||
|
||||
size_t goal_position;
|
||||
|
||||
@@ -166,14 +157,22 @@ int cfseek( CFILE *cfile, int offset, int where )
|
||||
// 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);
|
||||
int result = 0;
|
||||
|
||||
if (cb->fp) {
|
||||
// If we have a file pointer we can also seek in that file
|
||||
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);
|
||||
}
|
||||
// If we only have a data pointer this will do all the work
|
||||
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;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
if (cb->fp) {
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(tmp_offset == cb->raw_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
@@ -197,13 +196,6 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
|
||||
Cfile_block *cb = &Cfile_block_list[cfile->id];
|
||||
|
||||
// cfread() not supported for memory-mapped files
|
||||
if(cb->data != NULL)
|
||||
{
|
||||
Warning(LOCATION, "Writing is not supported for mem-mapped files");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (cb->raw_position+size) > cb->size ) {
|
||||
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
|
||||
size = cb->size - cb->raw_position;
|
||||
@@ -222,15 +214,24 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
}
|
||||
}
|
||||
|
||||
size_t bytes_read = fread( buf, 1, size, cb->fp );
|
||||
size_t bytes_read;
|
||||
if (cb->data != nullptr) {
|
||||
// This is a file from memory
|
||||
bytes_read = size;
|
||||
memcpy(buf, reinterpret_cast<const char*>(cb->data) + cb->raw_position, size);
|
||||
} else {
|
||||
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)
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
if (cb->fp) {
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (int)(bytes_read / elsize);
|
||||
@@ -254,14 +255,31 @@ int cfread_lua_number(double *buf, CFILE *cfile)
|
||||
return 0;
|
||||
}
|
||||
|
||||
long orig_pos = ftell(cb->fp);
|
||||
int items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
|
||||
cb->raw_position += ftell(cb->fp)-orig_pos;
|
||||
size_t advance = 0;
|
||||
int items_read;
|
||||
if (cb->fp) {
|
||||
long orig_pos = ftell(cb->fp);
|
||||
items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
|
||||
advance = (size_t) (ftell(cb->fp)-orig_pos);
|
||||
} else {
|
||||
int read;
|
||||
// %n returns the number of bytes currently read so we append that to the scan format at the end so it will return
|
||||
// how many bytes we have consumed
|
||||
items_read = sscanf(reinterpret_cast<const char*>(cb->data), LUA_NUMBER_SCAN "%n", buf, &read);
|
||||
if (items_read == 2) {
|
||||
// We need to correct the items read counter since we read one additional item
|
||||
items_read = 1;
|
||||
}
|
||||
advance = (size_t) read;
|
||||
}
|
||||
cb->raw_position += advance;
|
||||
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;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
if (cb->fp) {
|
||||
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
|
||||
Assert(tmp_offset==cb->raw_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
return items_read;
|
||||
|
||||
@@ -26,12 +26,12 @@ typedef struct Cfile_block {
|
||||
int type; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
|
||||
int dir_type; // directory location
|
||||
FILE *fp; // File pointer if opening an individual file
|
||||
void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
|
||||
const void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
|
||||
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
|
||||
#ifdef _WIN32
|
||||
HANDLE hInFile; // Handle from CreateFile()
|
||||
HANDLE hMapFile; // Handle from CreateFileMapping()
|
||||
#else
|
||||
// int fd; // file descriptor
|
||||
size_t data_length; // length of data for mmap
|
||||
#endif
|
||||
size_t lib_offset;
|
||||
|
||||
+4
-353
@@ -9,9 +9,9 @@
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -200,353 +200,4 @@ void cf_sort_filenames( int n, char **list, int sort, file_list_info *info )
|
||||
}
|
||||
|
||||
nprintf(("Error", "Unknown sorting method %d passed to cf_sort_filenames()\n", sort));
|
||||
}
|
||||
|
||||
|
||||
#if (0) // these aren't used anywhere now
|
||||
|
||||
// cf_compress - Do Run Length Compression on a block of data. Targa format.
|
||||
//
|
||||
// Usage:
|
||||
// out Buffer to write it out to
|
||||
// in Buffer to compress
|
||||
// bytecount Number of bytes input
|
||||
int cf_compress(char *out, char *in, int bytecount )
|
||||
{
|
||||
int pixcount; // number of pixels in the current packet
|
||||
char *inputpixel=NULL; // current input pixel position
|
||||
char *matchpixel=NULL; // pixel value to match for a run
|
||||
char *flagbyte=NULL; // location of last flag byte to set
|
||||
int rlcount; // current count in r.l. string
|
||||
int rlthresh; // minimum valid run length
|
||||
char *copyloc; // location to begin copying at
|
||||
|
||||
// set the threshold -- the minimum valid run length
|
||||
rlthresh = 2; // Require a 2 pixel span before rle'ing
|
||||
|
||||
// set the first pixel up
|
||||
|
||||
flagbyte = out; // place to put next flag if run
|
||||
inputpixel = in;
|
||||
pixcount = 1;
|
||||
rlcount = 0;
|
||||
copyloc = (char *)0;
|
||||
|
||||
// loop till data processing complete
|
||||
do {
|
||||
|
||||
// if we have accumulated a 128-byte packet, process it
|
||||
if ( pixcount == 129 ) {
|
||||
*flagbyte = 127;
|
||||
|
||||
// set the run flag if this is a run
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
*flagbyte |= 0x80;
|
||||
pixcount = 2;
|
||||
}
|
||||
|
||||
// copy the data into place
|
||||
++flagbyte;
|
||||
memmove( flagbyte, copyloc, pixcount-1 );
|
||||
flagbyte += pixcount-1;
|
||||
pixcount = 1;
|
||||
|
||||
// set up for next packet
|
||||
continue;
|
||||
}
|
||||
|
||||
// if zeroth byte, handle as special case
|
||||
if ( pixcount == 1 ) {
|
||||
rlcount = 0;
|
||||
copyloc = inputpixel; /* point to 1st guy in packet */
|
||||
matchpixel = inputpixel; /* set pointer to pix to match */
|
||||
pixcount = 2;
|
||||
inputpixel += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// assembling a packet -- look at next pixel
|
||||
|
||||
// current pixel == match pixel?
|
||||
if ( *inputpixel == *matchpixel ) {
|
||||
|
||||
// establishing a run of enough length to
|
||||
// save space by doing it
|
||||
// -- write the non-run length packet
|
||||
// -- start run-length packet
|
||||
|
||||
if ( ++rlcount == rlthresh ) {
|
||||
|
||||
// close a non-run packet
|
||||
|
||||
if ( pixcount > (rlcount+1) ) {
|
||||
// write out length and do not set run flag
|
||||
|
||||
*flagbyte++ = (char)(pixcount - 2 - rlthresh);
|
||||
|
||||
memmove(flagbyte, copyloc, (pixcount-1-rlcount) );
|
||||
flagbyte += (pixcount-1-rlcount);
|
||||
|
||||
copyloc = inputpixel;
|
||||
pixcount = rlcount + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// no match -- either break a run or continue without one
|
||||
// if a run exists break it:
|
||||
// write the bytes in the string (1+1)
|
||||
// start the next string
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
|
||||
*flagbyte++ = (char)(0x80 | rlcount);
|
||||
memmove(flagbyte, copyloc, 1 );
|
||||
flagbyte += 1;
|
||||
pixcount = 1;
|
||||
continue;
|
||||
} else {
|
||||
|
||||
// not a match and currently not a run
|
||||
// - save the current pixel
|
||||
// - reset the run-length flag
|
||||
rlcount = 0;
|
||||
matchpixel = inputpixel;
|
||||
}
|
||||
}
|
||||
pixcount++;
|
||||
inputpixel += 1;
|
||||
} while ( inputpixel < (in + bytecount));
|
||||
|
||||
// quit this buffer without loosing any data
|
||||
if ( --pixcount >= 1 ) {
|
||||
*flagbyte = (char)(pixcount - 1);
|
||||
if ( rlcount >= rlthresh ) {
|
||||
*flagbyte |= 0x80;
|
||||
pixcount = 1;
|
||||
}
|
||||
|
||||
// copy the data into place
|
||||
++flagbyte;
|
||||
memmove(flagbyte, copyloc, pixcount );
|
||||
flagbyte += pixcount;
|
||||
}
|
||||
return(flagbyte-out);
|
||||
}
|
||||
|
||||
|
||||
// cf_decompress - Do Decompression on a run-length encoded block of data. Targa format.
|
||||
//
|
||||
// Usage:
|
||||
// out Buffer to write it out to
|
||||
// in Buffer to compress
|
||||
// bytecount Number of bytes input
|
||||
int cf_decompress(char *out, char *in )
|
||||
{
|
||||
int count;
|
||||
|
||||
char *param_out = out;
|
||||
|
||||
while(1) {
|
||||
|
||||
count = int(*in++);
|
||||
int run_span = count & 0x80;
|
||||
|
||||
count &= (~0x80);
|
||||
|
||||
if ( count > 0 ) {
|
||||
if ( run_span ) {
|
||||
// RLE'd data
|
||||
ubyte c = *in++;
|
||||
|
||||
memset( out, c, count );
|
||||
out += count;
|
||||
} else {
|
||||
memmove( out, in, count );
|
||||
in += count;
|
||||
out += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out - param_out;
|
||||
|
||||
}
|
||||
|
||||
#endif // 0
|
||||
|
||||
|
||||
// cfread() reads from a file and decompresses it
|
||||
//
|
||||
// returns: returns the number of full elements read
|
||||
//
|
||||
//
|
||||
int cfread_compressed(void *buf, int elsize, int nelem, CFILE *cfile)
|
||||
{
|
||||
char *out = (char *)buf;
|
||||
|
||||
while(1) {
|
||||
|
||||
ubyte count;
|
||||
|
||||
if ( cfread( &count, 1, 1, cfile ) != 1 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
int run_span = count & 0x80;
|
||||
count &= (~0x80);
|
||||
count++;
|
||||
|
||||
if ( count > 0 ) {
|
||||
if ( run_span ) {
|
||||
// RLE'd data
|
||||
ubyte c;
|
||||
if ( cfread( &c, 1, 1, cfile ) != 1 ) {
|
||||
break;
|
||||
}
|
||||
memset( out, c, count );
|
||||
} else {
|
||||
if ( cfread( out, 1, count, cfile ) != count ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
out += count;
|
||||
if ( out >= (char *)buf + (elsize*nelem)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)((out - (char *)buf)/elsize);
|
||||
}
|
||||
|
||||
int cfwrite_compressed(void *param_buf, int param_elsize, int param_nelem, CFILE *cfile)
|
||||
{
|
||||
char *in = (char *)param_buf;
|
||||
int bytecount = (param_elsize * param_nelem );
|
||||
|
||||
int pixcount; // number of pixels in the current packet
|
||||
char *inputpixel=NULL; // current input pixel position
|
||||
char *matchpixel=NULL; // pixel value to match for a run
|
||||
int rlcount; // current count in r.l. string
|
||||
int rlthresh; // minimum valid run length
|
||||
char *copyloc; // location to begin copying at
|
||||
|
||||
// set the threshold -- the minimum valid run length
|
||||
rlthresh = 2; // Require a 2 pixel span before rle'ing
|
||||
|
||||
// set the first pixel up
|
||||
|
||||
inputpixel = in;
|
||||
pixcount = 1;
|
||||
rlcount = 0;
|
||||
copyloc = (char *)0;
|
||||
|
||||
// loop till data processing complete
|
||||
do {
|
||||
|
||||
// if we have accumulated a 128-byte packet, process it
|
||||
if ( pixcount == 129 ) {
|
||||
ubyte code = 127;
|
||||
|
||||
// set the run flag if this is a run
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
code |= 0x80;
|
||||
pixcount = 2;
|
||||
}
|
||||
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
|
||||
// copy the data into place
|
||||
cfwrite( copyloc, 1, pixcount-1, cfile );
|
||||
pixcount = 1;
|
||||
|
||||
// set up for next packet
|
||||
continue;
|
||||
}
|
||||
|
||||
// if zeroth byte, handle as special case
|
||||
if ( pixcount == 1 ) {
|
||||
rlcount = 0;
|
||||
copyloc = inputpixel; /* point to 1st guy in packet */
|
||||
matchpixel = inputpixel; /* set pointer to pix to match */
|
||||
pixcount = 2;
|
||||
inputpixel += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// assembling a packet -- look at next pixel
|
||||
|
||||
// current pixel == match pixel?
|
||||
if ( *inputpixel == *matchpixel ) {
|
||||
|
||||
// establishing a run of enough length to
|
||||
// save space by doing it
|
||||
// -- write the non-run length packet
|
||||
// -- start run-length packet
|
||||
|
||||
if ( ++rlcount == rlthresh ) {
|
||||
|
||||
// close a non-run packet
|
||||
|
||||
if ( pixcount > (rlcount+1) ) {
|
||||
// write out length and do not set run flag
|
||||
|
||||
ubyte code = (ubyte)(pixcount - 2 - rlthresh);
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
|
||||
cfwrite( copyloc, 1, (pixcount-1-rlcount), cfile );
|
||||
copyloc = inputpixel;
|
||||
pixcount = rlcount + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// no match -- either break a run or continue without one
|
||||
// if a run exists break it:
|
||||
// write the bytes in the string (1+1)
|
||||
// start the next string
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
|
||||
ubyte code = (ubyte)(0x80 | rlcount);
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
cfwrite( copyloc, 1, 1, cfile );
|
||||
pixcount = 1;
|
||||
continue;
|
||||
} else {
|
||||
|
||||
// not a match and currently not a run
|
||||
// - save the current pixel
|
||||
// - reset the run-length flag
|
||||
rlcount = 0;
|
||||
matchpixel = inputpixel;
|
||||
}
|
||||
}
|
||||
pixcount++;
|
||||
inputpixel += 1;
|
||||
} while ( inputpixel < (in + bytecount));
|
||||
|
||||
// quit this buffer without loosing any data
|
||||
if ( --pixcount >= 1 ) {
|
||||
ubyte code = ubyte(pixcount - 1);
|
||||
|
||||
// set the run flag if this is a run
|
||||
|
||||
if ( rlcount >= rlthresh ) {
|
||||
code |= 0x80;
|
||||
pixcount = 1;
|
||||
}
|
||||
|
||||
cfwrite( &code, 1, 1, cfile );
|
||||
|
||||
// copy the data into place
|
||||
cfwrite( copyloc, 1, pixcount, cfile );
|
||||
}
|
||||
|
||||
return param_nelem;
|
||||
}
|
||||
}
|
||||
+361
-190
@@ -9,10 +9,10 @@
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -37,15 +37,16 @@
|
||||
#include "cfile/cfilesystem.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "def_files/def_files.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
|
||||
SCP_string Pilot_file_path;
|
||||
enum CfileRootType {
|
||||
CF_ROOTTYPE_PATH = 0,
|
||||
CF_ROOTTYPE_PACK = 1,
|
||||
CF_ROOTTYPE_MEMORY = 2,
|
||||
};
|
||||
|
||||
// Created by:
|
||||
// specifying hard drive tree
|
||||
@@ -53,8 +54,9 @@ SCP_string Pilot_file_path;
|
||||
// specifying cd-rom tree
|
||||
// searching for pack files on CD-rom tree
|
||||
typedef struct cf_root {
|
||||
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
|
||||
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file
|
||||
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
|
||||
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file, CF_ROOTTYPE_MEMORY=In memory
|
||||
uint32_t location_flags;
|
||||
} cf_root;
|
||||
|
||||
// convenient type for sorting (see cf_build_pack_list())
|
||||
@@ -79,13 +81,14 @@ 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* real_name; // For real files, the full path
|
||||
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
|
||||
const void* data; // For in-memory files, the data pointer
|
||||
} cf_file;
|
||||
|
||||
#define CF_NUM_FILES_PER_BLOCK 512
|
||||
@@ -342,9 +345,9 @@ void cf_build_pack_list( cf_root *root )
|
||||
std::sort(temp_roots_sort, temp_roots_sort + temp_root_count, cf_packfile_sort_func);
|
||||
|
||||
// now insert them all into the real root list properly
|
||||
cf_root *new_root;
|
||||
for (i = 0; i < temp_root_count; i++) {
|
||||
new_root = cf_create_root();
|
||||
auto new_root = cf_create_root();
|
||||
new_root->location_flags = root->location_flags;
|
||||
strcpy_s( new_root->path, root->path );
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -373,10 +376,11 @@ static char normalize_directory_separator(char in)
|
||||
return in;
|
||||
}
|
||||
|
||||
static void cf_add_mod_roots(const char* rootDirectory)
|
||||
static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
|
||||
{
|
||||
if (Cmdline_mod)
|
||||
{
|
||||
bool primary = true;
|
||||
for (const char* cur_pos=Cmdline_mod; strlen(cur_pos) != 0; cur_pos+= (strlen(cur_pos)+1))
|
||||
{
|
||||
SCP_stringstream ss;
|
||||
@@ -400,9 +404,16 @@ static void cf_add_mod_roots(const char* rootDirectory)
|
||||
cf_root* root = cf_create_root();
|
||||
|
||||
strncpy(root->path, rootPath.c_str(), CF_MAX_PATHNAME_LENGTH-1);
|
||||
if (primary) {
|
||||
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
} else {
|
||||
root->location_flags = basic_location | CF_LOCATION_TYPE_SECONDARY_MODS;
|
||||
}
|
||||
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
cf_build_pack_list(root);
|
||||
|
||||
primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -420,10 +431,16 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
#ifdef WIN32
|
||||
// Nothing to do here, Windows uses the current directory as the base
|
||||
#else
|
||||
cf_add_mod_roots(Cfile_user_dir_legacy);
|
||||
cf_add_mod_roots(os_get_legacy_user_dir(), CF_LOCATION_ROOT_USER);
|
||||
|
||||
root = cf_create_root();
|
||||
strncpy(root->path, Cfile_user_dir_legacy, CF_MAX_PATHNAME_LENGTH - 1);
|
||||
strncpy(root->path, os_get_legacy_user_dir(), CF_MAX_PATHNAME_LENGTH - 1);
|
||||
|
||||
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
|
||||
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
|
||||
// If there are no mods then the root is the primary mod
|
||||
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
}
|
||||
|
||||
// do we already have a slash? as in the case of a root directory install
|
||||
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
|
||||
@@ -431,10 +448,6 @@ 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.empty())
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
cf_build_pack_list(root);
|
||||
#endif
|
||||
@@ -444,13 +457,19 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
{
|
||||
// =========================================================================
|
||||
// now look for mods under the users HOME directory to use before system ones
|
||||
cf_add_mod_roots(Cfile_user_dir);
|
||||
cf_add_mod_roots(Cfile_user_dir, CF_LOCATION_ROOT_USER);
|
||||
// =========================================================================
|
||||
|
||||
// =========================================================================
|
||||
// set users HOME directory as default for loading and saving files
|
||||
root = cf_create_root();
|
||||
strncpy(root->path, Cfile_user_dir, CF_MAX_PATHNAME_LENGTH - 1);
|
||||
strcpy_s(root->path, Cfile_user_dir);
|
||||
|
||||
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
|
||||
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
|
||||
// If there are no mods then the root is the primary mod
|
||||
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
}
|
||||
|
||||
// do we already have a slash? as in the case of a root directory install
|
||||
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
|
||||
@@ -458,10 +477,6 @@ 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.empty())
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
cf_build_pack_list(root);
|
||||
// =========================================================================
|
||||
@@ -472,11 +487,17 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
if ( !_getcwd(working_directory, CF_MAX_PATHNAME_LENGTH ) ) {
|
||||
Error(LOCATION, "Can't get current working directory -- %d", errno );
|
||||
}
|
||||
|
||||
cf_add_mod_roots(working_directory);
|
||||
|
||||
cf_add_mod_roots(working_directory, CF_LOCATION_ROOT_GAME);
|
||||
|
||||
root = cf_create_root();
|
||||
|
||||
|
||||
root->location_flags |= CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT;
|
||||
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
|
||||
// If there are no mods then the root is the primary mod
|
||||
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
}
|
||||
|
||||
strcpy_s(root->path, working_directory);
|
||||
|
||||
size_t path_len = strlen(root->path);
|
||||
@@ -488,10 +509,6 @@ 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.empty() )
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
//======================================================
|
||||
// Next, check any VP files under the current directory.
|
||||
cf_build_pack_list(root);
|
||||
@@ -510,6 +527,12 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
|
||||
}
|
||||
|
||||
// The final root is the in-memory root
|
||||
root = cf_create_root();
|
||||
root->location_flags = CF_LOCATION_ROOT_MEMORY | CF_LOCATION_TYPE_ROOT;
|
||||
memset(root->path, 0, sizeof(root->path));
|
||||
root->roottype = CF_ROOTTYPE_MEMORY;
|
||||
|
||||
}
|
||||
|
||||
// Given a lower case list of file extensions
|
||||
@@ -639,7 +662,7 @@ void cf_search_root_path(int root_index)
|
||||
struct dirent *dir = nullptr;
|
||||
while ((dir = readdir (parentDirP)) != nullptr) {
|
||||
|
||||
if (stricmp(search_name, dir->d_name)) {
|
||||
if (stricmp(search_name, dir->d_name) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -836,7 +859,48 @@ void cf_search_root_pack(int root_index)
|
||||
mprintf(( "%i files\n", num_files ));
|
||||
}
|
||||
|
||||
void cf_search_memory_root(int root_index) {
|
||||
int num_files = 0;
|
||||
mprintf(( "Searching memory root ... " ));
|
||||
|
||||
auto default_files = defaults_get_all();
|
||||
for (auto& default_file : default_files) {
|
||||
// Pure built in files have an empty path_type string
|
||||
if (strlen(default_file.path_type) <= 0) {
|
||||
// Ignore pure builtin files. They should only be accessible with defaults_get_file
|
||||
continue;
|
||||
}
|
||||
|
||||
int pathtype = -1;
|
||||
for (int i = 0; i < CF_MAX_PATH_TYPES; ++i) {
|
||||
if (Pathtypes[i].path == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(Pathtypes[i].path, default_file.path_type)) {
|
||||
pathtype = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assertion(pathtype != -1, "Default file '%s%s%s' does not use a valid path type!",
|
||||
default_file.path_type,
|
||||
DIR_SEPARATOR_STR,
|
||||
default_file.filename);
|
||||
|
||||
cf_file *file = cf_create_file();
|
||||
|
||||
strcpy_s( file->name_ext, default_file.filename );
|
||||
file->root_index = root_index;
|
||||
file->pathtype_index = pathtype;
|
||||
file->write_time = time(nullptr); // Just assume that memory files were last written to just now
|
||||
file->size = (int)default_file.size;
|
||||
file->data = default_file.data;
|
||||
|
||||
num_files++;
|
||||
}
|
||||
|
||||
mprintf(( "%i files\n", num_files ));
|
||||
}
|
||||
|
||||
void cf_build_file_list()
|
||||
{
|
||||
@@ -851,6 +915,8 @@ void cf_build_file_list()
|
||||
cf_search_root_path(i);
|
||||
} else if ( root->roottype == CF_ROOTTYPE_PACK ) {
|
||||
cf_search_root_pack(i);
|
||||
} else if (root->roottype == CF_ROOTTYPE_MEMORY) {
|
||||
cf_search_memory_root(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,15 +990,12 @@ void cf_free_secondary_filelist()
|
||||
*
|
||||
* @param filespec Filename & extension
|
||||
* @param pathtype See CF_TYPE_ defines in CFILE.H
|
||||
* @param max_out Maximum string length that should be stuffed into pack_filename
|
||||
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
|
||||
* @param size OUTPUT: File size
|
||||
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
|
||||
* @param localize Undertake localization
|
||||
* @param location_flags Specifies where to search for the specified flag
|
||||
*
|
||||
* @return If not found returns 0.
|
||||
* @return A structure which describes the found file
|
||||
*/
|
||||
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize )
|
||||
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize, uint32_t location_flags)
|
||||
{
|
||||
int i;
|
||||
uint ui;
|
||||
@@ -940,7 +1003,6 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
char longname[MAX_PATH_LEN];
|
||||
|
||||
Assert( (filespec != NULL) && (strlen(filespec) > 0) ); //-V805
|
||||
Assert( (pack_filename == NULL) || (max_out > 1) );
|
||||
|
||||
// see if we have something other than just a filename
|
||||
// our current rules say that any file that specifies a direct
|
||||
@@ -956,16 +1018,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
#endif
|
||||
FILE *fp = fopen(filespec, "rb" );
|
||||
if (fp) {
|
||||
if ( size ) *size = filelength(fileno(fp));
|
||||
if ( offset ) *offset = 0;
|
||||
if ( pack_filename ) {
|
||||
strncpy( pack_filename, filespec, max_out );
|
||||
}
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength(fileno(fp)));
|
||||
res.offset = 0;
|
||||
res.full_name = filespec;
|
||||
fclose(fp);
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0; // If they give a full path, fail if not found.
|
||||
return CFileLocation(); // If they give a full path, fail if not found.
|
||||
}
|
||||
|
||||
// Search the hard drive for files first.
|
||||
@@ -1004,43 +1065,39 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
}
|
||||
|
||||
if (cfs_slow_search) {
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, search_order[ui], filespec, localize );
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, search_order[ui], filespec, localize,
|
||||
location_flags);
|
||||
|
||||
#if defined _WIN32
|
||||
_finddata_t findstruct;
|
||||
|
||||
intptr_t findhandle = _findfirst(longname, &findstruct);
|
||||
if (findhandle != -1) {
|
||||
if (size)
|
||||
*size = findstruct.size;
|
||||
CFileLocation res;
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(findstruct.size);
|
||||
|
||||
_findclose(findhandle);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy( pack_filename, longname, max_out );
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
FILE *fp = fopen(longname, "rb" );
|
||||
|
||||
if (fp) {
|
||||
if (size)
|
||||
*size = filelength( fileno(fp) );
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy(pack_filename, longname, max_out);
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1054,6 +1111,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) )
|
||||
continue;
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (localize) {
|
||||
// create localized filespec
|
||||
@@ -1061,54 +1127,58 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
|
||||
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
|
||||
if ( !stricmp(longname, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = (size_t)f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (pack_filename) {
|
||||
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);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// file either not localized or localized version not found
|
||||
if ( !stricmp(filespec, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = (size_t)f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (pack_filename) {
|
||||
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);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return CFileLocation();
|
||||
}
|
||||
|
||||
// -- from parselo.cpp --
|
||||
@@ -1125,14 +1195,11 @@ extern char *stristr(char *str, const char *substr);
|
||||
* @param ext_list Extension filter list
|
||||
* @param pathtype See CF_TYPE_ defines in CFILE.H
|
||||
* @param max_out Maximum string length that should be stuffed into pack_filename
|
||||
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
|
||||
* @param size OUTPUT: File size
|
||||
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
|
||||
* @param localize Undertake localization
|
||||
*
|
||||
* @return If not found returns -1, else returns offset into ext_list.
|
||||
* @return A structure containing information about the found file
|
||||
*/
|
||||
int cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize )
|
||||
CFileLocationExt cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, bool localize)
|
||||
{
|
||||
int cur_ext, i;
|
||||
uint ui;
|
||||
@@ -1144,7 +1211,6 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
Assert( (filename != NULL) && (strlen(filename) < MAX_FILENAME_LEN) );
|
||||
Assert( (ext_list != NULL) && (ext_num > 1) ); // if we are searching for just one ext
|
||||
// then this is the wrong function to use
|
||||
Assert( (pack_filename == NULL) || (max_out > 1) );
|
||||
|
||||
|
||||
// if we have a full path already then fail. this function if for searching via filter only!
|
||||
@@ -1154,7 +1220,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
if ( strpbrk(filename,"/\\:") ) { // do we have a full path already?
|
||||
#endif
|
||||
Int3();
|
||||
return 0;
|
||||
return CFileLocationExt();
|
||||
}
|
||||
|
||||
// Search the hard drive for files first.
|
||||
@@ -1212,38 +1278,35 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
|
||||
#if defined _WIN32
|
||||
_finddata_t findstruct;
|
||||
|
||||
intptr_t findhandle = _findfirst(longname, &findstruct);
|
||||
if (findhandle != -1) {
|
||||
if (size)
|
||||
*size = findstruct.size;
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(findstruct.size);
|
||||
|
||||
_findclose(findhandle);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy( pack_filename, longname, max_out );
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
FILE *fp = fopen(longname, "rb" );
|
||||
|
||||
if (fp) {
|
||||
if (size)
|
||||
*size = filelength( fileno(fp) );
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy(pack_filename, longname, max_out);
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1284,7 +1347,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
continue;
|
||||
|
||||
// ... check that we match the base filename
|
||||
if ( strnicmp(f->name_ext, filespec, filespec_len) )
|
||||
if ( strnicmp(f->name_ext, filespec, filespec_len) != 0 )
|
||||
continue;
|
||||
|
||||
// ... make sure that it's one of our supported types
|
||||
@@ -1328,56 +1391,62 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
|
||||
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
|
||||
if ( !stricmp(longname, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (pack_filename) {
|
||||
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);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
// found it, so cleanup and return
|
||||
file_list_index.clear();
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// file either not localized or localized version not found
|
||||
if ( !stricmp(filespec, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (pack_filename) {
|
||||
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);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
// found it, so cleanup and return
|
||||
file_list_index.clear();
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
|
||||
// ok, we're still here, so strip off the extension again in order to
|
||||
@@ -1388,7 +1457,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return CFileLocationExt();
|
||||
}
|
||||
|
||||
|
||||
@@ -1432,6 +1501,7 @@ int cf_matches_spec(const char *filespec, const char *filename)
|
||||
int (*Get_file_list_filter)(const char *filename) = NULL;
|
||||
const char *Get_file_list_child = NULL;
|
||||
int Skip_packfile_search = 0;
|
||||
bool Skip_memory_files = false;
|
||||
|
||||
static bool verify_file_list_child()
|
||||
{
|
||||
@@ -1486,7 +1556,8 @@ static int cf_file_already_in_list( SCP_vector<SCP_string> &list, const char *fi
|
||||
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
|
||||
// location, 'filter' only needs to be the filter itself, with no path information.
|
||||
// See above descriptions of cf_get_file_list() for more information about how it all works.
|
||||
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort, SCP_vector<file_list_info> *info )
|
||||
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort,
|
||||
SCP_vector<file_list_info>* info, uint32_t location_flags)
|
||||
{
|
||||
char *ptr;
|
||||
uint i;
|
||||
@@ -1514,7 +1585,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
}
|
||||
|
||||
#if defined _WIN32
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
|
||||
location_flags);
|
||||
strcat_s(filespec, DIR_SEPARATOR_STR);
|
||||
strcat_s(filespec, filter);
|
||||
|
||||
@@ -1554,7 +1626,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
}
|
||||
|
||||
#elif defined SCP_UNIX
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
|
||||
location_flags);
|
||||
|
||||
DIR *dirp;
|
||||
struct dirent *dir;
|
||||
@@ -1567,8 +1640,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) {
|
||||
@@ -1620,6 +1695,16 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
continue;
|
||||
}
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !cf_matches_spec( filter,f->name_ext)) {
|
||||
continue;
|
||||
}
|
||||
@@ -1633,6 +1718,11 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip_memory_files && f->data != nullptr) {
|
||||
// If we want to skip memory files and this is a memory file then ignore it
|
||||
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 ));
|
||||
|
||||
@@ -1692,7 +1782,8 @@ int cf_file_already_in_list( int num_files, char **list, const char *filename )
|
||||
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
|
||||
// location, 'filter' only needs to be the filter itself, with no path information.
|
||||
// See above descriptions of cf_get_file_list() for more information about how it all works.
|
||||
int cf_get_file_list( int max, char **list, int pathtype, const char *filter, int sort, file_list_info *info )
|
||||
int cf_get_file_list(int max, char** list, int pathtype, const char* filter, int sort, file_list_info* info,
|
||||
uint32_t location_flags)
|
||||
{
|
||||
char *ptr;
|
||||
uint i;
|
||||
@@ -1715,7 +1806,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
char filespec[MAX_PATH_LEN];
|
||||
|
||||
#if defined _WIN32
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
|
||||
|
||||
_finddata_t find;
|
||||
intptr_t find_handle;
|
||||
@@ -1756,7 +1847,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
}
|
||||
|
||||
#elif defined SCP_UNIX
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
|
||||
|
||||
DIR *dirp;
|
||||
struct dirent *dir;
|
||||
@@ -1776,8 +1867,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) {
|
||||
@@ -1827,6 +1920,16 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
continue;
|
||||
}
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_files >= max)
|
||||
break;
|
||||
|
||||
@@ -1843,6 +1946,11 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip_memory_files && f->data != nullptr) {
|
||||
// If we want to skip memory files and this is a memory file then ignore it
|
||||
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 ));
|
||||
@@ -1905,7 +2013,8 @@ int cf_file_already_in_list_preallocated( int num_files, char arr[][MAX_FILENAME
|
||||
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
|
||||
// location, 'filter' only needs to be the filter itself, with no path information.
|
||||
// See above descriptions of cf_get_file_list() for more information about how it all works.
|
||||
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int pathtype, const char *filter, int sort, file_list_info *info )
|
||||
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int pathtype, const char* filter,
|
||||
int sort, file_list_info* info, uint32_t location_flags)
|
||||
{
|
||||
int num_files = 0, own_flag = 0;
|
||||
|
||||
@@ -1934,7 +2043,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
|
||||
// Search the default directories
|
||||
#if defined _WIN32
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
|
||||
|
||||
intptr_t find_handle;
|
||||
_finddata_t find;
|
||||
@@ -1975,7 +2084,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
}
|
||||
|
||||
#elif defined SCP_UNIX
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
|
||||
|
||||
DIR *dirp;
|
||||
struct dirent *dir;
|
||||
@@ -1991,8 +2100,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) {
|
||||
@@ -2009,7 +2120,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
|
||||
if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
|
||||
|
||||
strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
|
||||
strcpy_s(arr[num_files], dir->d_name );
|
||||
char *ptr = strrchr(arr[num_files], '.');
|
||||
if ( ptr ) {
|
||||
*ptr = 0;
|
||||
@@ -2044,6 +2155,16 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
continue;
|
||||
}
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_files >= max)
|
||||
|
||||
break;
|
||||
@@ -2061,6 +2182,11 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip_memory_files && f->data != nullptr) {
|
||||
// If we want to skip memory files and this is a memory file then ignore it
|
||||
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 ));
|
||||
@@ -2105,7 +2231,8 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
// filename - optional, if set, tacks the filename onto end of path.
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if the result would be too long (invalid result)
|
||||
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize )
|
||||
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename, bool localize,
|
||||
uint32_t location_flags)
|
||||
{
|
||||
#ifdef SCP_UNIX
|
||||
if ( filename && strpbrk(filename,"/") ) {
|
||||
@@ -2116,7 +2243,22 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
|
||||
strncpy( path, filename, path_max );
|
||||
|
||||
} else {
|
||||
cf_root *root = cf_get_root(0);
|
||||
cf_root* root = nullptr;
|
||||
|
||||
for (auto i = 0; i < Num_roots; ++i) {
|
||||
auto current_root = cf_get_root(i);
|
||||
|
||||
if (current_root->roottype != CF_ROOTTYPE_PATH) {
|
||||
// We want a "real" path here so only path roots are valid
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
|
||||
// We found a valid root
|
||||
root = current_root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
Assert( filename != NULL );
|
||||
@@ -2126,12 +2268,7 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
|
||||
|
||||
Assert(CF_TYPE_SPECIFIED(pathtype));
|
||||
|
||||
// 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.c_str(), path_max);
|
||||
} else {
|
||||
strncpy(path, root->path, path_max);
|
||||
}
|
||||
strncpy(path, root->path, path_max);
|
||||
|
||||
strcat_s(path, path_max, Pathtypes[pathtype].path);
|
||||
|
||||
@@ -2177,7 +2314,8 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
|
||||
// filename - optional, if set, tacks the filename onto end of path.
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if the result would be too long (invalid result)
|
||||
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename, bool localize )
|
||||
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename, bool /*localize*/,
|
||||
uint32_t location_flags)
|
||||
{
|
||||
#ifdef SCP_UNIX
|
||||
if ( filename && strpbrk(filename,"/") ) {
|
||||
@@ -2188,7 +2326,22 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
|
||||
path.assign(filename);
|
||||
|
||||
} else {
|
||||
cf_root *root = cf_get_root(0);
|
||||
cf_root* root = nullptr;
|
||||
|
||||
for (auto i = 0; i < Num_roots; ++i) {
|
||||
auto current_root = cf_get_root(i);
|
||||
|
||||
if (current_root->roottype != CF_ROOTTYPE_PATH) {
|
||||
// We want a "real" path here so only path roots are valid
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
|
||||
// We found a valid root
|
||||
root = current_root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
Assert( filename != NULL );
|
||||
@@ -2199,12 +2352,7 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
|
||||
Assert(CF_TYPE_SPECIFIED(pathtype));
|
||||
std::ostringstream s_path;
|
||||
|
||||
// force a specific directory to search for player files
|
||||
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
|
||||
s_path << Pilot_file_path;
|
||||
} else {
|
||||
s_path << root->path;
|
||||
}
|
||||
s_path << root->path;
|
||||
|
||||
s_path << Pathtypes[pathtype].path;
|
||||
|
||||
@@ -2269,3 +2417,26 @@ void cfile_spew_pack_file_crcs()
|
||||
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags)
|
||||
{
|
||||
Assertion((check_flags & CF_LOCATION_ROOT_MASK) != 0, "check_flags must have a valid root value");
|
||||
Assertion((check_flags & CF_LOCATION_TYPE_MASK) != 0, "check_flags must have a valid type value");
|
||||
|
||||
auto check_root = check_flags & CF_LOCATION_ROOT_MASK;
|
||||
auto desired_root_flags = desired_flags & CF_LOCATION_ROOT_MASK;
|
||||
|
||||
// If the root part is not set then assume that every root matches
|
||||
if (desired_root_flags != 0 && (check_root & desired_root_flags) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto check_type = check_flags & CF_LOCATION_TYPE_MASK;
|
||||
auto desired_type_flags = desired_flags & CF_LOCATION_TYPE_MASK;
|
||||
|
||||
if (desired_type_flags != 0 && (check_type & desired_type_flags) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -29,6 +29,8 @@ typedef struct cf_pathtype {
|
||||
// During cfile_init, verify that Pathtypes[n].index == n for each item
|
||||
extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
|
||||
|
||||
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
|
||||
|
||||
// Returns the default storage path for files given a
|
||||
// particular pathtype. In other words, the path to
|
||||
// the unpacked, non-cd'd, stored on hard drive path.
|
||||
@@ -39,7 +41,9 @@ extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
|
||||
// filename - optional, if set, tacks the filename onto end of path.
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if result would be too long (invalid result)
|
||||
int cf_create_default_path_string( char *path, uint path_max, int pathtype, const char *filename=NULL, bool localize = false);
|
||||
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename=NULL, bool localize = false );
|
||||
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename = nullptr,
|
||||
bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr, bool localize = false,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
#endif //_CFILESYSTEM_H
|
||||
+333
-118
@@ -23,6 +23,9 @@
|
||||
#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>
|
||||
@@ -36,8 +39,11 @@
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#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);
|
||||
@@ -148,7 +160,6 @@ Flag exe_params[] =
|
||||
{ "-noenv", "Disable environment maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-env", },
|
||||
{ "-nomotiondebris", "Disable motion debris", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
|
||||
{ "-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" },
|
||||
@@ -162,7 +173,6 @@ Flag exe_params[] =
|
||||
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT_MEM, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
|
||||
{ "-enable_shadows", "Enable Shadows", true, EASY_MEM_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_shadows"},
|
||||
{ "-no_vsync", "Disable vertical sync", true, 0, EASY_DEFAULT, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_vsync", },
|
||||
{ "-cache_bitmaps", "Cache bitmaps between missions", true, 0, EASY_DEFAULT_MEM, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-cache_bitmaps", },
|
||||
|
||||
{ "-dualscanlines", "Add another pair of scanning lines", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dualscanlines", },
|
||||
{ "-targetinfo", "Enable info next to target", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-targetinfo", },
|
||||
@@ -177,7 +187,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,7 +204,6 @@ Flag exe_params[] =
|
||||
{ "-no_set_gamma", "Disable setting of gamma", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_set_gamma", },
|
||||
{ "-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", },
|
||||
{ "-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", },
|
||||
@@ -203,9 +211,7 @@ Flag exe_params[] =
|
||||
{ "-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", },
|
||||
{ "-use_gldrawelements","Don't use glDrawRangeElements", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-use_gldrawelements", },
|
||||
{ "-old_collision", "Use old collision detection system", true, EASY_DEFAULT, EASY_ALL_ON, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-old_collision", },
|
||||
{ "-gl_finish", "Fix input lag on some ATI+Linux systems", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gl_finish", },
|
||||
{ "-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", },
|
||||
@@ -218,12 +224,12 @@ 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", },
|
||||
{ "-stats", "Show statistics", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stats", },
|
||||
{ "-coords", "Show coordinates", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-coords", },
|
||||
{ "-show_mem_usage", "Show memory usage", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-show_mem_usage", },
|
||||
{ "-pofspew", "Generate all ibx files immediately", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pofspew", },
|
||||
{ "-tablecrcs", "Dump table CRCs for multi validation", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-tablecrcs", },
|
||||
{ "-missioncrcs", "Dump mission CRCs for multi validation", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-missioncrcs", },
|
||||
@@ -238,7 +244,6 @@ Flag exe_params[] =
|
||||
{ "-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", },
|
||||
@@ -303,7 +308,6 @@ cmdline_parm spec_static_arg("-spec_static", "Adjusts suns contribution to specu
|
||||
cmdline_parm spec_point_arg("-spec_point", "Adjusts laser weapons contribution to specular highlights", AT_FLOAT);
|
||||
cmdline_parm spec_tube_arg("-spec_tube", "Adjusts beam weapons contribution to specular highlights", AT_FLOAT);
|
||||
cmdline_parm ambient_factor_arg("-ambient_factor", "Adjusts ambient light applied to all parts of a ship", AT_INT); // Cmdline_ambient_factor
|
||||
cmdline_parm missile_lighting_arg("-missile_lighting", NULL, AT_NONE); // Cmdline_missile_lighting
|
||||
cmdline_parm env("-noenv", NULL, AT_NONE); // Cmdline_env
|
||||
cmdline_parm glow_arg("-noglow", NULL, AT_NONE); // Cmdline_glow -- use Bobs glow code
|
||||
cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE); // Cmdline_nomotiondebris -- Removes those ugly floating rocks -C
|
||||
@@ -321,10 +325,10 @@ cmdline_parm fxaa_preset_arg("-fxaa_preset", "FXAA quality (0-9), requires -post
|
||||
cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
|
||||
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
|
||||
cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
|
||||
cmdline_parm no_batching("-no_batching", NULL, AT_NONE);
|
||||
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
|
||||
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
|
||||
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
|
||||
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
|
||||
|
||||
float Cmdline_clip_dist = Default_min_draw_distance;
|
||||
float Cmdline_fov = 0.75f;
|
||||
@@ -332,7 +336,6 @@ float Cmdline_ogl_spec = 80.0f;
|
||||
int Cmdline_ambient_factor = 128;
|
||||
int Cmdline_env = 1;
|
||||
int Cmdline_mipmap = 0;
|
||||
int Cmdline_missile_lighting = 0;
|
||||
int Cmdline_glow = 1;
|
||||
int Cmdline_nomotiondebris = 0;
|
||||
int Cmdline_noscalevid = 0;
|
||||
@@ -349,17 +352,15 @@ int Cmdline_fxaa_preset = 6;
|
||||
extern int Fxaa_preset_last_frame;
|
||||
bool Cmdline_fb_explosions = 0;
|
||||
bool Cmdline_fb_thrusters = false;
|
||||
bool Cmdline_no_batching = false;
|
||||
extern bool ls_force_off;
|
||||
int Cmdline_shadow_quality = 0;
|
||||
int Cmdline_no_deferred_lighting = 0;
|
||||
int Cmdline_aniso_level = 0;
|
||||
|
||||
// Game Speed related
|
||||
cmdline_parm cache_bitmaps_arg("-cache_bitmaps", NULL, AT_NONE); // Cmdline_cache_bitmaps
|
||||
cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NONE); // Cmdline_NoFPSCap
|
||||
cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE); // Cmdline_no_vsync
|
||||
|
||||
int Cmdline_cache_bitmaps = 0; // caching of bitmaps between missions (faster loads, can hit swap on reload with <512 Meg RAM though) - taylor
|
||||
int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
|
||||
int Cmdline_no_vsync = 0;
|
||||
|
||||
@@ -392,12 +393,8 @@ int Cmdline_autopilot_interruptable = 1;
|
||||
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;
|
||||
|
||||
@@ -437,7 +434,6 @@ cmdline_parm atiswap_arg("-ati_swap", NULL, AT_NONE); // Cmdline_atiswap
|
||||
cmdline_parm no3dsound_arg("-no_3d_sound", NULL, AT_NONE); // Cmdline_no_3d_sound - Disable use of full 3D sounds
|
||||
cmdline_parm no_drawrangeelements("-use_gldrawelements", NULL, AT_NONE); // Cmdline_drawelements -- Uses glDrawElements instead of glDrawRangeElements
|
||||
cmdline_parm keyboard_layout("-keyboard_layout", "Specify keyboard layout (qwertz or azerty)", AT_STRING);
|
||||
cmdline_parm old_collision_system("-old_collision", NULL, AT_NONE); // Cmdline_old_collision_sys
|
||||
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);
|
||||
@@ -472,6 +468,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 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
|
||||
@@ -486,7 +483,6 @@ cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); //
|
||||
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
|
||||
@@ -494,14 +490,15 @@ cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_
|
||||
|
||||
|
||||
char *Cmdline_start_mission = NULL;
|
||||
int Cmdline_old_collision_sys = 0;
|
||||
int Cmdline_dis_collisions = 0;
|
||||
int Cmdline_dis_weapons = 0;
|
||||
bool Cmdline_output_sexp_info = false;
|
||||
int Cmdline_noparseerrors = 0;
|
||||
#ifdef Allow_NoWarn
|
||||
int Cmdline_nowarn = 0; // turn warnings off in FRED
|
||||
#endif
|
||||
int Cmdline_extra_warn = 0;
|
||||
int Cmdline_bmpman_usage = 0;
|
||||
int Cmdline_show_pos = 0;
|
||||
int Cmdline_show_stats = 0;
|
||||
int Cmdline_save_render_targets = 0;
|
||||
@@ -515,14 +512,13 @@ 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
|
||||
|
||||
@@ -535,6 +531,9 @@ 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);
|
||||
cmdline_parm deprecated_missile_lighting_arg("-missile_lighting", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_cache_bitmaps_arg("-cache_bitmaps", "Deprecated", AT_NONE);
|
||||
|
||||
int Cmdline_deprecated_spec = 0;
|
||||
int Cmdline_deprecated_glow = 0;
|
||||
@@ -544,6 +543,8 @@ int Cmdline_deprecated_tbp = 0;
|
||||
int Cmdline_deprecated_jpgtga = 0;
|
||||
int Cmdline_deprecated_nohtl = 0;
|
||||
bool Cmdline_deprecated_brief_lighting = 0;
|
||||
bool Cmdline_deprecated_missile_lighting = false;
|
||||
bool Cmdline_deprecated_cache_bitmaps = false;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
|
||||
@@ -609,6 +610,15 @@ void cmdline_debug_print_cmdline()
|
||||
{
|
||||
mprintf(("Deprecated flag '-brief_lighting' found. Please remove from your cmdline.\n"));
|
||||
}
|
||||
|
||||
if (Cmdline_deprecated_missile_lighting)
|
||||
{
|
||||
mprintf(("Deprecated flag '-missile_lighting' found. Please remove from your cmdline.\n"));
|
||||
}
|
||||
|
||||
if (Cmdline_deprecated_cache_bitmaps) {
|
||||
mprintf(("Deprecated flag '-cache_bitmaps' found. Please remove from your cmdline.\n"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -801,7 +811,7 @@ void os_validate_parms(int argc, char *argv[])
|
||||
size_t sp = 0;
|
||||
for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
|
||||
// don't output deprecated flags
|
||||
if (stricmp("deprecated", parmp->help)) {
|
||||
if (stricmp("deprecated", parmp->help) != 0) {
|
||||
sp = strlen(parmp->name);
|
||||
if (parmp->arg_type != AT_NONE) {
|
||||
atp = strlen(cmdline_arg_types[parmp->arg_type]);
|
||||
@@ -987,32 +997,32 @@ 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
|
||||
|
||||
@@ -1143,11 +1153,14 @@ 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.
|
||||
// dir must not contain a slash.
|
||||
static SCP_vector<SCP_string> unix_get_single_dir_names(SCP_string parent, SCP_string dir)
|
||||
static SCP_vector<SCP_string> unix_get_single_dir_names(const SCP_string& parent, const SCP_string& dir)
|
||||
{
|
||||
SCP_vector<SCP_string> ret;
|
||||
|
||||
@@ -1170,7 +1183,7 @@ static SCP_vector<SCP_string> unix_get_single_dir_names(SCP_string parent, SCP_s
|
||||
|
||||
// Return a vector with all filesystem names of "parent/dir" relative to parent.
|
||||
// Recurses to deal with slashes in dir.
|
||||
static SCP_vector<SCP_string> unix_get_dir_names(SCP_string parent, SCP_string dir)
|
||||
static SCP_vector<SCP_string> unix_get_dir_names(const SCP_string& parent, const SCP_string& dir)
|
||||
{
|
||||
size_t slash = dir.find_first_of("/\\");
|
||||
|
||||
@@ -1241,6 +1254,257 @@ 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);
|
||||
}
|
||||
{
|
||||
auto efx_support_obj = json_object();
|
||||
|
||||
for (auto& pair : openal_info.efx_support) {
|
||||
json_object_set_new(efx_support_obj, pair.first.c_str(), json_boolean(pair.second));
|
||||
}
|
||||
|
||||
json_object_set_new(openal_obj, "efx_support", efx_support_obj);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
@@ -1248,47 +1512,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;
|
||||
}
|
||||
@@ -1541,6 +1765,11 @@ bool SetCmdlineParams()
|
||||
Show_framerate = 1;
|
||||
}
|
||||
|
||||
if (bmpmanusage_arg.found())
|
||||
{
|
||||
Cmdline_bmpman_usage = 1;
|
||||
}
|
||||
|
||||
if(pos_arg.found())
|
||||
{
|
||||
Cmdline_show_pos = 1;
|
||||
@@ -1644,9 +1873,6 @@ bool SetCmdlineParams()
|
||||
if ( glow_arg.found() )
|
||||
Cmdline_glow = 0;
|
||||
|
||||
if ( query_speech_arg.found() )
|
||||
Cmdline_query_speech = 1;
|
||||
|
||||
if ( ship_choice_3d_arg.found() )
|
||||
Cmdline_ship_choice_3d = 1;
|
||||
|
||||
@@ -1667,7 +1893,7 @@ bool SetCmdlineParams()
|
||||
Output_scripting_meta = true;
|
||||
|
||||
if (output_sexp_arg.found() ) {
|
||||
output_sexps("sexps.html");
|
||||
Cmdline_output_sexp_info = true;
|
||||
}
|
||||
|
||||
if ( no_pbo_arg.found() )
|
||||
@@ -1721,11 +1947,6 @@ bool SetCmdlineParams()
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( snd_preload_arg.found() )
|
||||
{
|
||||
Cmdline_snd_preload = 1;
|
||||
}
|
||||
|
||||
if ( env.found() ) {
|
||||
Cmdline_env = 0;
|
||||
}
|
||||
@@ -1734,13 +1955,6 @@ bool SetCmdlineParams()
|
||||
Cmdline_ballistic_gauge = 1;
|
||||
}
|
||||
|
||||
if ( cache_bitmaps_arg.found() ) {
|
||||
Cmdline_cache_bitmaps = 1;
|
||||
}
|
||||
|
||||
if(old_collision_system.found())
|
||||
Cmdline_old_collision_sys = 1;
|
||||
|
||||
if(dis_collisions.found())
|
||||
Cmdline_dis_collisions = 1;
|
||||
|
||||
@@ -1764,9 +1978,6 @@ bool SetCmdlineParams()
|
||||
if ( rearm_timer_arg.found() )
|
||||
Cmdline_rearm_timer = 1;
|
||||
|
||||
if ( missile_lighting_arg.found() )
|
||||
Cmdline_missile_lighting = 1;
|
||||
|
||||
if ( save_render_targets_arg.found() )
|
||||
Cmdline_save_render_targets = 1;
|
||||
|
||||
@@ -1801,11 +2012,6 @@ bool SetCmdlineParams()
|
||||
Cmdline_fb_thrusters = true;
|
||||
}
|
||||
|
||||
if ( no_batching.found() )
|
||||
{
|
||||
Cmdline_no_batching = true;
|
||||
}
|
||||
|
||||
if ( postprocess_arg.found() )
|
||||
{
|
||||
Cmdline_postprocess = 1;
|
||||
@@ -1841,6 +2047,11 @@ bool SetCmdlineParams()
|
||||
Cmdline_no_deferred_lighting = 1;
|
||||
}
|
||||
|
||||
if (anisotropy_level_arg.found())
|
||||
{
|
||||
Cmdline_aniso_level = anisotropy_level_arg.get_int();
|
||||
}
|
||||
|
||||
if (frame_profile_write_file.found())
|
||||
{
|
||||
Cmdline_profile_write_file = true;
|
||||
@@ -1861,11 +2072,6 @@ bool SetCmdlineParams()
|
||||
Cmdline_noninteractive = true;
|
||||
}
|
||||
|
||||
if (json_pilot.found())
|
||||
{
|
||||
Cmdline_json_pilot = true;
|
||||
}
|
||||
|
||||
if (json_profiling.found())
|
||||
{
|
||||
Cmdline_json_profiling = true;
|
||||
@@ -1926,6 +2132,15 @@ bool SetCmdlineParams()
|
||||
Cmdline_deprecated_brief_lighting = 1;
|
||||
}
|
||||
|
||||
if (deprecated_missile_lighting_arg.found())
|
||||
{
|
||||
Cmdline_deprecated_missile_lighting = true;
|
||||
}
|
||||
|
||||
if (deprecated_cache_bitmaps_arg.found()) {
|
||||
Cmdline_deprecated_cache_bitmaps = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@ extern float static_point_factor;
|
||||
extern float static_tube_factor;
|
||||
extern int Cmdline_ambient_factor;
|
||||
extern int Cmdline_env;
|
||||
extern int Cmdline_missile_lighting;
|
||||
extern int Cmdline_glow;
|
||||
extern int Cmdline_nomotiondebris;
|
||||
extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
|
||||
@@ -77,13 +76,12 @@ extern bool Cmdline_fxaa;
|
||||
extern int Cmdline_fxaa_preset;
|
||||
extern bool Cmdline_fb_explosions;
|
||||
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;
|
||||
extern int Cmdline_aniso_level;
|
||||
|
||||
// Game Speed related
|
||||
extern int Cmdline_cache_bitmaps;
|
||||
extern int Cmdline_NoFPSCap;
|
||||
extern int Cmdline_no_vsync;
|
||||
|
||||
@@ -103,8 +101,6 @@ extern int Cmdline_autopilot_interruptable;
|
||||
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;
|
||||
|
||||
@@ -143,11 +139,12 @@ extern bool Cmdline_alternate_registry_path;
|
||||
|
||||
// Developer/Testing related
|
||||
extern char *Cmdline_start_mission;
|
||||
extern int Cmdline_old_collision_sys;
|
||||
extern int Cmdline_dis_collisions;
|
||||
extern int Cmdline_dis_weapons;
|
||||
extern bool Cmdline_output_sexp_info;
|
||||
extern int Cmdline_noparseerrors;
|
||||
extern int Cmdline_extra_warn;
|
||||
extern int Cmdline_bmpman_usage;
|
||||
extern int Cmdline_show_pos;
|
||||
extern int Cmdline_show_stats;
|
||||
extern int Cmdline_save_render_targets;
|
||||
@@ -157,7 +154,6 @@ 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;
|
||||
|
||||
@@ -53,26 +53,6 @@ void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
|
||||
vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
|
||||
}
|
||||
|
||||
void cmeasure_select_next(ship *shipp)
|
||||
{
|
||||
Assert(shipp != NULL);
|
||||
int i, new_index;
|
||||
|
||||
for (i = 1; i < Num_weapon_types; i++)
|
||||
{
|
||||
new_index = (shipp->current_cmeasure + i) % Num_weapon_types;
|
||||
|
||||
if(Weapon_info[new_index].wi_flags[Weapon::Info_Flags::Cmeasure])
|
||||
{
|
||||
shipp->current_cmeasure = new_index;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mprintf(("Countermeasure type set to %i in frame %i\n", shipp->current_cmeasure, Framecount));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief If this is a player countermeasure, let the player know they evaded a missile.
|
||||
* @param objp [description]
|
||||
@@ -92,7 +72,7 @@ void cmeasure_maybe_alert_success(object *objp)
|
||||
|
||||
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, GameSounds::MISSILE_EVADED_POPUP)));
|
||||
} else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) {
|
||||
send_countermeasure_success_packet( objp->parent );
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ extern int Cmeasures_homing_check;
|
||||
extern int Countermeasures_enabled;
|
||||
|
||||
extern void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand);
|
||||
extern void cmeasure_select_next(object *objp);
|
||||
extern void cmeasure_maybe_alert_success(object *objp);
|
||||
|
||||
#endif // _CMEASURE_H
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
|
||||
|
||||
#define NUM_SYSTEM_KEYS 14
|
||||
#define NUM_BUTTONS 19
|
||||
#define NUM_TABS 4
|
||||
|
||||
@@ -157,11 +156,6 @@ char *Mouse_button_text[NUM_MOUSE_TEXT];
|
||||
char *Mouse_axis_text[NUM_MOUSE_AXIS_TEXT];
|
||||
char *Invert_text[NUM_INVERT_TEXT];
|
||||
|
||||
ubyte System_keys[NUM_SYSTEM_KEYS] = {
|
||||
KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,
|
||||
KEY_F11, KEY_F12, KEY_PRINT_SCRN
|
||||
};
|
||||
|
||||
int Control_check_count = 0;
|
||||
|
||||
static int Tab; // which tab we are currently in
|
||||
@@ -356,7 +350,7 @@ DCF_BOOL(show_controls_info, Show_controls_info);
|
||||
|
||||
static int Axes_origin[JOY_NUM_AXES];
|
||||
|
||||
static int joy_get_unscaled_reading(int raw, int axn)
|
||||
static int joy_get_unscaled_reading(int raw)
|
||||
{
|
||||
int rng;
|
||||
|
||||
@@ -615,7 +609,7 @@ int control_config_undo_last()
|
||||
int i, z, tab;
|
||||
|
||||
if (!Config_item_undo) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -664,7 +658,7 @@ int control_config_undo_last()
|
||||
free_undo_block();
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -715,7 +709,7 @@ int control_config_remove_binding()
|
||||
config_item_undo *ptr;
|
||||
|
||||
if (Selected_line < 0) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -723,7 +717,7 @@ int control_config_remove_binding()
|
||||
if (z & JOY_AXIS) {
|
||||
z &= ~JOY_AXIS;
|
||||
if (Axis_map_to[z] < 0) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -731,13 +725,13 @@ int control_config_remove_binding()
|
||||
Axis_map_to[z] = -1;
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
Selected_item = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((Control_config[z].joy_id < 0) && (Control_config[z].key_id < 0)) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -755,7 +749,7 @@ int control_config_remove_binding()
|
||||
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
Selected_item = -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -766,7 +760,7 @@ int control_config_clear_other()
|
||||
config_item_undo *ptr;
|
||||
|
||||
if (Selected_line < 0) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -776,7 +770,7 @@ int control_config_clear_other()
|
||||
|
||||
z &= ~JOY_AXIS;
|
||||
if (Axis_map_to[z] < 0) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -787,7 +781,7 @@ int control_config_clear_other()
|
||||
}
|
||||
|
||||
if (!total) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -808,7 +802,7 @@ int control_config_clear_other()
|
||||
}
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -820,12 +814,12 @@ int control_config_clear_other()
|
||||
}
|
||||
}
|
||||
if (!total) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((Control_config[z].joy_id < 0) && (Control_config[z].key_id < 0)) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -850,7 +844,7 @@ int control_config_clear_other()
|
||||
}
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -867,7 +861,7 @@ int control_config_clear_all()
|
||||
}
|
||||
|
||||
if (!total) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -888,7 +882,7 @@ int control_config_clear_all()
|
||||
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_RESET_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::RESET_PRESSED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -945,7 +939,7 @@ int control_config_do_reset()
|
||||
}
|
||||
|
||||
if (!total && !cycling_presets) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -981,7 +975,7 @@ int control_config_do_reset()
|
||||
|
||||
control_config_conflict_check();
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_RESET_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::RESET_PRESSED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1026,10 +1020,10 @@ void control_config_scroll_screen_up()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,10 +1036,10 @@ void control_config_scroll_line_up()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1059,10 +1053,10 @@ void control_config_scroll_screen_down()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1076,10 +1070,10 @@ void control_config_scroll_line_down()
|
||||
}
|
||||
|
||||
Selected_item = -1;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
} else {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1091,13 +1085,13 @@ void control_config_toggle_modifier(int bit)
|
||||
Assert(!(z & JOY_AXIS));
|
||||
k = Control_config[z].key_id;
|
||||
if (k < 0) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
control_config_bind_key(z, k ^ bit);
|
||||
control_config_conflict_check();
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
}
|
||||
|
||||
void control_config_toggle_invert()
|
||||
@@ -1118,7 +1112,7 @@ void control_config_do_bind()
|
||||
game_flush();
|
||||
// if ((Selected_line < 0) || (Cc_lines[Selected_line].cc_index & JOY_AXIS)) {
|
||||
if (Selected_line < 0) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1142,7 +1136,7 @@ void control_config_do_bind()
|
||||
Search_mode = 0;
|
||||
Last_key = -1;
|
||||
Axis_override = -1;
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
}
|
||||
|
||||
void control_config_do_search()
|
||||
@@ -1166,7 +1160,7 @@ void control_config_do_search()
|
||||
Binding_mode = 0;
|
||||
Search_mode = 1;
|
||||
Last_key = -1;
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
}
|
||||
|
||||
void control_config_do_cancel(int fail = 0)
|
||||
@@ -1189,9 +1183,9 @@ void control_config_do_cancel(int fail = 0)
|
||||
|
||||
Binding_mode = Search_mode = 0;
|
||||
if (fail){
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
} else {
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1206,13 +1200,13 @@ int control_config_accept()
|
||||
}
|
||||
|
||||
if (i < NUM_TABS) {
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
|
||||
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
|
||||
gamesnd_play_iface(SND_COMMIT_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1237,7 +1231,7 @@ void control_config_button_pressed(int n)
|
||||
Tab = n;
|
||||
Scroll_offset = Selected_line = 0;
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
|
||||
break;
|
||||
|
||||
case BIND_BUTTON:
|
||||
@@ -1250,17 +1244,17 @@ void control_config_button_pressed(int n)
|
||||
|
||||
case SHIFT_TOGGLE:
|
||||
control_config_toggle_modifier(KEY_SHIFTED);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
|
||||
case ALT_TOGGLE:
|
||||
control_config_toggle_modifier(KEY_ALTED);
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
|
||||
case INVERT_AXIS:
|
||||
control_config_toggle_invert();
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
break;
|
||||
|
||||
case SCROLL_UP_BUTTON:
|
||||
@@ -1281,7 +1275,7 @@ void control_config_button_pressed(int n)
|
||||
|
||||
case HELP_BUTTON:
|
||||
launch_context_help();
|
||||
gamesnd_play_iface(SND_HELP_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::HELP_PRESSED);
|
||||
break;
|
||||
|
||||
case RESET_BUTTON:
|
||||
@@ -1799,7 +1793,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
Scroll_offset = Selected_line = 0;
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
|
||||
break;
|
||||
|
||||
case KEY_TAB: // activate next tab
|
||||
@@ -1810,7 +1804,7 @@ void control_config_do_frame(float frametime)
|
||||
|
||||
Scroll_offset = Selected_line = 0;
|
||||
control_config_list_prepare();
|
||||
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
|
||||
break;
|
||||
|
||||
case KEY_LEFT:
|
||||
@@ -1825,7 +1819,7 @@ void control_config_do_frame(float frametime)
|
||||
}
|
||||
}
|
||||
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
break;
|
||||
|
||||
case KEY_RIGHT:
|
||||
@@ -1837,7 +1831,7 @@ void control_config_do_frame(float frametime)
|
||||
} else if (Selected_item > 1) {
|
||||
Selected_item = -1;
|
||||
}
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
break;
|
||||
|
||||
case KEY_BACKSP: // undo
|
||||
@@ -1873,7 +1867,7 @@ void control_config_do_frame(float frametime)
|
||||
Selected_item = 1;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(SND_USER_SELECT);
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
}
|
||||
|
||||
if (List_buttons[i].double_clicked()) {
|
||||
@@ -2193,17 +2187,6 @@ void control_config_do_frame(float frametime)
|
||||
gr_flip();
|
||||
}
|
||||
|
||||
void clear_key_binding(short key)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<CCFG_MAX; i++) {
|
||||
if (Control_config[i].key_id == key) {
|
||||
Control_config[i].key_id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float check_control_timef(int id)
|
||||
{
|
||||
float t1, t2;
|
||||
@@ -2345,7 +2328,7 @@ int check_control(int id, int key)
|
||||
// which has just been released
|
||||
|
||||
Script_system.SetHookVar("Action", 's', Control_config[id].text);
|
||||
Script_system.RunCondition(CHA_ONACTIONSTOPPED, '\0', NULL, NULL, id);
|
||||
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
|
||||
Script_system.RemHookVar("Action");
|
||||
|
||||
Control_config[id].continuous_ongoing = false;
|
||||
@@ -2379,7 +2362,7 @@ void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr)
|
||||
|
||||
*ta = 0;
|
||||
if (Axis_map_to[3] >= 0) {
|
||||
*ta = joy_get_unscaled_reading(axes_values[Axis_map_to[3]], Axis_map_to[3]);
|
||||
*ta = joy_get_unscaled_reading(axes_values[Axis_map_to[3]]);
|
||||
}
|
||||
|
||||
*tr = 0;
|
||||
@@ -2419,7 +2402,7 @@ void control_used(int id)
|
||||
if (Control_config[id].used < Last_frame_timestamp) {
|
||||
if (!Control_config[id].continuous_ongoing) {
|
||||
Script_system.SetHookVar("Action", 's', Control_config[id].text);
|
||||
Script_system.RunCondition(CHA_ONACTION, '\0', NULL, NULL, id);
|
||||
Script_system.RunCondition(CHA_ONACTION, nullptr, id);
|
||||
Script_system.RemHookVar("Action");
|
||||
|
||||
if (Control_config[id].type == CC_TYPE_CONTINUOUS)
|
||||
@@ -2447,9 +2430,4 @@ void control_config_clear()
|
||||
for (i=0; i<CCFG_MAX; i++) {
|
||||
Control_config[i].key_id = Control_config[i].joy_id = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int control_config_handle_conflict()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -277,12 +277,6 @@ enum IoActionId {
|
||||
};
|
||||
|
||||
extern int Failed_key_index;
|
||||
extern int Invert_heading;
|
||||
extern int Invert_pitch;
|
||||
extern int Invert_roll;
|
||||
extern int Invert_thrust;
|
||||
extern int Disable_axis2;
|
||||
extern int Disable_axis3;
|
||||
|
||||
extern int Axis_map_to[];
|
||||
extern int Invert_axis[];
|
||||
@@ -336,7 +330,6 @@ int check_control(int id, int key = -1);
|
||||
void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr);
|
||||
void control_used(int id);
|
||||
void control_config_clear();
|
||||
void clear_key_binding(short key);
|
||||
void control_check_indicate();
|
||||
void control_config_clear_used_status();
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
@@ -34,13 +34,6 @@ int Failed_key_index;
|
||||
int Joy_dead_zone_size = 10;
|
||||
int Joy_sensitivity = 9;
|
||||
|
||||
// assume control keys are used as modifiers until we find out
|
||||
int Shift_is_modifier;
|
||||
int Ctrl_is_modifier;
|
||||
int Alt_is_modifier;
|
||||
|
||||
int Axis_enabled[JOY_NUM_AXES] = { 1, 1, 1, 0, 0, 0 };
|
||||
int Axis_enabled_defaults[JOY_NUM_AXES] = { 1, 1, 1, 0, 0, 0 };
|
||||
int Invert_axis[JOY_NUM_AXES] = { 0, 0, 0, 0, 0, 0 };
|
||||
int Invert_axis_defaults[JOY_NUM_AXES] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
@@ -201,7 +194,7 @@ config_item Control_config[CCFG_MAX + 1] = {
|
||||
|
||||
const char *Scan_code_text_german[] = {
|
||||
"", "Esc", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab",
|
||||
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab", // NOLINT
|
||||
"Q", "W", "E", "R", "T", "Z", "U", "I",
|
||||
"O", "P", "\x9A", "+", "Eingabe", "Strg Links", "A", "S",
|
||||
|
||||
@@ -251,8 +244,8 @@ const char *Joy_button_text_german[] = {
|
||||
};
|
||||
|
||||
const char *Scan_code_text_french[] = {
|
||||
"", "\x90""chap", "1", "2", "3", "4", "5", "6",
|
||||
"7", "8", "9", "0", "-", "=", "Fl\x82""che Ret.", "Tab",
|
||||
"", "\x90""chap", "1", "2", "3", "4", "5", "6", // NOLINT
|
||||
"7", "8", "9", "0", "-", "=", "Fl\x82""che Ret.", "Tab", // NOLINT
|
||||
"Q", "W", "E", "R", "T", "Y", "U", "I",
|
||||
"O", "P", "[", "]", "Entr\x82""e", "Ctrl Gauche", "A", "S",
|
||||
|
||||
@@ -410,31 +403,6 @@ const char **Joy_button_text = Joy_button_text_english;
|
||||
SCP_vector<config_item*> Control_config_presets;
|
||||
SCP_vector<SCP_string> Control_config_preset_names;
|
||||
|
||||
void set_modifier_status()
|
||||
{
|
||||
int i;
|
||||
|
||||
Alt_is_modifier = 0;
|
||||
Shift_is_modifier = 0;
|
||||
Ctrl_is_modifier = 0;
|
||||
|
||||
for (i=0; i<CCFG_MAX; i++) {
|
||||
if (Control_config[i].key_id < 0)
|
||||
continue;
|
||||
|
||||
if (Control_config[i].key_id & KEY_ALTED)
|
||||
Alt_is_modifier = 1;
|
||||
|
||||
if (Control_config[i].key_id & KEY_SHIFTED)
|
||||
Shift_is_modifier = 1;
|
||||
|
||||
if (Control_config[i].key_id & KEY_CTRLED) {
|
||||
Assert(0); // get Alan
|
||||
Ctrl_is_modifier = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If find_override is set to true, then this returns the index of the action
|
||||
// which has been bound to the given key. Otherwise, the index of the action
|
||||
// which has the given key as its default key will be returned.
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
#include <memory>
|
||||
|
||||
namespace cutscene {
|
||||
FrameSize::FrameSize(size_t in_width, size_t in_height, size_t in_stride)
|
||||
: width(in_width), height(in_height), stride(in_stride)
|
||||
{
|
||||
}
|
||||
FrameSize::FrameSize() = default;
|
||||
|
||||
Decoder::Decoder() : m_decoding(true) {
|
||||
}
|
||||
|
||||
@@ -14,6 +20,11 @@ bool Decoder::tryPopAudioData(AudioFramePtr& 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;
|
||||
@@ -24,6 +35,7 @@ void Decoder::initializeQueues(size_t 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() {
|
||||
@@ -31,10 +43,7 @@ void Decoder::stopDecoder() {
|
||||
|
||||
m_videoQueue->close();
|
||||
m_audioQueue->close();
|
||||
}
|
||||
|
||||
bool Decoder::canPushAudioData() {
|
||||
return !isAudioQueueFull();
|
||||
m_subtitleQueue->close();
|
||||
}
|
||||
|
||||
void Decoder::pushAudioData(AudioFramePtr&& data) {
|
||||
@@ -48,8 +57,15 @@ void Decoder::pushAudioData(AudioFramePtr&& data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Decoder::canPushVideoData() {
|
||||
return !isVideoQueueFull();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::pushFrameData(VideoFramePtr&& frame) {
|
||||
|
||||
+42
-17
@@ -10,28 +10,26 @@ struct FrameSize {
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
size_t stride = 0;
|
||||
|
||||
FrameSize();
|
||||
FrameSize(size_t width, size_t in_height, size_t in_stride);
|
||||
};
|
||||
|
||||
class VideoFrame {
|
||||
protected:
|
||||
VideoFrame() {}
|
||||
VideoFrame() = default;
|
||||
|
||||
public:
|
||||
virtual ~VideoFrame() {}
|
||||
public:
|
||||
virtual ~VideoFrame() = default;
|
||||
|
||||
double frameTime = -1.0;
|
||||
int id = -1;
|
||||
|
||||
FrameSize ySize;
|
||||
FrameSize uvSize;
|
||||
virtual size_t getPlaneNumber() = 0;
|
||||
|
||||
struct DataPointers {
|
||||
ubyte* y;
|
||||
ubyte* u;
|
||||
ubyte* v;
|
||||
};
|
||||
virtual FrameSize getPlaneSize(size_t plane) = 0;
|
||||
|
||||
virtual DataPointers getDataPointers() = 0;
|
||||
virtual void* getPlaneData(size_t plane) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -43,10 +41,19 @@ using FramePtr = std::unique_ptr<T>;
|
||||
|
||||
typedef std::unique_ptr<VideoFrame> VideoFramePtr;
|
||||
|
||||
enum class FramePixelFormat {
|
||||
Invalid,
|
||||
YUV420,
|
||||
BGR,
|
||||
BGRA
|
||||
};
|
||||
|
||||
struct MovieProperties {
|
||||
FrameSize size;
|
||||
|
||||
float fps = -1.0f;
|
||||
|
||||
FramePixelFormat pixelFormat = FramePixelFormat::Invalid;
|
||||
};
|
||||
|
||||
struct AudioFrame {
|
||||
@@ -58,6 +65,19 @@ struct AudioFrame {
|
||||
};
|
||||
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;
|
||||
|
||||
struct PlaybackProperties {
|
||||
bool with_audio = true;
|
||||
bool looping = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstract class for decoding a video or audio stream
|
||||
*
|
||||
@@ -68,6 +88,7 @@ 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;
|
||||
@@ -90,13 +111,13 @@ class Decoder {
|
||||
* @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;
|
||||
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the properties of the video
|
||||
* @return The properties
|
||||
*/
|
||||
virtual MovieProperties getProperties() = 0;
|
||||
virtual MovieProperties getProperties() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Starts decoding the video
|
||||
@@ -107,7 +128,9 @@ class Decoder {
|
||||
* @brief Determines if the video has audio
|
||||
* @return @c true if audio is included in the video
|
||||
*/
|
||||
virtual bool hasAudio() = 0;
|
||||
virtual bool hasAudio() const = 0;
|
||||
|
||||
virtual bool hasSubtitles() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Ends decoding of the video file
|
||||
@@ -122,6 +145,10 @@ class Decoder {
|
||||
|
||||
bool tryPopAudioData(AudioFramePtr&);
|
||||
|
||||
bool isSubtitleQueueFull() { return m_subtitleQueue->size() == m_queueSize; }
|
||||
|
||||
bool tryPopSubtitleData(SubtitleFramePtr&);
|
||||
|
||||
bool isVideoQueueFull() { return m_videoQueue->size() == m_queueSize; }
|
||||
|
||||
bool isVideoFrameAvailable() { return !m_videoQueue->empty(); }
|
||||
@@ -137,11 +164,9 @@ class Decoder {
|
||||
protected:
|
||||
void initializeQueues(size_t queueSize);
|
||||
|
||||
bool canPushAudioData();
|
||||
|
||||
void pushAudioData(AudioFramePtr&& data);
|
||||
|
||||
bool canPushVideoData();
|
||||
void pushSubtitleData(SubtitleFramePtr&& data);
|
||||
|
||||
void pushFrameData(VideoFramePtr&& frame);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
#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) : _properties(props)
|
||||
{
|
||||
GR_DEBUG_SCOPE("Init video");
|
||||
|
||||
_planeTextureHandles.fill(-1);
|
||||
|
||||
auto w = static_cast<int>(props.size.width);
|
||||
auto h = static_cast<int>(props.size.height);
|
||||
|
||||
switch (props.pixelFormat) {
|
||||
case FramePixelFormat::YUV420:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h]);
|
||||
_planeTextureHandles[0] = bm_create(8, w, h, _planeTextureBuffers[0].get(), BMP_AABITMAP);
|
||||
|
||||
_planeTextureBuffers[1].reset(new uint8_t[w / 2 * h / 2]);
|
||||
_planeTextureHandles[1] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[1].get(), BMP_AABITMAP);
|
||||
|
||||
_planeTextureBuffers[2].reset(new uint8_t[w / 2 * h / 2]);
|
||||
_planeTextureHandles[2] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[2].get(), BMP_AABITMAP);
|
||||
|
||||
material_set_movie(&_movie_material, _planeTextureHandles[0], _planeTextureHandles[1], _planeTextureHandles[2]);
|
||||
break;
|
||||
case FramePixelFormat::BGR:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h * 3]);
|
||||
_planeTextureHandles[0] = bm_create(24, w, h, _planeTextureBuffers[0].get(), 0);
|
||||
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, false, false);
|
||||
break;
|
||||
case FramePixelFormat::BGRA:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h * 4]);
|
||||
_planeTextureHandles[0] = bm_create(32, w, h, _planeTextureBuffers[0].get(), 0);
|
||||
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, true, false);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VideoPresenter::~VideoPresenter() {
|
||||
GR_DEBUG_SCOPE("Deinit video");
|
||||
|
||||
for (auto& handle : _planeTextureHandles) {
|
||||
if (handle > 0) {
|
||||
bm_release(handle);
|
||||
handle = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
GR_DEBUG_SCOPE("Update video frame");
|
||||
|
||||
for (size_t i = 0; i < frame->getPlaneNumber(); ++i) {
|
||||
auto size = frame->getPlaneSize(i);
|
||||
auto data = frame->getPlaneData(i);
|
||||
|
||||
memcpy(_planeTextureBuffers[i].get(), data, size.stride * size.height);
|
||||
|
||||
int bpp = 0;
|
||||
switch (_properties.pixelFormat) {
|
||||
case FramePixelFormat::YUV420:
|
||||
bpp = 8;
|
||||
break;
|
||||
case FramePixelFormat::BGR:
|
||||
bpp = 24;
|
||||
break;
|
||||
case FramePixelFormat::BGRA:
|
||||
bpp = 32;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
|
||||
gr_update_texture(_planeTextureHandles[i], bpp, _planeTextureBuffers[i].get(), static_cast<int>(size.width),
|
||||
static_cast<int>(size.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]), offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offsetof(movie_vertex, uv));
|
||||
|
||||
if (_properties.pixelFormat == FramePixelFormat::YUV420) {
|
||||
gr_render_movie(&_movie_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle, offset);
|
||||
} else {
|
||||
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#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 {
|
||||
MovieProperties _properties;
|
||||
|
||||
std::array<int, 3> _planeTextureHandles;
|
||||
std::array<std::unique_ptr<uint8_t[]>, 3> _planeTextureBuffers;
|
||||
|
||||
movie_material _movie_material;
|
||||
material _rgb_material; // Material used when a RGB/RGBA movie is played
|
||||
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
|
||||
+12
-12
@@ -286,10 +286,10 @@ void cutscenes_screen_scroll_line_up()
|
||||
if (Selected_line)
|
||||
{
|
||||
Selected_line--;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
} else
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
|
||||
if (Selected_line < Scroll_offset)
|
||||
Scroll_offset = Selected_line;
|
||||
@@ -302,10 +302,10 @@ void cutscenes_screen_scroll_line_down()
|
||||
if (Selected_line < (int) Cutscene_list.size() - 1)
|
||||
{
|
||||
Selected_line++;
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
} else
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
|
||||
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
|
||||
if (Selected_line >= Scroll_offset + h)
|
||||
@@ -328,11 +328,11 @@ void cutscenes_screen_scroll_screen_up()
|
||||
Selected_line--;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
|
||||
} else
|
||||
{
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,10 +349,10 @@ void cutscenes_screen_scroll_screen_down()
|
||||
Selected_line = Scroll_offset;
|
||||
}
|
||||
|
||||
gamesnd_play_iface(SND_SCROLL);
|
||||
gamesnd_play_iface(InterfaceSounds::SCROLL);
|
||||
} else
|
||||
{
|
||||
gamesnd_play_iface(SND_GENERAL_FAIL);
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,17 +361,17 @@ int cutscenes_screen_button_pressed(int n)
|
||||
switch (n)
|
||||
{
|
||||
case TECH_DATABASE_BUTTON:
|
||||
gamesnd_play_iface(SND_SWITCH_SCREENS);
|
||||
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
|
||||
gameseq_post_event(GS_EVENT_TECH_MENU);
|
||||
return 1;
|
||||
|
||||
case SIMULATOR_BUTTON:
|
||||
gamesnd_play_iface(SND_SWITCH_SCREENS);
|
||||
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
|
||||
gameseq_post_event(GS_EVENT_SIMULATOR_ROOM);
|
||||
return 1;
|
||||
|
||||
case CREDITS_BUTTON:
|
||||
gamesnd_play_iface(SND_SWITCH_SCREENS);
|
||||
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
|
||||
gameseq_post_event(GS_EVENT_CREDITS);
|
||||
return 1;
|
||||
|
||||
@@ -388,7 +388,7 @@ int cutscenes_screen_button_pressed(int n)
|
||||
break;
|
||||
|
||||
case EXIT_BUTTON:
|
||||
gamesnd_play_iface(SND_COMMIT_PRESSED);
|
||||
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
|
||||
gameseq_post_event(GS_EVENT_MAIN_MENU);
|
||||
game_flush();
|
||||
break;
|
||||
|
||||
@@ -55,6 +55,9 @@ int resample_convert(SwrContext* ctx, uint8_t** output,
|
||||
#ifdef WITH_LIBAV
|
||||
return avresample_convert(ctx, output, out_plane_size, out_samples, input, in_plane_size, in_samples);
|
||||
#else
|
||||
(void)out_plane_size;
|
||||
(void)in_plane_size;
|
||||
|
||||
return swr_convert(ctx, output, out_samples, (const uint8_t**) input, in_samples);
|
||||
#endif
|
||||
}
|
||||
@@ -220,5 +223,8 @@ void AudioDecoder::finishDecoding() {
|
||||
// Push the last bits of audio data into the queue
|
||||
flushAudioBuffer();
|
||||
}
|
||||
void AudioDecoder::flushBuffers() {
|
||||
avcodec_flush_buffers(m_status->audioCodecCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,13 @@ class AudioDecoder: public FFMPEGStreamDecoder<AudioFrame> {
|
||||
public:
|
||||
explicit AudioDecoder(DecoderStatus* status);
|
||||
|
||||
virtual ~AudioDecoder();
|
||||
~AudioDecoder() override;
|
||||
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
void decodePacket(AVPacket* packet) override;
|
||||
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
void finishDecoding() override;
|
||||
|
||||
void flushBuffers() override;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
#include "cutscene/ffmpeg/AudioDecoder.h"
|
||||
#include "cutscene/ffmpeg/VideoDecoder.h"
|
||||
#include "cutscene/ffmpeg/SubtitleDecoder.h"
|
||||
|
||||
#include "FFMPEGDecoder.h"
|
||||
#include "localization/localize.h"
|
||||
|
||||
using namespace libs::ffmpeg;
|
||||
|
||||
@@ -24,20 +28,26 @@ class AVPacketScope
|
||||
: _packet(av_packet) {
|
||||
}
|
||||
|
||||
AVPacketScope(const AVPacketScope&) = delete;
|
||||
AVPacketScope& operator=(const AVPacketScope&) = delete;
|
||||
|
||||
~AVPacketScope() {
|
||||
av_packet_unref(_packet);
|
||||
}
|
||||
};
|
||||
|
||||
const char* CHECKED_EXTENSIONS[] = {
|
||||
"webm",
|
||||
"mp4",
|
||||
"ogg",
|
||||
"mve"
|
||||
};
|
||||
const char* CHECKED_EXTENSIONS[] = {"webm", "mp4", "ogg",
|
||||
"png", // This is designed to be used with APNG animations
|
||||
"mve"};
|
||||
|
||||
const char* CHECKED_SUBT_EXTENSIONS[] = {"srt"};
|
||||
|
||||
double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
|
||||
auto fps = av_q2d(stream->r_frame_rate);
|
||||
#else
|
||||
auto fps = av_q2d(av_stream_get_r_frame_rate(stream));
|
||||
#endif
|
||||
|
||||
if (fps < 0.000001)
|
||||
{
|
||||
@@ -55,23 +65,111 @@ double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
|
||||
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.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.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.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.sample_rate = stream->codec->sample_rate;
|
||||
paras.audio_format = stream->codec->sample_fmt;
|
||||
|
||||
paras.codec_id = stream->codec->codec_id;
|
||||
#endif
|
||||
return paras;
|
||||
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";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Given a FFmpeg pixel format returns the format it should be converted to
|
||||
* @param in_fmt The input format
|
||||
* @return The output format
|
||||
*/
|
||||
AVPixelFormat getConversionFormat(AVPixelFormat in_fmt)
|
||||
{
|
||||
switch (in_fmt) {
|
||||
case AV_PIX_FMT_RGB24:
|
||||
case AV_PIX_FMT_BGR24:
|
||||
case AV_PIX_FMT_BGR8:
|
||||
case AV_PIX_FMT_BGR4:
|
||||
case AV_PIX_FMT_BGR4_BYTE:
|
||||
case AV_PIX_FMT_RGB8:
|
||||
case AV_PIX_FMT_RGB4:
|
||||
case AV_PIX_FMT_RGB4_BYTE:
|
||||
case AV_PIX_FMT_RGB48BE:
|
||||
case AV_PIX_FMT_RGB48LE:
|
||||
case AV_PIX_FMT_RGB565BE:
|
||||
case AV_PIX_FMT_RGB565LE:
|
||||
case AV_PIX_FMT_RGB555BE:
|
||||
case AV_PIX_FMT_RGB555LE:
|
||||
case AV_PIX_FMT_BGR565BE:
|
||||
case AV_PIX_FMT_BGR565LE:
|
||||
case AV_PIX_FMT_BGR555BE:
|
||||
case AV_PIX_FMT_BGR555LE:
|
||||
case AV_PIX_FMT_RGB444LE:
|
||||
case AV_PIX_FMT_RGB444BE:
|
||||
case AV_PIX_FMT_BGR444LE:
|
||||
case AV_PIX_FMT_BGR444BE:
|
||||
case AV_PIX_FMT_BGR48BE:
|
||||
case AV_PIX_FMT_BGR48LE:
|
||||
case AV_PIX_FMT_0RGB:
|
||||
case AV_PIX_FMT_RGB0:
|
||||
case AV_PIX_FMT_0BGR:
|
||||
case AV_PIX_FMT_BGR0:
|
||||
return AV_PIX_FMT_BGR24;
|
||||
|
||||
case AV_PIX_FMT_RGBA64BE:
|
||||
case AV_PIX_FMT_RGBA64LE:
|
||||
case AV_PIX_FMT_BGRA64BE:
|
||||
case AV_PIX_FMT_BGRA64LE:
|
||||
case AV_PIX_FMT_ARGB:
|
||||
case AV_PIX_FMT_RGBA:
|
||||
case AV_PIX_FMT_ABGR:
|
||||
case AV_PIX_FMT_BGRA:
|
||||
return AV_PIX_FMT_BGRA;
|
||||
|
||||
default:
|
||||
// Assume that everything else is converted to YUV 420
|
||||
return AV_PIX_FMT_YUV420P;
|
||||
}
|
||||
}
|
||||
|
||||
FramePixelFormat getPixelFormat(AVPixelFormat fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AV_PIX_FMT_BGR24:
|
||||
return FramePixelFormat::BGR;
|
||||
case AV_PIX_FMT_BGRA:
|
||||
return FramePixelFormat::BGRA;
|
||||
default:
|
||||
return FramePixelFormat::YUV420;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +216,15 @@ std::unique_ptr<InputStream> openStream(const SCP_string& name) {
|
||||
return input;
|
||||
}
|
||||
|
||||
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream) {
|
||||
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream,
|
||||
std::unique_ptr<InputStream>& subt,
|
||||
const PlaybackProperties& properties)
|
||||
{
|
||||
if (subt && properties.looping) {
|
||||
mprintf(("FFmpeg: External subtitles and looping movies are not supported!\n"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<DecoderStatus> status(new DecoderStatus());
|
||||
|
||||
auto ctx = stream->m_ctx->ctx();
|
||||
@@ -136,14 +242,18 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
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"));
|
||||
int audioStream = -1;
|
||||
|
||||
if (properties.with_audio) {
|
||||
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 (audioStream == 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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +265,59 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
status->audioStream = ctx->streams[audioStream];
|
||||
}
|
||||
|
||||
status->videoCodecPars = getCodecParameters(status->videoStream);
|
||||
if (subt) {
|
||||
auto subtCtx = subt->m_ctx->ctx();
|
||||
|
||||
auto subtStream = av_find_best_stream(subtCtx, AVMEDIA_TYPE_SUBTITLE, -1, -1, nullptr, 0);
|
||||
if (subtStream < 0) {
|
||||
if (subtStream == AVERROR_STREAM_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: No subtitle stream found in subtitle file!\n"));
|
||||
} else if (subtStream == AVERROR_DECODER_NOT_FOUND) {
|
||||
mprintf(("FFmpeg: Codec for subtitle stream could not be found!\n"));
|
||||
} else {
|
||||
mprintf(("FFmpeg: Unknown error while finding subtitle stream!\n"));
|
||||
}
|
||||
} else {
|
||||
status->subtitleStream = subtCtx->streams[subtStream];
|
||||
status->externalSubtitles = true;
|
||||
status->subtitleStreamIndex = subtStream;
|
||||
}
|
||||
}
|
||||
|
||||
if (status->subtitleStream == nullptr) {
|
||||
// We don't have an external subtitle stream or loading from that file has failed
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
|
||||
auto test_stream = ctx->streams[i];
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
auto& pars = test_stream->codecpar;
|
||||
|
||||
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
|
||||
if (properties.looping && status->videoCodecPars.codec_id == AV_CODEC_ID_INTERPLAY_VIDEO) {
|
||||
mprintf(("FFmpeg: Looping is not supported for inteplay (MVE) movies!\n"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int err;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
@@ -213,6 +375,38 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
|
||||
status->audioCodec->name ? status->audioCodec->name : "<Unknown>"));
|
||||
}
|
||||
|
||||
if (status->subtitleStream != nullptr) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -231,12 +425,35 @@ std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string& name)
|
||||
{
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
|
||||
for (auto ext : CHECKED_SUBT_EXTENSIONS) {
|
||||
SCP_string fileName;
|
||||
if (strlen(current_language.lang_ext) == 0) {
|
||||
fileName = name + "." + ext;
|
||||
} else {
|
||||
fileName = name + "-" + current_language.lang_ext + "." + ext;
|
||||
}
|
||||
|
||||
auto input = openStream(fileName);
|
||||
|
||||
if (input) {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
|
||||
bool FFMPEGDecoder::initialize(const SCP_string& fileName, const PlaybackProperties& properties)
|
||||
{
|
||||
SCP_string movieName = fileName;
|
||||
// First make the file name lower case
|
||||
std::transform(movieName.begin(), movieName.end(), movieName.begin(), ::tolower);
|
||||
std::transform(movieName.begin(), movieName.end(), movieName.begin(), [](char c) { return (char)::tolower(c); });
|
||||
|
||||
// Then remove the extension
|
||||
size_t dotPos = movieName.find('.');
|
||||
@@ -250,8 +467,10 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto subt = openSubtitleStream(movieName);
|
||||
|
||||
// We now have a valid input stream, try to find the correct streams
|
||||
auto status = initializeStatus(input);
|
||||
auto status = initializeStatus(input, subt, properties);
|
||||
if (!status) {
|
||||
return false;
|
||||
}
|
||||
@@ -261,42 +480,178 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
|
||||
|
||||
// We're done, now just put the pointer into this
|
||||
std::swap(m_input, input);
|
||||
std::swap(m_subtitleInput, subt);
|
||||
std::swap(m_status, status);
|
||||
m_properties = properties;
|
||||
return true;
|
||||
}
|
||||
|
||||
MovieProperties FFMPEGDecoder::getProperties() {
|
||||
MovieProperties FFMPEGDecoder::getProperties() const
|
||||
{
|
||||
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));
|
||||
|
||||
props.pixelFormat = getPixelFormat(getConversionFormat(m_status->videoCodecPars.pixel_format));
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
void FFMPEGDecoder::startDecoding() {
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get(), getConversionFormat(m_status->videoCodecPars.pixel_format)));
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
std::unique_ptr<std::thread> subtitle_thread;
|
||||
if (hasExternalSubtitle()) {
|
||||
// Start a new thread for the subtitles since otherwise we would need to make sure that neither of the input
|
||||
// streames starves while the other waits for more space in the queues
|
||||
subtitle_thread.reset(
|
||||
new std::thread([this, &subtitleDecoder]() { runSubtitleDecoder(subtitleDecoder.get()); }));
|
||||
}
|
||||
|
||||
auto ctx = m_input->m_ctx->ctx();
|
||||
AVPacket packet;
|
||||
do {
|
||||
if (m_properties.looping) {
|
||||
// Only seek if we are looping the movie. The MVE code doesn't support seeking to this function may not be
|
||||
// called there
|
||||
auto seek_err = av_seek_frame(ctx, -1, 0, AVSEEK_FLAG_BACKWARD);
|
||||
if (seek_err < 0) {
|
||||
char errorStr[512];
|
||||
av_strerror(seek_err, errorStr, sizeof(errorStr));
|
||||
mprintf(("FFMPEG: Failed to seek to start of movie file! Error: %s\n", errorStr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
videoDecoder->flushBuffers();
|
||||
if (audioDecoder) {
|
||||
audioDecoder->flushBuffers();
|
||||
}
|
||||
if (subtitleDecoder) {
|
||||
subtitleDecoder->flushBuffers();
|
||||
}
|
||||
|
||||
while (isDecoding()) {
|
||||
auto read_err = av_read_frame(ctx, &packet);
|
||||
AVPacketScope scope(&packet);
|
||||
|
||||
if (read_err < 0) {
|
||||
if (read_err == AVERROR_EOF) {
|
||||
// Finished reading -> break out of loop
|
||||
break;
|
||||
} else if (avio_feof(ctx->pb) != 0) {
|
||||
// Also EOF!
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the video is being looped then we start again from the beginning
|
||||
} while (m_properties.looping && isDecoding());
|
||||
|
||||
// Stop the decoder first to let the subtitle thread know that it shouldn't continue
|
||||
stopDecoder();
|
||||
|
||||
if (subtitle_thread) {
|
||||
subtitle_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasAudio() const { return m_status->audioStreamIndex >= 0; }
|
||||
|
||||
bool FFMPEGDecoder::hasSubtitles() const { return m_status->subtitleStream != nullptr; }
|
||||
|
||||
bool FFMPEGDecoder::hasExternalSubtitle() const { return m_status->externalSubtitles; }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (m_subtitleInput) {
|
||||
m_subtitleInput = nullptr;
|
||||
}
|
||||
}
|
||||
void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder* decoder)
|
||||
{
|
||||
auto ctx = m_subtitleInput->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 < 0) {
|
||||
if (read_err == AVERROR_EOF) {
|
||||
// Finished reading -> break out of loop
|
||||
break;
|
||||
} else if (avio_feof(ctx->pb) != 0) {
|
||||
// Also EOF!
|
||||
break;
|
||||
} else {
|
||||
// Some kind of other error, try to continue reading
|
||||
char errorStr[512];
|
||||
@@ -308,56 +663,24 @@ void FFMPEGDecoder::startDecoding() {
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.stream_index == m_status->videoStreamIndex) {
|
||||
videoDecoder->decodePacket(&packet);
|
||||
if (packet.stream_index == m_status->subtitleStreamIndex) {
|
||||
decoder->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));
|
||||
SubtitleFramePtr ptr;
|
||||
while ((ptr = decoder->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));
|
||||
}
|
||||
decoder->finishDecoding();
|
||||
|
||||
if (audioDecoder) {
|
||||
audioDecoder->finishDecoding();
|
||||
AudioFramePtr audio_frame;
|
||||
while ((audio_frame = audioDecoder->getFrame()) != nullptr) {
|
||||
pushAudioData(std::move(audio_frame));
|
||||
}
|
||||
SubtitleFramePtr ptr;
|
||||
while ((ptr = decoder->getFrame()) != nullptr) {
|
||||
pushSubtitleData(std::move(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
stopDecoder();
|
||||
}
|
||||
|
||||
bool FFMPEGDecoder::hasAudio() {
|
||||
return m_status->audioStreamIndex >= 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,26 +8,38 @@ struct InputStream;
|
||||
|
||||
struct DecoderStatus;
|
||||
|
||||
class SubtitleDecoder;
|
||||
|
||||
class FFMPEGDecoder: public Decoder {
|
||||
private:
|
||||
std::unique_ptr<InputStream> m_input;
|
||||
|
||||
std::unique_ptr<InputStream> m_subtitleInput;
|
||||
|
||||
std::unique_ptr<DecoderStatus> m_status;
|
||||
|
||||
public:
|
||||
PlaybackProperties m_properties;
|
||||
|
||||
bool hasExternalSubtitle() const;
|
||||
|
||||
void runSubtitleDecoder(SubtitleDecoder* decoder);
|
||||
|
||||
public:
|
||||
FFMPEGDecoder();
|
||||
|
||||
virtual ~FFMPEGDecoder();
|
||||
~FFMPEGDecoder() override;
|
||||
|
||||
bool initialize(const SCP_string& fileName) SCP_OVERRIDE;
|
||||
bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) override;
|
||||
|
||||
MovieProperties getProperties() SCP_OVERRIDE;
|
||||
MovieProperties getProperties() const override;
|
||||
|
||||
void startDecoding() SCP_OVERRIDE;
|
||||
void startDecoding() override;
|
||||
|
||||
bool hasAudio() SCP_OVERRIDE;
|
||||
bool hasAudio() const override;
|
||||
|
||||
void close() SCP_OVERRIDE;
|
||||
bool hasSubtitles() const override;
|
||||
|
||||
void close() override;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
//
|
||||
//
|
||||
|
||||
#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() {
|
||||
// Handle those decoders that have a delay
|
||||
AVPacket nullPacket;
|
||||
memset(&nullPacket, 0, sizeof(nullPacket));
|
||||
nullPacket.data = nullptr;
|
||||
nullPacket.size = 0;
|
||||
|
||||
AVSubtitle subtitle;
|
||||
while (true) {
|
||||
int finishedFrame = 1;
|
||||
auto err = avcodec_decode_subtitle2(m_status->subtitleCodecCtx, &subtitle, &finishedFrame, &nullPacket);
|
||||
|
||||
if (err < 0 || !finishedFrame) {
|
||||
break;
|
||||
}
|
||||
|
||||
pushSubtitleFrame(&nullPacket, &subtitle);
|
||||
|
||||
avsubtitle_free(&subtitle);
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
void SubtitleDecoder::flushBuffers() {
|
||||
avcodec_flush_buffers(m_status->subtitleCodecCtx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#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);
|
||||
|
||||
~SubtitleDecoder() override;
|
||||
|
||||
void decodePacket(AVPacket* packet) override;
|
||||
|
||||
void finishDecoding() override;
|
||||
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
|
||||
void flushBuffers() override;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
#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);
|
||||
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt, AVPixelFormat destination_fmt)
|
||||
{
|
||||
return sws_getContext(width, height, fmt, width, height, destination_fmt, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
@@ -18,34 +16,53 @@ double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
class FFMPEGVideoFrame: public VideoFrame {
|
||||
public:
|
||||
FFMPEGVideoFrame() : frame(nullptr) {
|
||||
}
|
||||
size_t _width;
|
||||
size_t _height;
|
||||
AVFrame* _frame;
|
||||
|
||||
virtual ~FFMPEGVideoFrame() {
|
||||
if (frame != nullptr) {
|
||||
av_freep(&frame->data[0]);
|
||||
av_frame_free(&frame);
|
||||
public:
|
||||
FFMPEGVideoFrame(size_t width, size_t height, AVFrame* frame) : _width(width), _height(height), _frame(frame) {}
|
||||
|
||||
~FFMPEGVideoFrame() override {
|
||||
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;
|
||||
size_t getPlaneNumber() override
|
||||
{
|
||||
switch (_frame->format) {
|
||||
case AV_PIX_FMT_YUV420P:
|
||||
// YUV data is planar
|
||||
return 3;
|
||||
default:
|
||||
// Everything else is packed
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
FrameSize getPlaneSize(size_t plane) override
|
||||
{
|
||||
switch (_frame->format) {
|
||||
case AV_PIX_FMT_YUV420P: {
|
||||
// YUV data is planar
|
||||
auto width = plane > 0 ? _width / 2 : _width;
|
||||
auto height = plane > 0 ? _height / 2 : _height;
|
||||
|
||||
AVFrame* frame;
|
||||
return {width, height, (size_t)_frame->linesize[plane]};
|
||||
}
|
||||
default:
|
||||
// Everything else is packed
|
||||
return {_width, _height, (size_t)_frame->linesize[plane]};
|
||||
}
|
||||
}
|
||||
void* getPlaneData(size_t plane) override { return _frame->data[plane]; }
|
||||
};
|
||||
|
||||
VideoDecoder::VideoDecoder(DecoderStatus* status)
|
||||
: FFMPEGStreamDecoder(status),
|
||||
m_frameId(0) {
|
||||
VideoDecoder::VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt)
|
||||
: FFMPEGStreamDecoder(status), m_frameId(0), m_destinationFormat(destination_fmt)
|
||||
{
|
||||
m_swsCtx = getSWSContext(m_status->videoCodecPars.width, m_status->videoCodecPars.height,
|
||||
m_status->videoCodecPars.pixel_format);
|
||||
m_status->videoCodecPars.pixel_format, destination_fmt);
|
||||
}
|
||||
|
||||
VideoDecoder::~VideoDecoder() {
|
||||
@@ -53,53 +70,32 @@ VideoDecoder::~VideoDecoder() {
|
||||
}
|
||||
|
||||
void VideoDecoder::convertAndPushPicture(const AVFrame* frame) {
|
||||
// Allocate a picture to hold the YUV data
|
||||
// Allocate a picture to hold the destination data
|
||||
AVFrame* yuvFrame = av_frame_alloc();
|
||||
av_frame_copy(yuvFrame, frame);
|
||||
yuvFrame->format = DESTINATION_FORMAT;
|
||||
yuvFrame->format = m_destinationFormat;
|
||||
|
||||
av_image_alloc(yuvFrame->data,
|
||||
yuvFrame->linesize,
|
||||
m_status->videoCodecPars.width,
|
||||
m_status->videoCodecPars.height,
|
||||
DESTINATION_FORMAT,
|
||||
1);
|
||||
av_image_alloc(yuvFrame->data, yuvFrame->linesize, m_status->videoCodecPars.width, m_status->videoCodecPars.height,
|
||||
m_destinationFormat, 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);
|
||||
if (m_status->videoCodecPars.pixel_format == m_destinationFormat) {
|
||||
av_image_copy(yuvFrame->data, yuvFrame->linesize, (const uint8_t**)(frame->data), frame->linesize,
|
||||
m_destinationFormat, 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
|
||||
);
|
||||
// Convert frame to destination format
|
||||
sws_scale(m_swsCtx, (uint8_t const* const*)frame->data, frame->linesize, 0, m_status->videoCodecPars.height,
|
||||
yuvFrame->data, yuvFrame->linesize);
|
||||
}
|
||||
|
||||
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(
|
||||
new FFMPEGVideoFrame(static_cast<size_t>(m_status->videoCodecPars.width),
|
||||
static_cast<size_t>(m_status->videoCodecPars.height), yuvFrame));
|
||||
videoFramePtr->id = ++m_frameId;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
|
||||
videoFramePtr->frameTime = getFrameTime(frame->best_effort_timestamp, m_status->videoStream->time_base);
|
||||
#else
|
||||
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]);
|
||||
#endif
|
||||
|
||||
pushFrame(VideoFramePtr(videoFramePtr.release()));
|
||||
}
|
||||
@@ -162,5 +158,8 @@ void VideoDecoder::finishDecoding() {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void VideoDecoder::flushBuffers() {
|
||||
avcodec_flush_buffers(m_status->videoCodecCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,20 @@ class VideoDecoder: public FFMPEGStreamDecoder<VideoFrame> {
|
||||
private:
|
||||
int m_frameId;
|
||||
SwsContext* m_swsCtx;
|
||||
AVPixelFormat m_destinationFormat;
|
||||
|
||||
void convertAndPushPicture(const AVFrame* frame);
|
||||
|
||||
public:
|
||||
explicit VideoDecoder(DecoderStatus* status);
|
||||
explicit VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt);
|
||||
|
||||
virtual ~VideoDecoder();
|
||||
~VideoDecoder() override;
|
||||
|
||||
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
|
||||
void decodePacket(AVPacket* packet) override;
|
||||
|
||||
virtual void finishDecoding() SCP_OVERRIDE;
|
||||
void finishDecoding() override;
|
||||
|
||||
void flushBuffers() override;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,18 @@ DecoderStatus::~DecoderStatus() {
|
||||
#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
|
||||
|
||||
@@ -16,6 +16,8 @@ struct CodecContextParameters {
|
||||
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 {
|
||||
@@ -31,6 +33,14 @@ struct DecoderStatus {
|
||||
AVCodec* audioCodec = nullptr;
|
||||
AVCodecContext* audioCodecCtx = nullptr;
|
||||
|
||||
// Subtitles are a bit different since they max come from a different file
|
||||
bool externalSubtitles = false;
|
||||
int subtitleStreamIndex = -1;
|
||||
AVStream* subtitleStream = nullptr;
|
||||
CodecContextParameters subtitleCodecPars;
|
||||
AVCodec* subtitleCodec = nullptr;
|
||||
AVCodecContext* subtitleCodecCtx = nullptr;
|
||||
|
||||
DecoderStatus();
|
||||
|
||||
~DecoderStatus();
|
||||
@@ -64,6 +74,8 @@ class FFMPEGStreamDecoder {
|
||||
|
||||
virtual void finishDecoding() = 0;
|
||||
|
||||
virtual void flushBuffers() = 0;
|
||||
|
||||
virtual FramePtr<frame_type> getFrame();
|
||||
};
|
||||
|
||||
|
||||
+209
-1
@@ -14,6 +14,7 @@
|
||||
#endif
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "globalincs/alphacolors.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "io/cursor.h"
|
||||
#include "graphics/2d.h"
|
||||
@@ -21,10 +22,212 @@
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "cutscene/cutscenes.h" // cutscene_mark_viewable()
|
||||
#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;
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace cutscene;
|
||||
|
||||
struct PlaybackState {
|
||||
bool playing = true;
|
||||
|
||||
vec2d posTopLeft;
|
||||
vec2d posBottomRight;
|
||||
|
||||
int subtitle_font = -1;
|
||||
};
|
||||
|
||||
void processEvents()
|
||||
{
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
|
||||
os_poll();
|
||||
}
|
||||
|
||||
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 listener = [state](const SDL_Event& event) {
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
case SDLK_KP_ENTER:
|
||||
case SDLK_RETURN:
|
||||
case SDLK_SPACE:
|
||||
state->playing = false;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// Use a dedicated listener here since we want to listen for the KEYUP event
|
||||
auto key_handle = os::events::addEventListener(SDL_KEYUP, os::events::DEFAULT_LISTENER_WEIGHT - 10, listener);
|
||||
|
||||
auto lastDisplayTimestamp = timer_get_microseconds();
|
||||
while (state->playing) {
|
||||
TRACE_SCOPE(tracing::CutsceneStep);
|
||||
|
||||
auto timestamp = timer_get_microseconds();
|
||||
|
||||
auto passed = timestamp - lastDisplayTimestamp;
|
||||
lastDisplayTimestamp = timestamp;
|
||||
|
||||
if (player->isPlaybackReady()) {
|
||||
// Play as long as the player reports that there is more to display
|
||||
state->playing = player->update(passed);
|
||||
|
||||
displayVideo(player, state);
|
||||
}
|
||||
|
||||
processEvents();
|
||||
|
||||
if (passed < sleepTime) {
|
||||
auto sleep = sleepTime - passed;
|
||||
|
||||
os_sleep(static_cast<uint>(sleep));
|
||||
}
|
||||
}
|
||||
|
||||
os::events::removeEventListener(key_handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace movie {
|
||||
// Play one movie
|
||||
bool play(const char* name) {
|
||||
@@ -57,7 +260,12 @@ bool play(const char* name) {
|
||||
|
||||
auto player = cutscene::Player::newPlayer(name);
|
||||
if (player) {
|
||||
player->startPlayback();
|
||||
PlaybackState state;
|
||||
initialize_player_state(player.get(), &state);
|
||||
|
||||
movie_display_loop(player.get(), &state);
|
||||
|
||||
player->stopPlayback();
|
||||
} else {
|
||||
// uh-oh, movie is invalid... Abory, Retry, Fail?
|
||||
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
|
||||
|
||||
+120
-186
@@ -1,7 +1,7 @@
|
||||
#include "cutscene/player.h"
|
||||
|
||||
#include "cutscene/Decoder.h"
|
||||
#include "cutscene/player/VideoPresenter.h"
|
||||
#include "cutscene/VideoPresenter.h"
|
||||
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
|
||||
|
||||
#include "graphics/2d.h"
|
||||
@@ -17,64 +17,22 @@
|
||||
#include "io/key.h"
|
||||
#include "io/timer.h"
|
||||
|
||||
#include "player.h"
|
||||
#include "parse/parselo.h"
|
||||
|
||||
#include "cutscene/player/OpenGLVideoPresenter.h"
|
||||
|
||||
using namespace cutscene::player;
|
||||
|
||||
namespace cutscene {
|
||||
struct PlayerState {
|
||||
MovieProperties props;
|
||||
Decoder* decoder = nullptr;
|
||||
|
||||
bool playing = true;
|
||||
|
||||
bool playbackHasBegun = false;
|
||||
|
||||
// Timing state
|
||||
std::uint64_t playback_time = 0;
|
||||
|
||||
// Audio state
|
||||
bool audioInited = false;
|
||||
bool hasAudio = false;
|
||||
ALuint audioSid = 0;
|
||||
SCP_vector<ALuint> audioBuffers;
|
||||
SCP_queue<ALuint> unqueuedAudioBuffers;
|
||||
|
||||
// Graphics state following
|
||||
bool videoInited = false;
|
||||
|
||||
VideoFramePtr currentFrame;
|
||||
VideoFramePtr nextFrame;
|
||||
bool newFrameAdded = false;
|
||||
|
||||
std::unique_ptr<VideoPresenter> videoPresenter;
|
||||
|
||||
PlayerState() : decoder(nullptr), playing(true), playbackHasBegun(false),
|
||||
playback_time(0),
|
||||
audioInited(0), hasAudio(false), audioSid(0),
|
||||
videoInited(false), newFrameAdded(false) {}
|
||||
|
||||
private:
|
||||
PlayerState(const PlayerState&) SCP_DELETED_FUNCTION;
|
||||
|
||||
PlayerState& operator=(const PlayerState&) SCP_DELETED_FUNCTION;
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
using namespace cutscene;
|
||||
|
||||
const int MAX_AUDIO_BUFFERS = 15;
|
||||
|
||||
Decoder* findDecoder(const SCP_string& name) {
|
||||
std::unique_ptr<Decoder> findDecoder(const SCP_string& name, const PlaybackProperties& properties) {
|
||||
{
|
||||
auto ffmpeg = new ffmpeg::FFMPEGDecoder();
|
||||
if (ffmpeg->initialize(name)) {
|
||||
std::unique_ptr<Decoder> ffmpeg(new ::cutscene::ffmpeg::FFMPEGDecoder());
|
||||
if (ffmpeg->initialize(name, properties)) {
|
||||
return ffmpeg;
|
||||
}
|
||||
delete ffmpeg;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -92,8 +50,9 @@ void videoPlaybackInit(PlayerState* state) {
|
||||
|
||||
Assert(state != NULL);
|
||||
|
||||
if (gr_screen.mode == GR_OPENGL) {
|
||||
state->videoPresenter.reset(new OpenGLVideoPresenter(state->props));
|
||||
if (gr_screen.mode != GR_STUB) {
|
||||
// The video presenter is independent of the underlying graphics API
|
||||
state->videoPresenter.reset(new VideoPresenter(state->props));
|
||||
}
|
||||
|
||||
state->videoInited = true;
|
||||
@@ -163,7 +122,16 @@ void processVideoData(PlayerState* state) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(currentTime >= state->nextFrame->frameTime) {
|
||||
while (currentTime >= state->nextFrame->frameTime) {
|
||||
if (state->currentFrame) {
|
||||
if (state->nextFrame->frameTime < state->currentFrame->frameTime) {
|
||||
// We reached the end of the movie and just looped to the beginning. Now we need to reset the playback
|
||||
// time
|
||||
state->playback_time = 0;
|
||||
currentTime = playbackGetTime(state);
|
||||
}
|
||||
}
|
||||
|
||||
// Move the next frame to the current frame slot
|
||||
state->currentFrame = std::move(state->nextFrame);
|
||||
|
||||
@@ -184,6 +152,34 @@ void processVideoData(PlayerState* state) {
|
||||
}
|
||||
}
|
||||
|
||||
void processSubtitleData(PlayerState* state) {
|
||||
SubtitleFramePtr ptr;
|
||||
while (state->decoder->tryPopSubtitleData(ptr)) {
|
||||
// Take all subtitle frames from our queue
|
||||
state->queued_subtitles.push(std::move(ptr));
|
||||
}
|
||||
|
||||
if (state->currentSubtitle && playbackGetTime(state) <= state->currentSubtitle->displayEndTime) {
|
||||
// We currently have a frame and it it still being displayed so there is nothing for us to do here
|
||||
return;
|
||||
}
|
||||
|
||||
// Subtitle has expired so we don't need it anymore
|
||||
state->currentSubtitle = nullptr;
|
||||
|
||||
while(!state->queued_subtitles.empty()) {
|
||||
// Take a look at the first entry and check if it's time to display it yet
|
||||
auto& nextSubtitle = state->queued_subtitles.front();
|
||||
if (playbackGetTime(state) >= nextSubtitle->displayStartTime) {
|
||||
state->currentSubtitle = std::move(nextSubtitle);
|
||||
state->queued_subtitles.pop();
|
||||
} else {
|
||||
// The next subtitle should not be displayed yet so we are done here
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool processAudioData(PlayerState* state) {
|
||||
TRACE_SCOPE(tracing::CutsceneProcessAudioData);
|
||||
|
||||
@@ -191,7 +187,7 @@ bool processAudioData(PlayerState* state) {
|
||||
if (state->decoder->hasAudio()) {
|
||||
// Even if we don't play the sound we still need to remove it from the queue
|
||||
AudioFramePtr audioData;
|
||||
while(state->decoder->tryPopAudioData(audioData)) {
|
||||
while (state->decoder->tryPopAudioData(audioData)) {
|
||||
// Intentionally left empty
|
||||
}
|
||||
}
|
||||
@@ -216,7 +212,9 @@ bool processAudioData(PlayerState* state) {
|
||||
|
||||
ALenum format = (audioData->channels == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
|
||||
|
||||
OpenAL_ErrorCheck(alBufferData(buffer, format, audioData->audioData.data(),
|
||||
OpenAL_ErrorCheck(alBufferData(buffer,
|
||||
format,
|
||||
audioData->audioData.data(),
|
||||
static_cast<ALsizei>(audioData->audioData.size() * sizeof(short)),
|
||||
static_cast<ALsizei>(audioData->rate)), return false);
|
||||
|
||||
@@ -269,82 +267,10 @@ void videoPlaybackClose(PlayerState* state) {
|
||||
state->videoInited = false;
|
||||
}
|
||||
|
||||
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(PlayerState* state) {
|
||||
gr_set_color_fast(&Color_white);
|
||||
|
||||
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(PlayerState* state) {
|
||||
if (!state->currentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
|
||||
|
||||
gr_clear();
|
||||
if (state->videoPresenter) {
|
||||
state->videoPresenter->displayFrame();
|
||||
}
|
||||
|
||||
if (Cmdline_show_video_info) {
|
||||
showVideoInfo(state);
|
||||
}
|
||||
|
||||
gr_flip();
|
||||
}
|
||||
|
||||
void processEvents(PlayerState* state) {
|
||||
io::mouse::CursorManager::get()->showCursor(false);
|
||||
|
||||
os_poll();
|
||||
|
||||
int k = key_inkey();
|
||||
switch (k) {
|
||||
case KEY_ESC:
|
||||
case KEY_ENTER:
|
||||
case KEY_SPACEBAR:
|
||||
state->playing = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldBeginPlayback(Decoder* decoder) {
|
||||
auto video = decoder->isVideoQueueFull();
|
||||
auto audio = decoder->isAudioQueueFull();
|
||||
auto subtitles = decoder->isSubtitleQueueFull();
|
||||
|
||||
// Wait until one of the queues is full, that should make sure
|
||||
// that we have enough frames at the beginning of playback and that
|
||||
@@ -352,92 +278,80 @@ bool shouldBeginPlayback(Decoder* decoder) {
|
||||
// or video at the beginning
|
||||
// Also only wait while the decoder is still working. Otherwise we will wait indefinitely if the video
|
||||
// is very short.
|
||||
return (audio || video) || !decoder->isDecoding();
|
||||
return (audio || video || subtitles) || !decoder->isDecoding();
|
||||
}
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
Player::Player() {
|
||||
Player::Player(std::unique_ptr<Decoder>&& decoder, const PlaybackProperties& properties)
|
||||
: m_decoder(std::move(decoder))
|
||||
{
|
||||
Assertion(!m_state.videoInited,
|
||||
"Internal State has been initialized before! Create a new player for replaying a movie.");
|
||||
|
||||
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
|
||||
|
||||
m_state.props = m_decoder->getProperties();
|
||||
m_state.decoder = m_decoder.get();
|
||||
|
||||
videoPlaybackInit(&m_state);
|
||||
|
||||
if (properties.with_audio) {
|
||||
audioPlaybackInit(&m_state);
|
||||
}
|
||||
}
|
||||
|
||||
Player::~Player() {
|
||||
// If video is initialized it means that stopPlayback has not been called yet
|
||||
if (m_state.videoInited) {
|
||||
stopPlayback();
|
||||
}
|
||||
|
||||
if (m_decoder) {
|
||||
m_decoder->close();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::processDecoderData(PlayerState* state) {
|
||||
if (!state->playbackHasBegun) {
|
||||
bool Player::processDecoderData() {
|
||||
if (!m_state.playbackHasBegun) {
|
||||
// Wait until video and audio are available
|
||||
// If we don't have audio, don't wait for it (obviously...)
|
||||
if (!shouldBeginPlayback(state->decoder)) {
|
||||
return;
|
||||
if (!shouldBeginPlayback(m_state.decoder)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
state->playbackHasBegun = true;
|
||||
m_state.playbackHasBegun = true;
|
||||
}
|
||||
|
||||
TRACE_SCOPE(tracing::CutsceneProcessDecoder);
|
||||
|
||||
processVideoData(state);
|
||||
processVideoData(&m_state);
|
||||
|
||||
auto audioPlaying = processAudioData(state);
|
||||
processSubtitleData(&m_state);
|
||||
|
||||
auto audioPlaying = processAudioData(&m_state);
|
||||
|
||||
// Set the playing flag if the decoder is still active or there is still data available
|
||||
auto decoding = m_decoder->isDecoding();
|
||||
|
||||
// Audio is pending if there is data left in the queue or of OpenAL is still playing audio
|
||||
// Audio is pending if there is data left in the queue or if OpenAL is still playing audio
|
||||
auto pendingAudio = (m_decoder->isAudioFrameAvailable() && m_decoder->hasAudio()) || audioPlaying;
|
||||
auto pendingVideo = m_decoder->isVideoFrameAvailable();
|
||||
|
||||
state->playing = decoding || pendingAudio || pendingVideo;
|
||||
return decoding || pendingAudio || pendingVideo;
|
||||
}
|
||||
|
||||
void Player::startPlayback() {
|
||||
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
|
||||
|
||||
PlayerState state;
|
||||
state.props = m_decoder->getProperties();
|
||||
state.decoder = m_decoder.get();
|
||||
|
||||
// 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. * state.props.fps)) * 1000.);
|
||||
|
||||
videoPlaybackInit(&state);
|
||||
|
||||
audioPlaybackInit(&state);
|
||||
|
||||
auto lastDisplayTimestamp = timer_get_microseconds();
|
||||
while (state.playing) {
|
||||
TRACE_SCOPE(tracing::CutsceneStep);
|
||||
|
||||
processDecoderData(&state);
|
||||
|
||||
displayVideo(&state);
|
||||
|
||||
processEvents(&state);
|
||||
|
||||
auto timestamp = timer_get_microseconds();
|
||||
|
||||
auto passed = timestamp - lastDisplayTimestamp;
|
||||
lastDisplayTimestamp = timestamp;
|
||||
|
||||
if (state.playbackHasBegun) {
|
||||
state.playback_time += passed;
|
||||
}
|
||||
|
||||
if (passed < sleepTime) {
|
||||
auto sleep = sleepTime - passed;
|
||||
|
||||
os_sleep(static_cast<uint>(sleep));
|
||||
}
|
||||
bool Player::update(uint64_t diff_time_micro) {
|
||||
if (m_state.playbackHasBegun) {
|
||||
m_state.playback_time += diff_time_micro;
|
||||
}
|
||||
|
||||
return processDecoderData();
|
||||
}
|
||||
void Player::stopPlayback() {
|
||||
m_decoder->stopDecoder();
|
||||
|
||||
audioPlaybackClose(&state);
|
||||
videoPlaybackClose(&state);
|
||||
audioPlaybackClose(&m_state);
|
||||
videoPlaybackClose(&m_state);
|
||||
|
||||
m_decoderThread->join();
|
||||
}
|
||||
@@ -452,18 +366,38 @@ void Player::decoderThread() {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
|
||||
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name, const PlaybackProperties& properties)
|
||||
{
|
||||
mprintf(("Creating player for movie '%s'.\n", name.c_str()));
|
||||
|
||||
auto decoder = findDecoder(name);
|
||||
auto decoder = findDecoder(name, properties);
|
||||
|
||||
if (decoder == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Player> player(new Player());
|
||||
player->m_decoder.reset(decoder);
|
||||
|
||||
return player;
|
||||
return std::unique_ptr<Player>(new Player(std::move(decoder), properties));
|
||||
}
|
||||
const PlayerState& Player::getInternalState() const {
|
||||
return m_state;
|
||||
}
|
||||
const MovieProperties& Player::getMovieProperties() const {
|
||||
return m_state.props;
|
||||
}
|
||||
void Player::draw(float x1, float y1, float x2, float y2) {
|
||||
if (!m_state.currentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state.videoPresenter) {
|
||||
m_state.videoPresenter->displayFrame(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
SCP_string Player::getCurrentSubtitle() {
|
||||
if (!m_state.currentSubtitle) {
|
||||
return "";
|
||||
} else {
|
||||
return m_state.currentSubtitle->text;
|
||||
}
|
||||
}
|
||||
bool Player::isPlaybackReady() const { return m_state.playbackHasBegun || shouldBeginPlayback(m_decoder.get()); }
|
||||
}
|
||||
+107
-18
@@ -5,44 +5,133 @@
|
||||
#include <thread>
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "sound/openal.h"
|
||||
|
||||
#include "Decoder.h"
|
||||
#include "VideoPresenter.h"
|
||||
|
||||
namespace cutscene {
|
||||
class Decoder;
|
||||
|
||||
struct PlayerState;
|
||||
struct PlayerState {
|
||||
MovieProperties props;
|
||||
Decoder* decoder = nullptr;
|
||||
|
||||
bool playbackHasBegun = false;
|
||||
|
||||
// Timing state
|
||||
std::uint64_t playback_time = 0;
|
||||
|
||||
// Audio state
|
||||
bool audioInited = false;
|
||||
bool hasAudio = false;
|
||||
ALuint audioSid = 0;
|
||||
SCP_vector<ALuint> audioBuffers;
|
||||
SCP_queue<ALuint> unqueuedAudioBuffers;
|
||||
|
||||
// Graphics state following
|
||||
bool videoInited = false;
|
||||
|
||||
VideoFramePtr currentFrame;
|
||||
VideoFramePtr nextFrame;
|
||||
bool newFrameAdded = false;
|
||||
|
||||
std::unique_ptr<player::VideoPresenter> videoPresenter;
|
||||
|
||||
SCP_queue<SubtitleFramePtr> queued_subtitles;
|
||||
SubtitleFramePtr currentSubtitle;
|
||||
|
||||
PlayerState() {
|
||||
}
|
||||
|
||||
PlayerState(const PlayerState&) = delete;
|
||||
PlayerState& operator=(const PlayerState&) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A movie player
|
||||
*/
|
||||
class Player {
|
||||
private:
|
||||
private:
|
||||
std::unique_ptr<Decoder> m_decoder;
|
||||
|
||||
std::unique_ptr<std::thread> m_decoderThread;
|
||||
|
||||
void processDecoderData(PlayerState* state);
|
||||
PlayerState m_state;
|
||||
|
||||
private:
|
||||
Player(const Player&) = delete;
|
||||
bool processDecoderData();
|
||||
|
||||
private:
|
||||
void decoderThread();
|
||||
|
||||
public:
|
||||
Player();
|
||||
|
||||
Player(std::unique_ptr<Decoder>&& decoder, const PlaybackProperties& properties);
|
||||
public:
|
||||
~Player();
|
||||
|
||||
/**
|
||||
* @brief Begin playing the previously selected movie
|
||||
*/
|
||||
void startPlayback();
|
||||
Player(const Player&) = delete;
|
||||
Player& operator=(const Player&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Creates a player
|
||||
* The player is configured to play the movie with the specified name
|
||||
* @param name The movie to play
|
||||
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
|
||||
*/
|
||||
static std::unique_ptr<Player> newPlayer(const SCP_string& name);
|
||||
* @brief Update the player and increase display timestamp by specified delta time
|
||||
* @param diff_time_micro The time to increase the display timestamp in microseconds (not milliseconds!)
|
||||
* @return @c true if there is more content to display. @c false if the player reached the end of the movie and has
|
||||
* displayed the last frame.
|
||||
*/
|
||||
bool update(uint64_t diff_time_micro);
|
||||
|
||||
/**
|
||||
* @brief Gives access to the internal state of the player
|
||||
*
|
||||
* @warning This should only be used for debugging purposed!
|
||||
*
|
||||
* @return A reference to the internal state
|
||||
*/
|
||||
const PlayerState& getInternalState() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the properties of the movie that this player is displaying
|
||||
* @return A reference to the movie properties
|
||||
*/
|
||||
const MovieProperties& getMovieProperties() const;
|
||||
|
||||
/**
|
||||
* @brief Determines if this player can start displaying video.
|
||||
* @return true if the cutscene is ready, false otherwise
|
||||
*/
|
||||
bool isPlaybackReady() const;
|
||||
|
||||
/**
|
||||
* @brief Draws the current movie frame at the specified coordinates.
|
||||
*
|
||||
* This may not draw anything if there is currently not a frame to display.
|
||||
*
|
||||
* @param x1 The X coordinate of the top left corner
|
||||
* @param y1 The Y coordinate of the top left corner
|
||||
* @param x2 The X coordinate of the bottom right corner
|
||||
* @param y2 The Y coordinate of the bottom right corner
|
||||
*/
|
||||
void draw(float x1, float y1, float x2, float y2);
|
||||
|
||||
/**
|
||||
* @brief Gets the subtitle text that should be displayed now
|
||||
* @return The text, encoded in UTF-8
|
||||
*/
|
||||
SCP_string getCurrentSubtitle();
|
||||
|
||||
/**
|
||||
* @brief Stops playback
|
||||
*
|
||||
* This is also automatically called when this instance is destroyed.
|
||||
*/
|
||||
void stopPlayback();
|
||||
|
||||
/**
|
||||
* @brief Creates a player
|
||||
* The player is configured to play the movie with the specified name
|
||||
* @param name The movie to play
|
||||
* @param properties A structure describing how the movie will be used
|
||||
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
|
||||
*/
|
||||
static std::unique_ptr<Player> newPlayer(const SCP_string& name, const PlaybackProperties& properties = PlaybackProperties());
|
||||
};
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
|
||||
#include "OpenGLVideoPresenter.h"
|
||||
|
||||
#include "graphics/opengl/gropenglstate.h"
|
||||
#include "graphics/opengl/gropengltnl.h"
|
||||
#include "graphics/opengl/gropengldraw.h"
|
||||
|
||||
|
||||
using namespace cutscene;
|
||||
using namespace cutscene::player;
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
OpenGLVideoPresenter::OpenGLVideoPresenter(const MovieProperties& props) : _scaleVideo(false),
|
||||
_ytex(0), _utex(0), _vtex(0) {
|
||||
GR_DEBUG_SCOPE("Init video");
|
||||
|
||||
opengl_set_texture_target(GL_TEXTURE_2D);
|
||||
|
||||
_vertexBuffer = gr_create_vertex_buffer(true);
|
||||
|
||||
auto w = static_cast<int>(props.size.width);
|
||||
auto h = static_cast<int>(props.size.height);
|
||||
|
||||
_sdr_handle = gr_maybe_create_shader(SDR_TYPE_VIDEO_PROCESS, 0);
|
||||
|
||||
glGenTextures(1, &_ytex);
|
||||
glGenTextures(1, &_utex);
|
||||
glGenTextures(1, &_vtex);
|
||||
|
||||
if (_ytex + _utex + _vtex == 0) {
|
||||
throw std::runtime_error("Can't create a GL texture");
|
||||
}
|
||||
opengl_shader_set_current(_sdr_handle);
|
||||
|
||||
gr_set_lighting(false, false);
|
||||
|
||||
GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
|
||||
GL_state.SetZbufferType(ZBUFFER_TYPE_NONE);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
GL_state.Texture.SetTarget(GL_texture_target);
|
||||
GL_state.Texture.Enable(_ytex);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
|
||||
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w, h, 0, GL_RED,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(1);
|
||||
GL_state.Texture.SetTarget(GL_texture_target);
|
||||
GL_state.Texture.Enable(_utex);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
|
||||
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(2);
|
||||
GL_state.Texture.SetTarget(GL_texture_target);
|
||||
GL_state.Texture.Enable(_vtex);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
|
||||
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// don't bother setting anything if we aren't going to need it
|
||||
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
|
||||
vec3d scale;
|
||||
|
||||
scale.xyz.x = scale_by;
|
||||
scale.xyz.y = scale_by;
|
||||
scale.xyz.z = -1.0f;
|
||||
|
||||
gr_push_scale_matrix(&scale);
|
||||
_scaleVideo = true;
|
||||
}
|
||||
|
||||
int screenX;
|
||||
int screenY;
|
||||
|
||||
if (_scaleVideo) {
|
||||
screenX = fl2i(((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f);
|
||||
screenY = fl2i(((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 = ((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x;
|
||||
screenY = ((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
|
||||
int screenXW = screenX + static_cast<int>(props.size.width);
|
||||
int screenYH = screenY + static_cast<int>(props.size.height);
|
||||
|
||||
Current_shader->program->Uniforms.setUniformi("ytex", 0);
|
||||
Current_shader->program->Uniforms.setUniformi("utex", 1);
|
||||
Current_shader->program->Uniforms.setUniformi("vtex", 2);
|
||||
|
||||
Current_shader->program->Uniforms.setUniformMatrix4f("projMatrix", GL_projection_matrix);
|
||||
Current_shader->program->Uniforms.setUniformMatrix4f("modelViewMatrix", GL_model_view_matrix);
|
||||
|
||||
GLfloat glVertices[4][4] = {{0}};
|
||||
glVertices[0][0] = (GLfloat)screenX;
|
||||
glVertices[0][1] = (GLfloat)screenY;
|
||||
glVertices[0][2] = 0.0f;
|
||||
glVertices[0][3] = 0.0f;
|
||||
|
||||
glVertices[1][0] = (GLfloat)screenX;
|
||||
glVertices[1][1] = (GLfloat)screenYH;
|
||||
glVertices[1][2] = 0.0f;
|
||||
glVertices[1][3] = 1.0f;
|
||||
|
||||
glVertices[2][0] = (GLfloat)screenXW;
|
||||
glVertices[2][1] = (GLfloat)screenY;
|
||||
glVertices[2][2] = 1.0f;
|
||||
glVertices[2][3] = 0.0f;
|
||||
|
||||
glVertices[3][0] = (GLfloat)screenXW;
|
||||
glVertices[3][1] = (GLfloat)screenYH;
|
||||
glVertices[3][2] = 1.0f;
|
||||
glVertices[3][3] = 1.0f;
|
||||
|
||||
_vertexLayout.add_vertex_component(vertex_format_data::POSITION2, sizeof(glVertices[0]), 0);
|
||||
_vertexLayout.add_vertex_component(vertex_format_data::TEX_COORD, sizeof(glVertices[0]), sizeof(GLfloat) * 2);
|
||||
|
||||
gr_update_buffer_data(_vertexBuffer, sizeof(glVertices[0]) * 4, glVertices);
|
||||
}
|
||||
|
||||
OpenGLVideoPresenter::~OpenGLVideoPresenter() {
|
||||
GR_DEBUG_SCOPE("Deinit video");
|
||||
|
||||
if (_scaleVideo) {
|
||||
gr_pop_scale_matrix();
|
||||
}
|
||||
|
||||
gr_delete_buffer(_vertexBuffer);
|
||||
_vertexBuffer = -1;
|
||||
|
||||
GL_state.Texture.Delete(_ytex);
|
||||
GL_state.Texture.Delete(_utex);
|
||||
GL_state.Texture.Delete(_vtex);
|
||||
glDeleteTextures(1, &_ytex);
|
||||
glDeleteTextures(1, &_utex);
|
||||
glDeleteTextures(1, &_vtex);
|
||||
|
||||
opengl_set_texture_target();
|
||||
|
||||
_ytex = _utex = _vtex = 0;
|
||||
opengl_shader_set_current();
|
||||
}
|
||||
|
||||
void OpenGLVideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
GR_DEBUG_SCOPE("Update video frame");
|
||||
auto ptrs = frame->getDataPointers();
|
||||
|
||||
auto stride = static_cast<GLint>(frame->ySize.stride);
|
||||
auto width = static_cast<GLint>(frame->ySize.width);
|
||||
auto height = static_cast<GLint>(frame->ySize.height);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
GL_state.Texture.Enable(_ytex);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
|
||||
ptrs.y);
|
||||
|
||||
stride = static_cast<int>(frame->uvSize.stride);
|
||||
width = static_cast<int>(frame->uvSize.width);
|
||||
height = static_cast<int>(frame->uvSize.height);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(1);
|
||||
GL_state.Texture.Enable(_utex);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
|
||||
ptrs.u);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(2);
|
||||
GL_state.Texture.Enable(_vtex);
|
||||
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
|
||||
ptrs.v);
|
||||
|
||||
// Reset this back to default
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
|
||||
void OpenGLVideoPresenter::displayFrame() {
|
||||
opengl_shader_set_current(_sdr_handle);
|
||||
|
||||
opengl_bind_buffer_object(_vertexBuffer);
|
||||
opengl_bind_vertex_layout(_vertexLayout);
|
||||
|
||||
// Bind textures
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
GL_state.Texture.Enable(_ytex);
|
||||
GL_state.Texture.SetActiveUnit(1);
|
||||
GL_state.Texture.Enable(_utex);
|
||||
GL_state.Texture.SetActiveUnit(2);
|
||||
GL_state.Texture.Enable(_vtex);
|
||||
|
||||
GR_DEBUG_SCOPE("Draw video frame");
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
|
||||
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "cutscene/player/VideoPresenter.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <memory>
|
||||
#include <graphics/2d.h>
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
class OpenGLVideoPresenter: public VideoPresenter {
|
||||
int _vertexBuffer = -1;
|
||||
vertex_layout _vertexLayout;
|
||||
int _sdr_handle = -1;
|
||||
|
||||
bool _scaleVideo = false;
|
||||
|
||||
GLuint _ytex = 0;
|
||||
GLuint _utex = 0;
|
||||
GLuint _vtex = 0;
|
||||
public:
|
||||
OpenGLVideoPresenter(const MovieProperties& props);
|
||||
|
||||
virtual ~OpenGLVideoPresenter();
|
||||
|
||||
virtual void uploadVideoFrame(const VideoFramePtr& frame) SCP_OVERRIDE;
|
||||
|
||||
virtual void displayFrame() SCP_OVERRIDE;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
#ifndef FS2_OPEN_VIDEOPRESENTER_H
|
||||
#define FS2_OPEN_VIDEOPRESENTER_H
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "cutscene/Decoder.h"
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
class VideoPresenter {
|
||||
public:
|
||||
virtual ~VideoPresenter() {}
|
||||
|
||||
virtual void uploadVideoFrame(const VideoFramePtr& frame) = 0;
|
||||
|
||||
virtual void displayFrame() = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif //FS2_OPEN_VIDEOPRESENTER_H
|
||||
+12
-27
@@ -31,7 +31,6 @@
|
||||
#include "weapon/weapon.h"
|
||||
#include "tracing/Monitor.h"
|
||||
|
||||
#define MAX_LIFE 10.0f
|
||||
#define MIN_RADIUS_FOR_PERSISTANT_DEBRIS 50 // ship radius at which debris from it becomes persistant
|
||||
#define DEBRIS_SOUND_DELAY 2000 // time to start debris sound after created
|
||||
#define MAX_HULL_PIECES MAX_DEBRIS_PIECES // limit the number of hull debris chunks that can exist.
|
||||
@@ -52,10 +51,6 @@ int Debris_num_submodels = 0;
|
||||
#define DEBRIS_DISTANCE_CHECK_TIME (10*1000) // Check every 10 seconds.
|
||||
#define DEBRIS_INDEX(dp) (int)(dp-Debris)
|
||||
|
||||
#define MAX_SPEED_SMALL_DEBRIS 200 // maximum velocity of small debris piece
|
||||
#define MAX_SPEED_BIG_DEBRIS 150 // maximum velocity of big debris piece
|
||||
#define MAX_SPEED_CAPITAL_DEBRIS 100 // maximum velocity of capital debris piece
|
||||
|
||||
/**
|
||||
* Start the sequence of a piece of debris writhing in unholy agony!!!
|
||||
*/
|
||||
@@ -74,7 +69,7 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
|
||||
|
||||
// only play debris destroy sound if hull piece and it has been around for at least 2 seconds
|
||||
if ( Missiontime > debris_p->time_started + 2*F1_0 ) {
|
||||
snd_play_3d( &Snds[SND_MISSILE_IMPACT1], &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(gamesnd_id(GameSounds::MISSILE_IMPACT1)), &debris_obj->pos, &View_position, debris_obj->radius );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -238,7 +233,7 @@ void debris_process_post(object * obj, float frame_time)
|
||||
radar_plot_object( obj );
|
||||
|
||||
if ( timestamp_elapsed(db->sound_delay) ) {
|
||||
obj_snd_assign(objnum, SND_DEBRIS, &vmd_zero_vector, 0);
|
||||
obj_snd_assign(objnum, GameSounds::DEBRIS, &vmd_zero_vector, 0);
|
||||
db->sound_delay = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -270,13 +265,8 @@ void debris_process_post(object * obj, float frame_time)
|
||||
|
||||
vec3d v1, v2, v3, v4;
|
||||
|
||||
if ( Cmdline_old_collision_sys ) {
|
||||
submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
submodel_get_two_random_points( db->model_num, db->submodel_num, &v3, &v4 );
|
||||
} else {
|
||||
submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v3, &v4 );
|
||||
}
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v3, &v4);
|
||||
|
||||
n = 0;
|
||||
|
||||
@@ -324,19 +314,19 @@ void debris_process_post(object * obj, float frame_time)
|
||||
//Play a sound effect
|
||||
if ( lifetime > 750 ) {
|
||||
// 1.00 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_05], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 500 ) {
|
||||
// 0.75 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_04], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 250 ) {
|
||||
// 0.50 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_03], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
|
||||
} else if ( lifetime > 100 ) {
|
||||
// 0.25 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_02], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
|
||||
} else {
|
||||
// 0.10 second effect
|
||||
snd_play_3d( &Snds[SND_DEBRIS_ARC_01], &snd_pos, &View_position, obj->radius );
|
||||
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,12 +342,8 @@ void debris_process_post(object * obj, float frame_time)
|
||||
if ( mr < RAND_MAX/5 ) {
|
||||
vec3d v1, v2;
|
||||
|
||||
if ( Cmdline_old_collision_sys ) {
|
||||
submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
} else {
|
||||
submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 );
|
||||
}
|
||||
|
||||
submodel_get_two_random_points_better(db->model_num, db->submodel_num, &v1, &v2);
|
||||
|
||||
db->arc_pts[i][mr % 2] = v1;
|
||||
}
|
||||
}
|
||||
@@ -505,7 +491,6 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
db->flags |= DEBRIS_USED;
|
||||
db->is_hull = hull_flag;
|
||||
db->source_objnum = parent_objnum;
|
||||
db->source_sig = source_obj->signature;
|
||||
db->damage_type_idx = shipp->debris_damage_type_idx;
|
||||
db->ship_info_index = shipp->ship_info_index;
|
||||
db->team = shipp->team;
|
||||
@@ -693,7 +678,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
|
||||
* Alas, poor debris_obj got whacked. Fortunately, we know who did it, where and how hard, so we
|
||||
* can do something about it.
|
||||
*/
|
||||
void debris_hit(object *debris_obj, object *other_obj, vec3d *hitpos, float damage)
|
||||
void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float damage)
|
||||
{
|
||||
debris *debris_p = &Debris[debris_obj->instance];
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ typedef struct debris {
|
||||
debris *next, *prev; // used for a linked list of the hull debris chunks
|
||||
int flags; // See DEBRIS_??? defines
|
||||
int source_objnum; // What object this came from
|
||||
int source_sig; // Signature of the source object
|
||||
int damage_type_idx; // Damage type of this debris
|
||||
int ship_info_index; // Ship info index of the ship type debris came from
|
||||
int team; // Team of the ship where the debris came from
|
||||
|
||||
Loaded 100 of 1215 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user